zapo-js 0.1.2 → 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 +12 -4
- package/dist/appstate/WaAppStateCrypto.js +1 -1
- package/dist/appstate/WaAppStateSyncClient.js +138 -93
- package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/appstate/index.js +8 -6
- package/dist/appstate/utils.js +0 -5
- package/dist/auth/WaAuthClient.js +36 -47
- package/dist/auth/flow/WaAuthCredentialsFlow.js +7 -7
- package/dist/auth/index.js +1 -6
- package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/auth/pairing/WaPairingFlow.js +13 -3
- package/dist/client/WaClient.js +225 -101
- package/dist/client/WaClientFactory.js +294 -44
- package/dist/client/connection/WaConnectionManager.js +19 -10
- package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
- package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +292 -99
- 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 +179 -27
- package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
- package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
- package/dist/client/dirty.js +40 -20
- package/dist/client/events/devices.js +72 -0
- package/dist/client/events/group.js +3 -11
- package/dist/client/events/identity.js +22 -0
- package/dist/client/events/privacy-token.js +39 -0
- package/dist/client/history-sync.js +50 -9
- package/dist/client/incoming.js +37 -7
- package/dist/client/mailbox.js +24 -23
- package/dist/client/messages.js +107 -31
- package/dist/client/messaging/fanout.js +21 -11
- package/dist/client/messaging/participants.js +6 -4
- 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/index.js +2 -2
- package/dist/crypto/core/keys.js +4 -4
- package/dist/crypto/core/nonce.js +2 -0
- package/dist/crypto/core/primitives.js +0 -8
- package/dist/crypto/core/random.js +22 -0
- package/dist/crypto/curves/X25519.js +25 -6
- package/dist/crypto/index.js +3 -0
- 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 +1 -1
- package/dist/esm/appstate/WaAppStateSyncClient.js +138 -93
- 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 +2 -5
- package/dist/esm/auth/WaAuthClient.js +36 -47
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +7 -7
- package/dist/esm/auth/index.js +0 -2
- package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/esm/auth/pairing/WaPairingFlow.js +14 -4
- package/dist/esm/client/WaClient.js +225 -101
- package/dist/esm/client/WaClientFactory.js +295 -45
- package/dist/esm/client/connection/WaConnectionManager.js +19 -10
- package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +295 -102
- 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 +181 -29
- package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
- package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
- package/dist/esm/client/dirty.js +40 -20
- package/dist/esm/client/events/devices.js +68 -0
- package/dist/esm/client/events/group.js +3 -11
- 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 +50 -9
- package/dist/esm/client/incoming.js +38 -8
- package/dist/esm/client/mailbox.js +24 -23
- package/dist/esm/client/messages.js +108 -32
- package/dist/esm/client/messaging/fanout.js +22 -12
- package/dist/esm/client/messaging/participants.js +6 -4
- 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/index.js +2 -2
- package/dist/esm/crypto/core/keys.js +1 -1
- package/dist/esm/crypto/core/nonce.js +2 -0
- package/dist/esm/crypto/core/primitives.js +0 -7
- package/dist/esm/crypto/core/random.js +22 -1
- package/dist/esm/crypto/curves/X25519.js +25 -6
- package/dist/esm/crypto/index.js +1 -0
- 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/perf/BackgroundQueue.js +478 -0
- package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
- 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 +95 -13
- package/dist/esm/media/WaMediaTransferClient.js +39 -47
- package/dist/esm/media/constants.js +2 -1
- package/dist/esm/message/WaMessageClient.js +26 -19
- package/dist/esm/message/content.js +195 -9
- package/dist/esm/message/icdc.js +76 -0
- package/dist/esm/message/incoming.js +24 -12
- package/dist/esm/message/phash.js +3 -1
- package/dist/esm/message/reporting-token.js +14 -27
- package/dist/esm/protocol/appstate.js +9 -40
- package/dist/esm/protocol/browser.js +10 -18
- package/dist/esm/protocol/constants.js +5 -3
- package/dist/esm/protocol/defaults.js +6 -0
- package/dist/esm/protocol/index.js +1 -2
- package/dist/esm/protocol/jid.js +105 -36
- package/dist/esm/protocol/message.js +61 -1
- package/dist/esm/protocol/nodes.js +2 -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/retry/codec.js +216 -0
- package/dist/esm/retry/constants.js +1 -1
- package/dist/esm/retry/index.js +2 -2
- package/dist/esm/retry/parse.js +50 -30
- package/dist/esm/retry/replay.js +11 -7
- package/dist/esm/retry/tracker.js +50 -12
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +49 -32
- package/dist/esm/signal/api/SignalDigestSyncApi.js +13 -9
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +26 -11
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +18 -7
- package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/esm/signal/api/SignalSessionSyncApi.js +16 -7
- 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 +12 -6
- package/dist/esm/signal/{store/sqlite.js → encoding.js} +78 -24
- package/dist/esm/signal/group/SenderKeyCodec.js +3 -2
- package/dist/esm/signal/group/SenderKeyManager.js +125 -106
- package/dist/esm/signal/index.js +1 -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 +150 -74
- package/dist/esm/signal/session/resolver.js +137 -102
- package/dist/esm/store/contracts/privacy-token.store.js +1 -0
- package/dist/esm/store/createStore.js +101 -187
- 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 +1 -1
- package/dist/esm/store/providers/memory/appstate.store.js +22 -24
- package/dist/esm/store/providers/memory/device-list.store.js +10 -5
- 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 +6 -1
- package/dist/esm/store/providers/memory/signal.store.js +36 -19
- package/dist/esm/transport/WaComms.js +3 -1
- package/dist/esm/transport/WaWebSocket.js +0 -6
- package/dist/esm/transport/binary/constants.js +0 -30
- package/dist/esm/transport/binary/decoder.js +4 -4
- package/dist/esm/transport/binary/encoder.js +8 -15
- package/dist/esm/transport/binary/index.js +0 -1
- package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -19
- 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 +5 -2
- package/dist/esm/transport/node/builders/message.js +63 -239
- package/dist/esm/transport/node/builders/pairing.js +0 -24
- 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 +6 -2
- package/dist/esm/transport/node/helpers.js +19 -1
- package/dist/esm/transport/node/usync.js +3 -33
- package/dist/esm/transport/node/xml.js +35 -14
- package/dist/esm/transport/noise/WaClientPayload.js +10 -10
- package/dist/esm/transport/noise/WaNoiseCert.js +3 -3
- package/dist/esm/transport/noise/WaNoiseSession.js +64 -23
- package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/esm/transport/stream/parse.js +8 -4
- package/dist/esm/util/bytes.js +22 -18
- package/dist/esm/util/index.js +5 -0
- package/dist/esm/util/primitives.js +3 -2
- package/dist/index.js +7 -1
- package/dist/infra/perf/BackgroundQueue.js +482 -0
- package/dist/infra/perf/BoundedTaskQueue.js +3 -1
- 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 +94 -12
- package/dist/media/WaMediaTransferClient.js +39 -47
- package/dist/media/constants.js +2 -1
- package/dist/message/WaMessageClient.js +26 -19
- package/dist/message/content.js +198 -9
- package/dist/message/icdc.js +81 -0
- package/dist/message/incoming.js +24 -12
- package/dist/message/phash.js +3 -1
- package/dist/message/reporting-token.js +14 -28
- package/dist/protocol/appstate.js +10 -41
- package/dist/protocol/browser.js +10 -18
- package/dist/protocol/constants.js +21 -2
- package/dist/protocol/defaults.js +6 -0
- package/dist/protocol/index.js +8 -5
- package/dist/protocol/jid.js +111 -36
- package/dist/protocol/message.js +62 -2
- package/dist/protocol/nodes.js +2 -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/retry/codec.js +220 -0
- package/dist/retry/constants.js +1 -1
- package/dist/retry/index.js +5 -5
- package/dist/retry/parse.js +51 -30
- package/dist/retry/replay.js +10 -6
- package/dist/retry/tracker.js +50 -12
- package/dist/signal/api/SignalDeviceSyncApi.js +48 -31
- package/dist/signal/api/SignalDigestSyncApi.js +13 -9
- package/dist/signal/api/SignalIdentitySyncApi.js +25 -10
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
- package/dist/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/signal/api/SignalSessionSyncApi.js +16 -7
- package/dist/signal/api/result-map.js +13 -0
- package/dist/signal/constants.js +1 -5
- package/dist/signal/crypto/WaAdvSignature.js +11 -5
- package/dist/signal/{store/sqlite.js → encoding.js} +79 -25
- package/dist/signal/group/SenderKeyCodec.js +4 -3
- package/dist/signal/group/SenderKeyManager.js +125 -106
- package/dist/signal/index.js +13 -1
- package/dist/signal/registration/keygen.js +6 -2
- package/dist/signal/registration/utils.js +1 -0
- package/dist/signal/session/SignalProtocol.js +150 -74
- package/dist/signal/session/resolver.js +135 -100
- package/dist/store/contracts/privacy-token.store.js +2 -0
- package/dist/store/createStore.js +101 -187
- 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 +1 -1
- package/dist/store/providers/memory/appstate.store.js +22 -24
- package/dist/store/providers/memory/device-list.store.js +10 -5
- 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 +6 -1
- package/dist/store/providers/memory/signal.store.js +36 -19
- package/dist/transport/WaComms.js +3 -1
- package/dist/transport/WaWebSocket.js +0 -6
- package/dist/transport/binary/constants.js +1 -31
- package/dist/transport/binary/decoder.js +4 -4
- package/dist/transport/binary/encoder.js +8 -15
- package/dist/transport/binary/index.js +0 -4
- package/dist/transport/node/WaNodeOrchestrator.js +24 -18
- 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 +18 -9
- package/dist/transport/node/builders/message.js +64 -245
- package/dist/transport/node/builders/pairing.js +0 -26
- 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 +6 -2
- package/dist/transport/node/helpers.js +20 -1
- package/dist/transport/node/usync.js +2 -32
- package/dist/transport/node/xml.js +35 -14
- package/dist/transport/noise/WaClientPayload.js +13 -13
- package/dist/transport/noise/WaNoiseCert.js +2 -2
- package/dist/transport/noise/WaNoiseSession.js +64 -23
- package/dist/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/transport/stream/parse.js +7 -3
- 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 -2
- package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
- package/dist/types/auth/index.d.ts +0 -2
- package/dist/types/auth/types.d.ts +1 -0
- package/dist/types/client/WaClient.d.ts +27 -12
- package/dist/types/client/WaClientFactory.d.ts +12 -4
- package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
- package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -1
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +14 -0
- 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 +6 -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/events/devices.d.ts +20 -0
- 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/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 +51 -3
- package/dist/types/crypto/core/index.d.ts +2 -2
- 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 +1 -0
- package/dist/types/crypto/index.d.ts +1 -0
- 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/perf/BackgroundQueue.d.ts +58 -0
- 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 +3 -12
- 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 +10 -2
- package/dist/types/message/content.d.ts +8 -0
- package/dist/types/message/icdc.d.ts +13 -0
- package/dist/types/message/reporting-token.d.ts +0 -1
- package/dist/types/message/types.d.ts +45 -6
- package/dist/types/protocol/appstate.d.ts +0 -11
- package/dist/types/protocol/constants.d.ts +7 -3
- package/dist/types/protocol/defaults.d.ts +6 -0
- package/dist/types/protocol/index.d.ts +1 -2
- package/dist/types/protocol/jid.d.ts +19 -2
- package/dist/types/protocol/message.d.ts +60 -0
- package/dist/types/protocol/nodes.d.ts +2 -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/retry/codec.d.ts +3 -0
- package/dist/types/retry/index.d.ts +3 -3
- package/dist/types/retry/parse.d.ts +5 -2
- package/dist/types/retry/tracker.d.ts +1 -0
- package/dist/types/retry/types.d.ts +6 -1
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
- 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/SenderKeyManager.d.ts +10 -5
- package/dist/types/signal/index.d.ts +2 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +10 -4
- package/dist/types/signal/session/resolver.d.ts +7 -2
- package/dist/types/store/contracts/appstate.store.d.ts +1 -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/signal.store.d.ts +7 -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 +1 -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/signal.store.d.ts +2 -1
- package/dist/types/store/types.d.ts +49 -61
- package/dist/types/transport/WaWebSocket.d.ts +0 -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/node/WaNodeOrchestrator.d.ts +3 -4
- 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/index.d.ts +5 -2
- package/dist/types/transport/node/builders/message.d.ts +8 -7
- 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 +0 -1
- package/dist/types/transport/node/helpers.d.ts +5 -0
- package/dist/types/transport/noise/WaNoiseSession.d.ts +3 -2
- package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
- package/dist/types/util/bytes.d.ts +1 -1
- package/dist/types/util/index.d.ts +5 -0
- package/dist/types/util/primitives.d.ts +0 -1
- package/dist/util/bytes.js +22 -18
- package/dist/util/index.js +23 -0
- package/dist/util/primitives.js +2 -2
- package/package.json +29 -7
- package/proto/index.js +1 -1
- package/dist/crypto/core/constants.js +0 -4
- package/dist/esm/crypto/core/constants.js +0 -1
- package/dist/esm/retry/outbound.js +0 -82
- package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
- package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
- package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
- package/dist/esm/store/providers/sqlite/connection.js +0 -245
- package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
- package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
- package/dist/esm/store/providers/sqlite/message.store.js +0 -132
- package/dist/esm/store/providers/sqlite/migrations.js +0 -347
- package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
- package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
- package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
- package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
- package/dist/esm/store/providers/sqlite/table-names.js +0 -107
- package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
- package/dist/retry/outbound.js +0 -87
- package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
- package/dist/store/providers/sqlite/appstate.store.js +0 -254
- package/dist/store/providers/sqlite/auth.store.js +0 -180
- package/dist/store/providers/sqlite/connection.js +0 -281
- package/dist/store/providers/sqlite/contact.store.js +0 -78
- package/dist/store/providers/sqlite/device-list.store.js +0 -131
- package/dist/store/providers/sqlite/message.store.js +0 -136
- package/dist/store/providers/sqlite/migrations.js +0 -350
- package/dist/store/providers/sqlite/participants.store.js +0 -81
- package/dist/store/providers/sqlite/retry.store.js +0 -145
- package/dist/store/providers/sqlite/sender-key.store.js +0 -202
- package/dist/store/providers/sqlite/signal.store.js +0 -439
- package/dist/store/providers/sqlite/table-names.js +0 -113
- package/dist/store/providers/sqlite/thread.store.js +0 -89
- package/dist/types/appstate/store/sqlite.d.ts +0 -7
- package/dist/types/crypto/core/constants.d.ts +0 -1
- 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 -17
- 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 -12
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
- package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
- package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
- package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
- package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
|
@@ -5,15 +5,17 @@ const _proto_1 = require("../../proto.js");
|
|
|
5
5
|
const constants_1 = require("../../protocol/constants");
|
|
6
6
|
const jid_1 = require("../../protocol/jid");
|
|
7
7
|
const constants_2 = require("../../retry/constants");
|
|
8
|
-
const outbound_1 = require("../../retry/outbound");
|
|
9
8
|
const parse_1 = require("../../retry/parse");
|
|
10
9
|
const reason_1 = require("../../retry/reason");
|
|
11
10
|
const replay_1 = require("../../retry/replay");
|
|
12
11
|
const keygen_1 = require("../../signal/registration/keygen");
|
|
13
|
-
const
|
|
12
|
+
const global_1 = require("../../transport/node/builders/global");
|
|
14
13
|
const retry_1 = require("../../transport/node/builders/retry");
|
|
14
|
+
const bytes_1 = require("../../util/bytes");
|
|
15
|
+
const collections_1 = require("../../util/collections");
|
|
15
16
|
const primitives_1 = require("../../util/primitives");
|
|
16
17
|
const RETRY_CLEANUP_INTERVAL_MS = 30000;
|
|
18
|
+
const RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES = 8192;
|
|
17
19
|
function getRetryReasonName(code) {
|
|
18
20
|
if (code === undefined) {
|
|
19
21
|
return undefined;
|
|
@@ -55,6 +57,7 @@ class WaRetryCoordinator {
|
|
|
55
57
|
getCurrentSignedIdentity: this.getCurrentSignedIdentity
|
|
56
58
|
});
|
|
57
59
|
this.retryProcessingByMessageId = new Map();
|
|
60
|
+
this.retrySessionBaseKeys = new Map();
|
|
58
61
|
}
|
|
59
62
|
async onDecryptFailure(context, error) {
|
|
60
63
|
try {
|
|
@@ -79,12 +82,23 @@ class WaRetryCoordinator {
|
|
|
79
82
|
if (!this.isRetryReceiptNode(receiptNode)) {
|
|
80
83
|
return;
|
|
81
84
|
}
|
|
85
|
+
let shouldAck = false;
|
|
82
86
|
try {
|
|
83
87
|
await this.maybeCleanupRetryStore(Date.now());
|
|
84
|
-
const
|
|
88
|
+
const expectedToJids = [];
|
|
89
|
+
const meJid = this.getCurrentMeJid()?.trim();
|
|
90
|
+
const meLid = this.getCurrentMeLid()?.trim();
|
|
91
|
+
if (meJid) {
|
|
92
|
+
expectedToJids.push(meJid);
|
|
93
|
+
}
|
|
94
|
+
if (meLid) {
|
|
95
|
+
expectedToJids.push(meLid);
|
|
96
|
+
}
|
|
97
|
+
const request = (0, parse_1.parseRetryReceiptRequest)(receiptNode, expectedToJids.length > 0 ? { expectedToJids } : undefined);
|
|
85
98
|
if (!request) {
|
|
86
99
|
return;
|
|
87
100
|
}
|
|
101
|
+
shouldAck = true;
|
|
88
102
|
await this.handleParsedRetryRequest(receiptNode, request);
|
|
89
103
|
}
|
|
90
104
|
catch (error) {
|
|
@@ -96,7 +110,9 @@ class WaRetryCoordinator {
|
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
finally {
|
|
99
|
-
|
|
113
|
+
if (shouldAck) {
|
|
114
|
+
await this.sendRetryAckSafe(receiptNode);
|
|
115
|
+
}
|
|
100
116
|
}
|
|
101
117
|
}
|
|
102
118
|
isRetryReceiptNode(node) {
|
|
@@ -132,7 +148,6 @@ class WaRetryCoordinator {
|
|
|
132
148
|
to: context.from,
|
|
133
149
|
participant: context.participant,
|
|
134
150
|
recipient: context.recipient,
|
|
135
|
-
from: this.getCurrentMeJid() ?? undefined,
|
|
136
151
|
originalMsgId: context.stanzaId,
|
|
137
152
|
retryCount: prepared.retryCount,
|
|
138
153
|
t: prepared.timestamp,
|
|
@@ -203,8 +218,9 @@ class WaRetryCoordinator {
|
|
|
203
218
|
let requesterAddress;
|
|
204
219
|
let requesterNormalizedDeviceJid;
|
|
205
220
|
try {
|
|
206
|
-
|
|
207
|
-
|
|
221
|
+
const requesterParsed = (0, jid_1.parseJidFull)(requesterJid);
|
|
222
|
+
requesterAddress = requesterParsed.address;
|
|
223
|
+
requesterNormalizedDeviceJid = requesterParsed.normalizedJid;
|
|
208
224
|
}
|
|
209
225
|
catch (error) {
|
|
210
226
|
this.logger.info('retry request rejected: invalid requester jid', {
|
|
@@ -280,20 +296,36 @@ class WaRetryCoordinator {
|
|
|
280
296
|
if (!nextState) {
|
|
281
297
|
return;
|
|
282
298
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
299
|
+
await this.runRetryTaskSerialized(messageId, async () => {
|
|
300
|
+
const current = await this.retryStore.getOutboundMessage(messageId);
|
|
301
|
+
if (!current) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const nowMs = Date.now();
|
|
305
|
+
const expiresAtMs = nowMs + this.retryTtlMs;
|
|
306
|
+
const merged = (0, parse_1.pickRetryStateMax)(current.state, nextState);
|
|
307
|
+
if (merged !== current.state) {
|
|
308
|
+
await this.retryStore.updateOutboundMessageState(messageId, merged, nowMs, expiresAtMs);
|
|
309
|
+
}
|
|
310
|
+
const requesterJid = receiptNode.attrs.participant ?? receiptNode.attrs.from;
|
|
311
|
+
if (!requesterJid) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
await this.retryStore.markOutboundRequesterDelivered(messageId, (0, jid_1.normalizeDeviceJid)(requesterJid), nowMs, expiresAtMs);
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
this.logger.warn('failed to update outbound requester delivery state', {
|
|
319
|
+
id: messageId,
|
|
320
|
+
requester: requesterJid,
|
|
321
|
+
message: (0, primitives_1.toError)(error).message
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
});
|
|
293
325
|
}
|
|
294
326
|
async runRetryTaskSerialized(messageId, task) {
|
|
295
327
|
const previous = this.retryProcessingByMessageId.get(messageId) ?? Promise.resolve();
|
|
296
|
-
const current = previous.then(task
|
|
328
|
+
const current = previous.then(task);
|
|
297
329
|
const tracker = current.then(() => undefined, () => undefined);
|
|
298
330
|
this.retryProcessingByMessageId.set(messageId, tracker);
|
|
299
331
|
try {
|
|
@@ -334,15 +366,45 @@ class WaRetryCoordinator {
|
|
|
334
366
|
};
|
|
335
367
|
}
|
|
336
368
|
async updateLocalSessionFromRetryRequest(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
337
|
-
await
|
|
338
|
-
|
|
339
|
-
|
|
369
|
+
const [, currentSession] = await Promise.all([
|
|
370
|
+
this.markRetryRequesterSenderKeyAsStale(request, requesterJid, requesterAddress),
|
|
371
|
+
this.signalStore.getSession(requesterAddress)
|
|
372
|
+
]);
|
|
373
|
+
const regIdMismatch = !!currentSession && request.regId > 0 && currentSession.remote.regId !== request.regId;
|
|
374
|
+
if (regIdMismatch && !request.keyBundle) {
|
|
340
375
|
await this.signalStore.deleteSession(requesterAddress);
|
|
341
376
|
}
|
|
342
377
|
if (request.keyBundle) {
|
|
343
378
|
if (!request.keyBundle.key || !request.keyBundle.skey.signature) {
|
|
344
379
|
return false;
|
|
345
380
|
}
|
|
381
|
+
if (request.offline) {
|
|
382
|
+
if (!currentSession) {
|
|
383
|
+
this.logger.info('retry request rejected: offline retry missing existing session', {
|
|
384
|
+
id: request.stanzaId,
|
|
385
|
+
originalMsgId: request.originalMsgId,
|
|
386
|
+
requester: requesterJid,
|
|
387
|
+
remoteRetryCount: request.retryCount,
|
|
388
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
389
|
+
});
|
|
390
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
if (regIdMismatch) {
|
|
394
|
+
this.logger.info('retry request rejected: offline retry registration id mismatch', {
|
|
395
|
+
id: request.stanzaId,
|
|
396
|
+
originalMsgId: request.originalMsgId,
|
|
397
|
+
requester: requesterJid,
|
|
398
|
+
remoteRetryCount: request.retryCount,
|
|
399
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
400
|
+
});
|
|
401
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
else if (regIdMismatch) {
|
|
406
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
407
|
+
}
|
|
346
408
|
await this.signalProtocol.establishOutgoingSession(requesterAddress, {
|
|
347
409
|
regId: request.regId,
|
|
348
410
|
identity: request.keyBundle.identity,
|
|
@@ -356,12 +418,45 @@ class WaRetryCoordinator {
|
|
|
356
418
|
publicKey: request.keyBundle.key.publicKey
|
|
357
419
|
}
|
|
358
420
|
});
|
|
421
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
422
|
+
}
|
|
423
|
+
const sessionStillExists = currentSession !== null && !regIdMismatch;
|
|
424
|
+
if (sessionStillExists) {
|
|
425
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
426
|
+
}
|
|
427
|
+
const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
|
|
428
|
+
if (!fetched) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
await this.signalProtocol.establishOutgoingSession(requesterAddress, fetched);
|
|
432
|
+
return this.applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
433
|
+
}
|
|
434
|
+
async applySessionBaseKeyPolicy(request, requesterJid, requesterAddress, requesterNormalizedDeviceJid) {
|
|
435
|
+
if (request.retryCount < 2) {
|
|
359
436
|
return true;
|
|
360
437
|
}
|
|
361
|
-
const
|
|
362
|
-
|
|
438
|
+
const currentSession = await this.signalStore.getSession(requesterAddress);
|
|
439
|
+
const sessionBaseKey = currentSession?.aliceBaseKey ?? null;
|
|
440
|
+
if (!sessionBaseKey) {
|
|
363
441
|
return true;
|
|
364
442
|
}
|
|
443
|
+
const expiresAtMs = Date.now() + this.retryTtlMs;
|
|
444
|
+
if (request.retryCount === 2) {
|
|
445
|
+
this.setRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid, sessionBaseKey, expiresAtMs);
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
const saved = this.getRetrySessionBaseKey(request.originalMsgId, requesterNormalizedDeviceJid);
|
|
449
|
+
if (!saved || !(0, bytes_1.uint8Equal)(saved.baseKey, sessionBaseKey)) {
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
await this.signalStore.deleteSession(requesterAddress);
|
|
453
|
+
this.logger.info('retry request forcing session refresh due to repeated base key', {
|
|
454
|
+
id: request.stanzaId,
|
|
455
|
+
originalMsgId: request.originalMsgId,
|
|
456
|
+
requester: requesterJid,
|
|
457
|
+
remoteRetryCount: request.retryCount,
|
|
458
|
+
...getRemoteRetryReasonLogFields(request.retryReason)
|
|
459
|
+
});
|
|
365
460
|
const fetched = await this.fetchMissingPreKeysSession(requesterJid, requesterAddress, requesterNormalizedDeviceJid, request.regId);
|
|
366
461
|
if (!fetched) {
|
|
367
462
|
return false;
|
|
@@ -434,13 +529,35 @@ class WaRetryCoordinator {
|
|
|
434
529
|
if (outbound.state === 'ineligible') {
|
|
435
530
|
return { authorized: false, reason: `state_${outbound.state}` };
|
|
436
531
|
}
|
|
532
|
+
let requesterStatus = null;
|
|
533
|
+
try {
|
|
534
|
+
requesterStatus = await this.retryStore.getOutboundRequesterStatus(outbound.messageId, requesterNormalizedDeviceJid);
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
this.logger.warn('failed to resolve outbound requester status from retry store', {
|
|
538
|
+
id: request.stanzaId,
|
|
539
|
+
originalMsgId: request.originalMsgId,
|
|
540
|
+
requester: requesterJid,
|
|
541
|
+
message: (0, primitives_1.toError)(error).message
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
if (requesterStatus) {
|
|
545
|
+
if (!requesterStatus.eligible) {
|
|
546
|
+
return { authorized: false, reason: 'requester_device_not_eligible' };
|
|
547
|
+
}
|
|
548
|
+
if (requesterStatus.delivered) {
|
|
549
|
+
return { authorized: false, reason: 'requester_already_delivered' };
|
|
550
|
+
}
|
|
551
|
+
}
|
|
437
552
|
const isGroupOutbound = (0, jid_1.isGroupOrBroadcastJid)(outbound.toJid);
|
|
438
553
|
if (!isGroupOutbound && (outbound.state === 'read' || outbound.state === 'played')) {
|
|
439
554
|
return { authorized: false, reason: `state_${outbound.state}` };
|
|
440
555
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
556
|
+
if (!requesterStatus) {
|
|
557
|
+
const requesterAuthorized = await this.isRequesterAuthorizedDevice(requesterJid, requesterAddress, requesterNormalizedDeviceJid);
|
|
558
|
+
if (!requesterAuthorized) {
|
|
559
|
+
return { authorized: false, reason: 'requester_device_not_authorized' };
|
|
560
|
+
}
|
|
444
561
|
}
|
|
445
562
|
return { authorized: true };
|
|
446
563
|
}
|
|
@@ -498,7 +615,11 @@ class WaRetryCoordinator {
|
|
|
498
615
|
return;
|
|
499
616
|
}
|
|
500
617
|
try {
|
|
501
|
-
await this.sendNode((0,
|
|
618
|
+
await this.sendNode((0, global_1.buildAckNode)({
|
|
619
|
+
kind: 'receipt',
|
|
620
|
+
node: receiptNode,
|
|
621
|
+
retryType: true
|
|
622
|
+
}));
|
|
502
623
|
}
|
|
503
624
|
catch (error) {
|
|
504
625
|
this.logger.warn('failed to send retry ack', {
|
|
@@ -514,6 +635,7 @@ class WaRetryCoordinator {
|
|
|
514
635
|
return;
|
|
515
636
|
}
|
|
516
637
|
this.nextRetryCleanupAtMs = nowMs + RETRY_CLEANUP_INTERVAL_MS;
|
|
638
|
+
this.cleanupRetrySessionBaseKeys(nowMs);
|
|
517
639
|
try {
|
|
518
640
|
await this.retryStore.cleanupExpired(nowMs);
|
|
519
641
|
}
|
|
@@ -523,5 +645,35 @@ class WaRetryCoordinator {
|
|
|
523
645
|
});
|
|
524
646
|
}
|
|
525
647
|
}
|
|
648
|
+
retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid) {
|
|
649
|
+
return `${originalMsgId}|${requesterNormalizedDeviceJid}`;
|
|
650
|
+
}
|
|
651
|
+
setRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid, baseKey, expiresAtMs) {
|
|
652
|
+
const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
|
|
653
|
+
(0, collections_1.setBoundedMapEntry)(this.retrySessionBaseKeys, key, {
|
|
654
|
+
baseKey: Uint8Array.from(baseKey),
|
|
655
|
+
expiresAtMs
|
|
656
|
+
}, RETRY_SESSION_BASE_KEY_CACHE_MAX_ENTRIES);
|
|
657
|
+
}
|
|
658
|
+
getRetrySessionBaseKey(originalMsgId, requesterNormalizedDeviceJid) {
|
|
659
|
+
const key = this.retrySessionBaseKeyMapKey(originalMsgId, requesterNormalizedDeviceJid);
|
|
660
|
+
const entry = this.retrySessionBaseKeys.get(key);
|
|
661
|
+
if (!entry) {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
if (entry.expiresAtMs <= Date.now()) {
|
|
665
|
+
this.retrySessionBaseKeys.delete(key);
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
return entry;
|
|
669
|
+
}
|
|
670
|
+
cleanupRetrySessionBaseKeys(nowMs) {
|
|
671
|
+
for (const [key, entry] of this.retrySessionBaseKeys) {
|
|
672
|
+
if (entry.expiresAtMs > nowMs) {
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
this.retrySessionBaseKeys.delete(key);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
526
678
|
}
|
|
527
679
|
exports.WaRetryCoordinator = WaRetryCoordinator;
|
|
@@ -19,7 +19,7 @@ function createStreamControlHandler(options) {
|
|
|
19
19
|
const restartBackendAfterStreamControl = async (reason) => {
|
|
20
20
|
logger.info('restarting backend after stream control', { reason });
|
|
21
21
|
try {
|
|
22
|
-
await connect();
|
|
22
|
+
await connect(constants_1.WA_CONNECTION_REASONS.RECONNECTED);
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
25
|
logger.warn('failed to restart backend after stream control', {
|
|
@@ -46,29 +46,36 @@ function createStreamControlHandler(options) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
+
const stopCommsImmediately = () => {
|
|
50
|
+
void getComms()?.stopComms();
|
|
51
|
+
};
|
|
49
52
|
const forceLoginDueToStreamError = async (code) => {
|
|
50
|
-
|
|
53
|
+
const reason = constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGIN;
|
|
54
|
+
stopCommsImmediately();
|
|
55
|
+
await runStreamControlLifecycle(reason, async () => {
|
|
51
56
|
logger.warn('received forced login stream error; starting login lifecycle', {
|
|
52
57
|
code
|
|
53
58
|
});
|
|
54
|
-
await disconnect();
|
|
59
|
+
await disconnect(reason, true, code);
|
|
55
60
|
await clearStoredCredentials();
|
|
56
|
-
await restartBackendAfterStreamControl(
|
|
61
|
+
await restartBackendAfterStreamControl(reason);
|
|
57
62
|
});
|
|
58
63
|
};
|
|
59
|
-
const disconnectDueToStreamError = async (reason) => {
|
|
64
|
+
const disconnectDueToStreamError = async (reason, code) => {
|
|
65
|
+
stopCommsImmediately();
|
|
60
66
|
await runStreamControlLifecycle(reason, async () => {
|
|
61
67
|
logger.warn('disconnecting due to stream control node', { reason });
|
|
62
|
-
await disconnect();
|
|
68
|
+
await disconnect(reason, false, code);
|
|
63
69
|
});
|
|
64
70
|
};
|
|
65
|
-
const logoutDueToStreamError = async (reason, shouldRestartBackend) => {
|
|
71
|
+
const logoutDueToStreamError = async (reason, code, shouldRestartBackend) => {
|
|
72
|
+
stopCommsImmediately();
|
|
66
73
|
await runStreamControlLifecycle(reason, async () => {
|
|
67
74
|
logger.warn('logging out due to stream control node', {
|
|
68
75
|
reason,
|
|
69
76
|
shouldRestartBackend
|
|
70
77
|
});
|
|
71
|
-
await disconnect();
|
|
78
|
+
await disconnect(reason, true, code);
|
|
72
79
|
await clearStoredCredentials();
|
|
73
80
|
if (shouldRestartBackend) {
|
|
74
81
|
await restartBackendAfterStreamControl(reason);
|
|
@@ -89,7 +96,7 @@ function createStreamControlHandler(options) {
|
|
|
89
96
|
return;
|
|
90
97
|
}
|
|
91
98
|
if (result.code === constants_1.WA_STREAM_SIGNALING.FORCE_LOGOUT_CODE) {
|
|
92
|
-
await logoutDueToStreamError(
|
|
99
|
+
await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_FORCE_LOGOUT, result.code, true);
|
|
93
100
|
return;
|
|
94
101
|
}
|
|
95
102
|
}
|
|
@@ -97,11 +104,11 @@ function createStreamControlHandler(options) {
|
|
|
97
104
|
return;
|
|
98
105
|
case 'stream_error_replaced':
|
|
99
106
|
logger.warn('received stream:error replaced, stopping client');
|
|
100
|
-
await disconnectDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED);
|
|
107
|
+
await disconnectDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_REPLACED, null);
|
|
101
108
|
return;
|
|
102
109
|
case 'stream_error_device_removed':
|
|
103
110
|
logger.warn('received stream:error device removed, logging out');
|
|
104
|
-
await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, false);
|
|
111
|
+
await logoutDueToStreamError(constants_1.WA_DISCONNECT_REASONS.STREAM_ERROR_DEVICE_REMOVED, null, false);
|
|
105
112
|
return;
|
|
106
113
|
case 'stream_error_ack':
|
|
107
114
|
logger.warn('received stream:error ack', { id: result.id });
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WaTrustedContactTokenCoordinator = void 0;
|
|
4
|
+
const cs_token_1 = require("../tokens/cs-token");
|
|
5
|
+
const tc_token_1 = require("../tokens/tc-token");
|
|
6
|
+
const PromiseDedup_1 = require("../../infra/perf/PromiseDedup");
|
|
7
|
+
const privacy_token_1 = require("../../protocol/privacy-token");
|
|
8
|
+
const privacy_token_2 = require("../../transport/node/builders/privacy-token");
|
|
9
|
+
const primitives_1 = require("../../util/primitives");
|
|
10
|
+
const NCT_SALT_SENTINEL_JID = '__nct_salt__';
|
|
11
|
+
class WaTrustedContactTokenCoordinator {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.logger = options.logger;
|
|
14
|
+
this.store = options.store;
|
|
15
|
+
this.runtime = options.runtime;
|
|
16
|
+
const maxDurationS = options.maxDurationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.MAX_DURATION_S;
|
|
17
|
+
this.config = {
|
|
18
|
+
durationS: (0, tc_token_1.clampDuration)(options.durationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.DURATION_S, maxDurationS),
|
|
19
|
+
numBuckets: options.numBuckets ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.NUM_BUCKETS,
|
|
20
|
+
senderDurationS: (0, tc_token_1.clampDuration)(options.senderDurationS ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.SENDER_DURATION_S, maxDurationS),
|
|
21
|
+
senderNumBuckets: options.senderNumBuckets ?? privacy_token_1.WA_TC_TOKEN_DEFAULTS.SENDER_NUM_BUCKETS,
|
|
22
|
+
maxDurationS
|
|
23
|
+
};
|
|
24
|
+
this.csTokenGenerator = new cs_token_1.CsTokenGenerator();
|
|
25
|
+
this.senderTokenDedup = new PromiseDedup_1.PromiseDedup();
|
|
26
|
+
this.cachedNctSalt = null;
|
|
27
|
+
this.nctSaltHydrated = false;
|
|
28
|
+
}
|
|
29
|
+
async resolveTokenForMessage(recipientJid) {
|
|
30
|
+
const record = await this.store.getByJid(recipientJid);
|
|
31
|
+
const nowS = Math.floor(Date.now() / 1000);
|
|
32
|
+
if (record?.tcToken &&
|
|
33
|
+
record.tcTokenTimestamp !== undefined &&
|
|
34
|
+
!(0, tc_token_1.isTokenExpired)(record.tcTokenTimestamp, nowS, this.config.durationS, this.config.numBuckets)) {
|
|
35
|
+
return (0, privacy_token_2.buildTcTokenMessageNode)(record.tcToken);
|
|
36
|
+
}
|
|
37
|
+
const nctSalt = await this.getNctSalt();
|
|
38
|
+
if (!nctSalt) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const meLid = this.runtime.getCurrentMeLid();
|
|
42
|
+
if (!meLid) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const hash = await this.csTokenGenerator.generate(nctSalt, meLid);
|
|
46
|
+
return (0, privacy_token_2.buildCsTokenMessageNode)(hash);
|
|
47
|
+
}
|
|
48
|
+
async handleIncomingToken(fromJid, tokens) {
|
|
49
|
+
const nowMs = Date.now();
|
|
50
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
51
|
+
const token = tokens[i];
|
|
52
|
+
if (token.type !== privacy_token_1.WA_PRIVACY_TOKEN_TYPES.TRUSTED_CONTACT) {
|
|
53
|
+
this.logger.warn('ignoring unknown privacy token type', { type: token.type });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
await this.store.upsert({
|
|
57
|
+
jid: fromJid,
|
|
58
|
+
tcToken: token.tokenBytes,
|
|
59
|
+
tcTokenTimestamp: token.timestampS,
|
|
60
|
+
updatedAtMs: nowMs
|
|
61
|
+
});
|
|
62
|
+
this.runtime.emitEvent('privacy_token_update', {
|
|
63
|
+
jid: fromJid,
|
|
64
|
+
timestampS: token.timestampS,
|
|
65
|
+
type: token.type,
|
|
66
|
+
source: 'notification'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async maybeIssueSenderToken(recipientJid) {
|
|
71
|
+
return this.senderTokenDedup.run(recipientJid, async () => {
|
|
72
|
+
const nowS = Math.floor(Date.now() / 1000);
|
|
73
|
+
const record = await this.store.getByJid(recipientJid);
|
|
74
|
+
const senderTimestampS = record?.tcTokenSenderTimestamp;
|
|
75
|
+
if (senderTimestampS !== undefined && senderTimestampS > 0) {
|
|
76
|
+
if (!(0, tc_token_1.shouldSendNewToken)(senderTimestampS, nowS, this.config.senderDurationS)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
await this.issuePrivacyToken(recipientJid, nowS);
|
|
81
|
+
await this.store.upsert({
|
|
82
|
+
jid: recipientJid,
|
|
83
|
+
tcTokenSenderTimestamp: nowS,
|
|
84
|
+
updatedAtMs: Date.now()
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async reissueOnIdentityChange(jid) {
|
|
89
|
+
const record = await this.store.getByJid(jid);
|
|
90
|
+
if (!record?.tcTokenSenderTimestamp) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const nowS = Math.floor(Date.now() / 1000);
|
|
94
|
+
if ((0, tc_token_1.isTokenExpired)(record.tcTokenSenderTimestamp, nowS, this.config.senderDurationS, this.config.senderNumBuckets)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
await this.issuePrivacyToken(jid, record.tcTokenSenderTimestamp);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.logger.warn('send-tc-token-device-identity-change-failed', {
|
|
102
|
+
jid,
|
|
103
|
+
message: (0, primitives_1.toError)(error).message
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async hydrateFromHistorySync(conversations) {
|
|
108
|
+
const nowMs = Date.now();
|
|
109
|
+
const records = [];
|
|
110
|
+
for (let i = 0; i < conversations.length; i += 1) {
|
|
111
|
+
const conv = conversations[i];
|
|
112
|
+
if (!conv.tcToken && !conv.tcTokenTimestamp && !conv.tcTokenSenderTimestamp) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
records[records.length] = {
|
|
116
|
+
jid: conv.jid,
|
|
117
|
+
tcToken: conv.tcToken ?? undefined,
|
|
118
|
+
tcTokenTimestamp: conv.tcTokenTimestamp ?? undefined,
|
|
119
|
+
tcTokenSenderTimestamp: conv.tcTokenSenderTimestamp ?? undefined,
|
|
120
|
+
updatedAtMs: nowMs
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (records.length > 0) {
|
|
124
|
+
await this.store.upsertBatch(records);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async handleNctSaltSync(salt) {
|
|
128
|
+
if (salt) {
|
|
129
|
+
await this.store.upsert({
|
|
130
|
+
jid: NCT_SALT_SENTINEL_JID,
|
|
131
|
+
nctSalt: salt,
|
|
132
|
+
updatedAtMs: Date.now()
|
|
133
|
+
});
|
|
134
|
+
this.cachedNctSalt = salt;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
await this.store.deleteByJid(NCT_SALT_SENTINEL_JID);
|
|
138
|
+
this.cachedNctSalt = null;
|
|
139
|
+
}
|
|
140
|
+
this.nctSaltHydrated = true;
|
|
141
|
+
this.csTokenGenerator.invalidate();
|
|
142
|
+
}
|
|
143
|
+
async hydrateNctSaltFromHistorySync(salt) {
|
|
144
|
+
await this.store.upsert({
|
|
145
|
+
jid: NCT_SALT_SENTINEL_JID,
|
|
146
|
+
nctSalt: salt,
|
|
147
|
+
updatedAtMs: Date.now()
|
|
148
|
+
});
|
|
149
|
+
this.cachedNctSalt = salt;
|
|
150
|
+
this.nctSaltHydrated = true;
|
|
151
|
+
}
|
|
152
|
+
async getNctSalt() {
|
|
153
|
+
if (this.nctSaltHydrated) {
|
|
154
|
+
return this.cachedNctSalt;
|
|
155
|
+
}
|
|
156
|
+
const record = await this.store.getByJid(NCT_SALT_SENTINEL_JID);
|
|
157
|
+
this.cachedNctSalt = record?.nctSalt ?? null;
|
|
158
|
+
this.nctSaltHydrated = true;
|
|
159
|
+
return this.cachedNctSalt;
|
|
160
|
+
}
|
|
161
|
+
async issuePrivacyToken(jid, timestampS) {
|
|
162
|
+
const node = (0, privacy_token_2.buildPrivacyTokenIqNode)({ jid, timestampS });
|
|
163
|
+
await this.runtime.queryWithContext('issue-privacy-token', node);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.WaTrustedContactTokenCoordinator = WaTrustedContactTokenCoordinator;
|
package/dist/client/dirty.js
CHANGED
|
@@ -28,7 +28,13 @@ function parseDirtyBitNode(node, logger) {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
function resolveAccountSyncProtocols(protocols) {
|
|
31
|
-
const selected =
|
|
31
|
+
const selected = [];
|
|
32
|
+
for (let index = 0; index < protocols.length; index += 1) {
|
|
33
|
+
const protocol = protocols[index];
|
|
34
|
+
if (ACCOUNT_SYNC_PROTOCOL_SET.has(protocol)) {
|
|
35
|
+
selected.push(protocol);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
32
38
|
if (selected.length > 0) {
|
|
33
39
|
return selected;
|
|
34
40
|
}
|
|
@@ -60,12 +66,24 @@ async function handleDirtyBits(runtime, dirtyBits) {
|
|
|
60
66
|
}
|
|
61
67
|
unsupported.push(dirtyBit);
|
|
62
68
|
}
|
|
69
|
+
const supportedTypes = new Array(supported.length);
|
|
70
|
+
for (let index = 0; index < supported.length; index += 1) {
|
|
71
|
+
supportedTypes[index] = supported[index].type;
|
|
72
|
+
}
|
|
73
|
+
const unsupportedTypes = new Array(unsupported.length);
|
|
74
|
+
for (let index = 0; index < unsupported.length; index += 1) {
|
|
75
|
+
unsupportedTypes[index] = unsupported[index].type;
|
|
76
|
+
}
|
|
63
77
|
runtime.logger.info('handling dirty bits from info bulletin', {
|
|
64
|
-
supported:
|
|
65
|
-
unsupported:
|
|
78
|
+
supported: supportedTypes.join(','),
|
|
79
|
+
unsupported: unsupportedTypes.join(',')
|
|
66
80
|
});
|
|
67
81
|
const clearableDirtyBits = [...unsupported];
|
|
68
|
-
const
|
|
82
|
+
const supportedPromises = new Array(supported.length);
|
|
83
|
+
for (let index = 0; index < supported.length; index += 1) {
|
|
84
|
+
supportedPromises[index] = handleDirtyBit(runtime, supported[index]);
|
|
85
|
+
}
|
|
86
|
+
const settledSupported = await Promise.allSettled(supportedPromises);
|
|
69
87
|
for (let index = 0; index < settledSupported.length; index += 1) {
|
|
70
88
|
const result = settledSupported[index];
|
|
71
89
|
if (result.status === 'fulfilled') {
|
|
@@ -105,18 +123,23 @@ async function handleAccountSyncDirtyBit(runtime, protocols) {
|
|
|
105
123
|
protocols: selectedProtocols.join(',')
|
|
106
124
|
});
|
|
107
125
|
const failures = [];
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
const protocolPromises = new Array(selectedProtocols.length);
|
|
127
|
+
for (let index = 0; index < selectedProtocols.length; index += 1) {
|
|
128
|
+
const protocol = selectedProtocols[index];
|
|
129
|
+
protocolPromises[index] = (async () => {
|
|
130
|
+
try {
|
|
131
|
+
await runAccountSyncProtocol(runtime, protocol);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
failures.push(protocol);
|
|
135
|
+
runtime.logger.warn('account_sync protocol failed', {
|
|
136
|
+
protocol,
|
|
137
|
+
message: (0, primitives_1.toError)(error).message
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
}
|
|
142
|
+
await Promise.all(protocolPromises);
|
|
120
143
|
if (failures.length > 0) {
|
|
121
144
|
throw new Error(`account_sync protocols failed: ${failures.join(',')}`);
|
|
122
145
|
}
|
|
@@ -136,7 +159,7 @@ async function runAccountSyncProtocol(runtime, protocol) {
|
|
|
136
159
|
await syncAccountBlocklistDirtyBit(runtime);
|
|
137
160
|
return;
|
|
138
161
|
case constants_1.WA_DIRTY_PROTOCOLS.NOTICE:
|
|
139
|
-
|
|
162
|
+
runtime.logger.info('account_sync notice protocol received (no GraphQL/MEX job configured)');
|
|
140
163
|
return;
|
|
141
164
|
default:
|
|
142
165
|
runtime.logger.debug('unsupported account_sync protocol', {
|
|
@@ -211,9 +234,6 @@ async function syncAccountBlocklistDirtyBit(runtime) {
|
|
|
211
234
|
logMessage: 'account_sync blocklist synchronized'
|
|
212
235
|
});
|
|
213
236
|
}
|
|
214
|
-
async function syncAccountNoticeDirtyBit(runtime) {
|
|
215
|
-
runtime.logger.info('account_sync notice protocol received (no GraphQL/MEX job configured)');
|
|
216
|
-
}
|
|
217
237
|
async function syncGroupsDirtyBit(runtime) {
|
|
218
238
|
await runSyncQuery(runtime, {
|
|
219
239
|
queryContext: 'dirty.groups',
|