Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 431e48d147 |
@@ -69,7 +69,7 @@ import {
|
||||
recordMessageReceived,
|
||||
recordMessageRetry
|
||||
} from '../Utils/prometheus-metrics.js'
|
||||
import { isTcTokenExpired, resolveTcTokenJid } from '../Utils/tc-token-utils'
|
||||
import { isTcTokenExpired, resolveTcTokenJid, storeTcTokensFromIqResult } from '../Utils/tc-token-utils'
|
||||
import {
|
||||
areJidsSameUser,
|
||||
type BinaryNode,
|
||||
@@ -1453,6 +1453,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
||||
})
|
||||
|
||||
// When a session is refreshed (identity change), re-issue tctoken fire-and-forget
|
||||
// WABA Android: reissue stores senderTimestamp + realIssueTimestamp after IQ success
|
||||
if (result.action === 'session_refreshed') {
|
||||
const normalizedJid = jidNormalizedUser(from)
|
||||
resolveTcTokenJid(normalizedJid, getLIDForPN)
|
||||
@@ -1462,9 +1463,36 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
||||
if (entry?.token?.length && !isTcTokenExpired(entry.timestamp)) {
|
||||
const senderTs = unixTimestampSeconds()
|
||||
logTcToken('reissue', { jid: normalizedJid, reason: 'session_refreshed' })
|
||||
getPrivacyTokens([normalizedJid], senderTs).catch(err => {
|
||||
logTcToken('reissue_fail', { jid: normalizedJid, error: err?.message })
|
||||
})
|
||||
getPrivacyTokens([normalizedJid], senderTs)
|
||||
.then(async (iqResult) => {
|
||||
await storeTcTokensFromIqResult({
|
||||
result: iqResult,
|
||||
fallbackJid: normalizedJid,
|
||||
keys: authState.keys,
|
||||
getLIDForPN,
|
||||
onNewJidStored: (storedJid) => {
|
||||
tcTokenKnownJids.add(storedJid)
|
||||
scheduleTcTokenIndexSave()
|
||||
}
|
||||
})
|
||||
// Persist senderTimestamp + realIssueTimestamp after IQ success
|
||||
const currentData = await authState.keys.get('tctoken', [tcJid])
|
||||
const currentEntry = currentData[tcJid]
|
||||
await authState.keys.set({
|
||||
tctoken: {
|
||||
[tcJid]: {
|
||||
...currentEntry,
|
||||
token: currentEntry?.token ?? Buffer.alloc(0),
|
||||
senderTimestamp: senderTs,
|
||||
realIssueTimestamp: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
logTcToken('reissue_ok', { jid: normalizedJid, reason: 'session_refreshed' })
|
||||
})
|
||||
.catch(err => {
|
||||
logTcToken('reissue_fail', { jid: normalizedJid, error: err?.message })
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -1912,7 +1940,10 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
||||
[storageJid]: {
|
||||
...existing,
|
||||
token: Buffer.from(content),
|
||||
timestamp
|
||||
timestamp,
|
||||
// WABA Android: resets real_issue_timestamp when a new incoming token arrives
|
||||
// (UPDATE wa_trusted_contacts_send SET real_issue_timestamp=null)
|
||||
realIssueTimestamp: null
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -2823,6 +2854,24 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
||||
const jid = jidNormalizedUser(attrs.from)
|
||||
logTcToken('error_463', { jid, msgId })
|
||||
|
||||
// WABA Android: error 463 triggers getPrivacyTokens() fire-and-forget
|
||||
// to ensure token is available for the retry below
|
||||
getPrivacyTokens([jid])
|
||||
.then(async (result) => {
|
||||
await storeTcTokensFromIqResult({
|
||||
result,
|
||||
fallbackJid: jid,
|
||||
keys: authState.keys,
|
||||
getLIDForPN,
|
||||
onNewJidStored: (storedJid) => {
|
||||
tcTokenKnownJids.add(storedJid)
|
||||
scheduleTcTokenIndexSave()
|
||||
}
|
||||
})
|
||||
logTcToken('fetched', { jid, reason: 'error_463' })
|
||||
})
|
||||
.catch(() => { /* fire-and-forget */ })
|
||||
|
||||
// Single-retry: wait 1.5s for the server's tctoken notification to arrive,
|
||||
// then resend. A Set prevents infinite retry loops.
|
||||
// Composite key (jid:msgId) ensures retries are isolated per destination.
|
||||
@@ -2858,7 +2907,24 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
||||
return
|
||||
}
|
||||
} else if (attrs.error === SERVER_ERROR_CODES.SmaxInvalid) {
|
||||
logTcToken('error_479', { jid: attrs.from, msgId: attrs.id })
|
||||
const jid479 = jidNormalizedUser(attrs.from)
|
||||
logTcToken('error_479', { jid: jid479, msgId: attrs.id })
|
||||
// WABA Android: error 479 (SmaxInvalid) also triggers token re-fetch
|
||||
getPrivacyTokens([jid479])
|
||||
.then(async (result) => {
|
||||
await storeTcTokensFromIqResult({
|
||||
result,
|
||||
fallbackJid: jid479,
|
||||
keys: authState.keys,
|
||||
getLIDForPN,
|
||||
onNewJidStored: (storedJid) => {
|
||||
tcTokenKnownJids.add(storedJid)
|
||||
scheduleTcTokenIndexSave()
|
||||
}
|
||||
})
|
||||
logTcToken('fetched', { jid: jid479, reason: 'error_479' })
|
||||
})
|
||||
.catch(() => { /* fire-and-forget */ })
|
||||
} else {
|
||||
logger.warn({ attrs }, 'received error in ack')
|
||||
}
|
||||
|
||||
@@ -1611,6 +1611,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
|
||||
// Persist senderTimestamp unconditionally — WA Web stores it in the chat table
|
||||
// regardless of whether a token exists. Spread preserves token+timestamp if present.
|
||||
// WABA Android: INSERT INTO wa_trusted_contacts_send (jid, sent_tc_token_timestamp, real_issue_timestamp)
|
||||
// VALUES (?, ?, 0) — realIssueTimestamp=0 means issued but not yet confirmed by server
|
||||
const currentData = await authState.keys.get('tctoken', [tcTokenJid])
|
||||
const currentEntry = currentData[tcTokenJid]
|
||||
await authState.keys.set({
|
||||
@@ -1618,7 +1620,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
[tcTokenJid]: {
|
||||
...currentEntry,
|
||||
token: currentEntry?.token ?? Buffer.alloc(0),
|
||||
senderTimestamp: issueTimestamp
|
||||
senderTimestamp: issueTimestamp,
|
||||
realIssueTimestamp: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ export type SignalDataTypeMap = {
|
||||
'app-state-sync-version': LTHashState
|
||||
'lid-mapping': string
|
||||
'device-list': string[]
|
||||
tctoken: { token: Buffer; timestamp?: string; senderTimestamp?: number }
|
||||
tctoken: { token: Buffer; timestamp?: string; senderTimestamp?: number; realIssueTimestamp?: number | null }
|
||||
/** Identity key for Signal Protocol - used for detecting contact reinstalls */
|
||||
'identity-key': Uint8Array
|
||||
}
|
||||
|
||||
@@ -159,7 +159,10 @@ export async function storeTcTokensFromIqResult({
|
||||
[storageJid]: {
|
||||
...existingEntry,
|
||||
token: Buffer.from(tokenNode.content),
|
||||
timestamp: tokenNode.attrs.t
|
||||
timestamp: tokenNode.attrs.t,
|
||||
// WABA Android: resets real_issue_timestamp to null when storing a new token
|
||||
// (UPDATE wa_trusted_contacts_send SET real_issue_timestamp=null)
|
||||
realIssueTimestamp: null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user