zapo-js 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/dist/appstate/WaAppStateCrypto.js +19 -26
- package/dist/appstate/WaAppStateSyncClient.js +293 -181
- package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
- package/dist/appstate/constants.js +4 -3
- package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/appstate/index.js +8 -6
- package/dist/appstate/utils.js +9 -34
- package/dist/auth/WaAuthClient.js +43 -61
- package/dist/auth/flow/WaAuthCredentialsFlow.js +22 -15
- package/dist/auth/index.js +1 -8
- package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/auth/pairing/WaPairingFlow.js +34 -26
- package/dist/auth/pairing/WaQrFlow.js +37 -24
- package/dist/client/WaClient.js +275 -324
- package/dist/client/WaClientFactory.js +500 -133
- package/dist/client/connection/WaConnectionManager.js +301 -0
- package/dist/client/connection/WaKeyShareCoordinator.js +63 -0
- package/dist/client/connection/WaReceiptQueue.js +51 -0
- package/dist/client/coordinators/WaAppStateMutationCoordinator.js +471 -0
- package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
- package/dist/client/coordinators/WaGroupCoordinator.js +30 -16
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +439 -701
- package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
- package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
- package/dist/client/coordinators/WaRetryCoordinator.js +242 -57
- package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
- package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
- package/dist/client/dirty.js +74 -48
- package/dist/client/events/chat.js +4 -3
- package/dist/client/events/devices.js +72 -0
- package/dist/client/events/group.js +62 -47
- package/dist/client/events/identity.js +22 -0
- package/dist/client/events/privacy-token.js +39 -0
- package/dist/client/history-sync.js +94 -63
- package/dist/client/incoming.js +60 -27
- package/dist/client/mailbox.js +24 -23
- package/dist/client/messages.js +107 -31
- package/dist/client/messaging/fanout.js +199 -0
- package/dist/client/messaging/key-protocol.js +130 -0
- package/dist/client/messaging/participants.js +193 -0
- package/dist/client/persistence/WriteBehindPersistence.js +129 -0
- package/dist/client/tokens/cs-token.js +50 -0
- package/dist/client/tokens/tc-token.js +25 -0
- package/dist/crypto/core/hkdf.js +3 -8
- package/dist/crypto/core/index.js +2 -5
- package/dist/crypto/core/keys.js +6 -7
- package/dist/crypto/core/nonce.js +2 -0
- package/dist/crypto/core/primitives.js +12 -23
- package/dist/crypto/core/random.js +26 -23
- package/dist/crypto/curves/Ed25519.js +7 -8
- package/dist/crypto/curves/X25519.js +38 -22
- package/dist/crypto/index.js +1 -3
- package/dist/crypto/math/constants.js +13 -36
- package/dist/crypto/math/edwards.js +171 -44
- package/dist/crypto/math/fe.js +706 -0
- package/dist/crypto/math/mod.js +10 -3
- package/dist/esm/appstate/WaAppStateCrypto.js +7 -14
- package/dist/esm/appstate/WaAppStateSyncClient.js +284 -172
- package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
- package/dist/esm/appstate/constants.js +3 -2
- package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/esm/appstate/index.js +2 -2
- package/dist/esm/appstate/utils.js +8 -30
- package/dist/esm/auth/WaAuthClient.js +43 -61
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +22 -15
- package/dist/esm/auth/index.js +0 -3
- package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/esm/auth/pairing/WaPairingFlow.js +28 -20
- package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
- package/dist/esm/client/WaClient.js +275 -324
- package/dist/esm/client/WaClientFactory.js +501 -134
- package/dist/esm/client/connection/WaConnectionManager.js +297 -0
- package/dist/esm/client/connection/WaKeyShareCoordinator.js +59 -0
- package/dist/esm/client/connection/WaReceiptQueue.js +47 -0
- package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +467 -0
- package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +23 -9
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +443 -705
- package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
- package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +244 -59
- package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
- package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
- package/dist/esm/client/dirty.js +69 -43
- package/dist/esm/client/events/chat.js +4 -3
- package/dist/esm/client/events/devices.js +68 -0
- package/dist/esm/client/events/group.js +53 -39
- package/dist/esm/client/events/identity.js +19 -0
- package/dist/esm/client/events/privacy-token.js +36 -0
- package/dist/esm/client/history-sync.js +91 -60
- package/dist/esm/client/incoming.js +61 -28
- package/dist/esm/client/mailbox.js +24 -23
- package/dist/esm/client/messages.js +108 -32
- package/dist/esm/client/messaging/fanout.js +196 -0
- package/dist/esm/client/messaging/key-protocol.js +127 -0
- package/dist/esm/client/messaging/participants.js +190 -0
- package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
- package/dist/esm/client/tokens/cs-token.js +46 -0
- package/dist/esm/client/tokens/tc-token.js +18 -0
- package/dist/esm/crypto/core/hkdf.js +3 -8
- package/dist/esm/crypto/core/index.js +2 -3
- package/dist/esm/crypto/core/keys.js +3 -4
- package/dist/esm/crypto/core/nonce.js +2 -0
- package/dist/esm/crypto/core/primitives.js +12 -22
- package/dist/esm/crypto/core/random.js +25 -23
- package/dist/esm/crypto/curves/Ed25519.js +4 -5
- package/dist/esm/crypto/curves/X25519.js +35 -19
- package/dist/esm/crypto/index.js +0 -1
- package/dist/esm/crypto/math/constants.js +12 -35
- package/dist/esm/crypto/math/edwards.js +174 -47
- package/dist/esm/crypto/math/fe.js +691 -0
- package/dist/esm/crypto/math/mod.js +10 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/infra/log/ConsoleLogger.js +18 -17
- package/dist/esm/infra/log/PinoLogger.js +15 -9
- package/dist/esm/infra/log/types.js +11 -1
- package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
- package/dist/esm/infra/perf/BoundedTaskQueue.js +16 -18
- package/dist/esm/infra/perf/PromiseDedup.js +20 -0
- package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
- package/dist/esm/infra/perf/StoreLock.js +77 -0
- package/dist/esm/media/WaMediaCrypto.js +96 -16
- package/dist/esm/media/WaMediaTransferClient.js +251 -91
- package/dist/esm/media/conn.js +10 -6
- package/dist/esm/media/constants.js +6 -2
- package/dist/esm/message/WaMessageClient.js +30 -32
- package/dist/esm/message/ack.js +6 -6
- package/dist/esm/message/addon-crypto.js +59 -0
- package/dist/esm/message/content.js +195 -9
- package/dist/esm/message/icdc.js +76 -0
- package/dist/esm/message/incoming.js +129 -122
- package/dist/esm/message/index.js +2 -0
- package/dist/esm/message/phash.js +3 -1
- package/dist/esm/message/reporting-token.js +425 -0
- package/dist/esm/message/use-case-secret.js +49 -0
- package/dist/esm/protocol/appstate.js +27 -0
- package/dist/esm/protocol/browser.js +10 -18
- package/dist/esm/protocol/constants.js +6 -3
- package/dist/esm/protocol/defaults.js +6 -0
- package/dist/esm/protocol/index.js +2 -11
- package/dist/esm/protocol/jid.js +133 -52
- package/dist/esm/protocol/media.js +3 -3
- package/dist/esm/protocol/message.js +61 -1
- package/dist/esm/protocol/nodes.js +4 -0
- package/dist/esm/protocol/notification.js +3 -1
- package/dist/esm/protocol/privacy-token.js +17 -0
- package/dist/esm/protocol/privacy.js +55 -0
- package/dist/esm/protocol/stream.js +26 -1
- package/dist/esm/protocol/usync.js +11 -0
- package/dist/esm/retry/codec.js +216 -0
- package/dist/esm/retry/constants.js +1 -1
- package/dist/esm/retry/index.js +3 -2
- package/dist/esm/retry/parse.js +88 -86
- package/dist/esm/retry/replay.js +54 -51
- package/dist/esm/retry/tracker.js +94 -0
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +276 -92
- package/dist/esm/signal/api/SignalDigestSyncApi.js +17 -8
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +67 -37
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +86 -67
- package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/esm/signal/api/SignalSessionSyncApi.js +36 -34
- package/dist/esm/signal/api/result-map.js +10 -0
- package/dist/esm/signal/constants.js +0 -4
- package/dist/esm/signal/crypto/WaAdvSignature.js +13 -9
- package/dist/esm/signal/{store/sqlite.js → encoding.js} +93 -60
- package/dist/esm/signal/group/SenderKeyChain.js +28 -23
- package/dist/esm/signal/group/SenderKeyCodec.js +5 -6
- package/dist/esm/signal/group/SenderKeyManager.js +144 -115
- package/dist/esm/signal/index.js +2 -0
- package/dist/esm/signal/registration/keygen.js +6 -2
- package/dist/esm/signal/registration/utils.js +1 -0
- package/dist/esm/signal/session/SignalProtocol.js +164 -53
- package/dist/esm/signal/session/SignalRatchet.js +24 -15
- package/dist/esm/signal/session/SignalSession.js +14 -9
- package/dist/esm/signal/session/resolver.js +221 -0
- package/dist/esm/store/contracts/privacy-token.store.js +1 -0
- package/dist/esm/store/createStore.js +100 -188
- package/dist/esm/store/index.js +1 -10
- package/dist/esm/store/locks/appstate.lock.js +26 -0
- package/dist/esm/store/locks/auth.lock.js +15 -0
- package/dist/esm/store/locks/contact.lock.js +20 -0
- package/dist/esm/store/locks/device-list.lock.js +20 -0
- package/dist/esm/store/locks/message.lock.js +21 -0
- package/dist/esm/store/locks/participants.lock.js +20 -0
- package/dist/esm/store/locks/privacy-token.lock.js +18 -0
- package/dist/esm/store/locks/retry.lock.js +29 -0
- package/dist/esm/store/locks/sender-key.lock.js +52 -0
- package/dist/esm/store/locks/signal.lock.js +63 -0
- package/dist/esm/store/locks/thread.lock.js +21 -0
- package/dist/esm/store/noop.store.js +4 -7
- package/dist/esm/store/providers/memory/appstate.store.js +38 -16
- package/dist/esm/store/providers/memory/contact.store.js +5 -0
- package/dist/esm/store/providers/memory/device-list.store.js +12 -34
- package/dist/esm/store/providers/memory/message.store.js +11 -5
- package/dist/esm/store/providers/memory/participants.store.js +1 -8
- package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
- package/dist/esm/store/providers/memory/retry.store.js +77 -2
- package/dist/esm/store/providers/memory/sender-key.store.js +11 -8
- package/dist/esm/store/providers/memory/signal.store.js +47 -18
- package/dist/esm/store/providers/memory/thread.store.js +5 -0
- package/dist/esm/transport/WaComms.js +28 -24
- package/dist/esm/transport/WaWebSocket.js +115 -18
- package/dist/esm/transport/binary/constants.js +0 -30
- package/dist/esm/transport/binary/decoder.js +8 -8
- package/dist/esm/transport/binary/encoder.js +10 -9
- package/dist/esm/transport/binary/index.js +0 -1
- package/dist/esm/transport/index.js +1 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
- package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -21
- package/dist/esm/transport/node/WaNodeTransport.js +0 -3
- package/dist/esm/transport/node/builders/{accountSync.js → account-sync.js} +16 -36
- package/dist/esm/transport/node/builders/business.js +129 -0
- package/dist/esm/transport/node/builders/global.js +370 -0
- package/dist/esm/transport/node/builders/index.js +7 -3
- package/dist/esm/transport/node/builders/message.js +63 -230
- package/dist/esm/transport/node/builders/pairing.js +2 -27
- package/dist/esm/transport/node/builders/privacy-token.js +41 -0
- package/dist/esm/transport/node/builders/privacy.js +48 -0
- package/dist/esm/transport/node/builders/profile.js +70 -0
- package/dist/esm/transport/node/builders/retry.js +10 -22
- package/dist/esm/transport/node/builders/usync.js +45 -0
- package/dist/esm/transport/node/helpers.js +125 -5
- package/dist/esm/transport/node/usync.js +5 -0
- package/dist/esm/transport/node/xml.js +35 -14
- package/dist/esm/transport/noise/WaClientPayload.js +10 -10
- package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
- package/dist/esm/transport/noise/WaNoiseCert.js +4 -7
- package/dist/esm/transport/noise/WaNoiseSession.js +77 -29
- package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/esm/transport/proxy.js +27 -0
- package/dist/esm/transport/stream/parse.js +17 -48
- package/dist/esm/util/bytes.js +67 -45
- package/dist/esm/util/coercion.js +6 -14
- package/dist/esm/util/index.js +5 -0
- package/dist/esm/util/primitives.js +40 -14
- package/dist/index.js +7 -1
- package/dist/infra/log/ConsoleLogger.js +18 -17
- package/dist/infra/log/PinoLogger.js +15 -9
- package/dist/infra/log/types.js +12 -0
- package/dist/infra/perf/BackgroundQueue.js +482 -0
- package/dist/infra/perf/BoundedTaskQueue.js +16 -18
- package/dist/infra/perf/PromiseDedup.js +24 -0
- package/dist/infra/perf/SharedExclusiveGate.js +113 -0
- package/dist/infra/perf/StoreLock.js +81 -0
- package/dist/media/WaMediaCrypto.js +95 -15
- package/dist/media/WaMediaTransferClient.js +284 -91
- package/dist/media/conn.js +10 -6
- package/dist/media/constants.js +6 -2
- package/dist/message/WaMessageClient.js +31 -33
- package/dist/message/ack.js +6 -6
- package/dist/message/addon-crypto.js +65 -0
- package/dist/message/content.js +198 -9
- package/dist/message/icdc.js +81 -0
- package/dist/message/incoming.js +127 -120
- package/dist/message/index.js +2 -0
- package/dist/message/phash.js +3 -1
- package/dist/message/reporting-token.js +429 -0
- package/dist/message/use-case-secret.js +55 -0
- package/dist/protocol/appstate.js +28 -1
- package/dist/protocol/browser.js +10 -18
- package/dist/protocol/constants.js +26 -1
- package/dist/protocol/defaults.js +6 -0
- package/dist/protocol/index.js +23 -42
- package/dist/protocol/jid.js +140 -52
- package/dist/protocol/media.js +3 -3
- package/dist/protocol/message.js +62 -2
- package/dist/protocol/nodes.js +4 -0
- package/dist/protocol/notification.js +3 -1
- package/dist/protocol/privacy-token.js +20 -0
- package/dist/protocol/privacy.js +58 -0
- package/dist/protocol/stream.js +27 -2
- package/dist/protocol/usync.js +14 -0
- package/dist/retry/codec.js +220 -0
- package/dist/retry/constants.js +1 -1
- package/dist/retry/index.js +7 -5
- package/dist/retry/parse.js +88 -85
- package/dist/retry/replay.js +52 -49
- package/dist/retry/tracker.js +97 -0
- package/dist/signal/api/SignalDeviceSyncApi.js +273 -89
- package/dist/signal/api/SignalDigestSyncApi.js +17 -8
- package/dist/signal/api/SignalIdentitySyncApi.js +66 -36
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +82 -63
- package/dist/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/signal/api/SignalSessionSyncApi.js +36 -34
- package/dist/signal/api/result-map.js +13 -0
- package/dist/signal/constants.js +1 -5
- package/dist/signal/crypto/WaAdvSignature.js +11 -7
- package/dist/signal/{store/sqlite.js → encoding.js} +94 -61
- package/dist/signal/group/SenderKeyChain.js +27 -22
- package/dist/signal/group/SenderKeyCodec.js +5 -6
- package/dist/signal/group/SenderKeyManager.js +144 -115
- package/dist/signal/index.js +15 -1
- package/dist/signal/registration/keygen.js +6 -2
- package/dist/signal/registration/utils.js +1 -0
- package/dist/signal/session/SignalProtocol.js +164 -53
- package/dist/signal/session/SignalRatchet.js +24 -15
- package/dist/signal/session/SignalSession.js +14 -9
- package/dist/signal/session/resolver.js +224 -0
- package/dist/store/contracts/privacy-token.store.js +2 -0
- package/dist/store/createStore.js +100 -188
- package/dist/store/index.js +15 -33
- package/dist/store/locks/appstate.lock.js +29 -0
- package/dist/store/locks/auth.lock.js +18 -0
- package/dist/store/locks/contact.lock.js +23 -0
- package/dist/store/locks/device-list.lock.js +23 -0
- package/dist/store/locks/message.lock.js +24 -0
- package/dist/store/locks/participants.lock.js +23 -0
- package/dist/store/locks/privacy-token.lock.js +21 -0
- package/dist/store/locks/retry.lock.js +32 -0
- package/dist/store/locks/sender-key.lock.js +55 -0
- package/dist/store/locks/signal.lock.js +66 -0
- package/dist/store/locks/thread.lock.js +24 -0
- package/dist/store/noop.store.js +4 -7
- package/dist/store/providers/memory/appstate.store.js +36 -14
- package/dist/store/providers/memory/contact.store.js +5 -0
- package/dist/store/providers/memory/device-list.store.js +12 -34
- package/dist/store/providers/memory/message.store.js +11 -5
- package/dist/store/providers/memory/participants.store.js +1 -8
- package/dist/store/providers/memory/privacy-token.store.js +47 -0
- package/dist/store/providers/memory/retry.store.js +77 -2
- package/dist/store/providers/memory/sender-key.store.js +14 -11
- package/dist/store/providers/memory/signal.store.js +54 -25
- package/dist/store/providers/memory/thread.store.js +5 -0
- package/dist/transport/WaComms.js +30 -26
- package/dist/transport/WaWebSocket.js +148 -18
- package/dist/transport/binary/constants.js +1 -31
- package/dist/transport/binary/decoder.js +8 -8
- package/dist/transport/binary/encoder.js +10 -9
- package/dist/transport/binary/index.js +0 -4
- package/dist/transport/index.js +7 -1
- package/dist/transport/keepalive/WaKeepAlive.js +1 -7
- package/dist/transport/node/WaNodeOrchestrator.js +25 -21
- package/dist/transport/node/WaNodeTransport.js +0 -3
- package/dist/transport/node/builders/{accountSync.js → account-sync.js} +15 -35
- package/dist/transport/node/builders/business.js +137 -0
- package/dist/transport/node/builders/global.js +375 -0
- package/dist/transport/node/builders/index.js +29 -17
- package/dist/transport/node/builders/message.js +64 -236
- package/dist/transport/node/builders/pairing.js +2 -29
- package/dist/transport/node/builders/privacy-token.js +46 -0
- package/dist/transport/node/builders/privacy.js +55 -0
- package/dist/transport/node/builders/profile.js +78 -0
- package/dist/transport/node/builders/retry.js +9 -21
- package/dist/transport/node/builders/usync.js +49 -0
- package/dist/transport/node/helpers.js +131 -4
- package/dist/transport/node/usync.js +8 -0
- package/dist/transport/node/xml.js +35 -14
- package/dist/transport/noise/WaClientPayload.js +13 -13
- package/dist/transport/noise/WaFrameCodec.js +47 -32
- package/dist/transport/noise/WaNoiseCert.js +5 -8
- package/dist/transport/noise/WaNoiseSession.js +77 -29
- package/dist/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/transport/proxy.js +34 -0
- package/dist/transport/stream/parse.js +20 -52
- package/dist/types/appstate/WaAppStateCrypto.d.ts +0 -1
- package/dist/types/appstate/WaAppStateSyncClient.d.ts +5 -2
- package/dist/types/appstate/constants.d.ts +1 -0
- package/dist/types/appstate/encoding.d.ts +7 -0
- package/dist/types/appstate/index.d.ts +3 -3
- package/dist/types/appstate/utils.d.ts +0 -3
- package/dist/types/auth/WaAuthClient.d.ts +10 -12
- package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
- package/dist/types/auth/index.d.ts +0 -4
- package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
- package/dist/types/auth/types.d.ts +7 -9
- package/dist/types/client/WaClient.d.ts +42 -25
- package/dist/types/client/WaClientFactory.d.ts +33 -26
- package/dist/types/client/connection/WaConnectionManager.d.ts +66 -0
- package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +14 -0
- package/dist/types/client/connection/WaReceiptQueue.d.ts +13 -0
- package/dist/types/client/coordinators/WaAppStateMutationCoordinator.d.ts +46 -0
- package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -2
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +29 -38
- package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
- package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
- package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +8 -0
- package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
- package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
- package/dist/types/client/dirty.d.ts +1 -0
- package/dist/types/client/events/devices.d.ts +20 -0
- package/dist/types/client/events/group.d.ts +2 -1
- package/dist/types/client/events/identity.d.ts +9 -0
- package/dist/types/client/events/privacy-token.d.ts +7 -0
- package/dist/types/client/history-sync.d.ts +9 -6
- package/dist/types/client/incoming.d.ts +3 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/mailbox.d.ts +3 -5
- package/dist/types/client/messages.d.ts +1 -2
- package/dist/types/client/messaging/fanout.d.ts +14 -0
- package/dist/types/client/messaging/key-protocol.d.ts +18 -0
- package/dist/types/client/messaging/participants.d.ts +13 -0
- package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
- package/dist/types/client/tokens/cs-token.d.ts +10 -0
- package/dist/types/client/tokens/tc-token.d.ts +5 -0
- package/dist/types/client/types.d.ts +75 -4
- package/dist/types/crypto/core/hkdf.d.ts +0 -6
- package/dist/types/crypto/core/index.d.ts +2 -3
- package/dist/types/crypto/core/nonce.d.ts +2 -0
- package/dist/types/crypto/core/primitives.d.ts +0 -1
- package/dist/types/crypto/core/random.d.ts +2 -7
- package/dist/types/crypto/index.d.ts +0 -1
- package/dist/types/crypto/math/constants.d.ts +4 -2
- package/dist/types/crypto/math/fe.d.ts +30 -0
- package/dist/types/crypto/math/mod.d.ts +0 -2
- package/dist/types/crypto/math/types.d.ts +11 -4
- package/dist/types/index.d.ts +5 -3
- package/dist/types/infra/log/ConsoleLogger.d.ts +2 -1
- package/dist/types/infra/log/PinoLogger.d.ts +1 -1
- package/dist/types/infra/log/types.d.ts +1 -0
- package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
- package/dist/types/infra/perf/BoundedTaskQueue.d.ts +1 -1
- package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
- package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
- package/dist/types/infra/perf/StoreLock.d.ts +10 -0
- package/dist/types/media/WaMediaCrypto.d.ts +3 -2
- package/dist/types/media/WaMediaTransferClient.d.ts +16 -15
- package/dist/types/media/constants.d.ts +1 -1
- package/dist/types/media/index.d.ts +1 -1
- package/dist/types/media/types.d.ts +15 -2
- package/dist/types/message/addon-crypto.d.ts +25 -0
- package/dist/types/message/content.d.ts +8 -0
- package/dist/types/message/icdc.d.ts +13 -0
- package/dist/types/message/index.d.ts +2 -0
- package/dist/types/message/reporting-token.d.ts +18 -0
- package/dist/types/message/types.d.ts +45 -6
- package/dist/types/message/use-case-secret.d.ts +20 -0
- package/dist/types/protocol/appstate.d.ts +47 -0
- package/dist/types/protocol/constants.d.ts +8 -3
- package/dist/types/protocol/defaults.d.ts +6 -0
- package/dist/types/protocol/index.d.ts +2 -11
- package/dist/types/protocol/jid.d.ts +22 -5
- package/dist/types/protocol/message.d.ts +60 -0
- package/dist/types/protocol/nodes.d.ts +4 -0
- package/dist/types/protocol/notification.d.ts +2 -0
- package/dist/types/protocol/privacy-token.d.ts +17 -0
- package/dist/types/protocol/privacy.d.ts +75 -0
- package/dist/types/protocol/stream.d.ts +30 -0
- package/dist/types/protocol/usync.d.ts +11 -0
- package/dist/types/retry/codec.d.ts +3 -0
- package/dist/types/retry/index.d.ts +4 -3
- package/dist/types/retry/parse.d.ts +5 -2
- package/dist/types/retry/replay.d.ts +0 -4
- package/dist/types/retry/tracker.d.ts +20 -0
- package/dist/types/retry/types.d.ts +10 -4
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +15 -2
- package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
- package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
- package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
- package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
- package/dist/types/signal/api/result-map.d.ts +1 -0
- package/dist/types/signal/constants.d.ts +0 -3
- package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
- package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
- package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
- package/dist/types/signal/index.d.ts +3 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +19 -4
- package/dist/types/signal/session/resolver.d.ts +22 -0
- package/dist/types/store/contracts/appstate.store.d.ts +4 -1
- package/dist/types/store/contracts/contact.store.d.ts +1 -0
- package/dist/types/store/contracts/device-list.store.d.ts +0 -3
- package/dist/types/store/contracts/message.store.d.ts +1 -0
- package/dist/types/store/contracts/participants.store.d.ts +0 -1
- package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
- package/dist/types/store/contracts/retry.store.d.ts +7 -0
- package/dist/types/store/contracts/sender-key.store.d.ts +0 -1
- package/dist/types/store/contracts/signal.store.d.ts +13 -0
- package/dist/types/store/contracts/thread.store.d.ts +1 -0
- package/dist/types/store/createStore.d.ts +1 -1
- package/dist/types/store/index.d.ts +5 -13
- package/dist/types/store/locks/appstate.lock.d.ts +3 -0
- package/dist/types/store/locks/auth.lock.d.ts +3 -0
- package/dist/types/store/locks/contact.lock.d.ts +3 -0
- package/dist/types/store/locks/device-list.lock.d.ts +2 -0
- package/dist/types/store/locks/message.lock.d.ts +3 -0
- package/dist/types/store/locks/participants.lock.d.ts +2 -0
- package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
- package/dist/types/store/locks/retry.lock.d.ts +2 -0
- package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
- package/dist/types/store/locks/signal.lock.d.ts +3 -0
- package/dist/types/store/locks/thread.lock.d.ts +3 -0
- package/dist/types/store/providers/memory/appstate.store.d.ts +3 -1
- package/dist/types/store/providers/memory/contact.store.d.ts +1 -0
- package/dist/types/store/providers/memory/device-list.store.d.ts +0 -3
- package/dist/types/store/providers/memory/message.store.d.ts +1 -0
- package/dist/types/store/providers/memory/participants.store.d.ts +0 -1
- package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
- package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
- package/dist/types/store/providers/memory/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/memory/signal.store.d.ts +8 -1
- package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
- package/dist/types/store/types.d.ts +49 -58
- package/dist/types/transport/WaWebSocket.d.ts +3 -1
- package/dist/types/transport/binary/constants.d.ts +0 -30
- package/dist/types/transport/binary/index.d.ts +0 -1
- package/dist/types/transport/index.d.ts +2 -1
- package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
- package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
- package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
- package/dist/types/transport/node/builders/business.d.ts +29 -0
- package/dist/types/transport/node/builders/global.d.ts +102 -0
- package/dist/types/transport/node/builders/group.d.ts +4 -6
- package/dist/types/transport/node/builders/index.d.ts +7 -3
- package/dist/types/transport/node/builders/message.d.ts +20 -30
- package/dist/types/transport/node/builders/pairing.d.ts +0 -2
- package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
- package/dist/types/transport/node/builders/privacy.d.ts +7 -0
- package/dist/types/transport/node/builders/profile.d.ts +8 -0
- package/dist/types/transport/node/builders/retry.d.ts +2 -5
- package/dist/types/transport/node/builders/usync.d.ts +21 -0
- package/dist/types/transport/node/helpers.d.ts +13 -0
- package/dist/types/transport/node/usync.d.ts +2 -0
- package/dist/types/transport/noise/WaFrameCodec.d.ts +3 -0
- package/dist/types/transport/noise/WaNoiseSession.d.ts +4 -2
- package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
- package/dist/types/transport/proxy.d.ts +6 -0
- package/dist/types/transport/stream/parse.d.ts +0 -1
- package/dist/types/transport/types.d.ts +18 -1
- package/dist/types/util/bytes.d.ts +5 -0
- package/dist/types/util/index.d.ts +5 -0
- package/dist/types/util/primitives.d.ts +2 -0
- package/dist/util/bytes.js +72 -46
- package/dist/util/coercion.js +6 -14
- package/dist/util/index.js +23 -0
- package/dist/util/primitives.js +42 -14
- package/package.json +52 -9
- package/proto/index.js +1 -1
- package/dist/crypto/core/constants.js +0 -4
- package/dist/crypto/core/encoding.js +0 -29
- package/dist/esm/crypto/core/constants.js +0 -1
- package/dist/esm/crypto/core/encoding.js +0 -25
- package/dist/esm/retry/outbound.js +0 -83
- package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
- package/dist/esm/store/providers/sqlite/appstate.store.js +0 -169
- package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
- package/dist/esm/store/providers/sqlite/connection.js +0 -240
- package/dist/esm/store/providers/sqlite/contact.store.js +0 -61
- package/dist/esm/store/providers/sqlite/device-list.store.js +0 -155
- package/dist/esm/store/providers/sqlite/message.store.js +0 -119
- package/dist/esm/store/providers/sqlite/migrations.js +0 -347
- package/dist/esm/store/providers/sqlite/participants.store.js +0 -85
- package/dist/esm/store/providers/sqlite/retry.store.js +0 -144
- package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -203
- package/dist/esm/store/providers/sqlite/signal.store.js +0 -353
- package/dist/esm/store/providers/sqlite/thread.store.js +0 -72
- package/dist/esm/util/base64.js +0 -18
- package/dist/esm/util/signal-address.js +0 -5
- package/dist/retry/outbound.js +0 -88
- package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
- package/dist/store/providers/sqlite/appstate.store.js +0 -173
- package/dist/store/providers/sqlite/auth.store.js +0 -180
- package/dist/store/providers/sqlite/connection.js +0 -276
- package/dist/store/providers/sqlite/contact.store.js +0 -65
- package/dist/store/providers/sqlite/device-list.store.js +0 -159
- package/dist/store/providers/sqlite/message.store.js +0 -123
- package/dist/store/providers/sqlite/migrations.js +0 -350
- package/dist/store/providers/sqlite/participants.store.js +0 -89
- package/dist/store/providers/sqlite/retry.store.js +0 -148
- package/dist/store/providers/sqlite/sender-key.store.js +0 -207
- package/dist/store/providers/sqlite/signal.store.js +0 -357
- package/dist/store/providers/sqlite/thread.store.js +0 -76
- package/dist/types/appstate/store/sqlite.d.ts +0 -21
- package/dist/types/crypto/core/constants.d.ts +0 -1
- package/dist/types/crypto/core/encoding.d.ts +0 -11
- package/dist/types/retry/outbound.d.ts +0 -4
- package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
- package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
- package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
- package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -10
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -18
- package/dist/types/store/providers/sqlite/message.store.d.ts +0 -11
- package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -13
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -16
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -25
- package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -46
- package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -11
- package/dist/types/util/base64.d.ts +0 -4
- package/dist/types/util/signal-address.d.ts +0 -2
- package/dist/util/base64.js +0 -24
- package/dist/util/signal-address.js +0 -8
- /package/dist/types/transport/node/builders/{accountSync.d.ts → account-sync.d.ts} +0 -0
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import { proto } from '../../proto.js';
|
|
2
2
|
import { WA_MESSAGE_TAGS } from '../../protocol/constants.js';
|
|
3
|
-
import { isGroupOrBroadcastJid, normalizeDeviceJid,
|
|
3
|
+
import { isGroupOrBroadcastJid, normalizeDeviceJid, parseJidFull } from '../../protocol/jid.js';
|
|
4
4
|
import { MAX_RETRY_ATTEMPTS, RETRY_KEYS_MIN_COUNT, RETRY_OUTBOUND_TTL_MS, RETRY_REASON } from '../../retry/constants.js';
|
|
5
|
-
import { pickRetryStateMax } from '../../retry/
|
|
6
|
-
import { parseRetryReceiptRequest } from '../../retry/parse.js';
|
|
5
|
+
import { parseRetryReceiptRequest, pickRetryStateMax } from '../../retry/parse.js';
|
|
7
6
|
import { mapRetryReasonFromError } from '../../retry/reason.js';
|
|
8
7
|
import { WaRetryReplayService } from '../../retry/replay.js';
|
|
9
8
|
import { generatePreKeyPair } from '../../signal/registration/keygen.js';
|
|
10
|
-
import {
|
|
9
|
+
import { buildAckNode } from '../../transport/node/builders/global.js';
|
|
11
10
|
import { buildRetryReceiptNode } from '../../transport/node/builders/retry.js';
|
|
11
|
+
import { uint8Equal } from '../../util/bytes.js';
|
|
12
|
+
import { setBoundedMapEntry } from '../../util/collections.js';
|
|
12
13
|
import { toError } from '../../util/primitives.js';
|
|
14
|
+
const RETRY_CLEANUP_INTERVAL_MS = 30000;
|
|
15
|
+
const RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES = 8192;
|
|
13
16
|
function getRetryReasonName(code) {
|
|
14
17
|
if (code === undefined) {
|
|
15
18
|
return undefined;
|
|
16
19
|
}
|
|
17
|
-
const
|
|
18
|
-
|
|
20
|
+
for (const reasonName in RETRY_REASON) {
|
|
21
|
+
if (RETRY_REASON[reasonName] === code)
|
|
22
|
+
return reasonName;
|
|
23
|
+
}
|
|
24
|
+
return 'unknown';
|
|
19
25
|
}
|
|
20
26
|
function getRemoteRetryReasonLogFields(reason) {
|
|
21
27
|
return {
|
|
@@ -26,6 +32,7 @@ function getRemoteRetryReasonLogFields(reason) {
|
|
|
26
32
|
}
|
|
27
33
|
export class WaRetryCoordinator {
|
|
28
34
|
constructor(options) {
|
|
35
|
+
this.nextRetryCleanupAtMs = 0;
|
|
29
36
|
this.logger = options.logger;
|
|
30
37
|
this.retryStore = options.retryStore;
|
|
31
38
|
this.retryTtlMs = this.retryStore.getTtlMs?.() ?? RETRY_OUTBOUND_TTL_MS;
|
|
@@ -47,6 +54,7 @@ export class WaRetryCoordinator {
|
|
|
47
54
|
getCurrentSignedIdentity: this.getCurrentSignedIdentity
|
|
48
55
|
});
|
|
49
56
|
this.retryProcessingByMessageId = new Map();
|
|
57
|
+
this.retrySessionBaseKeys = new Map();
|
|
50
58
|
}
|
|
51
59
|
async onDecryptFailure(context, error) {
|
|
52
60
|
try {
|
|
@@ -71,12 +79,23 @@ export class WaRetryCoordinator {
|
|
|
71
79
|
if (!this.isRetryReceiptNode(receiptNode)) {
|
|
72
80
|
return;
|
|
73
81
|
}
|
|
82
|
+
let shouldAck = false;
|
|
74
83
|
try {
|
|
75
|
-
await this.
|
|
76
|
-
const
|
|
84
|
+
await this.maybeCleanupRetryStore(Date.now());
|
|
85
|
+
const expectedToJids = [];
|
|
86
|
+
const meJid = this.getCurrentMeJid()?.trim();
|
|
87
|
+
const meLid = this.getCurrentMeLid()?.trim();
|
|
88
|
+
if (meJid) {
|
|
89
|
+
expectedToJids.push(meJid);
|
|
90
|
+
}
|
|
91
|
+
if (meLid) {
|
|
92
|
+
expectedToJids.push(meLid);
|
|
93
|
+
}
|
|
94
|
+
const request = parseRetryReceiptRequest(receiptNode, expectedToJids.length > 0 ? { expectedToJids } : undefined);
|
|
77
95
|
if (!request) {
|
|
78
96
|
return;
|
|
79
97
|
}
|
|
98
|
+
shouldAck = true;
|
|
80
99
|
await this.handleParsedRetryRequest(receiptNode, request);
|
|
81
100
|
}
|
|
82
101
|
catch (error) {
|
|
@@ -88,7 +107,9 @@ export class WaRetryCoordinator {
|
|
|
88
107
|
});
|
|
89
108
|
}
|
|
90
109
|
finally {
|
|
91
|
-
|
|
110
|
+
if (shouldAck) {
|
|
111
|
+
await this.sendRetryAckSafe(receiptNode);
|
|
112
|
+
}
|
|
92
113
|
}
|
|
93
114
|
}
|
|
94
115
|
isRetryReceiptNode(node) {
|
|
@@ -97,10 +118,7 @@ export class WaRetryCoordinator {
|
|
|
97
118
|
}
|
|
98
119
|
async prepareDecryptFailureRetry(context, error) {
|
|
99
120
|
const nowMs = Date.now();
|
|
100
|
-
const
|
|
101
|
-
this.retryStore.cleanupExpired(nowMs),
|
|
102
|
-
this.signalStore.getRegistrationInfo()
|
|
103
|
-
]);
|
|
121
|
+
const registrationInfo = await this.signalStore.getRegistrationInfo();
|
|
104
122
|
if (!registrationInfo) {
|
|
105
123
|
this.logger.warn('retry receipt skipped: missing local registration info', {
|
|
106
124
|
id: context.stanzaId,
|
|
@@ -127,7 +145,6 @@ export class WaRetryCoordinator {
|
|
|
127
145
|
to: context.from,
|
|
128
146
|
participant: context.participant,
|
|
129
147
|
recipient: context.recipient,
|
|
130
|
-
from: this.getCurrentMeJid() ?? undefined,
|
|
131
148
|
originalMsgId: context.stanzaId,
|
|
132
149
|
retryCount: prepared.retryCount,
|
|
133
150
|
t: prepared.timestamp,
|
|
@@ -195,6 +212,22 @@ export class WaRetryCoordinator {
|
|
|
195
212
|
});
|
|
196
213
|
return null;
|
|
197
214
|
}
|
|
215
|
+
let requesterAddress;
|
|
216
|
+
let requesterNormalizedDeviceJid;
|
|
217
|
+
try {
|
|
218
|
+
const requesterParsed = parseJidFull(requesterJid);
|
|
219
|
+
requesterAddress = requesterParsed.address;
|
|
220
|
+
requesterNormalizedDeviceJid = requesterParsed.normalizedJid;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
this.logger.info('retry request rejected: invalid requester jid', {
|
|
224
|
+
id: request.stanzaId,
|
|
225
|
+
originalMsgId: request.originalMsgId,
|
|
226
|
+
requester: requesterJid,
|
|
227
|
+
message: toError(error).message
|
|
228
|
+
});
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
198
231
|
if (request.retryCount >= MAX_RETRY_ATTEMPTS) {
|
|
199
232
|
this.logger.info('retry request rejected: retry count exceeded', {
|
|
200
233
|
id: request.stanzaId,
|
|
@@ -214,7 +247,7 @@ export class WaRetryCoordinator {
|
|
|
214
247
|
});
|
|
215
248
|
return null;
|
|
216
249
|
}
|
|
217
|
-
const sessionReady = await this.updateLocalSessionFromRetryRequest(request, requesterJid);
|
|
250
|
+
const sessionReady = await this.updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
218
251
|
if (!sessionReady) {
|
|
219
252
|
this.logger.info('retry request rejected: missing compatible session', {
|
|
220
253
|
id: request.stanzaId,
|
|
@@ -225,7 +258,7 @@ export class WaRetryCoordinator {
|
|
|
225
258
|
});
|
|
226
259
|
return null;
|
|
227
260
|
}
|
|
228
|
-
const authorization = await this.authorizeRetryRequest(request, outbound, requesterJid);
|
|
261
|
+
const authorization = await this.authorizeRetryRequest(request, outbound, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
229
262
|
if (!authorization.authorized) {
|
|
230
263
|
this.logger.info('retry request rejected', {
|
|
231
264
|
id: request.stanzaId,
|
|
@@ -239,6 +272,8 @@ export class WaRetryCoordinator {
|
|
|
239
272
|
}
|
|
240
273
|
return {
|
|
241
274
|
requesterJid,
|
|
275
|
+
requesterAddress,
|
|
276
|
+
requesterNormalizedDeviceJid,
|
|
242
277
|
outbound
|
|
243
278
|
};
|
|
244
279
|
}
|
|
@@ -258,20 +293,36 @@ export class WaRetryCoordinator {
|
|
|
258
293
|
if (!nextState) {
|
|
259
294
|
return;
|
|
260
295
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
296
|
+
await this.runRetryTaskSerialized(messageId, async () => {
|
|
297
|
+
const current = await this.retryStore.getOutboundMessage(messageId);
|
|
298
|
+
if (!current) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const nowMs = Date.now();
|
|
302
|
+
const expiresAtMs = nowMs + this.retryTtlMs;
|
|
303
|
+
const merged = pickRetryStateMax(current.state, nextState);
|
|
304
|
+
if (merged !== current.state) {
|
|
305
|
+
await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, expiresAtMs);
|
|
306
|
+
}
|
|
307
|
+
const requesterJid = receiptNode.attrs.participant ?? receiptNode.attrs.from;
|
|
308
|
+
if (!requesterJid) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
await this.retryStore.markOutboundRequesterDelivered(messageId, normalizeDeviceJid(requesterJid), nowMs, expiresAtMs);
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
this.logger.warn('failed to update outbound requester delivery state', {
|
|
316
|
+
id: messageId,
|
|
317
|
+
requester: requesterJid,
|
|
318
|
+
message: toError(error).message
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
});
|
|
271
322
|
}
|
|
272
323
|
async runRetryTaskSerialized(messageId, task) {
|
|
273
324
|
const previous = this.retryProcessingByMessageId.get(messageId) ?? Promise.resolve();
|
|
274
|
-
const current = previous.
|
|
325
|
+
const current = previous.then(task);
|
|
275
326
|
const tracker = current.then(() => undefined, () => undefined);
|
|
276
327
|
this.retryProcessingByMessageId.set(messageId, tracker);
|
|
277
328
|
try {
|
|
@@ -311,18 +362,47 @@ export class WaRetryCoordinator {
|
|
|
311
362
|
: undefined
|
|
312
363
|
};
|
|
313
364
|
}
|
|
314
|
-
async updateLocalSessionFromRetryRequest(request, requesterJid) {
|
|
315
|
-
await
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
365
|
+
async updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
366
|
+
const [, currentSession] = await Promise.all([
|
|
367
|
+
this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress),
|
|
368
|
+
this.signalStore.getSession(requesterAddress)
|
|
369
|
+
]);
|
|
370
|
+
const regIdMismatch = !!currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId;
|
|
371
|
+
if (regIdMismatch && !request.keyBundle) {
|
|
372
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
320
373
|
}
|
|
321
374
|
if (request.keyBundle) {
|
|
322
|
-
if (!request.keyBundle.key) {
|
|
375
|
+
if (!request.keyBundle.key || !request.keyBundle.skey.signature) {
|
|
323
376
|
return false;
|
|
324
377
|
}
|
|
325
|
-
|
|
378
|
+
if (request.offline) {
|
|
379
|
+
if (!currentSession) {
|
|
380
|
+
this.logger.info('retry request rejected: offline retry missing existing session', {
|
|
381
|
+
id: request.stanzaId,
|
|
382
|
+
originalMsgId: request.originalMsgId,
|
|
383
|
+
requester: requesterJid,
|
|
384
|
+
remoteRetryCount: request.retryCount,
|
|
385
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
386
|
+
});
|
|
387
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
if (regIdMismatch) {
|
|
391
|
+
this.logger.info('retry request rejected: offline retry registration id mismatch', {
|
|
392
|
+
id: request.stanzaId,
|
|
393
|
+
originalMsgId: request.originalMsgId,
|
|
394
|
+
requester: requesterJid,
|
|
395
|
+
remoteRetryCount: request.retryCount,
|
|
396
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
397
|
+
});
|
|
398
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (regIdMismatch) {
|
|
403
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
404
|
+
}
|
|
405
|
+
await this.signalProtocol.establishOutgoingSession(requesterAddress, {
|
|
326
406
|
regId: request.regId,
|
|
327
407
|
identity: request.keyBundle.identity,
|
|
328
408
|
signedKey: {
|
|
@@ -335,25 +415,57 @@ export class WaRetryCoordinator {
|
|
|
335
415
|
publicKey: request.keyBundle.key.publicKey
|
|
336
416
|
}
|
|
337
417
|
});
|
|
418
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
419
|
+
}
|
|
420
|
+
const sessionStillExists = currentSession !== null && !regIdMismatch;
|
|
421
|
+
if (sessionStillExists) {
|
|
422
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
423
|
+
}
|
|
424
|
+
const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
|
|
425
|
+
if (!fetched) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
|
|
429
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
430
|
+
}
|
|
431
|
+
async applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
432
|
+
if (request.retryCount < 2) {
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
const currentSession = await this.signalStore.getSession(requesterAddress);
|
|
436
|
+
const sessionBaseKey = currentSession?.aliceBaseKey ?? null;
|
|
437
|
+
if (!sessionBaseKey) {
|
|
338
438
|
return true;
|
|
339
439
|
}
|
|
340
|
-
const
|
|
341
|
-
if (
|
|
440
|
+
const expiresAtMs = Date.now() + this.retryTtlMs;
|
|
441
|
+
if (request.retryCount === 2) {
|
|
442
|
+
this.setRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid, sessionBaseKey, expiresAtMs);
|
|
342
443
|
return true;
|
|
343
444
|
}
|
|
344
|
-
const
|
|
445
|
+
const saved = this.getRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid);
|
|
446
|
+
if (!saved || !uint8Equal(saved.baseKey, sessionBaseKey)) {
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
450
|
+
this.logger.info('retry request forcing session refresh due to repeated base key', {
|
|
451
|
+
id: request.stanzaId,
|
|
452
|
+
originalMsgId: request.originalMsgId,
|
|
453
|
+
requester: requesterJid,
|
|
454
|
+
remoteRetryCount: request.retryCount,
|
|
455
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
456
|
+
});
|
|
457
|
+
const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
|
|
345
458
|
if (!fetched) {
|
|
346
459
|
return false;
|
|
347
460
|
}
|
|
348
|
-
await this.signalProtocol.establishOutgoingSession(
|
|
461
|
+
await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
|
|
349
462
|
return true;
|
|
350
463
|
}
|
|
351
|
-
async markRetryRequesterSenderKeyAsStale(request, requesterJid) {
|
|
464
|
+
async markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress) {
|
|
352
465
|
if (!isGroupOrBroadcastJid(request.from)) {
|
|
353
466
|
return;
|
|
354
467
|
}
|
|
355
468
|
try {
|
|
356
|
-
const requesterAddress = parseSignalAddressFromJid(requesterJid);
|
|
357
469
|
const deleted = await this.senderKeyStore.markForgetSenderKey(request.from, [
|
|
358
470
|
requesterAddress
|
|
359
471
|
]);
|
|
@@ -371,12 +483,11 @@ export class WaRetryCoordinator {
|
|
|
371
483
|
});
|
|
372
484
|
}
|
|
373
485
|
}
|
|
374
|
-
async fetchMissingPreKeysSession(requesterJid, requesterRegistrationId) {
|
|
486
|
+
async fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, requesterRegistrationId) {
|
|
375
487
|
try {
|
|
376
|
-
const requesterAddress = parseSignalAddressFromJid(requesterJid);
|
|
377
488
|
const results = await this.signalMissingPreKeysSync.fetchMissingPreKeys([
|
|
378
489
|
{
|
|
379
|
-
userJid:
|
|
490
|
+
userJid: `${requesterAddress.user}@${requesterAddress.server}`,
|
|
380
491
|
devices: [
|
|
381
492
|
{
|
|
382
493
|
deviceId: requesterAddress.device,
|
|
@@ -393,8 +504,7 @@ export class WaRetryCoordinator {
|
|
|
393
504
|
});
|
|
394
505
|
return null;
|
|
395
506
|
}
|
|
396
|
-
const
|
|
397
|
-
const matched = first.devices.find((device) => normalizeDeviceJid(device.deviceJid) === requesterDeviceJid);
|
|
507
|
+
const matched = first.devices.find((device) => normalizeDeviceJid(device.deviceJid) === requesterNormalizedDeviceJid);
|
|
398
508
|
if (!matched) {
|
|
399
509
|
this.logger.warn('missing prekeys fetch did not return requested device', {
|
|
400
510
|
requester: requesterJid,
|
|
@@ -412,33 +522,59 @@ export class WaRetryCoordinator {
|
|
|
412
522
|
return null;
|
|
413
523
|
}
|
|
414
524
|
}
|
|
415
|
-
async authorizeRetryRequest(request, outbound, requesterJid) {
|
|
525
|
+
async authorizeRetryRequest(request, outbound, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
416
526
|
if (outbound.state === 'ineligible') {
|
|
417
527
|
return { authorized: false, reason: `state_${outbound.state}` };
|
|
418
528
|
}
|
|
529
|
+
let requesterStatus = null;
|
|
530
|
+
try {
|
|
531
|
+
requesterStatus = await this.retryStore.getOutboundRequesterStatus(outbound.messageId, requesterNormalizedDeviceJid);
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
this.logger.warn('failed to resolve outbound requester status from retry store', {
|
|
535
|
+
id: request.stanzaId,
|
|
536
|
+
originalMsgId: request.originalMsgId,
|
|
537
|
+
requester: requesterJid,
|
|
538
|
+
message: toError(error).message
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (requesterStatus) {
|
|
542
|
+
if (!requesterStatus.eligible) {
|
|
543
|
+
return { authorized: false, reason: 'requester_device_not_eligible' };
|
|
544
|
+
}
|
|
545
|
+
if (requesterStatus.delivered) {
|
|
546
|
+
return { authorized: false, reason: 'requester_already_delivered' };
|
|
547
|
+
}
|
|
548
|
+
}
|
|
419
549
|
const isGroupOutbound = isGroupOrBroadcastJid(outbound.toJid);
|
|
420
550
|
if (!isGroupOutbound && (outbound.state === 'read' || outbound.state === 'played')) {
|
|
421
551
|
return { authorized: false, reason: `state_${outbound.state}` };
|
|
422
552
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
553
|
+
if (!requesterStatus) {
|
|
554
|
+
const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
555
|
+
if (!requesterAuthorized) {
|
|
556
|
+
return { authorized: false, reason: 'requester_device_not_authorized' };
|
|
557
|
+
}
|
|
426
558
|
}
|
|
427
559
|
return { authorized: true };
|
|
428
560
|
}
|
|
429
|
-
async isRequesterAuthorizedDevice(requesterJid) {
|
|
561
|
+
async isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
430
562
|
try {
|
|
431
|
-
const requesterUser =
|
|
563
|
+
const requesterUser = `${requesterAddress.user}@${requesterAddress.server}`;
|
|
564
|
+
if (requesterNormalizedDeviceJid === normalizeDeviceJid(requesterUser)) {
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
432
567
|
const synced = await this.signalDeviceSync.syncDeviceList([requesterUser]);
|
|
433
568
|
const target = synced.find((entry) => entry.jid === requesterUser);
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
569
|
+
if (!target) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
for (let index = 0; index < target.deviceJids.length; index += 1) {
|
|
573
|
+
if (normalizeDeviceJid(target.deviceJids[index]) === requesterNormalizedDeviceJid) {
|
|
574
|
+
return true;
|
|
439
575
|
}
|
|
440
576
|
}
|
|
441
|
-
return
|
|
577
|
+
return false;
|
|
442
578
|
}
|
|
443
579
|
catch (error) {
|
|
444
580
|
this.logger.warn('retry authorization failed while syncing requester device list', {
|
|
@@ -476,7 +612,11 @@ export class WaRetryCoordinator {
|
|
|
476
612
|
return;
|
|
477
613
|
}
|
|
478
614
|
try {
|
|
479
|
-
await this.sendNode(
|
|
615
|
+
await this.sendNode(buildAckNode({
|
|
616
|
+
kind: 'receipt',
|
|
617
|
+
node: receiptNode,
|
|
618
|
+
retryType: true
|
|
619
|
+
}));
|
|
480
620
|
}
|
|
481
621
|
catch (error) {
|
|
482
622
|
this.logger.warn('failed to send retry ack', {
|
|
@@ -487,4 +627,49 @@ export class WaRetryCoordinator {
|
|
|
487
627
|
});
|
|
488
628
|
}
|
|
489
629
|
}
|
|
630
|
+
async maybeCleanupRetryStore(nowMs) {
|
|
631
|
+
if (nowMs < this.nextRetryCleanupAtMs) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
this.nextRetryCleanupAtMs = nowMs + RETRY_CLEANUP_INTERVAL_MS;
|
|
635
|
+
this.cleanupRetrySessionBaseKeys(nowMs);
|
|
636
|
+
try {
|
|
637
|
+
await this.retryStore.cleanupExpired(nowMs);
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
this.logger.warn('retry store cleanup failed', {
|
|
641
|
+
message: toError(error).message
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid) {
|
|
646
|
+
return `${originalMsgId}|${requesterNormalizedDeviceJid}`;
|
|
647
|
+
}
|
|
648
|
+
setRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid, baseKey, expiresAtMs) {
|
|
649
|
+
const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
|
|
650
|
+
setBoundedMapEntry(this.retrySessionBaseKeys, key, {
|
|
651
|
+
baseKey: Uint8Array.from(baseKey),
|
|
652
|
+
expiresAtMs
|
|
653
|
+
}, RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES);
|
|
654
|
+
}
|
|
655
|
+
getRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid) {
|
|
656
|
+
const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
|
|
657
|
+
const entry = this.retrySessionBaseKeys.get(key);
|
|
658
|
+
if (!entry) {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
if (entry.expiresAtMs <= Date.now()) {
|
|
662
|
+
this.retrySessionBaseKeys.delete(key);
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
return entry;
|
|
666
|
+
}
|
|
667
|
+
cleanupRetrySessionBaseKeys(nowMs) {
|
|
668
|
+
for (const [key, entry] of this.retrySessionBaseKeys) {
|
|
669
|
+
if (entry.expiresAtMs > nowMs) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
this.retrySessionBaseKeys.delete(key);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
490
675
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WA_DISCONNECT_REASONS, WA_STREAM_SIGNALING } from '../../protocol/constants.js';
|
|
1
|
+
import { WA_CONNECTION_REASONS, WA_DISCONNECT_REASONS, WA_STREAM_SIGNALING } from '../../protocol/constants.js';
|
|
2
2
|
import { toError } from '../../util/primitives.js';
|
|
3
3
|
export function createStreamControlHandler(options) {
|
|
4
4
|
const { logger, getComms, clearPendingQueries, clearMediaConnCache, disconnect, clearStoredCredentials, connect } = options;
|
|
@@ -16,7 +16,7 @@ export function createStreamControlHandler(options) {
|
|
|
16
16
|
const restartBackendAfterStreamControl = async (reason) => {
|
|
17
17
|
logger.info('restarting backend after stream control', { reason });
|
|
18
18
|
try {
|
|
19
|
-
await connect();
|
|
19
|
+
await connect(WA_CONNECTION_REASONS.RECONNECTED);
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
22
|
logger.warn('failed to restart backend after stream control', {
|
|
@@ -43,29 +43,36 @@ export function createStreamControlHandler(options) {
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
|
+
const stopCommsImmediately = () => {
|
|
47
|
+
void getComms()?.stopComms();
|
|
48
|
+
};
|
|
46
49
|
const forceLoginDueToStreamError = async (code) => {
|
|
47
|
-
|
|
50
|
+
const reason = WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGIN;
|
|
51
|
+
stopCommsImmediately();
|
|
52
|
+
await runStreamControlLifecycle(reason, async () => {
|
|
48
53
|
logger.warn('received forced login stream error; starting login lifecycle', {
|
|
49
54
|
code
|
|
50
55
|
});
|
|
51
|
-
await disconnect();
|
|
56
|
+
await disconnect(reason, true, code);
|
|
52
57
|
await clearStoredCredentials();
|
|
53
|
-
await restartBackendAfterStreamControl(
|
|
58
|
+
await restartBackendAfterStreamControl(reason);
|
|
54
59
|
});
|
|
55
60
|
};
|
|
56
|
-
const disconnectDueToStreamError = async (reason) => {
|
|
61
|
+
const disconnectDueToStreamError = async (reason, code) => {
|
|
62
|
+
stopCommsImmediately();
|
|
57
63
|
await runStreamControlLifecycle(reason, async () => {
|
|
58
64
|
logger.warn('disconnecting due to stream control node', { reason });
|
|
59
|
-
await disconnect();
|
|
65
|
+
await disconnect(reason, false, code);
|
|
60
66
|
});
|
|
61
67
|
};
|
|
62
|
-
const logoutDueToStreamError = async (reason, shouldRestartBackend) => {
|
|
68
|
+
const logoutDueToStreamError = async (reason, code, shouldRestartBackend) => {
|
|
69
|
+
stopCommsImmediately();
|
|
63
70
|
await runStreamControlLifecycle(reason, async () => {
|
|
64
71
|
logger.warn('logging out due to stream control node', {
|
|
65
72
|
reason,
|
|
66
73
|
shouldRestartBackend
|
|
67
74
|
});
|
|
68
|
-
await disconnect();
|
|
75
|
+
await disconnect(reason, true, code);
|
|
69
76
|
await clearStoredCredentials();
|
|
70
77
|
if (shouldRestartBackend) {
|
|
71
78
|
await restartBackendAfterStreamControl(reason);
|
|
@@ -86,7 +93,7 @@ export function createStreamControlHandler(options) {
|
|
|
86
93
|
return;
|
|
87
94
|
}
|
|
88
95
|
if (result.code === WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE) {
|
|
89
|
-
await logoutDueToStreamError(
|
|
96
|
+
await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGOUT, result.code, true);
|
|
90
97
|
return;
|
|
91
98
|
}
|
|
92
99
|
}
|
|
@@ -94,11 +101,11 @@ export function createStreamControlHandler(options) {
|
|
|
94
101
|
return;
|
|
95
102
|
case 'stream_error_replaced':
|
|
96
103
|
logger.warn('received stream:error replaced, stopping client');
|
|
97
|
-
await disconnectDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED);
|
|
104
|
+
await disconnectDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED, null);
|
|
98
105
|
return;
|
|
99
106
|
case 'stream_error_device_removed':
|
|
100
107
|
logger.warn('received stream:error device removed, logging out');
|
|
101
|
-
await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, false);
|
|
108
|
+
await logoutDueToStreamError(WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, null, false);
|
|
102
109
|
return;
|
|
103
110
|
case 'stream_error_ack':
|
|
104
111
|
logger.warn('received stream:error ack', { id: result.id });
|