zapo-js 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/dist/appstate/WaAppStateCrypto.js +19 -26
- package/dist/appstate/WaAppStateSyncClient.js +293 -181
- package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
- package/dist/appstate/constants.js +4 -3
- package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/appstate/index.js +8 -6
- package/dist/appstate/utils.js +9 -34
- package/dist/auth/WaAuthClient.js +43 -61
- package/dist/auth/flow/WaAuthCredentialsFlow.js +22 -15
- package/dist/auth/index.js +1 -8
- package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/auth/pairing/WaPairingFlow.js +34 -26
- package/dist/auth/pairing/WaQrFlow.js +37 -24
- package/dist/client/WaClient.js +275 -324
- package/dist/client/WaClientFactory.js +500 -133
- package/dist/client/connection/WaConnectionManager.js +301 -0
- package/dist/client/connection/WaKeyShareCoordinator.js +63 -0
- package/dist/client/connection/WaReceiptQueue.js +51 -0
- package/dist/client/coordinators/WaAppStateMutationCoordinator.js +471 -0
- package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
- package/dist/client/coordinators/WaGroupCoordinator.js +30 -16
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +439 -701
- package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
- package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
- package/dist/client/coordinators/WaRetryCoordinator.js +242 -57
- package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
- package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
- package/dist/client/dirty.js +74 -48
- package/dist/client/events/chat.js +4 -3
- package/dist/client/events/devices.js +72 -0
- package/dist/client/events/group.js +62 -47
- package/dist/client/events/identity.js +22 -0
- package/dist/client/events/privacy-token.js +39 -0
- package/dist/client/history-sync.js +94 -63
- package/dist/client/incoming.js +60 -27
- package/dist/client/mailbox.js +24 -23
- package/dist/client/messages.js +107 -31
- package/dist/client/messaging/fanout.js +199 -0
- package/dist/client/messaging/key-protocol.js +130 -0
- package/dist/client/messaging/participants.js +193 -0
- package/dist/client/persistence/WriteBehindPersistence.js +129 -0
- package/dist/client/tokens/cs-token.js +50 -0
- package/dist/client/tokens/tc-token.js +25 -0
- package/dist/crypto/core/hkdf.js +3 -8
- package/dist/crypto/core/index.js +2 -5
- package/dist/crypto/core/keys.js +6 -7
- package/dist/crypto/core/nonce.js +2 -0
- package/dist/crypto/core/primitives.js +12 -23
- package/dist/crypto/core/random.js +26 -23
- package/dist/crypto/curves/Ed25519.js +7 -8
- package/dist/crypto/curves/X25519.js +38 -22
- package/dist/crypto/index.js +1 -3
- package/dist/crypto/math/constants.js +13 -36
- package/dist/crypto/math/edwards.js +171 -44
- package/dist/crypto/math/fe.js +706 -0
- package/dist/crypto/math/mod.js +10 -3
- package/dist/esm/appstate/WaAppStateCrypto.js +7 -14
- package/dist/esm/appstate/WaAppStateSyncClient.js +284 -172
- package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
- package/dist/esm/appstate/constants.js +3 -2
- package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/esm/appstate/index.js +2 -2
- package/dist/esm/appstate/utils.js +8 -30
- package/dist/esm/auth/WaAuthClient.js +43 -61
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +22 -15
- package/dist/esm/auth/index.js +0 -3
- package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/esm/auth/pairing/WaPairingFlow.js +28 -20
- package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
- package/dist/esm/client/WaClient.js +275 -324
- package/dist/esm/client/WaClientFactory.js +501 -134
- package/dist/esm/client/connection/WaConnectionManager.js +297 -0
- package/dist/esm/client/connection/WaKeyShareCoordinator.js +59 -0
- package/dist/esm/client/connection/WaReceiptQueue.js +47 -0
- package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +467 -0
- package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +23 -9
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +21 -27
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +443 -705
- package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
- package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +244 -59
- package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
- package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
- package/dist/esm/client/dirty.js +69 -43
- package/dist/esm/client/events/chat.js +4 -3
- package/dist/esm/client/events/devices.js +68 -0
- package/dist/esm/client/events/group.js +53 -39
- package/dist/esm/client/events/identity.js +19 -0
- package/dist/esm/client/events/privacy-token.js +36 -0
- package/dist/esm/client/history-sync.js +91 -60
- package/dist/esm/client/incoming.js +61 -28
- package/dist/esm/client/mailbox.js +24 -23
- package/dist/esm/client/messages.js +108 -32
- package/dist/esm/client/messaging/fanout.js +196 -0
- package/dist/esm/client/messaging/key-protocol.js +127 -0
- package/dist/esm/client/messaging/participants.js +190 -0
- package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
- package/dist/esm/client/tokens/cs-token.js +46 -0
- package/dist/esm/client/tokens/tc-token.js +18 -0
- package/dist/esm/crypto/core/hkdf.js +3 -8
- package/dist/esm/crypto/core/index.js +2 -3
- package/dist/esm/crypto/core/keys.js +3 -4
- package/dist/esm/crypto/core/nonce.js +2 -0
- package/dist/esm/crypto/core/primitives.js +12 -22
- package/dist/esm/crypto/core/random.js +25 -23
- package/dist/esm/crypto/curves/Ed25519.js +4 -5
- package/dist/esm/crypto/curves/X25519.js +35 -19
- package/dist/esm/crypto/index.js +0 -1
- package/dist/esm/crypto/math/constants.js +12 -35
- package/dist/esm/crypto/math/edwards.js +174 -47
- package/dist/esm/crypto/math/fe.js +691 -0
- package/dist/esm/crypto/math/mod.js +10 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/infra/log/ConsoleLogger.js +18 -17
- package/dist/esm/infra/log/PinoLogger.js +15 -9
- package/dist/esm/infra/log/types.js +11 -1
- package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
- package/dist/esm/infra/perf/BoundedTaskQueue.js +16 -18
- package/dist/esm/infra/perf/PromiseDedup.js +20 -0
- package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
- package/dist/esm/infra/perf/StoreLock.js +77 -0
- package/dist/esm/media/WaMediaCrypto.js +96 -16
- package/dist/esm/media/WaMediaTransferClient.js +251 -91
- package/dist/esm/media/conn.js +10 -6
- package/dist/esm/media/constants.js +6 -2
- package/dist/esm/message/WaMessageClient.js +30 -32
- package/dist/esm/message/ack.js +6 -6
- package/dist/esm/message/addon-crypto.js +59 -0
- package/dist/esm/message/content.js +195 -9
- package/dist/esm/message/icdc.js +76 -0
- package/dist/esm/message/incoming.js +129 -122
- package/dist/esm/message/index.js +2 -0
- package/dist/esm/message/phash.js +3 -1
- package/dist/esm/message/reporting-token.js +425 -0
- package/dist/esm/message/use-case-secret.js +49 -0
- package/dist/esm/protocol/appstate.js +27 -0
- package/dist/esm/protocol/browser.js +10 -18
- package/dist/esm/protocol/constants.js +6 -3
- package/dist/esm/protocol/defaults.js +6 -0
- package/dist/esm/protocol/index.js +2 -11
- package/dist/esm/protocol/jid.js +133 -52
- package/dist/esm/protocol/media.js +3 -3
- package/dist/esm/protocol/message.js +61 -1
- package/dist/esm/protocol/nodes.js +4 -0
- package/dist/esm/protocol/notification.js +3 -1
- package/dist/esm/protocol/privacy-token.js +17 -0
- package/dist/esm/protocol/privacy.js +55 -0
- package/dist/esm/protocol/stream.js +26 -1
- package/dist/esm/protocol/usync.js +11 -0
- package/dist/esm/retry/codec.js +216 -0
- package/dist/esm/retry/constants.js +1 -1
- package/dist/esm/retry/index.js +3 -2
- package/dist/esm/retry/parse.js +88 -86
- package/dist/esm/retry/replay.js +54 -51
- package/dist/esm/retry/tracker.js +94 -0
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +276 -92
- package/dist/esm/signal/api/SignalDigestSyncApi.js +17 -8
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +67 -37
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +86 -67
- package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/esm/signal/api/SignalSessionSyncApi.js +36 -34
- package/dist/esm/signal/api/result-map.js +10 -0
- package/dist/esm/signal/constants.js +0 -4
- package/dist/esm/signal/crypto/WaAdvSignature.js +13 -9
- package/dist/esm/signal/{store/sqlite.js → encoding.js} +93 -60
- package/dist/esm/signal/group/SenderKeyChain.js +28 -23
- package/dist/esm/signal/group/SenderKeyCodec.js +5 -6
- package/dist/esm/signal/group/SenderKeyManager.js +144 -115
- package/dist/esm/signal/index.js +2 -0
- package/dist/esm/signal/registration/keygen.js +6 -2
- package/dist/esm/signal/registration/utils.js +1 -0
- package/dist/esm/signal/session/SignalProtocol.js +164 -53
- package/dist/esm/signal/session/SignalRatchet.js +24 -15
- package/dist/esm/signal/session/SignalSession.js +14 -9
- package/dist/esm/signal/session/resolver.js +221 -0
- package/dist/esm/store/contracts/privacy-token.store.js +1 -0
- package/dist/esm/store/createStore.js +100 -188
- package/dist/esm/store/index.js +1 -10
- package/dist/esm/store/locks/appstate.lock.js +26 -0
- package/dist/esm/store/locks/auth.lock.js +15 -0
- package/dist/esm/store/locks/contact.lock.js +20 -0
- package/dist/esm/store/locks/device-list.lock.js +20 -0
- package/dist/esm/store/locks/message.lock.js +21 -0
- package/dist/esm/store/locks/participants.lock.js +20 -0
- package/dist/esm/store/locks/privacy-token.lock.js +18 -0
- package/dist/esm/store/locks/retry.lock.js +29 -0
- package/dist/esm/store/locks/sender-key.lock.js +52 -0
- package/dist/esm/store/locks/signal.lock.js +63 -0
- package/dist/esm/store/locks/thread.lock.js +21 -0
- package/dist/esm/store/noop.store.js +4 -7
- package/dist/esm/store/providers/memory/appstate.store.js +38 -16
- package/dist/esm/store/providers/memory/contact.store.js +5 -0
- package/dist/esm/store/providers/memory/device-list.store.js +12 -34
- package/dist/esm/store/providers/memory/message.store.js +11 -5
- package/dist/esm/store/providers/memory/participants.store.js +1 -8
- package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
- package/dist/esm/store/providers/memory/retry.store.js +77 -2
- package/dist/esm/store/providers/memory/sender-key.store.js +11 -8
- package/dist/esm/store/providers/memory/signal.store.js +47 -18
- package/dist/esm/store/providers/memory/thread.store.js +5 -0
- package/dist/esm/transport/WaComms.js +28 -24
- package/dist/esm/transport/WaWebSocket.js +115 -18
- package/dist/esm/transport/binary/constants.js +0 -30
- package/dist/esm/transport/binary/decoder.js +8 -8
- package/dist/esm/transport/binary/encoder.js +10 -9
- package/dist/esm/transport/binary/index.js +0 -1
- package/dist/esm/transport/index.js +1 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
- package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -21
- package/dist/esm/transport/node/WaNodeTransport.js +0 -3
- package/dist/esm/transport/node/builders/{accountSync.js → account-sync.js} +16 -36
- package/dist/esm/transport/node/builders/business.js +129 -0
- package/dist/esm/transport/node/builders/global.js +370 -0
- package/dist/esm/transport/node/builders/index.js +7 -3
- package/dist/esm/transport/node/builders/message.js +63 -230
- package/dist/esm/transport/node/builders/pairing.js +2 -27
- package/dist/esm/transport/node/builders/privacy-token.js +41 -0
- package/dist/esm/transport/node/builders/privacy.js +48 -0
- package/dist/esm/transport/node/builders/profile.js +70 -0
- package/dist/esm/transport/node/builders/retry.js +10 -22
- package/dist/esm/transport/node/builders/usync.js +45 -0
- package/dist/esm/transport/node/helpers.js +125 -5
- package/dist/esm/transport/node/usync.js +5 -0
- package/dist/esm/transport/node/xml.js +35 -14
- package/dist/esm/transport/noise/WaClientPayload.js +10 -10
- package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
- package/dist/esm/transport/noise/WaNoiseCert.js +4 -7
- package/dist/esm/transport/noise/WaNoiseSession.js +77 -29
- package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/esm/transport/proxy.js +27 -0
- package/dist/esm/transport/stream/parse.js +17 -48
- package/dist/esm/util/bytes.js +67 -45
- package/dist/esm/util/coercion.js +6 -14
- package/dist/esm/util/index.js +5 -0
- package/dist/esm/util/primitives.js +40 -14
- package/dist/index.js +7 -1
- package/dist/infra/log/ConsoleLogger.js +18 -17
- package/dist/infra/log/PinoLogger.js +15 -9
- package/dist/infra/log/types.js +12 -0
- package/dist/infra/perf/BackgroundQueue.js +482 -0
- package/dist/infra/perf/BoundedTaskQueue.js +16 -18
- package/dist/infra/perf/PromiseDedup.js +24 -0
- package/dist/infra/perf/SharedExclusiveGate.js +113 -0
- package/dist/infra/perf/StoreLock.js +81 -0
- package/dist/media/WaMediaCrypto.js +95 -15
- package/dist/media/WaMediaTransferClient.js +284 -91
- package/dist/media/conn.js +10 -6
- package/dist/media/constants.js +6 -2
- package/dist/message/WaMessageClient.js +31 -33
- package/dist/message/ack.js +6 -6
- package/dist/message/addon-crypto.js +65 -0
- package/dist/message/content.js +198 -9
- package/dist/message/icdc.js +81 -0
- package/dist/message/incoming.js +127 -120
- package/dist/message/index.js +2 -0
- package/dist/message/phash.js +3 -1
- package/dist/message/reporting-token.js +429 -0
- package/dist/message/use-case-secret.js +55 -0
- package/dist/protocol/appstate.js +28 -1
- package/dist/protocol/browser.js +10 -18
- package/dist/protocol/constants.js +26 -1
- package/dist/protocol/defaults.js +6 -0
- package/dist/protocol/index.js +23 -42
- package/dist/protocol/jid.js +140 -52
- package/dist/protocol/media.js +3 -3
- package/dist/protocol/message.js +62 -2
- package/dist/protocol/nodes.js +4 -0
- package/dist/protocol/notification.js +3 -1
- package/dist/protocol/privacy-token.js +20 -0
- package/dist/protocol/privacy.js +58 -0
- package/dist/protocol/stream.js +27 -2
- package/dist/protocol/usync.js +14 -0
- package/dist/retry/codec.js +220 -0
- package/dist/retry/constants.js +1 -1
- package/dist/retry/index.js +7 -5
- package/dist/retry/parse.js +88 -85
- package/dist/retry/replay.js +52 -49
- package/dist/retry/tracker.js +97 -0
- package/dist/signal/api/SignalDeviceSyncApi.js +273 -89
- package/dist/signal/api/SignalDigestSyncApi.js +17 -8
- package/dist/signal/api/SignalIdentitySyncApi.js +66 -36
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +82 -63
- package/dist/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/signal/api/SignalSessionSyncApi.js +36 -34
- package/dist/signal/api/result-map.js +13 -0
- package/dist/signal/constants.js +1 -5
- package/dist/signal/crypto/WaAdvSignature.js +11 -7
- package/dist/signal/{store/sqlite.js → encoding.js} +94 -61
- package/dist/signal/group/SenderKeyChain.js +27 -22
- package/dist/signal/group/SenderKeyCodec.js +5 -6
- package/dist/signal/group/SenderKeyManager.js +144 -115
- package/dist/signal/index.js +15 -1
- package/dist/signal/registration/keygen.js +6 -2
- package/dist/signal/registration/utils.js +1 -0
- package/dist/signal/session/SignalProtocol.js +164 -53
- package/dist/signal/session/SignalRatchet.js +24 -15
- package/dist/signal/session/SignalSession.js +14 -9
- package/dist/signal/session/resolver.js +224 -0
- package/dist/store/contracts/privacy-token.store.js +2 -0
- package/dist/store/createStore.js +100 -188
- package/dist/store/index.js +15 -33
- package/dist/store/locks/appstate.lock.js +29 -0
- package/dist/store/locks/auth.lock.js +18 -0
- package/dist/store/locks/contact.lock.js +23 -0
- package/dist/store/locks/device-list.lock.js +23 -0
- package/dist/store/locks/message.lock.js +24 -0
- package/dist/store/locks/participants.lock.js +23 -0
- package/dist/store/locks/privacy-token.lock.js +21 -0
- package/dist/store/locks/retry.lock.js +32 -0
- package/dist/store/locks/sender-key.lock.js +55 -0
- package/dist/store/locks/signal.lock.js +66 -0
- package/dist/store/locks/thread.lock.js +24 -0
- package/dist/store/noop.store.js +4 -7
- package/dist/store/providers/memory/appstate.store.js +36 -14
- package/dist/store/providers/memory/contact.store.js +5 -0
- package/dist/store/providers/memory/device-list.store.js +12 -34
- package/dist/store/providers/memory/message.store.js +11 -5
- package/dist/store/providers/memory/participants.store.js +1 -8
- package/dist/store/providers/memory/privacy-token.store.js +47 -0
- package/dist/store/providers/memory/retry.store.js +77 -2
- package/dist/store/providers/memory/sender-key.store.js +14 -11
- package/dist/store/providers/memory/signal.store.js +54 -25
- package/dist/store/providers/memory/thread.store.js +5 -0
- package/dist/transport/WaComms.js +30 -26
- package/dist/transport/WaWebSocket.js +148 -18
- package/dist/transport/binary/constants.js +1 -31
- package/dist/transport/binary/decoder.js +8 -8
- package/dist/transport/binary/encoder.js +10 -9
- package/dist/transport/binary/index.js +0 -4
- package/dist/transport/index.js +7 -1
- package/dist/transport/keepalive/WaKeepAlive.js +1 -7
- package/dist/transport/node/WaNodeOrchestrator.js +25 -21
- package/dist/transport/node/WaNodeTransport.js +0 -3
- package/dist/transport/node/builders/{accountSync.js → account-sync.js} +15 -35
- package/dist/transport/node/builders/business.js +137 -0
- package/dist/transport/node/builders/global.js +375 -0
- package/dist/transport/node/builders/index.js +29 -17
- package/dist/transport/node/builders/message.js +64 -236
- package/dist/transport/node/builders/pairing.js +2 -29
- package/dist/transport/node/builders/privacy-token.js +46 -0
- package/dist/transport/node/builders/privacy.js +55 -0
- package/dist/transport/node/builders/profile.js +78 -0
- package/dist/transport/node/builders/retry.js +9 -21
- package/dist/transport/node/builders/usync.js +49 -0
- package/dist/transport/node/helpers.js +131 -4
- package/dist/transport/node/usync.js +8 -0
- package/dist/transport/node/xml.js +35 -14
- package/dist/transport/noise/WaClientPayload.js +13 -13
- package/dist/transport/noise/WaFrameCodec.js +47 -32
- package/dist/transport/noise/WaNoiseCert.js +5 -8
- package/dist/transport/noise/WaNoiseSession.js +77 -29
- package/dist/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/transport/proxy.js +34 -0
- package/dist/transport/stream/parse.js +20 -52
- package/dist/types/appstate/WaAppStateCrypto.d.ts +0 -1
- package/dist/types/appstate/WaAppStateSyncClient.d.ts +5 -2
- package/dist/types/appstate/constants.d.ts +1 -0
- package/dist/types/appstate/encoding.d.ts +7 -0
- package/dist/types/appstate/index.d.ts +3 -3
- package/dist/types/appstate/utils.d.ts +0 -3
- package/dist/types/auth/WaAuthClient.d.ts +10 -12
- package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
- package/dist/types/auth/index.d.ts +0 -4
- package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
- package/dist/types/auth/types.d.ts +7 -9
- package/dist/types/client/WaClient.d.ts +42 -25
- package/dist/types/client/WaClientFactory.d.ts +33 -26
- package/dist/types/client/connection/WaConnectionManager.d.ts +66 -0
- package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +14 -0
- package/dist/types/client/connection/WaReceiptQueue.d.ts +13 -0
- package/dist/types/client/coordinators/WaAppStateMutationCoordinator.d.ts +46 -0
- package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -2
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +29 -38
- package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
- package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
- package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +8 -0
- package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
- package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
- package/dist/types/client/dirty.d.ts +1 -0
- package/dist/types/client/events/devices.d.ts +20 -0
- package/dist/types/client/events/group.d.ts +2 -1
- package/dist/types/client/events/identity.d.ts +9 -0
- package/dist/types/client/events/privacy-token.d.ts +7 -0
- package/dist/types/client/history-sync.d.ts +9 -6
- package/dist/types/client/incoming.d.ts +3 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/mailbox.d.ts +3 -5
- package/dist/types/client/messages.d.ts +1 -2
- package/dist/types/client/messaging/fanout.d.ts +14 -0
- package/dist/types/client/messaging/key-protocol.d.ts +18 -0
- package/dist/types/client/messaging/participants.d.ts +13 -0
- package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
- package/dist/types/client/tokens/cs-token.d.ts +10 -0
- package/dist/types/client/tokens/tc-token.d.ts +5 -0
- package/dist/types/client/types.d.ts +75 -4
- package/dist/types/crypto/core/hkdf.d.ts +0 -6
- package/dist/types/crypto/core/index.d.ts +2 -3
- package/dist/types/crypto/core/nonce.d.ts +2 -0
- package/dist/types/crypto/core/primitives.d.ts +0 -1
- package/dist/types/crypto/core/random.d.ts +2 -7
- package/dist/types/crypto/index.d.ts +0 -1
- package/dist/types/crypto/math/constants.d.ts +4 -2
- package/dist/types/crypto/math/fe.d.ts +30 -0
- package/dist/types/crypto/math/mod.d.ts +0 -2
- package/dist/types/crypto/math/types.d.ts +11 -4
- package/dist/types/index.d.ts +5 -3
- package/dist/types/infra/log/ConsoleLogger.d.ts +2 -1
- package/dist/types/infra/log/PinoLogger.d.ts +1 -1
- package/dist/types/infra/log/types.d.ts +1 -0
- package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
- package/dist/types/infra/perf/BoundedTaskQueue.d.ts +1 -1
- package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
- package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
- package/dist/types/infra/perf/StoreLock.d.ts +10 -0
- package/dist/types/media/WaMediaCrypto.d.ts +3 -2
- package/dist/types/media/WaMediaTransferClient.d.ts +16 -15
- package/dist/types/media/constants.d.ts +1 -1
- package/dist/types/media/index.d.ts +1 -1
- package/dist/types/media/types.d.ts +15 -2
- package/dist/types/message/addon-crypto.d.ts +25 -0
- package/dist/types/message/content.d.ts +8 -0
- package/dist/types/message/icdc.d.ts +13 -0
- package/dist/types/message/index.d.ts +2 -0
- package/dist/types/message/reporting-token.d.ts +18 -0
- package/dist/types/message/types.d.ts +45 -6
- package/dist/types/message/use-case-secret.d.ts +20 -0
- package/dist/types/protocol/appstate.d.ts +47 -0
- package/dist/types/protocol/constants.d.ts +8 -3
- package/dist/types/protocol/defaults.d.ts +6 -0
- package/dist/types/protocol/index.d.ts +2 -11
- package/dist/types/protocol/jid.d.ts +22 -5
- package/dist/types/protocol/message.d.ts +60 -0
- package/dist/types/protocol/nodes.d.ts +4 -0
- package/dist/types/protocol/notification.d.ts +2 -0
- package/dist/types/protocol/privacy-token.d.ts +17 -0
- package/dist/types/protocol/privacy.d.ts +75 -0
- package/dist/types/protocol/stream.d.ts +30 -0
- package/dist/types/protocol/usync.d.ts +11 -0
- package/dist/types/retry/codec.d.ts +3 -0
- package/dist/types/retry/index.d.ts +4 -3
- package/dist/types/retry/parse.d.ts +5 -2
- package/dist/types/retry/replay.d.ts +0 -4
- package/dist/types/retry/tracker.d.ts +20 -0
- package/dist/types/retry/types.d.ts +10 -4
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +15 -2
- package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
- package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
- package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
- package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
- package/dist/types/signal/api/result-map.d.ts +1 -0
- package/dist/types/signal/constants.d.ts +0 -3
- package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
- package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
- package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
- package/dist/types/signal/index.d.ts +3 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +19 -4
- package/dist/types/signal/session/resolver.d.ts +22 -0
- package/dist/types/store/contracts/appstate.store.d.ts +4 -1
- package/dist/types/store/contracts/contact.store.d.ts +1 -0
- package/dist/types/store/contracts/device-list.store.d.ts +0 -3
- package/dist/types/store/contracts/message.store.d.ts +1 -0
- package/dist/types/store/contracts/participants.store.d.ts +0 -1
- package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
- package/dist/types/store/contracts/retry.store.d.ts +7 -0
- package/dist/types/store/contracts/sender-key.store.d.ts +0 -1
- package/dist/types/store/contracts/signal.store.d.ts +13 -0
- package/dist/types/store/contracts/thread.store.d.ts +1 -0
- package/dist/types/store/createStore.d.ts +1 -1
- package/dist/types/store/index.d.ts +5 -13
- package/dist/types/store/locks/appstate.lock.d.ts +3 -0
- package/dist/types/store/locks/auth.lock.d.ts +3 -0
- package/dist/types/store/locks/contact.lock.d.ts +3 -0
- package/dist/types/store/locks/device-list.lock.d.ts +2 -0
- package/dist/types/store/locks/message.lock.d.ts +3 -0
- package/dist/types/store/locks/participants.lock.d.ts +2 -0
- package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
- package/dist/types/store/locks/retry.lock.d.ts +2 -0
- package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
- package/dist/types/store/locks/signal.lock.d.ts +3 -0
- package/dist/types/store/locks/thread.lock.d.ts +3 -0
- package/dist/types/store/providers/memory/appstate.store.d.ts +3 -1
- package/dist/types/store/providers/memory/contact.store.d.ts +1 -0
- package/dist/types/store/providers/memory/device-list.store.d.ts +0 -3
- package/dist/types/store/providers/memory/message.store.d.ts +1 -0
- package/dist/types/store/providers/memory/participants.store.d.ts +0 -1
- package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
- package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
- package/dist/types/store/providers/memory/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/memory/signal.store.d.ts +8 -1
- package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
- package/dist/types/store/types.d.ts +49 -58
- package/dist/types/transport/WaWebSocket.d.ts +3 -1
- package/dist/types/transport/binary/constants.d.ts +0 -30
- package/dist/types/transport/binary/index.d.ts +0 -1
- package/dist/types/transport/index.d.ts +2 -1
- package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
- package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
- package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
- package/dist/types/transport/node/builders/business.d.ts +29 -0
- package/dist/types/transport/node/builders/global.d.ts +102 -0
- package/dist/types/transport/node/builders/group.d.ts +4 -6
- package/dist/types/transport/node/builders/index.d.ts +7 -3
- package/dist/types/transport/node/builders/message.d.ts +20 -30
- package/dist/types/transport/node/builders/pairing.d.ts +0 -2
- package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
- package/dist/types/transport/node/builders/privacy.d.ts +7 -0
- package/dist/types/transport/node/builders/profile.d.ts +8 -0
- package/dist/types/transport/node/builders/retry.d.ts +2 -5
- package/dist/types/transport/node/builders/usync.d.ts +21 -0
- package/dist/types/transport/node/helpers.d.ts +13 -0
- package/dist/types/transport/node/usync.d.ts +2 -0
- package/dist/types/transport/noise/WaFrameCodec.d.ts +3 -0
- package/dist/types/transport/noise/WaNoiseSession.d.ts +4 -2
- package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
- package/dist/types/transport/proxy.d.ts +6 -0
- package/dist/types/transport/stream/parse.d.ts +0 -1
- package/dist/types/transport/types.d.ts +18 -1
- package/dist/types/util/bytes.d.ts +5 -0
- package/dist/types/util/index.d.ts +5 -0
- package/dist/types/util/primitives.d.ts +2 -0
- package/dist/util/bytes.js +72 -46
- package/dist/util/coercion.js +6 -14
- package/dist/util/index.js +23 -0
- package/dist/util/primitives.js +42 -14
- package/package.json +52 -9
- package/proto/index.js +1 -1
- package/dist/crypto/core/constants.js +0 -4
- package/dist/crypto/core/encoding.js +0 -29
- package/dist/esm/crypto/core/constants.js +0 -1
- package/dist/esm/crypto/core/encoding.js +0 -25
- package/dist/esm/retry/outbound.js +0 -83
- package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
- package/dist/esm/store/providers/sqlite/appstate.store.js +0 -169
- package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
- package/dist/esm/store/providers/sqlite/connection.js +0 -240
- package/dist/esm/store/providers/sqlite/contact.store.js +0 -61
- package/dist/esm/store/providers/sqlite/device-list.store.js +0 -155
- package/dist/esm/store/providers/sqlite/message.store.js +0 -119
- package/dist/esm/store/providers/sqlite/migrations.js +0 -347
- package/dist/esm/store/providers/sqlite/participants.store.js +0 -85
- package/dist/esm/store/providers/sqlite/retry.store.js +0 -144
- package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -203
- package/dist/esm/store/providers/sqlite/signal.store.js +0 -353
- package/dist/esm/store/providers/sqlite/thread.store.js +0 -72
- package/dist/esm/util/base64.js +0 -18
- package/dist/esm/util/signal-address.js +0 -5
- package/dist/retry/outbound.js +0 -88
- package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
- package/dist/store/providers/sqlite/appstate.store.js +0 -173
- package/dist/store/providers/sqlite/auth.store.js +0 -180
- package/dist/store/providers/sqlite/connection.js +0 -276
- package/dist/store/providers/sqlite/contact.store.js +0 -65
- package/dist/store/providers/sqlite/device-list.store.js +0 -159
- package/dist/store/providers/sqlite/message.store.js +0 -123
- package/dist/store/providers/sqlite/migrations.js +0 -350
- package/dist/store/providers/sqlite/participants.store.js +0 -89
- package/dist/store/providers/sqlite/retry.store.js +0 -148
- package/dist/store/providers/sqlite/sender-key.store.js +0 -207
- package/dist/store/providers/sqlite/signal.store.js +0 -357
- package/dist/store/providers/sqlite/thread.store.js +0 -76
- package/dist/types/appstate/store/sqlite.d.ts +0 -21
- package/dist/types/crypto/core/constants.d.ts +0 -1
- package/dist/types/crypto/core/encoding.d.ts +0 -11
- package/dist/types/retry/outbound.d.ts +0 -4
- package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
- package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
- package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
- package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -10
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -18
- package/dist/types/store/providers/sqlite/message.store.d.ts +0 -11
- package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -13
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -16
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -25
- package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -46
- package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -11
- package/dist/types/util/base64.d.ts +0 -4
- package/dist/types/util/signal-address.d.ts +0 -2
- package/dist/util/base64.js +0 -24
- package/dist/util/signal-address.js +0 -8
- /package/dist/types/transport/node/builders/{accountSync.d.ts → account-sync.d.ts} +0 -0
|
@@ -1,39 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WaMessageDispatchCoordinator = void 0;
|
|
4
|
-
const
|
|
4
|
+
const _crypto_1 = require("../../crypto/index.js");
|
|
5
|
+
const PromiseDedup_1 = require("../../infra/perf/PromiseDedup");
|
|
6
|
+
const _message_1 = require("../../message/index.js");
|
|
5
7
|
const content_1 = require("../../message/content");
|
|
6
8
|
const device_sent_1 = require("../../message/device-sent");
|
|
9
|
+
const icdc_1 = require("../../message/icdc");
|
|
7
10
|
const padding_1 = require("../../message/padding");
|
|
8
11
|
const phash_1 = require("../../message/phash");
|
|
12
|
+
const reporting_token_1 = require("../../message/reporting-token");
|
|
9
13
|
const _proto_1 = require("../../proto.js");
|
|
10
14
|
const constants_1 = require("../../protocol/constants");
|
|
11
15
|
const jid_1 = require("../../protocol/jid");
|
|
12
|
-
const
|
|
13
|
-
const outbound_1 = require("../../retry/outbound");
|
|
16
|
+
const jid_2 = require("../../protocol/jid");
|
|
14
17
|
const binary_1 = require("../../transport/binary");
|
|
15
18
|
const message_1 = require("../../transport/node/builders/message");
|
|
16
19
|
const bytes_1 = require("../../util/bytes");
|
|
17
20
|
const primitives_1 = require("../../util/primitives");
|
|
18
|
-
const signal_address_1 = require("../../util/signal-address");
|
|
19
21
|
class WaMessageDispatchCoordinator {
|
|
20
22
|
constructor(options) {
|
|
23
|
+
this.icdcDedup = new PromiseDedup_1.PromiseDedup();
|
|
24
|
+
this.privacyTokenDedup = new PromiseDedup_1.PromiseDedup();
|
|
25
|
+
this.distributionDedup = new PromiseDedup_1.PromiseDedup();
|
|
21
26
|
this.logger = options.logger;
|
|
22
27
|
this.messageClient = options.messageClient;
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
28
|
+
this.retryTracker = options.retryTracker;
|
|
29
|
+
this.sessionResolver = options.sessionResolver;
|
|
30
|
+
this.fanoutResolver = options.fanoutResolver;
|
|
31
|
+
this.participantsCache = options.participantsCache;
|
|
32
|
+
this.appStateSyncKeyProtocol = options.appStateSyncKeyProtocol;
|
|
26
33
|
this.buildMessageContent = options.buildMessageContent;
|
|
27
|
-
this.queryGroupParticipantJids = options.queryGroupParticipantJids;
|
|
28
34
|
this.senderKeyManager = options.senderKeyManager;
|
|
29
35
|
this.signalProtocol = options.signalProtocol;
|
|
30
36
|
this.signalStore = options.signalStore;
|
|
31
|
-
this.
|
|
32
|
-
this.signalIdentitySync = options.signalIdentitySync;
|
|
33
|
-
this.signalSessionSync = options.signalSessionSync;
|
|
37
|
+
this.deviceListStore = options.deviceListStore;
|
|
34
38
|
this.getCurrentMeJid = options.getCurrentMeJid;
|
|
35
39
|
this.getCurrentMeLid = options.getCurrentMeLid;
|
|
36
40
|
this.getCurrentSignedIdentity = options.getCurrentSignedIdentity;
|
|
41
|
+
this.resolvePrivacyTokenNode = options.resolvePrivacyTokenNode;
|
|
42
|
+
this.onDirectMessageSent = options.onDirectMessageSent;
|
|
37
43
|
}
|
|
38
44
|
async publishMessageNode(node, options = {}) {
|
|
39
45
|
this.logger.debug('wa client publish message node', {
|
|
@@ -46,13 +52,13 @@ class WaMessageDispatchCoordinator {
|
|
|
46
52
|
mode: 'opaque_node',
|
|
47
53
|
node: (0, binary_1.encodeBinaryNode)(node)
|
|
48
54
|
};
|
|
49
|
-
return this.
|
|
55
|
+
return this.retryTracker.track({
|
|
50
56
|
messageIdHint: node.attrs.id,
|
|
51
57
|
toJid: node.attrs.to,
|
|
58
|
+
type: messageType,
|
|
59
|
+
replayPayload,
|
|
52
60
|
participantJid: node.attrs.participant,
|
|
53
|
-
recipientJid: node.attrs.recipient
|
|
54
|
-
messageType,
|
|
55
|
-
replayPayload
|
|
61
|
+
recipientJid: node.attrs.recipient
|
|
56
62
|
}, async () => this.messageClient.publishNode(node, options));
|
|
57
63
|
}
|
|
58
64
|
async publishEncryptedMessage(input, options = {}) {
|
|
@@ -69,12 +75,13 @@ class WaMessageDispatchCoordinator {
|
|
|
69
75
|
ciphertext: input.ciphertext,
|
|
70
76
|
participant: input.participant
|
|
71
77
|
};
|
|
72
|
-
return this.
|
|
78
|
+
return this.retryTracker.track({
|
|
73
79
|
messageIdHint: input.id,
|
|
74
80
|
toJid: input.to,
|
|
81
|
+
type: input.type ?? 'text',
|
|
82
|
+
replayPayload,
|
|
75
83
|
participantJid: input.participant,
|
|
76
|
-
|
|
77
|
-
replayPayload
|
|
84
|
+
eligibleRequesterDeviceJids: [input.to]
|
|
78
85
|
}, async () => this.messageClient.publishEncrypted(input, options));
|
|
79
86
|
}
|
|
80
87
|
async publishSignalMessage(input, options = {}) {
|
|
@@ -89,7 +96,7 @@ class WaMessageDispatchCoordinator {
|
|
|
89
96
|
});
|
|
90
97
|
const [paddedPlaintext] = await Promise.all([
|
|
91
98
|
(0, padding_1.writeRandomPadMax16)(input.plaintext),
|
|
92
|
-
this.
|
|
99
|
+
this.sessionResolver.ensureSession(address, input.to, input.expectedIdentity)
|
|
93
100
|
]);
|
|
94
101
|
const encrypted = await this.signalProtocol.encryptMessage(address, paddedPlaintext, input.expectedIdentity);
|
|
95
102
|
const messageType = input.type ?? 'text';
|
|
@@ -99,12 +106,13 @@ class WaMessageDispatchCoordinator {
|
|
|
99
106
|
type: messageType,
|
|
100
107
|
plaintext: paddedPlaintext
|
|
101
108
|
};
|
|
102
|
-
return this.
|
|
109
|
+
return this.retryTracker.track({
|
|
103
110
|
messageIdHint: input.id,
|
|
104
111
|
toJid: input.to,
|
|
112
|
+
type: messageType,
|
|
113
|
+
replayPayload,
|
|
105
114
|
participantJid: input.participant,
|
|
106
|
-
|
|
107
|
-
replayPayload
|
|
115
|
+
eligibleRequesterDeviceJids: [input.to]
|
|
108
116
|
}, async () => this.messageClient.publishEncrypted({
|
|
109
117
|
to: input.to,
|
|
110
118
|
encType: encrypted.type,
|
|
@@ -119,286 +127,56 @@ class WaMessageDispatchCoordinator {
|
|
|
119
127
|
}
|
|
120
128
|
async sendMessage(to, content, options = {}) {
|
|
121
129
|
const recipientJid = (0, jid_1.normalizeRecipientJid)(to);
|
|
122
|
-
const message = await
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
const [message, sendOptions] = await Promise.all([
|
|
131
|
+
this.buildMessageContent(content),
|
|
132
|
+
this.withResolvedMessageId(options)
|
|
133
|
+
]);
|
|
134
|
+
const messageWithSecret = await (0, _message_1.ensureMessageSecret)(message);
|
|
135
|
+
const meJid = this.getCurrentMeJid();
|
|
136
|
+
const regInfo = meJid ? await this.signalStore.getRegistrationInfo() : null;
|
|
137
|
+
const localPubKey = regInfo?.identityKeyPair.pubKey;
|
|
138
|
+
const meParsed = meJid ? (0, jid_1.parseJidFull)(meJid) : undefined;
|
|
139
|
+
const meUserJid = meParsed?.userJid;
|
|
140
|
+
const localIdentity = meParsed && localPubKey ? { address: meParsed.address, pubKey: localPubKey } : undefined;
|
|
141
|
+
const isGroup = (0, jid_1.isGroupJid)(recipientJid);
|
|
142
|
+
const [senderIcdc, recipientIcdc] = await Promise.all([
|
|
143
|
+
meUserJid ? this.resolveUserIcdc(meUserJid, localIdentity) : null,
|
|
144
|
+
!isGroup ? this.resolveUserIcdc((0, jid_1.toUserJid)(recipientJid)) : null
|
|
145
|
+
]);
|
|
146
|
+
const messageWithIcdc = (0, icdc_1.injectDeviceListMetadata)(messageWithSecret, senderIcdc, recipientIcdc);
|
|
147
|
+
const plaintext = await (0, padding_1.writeRandomPadMax16)(_proto_1.proto.Message.encode(messageWithIcdc).finish());
|
|
148
|
+
const type = (0, content_1.resolveMessageTypeAttr)(messageWithIcdc);
|
|
149
|
+
const edit = (0, content_1.resolveEditAttr)(messageWithIcdc, sendOptions.subtype) ?? undefined;
|
|
150
|
+
const mediatype = (0, content_1.resolveEncMediaType)(messageWithIcdc) ?? undefined;
|
|
151
|
+
const metaAttrs = (0, content_1.resolveMetaAttrs)(messageWithIcdc);
|
|
152
|
+
const metaNode = metaAttrs ? (0, message_1.buildMetaNode)(metaAttrs) : undefined;
|
|
153
|
+
if (isGroup) {
|
|
154
|
+
if (this.shouldUseGroupDirectPath(messageWithIcdc)) {
|
|
155
|
+
return this.publishGroupDirectMessage(recipientJid, messageWithIcdc, plaintext, type, sendOptions, {}, edit, mediatype, metaNode);
|
|
156
|
+
}
|
|
157
|
+
return this.publishGroupSenderKeyMessage(recipientJid, messageWithIcdc, plaintext, type, sendOptions, {}, edit, mediatype, metaNode);
|
|
130
158
|
}
|
|
131
159
|
const directRecipientJid = (0, jid_1.toUserJid)(recipientJid);
|
|
132
|
-
return this.publishDirectSignalMessageWithFanout(directRecipientJid,
|
|
160
|
+
return this.publishDirectSignalMessageWithFanout(directRecipientJid, messageWithIcdc, plaintext, type, sendOptions, edit, mediatype, metaNode);
|
|
133
161
|
}
|
|
134
162
|
async syncSignalSession(jid, reasonIdentity = false) {
|
|
135
163
|
const address = (0, jid_1.parseSignalAddressFromJid)(jid);
|
|
136
164
|
if (address.server === constants_1.WA_DEFAULTS.GROUP_SERVER) {
|
|
137
165
|
throw new Error('syncSignalSession supports only direct chats');
|
|
138
166
|
}
|
|
139
|
-
await this.
|
|
167
|
+
await this.sessionResolver.ensureSession(address, jid, undefined, reasonIdentity);
|
|
140
168
|
}
|
|
141
169
|
async sendReceipt(input) {
|
|
142
170
|
await this.messageClient.sendReceipt(input);
|
|
143
171
|
}
|
|
144
172
|
async requestAppStateSyncKeys(keyIds) {
|
|
145
|
-
|
|
146
|
-
if (normalizedKeyIds.length === 0) {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
149
|
-
const peerDeviceJids = await this.resolveOwnPeerDeviceJids();
|
|
150
|
-
if (peerDeviceJids.length === 0) {
|
|
151
|
-
this.logger.warn('app-state sync key request skipped: no peer devices available', {
|
|
152
|
-
keys: normalizedKeyIds.length
|
|
153
|
-
});
|
|
154
|
-
return [];
|
|
155
|
-
}
|
|
156
|
-
const protocolMessage = {
|
|
157
|
-
type: _proto_1.proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_REQUEST,
|
|
158
|
-
appStateSyncKeyRequest: {
|
|
159
|
-
keyIds: normalizedKeyIds.map((keyId) => ({
|
|
160
|
-
keyId
|
|
161
|
-
}))
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
await Promise.all(peerDeviceJids.map((deviceJid) => this.publishProtocolMessageToDevice(deviceJid, protocolMessage)));
|
|
165
|
-
this.logger.info('app-state sync key request sent to peer devices', {
|
|
166
|
-
devices: peerDeviceJids.length,
|
|
167
|
-
keys: normalizedKeyIds.length,
|
|
168
|
-
keyIds: normalizedKeyIds.map((keyId) => (0, bytes_1.bytesToHex)(keyId)).join(',')
|
|
169
|
-
});
|
|
170
|
-
return peerDeviceJids;
|
|
173
|
+
return this.appStateSyncKeyProtocol.requestKeys(keyIds);
|
|
171
174
|
}
|
|
172
175
|
async sendAppStateSyncKeyShare(toDeviceJid, keys, missingKeyIds = []) {
|
|
173
|
-
|
|
174
|
-
const dedupedKeysById = new Map();
|
|
175
|
-
for (const key of keys) {
|
|
176
|
-
dedupedKeysById.set((0, bytes_1.bytesToHex)(key.keyId), key);
|
|
177
|
-
}
|
|
178
|
-
const dedupedKeys = [...dedupedKeysById.values()];
|
|
179
|
-
const dedupedMissingKeyIds = this.normalizeKeyIds(missingKeyIds).filter((keyId) => !dedupedKeysById.has((0, bytes_1.bytesToHex)(keyId)));
|
|
180
|
-
const keyShareEntries = [
|
|
181
|
-
...dedupedKeys.map((key) => ({
|
|
182
|
-
keyId: { keyId: key.keyId },
|
|
183
|
-
keyData: {
|
|
184
|
-
keyData: key.keyData,
|
|
185
|
-
timestamp: key.timestamp,
|
|
186
|
-
...(key.fingerprint ? { fingerprint: key.fingerprint } : {})
|
|
187
|
-
}
|
|
188
|
-
})),
|
|
189
|
-
...dedupedMissingKeyIds.map((keyId) => ({
|
|
190
|
-
keyId: { keyId }
|
|
191
|
-
}))
|
|
192
|
-
];
|
|
193
|
-
const protocolMessage = {
|
|
194
|
-
type: _proto_1.proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE,
|
|
195
|
-
appStateSyncKeyShare: {
|
|
196
|
-
keys: keyShareEntries
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
await this.publishProtocolMessageToDevice(normalizedTo, protocolMessage);
|
|
200
|
-
this.logger.info('app-state sync key share sent', {
|
|
201
|
-
to: normalizedTo,
|
|
202
|
-
keys: dedupedKeys.length,
|
|
203
|
-
orphanKeys: dedupedMissingKeyIds.length
|
|
204
|
-
});
|
|
176
|
+
await this.appStateSyncKeyProtocol.sendKeyShare(toDeviceJid, keys, missingKeyIds);
|
|
205
177
|
}
|
|
206
178
|
async mutateParticipantsCacheFromGroupEvent(event) {
|
|
207
|
-
|
|
208
|
-
if (!groupJid) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
if (event.action === 'delete') {
|
|
212
|
-
await this.participantsStore.deleteGroupParticipants(groupJid);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const participantUsers = this.extractParticipantUsersFromGroupEvent(event);
|
|
216
|
-
if (event.action === 'create') {
|
|
217
|
-
if (participantUsers.length === 0) {
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
await this.participantsStore.upsertGroupParticipants({
|
|
221
|
-
groupJid,
|
|
222
|
-
participants: participantUsers,
|
|
223
|
-
updatedAtMs: Date.now()
|
|
224
|
-
});
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
const cached = await this.participantsStore.getGroupParticipants(groupJid);
|
|
228
|
-
if (!cached || cached.participants.length === 0) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const cachedParticipants = this.sanitizeParticipantUsers(cached.participants);
|
|
232
|
-
if (cachedParticipants.length === 0) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (event.action === 'add' ||
|
|
236
|
-
event.action === 'promote' ||
|
|
237
|
-
event.action === 'demote' ||
|
|
238
|
-
event.action === 'linked_group_promote' ||
|
|
239
|
-
event.action === 'linked_group_demote') {
|
|
240
|
-
await this.mergeParticipantUsersIntoCache(groupJid, cachedParticipants, participantUsers);
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
if (event.action === 'remove') {
|
|
244
|
-
await this.removeParticipantUsersFromCache(groupJid, cachedParticipants, participantUsers);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
if (event.action === 'modify') {
|
|
248
|
-
const authorUsers = event.authorJid
|
|
249
|
-
? this.sanitizeParticipantUsers([event.authorJid])
|
|
250
|
-
: [];
|
|
251
|
-
await this.replaceParticipantUsersInCache(groupJid, cachedParticipants, authorUsers, participantUsers);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
async publishProtocolMessageToDevice(deviceJid, protocolMessage) {
|
|
255
|
-
const plaintext = await (0, padding_1.writeRandomPadMax16)(_proto_1.proto.Message.encode({
|
|
256
|
-
protocolMessage
|
|
257
|
-
}).finish());
|
|
258
|
-
await this.publishSignalMessage({
|
|
259
|
-
to: deviceJid,
|
|
260
|
-
plaintext,
|
|
261
|
-
type: 'protocol',
|
|
262
|
-
category: 'peer',
|
|
263
|
-
pushPriority: 'high'
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
async resolveOwnPeerDeviceJids() {
|
|
267
|
-
const meJid = this.requireCurrentMeJid('resolveOwnPeerDeviceJids');
|
|
268
|
-
const meUserJid = (0, jid_1.toUserJid)(meJid);
|
|
269
|
-
const meDevices = new Set();
|
|
270
|
-
meDevices.add((0, jid_1.normalizeDeviceJid)(meJid));
|
|
271
|
-
const meLid = this.getCurrentMeLid();
|
|
272
|
-
if (meLid && meLid.includes('@')) {
|
|
273
|
-
try {
|
|
274
|
-
meDevices.add((0, jid_1.normalizeDeviceJid)(meLid));
|
|
275
|
-
}
|
|
276
|
-
catch (error) {
|
|
277
|
-
this.logger.trace('ignoring malformed me lid jid while resolving peer devices', {
|
|
278
|
-
meLid,
|
|
279
|
-
message: (0, primitives_1.toError)(error).message
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
try {
|
|
284
|
-
const synced = await this.signalDeviceSync.syncDeviceList([meUserJid]);
|
|
285
|
-
const peerDevices = new Set();
|
|
286
|
-
for (const entry of synced) {
|
|
287
|
-
const sourceDevices = entry.deviceJids.length > 0 ? entry.deviceJids : [entry.jid];
|
|
288
|
-
for (const deviceJid of sourceDevices) {
|
|
289
|
-
try {
|
|
290
|
-
const normalized = (0, jid_1.normalizeDeviceJid)(deviceJid);
|
|
291
|
-
if (meDevices.has(normalized)) {
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
peerDevices.add(normalized);
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
this.logger.trace('ignoring malformed peer device jid while resolving app-state peers', {
|
|
298
|
-
deviceJid,
|
|
299
|
-
message: (0, primitives_1.toError)(error).message
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return [...peerDevices];
|
|
305
|
-
}
|
|
306
|
-
catch (error) {
|
|
307
|
-
this.logger.warn('failed to resolve peer devices for app-state key request', {
|
|
308
|
-
message: (0, primitives_1.toError)(error).message
|
|
309
|
-
});
|
|
310
|
-
return [];
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
normalizeKeyIds(keyIds) {
|
|
314
|
-
const deduped = new Map();
|
|
315
|
-
for (const keyId of keyIds) {
|
|
316
|
-
if (keyId.byteLength === 0) {
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
const keyHex = (0, bytes_1.bytesToHex)(keyId);
|
|
320
|
-
if (deduped.has(keyHex)) {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
deduped.set(keyHex, keyId);
|
|
324
|
-
}
|
|
325
|
-
return [...deduped.values()];
|
|
326
|
-
}
|
|
327
|
-
async publishWithRetryTracking(args, publish) {
|
|
328
|
-
const nowMs = Date.now();
|
|
329
|
-
const expiresAtMs = nowMs + this.retryTtlMs;
|
|
330
|
-
const hintedMessageId = args.messageIdHint?.trim();
|
|
331
|
-
const resolvedToJid = args.toJid ?? (args.replayPayload.mode === 'opaque_node' ? '' : args.replayPayload.to);
|
|
332
|
-
let hintedPersisted = false;
|
|
333
|
-
if (hintedMessageId) {
|
|
334
|
-
hintedPersisted = await this.safeUpsertRetryOutboundRecord(this.createRetryOutboundRecord({
|
|
335
|
-
messageId: hintedMessageId,
|
|
336
|
-
toJid: resolvedToJid,
|
|
337
|
-
participantJid: args.participantJid,
|
|
338
|
-
recipientJid: args.recipientJid,
|
|
339
|
-
messageType: args.messageType,
|
|
340
|
-
replayPayload: args.replayPayload,
|
|
341
|
-
createdAtMs: nowMs,
|
|
342
|
-
updatedAtMs: nowMs,
|
|
343
|
-
expiresAtMs
|
|
344
|
-
}));
|
|
345
|
-
}
|
|
346
|
-
const result = await publish();
|
|
347
|
-
if (hintedPersisted && hintedMessageId && result.id === hintedMessageId) {
|
|
348
|
-
// Hint and final message id matched; avoid a second equivalent upsert on the hot path.
|
|
349
|
-
return result;
|
|
350
|
-
}
|
|
351
|
-
const persistedNowMs = Date.now();
|
|
352
|
-
await this.safeUpsertRetryOutboundRecord(this.createRetryOutboundRecord({
|
|
353
|
-
messageId: result.id,
|
|
354
|
-
toJid: resolvedToJid,
|
|
355
|
-
participantJid: args.participantJid,
|
|
356
|
-
recipientJid: args.recipientJid,
|
|
357
|
-
messageType: args.messageType,
|
|
358
|
-
replayPayload: args.replayPayload,
|
|
359
|
-
createdAtMs: hintedMessageId ? nowMs : persistedNowMs,
|
|
360
|
-
updatedAtMs: persistedNowMs,
|
|
361
|
-
expiresAtMs: persistedNowMs + this.retryTtlMs
|
|
362
|
-
}));
|
|
363
|
-
return result;
|
|
364
|
-
}
|
|
365
|
-
createRetryOutboundRecord(input) {
|
|
366
|
-
return {
|
|
367
|
-
messageId: input.messageId,
|
|
368
|
-
toJid: input.toJid,
|
|
369
|
-
participantJid: input.participantJid,
|
|
370
|
-
recipientJid: input.recipientJid,
|
|
371
|
-
messageType: input.messageType,
|
|
372
|
-
replayMode: input.replayPayload.mode,
|
|
373
|
-
replayPayload: (0, outbound_1.encodeRetryReplayPayload)(input.replayPayload),
|
|
374
|
-
state: 'pending',
|
|
375
|
-
createdAtMs: input.createdAtMs,
|
|
376
|
-
updatedAtMs: input.updatedAtMs,
|
|
377
|
-
expiresAtMs: input.expiresAtMs
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
async safeUpsertRetryOutboundRecord(record) {
|
|
381
|
-
try {
|
|
382
|
-
await this.retryStore.upsertOutboundMessage(record);
|
|
383
|
-
}
|
|
384
|
-
catch (error) {
|
|
385
|
-
this.logger.warn('failed to persist retry outbound message record', {
|
|
386
|
-
messageId: record.messageId,
|
|
387
|
-
to: record.toJid,
|
|
388
|
-
mode: record.replayMode,
|
|
389
|
-
message: (0, primitives_1.toError)(error).message
|
|
390
|
-
});
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
try {
|
|
394
|
-
await this.retryStore.cleanupExpired(Date.now());
|
|
395
|
-
}
|
|
396
|
-
catch (error) {
|
|
397
|
-
this.logger.warn('failed to cleanup retry records after outbound persist', {
|
|
398
|
-
message: (0, primitives_1.toError)(error).message
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
return true;
|
|
179
|
+
await this.participantsCache.mutateFromGroupEvent(event);
|
|
402
180
|
}
|
|
403
181
|
shouldUseGroupDirectPath(message) {
|
|
404
182
|
const protocolType = message.protocolMessage?.type;
|
|
@@ -408,41 +186,81 @@ class WaMessageDispatchCoordinator {
|
|
|
408
186
|
}
|
|
409
187
|
return message.keepInChatMessage?.keepType === _proto_1.proto.KeepType.UNDO_KEEP_FOR_ALL;
|
|
410
188
|
}
|
|
411
|
-
async publishGroupDirectMessage(groupJid, plaintext, type, options, retryContext = {}) {
|
|
189
|
+
async publishGroupDirectMessage(groupJid, message, plaintext, type, options, retryContext = {}, edit, mediatype, metaNode) {
|
|
190
|
+
const sendOptions = await this.withResolvedMessageId(options);
|
|
412
191
|
const meJid = this.requireCurrentMeJid('sendMessage');
|
|
413
192
|
const participantUserJids = retryContext.forceRefreshParticipants
|
|
414
|
-
? await this.
|
|
415
|
-
: await this.
|
|
193
|
+
? await this.participantsCache.refreshParticipantUsers(groupJid)
|
|
194
|
+
: await this.participantsCache.resolveParticipantUsers(groupJid);
|
|
416
195
|
const addressingMode = retryContext.forceAddressingMode ??
|
|
417
196
|
this.resolveGroupAddressingMode(participantUserJids, groupJid);
|
|
418
197
|
const senderForPhash = this.resolveSenderForAddressingMode(addressingMode, meJid);
|
|
419
|
-
const fanoutDeviceJids = await this.resolveGroupParticipantDeviceJids(participantUserJids);
|
|
198
|
+
const fanoutDeviceJids = await this.fanoutResolver.resolveGroupParticipantDeviceJids(participantUserJids);
|
|
420
199
|
if (fanoutDeviceJids.length === 0) {
|
|
421
200
|
throw new Error('group direct send resolved no target devices');
|
|
422
201
|
}
|
|
423
|
-
await this.
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
202
|
+
const resolvedFanoutTargets = await this.sessionResolver.ensureSessionsBatch(fanoutDeviceJids);
|
|
203
|
+
const uniqueNormalizedFanoutJids = new Set();
|
|
204
|
+
for (let index = 0; index < fanoutDeviceJids.length; index += 1) {
|
|
205
|
+
uniqueNormalizedFanoutJids.add((0, jid_1.normalizeDeviceJid)(fanoutDeviceJids[index]));
|
|
206
|
+
}
|
|
207
|
+
if (resolvedFanoutTargets.length !== uniqueNormalizedFanoutJids.size) {
|
|
208
|
+
throw new Error('group direct send resolved incomplete signal sessions');
|
|
209
|
+
}
|
|
210
|
+
const participantEncryptRequests = new Array(resolvedFanoutTargets.length);
|
|
211
|
+
for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
|
|
212
|
+
const target = resolvedFanoutTargets[index];
|
|
213
|
+
participantEncryptRequests[index] = {
|
|
214
|
+
address: target.address,
|
|
215
|
+
plaintext
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(participantEncryptRequests, resolvedFanoutTargets);
|
|
219
|
+
const participants = new Array(resolvedFanoutTargets.length);
|
|
220
|
+
for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
|
|
221
|
+
const target = resolvedFanoutTargets[index];
|
|
222
|
+
participants[index] = {
|
|
223
|
+
jid: target.jid,
|
|
224
|
+
encType: encryptedParticipants[index].type,
|
|
225
|
+
ciphertext: encryptedParticipants[index].ciphertext
|
|
432
226
|
};
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
227
|
+
}
|
|
228
|
+
let shouldAttachDeviceIdentity = false;
|
|
229
|
+
for (let index = 0; index < participants.length; index += 1) {
|
|
230
|
+
if (participants[index].encType === 'pkmsg') {
|
|
231
|
+
shouldAttachDeviceIdentity = true;
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const phashTargets = new Array(resolvedFanoutTargets.length + 1);
|
|
236
|
+
for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
|
|
237
|
+
phashTargets[index] = resolvedFanoutTargets[index].jid;
|
|
238
|
+
}
|
|
239
|
+
phashTargets[resolvedFanoutTargets.length] = senderForPhash;
|
|
240
|
+
const [localPhash, reportingArtifacts] = await Promise.all([
|
|
241
|
+
(0, phash_1.computePhashV2)(phashTargets),
|
|
242
|
+
this.tryBuildReportingTokenArtifacts({
|
|
243
|
+
message,
|
|
244
|
+
stanzaId: sendOptions.id,
|
|
245
|
+
senderUserJid: (0, jid_1.toUserJid)(senderForPhash),
|
|
246
|
+
remoteJid: groupJid,
|
|
247
|
+
context: 'group_direct'
|
|
248
|
+
})
|
|
249
|
+
]);
|
|
250
|
+
const messageNode = (0, message_1.buildDirectMessageFanoutNode)({
|
|
437
251
|
to: groupJid,
|
|
438
252
|
type,
|
|
439
|
-
id:
|
|
253
|
+
id: sendOptions.id,
|
|
254
|
+
edit,
|
|
440
255
|
phash: localPhash,
|
|
441
256
|
addressingMode,
|
|
442
257
|
participants,
|
|
443
258
|
deviceIdentity: shouldAttachDeviceIdentity
|
|
444
259
|
? this.getEncodedSignedDeviceIdentity()
|
|
445
|
-
: undefined
|
|
260
|
+
: undefined,
|
|
261
|
+
reportingNode: reportingArtifacts?.node ?? undefined,
|
|
262
|
+
metaNode,
|
|
263
|
+
mediatype
|
|
446
264
|
});
|
|
447
265
|
const replayPayload = {
|
|
448
266
|
mode: 'plaintext',
|
|
@@ -450,12 +268,13 @@ class WaMessageDispatchCoordinator {
|
|
|
450
268
|
type,
|
|
451
269
|
plaintext
|
|
452
270
|
};
|
|
453
|
-
const result = await this.
|
|
454
|
-
messageIdHint:
|
|
271
|
+
const result = await this.retryTracker.track({
|
|
272
|
+
messageIdHint: sendOptions.id ?? messageNode.attrs.id,
|
|
455
273
|
toJid: groupJid,
|
|
456
|
-
|
|
457
|
-
replayPayload
|
|
458
|
-
|
|
274
|
+
type,
|
|
275
|
+
replayPayload,
|
|
276
|
+
eligibleRequesterDeviceJids: undefined
|
|
277
|
+
}, async () => this.messageClient.publishNode(messageNode, sendOptions));
|
|
459
278
|
const ackError = result.ack.error;
|
|
460
279
|
const serverPhash = result.ack.phash;
|
|
461
280
|
const serverAddressingMode = result.ack.addressingMode;
|
|
@@ -473,43 +292,67 @@ class WaMessageDispatchCoordinator {
|
|
|
473
292
|
serverAddressingMode,
|
|
474
293
|
ackError
|
|
475
294
|
});
|
|
476
|
-
return this.publishGroupDirectMessage(groupJid, plaintext, type, {
|
|
477
|
-
...
|
|
295
|
+
return this.publishGroupDirectMessage(groupJid, message, plaintext, type, {
|
|
296
|
+
...sendOptions,
|
|
478
297
|
id: result.id
|
|
479
298
|
}, {
|
|
480
299
|
retried: true,
|
|
481
300
|
forceRefreshParticipants: true,
|
|
482
301
|
forceAddressingMode: serverAddressingMode
|
|
483
|
-
});
|
|
302
|
+
}, edit, mediatype, metaNode);
|
|
484
303
|
}
|
|
485
304
|
return result;
|
|
486
305
|
}
|
|
487
|
-
async publishGroupSenderKeyMessage(groupJid, plaintext, type, options, retryContext = {}) {
|
|
306
|
+
async publishGroupSenderKeyMessage(groupJid, message, plaintext, type, options, retryContext = {}, edit, mediatype, metaNode) {
|
|
307
|
+
const sendOptions = await this.withResolvedMessageId(options);
|
|
488
308
|
const meJid = this.requireCurrentMeJid('sendMessage');
|
|
489
309
|
const participantUserJids = retryContext.forceRefreshParticipants
|
|
490
|
-
? await this.
|
|
491
|
-
: await this.
|
|
310
|
+
? await this.participantsCache.refreshParticipantUsers(groupJid)
|
|
311
|
+
: await this.participantsCache.resolveParticipantUsers(groupJid);
|
|
492
312
|
const addressingMode = retryContext.forceAddressingMode ??
|
|
493
313
|
this.resolveGroupAddressingMode(participantUserJids, groupJid);
|
|
494
314
|
const senderJid = this.resolveSenderForAddressingMode(addressingMode, meJid);
|
|
495
315
|
const sender = (0, jid_1.parseSignalAddressFromJid)(senderJid);
|
|
496
|
-
const senderKeyDistributionMessage = await this.senderKeyManager.
|
|
497
|
-
const
|
|
498
|
-
const distributionData = await this.encryptGroupDistributionParticipants(groupJid, sender, senderKeyDistributionMessage, participantUserJids);
|
|
316
|
+
const { distributionMessage: senderKeyDistributionMessage, ciphertext: groupCiphertext, keyId: senderKeyId } = await this.senderKeyManager.prepareGroupEncryption(groupJid, sender, plaintext);
|
|
317
|
+
const distributionData = await this.distributionDedup.run(`dist:${groupJid}:${senderKeyId}`, () => this.encryptGroupDistributionParticipants(groupJid, senderKeyId, senderKeyDistributionMessage, participantUserJids));
|
|
499
318
|
const { fanoutDeviceJids, distributionParticipants } = distributionData;
|
|
500
|
-
|
|
501
|
-
|
|
319
|
+
let shouldAttachDeviceIdentity = false;
|
|
320
|
+
for (let index = 0; index < distributionParticipants.length; index += 1) {
|
|
321
|
+
if (distributionParticipants[index].encType === 'pkmsg') {
|
|
322
|
+
shouldAttachDeviceIdentity = true;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const phashTargets = new Array(fanoutDeviceJids.length + 1);
|
|
327
|
+
for (let index = 0; index < fanoutDeviceJids.length; index += 1) {
|
|
328
|
+
phashTargets[index] = fanoutDeviceJids[index];
|
|
329
|
+
}
|
|
330
|
+
phashTargets[fanoutDeviceJids.length] = senderJid;
|
|
331
|
+
const [localPhash, reportingArtifacts] = await Promise.all([
|
|
332
|
+
(0, phash_1.computePhashV2)(phashTargets),
|
|
333
|
+
this.tryBuildReportingTokenArtifacts({
|
|
334
|
+
message,
|
|
335
|
+
stanzaId: sendOptions.id,
|
|
336
|
+
senderUserJid: (0, jid_1.toUserJid)(senderJid),
|
|
337
|
+
remoteJid: groupJid,
|
|
338
|
+
context: 'group_sender_key'
|
|
339
|
+
})
|
|
340
|
+
]);
|
|
502
341
|
const messageNode = (0, message_1.buildGroupSenderKeyMessageNode)({
|
|
503
342
|
to: groupJid,
|
|
504
343
|
type,
|
|
505
|
-
id:
|
|
344
|
+
id: sendOptions.id,
|
|
345
|
+
edit,
|
|
506
346
|
phash: localPhash,
|
|
507
347
|
addressingMode,
|
|
508
348
|
groupCiphertext: groupCiphertext.ciphertext,
|
|
509
349
|
participants: distributionParticipants,
|
|
510
350
|
deviceIdentity: shouldAttachDeviceIdentity
|
|
511
351
|
? this.getEncodedSignedDeviceIdentity()
|
|
512
|
-
: undefined
|
|
352
|
+
: undefined,
|
|
353
|
+
reportingNode: reportingArtifacts?.node ?? undefined,
|
|
354
|
+
metaNode,
|
|
355
|
+
mediatype
|
|
513
356
|
});
|
|
514
357
|
const replayPayload = {
|
|
515
358
|
mode: 'plaintext',
|
|
@@ -517,15 +360,19 @@ class WaMessageDispatchCoordinator {
|
|
|
517
360
|
type,
|
|
518
361
|
plaintext
|
|
519
362
|
};
|
|
520
|
-
const result = await this.
|
|
521
|
-
messageIdHint:
|
|
363
|
+
const result = await this.retryTracker.track({
|
|
364
|
+
messageIdHint: sendOptions.id ?? messageNode.attrs.id,
|
|
522
365
|
toJid: groupJid,
|
|
523
|
-
|
|
524
|
-
replayPayload
|
|
525
|
-
|
|
526
|
-
|
|
366
|
+
type,
|
|
367
|
+
replayPayload,
|
|
368
|
+
eligibleRequesterDeviceJids: undefined
|
|
369
|
+
}, async () => this.messageClient.publishNode(messageNode, sendOptions));
|
|
370
|
+
const distributedAddresses = new Array(distributionParticipants.length);
|
|
371
|
+
for (let index = 0; index < distributionParticipants.length; index += 1) {
|
|
372
|
+
distributedAddresses[index] = distributionParticipants[index].address;
|
|
373
|
+
}
|
|
527
374
|
try {
|
|
528
|
-
await this.senderKeyManager.markSenderKeyDistributed(groupJid,
|
|
375
|
+
await this.senderKeyManager.markSenderKeyDistributed(groupJid, senderKeyId, distributedAddresses);
|
|
529
376
|
}
|
|
530
377
|
catch (error) {
|
|
531
378
|
this.logger.warn('failed to mark sender key distribution targets', {
|
|
@@ -551,150 +398,20 @@ class WaMessageDispatchCoordinator {
|
|
|
551
398
|
serverAddressingMode,
|
|
552
399
|
ackError
|
|
553
400
|
});
|
|
554
|
-
return this.publishGroupSenderKeyMessage(groupJid, plaintext, type, {
|
|
555
|
-
...
|
|
401
|
+
return this.publishGroupSenderKeyMessage(groupJid, message, plaintext, type, {
|
|
402
|
+
...sendOptions,
|
|
556
403
|
id: result.id
|
|
557
404
|
}, {
|
|
558
405
|
retried: true,
|
|
559
406
|
forceRefreshParticipants: true,
|
|
560
407
|
forceAddressingMode: serverAddressingMode
|
|
561
|
-
});
|
|
408
|
+
}, edit, mediatype, metaNode);
|
|
562
409
|
}
|
|
563
410
|
return result;
|
|
564
411
|
}
|
|
565
|
-
async resolveGroupParticipantUsers(groupJid) {
|
|
566
|
-
const cached = await this.participantsStore.getGroupParticipants(groupJid);
|
|
567
|
-
if (cached && cached.participants.length > 0) {
|
|
568
|
-
return this.sanitizeParticipantUsers(cached.participants);
|
|
569
|
-
}
|
|
570
|
-
return this.refreshGroupParticipantUsers(groupJid);
|
|
571
|
-
}
|
|
572
|
-
resolveGroupJidForParticipantCacheEvent(event) {
|
|
573
|
-
if (event.action === 'linked_group_promote' || event.action === 'linked_group_demote') {
|
|
574
|
-
return event.contextGroupJid ?? event.groupJid ?? null;
|
|
575
|
-
}
|
|
576
|
-
return event.groupJid ?? null;
|
|
577
|
-
}
|
|
578
|
-
extractParticipantUsersFromGroupEvent(event) {
|
|
579
|
-
const candidates = [];
|
|
580
|
-
for (const participant of event.participants ?? []) {
|
|
581
|
-
if (participant.jid) {
|
|
582
|
-
candidates.push(participant.jid);
|
|
583
|
-
}
|
|
584
|
-
if (participant.lidJid) {
|
|
585
|
-
candidates.push(participant.lidJid);
|
|
586
|
-
}
|
|
587
|
-
if (participant.phoneJid) {
|
|
588
|
-
candidates.push(participant.phoneJid);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
return this.sanitizeParticipantUsers(candidates);
|
|
592
|
-
}
|
|
593
|
-
async mergeParticipantUsersIntoCache(groupJid, cachedParticipants, participantsToAdd) {
|
|
594
|
-
if (participantsToAdd.length === 0) {
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
const nextParticipants = [...cachedParticipants];
|
|
598
|
-
const existing = new Set(cachedParticipants);
|
|
599
|
-
for (const participant of participantsToAdd) {
|
|
600
|
-
if (existing.has(participant)) {
|
|
601
|
-
continue;
|
|
602
|
-
}
|
|
603
|
-
existing.add(participant);
|
|
604
|
-
nextParticipants.push(participant);
|
|
605
|
-
}
|
|
606
|
-
if (nextParticipants.length === cachedParticipants.length) {
|
|
607
|
-
return;
|
|
608
|
-
}
|
|
609
|
-
await this.participantsStore.upsertGroupParticipants({
|
|
610
|
-
groupJid,
|
|
611
|
-
participants: nextParticipants,
|
|
612
|
-
updatedAtMs: Date.now()
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
async removeParticipantUsersFromCache(groupJid, cachedParticipants, participantsToRemove) {
|
|
616
|
-
if (participantsToRemove.length === 0) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
const removed = new Set(participantsToRemove);
|
|
620
|
-
const nextParticipants = cachedParticipants.filter((participant) => !removed.has(participant));
|
|
621
|
-
if (nextParticipants.length === cachedParticipants.length) {
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
if (nextParticipants.length === 0) {
|
|
625
|
-
await this.participantsStore.deleteGroupParticipants(groupJid);
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
await this.participantsStore.upsertGroupParticipants({
|
|
629
|
-
groupJid,
|
|
630
|
-
participants: nextParticipants,
|
|
631
|
-
updatedAtMs: Date.now()
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
async replaceParticipantUsersInCache(groupJid, cachedParticipants, participantsToReplace, replacementParticipants) {
|
|
635
|
-
const toReplace = new Set(participantsToReplace);
|
|
636
|
-
const nextParticipants = cachedParticipants.filter((participant) => !toReplace.has(participant));
|
|
637
|
-
const existing = new Set(nextParticipants);
|
|
638
|
-
for (const participant of replacementParticipants) {
|
|
639
|
-
if (existing.has(participant)) {
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
existing.add(participant);
|
|
643
|
-
nextParticipants.push(participant);
|
|
644
|
-
}
|
|
645
|
-
if (this.areParticipantListsEqual(cachedParticipants, nextParticipants)) {
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
if (nextParticipants.length === 0) {
|
|
649
|
-
await this.participantsStore.deleteGroupParticipants(groupJid);
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
await this.participantsStore.upsertGroupParticipants({
|
|
653
|
-
groupJid,
|
|
654
|
-
participants: nextParticipants,
|
|
655
|
-
updatedAtMs: Date.now()
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
areParticipantListsEqual(left, right) {
|
|
659
|
-
if (left.length !== right.length) {
|
|
660
|
-
return false;
|
|
661
|
-
}
|
|
662
|
-
for (let index = 0; index < left.length; index += 1) {
|
|
663
|
-
if (left[index] !== right[index]) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return true;
|
|
668
|
-
}
|
|
669
|
-
async refreshGroupParticipantUsers(groupJid) {
|
|
670
|
-
const queried = await this.queryGroupParticipantJids(groupJid);
|
|
671
|
-
const participants = this.sanitizeParticipantUsers(queried);
|
|
672
|
-
await this.participantsStore.upsertGroupParticipants({
|
|
673
|
-
groupJid,
|
|
674
|
-
participants,
|
|
675
|
-
updatedAtMs: Date.now()
|
|
676
|
-
});
|
|
677
|
-
return participants;
|
|
678
|
-
}
|
|
679
|
-
sanitizeParticipantUsers(participants) {
|
|
680
|
-
const deduped = new Set();
|
|
681
|
-
for (const participant of participants) {
|
|
682
|
-
if (!participant || !participant.includes('@'))
|
|
683
|
-
continue;
|
|
684
|
-
try {
|
|
685
|
-
deduped.add((0, jid_1.toUserJid)(participant));
|
|
686
|
-
}
|
|
687
|
-
catch (error) {
|
|
688
|
-
this.logger.trace('ignoring malformed participant jid', {
|
|
689
|
-
participant,
|
|
690
|
-
message: (0, primitives_1.toError)(error).message
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
return [...deduped];
|
|
695
|
-
}
|
|
696
412
|
resolveGroupAddressingMode(participantUserJids, groupJid) {
|
|
697
|
-
for (
|
|
413
|
+
for (let index = 0; index < participantUserJids.length; index += 1) {
|
|
414
|
+
const participantJid = participantUserJids[index];
|
|
698
415
|
try {
|
|
699
416
|
if ((0, jid_1.splitJid)(participantJid).server === 'lid') {
|
|
700
417
|
return 'lid';
|
|
@@ -727,115 +444,131 @@ class WaMessageDispatchCoordinator {
|
|
|
727
444
|
}
|
|
728
445
|
return (0, jid_1.normalizeDeviceJid)(meJid);
|
|
729
446
|
}
|
|
730
|
-
async encryptGroupDistributionParticipants(groupJid,
|
|
447
|
+
async encryptGroupDistributionParticipants(groupJid, senderKeyId, senderKeyDistributionMessage, participantUserJids) {
|
|
731
448
|
const distributionPayload = await (0, padding_1.writeRandomPadMax16)(_proto_1.proto.Message.encode({
|
|
732
449
|
senderKeyDistributionMessage
|
|
733
450
|
}).finish());
|
|
734
|
-
const fanoutDeviceJids = await this.resolveGroupParticipantDeviceJids(participantUserJids);
|
|
451
|
+
const fanoutDeviceJids = await this.fanoutResolver.resolveGroupParticipantDeviceJids(participantUserJids);
|
|
735
452
|
if (fanoutDeviceJids.length === 0) {
|
|
736
453
|
return {
|
|
737
454
|
fanoutDeviceJids,
|
|
738
455
|
distributionParticipants: []
|
|
739
456
|
};
|
|
740
457
|
}
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
458
|
+
const fanoutTargetsByAddressKey = new Map();
|
|
459
|
+
const fanoutAddresses = new Array(fanoutDeviceJids.length);
|
|
460
|
+
for (let index = 0; index < fanoutDeviceJids.length; index += 1) {
|
|
461
|
+
const jid = fanoutDeviceJids[index];
|
|
462
|
+
const address = (0, jid_1.parseSignalAddressFromJid)(jid);
|
|
463
|
+
fanoutAddresses[index] = address;
|
|
464
|
+
fanoutTargetsByAddressKey.set((0, jid_2.signalAddressKey)(address), { jid, address });
|
|
465
|
+
}
|
|
466
|
+
const pendingAddresses = await this.senderKeyManager.filterParticipantsNeedingDistribution(groupJid, senderKeyId, fanoutAddresses);
|
|
746
467
|
if (pendingAddresses.length === 0) {
|
|
747
468
|
return {
|
|
748
469
|
fanoutDeviceJids,
|
|
749
470
|
distributionParticipants: []
|
|
750
471
|
};
|
|
751
472
|
}
|
|
752
|
-
const pendingAddressKeys = new Set(
|
|
753
|
-
const pendingTargets =
|
|
473
|
+
const pendingAddressKeys = new Set();
|
|
474
|
+
const pendingTargets = [];
|
|
475
|
+
for (let index = 0; index < pendingAddresses.length; index += 1) {
|
|
476
|
+
const key = (0, jid_2.signalAddressKey)(pendingAddresses[index]);
|
|
477
|
+
if (pendingAddressKeys.has(key)) {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
pendingAddressKeys.add(key);
|
|
481
|
+
const target = fanoutTargetsByAddressKey.get(key);
|
|
482
|
+
if (target) {
|
|
483
|
+
pendingTargets.push(target);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
754
486
|
if (pendingTargets.length === 0) {
|
|
755
487
|
return {
|
|
756
488
|
fanoutDeviceJids,
|
|
757
489
|
distributionParticipants: []
|
|
758
490
|
};
|
|
759
491
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
492
|
+
const pendingTargetJids = new Array(pendingTargets.length);
|
|
493
|
+
for (let index = 0; index < pendingTargets.length; index += 1) {
|
|
494
|
+
pendingTargetJids[index] = pendingTargets[index].jid;
|
|
495
|
+
}
|
|
496
|
+
let availableTargets = [];
|
|
497
|
+
let prefetchedAvailableTargets;
|
|
498
|
+
try {
|
|
499
|
+
const resolvedTargets = await this.sessionResolver.ensureSessionsBatch(pendingTargetJids);
|
|
500
|
+
availableTargets = resolvedTargets;
|
|
501
|
+
prefetchedAvailableTargets = resolvedTargets;
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
const normalized = (0, primitives_1.toError)(error);
|
|
505
|
+
if (normalized.message === 'identity mismatch') {
|
|
506
|
+
throw normalized;
|
|
507
|
+
}
|
|
508
|
+
this.logger.warn('group sender-key distribution session sync failed, continuing with available sessions', {
|
|
509
|
+
groupJid,
|
|
510
|
+
requested: pendingTargetJids.length,
|
|
511
|
+
message: normalized.message
|
|
512
|
+
});
|
|
513
|
+
const pendingTargetAddresses = new Array(pendingTargets.length);
|
|
514
|
+
for (let index = 0; index < pendingTargets.length; index += 1) {
|
|
515
|
+
pendingTargetAddresses[index] = pendingTargets[index].address;
|
|
516
|
+
}
|
|
517
|
+
const hasPendingSessions = await this.signalStore.hasSessions(pendingTargetAddresses);
|
|
518
|
+
const nextAvailableTargets = [];
|
|
519
|
+
for (let index = 0; index < pendingTargets.length; index += 1) {
|
|
520
|
+
if (hasPendingSessions[index]) {
|
|
521
|
+
nextAvailableTargets.push(pendingTargets[index]);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
availableTargets = nextAvailableTargets;
|
|
525
|
+
}
|
|
526
|
+
if (availableTargets.length === 0) {
|
|
764
527
|
return {
|
|
528
|
+
fanoutDeviceJids,
|
|
529
|
+
distributionParticipants: []
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
const distributionEncryptRequests = new Array(availableTargets.length);
|
|
533
|
+
for (let index = 0; index < availableTargets.length; index += 1) {
|
|
534
|
+
const target = availableTargets[index];
|
|
535
|
+
distributionEncryptRequests[index] = {
|
|
536
|
+
address: target.address,
|
|
537
|
+
plaintext: distributionPayload
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
const encryptedDistributionParticipants = await this.signalProtocol.encryptMessagesBatch(distributionEncryptRequests, prefetchedAvailableTargets);
|
|
541
|
+
const distributionParticipants = new Array(availableTargets.length);
|
|
542
|
+
for (let index = 0; index < availableTargets.length; index += 1) {
|
|
543
|
+
const target = availableTargets[index];
|
|
544
|
+
distributionParticipants[index] = {
|
|
765
545
|
jid: target.jid,
|
|
766
546
|
address: target.address,
|
|
767
|
-
encType:
|
|
768
|
-
ciphertext:
|
|
547
|
+
encType: encryptedDistributionParticipants[index].type,
|
|
548
|
+
ciphertext: encryptedDistributionParticipants[index].ciphertext
|
|
769
549
|
};
|
|
770
|
-
}
|
|
550
|
+
}
|
|
771
551
|
return {
|
|
772
552
|
fanoutDeviceJids,
|
|
773
553
|
distributionParticipants
|
|
774
554
|
};
|
|
775
555
|
}
|
|
776
|
-
async
|
|
777
|
-
const
|
|
778
|
-
const meJid = this.getCurrentMeJid();
|
|
779
|
-
if (meJid) {
|
|
780
|
-
try {
|
|
781
|
-
meDeviceJids.add((0, jid_1.normalizeDeviceJid)(meJid));
|
|
782
|
-
}
|
|
783
|
-
catch (error) {
|
|
784
|
-
this.logger.trace('ignoring malformed me jid', {
|
|
785
|
-
meJid,
|
|
786
|
-
message: (0, primitives_1.toError)(error).message
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
const meLid = this.getCurrentMeLid();
|
|
791
|
-
if (meLid && meLid.includes('@')) {
|
|
792
|
-
try {
|
|
793
|
-
meDeviceJids.add((0, jid_1.normalizeDeviceJid)(meLid));
|
|
794
|
-
}
|
|
795
|
-
catch (error) {
|
|
796
|
-
this.logger.trace('ignoring malformed me lid jid', {
|
|
797
|
-
meLid,
|
|
798
|
-
message: (0, primitives_1.toError)(error).message
|
|
799
|
-
});
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
const candidateUsers = [...new Set(participantUserJids)];
|
|
803
|
-
if (candidateUsers.length === 0) {
|
|
804
|
-
return [];
|
|
805
|
-
}
|
|
806
|
-
try {
|
|
807
|
-
const synced = await this.signalDeviceSync.syncDeviceList(candidateUsers);
|
|
808
|
-
const fanout = new Set();
|
|
809
|
-
for (const entry of synced) {
|
|
810
|
-
if (entry.deviceJids.length === 0) {
|
|
811
|
-
const normalizedEntryJid = (0, jid_1.normalizeDeviceJid)(entry.jid);
|
|
812
|
-
if (meDeviceJids.has(normalizedEntryJid))
|
|
813
|
-
continue;
|
|
814
|
-
fanout.add(normalizedEntryJid);
|
|
815
|
-
continue;
|
|
816
|
-
}
|
|
817
|
-
for (const deviceJid of entry.deviceJids) {
|
|
818
|
-
const normalizedDeviceJid = (0, jid_1.normalizeDeviceJid)(deviceJid);
|
|
819
|
-
if (meDeviceJids.has(normalizedDeviceJid))
|
|
820
|
-
continue;
|
|
821
|
-
fanout.add(normalizedDeviceJid);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
return [...fanout];
|
|
825
|
-
}
|
|
826
|
-
catch (error) {
|
|
827
|
-
this.logger.warn('group participant device sync failed, falling back to participant user jids', {
|
|
828
|
-
participants: candidateUsers.length,
|
|
829
|
-
message: (0, primitives_1.toError)(error).message
|
|
830
|
-
});
|
|
831
|
-
return [...new Set(candidateUsers.map((jid) => (0, jid_1.normalizeDeviceJid)(jid)))].filter((jid) => !meDeviceJids.has(jid));
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
async publishDirectSignalMessageWithFanout(recipientJid, message, plaintext, type, options) {
|
|
556
|
+
async publishDirectSignalMessageWithFanout(recipientJid, message, plaintext, type, options, edit, mediatype, metaNode) {
|
|
557
|
+
const sendOptions = await this.withResolvedMessageId(options);
|
|
835
558
|
const meJid = this.requireCurrentMeJid('sendMessage');
|
|
836
559
|
const meLid = this.getCurrentMeLid();
|
|
837
|
-
const selfDeviceJidForRecipient = this.resolveSelfDeviceJidForRecipient(recipientJid, meJid, meLid);
|
|
838
|
-
const deviceJids = await this.resolveDirectFanoutDeviceJids(recipientJid, selfDeviceJidForRecipient);
|
|
560
|
+
const selfDeviceJidForRecipient = this.fanoutResolver.resolveSelfDeviceJidForRecipient(recipientJid, meJid, meLid);
|
|
561
|
+
const deviceJids = await this.fanoutResolver.resolveDirectFanoutDeviceJids(recipientJid, selfDeviceJidForRecipient);
|
|
562
|
+
const targets = new Array(deviceJids.length);
|
|
563
|
+
for (let index = 0; index < deviceJids.length; index += 1) {
|
|
564
|
+
const jid = deviceJids[index];
|
|
565
|
+
const parsed = (0, jid_1.parseJidFull)(jid);
|
|
566
|
+
targets[index] = {
|
|
567
|
+
jid,
|
|
568
|
+
normalizedJid: parsed.normalizedJid,
|
|
569
|
+
userJid: parsed.userJid
|
|
570
|
+
};
|
|
571
|
+
}
|
|
839
572
|
const recipientUserJid = (0, jid_1.toUserJid)(recipientJid);
|
|
840
573
|
const meUserJid = (0, jid_1.toUserJid)(selfDeviceJidForRecipient);
|
|
841
574
|
this.logger.debug('wa client publish signal fanout', {
|
|
@@ -844,44 +577,115 @@ class WaMessageDispatchCoordinator {
|
|
|
844
577
|
type
|
|
845
578
|
});
|
|
846
579
|
const expectedIdentityByJid = new Map();
|
|
847
|
-
if (
|
|
848
|
-
for (let index = 0; index <
|
|
849
|
-
const
|
|
850
|
-
if (
|
|
851
|
-
expectedIdentityByJid.set(
|
|
580
|
+
if (sendOptions.expectedIdentity) {
|
|
581
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
582
|
+
const target = targets[index];
|
|
583
|
+
if (target.userJid === recipientUserJid) {
|
|
584
|
+
expectedIdentityByJid.set(target.normalizedJid, sendOptions.expectedIdentity);
|
|
852
585
|
}
|
|
853
586
|
}
|
|
854
587
|
}
|
|
855
|
-
await this.
|
|
856
|
-
const
|
|
588
|
+
const resolvedFanoutTargets = await this.sessionResolver.ensureSessionsBatch(deviceJids, expectedIdentityByJid);
|
|
589
|
+
const resolvedFanoutTargetsByJid = new Map();
|
|
590
|
+
for (let index = 0; index < resolvedFanoutTargets.length; index += 1) {
|
|
591
|
+
const target = resolvedFanoutTargets[index];
|
|
592
|
+
resolvedFanoutTargetsByJid.set((0, jid_1.normalizeDeviceJid)(target.jid), target);
|
|
593
|
+
}
|
|
594
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
595
|
+
if (!resolvedFanoutTargetsByJid.has(targets[index].normalizedJid)) {
|
|
596
|
+
throw new Error('direct fanout missing signal sessions for one or more targets');
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
let hasSelfDeviceFanout = false;
|
|
600
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
601
|
+
if (targets[index].userJid === meUserJid) {
|
|
602
|
+
hasSelfDeviceFanout = true;
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
857
606
|
const selfDevicePlaintext = hasSelfDeviceFanout
|
|
858
607
|
? await (0, padding_1.writeRandomPadMax16)(_proto_1.proto.Message.encode((0, device_sent_1.wrapDeviceSentMessage)(message, recipientUserJid)).finish())
|
|
859
608
|
: null;
|
|
860
|
-
const
|
|
861
|
-
|
|
862
|
-
const
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
609
|
+
const participantRequests = new Array(targets.length);
|
|
610
|
+
for (let index = 0; index < targets.length; index += 1) {
|
|
611
|
+
const target = targets[index];
|
|
612
|
+
const resolvedTarget = resolvedFanoutTargetsByJid.get(target.normalizedJid);
|
|
613
|
+
if (!resolvedTarget) {
|
|
614
|
+
throw new Error('direct fanout missing signal session for target');
|
|
615
|
+
}
|
|
616
|
+
participantRequests[index] = {
|
|
617
|
+
target,
|
|
618
|
+
address: resolvedTarget.address,
|
|
619
|
+
session: resolvedTarget.session,
|
|
620
|
+
expectedIdentity: target.userJid === recipientUserJid ? sendOptions.expectedIdentity : undefined,
|
|
621
|
+
plaintext: selfDevicePlaintext && target.userJid === meUserJid
|
|
622
|
+
? selfDevicePlaintext
|
|
623
|
+
: plaintext
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
const encryptRequests = new Array(participantRequests.length);
|
|
627
|
+
const prefetchedSessions = new Array(participantRequests.length);
|
|
628
|
+
for (let index = 0; index < participantRequests.length; index += 1) {
|
|
629
|
+
const request = participantRequests[index];
|
|
630
|
+
encryptRequests[index] = {
|
|
631
|
+
address: request.address,
|
|
632
|
+
plaintext: request.plaintext,
|
|
633
|
+
expectedIdentity: request.expectedIdentity
|
|
634
|
+
};
|
|
635
|
+
prefetchedSessions[index] = {
|
|
636
|
+
address: request.address,
|
|
637
|
+
session: request.session
|
|
873
638
|
};
|
|
874
|
-
}
|
|
875
|
-
const
|
|
639
|
+
}
|
|
640
|
+
const encryptedParticipants = await this.signalProtocol.encryptMessagesBatch(encryptRequests, prefetchedSessions);
|
|
641
|
+
const participants = new Array(participantRequests.length);
|
|
642
|
+
for (let index = 0; index < participantRequests.length; index += 1) {
|
|
643
|
+
const request = participantRequests[index];
|
|
644
|
+
participants[index] = {
|
|
645
|
+
jid: request.target.jid,
|
|
646
|
+
encType: encryptedParticipants[index].type,
|
|
647
|
+
ciphertext: encryptedParticipants[index].ciphertext
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
let shouldAttachDeviceIdentity = false;
|
|
651
|
+
for (let index = 0; index < participants.length; index += 1) {
|
|
652
|
+
if (participants[index].encType === 'pkmsg') {
|
|
653
|
+
shouldAttachDeviceIdentity = true;
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
876
657
|
const deviceIdentity = shouldAttachDeviceIdentity
|
|
877
658
|
? this.getEncodedSignedDeviceIdentity()
|
|
878
659
|
: undefined;
|
|
660
|
+
const reportingArtifacts = await this.tryBuildReportingTokenArtifacts({
|
|
661
|
+
message,
|
|
662
|
+
stanzaId: sendOptions.id,
|
|
663
|
+
senderUserJid: meUserJid,
|
|
664
|
+
remoteJid: recipientUserJid,
|
|
665
|
+
context: 'direct_fanout'
|
|
666
|
+
});
|
|
667
|
+
let privacyTokenNode;
|
|
668
|
+
try {
|
|
669
|
+
privacyTokenNode =
|
|
670
|
+
(await this.privacyTokenDedup.run(`pt:${recipientUserJid}`, () => this.resolvePrivacyTokenNode(recipientUserJid))) ?? undefined;
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
this.logger.warn('privacy token resolution failed', {
|
|
674
|
+
to: recipientUserJid,
|
|
675
|
+
message: (0, primitives_1.toError)(error).message
|
|
676
|
+
});
|
|
677
|
+
}
|
|
879
678
|
const messageNode = (0, message_1.buildDirectMessageFanoutNode)({
|
|
880
679
|
to: recipientJid,
|
|
881
680
|
type,
|
|
882
|
-
id:
|
|
681
|
+
id: sendOptions.id,
|
|
682
|
+
edit,
|
|
883
683
|
participants,
|
|
884
|
-
deviceIdentity
|
|
684
|
+
deviceIdentity,
|
|
685
|
+
reportingNode: reportingArtifacts?.node ?? undefined,
|
|
686
|
+
privacyTokenNode,
|
|
687
|
+
metaNode,
|
|
688
|
+
mediatype
|
|
885
689
|
});
|
|
886
690
|
const replayPayload = {
|
|
887
691
|
mode: 'plaintext',
|
|
@@ -889,130 +693,75 @@ class WaMessageDispatchCoordinator {
|
|
|
889
693
|
type,
|
|
890
694
|
plaintext
|
|
891
695
|
};
|
|
892
|
-
|
|
893
|
-
messageIdHint:
|
|
696
|
+
const result = await this.retryTracker.track({
|
|
697
|
+
messageIdHint: sendOptions.id ?? messageNode.attrs.id,
|
|
894
698
|
toJid: recipientJid,
|
|
895
|
-
|
|
896
|
-
replayPayload
|
|
897
|
-
|
|
699
|
+
type,
|
|
700
|
+
replayPayload,
|
|
701
|
+
eligibleRequesterDeviceJids: deviceJids
|
|
702
|
+
}, async () => this.messageClient.publishNode(messageNode, sendOptions));
|
|
703
|
+
this.onDirectMessageSent(recipientUserJid);
|
|
704
|
+
return result;
|
|
898
705
|
}
|
|
899
|
-
async
|
|
900
|
-
const
|
|
901
|
-
if (
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
const missingTargets = normalizedTargets.filter((_, index) => !hasSessions[index]);
|
|
910
|
-
if (missingTargets.length === 0) {
|
|
911
|
-
return;
|
|
706
|
+
async withResolvedMessageId(options) {
|
|
707
|
+
const normalizedId = options.id?.trim();
|
|
708
|
+
if (normalizedId) {
|
|
709
|
+
if (normalizedId === options.id) {
|
|
710
|
+
return options;
|
|
711
|
+
}
|
|
712
|
+
return {
|
|
713
|
+
...options,
|
|
714
|
+
id: normalizedId
|
|
715
|
+
};
|
|
912
716
|
}
|
|
717
|
+
return {
|
|
718
|
+
...options,
|
|
719
|
+
id: await this.generateOutgoingMessageId()
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
async generateOutgoingMessageId() {
|
|
913
723
|
try {
|
|
914
|
-
const
|
|
915
|
-
const
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const expectedIdentity = expectedIdentityByJid.get(target.jid);
|
|
926
|
-
const remoteIdentity = (0, keys_1.toSerializedPubKey)(result.bundle.identity);
|
|
927
|
-
if (expectedIdentity &&
|
|
928
|
-
!(0, bytes_1.uint8Equal)(remoteIdentity, (0, keys_1.toSerializedPubKey)(expectedIdentity))) {
|
|
929
|
-
throw new Error('identity mismatch');
|
|
930
|
-
}
|
|
931
|
-
establishPromises.push(this.signalProtocol
|
|
932
|
-
.establishOutgoingSession(target.address, result.bundle)
|
|
933
|
-
.then(() => {
|
|
934
|
-
this.logger.debug('signal session synchronized from batch key fetch', {
|
|
935
|
-
jid: target.jid,
|
|
936
|
-
regId: result.bundle.regId,
|
|
937
|
-
hasOneTimeKey: result.bundle.oneTimeKey !== undefined
|
|
938
|
-
});
|
|
939
|
-
}));
|
|
940
|
-
}
|
|
941
|
-
await Promise.all(establishPromises);
|
|
942
|
-
if (fallbackJids.length === 0) {
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
this.logger.warn('signal batch key fetch returned partial errors, falling back to single requests', {
|
|
946
|
-
requested: missingTargets.length,
|
|
947
|
-
fallbackTargets: fallbackJids.length
|
|
948
|
-
});
|
|
949
|
-
for (let index = 0; index < fallbackJids.length; index += 1) {
|
|
950
|
-
const jid = fallbackJids[index];
|
|
951
|
-
const address = (0, jid_1.parseSignalAddressFromJid)(jid);
|
|
952
|
-
await this.ensureSignalSession(address, jid, expectedIdentityByJid.get(jid));
|
|
953
|
-
}
|
|
724
|
+
const meUserJid = (0, jid_1.toUserJid)(this.requireCurrentMeJid('sendMessage'));
|
|
725
|
+
const timestampSeconds = Math.floor(Date.now() / 1000);
|
|
726
|
+
const timestampBytes = new Uint8Array(8);
|
|
727
|
+
new DataView(timestampBytes.buffer, timestampBytes.byteOffset, timestampBytes.byteLength).setBigUint64(0, BigInt(timestampSeconds), false);
|
|
728
|
+
const entropy = (0, bytes_1.concatBytes)([
|
|
729
|
+
timestampBytes,
|
|
730
|
+
bytes_1.TEXT_ENCODER.encode(meUserJid),
|
|
731
|
+
await (0, _crypto_1.randomBytesAsync)(8)
|
|
732
|
+
]);
|
|
733
|
+
const digest = await (0, _crypto_1.sha256)(entropy);
|
|
734
|
+
return `3EB0${(0, bytes_1.bytesToHex)(digest.subarray(0, 9)).toUpperCase()}`;
|
|
954
735
|
}
|
|
955
736
|
catch (error) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
throw normalized;
|
|
959
|
-
}
|
|
960
|
-
this.logger.warn('signal batch key fetch failed, falling back to single requests', {
|
|
961
|
-
requested: missingTargets.length,
|
|
962
|
-
message: normalized.message
|
|
737
|
+
this.logger.warn('failed to generate sha256 message id, falling back to random id', {
|
|
738
|
+
message: (0, primitives_1.toError)(error).message
|
|
963
739
|
});
|
|
964
|
-
|
|
965
|
-
const target = missingTargets[index];
|
|
966
|
-
await this.ensureSignalSession(target.address, target.jid, expectedIdentityByJid.get(target.jid));
|
|
967
|
-
}
|
|
740
|
+
return `3EB0${(0, bytes_1.bytesToHex)(await (0, _crypto_1.randomBytesAsync)(8)).toUpperCase()}`;
|
|
968
741
|
}
|
|
969
742
|
}
|
|
970
|
-
async
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
743
|
+
async tryBuildReportingTokenArtifacts(input) {
|
|
744
|
+
if (!input.stanzaId) {
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
974
747
|
try {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
}
|
|
982
|
-
else {
|
|
983
|
-
for (let index = 0; index < recipientDevices.length; index += 1) {
|
|
984
|
-
fanout.add(recipientDevices[index]);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
const meDevices = byUser.get(meUserJid) ?? [];
|
|
988
|
-
const normalizedMeJid = (0, jid_1.normalizeDeviceJid)(selfDeviceJidForRecipient);
|
|
989
|
-
for (let index = 0; index < meDevices.length; index += 1) {
|
|
990
|
-
const deviceJid = meDevices[index];
|
|
991
|
-
if ((0, jid_1.normalizeDeviceJid)(deviceJid) === normalizedMeJid) {
|
|
992
|
-
continue;
|
|
993
|
-
}
|
|
994
|
-
fanout.add(deviceJid);
|
|
995
|
-
}
|
|
996
|
-
return [...fanout];
|
|
748
|
+
return await (0, reporting_token_1.buildReportingTokenArtifacts)({
|
|
749
|
+
message: input.message,
|
|
750
|
+
stanzaId: input.stanzaId,
|
|
751
|
+
senderUserJid: input.senderUserJid,
|
|
752
|
+
remoteJid: input.remoteJid
|
|
753
|
+
});
|
|
997
754
|
}
|
|
998
755
|
catch (error) {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
756
|
+
this.logger.warn('failed to generate reporting token', {
|
|
757
|
+
context: input.context,
|
|
758
|
+
id: input.stanzaId,
|
|
759
|
+
remoteJid: input.remoteJid,
|
|
760
|
+
message: (0, primitives_1.toError)(error).message
|
|
1003
761
|
});
|
|
1004
|
-
return
|
|
762
|
+
return null;
|
|
1005
763
|
}
|
|
1006
764
|
}
|
|
1007
|
-
resolveSelfDeviceJidForRecipient(recipientJid, meJid, meLid) {
|
|
1008
|
-
if ((0, jid_1.splitJid)(recipientJid).server !== 'lid') {
|
|
1009
|
-
return meJid;
|
|
1010
|
-
}
|
|
1011
|
-
if (!meLid || !meLid.includes('@')) {
|
|
1012
|
-
return meJid;
|
|
1013
|
-
}
|
|
1014
|
-
return meLid;
|
|
1015
|
-
}
|
|
1016
765
|
getEncodedSignedDeviceIdentity() {
|
|
1017
766
|
const signedIdentity = this.getCurrentSignedIdentity();
|
|
1018
767
|
if (!signedIdentity) {
|
|
@@ -1020,34 +769,23 @@ class WaMessageDispatchCoordinator {
|
|
|
1020
769
|
}
|
|
1021
770
|
return _proto_1.proto.ADVSignedDeviceIdentity.encode(signedIdentity).finish();
|
|
1022
771
|
}
|
|
1023
|
-
|
|
1024
|
-
this.
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
if (storedIdentity && !(0, bytes_1.uint8Equal)(remoteIdentity, storedIdentity)) {
|
|
1040
|
-
throw new Error('identity mismatch');
|
|
772
|
+
resolveUserIcdc(userJid, localIdentity) {
|
|
773
|
+
return this.icdcDedup.run(`icdc:${userJid}:${localIdentity ? '1' : '0'}`, async () => {
|
|
774
|
+
try {
|
|
775
|
+
const snapshots = await this.deviceListStore.getUserDevicesBatch([userJid]);
|
|
776
|
+
const snapshot = snapshots[0];
|
|
777
|
+
if (!snapshot || snapshot.deviceJids.length === 0) {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
return (0, icdc_1.resolveIcdcMeta)(snapshot.deviceJids, this.signalStore, snapshot.updatedAtMs, localIdentity);
|
|
781
|
+
}
|
|
782
|
+
catch (error) {
|
|
783
|
+
this.logger.trace('icdc resolution failed', {
|
|
784
|
+
userJid,
|
|
785
|
+
message: (0, primitives_1.toError)(error).message
|
|
786
|
+
});
|
|
787
|
+
return null;
|
|
1041
788
|
}
|
|
1042
|
-
}
|
|
1043
|
-
if (expectedIdentity && !(0, bytes_1.uint8Equal)(remoteIdentity, (0, keys_1.toSerializedPubKey)(expectedIdentity))) {
|
|
1044
|
-
throw new Error('identity mismatch');
|
|
1045
|
-
}
|
|
1046
|
-
await this.signalProtocol.establishOutgoingSession(address, fetched.bundle);
|
|
1047
|
-
this.logger.info('signal session synchronized', {
|
|
1048
|
-
jid,
|
|
1049
|
-
regId: fetched.bundle.regId,
|
|
1050
|
-
hasOneTimeKey: fetched.bundle.oneTimeKey !== undefined
|
|
1051
789
|
});
|
|
1052
790
|
}
|
|
1053
791
|
requireCurrentMeJid(context) {
|