fix: apply 3 surgical gaps from upstream

fix: apply 3 surgical gaps from upstream
This commit is contained in:
Renato Alcara
2026-02-23 12:13:41 -03:00
committed by GitHub
parent 1112110556
commit c63c7a815f
3 changed files with 34 additions and 35 deletions
+9 -6
View File
@@ -85,6 +85,8 @@ export const makeChatsSocket = (config: SocketConfig) => {
sendUnifiedSession
} = sock
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
let privacySettings: { [_: string]: string } | undefined
let syncState: SyncState = SyncState.Connecting
@@ -752,7 +754,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
authState,
jid: normalizedJid,
baseContent,
getLIDForPN: signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
getLIDForPN
})
}
@@ -858,11 +860,12 @@ export const makeChatsSocket = (config: SocketConfig) => {
* @param tcToken token for subscription, use if present
*/
const presenceSubscribe = async (toJid: string) => {
const tcTokenContent = await buildTcTokenFromJid({
authState,
jid: toJid,
getLIDForPN: signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
})
// Only include tctoken for user JIDs — groups/newsletters don't use tctokens
const normalizedToJid = jidNormalizedUser(toJid)
const isUserJid = isAnyPnUser(normalizedToJid) || isAnyLidUser(normalizedToJid)
const tcTokenContent = isUserJid
? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
: undefined
return sendNode({
tag: 'presence',
+3 -5
View File
@@ -123,6 +123,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
getPrivacyTokens
} = sock
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
const retryMutex = makeMutex()
@@ -720,10 +722,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
// When a session is refreshed (identity change), re-issue tctoken fire-and-forget
if(result.action === 'session_refreshed') {
const normalizedJid = jidNormalizedUser(from)
resolveTcTokenJid(
normalizedJid,
signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
).then(async (tcJid) => {
resolveTcTokenJid(normalizedJid, getLIDForPN).then(async (tcJid) => {
const tcData = await authState.keys.get('tctoken', [tcJid])
const entry = tcData[tcJid]
if(entry?.token?.length && !isTcTokenExpired(entry.timestamp)) {
@@ -1064,7 +1063,6 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
if(!tokensNode) return
const tokenNodes = getBinaryNodeChildren(tokensNode, 'token')
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
for(const tokenNode of tokenNodes) {
const { attrs, content } = tokenNode
+15 -17
View File
@@ -100,6 +100,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
groupToggleEphemeral
} = sock
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
const userDevicesCache =
config.userDevicesCache ||
new NodeCache<JidWithDevice[]>({
@@ -1456,10 +1458,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
const tcTokenJid = is1on1Send
? await resolveTcTokenJid(
destinationJid,
signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
)
? await resolveTcTokenJid(destinationJid, getLIDForPN)
: destinationJid
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {}
const existingTokenEntry = contactTcTokenData[tcTokenJid]
@@ -1488,7 +1487,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
result: fetchResult,
fallbackJid: destinationJid,
keys: authState.keys,
getLIDForPN: signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
getLIDForPN
// onNewJidStored not passed — the pruning index lives in messages-recv (higher layer)
})
})
@@ -1594,38 +1593,37 @@ export const makeMessagesSocket = (config: SocketConfig) => {
await sendNode(stanza)
// Fire-and-forget: issue our token to the contact (like WA Web's sendTcToken)
// Only for 1:1 sends where we already have a token, and when bucket boundary crossed
if (is1on1Send && tcTokenBuffer?.length && shouldSendNewTcToken(existingTokenEntry?.senderTimestamp)) {
// Fire-and-forget: issue our token to the contact (like WA Web's sendTcToken).
// Gated only by shouldSendNewTcToken — removed tcTokenBuffer?.length guard so
// issuance fires even when we don't yet hold a token (bucket boundary crossed).
// IMPORTANT: must run AFTER sendNode — issuing before the message causes error 463.
if (is1on1Send && shouldSendNewTcToken(existingTokenEntry?.senderTimestamp)) {
const issueTimestamp = unixTimestampSeconds()
logTcToken('reissue', { jid: destinationJid })
// WA Web writes senderTimestamp only AFTER the IQ succeeds
// (WAWebSendTcTokenChatAction.sendTcToken).
// This ensures failed issuance allows re-issuance on the next message
// rather than blocking it for up to 7 days (one bucket duration).
getPrivacyTokens([destinationJid], issueTimestamp)
.then(async result => {
// Store any tokens received in the IQ response
// Store any tokens received in the IQ response.
// onNewJidStored not passed — pruning index lives in messages-recv (higher layer).
await storeTcTokensFromIqResult({
result,
fallbackJid: tcTokenJid,
keys: authState.keys,
getLIDForPN: signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
getLIDForPN
})
// Re-read entry to avoid overwriting concurrent notification handler updates
// Persist senderTimestamp unconditionally — WA Web stores it in the chat table
// regardless of whether a token exists. Spread preserves token+timestamp if present.
const currentData = await authState.keys.get('tctoken', [tcTokenJid])
const currentEntry = currentData[tcTokenJid]
if (currentEntry?.token?.length) {
await authState.keys.set({
tctoken: {
[tcTokenJid]: {
token: Buffer.alloc(0),
...currentEntry,
senderTimestamp: issueTimestamp
}
}
})
}
logTcToken('reissue_ok', { jid: destinationJid })
})