zapo-js 0.1.1 → 0.1.2
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 +8 -0
- package/dist/appstate/WaAppStateCrypto.js +18 -25
- package/dist/appstate/WaAppStateSyncClient.js +181 -114
- package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
- package/dist/appstate/constants.js +4 -3
- package/dist/appstate/utils.js +10 -30
- package/dist/auth/WaAuthClient.js +48 -55
- package/dist/auth/flow/WaAuthCredentialsFlow.js +21 -14
- package/dist/auth/index.js +1 -3
- package/dist/auth/pairing/WaPairingFlow.js +21 -23
- package/dist/auth/pairing/WaQrFlow.js +37 -24
- package/dist/client/WaClient.js +103 -276
- package/dist/client/WaClientFactory.js +227 -110
- package/dist/client/connection/WaConnectionManager.js +292 -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/WaGroupCoordinator.js +27 -17
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +231 -686
- package/dist/client/coordinators/WaRetryCoordinator.js +70 -37
- package/dist/client/dirty.js +35 -29
- package/dist/client/events/chat.js +4 -3
- package/dist/client/events/group.js +59 -36
- package/dist/client/history-sync.js +53 -63
- package/dist/client/incoming.js +23 -20
- package/dist/client/mailbox.js +8 -8
- package/dist/client/messages.js +4 -4
- package/dist/client/messaging/fanout.js +189 -0
- package/dist/client/messaging/key-protocol.js +130 -0
- package/dist/client/messaging/participants.js +191 -0
- package/dist/crypto/core/hkdf.js +3 -8
- package/dist/crypto/core/index.js +1 -4
- package/dist/crypto/core/keys.js +2 -3
- package/dist/crypto/core/primitives.js +12 -15
- package/dist/crypto/core/random.js +7 -26
- package/dist/crypto/curves/Ed25519.js +7 -8
- package/dist/crypto/curves/X25519.js +13 -16
- package/dist/crypto/index.js +0 -5
- package/dist/esm/appstate/WaAppStateCrypto.js +6 -13
- package/dist/esm/appstate/WaAppStateSyncClient.js +174 -107
- package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
- package/dist/esm/appstate/constants.js +3 -2
- package/dist/esm/appstate/utils.js +8 -27
- package/dist/esm/auth/WaAuthClient.js +48 -55
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +21 -14
- package/dist/esm/auth/index.js +0 -1
- package/dist/esm/auth/pairing/WaPairingFlow.js +14 -16
- package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
- package/dist/esm/client/WaClient.js +103 -276
- package/dist/esm/client/WaClientFactory.js +227 -110
- package/dist/esm/client/connection/WaConnectionManager.js +288 -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/WaGroupCoordinator.js +20 -10
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +232 -687
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +71 -38
- package/dist/esm/client/dirty.js +30 -24
- package/dist/esm/client/events/chat.js +4 -3
- package/dist/esm/client/events/group.js +50 -28
- package/dist/esm/client/history-sync.js +50 -60
- package/dist/esm/client/incoming.js +23 -20
- package/dist/esm/client/mailbox.js +8 -8
- package/dist/esm/client/messages.js +1 -1
- package/dist/esm/client/messaging/fanout.js +186 -0
- package/dist/esm/client/messaging/key-protocol.js +127 -0
- package/dist/esm/client/messaging/participants.js +188 -0
- package/dist/esm/crypto/core/hkdf.js +3 -8
- package/dist/esm/crypto/core/index.js +0 -1
- package/dist/esm/crypto/core/keys.js +2 -3
- package/dist/esm/crypto/core/primitives.js +12 -15
- package/dist/esm/crypto/core/random.js +6 -25
- package/dist/esm/crypto/curves/Ed25519.js +4 -5
- package/dist/esm/crypto/curves/X25519.js +10 -13
- package/dist/esm/crypto/index.js +0 -2
- 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/BoundedTaskQueue.js +13 -17
- package/dist/esm/media/WaMediaCrypto.js +2 -4
- package/dist/esm/media/WaMediaTransferClient.js +226 -58
- package/dist/esm/media/conn.js +10 -6
- package/dist/esm/media/constants.js +4 -1
- package/dist/esm/message/WaMessageClient.js +4 -13
- package/dist/esm/message/ack.js +6 -6
- package/dist/esm/message/addon-crypto.js +59 -0
- package/dist/esm/message/incoming.js +106 -111
- package/dist/esm/message/index.js +2 -0
- package/dist/esm/message/reporting-token.js +438 -0
- package/dist/esm/message/use-case-secret.js +49 -0
- package/dist/esm/protocol/appstate.js +58 -0
- package/dist/esm/protocol/constants.js +2 -1
- package/dist/esm/protocol/index.js +2 -10
- package/dist/esm/protocol/jid.js +63 -51
- package/dist/esm/protocol/media.js +3 -3
- package/dist/esm/protocol/nodes.js +2 -0
- package/dist/esm/protocol/usync.js +11 -0
- package/dist/esm/retry/index.js +1 -0
- package/dist/esm/retry/outbound.js +4 -5
- package/dist/esm/retry/parse.js +58 -76
- package/dist/esm/retry/replay.js +48 -49
- package/dist/esm/retry/tracker.js +56 -0
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +249 -82
- package/dist/esm/signal/api/SignalDigestSyncApi.js +6 -1
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +49 -34
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +70 -62
- package/dist/esm/signal/api/SignalSessionSyncApi.js +23 -30
- package/dist/esm/signal/crypto/WaAdvSignature.js +3 -5
- package/dist/esm/signal/group/SenderKeyChain.js +28 -23
- package/dist/esm/signal/group/SenderKeyCodec.js +2 -4
- package/dist/esm/signal/group/SenderKeyManager.js +26 -16
- package/dist/esm/signal/index.js +1 -0
- package/dist/esm/signal/session/SignalProtocol.js +49 -14
- 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 +186 -0
- package/dist/esm/signal/store/sqlite.js +16 -37
- package/dist/esm/store/createStore.js +16 -18
- package/dist/esm/store/noop.store.js +3 -6
- package/dist/esm/store/providers/memory/appstate.store.js +30 -6
- package/dist/esm/store/providers/memory/contact.store.js +5 -0
- package/dist/esm/store/providers/memory/device-list.store.js +3 -30
- 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/sender-key.store.js +5 -7
- package/dist/esm/store/providers/memory/signal.store.js +13 -1
- package/dist/esm/store/providers/memory/thread.store.js +5 -0
- package/dist/esm/store/providers/sqlite/appstate.store.js +82 -1
- package/dist/esm/store/providers/sqlite/connection.js +18 -13
- package/dist/esm/store/providers/sqlite/contact.store.js +31 -18
- package/dist/esm/store/providers/sqlite/device-list.store.js +7 -35
- package/dist/esm/store/providers/sqlite/message.store.js +45 -32
- package/dist/esm/store/providers/sqlite/migrations.js +1 -1
- package/dist/esm/store/providers/sqlite/participants.store.js +1 -9
- package/dist/esm/store/providers/sqlite/retry.store.js +8 -11
- package/dist/esm/store/providers/sqlite/sender-key.store.js +25 -30
- package/dist/esm/store/providers/sqlite/signal.store.js +104 -22
- package/dist/esm/store/providers/sqlite/table-names.js +107 -0
- package/dist/esm/store/providers/sqlite/thread.store.js +35 -22
- package/dist/esm/transport/WaComms.js +25 -23
- package/dist/esm/transport/WaWebSocket.js +115 -12
- package/dist/esm/transport/binary/decoder.js +4 -4
- package/dist/esm/transport/binary/encoder.js +12 -4
- package/dist/esm/transport/index.js +1 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
- package/dist/esm/transport/node/WaNodeOrchestrator.js +2 -4
- 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/index.js +2 -1
- package/dist/esm/transport/node/builders/message.js +9 -0
- package/dist/esm/transport/node/builders/pairing.js +4 -5
- package/dist/esm/transport/node/builders/usync.js +41 -0
- package/dist/esm/transport/node/helpers.js +107 -5
- package/dist/esm/transport/node/usync.js +35 -0
- package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
- package/dist/esm/transport/noise/WaNoiseCert.js +3 -6
- package/dist/esm/transport/noise/WaNoiseSession.js +17 -10
- package/dist/esm/transport/proxy.js +27 -0
- package/dist/esm/transport/stream/parse.js +13 -48
- package/dist/esm/util/bytes.js +50 -32
- package/dist/esm/util/coercion.js +6 -14
- package/dist/esm/util/primitives.js +39 -14
- 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/BoundedTaskQueue.js +13 -17
- package/dist/media/WaMediaCrypto.js +1 -3
- package/dist/media/WaMediaTransferClient.js +259 -58
- package/dist/media/conn.js +10 -6
- package/dist/media/constants.js +4 -1
- package/dist/message/WaMessageClient.js +5 -14
- package/dist/message/ack.js +6 -6
- package/dist/message/addon-crypto.js +65 -0
- package/dist/message/incoming.js +104 -109
- package/dist/message/index.js +2 -0
- package/dist/message/reporting-token.js +443 -0
- package/dist/message/use-case-secret.js +55 -0
- package/dist/protocol/appstate.js +59 -1
- package/dist/protocol/constants.js +7 -1
- package/dist/protocol/index.js +20 -42
- package/dist/protocol/jid.js +64 -51
- package/dist/protocol/media.js +3 -3
- package/dist/protocol/nodes.js +2 -0
- package/dist/protocol/usync.js +14 -0
- package/dist/retry/index.js +3 -1
- package/dist/retry/outbound.js +6 -7
- package/dist/retry/parse.js +57 -75
- package/dist/retry/replay.js +46 -47
- package/dist/retry/tracker.js +59 -0
- package/dist/signal/api/SignalDeviceSyncApi.js +247 -80
- package/dist/signal/api/SignalDigestSyncApi.js +6 -1
- package/dist/signal/api/SignalIdentitySyncApi.js +49 -34
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +67 -59
- package/dist/signal/api/SignalSessionSyncApi.js +23 -30
- package/dist/signal/crypto/WaAdvSignature.js +2 -4
- package/dist/signal/group/SenderKeyChain.js +27 -22
- package/dist/signal/group/SenderKeyCodec.js +1 -3
- package/dist/signal/group/SenderKeyManager.js +26 -16
- package/dist/signal/index.js +3 -1
- package/dist/signal/session/SignalProtocol.js +49 -14
- package/dist/signal/session/SignalRatchet.js +24 -15
- package/dist/signal/session/SignalSession.js +14 -9
- package/dist/signal/session/resolver.js +189 -0
- package/dist/signal/store/sqlite.js +16 -37
- package/dist/store/createStore.js +16 -18
- package/dist/store/noop.store.js +3 -6
- package/dist/store/providers/memory/appstate.store.js +28 -4
- package/dist/store/providers/memory/contact.store.js +5 -0
- package/dist/store/providers/memory/device-list.store.js +3 -30
- 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/sender-key.store.js +8 -10
- package/dist/store/providers/memory/signal.store.js +21 -9
- package/dist/store/providers/memory/thread.store.js +5 -0
- package/dist/store/providers/sqlite/appstate.store.js +81 -0
- package/dist/store/providers/sqlite/connection.js +18 -13
- package/dist/store/providers/sqlite/contact.store.js +31 -18
- package/dist/store/providers/sqlite/device-list.store.js +7 -35
- package/dist/store/providers/sqlite/message.store.js +45 -32
- package/dist/store/providers/sqlite/migrations.js +1 -1
- package/dist/store/providers/sqlite/participants.store.js +1 -9
- package/dist/store/providers/sqlite/retry.store.js +8 -11
- package/dist/store/providers/sqlite/sender-key.store.js +24 -29
- package/dist/store/providers/sqlite/signal.store.js +105 -23
- package/dist/store/providers/sqlite/table-names.js +113 -0
- package/dist/store/providers/sqlite/thread.store.js +35 -22
- package/dist/transport/WaComms.js +27 -25
- package/dist/transport/WaWebSocket.js +148 -12
- package/dist/transport/binary/decoder.js +4 -4
- package/dist/transport/binary/encoder.js +12 -4
- package/dist/transport/index.js +7 -1
- package/dist/transport/keepalive/WaKeepAlive.js +1 -7
- package/dist/transport/node/WaNodeOrchestrator.js +2 -4
- 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/index.js +12 -9
- package/dist/transport/node/builders/message.js +9 -0
- package/dist/transport/node/builders/pairing.js +4 -5
- package/dist/transport/node/builders/usync.js +45 -0
- package/dist/transport/node/helpers.js +112 -4
- package/dist/transport/node/usync.js +38 -0
- package/dist/transport/noise/WaFrameCodec.js +47 -32
- package/dist/transport/noise/WaNoiseCert.js +5 -8
- package/dist/transport/noise/WaNoiseSession.js +17 -10
- package/dist/transport/proxy.js +34 -0
- package/dist/transport/stream/parse.js +17 -53
- 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/store/sqlite.d.ts +4 -18
- package/dist/types/appstate/utils.d.ts +0 -1
- package/dist/types/auth/WaAuthClient.d.ts +10 -12
- package/dist/types/auth/index.d.ts +0 -2
- package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
- package/dist/types/auth/types.d.ts +6 -9
- package/dist/types/client/WaClient.d.ts +27 -25
- package/dist/types/client/WaClientFactory.d.ts +22 -23
- package/dist/types/client/connection/WaConnectionManager.d.ts +64 -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/WaIncomingNodeCoordinator.d.ts +0 -1
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +18 -41
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +2 -0
- package/dist/types/client/dirty.d.ts +1 -0
- package/dist/types/client/events/group.d.ts +2 -1
- package/dist/types/client/index.d.ts +1 -1
- 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/types.d.ts +24 -1
- package/dist/types/crypto/core/hkdf.d.ts +0 -6
- package/dist/types/crypto/core/index.d.ts +0 -1
- package/dist/types/crypto/core/random.d.ts +1 -7
- package/dist/types/crypto/index.d.ts +0 -2
- package/dist/types/index.d.ts +1 -1
- 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/BoundedTaskQueue.d.ts +1 -1
- package/dist/types/media/WaMediaTransferClient.d.ts +13 -3
- package/dist/types/media/types.d.ts +5 -0
- package/dist/types/message/addon-crypto.d.ts +25 -0
- package/dist/types/message/index.d.ts +2 -0
- package/dist/types/message/reporting-token.d.ts +19 -0
- package/dist/types/message/use-case-secret.d.ts +20 -0
- package/dist/types/protocol/appstate.d.ts +58 -0
- package/dist/types/protocol/constants.d.ts +2 -1
- package/dist/types/protocol/index.d.ts +2 -10
- package/dist/types/protocol/jid.d.ts +3 -3
- package/dist/types/protocol/nodes.d.ts +2 -0
- package/dist/types/protocol/usync.d.ts +11 -0
- package/dist/types/retry/index.d.ts +1 -0
- package/dist/types/retry/replay.d.ts +0 -4
- package/dist/types/retry/tracker.d.ts +19 -0
- package/dist/types/retry/types.d.ts +4 -3
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +13 -1
- package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
- package/dist/types/signal/index.d.ts +1 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +9 -0
- package/dist/types/signal/session/resolver.d.ts +17 -0
- package/dist/types/store/contracts/appstate.store.d.ts +3 -0
- 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/sender-key.store.d.ts +0 -1
- package/dist/types/store/contracts/signal.store.d.ts +6 -0
- package/dist/types/store/contracts/thread.store.d.ts +1 -0
- package/dist/types/store/index.d.ts +1 -1
- package/dist/types/store/providers/memory/appstate.store.d.ts +2 -0
- 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/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/memory/signal.store.d.ts +6 -0
- package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
- package/dist/types/store/providers/sqlite/appstate.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/contact.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -3
- package/dist/types/store/providers/sqlite/message.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/signal.store.d.ts +7 -0
- package/dist/types/store/providers/sqlite/table-names.d.ts +5 -0
- package/dist/types/store/providers/sqlite/thread.store.d.ts +2 -0
- package/dist/types/store/types.d.ts +3 -0
- package/dist/types/transport/WaWebSocket.d.ts +3 -0
- package/dist/types/transport/index.d.ts +2 -1
- package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
- package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
- package/dist/types/transport/node/builders/group.d.ts +4 -6
- package/dist/types/transport/node/builders/index.d.ts +2 -1
- package/dist/types/transport/node/builders/message.d.ts +14 -25
- package/dist/types/transport/node/builders/retry.d.ts +2 -4
- package/dist/types/transport/node/builders/usync.d.ts +21 -0
- package/dist/types/transport/node/helpers.d.ts +8 -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 +1 -0
- 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/primitives.d.ts +3 -0
- package/dist/util/bytes.js +55 -33
- package/dist/util/coercion.js +6 -14
- package/dist/util/primitives.js +42 -14
- package/package.json +26 -5
- package/dist/crypto/core/encoding.js +0 -29
- package/dist/esm/crypto/core/encoding.js +0 -25
- package/dist/esm/util/base64.js +0 -18
- package/dist/esm/util/signal-address.js +0 -5
- package/dist/types/crypto/core/encoding.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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { RETRY_OUTBOUND_TTL_MS } from './constants.js';
|
|
2
|
+
import { encodeRetryReplayPayload } from './outbound.js';
|
|
3
|
+
import { toError } from '../util/primitives.js';
|
|
4
|
+
export function createOutboundRetryTracker(options) {
|
|
5
|
+
const { retryStore, logger } = options;
|
|
6
|
+
const retryTtlMs = retryStore.getTtlMs?.() ?? RETRY_OUTBOUND_TTL_MS;
|
|
7
|
+
const safeUpsertRetryOutboundRecord = async (record) => {
|
|
8
|
+
try {
|
|
9
|
+
await retryStore.upsertOutboundMessage(record);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
logger.warn('failed to persist retry outbound message record', {
|
|
13
|
+
messageId: record.messageId,
|
|
14
|
+
to: record.toJid,
|
|
15
|
+
mode: record.replayMode,
|
|
16
|
+
message: toError(error).message
|
|
17
|
+
});
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
track: async (hint, publish) => {
|
|
24
|
+
const nowMs = Date.now();
|
|
25
|
+
const expiresAtMs = nowMs + retryTtlMs;
|
|
26
|
+
const hintedMessageId = hint.messageIdHint?.trim();
|
|
27
|
+
const replayMode = hint.replayPayload.mode;
|
|
28
|
+
const resolvedToJid = hint.toJid ?? (replayMode === 'opaque_node' ? '' : hint.replayPayload.to);
|
|
29
|
+
const replayPayload = encodeRetryReplayPayload(hint.replayPayload);
|
|
30
|
+
let hintedPersisted = false;
|
|
31
|
+
const createRetryOutboundRecord = (messageId, createdAtMs, updatedAtMs, expiresAtMs) => ({
|
|
32
|
+
messageId,
|
|
33
|
+
toJid: resolvedToJid,
|
|
34
|
+
participantJid: hint.participantJid,
|
|
35
|
+
recipientJid: hint.recipientJid,
|
|
36
|
+
messageType: hint.type,
|
|
37
|
+
replayMode,
|
|
38
|
+
replayPayload,
|
|
39
|
+
state: 'pending',
|
|
40
|
+
createdAtMs,
|
|
41
|
+
updatedAtMs,
|
|
42
|
+
expiresAtMs
|
|
43
|
+
});
|
|
44
|
+
if (hintedMessageId) {
|
|
45
|
+
hintedPersisted = await safeUpsertRetryOutboundRecord(createRetryOutboundRecord(hintedMessageId, nowMs, nowMs, expiresAtMs));
|
|
46
|
+
}
|
|
47
|
+
const result = await publish();
|
|
48
|
+
if (hintedPersisted && hintedMessageId && result.id === hintedMessageId) {
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
const persistedNowMs = Date.now();
|
|
52
|
+
await safeUpsertRetryOutboundRecord(createRetryOutboundRecord(result.id, hintedMessageId ? nowMs : persistedNowMs, persistedNowMs, persistedNowMs + retryTtlMs));
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { WA_DEFAULTS, WA_NODE_TAGS, WA_XMLNS } from '../../protocol/constants.js';
|
|
1
|
+
import { WA_DEFAULTS, WA_NODE_TAGS, WA_USYNC_CONTEXTS } from '../../protocol/constants.js';
|
|
3
2
|
import { parseSignalAddressFromJid, splitJid } from '../../protocol/jid.js';
|
|
3
|
+
import { buildUsyncIq } from '../../transport/node/builders/usync.js';
|
|
4
4
|
import { findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
|
|
5
|
-
import { assertIqResult
|
|
5
|
+
import { assertIqResult } from '../../transport/node/query.js';
|
|
6
|
+
import { createUsyncSidGenerator } from '../../transport/node/usync.js';
|
|
6
7
|
export class SignalDeviceSyncApi {
|
|
7
8
|
constructor(options) {
|
|
8
9
|
this.logger = options.logger;
|
|
@@ -11,6 +12,7 @@ export class SignalDeviceSyncApi {
|
|
|
11
12
|
this.defaultTimeoutMs =
|
|
12
13
|
options.defaultTimeoutMs ?? WA_DEFAULTS.SIGNAL_FETCH_KEY_BUNDLES_TIMEOUT_MS;
|
|
13
14
|
this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
|
|
15
|
+
this.generateSid = options.generateSid ?? createUsyncSidGenerator();
|
|
14
16
|
}
|
|
15
17
|
async syncDeviceList(userJids, timeoutMs = this.defaultTimeoutMs) {
|
|
16
18
|
const normalizedUsers = this.normalizeUsers(userJids);
|
|
@@ -23,12 +25,18 @@ export class SignalDeviceSyncApi {
|
|
|
23
25
|
? await this.collectUsersToQuery(normalizedUsers, nowMs, cachedByUser, this.deviceListStore)
|
|
24
26
|
: normalizedUsers;
|
|
25
27
|
if (usersToQuery.length === 0) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const fromCache = new Array(normalizedUsers.length);
|
|
29
|
+
for (let index = 0; index < normalizedUsers.length; index += 1) {
|
|
30
|
+
const jid = normalizedUsers[index];
|
|
31
|
+
fromCache[index] = {
|
|
32
|
+
jid,
|
|
33
|
+
deviceJids: cachedByUser.get(jid) ?? []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return fromCache;
|
|
30
37
|
}
|
|
31
|
-
const
|
|
38
|
+
const sid = await this.generateSid();
|
|
39
|
+
const request = this.makeDeviceSyncRequest(usersToQuery, sid);
|
|
32
40
|
this.logger.debug('signal device sync request', {
|
|
33
41
|
users: usersToQuery.length,
|
|
34
42
|
timeoutMs
|
|
@@ -37,23 +45,82 @@ export class SignalDeviceSyncApi {
|
|
|
37
45
|
const parsed = this.parseDeviceSyncResponse(response, usersToQuery);
|
|
38
46
|
if (this.deviceListStore) {
|
|
39
47
|
const updatedAtMs = Date.now();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
48
|
+
const batch = new Array(parsed.length);
|
|
49
|
+
for (let index = 0; index < parsed.length; index += 1) {
|
|
50
|
+
const entry = parsed[index];
|
|
51
|
+
batch[index] = {
|
|
52
|
+
userJid: entry.jid,
|
|
53
|
+
deviceJids: entry.deviceJids,
|
|
54
|
+
updatedAtMs
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
await this.deviceListStore.upsertUserDevicesBatch(batch);
|
|
58
|
+
}
|
|
59
|
+
const parsedByUser = new Map();
|
|
60
|
+
for (let index = 0; index < parsed.length; index += 1) {
|
|
61
|
+
const entry = parsed[index];
|
|
62
|
+
parsedByUser.set(entry.jid, entry.deviceJids);
|
|
63
|
+
}
|
|
64
|
+
const merged = new Array(normalizedUsers.length);
|
|
65
|
+
let totalDevices = 0;
|
|
66
|
+
for (let index = 0; index < normalizedUsers.length; index += 1) {
|
|
67
|
+
const jid = normalizedUsers[index];
|
|
68
|
+
const deviceJids = parsedByUser.get(jid) ?? cachedByUser.get(jid) ?? [];
|
|
69
|
+
totalDevices += deviceJids.length;
|
|
70
|
+
merged[index] = {
|
|
71
|
+
jid,
|
|
72
|
+
deviceJids
|
|
73
|
+
};
|
|
74
|
+
}
|
|
51
75
|
this.logger.debug('signal device sync success', {
|
|
52
76
|
users: merged.length,
|
|
53
|
-
devices:
|
|
77
|
+
devices: totalDevices
|
|
54
78
|
});
|
|
55
79
|
return merged;
|
|
56
80
|
}
|
|
81
|
+
async queryLidsByPhoneJids(phoneJids, timeoutMs = this.defaultTimeoutMs) {
|
|
82
|
+
const normalizedPhoneJids = this.normalizeUsers(phoneJids);
|
|
83
|
+
if (normalizedPhoneJids.length === 0) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const sid = await this.generateSid();
|
|
87
|
+
const request = this.makeLidSyncRequest(normalizedPhoneJids, sid);
|
|
88
|
+
this.logger.debug('signal lid sync request', {
|
|
89
|
+
users: normalizedPhoneJids.length,
|
|
90
|
+
timeoutMs
|
|
91
|
+
});
|
|
92
|
+
const response = await this.query(request, timeoutMs);
|
|
93
|
+
const parsed = this.parseLidSyncResponse(response, normalizedPhoneJids);
|
|
94
|
+
const parsedByPhoneJid = new Map();
|
|
95
|
+
for (let index = 0; index < parsed.length; index += 1) {
|
|
96
|
+
const entry = parsed[index];
|
|
97
|
+
const phoneJid = entry.phoneJid ?? entry.jid;
|
|
98
|
+
parsedByPhoneJid.set(phoneJid, {
|
|
99
|
+
phoneJid,
|
|
100
|
+
lidJid: entry.lidJid,
|
|
101
|
+
exists: entry.exists
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const result = new Array(normalizedPhoneJids.length);
|
|
105
|
+
let found = 0;
|
|
106
|
+
for (let index = 0; index < normalizedPhoneJids.length; index += 1) {
|
|
107
|
+
const phoneJid = normalizedPhoneJids[index];
|
|
108
|
+
const resolved = parsedByPhoneJid.get(phoneJid) ?? {
|
|
109
|
+
phoneJid,
|
|
110
|
+
lidJid: null,
|
|
111
|
+
exists: false
|
|
112
|
+
};
|
|
113
|
+
if (resolved.exists) {
|
|
114
|
+
found += 1;
|
|
115
|
+
}
|
|
116
|
+
result[index] = resolved;
|
|
117
|
+
}
|
|
118
|
+
this.logger.debug('signal lid sync success', {
|
|
119
|
+
users: result.length,
|
|
120
|
+
found
|
|
121
|
+
});
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
57
124
|
async collectUsersToQuery(normalizedUsers, nowMs, cachedByUser, store) {
|
|
58
125
|
const records = await store.getUserDevicesBatch(normalizedUsers, nowMs);
|
|
59
126
|
const usersToQuery = [];
|
|
@@ -68,41 +135,59 @@ export class SignalDeviceSyncApi {
|
|
|
68
135
|
}
|
|
69
136
|
return usersToQuery;
|
|
70
137
|
}
|
|
71
|
-
makeDeviceSyncRequest(userJids) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
138
|
+
makeDeviceSyncRequest(userJids, sid) {
|
|
139
|
+
const users = new Array(userJids.length);
|
|
140
|
+
for (let index = 0; index < userJids.length; index += 1) {
|
|
141
|
+
users[index] = {
|
|
142
|
+
jid: userJids[index]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return buildUsyncIq({
|
|
146
|
+
sid,
|
|
147
|
+
hostDomain: this.hostDomain,
|
|
148
|
+
context: WA_USYNC_CONTEXTS.INTERACTIVE,
|
|
149
|
+
queryProtocolNodes: [
|
|
150
|
+
{
|
|
151
|
+
tag: WA_NODE_TAGS.DEVICES,
|
|
152
|
+
attrs: {
|
|
153
|
+
version: '2'
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
users
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
makeLidSyncRequest(userJids, sid) {
|
|
161
|
+
const users = new Array(userJids.length);
|
|
162
|
+
for (let index = 0; index < userJids.length; index += 1) {
|
|
163
|
+
const jid = userJids[index];
|
|
164
|
+
users[index] = {
|
|
165
|
+
jid,
|
|
82
166
|
content: [
|
|
83
167
|
{
|
|
84
|
-
tag: WA_NODE_TAGS.
|
|
85
|
-
attrs: {},
|
|
86
|
-
content: [
|
|
87
|
-
{
|
|
88
|
-
tag: WA_NODE_TAGS.DEVICES,
|
|
89
|
-
attrs: {
|
|
90
|
-
version: '2'
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
tag: WA_NODE_TAGS.LIST,
|
|
168
|
+
tag: WA_NODE_TAGS.CONTACT,
|
|
97
169
|
attrs: {},
|
|
98
|
-
content:
|
|
99
|
-
tag: WA_NODE_TAGS.USER,
|
|
100
|
-
attrs: { jid }
|
|
101
|
-
}))
|
|
170
|
+
content: splitJid(jid).user
|
|
102
171
|
}
|
|
103
172
|
]
|
|
104
|
-
}
|
|
105
|
-
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return buildUsyncIq({
|
|
176
|
+
sid,
|
|
177
|
+
hostDomain: this.hostDomain,
|
|
178
|
+
context: WA_USYNC_CONTEXTS.INTERACTIVE,
|
|
179
|
+
queryProtocolNodes: [
|
|
180
|
+
{
|
|
181
|
+
tag: WA_NODE_TAGS.CONTACT,
|
|
182
|
+
attrs: {}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
tag: WA_NODE_TAGS.LID,
|
|
186
|
+
attrs: {}
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
users
|
|
190
|
+
});
|
|
106
191
|
}
|
|
107
192
|
parseDeviceSyncResponse(node, requestedUsers) {
|
|
108
193
|
assertIqResult(node, 'signal device sync');
|
|
@@ -116,22 +201,95 @@ export class SignalDeviceSyncApi {
|
|
|
116
201
|
}
|
|
117
202
|
const requestedSet = new Set(requestedUsers);
|
|
118
203
|
const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
|
|
119
|
-
|
|
204
|
+
const parsed = [];
|
|
205
|
+
for (let index = 0; index < userNodes.length; index += 1) {
|
|
206
|
+
const userNode = userNodes[index];
|
|
120
207
|
const userJid = userNode.attrs.jid;
|
|
121
208
|
if (!userJid) {
|
|
122
|
-
|
|
209
|
+
continue;
|
|
123
210
|
}
|
|
124
211
|
const normalizedUserJid = this.normalizeUserJid(userJid);
|
|
125
212
|
if (!requestedSet.has(normalizedUserJid)) {
|
|
126
|
-
|
|
213
|
+
continue;
|
|
127
214
|
}
|
|
128
|
-
|
|
129
|
-
|
|
215
|
+
parsed.push({
|
|
216
|
+
jid: normalizedUserJid,
|
|
217
|
+
deviceJids: this.parseUserDeviceJids(userNode, normalizedUserJid)
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return parsed;
|
|
221
|
+
}
|
|
222
|
+
parseLidSyncResponse(node, requestedUsers) {
|
|
223
|
+
assertIqResult(node, 'signal lid sync');
|
|
224
|
+
const usyncNode = findNodeChild(node, WA_NODE_TAGS.USYNC);
|
|
225
|
+
if (!usyncNode) {
|
|
226
|
+
throw new Error('signal lid sync response missing usync node');
|
|
227
|
+
}
|
|
228
|
+
const listNode = findNodeChild(usyncNode, WA_NODE_TAGS.LIST);
|
|
229
|
+
if (!listNode) {
|
|
230
|
+
throw new Error('signal lid sync response missing list node');
|
|
231
|
+
}
|
|
232
|
+
const requestedSet = new Set(requestedUsers);
|
|
233
|
+
const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
|
|
234
|
+
const parsed = [];
|
|
235
|
+
for (let index = 0; index < userNodes.length; index += 1) {
|
|
236
|
+
const userNode = userNodes[index];
|
|
237
|
+
const userJid = userNode.attrs.jid;
|
|
238
|
+
if (!userJid) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const normalizedUserJid = this.normalizeUserJid(userJid);
|
|
242
|
+
const normalizedPhoneJid = userNode.attrs.pn_jid
|
|
243
|
+
? this.normalizeUserJid(userNode.attrs.pn_jid)
|
|
244
|
+
: null;
|
|
245
|
+
const wasRequested = requestedSet.has(normalizedUserJid) ||
|
|
246
|
+
(normalizedPhoneJid !== null && requestedSet.has(normalizedPhoneJid));
|
|
247
|
+
if (!wasRequested) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const lidNode = findNodeChild(userNode, WA_NODE_TAGS.LID);
|
|
251
|
+
const contactNode = findNodeChild(userNode, WA_NODE_TAGS.CONTACT);
|
|
252
|
+
if (!lidNode) {
|
|
253
|
+
parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null));
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const errorNode = findNodeChild(lidNode, WA_NODE_TAGS.ERROR);
|
|
257
|
+
if (errorNode) {
|
|
258
|
+
this.logger.warn('signal lid sync user error', {
|
|
130
259
|
jid: normalizedUserJid,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
260
|
+
code: errorNode.attrs.code,
|
|
261
|
+
text: errorNode.attrs.text
|
|
262
|
+
});
|
|
263
|
+
parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, null));
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const lidJid = lidNode.attrs.val ? this.normalizeUserJid(lidNode.attrs.val) : null;
|
|
267
|
+
parsed.push(this.buildLidSyncResult(normalizedUserJid, normalizedPhoneJid, contactNode, lidJid));
|
|
268
|
+
}
|
|
269
|
+
return parsed;
|
|
270
|
+
}
|
|
271
|
+
buildLidSyncResult(jid, phoneJid, contactNode, lidJid) {
|
|
272
|
+
return {
|
|
273
|
+
jid,
|
|
274
|
+
lidJid,
|
|
275
|
+
phoneJid,
|
|
276
|
+
exists: this.parseLidSyncContactExists(contactNode, jid, lidJid !== null)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
parseLidSyncContactExists(contactNode, userJid, defaultExists) {
|
|
280
|
+
if (!contactNode) {
|
|
281
|
+
return defaultExists;
|
|
282
|
+
}
|
|
283
|
+
const errorNode = findNodeChild(contactNode, WA_NODE_TAGS.ERROR);
|
|
284
|
+
if (errorNode) {
|
|
285
|
+
this.logger.warn('signal lid sync contact error', {
|
|
286
|
+
jid: userJid,
|
|
287
|
+
code: errorNode.attrs.code,
|
|
288
|
+
text: errorNode.attrs.text
|
|
289
|
+
});
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
return contactNode.attrs.type === 'in';
|
|
135
293
|
}
|
|
136
294
|
parseUserDeviceJids(userNode, userJid) {
|
|
137
295
|
const devicesNode = findNodeChild(userNode, WA_NODE_TAGS.DEVICES);
|
|
@@ -151,35 +309,44 @@ export class SignalDeviceSyncApi {
|
|
|
151
309
|
if (!deviceListNode) {
|
|
152
310
|
return [];
|
|
153
311
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
];
|
|
312
|
+
const parsedUser = splitJid(userJid);
|
|
313
|
+
const dedup = new Set();
|
|
314
|
+
for (const deviceNode of getNodeChildrenByTag(deviceListNode, 'device')) {
|
|
315
|
+
const parsedId = deviceNode.attrs.id
|
|
316
|
+
? Number.parseInt(deviceNode.attrs.id, 10)
|
|
317
|
+
: Number.NaN;
|
|
318
|
+
if (!Number.isSafeInteger(parsedId) || parsedId < 0) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
dedup.add(this.toDeviceJid(parsedUser.user, parsedUser.server, parsedId));
|
|
322
|
+
}
|
|
323
|
+
const deviceJids = [];
|
|
324
|
+
for (const jid of dedup.values()) {
|
|
325
|
+
deviceJids.push(jid);
|
|
326
|
+
}
|
|
327
|
+
return deviceJids;
|
|
166
328
|
}
|
|
167
329
|
normalizeUsers(userJids) {
|
|
168
|
-
|
|
330
|
+
const normalized = [];
|
|
331
|
+
const dedup = new Set();
|
|
332
|
+
for (let index = 0; index < userJids.length; index += 1) {
|
|
333
|
+
const normalizedJid = this.normalizeUserJid(userJids[index]);
|
|
334
|
+
if (dedup.has(normalizedJid)) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
dedup.add(normalizedJid);
|
|
338
|
+
normalized.push(normalizedJid);
|
|
339
|
+
}
|
|
340
|
+
return normalized;
|
|
169
341
|
}
|
|
170
342
|
normalizeUserJid(jid) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
return `${user}@${server}`;
|
|
343
|
+
const address = parseSignalAddressFromJid(jid);
|
|
344
|
+
return `${address.user}@${address.server}`;
|
|
174
345
|
}
|
|
175
|
-
toDeviceJid(
|
|
176
|
-
const parsed = splitJid(userJid);
|
|
346
|
+
toDeviceJid(user, server, deviceId) {
|
|
177
347
|
if (deviceId === 0) {
|
|
178
|
-
return `${
|
|
348
|
+
return `${user}@${server}`;
|
|
179
349
|
}
|
|
180
|
-
return `${
|
|
181
|
-
}
|
|
182
|
-
makeSid() {
|
|
183
|
-
return `${Date.now()}.${randomInt(1000000)}`;
|
|
350
|
+
return `${user}:${deviceId}@${server}`;
|
|
184
351
|
}
|
|
185
352
|
}
|
|
@@ -161,7 +161,12 @@ export class SignalDigestSyncApi {
|
|
|
161
161
|
const signedKeyId = parseUint(decodeExactLength(signedKeyIdNode.content, 'signal digest skey.id', SIGNAL_KEY_ID_LENGTH), 'signal digest skey.id');
|
|
162
162
|
const signedKeyPublicKey = decodeExactLength(signedKeyValueNode.content, 'signal digest skey.value', SIGNAL_KEY_DATA_LENGTH);
|
|
163
163
|
const signedKeySignature = decodeExactLength(signedKeySignatureNode.content, 'signal digest skey.signature', SIGNAL_SIGNATURE_LENGTH);
|
|
164
|
-
const preKeyIds =
|
|
164
|
+
const preKeyIds = [];
|
|
165
|
+
const listChildren = getNodeChildren(listNode);
|
|
166
|
+
for (let index = 0; index < listChildren.length; index += 1) {
|
|
167
|
+
const child = listChildren[index];
|
|
168
|
+
preKeyIds.push(parseUint(decodeExactLength(child.content, `signal digest list[${index}]`, SIGNAL_KEY_ID_LENGTH), `signal digest list[${index}]`));
|
|
169
|
+
}
|
|
165
170
|
const hash = decodeNodeContentBase64OrBytes(hashNode.content, 'signal digest hash');
|
|
166
171
|
return {
|
|
167
172
|
registrationId,
|
|
@@ -4,6 +4,7 @@ import { normalizeDeviceJid, parseSignalAddressFromJid } from '../../protocol/ji
|
|
|
4
4
|
import { decodeExactLength, parseUint } from '../api/codec.js';
|
|
5
5
|
import { SIGNAL_KEY_BUNDLE_TYPE_LENGTH, SIGNAL_KEY_DATA_LENGTH } from '../api/constants.js';
|
|
6
6
|
import { findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
|
|
7
|
+
import { assertIqResult } from '../../transport/node/query.js';
|
|
7
8
|
export class SignalIdentitySyncApi {
|
|
8
9
|
constructor(options) {
|
|
9
10
|
this.logger = options.logger;
|
|
@@ -14,10 +15,28 @@ export class SignalIdentitySyncApi {
|
|
|
14
15
|
this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
|
|
15
16
|
}
|
|
16
17
|
async syncIdentityKeys(targetJids, timeoutMs = this.defaultTimeoutMs) {
|
|
17
|
-
const normalizedTargets = [
|
|
18
|
+
const normalizedTargets = [];
|
|
19
|
+
const dedup = new Set();
|
|
20
|
+
for (let index = 0; index < targetJids.length; index += 1) {
|
|
21
|
+
const normalized = normalizeDeviceJid(targetJids[index]);
|
|
22
|
+
if (dedup.has(normalized)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
dedup.add(normalized);
|
|
26
|
+
normalizedTargets.push(normalized);
|
|
27
|
+
}
|
|
18
28
|
if (normalizedTargets.length === 0) {
|
|
19
29
|
return [];
|
|
20
30
|
}
|
|
31
|
+
const users = new Array(normalizedTargets.length);
|
|
32
|
+
for (let index = 0; index < normalizedTargets.length; index += 1) {
|
|
33
|
+
users[index] = {
|
|
34
|
+
tag: WA_NODE_TAGS.USER,
|
|
35
|
+
attrs: {
|
|
36
|
+
jid: normalizedTargets[index]
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
21
40
|
this.logger.debug('signal identity sync request', {
|
|
22
41
|
targets: normalizedTargets.length,
|
|
23
42
|
timeoutMs
|
|
@@ -33,20 +52,22 @@ export class SignalIdentitySyncApi {
|
|
|
33
52
|
{
|
|
34
53
|
tag: WA_NODE_TAGS.IDENTITY,
|
|
35
54
|
attrs: {},
|
|
36
|
-
content:
|
|
37
|
-
tag: WA_NODE_TAGS.USER,
|
|
38
|
-
attrs: { jid }
|
|
39
|
-
}))
|
|
55
|
+
content: users
|
|
40
56
|
}
|
|
41
57
|
]
|
|
42
58
|
}, timeoutMs);
|
|
43
59
|
const entries = this.parseIdentitySyncResponse(response, normalizedTargets);
|
|
44
60
|
const { signalStore } = this;
|
|
45
61
|
if (signalStore && entries.length > 0) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
const identities = new Array(entries.length);
|
|
63
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
64
|
+
const entry = entries[index];
|
|
65
|
+
identities[index] = {
|
|
66
|
+
address: parseSignalAddressFromJid(entry.jid),
|
|
67
|
+
identityKey: toSerializedPubKey(entry.identity)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
await signalStore.setRemoteIdentities(identities);
|
|
50
71
|
}
|
|
51
72
|
this.logger.debug('signal identity sync success', {
|
|
52
73
|
requested: normalizedTargets.length,
|
|
@@ -55,31 +76,19 @@ export class SignalIdentitySyncApi {
|
|
|
55
76
|
return entries;
|
|
56
77
|
}
|
|
57
78
|
parseIdentitySyncResponse(node, requestedJids) {
|
|
58
|
-
|
|
59
|
-
throw new Error(`invalid identity sync response tag: ${node.tag}`);
|
|
60
|
-
}
|
|
61
|
-
if (node.attrs.type === WA_IQ_TYPES.ERROR) {
|
|
62
|
-
const errorNode = findNodeChild(node, WA_NODE_TAGS.ERROR);
|
|
63
|
-
if (!errorNode) {
|
|
64
|
-
throw new Error(`identity sync iq error for ${node.attrs.id ?? 'unknown id'}`);
|
|
65
|
-
}
|
|
66
|
-
const code = errorNode.attrs.code ?? 'unknown';
|
|
67
|
-
const text = errorNode.attrs.text ?? errorNode.attrs.type ?? 'unknown';
|
|
68
|
-
throw new Error(`identity sync iq error (${code} ${text})`);
|
|
69
|
-
}
|
|
70
|
-
if (node.attrs.type !== WA_IQ_TYPES.RESULT) {
|
|
71
|
-
throw new Error(`invalid identity sync response type: ${node.attrs.type ?? 'unknown'}`);
|
|
72
|
-
}
|
|
79
|
+
assertIqResult(node, 'identity sync');
|
|
73
80
|
const listNode = findNodeChild(node, WA_NODE_TAGS.LIST);
|
|
74
81
|
if (!listNode) {
|
|
75
82
|
throw new Error('identity sync response missing list node');
|
|
76
83
|
}
|
|
77
84
|
const requested = new Set(requestedJids);
|
|
78
85
|
const userNodes = getNodeChildrenByTag(listNode, WA_NODE_TAGS.USER);
|
|
79
|
-
|
|
86
|
+
const parsed = [];
|
|
87
|
+
for (let index = 0; index < userNodes.length; index += 1) {
|
|
88
|
+
const userNode = userNodes[index];
|
|
80
89
|
const jid = userNode.attrs.jid ? normalizeDeviceJid(userNode.attrs.jid) : '';
|
|
81
90
|
if (!jid || !requested.has(jid)) {
|
|
82
|
-
|
|
91
|
+
continue;
|
|
83
92
|
}
|
|
84
93
|
const errorNode = findNodeChild(userNode, WA_NODE_TAGS.ERROR);
|
|
85
94
|
if (errorNode) {
|
|
@@ -88,7 +97,7 @@ export class SignalIdentitySyncApi {
|
|
|
88
97
|
code: errorNode.attrs.code,
|
|
89
98
|
text: errorNode.attrs.text
|
|
90
99
|
});
|
|
91
|
-
|
|
100
|
+
continue;
|
|
92
101
|
}
|
|
93
102
|
const identityNode = findNodeChild(userNode, WA_NODE_TAGS.IDENTITY);
|
|
94
103
|
if (!identityNode) {
|
|
@@ -99,13 +108,19 @@ export class SignalIdentitySyncApi {
|
|
|
99
108
|
const parsedType = typeNode
|
|
100
109
|
? parseUint(decodeExactLength(typeNode.content, 'identity sync type', SIGNAL_KEY_BUNDLE_TYPE_LENGTH), 'identity sync type')
|
|
101
110
|
: undefined;
|
|
102
|
-
|
|
103
|
-
{
|
|
111
|
+
if (parsedType === undefined) {
|
|
112
|
+
parsed.push({
|
|
104
113
|
jid,
|
|
105
|
-
identity
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
identity
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
parsed.push({
|
|
119
|
+
jid,
|
|
120
|
+
identity,
|
|
121
|
+
type: parsedType
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return parsed;
|
|
110
125
|
}
|
|
111
126
|
}
|