zapo-js 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/dist/appstate/WaAppStateCrypto.js +1 -1
- package/dist/appstate/WaAppStateSyncClient.js +138 -93
- package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/appstate/index.js +8 -6
- package/dist/appstate/utils.js +0 -5
- package/dist/auth/WaAuthClient.js +36 -47
- package/dist/auth/flow/WaAuthCredentialsFlow.js +7 -7
- package/dist/auth/index.js +1 -6
- package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/auth/pairing/WaPairingFlow.js +13 -3
- package/dist/client/WaClient.js +225 -101
- package/dist/client/WaClientFactory.js +294 -44
- package/dist/client/connection/WaConnectionManager.js +19 -10
- package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
- package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +292 -99
- package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
- package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
- package/dist/client/coordinators/WaRetryCoordinator.js +179 -27
- package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
- package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
- package/dist/client/dirty.js +40 -20
- package/dist/client/events/devices.js +72 -0
- package/dist/client/events/group.js +3 -11
- package/dist/client/events/identity.js +22 -0
- package/dist/client/events/privacy-token.js +39 -0
- package/dist/client/history-sync.js +50 -9
- package/dist/client/incoming.js +37 -7
- package/dist/client/mailbox.js +24 -23
- package/dist/client/messages.js +107 -31
- package/dist/client/messaging/fanout.js +21 -11
- package/dist/client/messaging/participants.js +6 -4
- package/dist/client/persistence/WriteBehindPersistence.js +129 -0
- package/dist/client/tokens/cs-token.js +50 -0
- package/dist/client/tokens/tc-token.js +25 -0
- package/dist/crypto/core/index.js +2 -2
- package/dist/crypto/core/keys.js +4 -4
- package/dist/crypto/core/nonce.js +2 -0
- package/dist/crypto/core/primitives.js +0 -8
- package/dist/crypto/core/random.js +22 -0
- package/dist/crypto/curves/X25519.js +25 -6
- package/dist/crypto/index.js +3 -0
- package/dist/crypto/math/constants.js +13 -36
- package/dist/crypto/math/edwards.js +171 -44
- package/dist/crypto/math/fe.js +706 -0
- package/dist/crypto/math/mod.js +10 -3
- package/dist/esm/appstate/WaAppStateCrypto.js +1 -1
- package/dist/esm/appstate/WaAppStateSyncClient.js +138 -93
- package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
- package/dist/esm/appstate/index.js +2 -2
- package/dist/esm/appstate/utils.js +2 -5
- package/dist/esm/auth/WaAuthClient.js +36 -47
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +7 -7
- package/dist/esm/auth/index.js +0 -2
- package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
- package/dist/esm/auth/pairing/WaPairingFlow.js +14 -4
- package/dist/esm/client/WaClient.js +225 -101
- package/dist/esm/client/WaClientFactory.js +295 -45
- package/dist/esm/client/connection/WaConnectionManager.js +19 -10
- package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +295 -102
- package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
- package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
- package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +181 -29
- package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
- package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
- package/dist/esm/client/dirty.js +40 -20
- package/dist/esm/client/events/devices.js +68 -0
- package/dist/esm/client/events/group.js +3 -11
- package/dist/esm/client/events/identity.js +19 -0
- package/dist/esm/client/events/privacy-token.js +36 -0
- package/dist/esm/client/history-sync.js +50 -9
- package/dist/esm/client/incoming.js +38 -8
- package/dist/esm/client/mailbox.js +24 -23
- package/dist/esm/client/messages.js +108 -32
- package/dist/esm/client/messaging/fanout.js +22 -12
- package/dist/esm/client/messaging/participants.js +6 -4
- package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
- package/dist/esm/client/tokens/cs-token.js +46 -0
- package/dist/esm/client/tokens/tc-token.js +18 -0
- package/dist/esm/crypto/core/index.js +2 -2
- package/dist/esm/crypto/core/keys.js +1 -1
- package/dist/esm/crypto/core/nonce.js +2 -0
- package/dist/esm/crypto/core/primitives.js +0 -7
- package/dist/esm/crypto/core/random.js +22 -1
- package/dist/esm/crypto/curves/X25519.js +25 -6
- package/dist/esm/crypto/index.js +1 -0
- package/dist/esm/crypto/math/constants.js +12 -35
- package/dist/esm/crypto/math/edwards.js +174 -47
- package/dist/esm/crypto/math/fe.js +691 -0
- package/dist/esm/crypto/math/mod.js +10 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
- package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
- package/dist/esm/infra/perf/PromiseDedup.js +20 -0
- package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
- package/dist/esm/infra/perf/StoreLock.js +77 -0
- package/dist/esm/media/WaMediaCrypto.js +95 -13
- package/dist/esm/media/WaMediaTransferClient.js +39 -47
- package/dist/esm/media/constants.js +2 -1
- package/dist/esm/message/WaMessageClient.js +26 -19
- package/dist/esm/message/content.js +195 -9
- package/dist/esm/message/icdc.js +76 -0
- package/dist/esm/message/incoming.js +24 -12
- package/dist/esm/message/phash.js +3 -1
- package/dist/esm/message/reporting-token.js +14 -27
- package/dist/esm/protocol/appstate.js +9 -40
- package/dist/esm/protocol/browser.js +10 -18
- package/dist/esm/protocol/constants.js +5 -3
- package/dist/esm/protocol/defaults.js +6 -0
- package/dist/esm/protocol/index.js +1 -2
- package/dist/esm/protocol/jid.js +105 -36
- package/dist/esm/protocol/message.js +61 -1
- package/dist/esm/protocol/nodes.js +2 -0
- package/dist/esm/protocol/notification.js +3 -1
- package/dist/esm/protocol/privacy-token.js +17 -0
- package/dist/esm/protocol/privacy.js +55 -0
- package/dist/esm/protocol/stream.js +26 -1
- package/dist/esm/retry/codec.js +216 -0
- package/dist/esm/retry/constants.js +1 -1
- package/dist/esm/retry/index.js +2 -2
- package/dist/esm/retry/parse.js +50 -30
- package/dist/esm/retry/replay.js +11 -7
- package/dist/esm/retry/tracker.js +50 -12
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +49 -32
- package/dist/esm/signal/api/SignalDigestSyncApi.js +13 -9
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +26 -11
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +18 -7
- package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/esm/signal/api/SignalSessionSyncApi.js +16 -7
- package/dist/esm/signal/api/result-map.js +10 -0
- package/dist/esm/signal/constants.js +0 -4
- package/dist/esm/signal/crypto/WaAdvSignature.js +12 -6
- package/dist/esm/signal/{store/sqlite.js → encoding.js} +78 -24
- package/dist/esm/signal/group/SenderKeyCodec.js +3 -2
- package/dist/esm/signal/group/SenderKeyManager.js +125 -106
- package/dist/esm/signal/index.js +1 -0
- package/dist/esm/signal/registration/keygen.js +6 -2
- package/dist/esm/signal/registration/utils.js +1 -0
- package/dist/esm/signal/session/SignalProtocol.js +150 -74
- package/dist/esm/signal/session/resolver.js +137 -102
- package/dist/esm/store/contracts/privacy-token.store.js +1 -0
- package/dist/esm/store/createStore.js +101 -187
- package/dist/esm/store/index.js +1 -10
- package/dist/esm/store/locks/appstate.lock.js +26 -0
- package/dist/esm/store/locks/auth.lock.js +15 -0
- package/dist/esm/store/locks/contact.lock.js +20 -0
- package/dist/esm/store/locks/device-list.lock.js +20 -0
- package/dist/esm/store/locks/message.lock.js +21 -0
- package/dist/esm/store/locks/participants.lock.js +20 -0
- package/dist/esm/store/locks/privacy-token.lock.js +18 -0
- package/dist/esm/store/locks/retry.lock.js +29 -0
- package/dist/esm/store/locks/sender-key.lock.js +52 -0
- package/dist/esm/store/locks/signal.lock.js +63 -0
- package/dist/esm/store/locks/thread.lock.js +21 -0
- package/dist/esm/store/noop.store.js +1 -1
- package/dist/esm/store/providers/memory/appstate.store.js +22 -24
- package/dist/esm/store/providers/memory/device-list.store.js +10 -5
- package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
- package/dist/esm/store/providers/memory/retry.store.js +77 -2
- package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
- package/dist/esm/store/providers/memory/signal.store.js +36 -19
- package/dist/esm/transport/WaComms.js +3 -1
- package/dist/esm/transport/WaWebSocket.js +0 -6
- package/dist/esm/transport/binary/constants.js +0 -30
- package/dist/esm/transport/binary/decoder.js +4 -4
- package/dist/esm/transport/binary/encoder.js +8 -15
- package/dist/esm/transport/binary/index.js +0 -1
- package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -19
- package/dist/esm/transport/node/builders/business.js +129 -0
- package/dist/esm/transport/node/builders/global.js +370 -0
- package/dist/esm/transport/node/builders/index.js +5 -2
- package/dist/esm/transport/node/builders/message.js +63 -239
- package/dist/esm/transport/node/builders/pairing.js +0 -24
- package/dist/esm/transport/node/builders/privacy-token.js +41 -0
- package/dist/esm/transport/node/builders/privacy.js +48 -0
- package/dist/esm/transport/node/builders/profile.js +70 -0
- package/dist/esm/transport/node/builders/retry.js +10 -22
- package/dist/esm/transport/node/builders/usync.js +6 -2
- package/dist/esm/transport/node/helpers.js +19 -1
- package/dist/esm/transport/node/usync.js +3 -33
- package/dist/esm/transport/node/xml.js +35 -14
- package/dist/esm/transport/noise/WaClientPayload.js +10 -10
- package/dist/esm/transport/noise/WaNoiseCert.js +3 -3
- package/dist/esm/transport/noise/WaNoiseSession.js +64 -23
- package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/esm/transport/stream/parse.js +8 -4
- package/dist/esm/util/bytes.js +22 -18
- package/dist/esm/util/index.js +5 -0
- package/dist/esm/util/primitives.js +3 -2
- package/dist/index.js +7 -1
- package/dist/infra/perf/BackgroundQueue.js +482 -0
- package/dist/infra/perf/BoundedTaskQueue.js +3 -1
- package/dist/infra/perf/PromiseDedup.js +24 -0
- package/dist/infra/perf/SharedExclusiveGate.js +113 -0
- package/dist/infra/perf/StoreLock.js +81 -0
- package/dist/media/WaMediaCrypto.js +94 -12
- package/dist/media/WaMediaTransferClient.js +39 -47
- package/dist/media/constants.js +2 -1
- package/dist/message/WaMessageClient.js +26 -19
- package/dist/message/content.js +198 -9
- package/dist/message/icdc.js +81 -0
- package/dist/message/incoming.js +24 -12
- package/dist/message/phash.js +3 -1
- package/dist/message/reporting-token.js +14 -28
- package/dist/protocol/appstate.js +10 -41
- package/dist/protocol/browser.js +10 -18
- package/dist/protocol/constants.js +21 -2
- package/dist/protocol/defaults.js +6 -0
- package/dist/protocol/index.js +8 -5
- package/dist/protocol/jid.js +111 -36
- package/dist/protocol/message.js +62 -2
- package/dist/protocol/nodes.js +2 -0
- package/dist/protocol/notification.js +3 -1
- package/dist/protocol/privacy-token.js +20 -0
- package/dist/protocol/privacy.js +58 -0
- package/dist/protocol/stream.js +27 -2
- package/dist/retry/codec.js +220 -0
- package/dist/retry/constants.js +1 -1
- package/dist/retry/index.js +5 -5
- package/dist/retry/parse.js +51 -30
- package/dist/retry/replay.js +10 -6
- package/dist/retry/tracker.js +50 -12
- package/dist/signal/api/SignalDeviceSyncApi.js +48 -31
- package/dist/signal/api/SignalDigestSyncApi.js +13 -9
- package/dist/signal/api/SignalIdentitySyncApi.js +25 -10
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
- package/dist/signal/api/SignalRotateKeyApi.js +4 -2
- package/dist/signal/api/SignalSessionSyncApi.js +16 -7
- package/dist/signal/api/result-map.js +13 -0
- package/dist/signal/constants.js +1 -5
- package/dist/signal/crypto/WaAdvSignature.js +11 -5
- package/dist/signal/{store/sqlite.js → encoding.js} +79 -25
- package/dist/signal/group/SenderKeyCodec.js +4 -3
- package/dist/signal/group/SenderKeyManager.js +125 -106
- package/dist/signal/index.js +13 -1
- package/dist/signal/registration/keygen.js +6 -2
- package/dist/signal/registration/utils.js +1 -0
- package/dist/signal/session/SignalProtocol.js +150 -74
- package/dist/signal/session/resolver.js +135 -100
- package/dist/store/contracts/privacy-token.store.js +2 -0
- package/dist/store/createStore.js +101 -187
- package/dist/store/index.js +15 -33
- package/dist/store/locks/appstate.lock.js +29 -0
- package/dist/store/locks/auth.lock.js +18 -0
- package/dist/store/locks/contact.lock.js +23 -0
- package/dist/store/locks/device-list.lock.js +23 -0
- package/dist/store/locks/message.lock.js +24 -0
- package/dist/store/locks/participants.lock.js +23 -0
- package/dist/store/locks/privacy-token.lock.js +21 -0
- package/dist/store/locks/retry.lock.js +32 -0
- package/dist/store/locks/sender-key.lock.js +55 -0
- package/dist/store/locks/signal.lock.js +66 -0
- package/dist/store/locks/thread.lock.js +24 -0
- package/dist/store/noop.store.js +1 -1
- package/dist/store/providers/memory/appstate.store.js +22 -24
- package/dist/store/providers/memory/device-list.store.js +10 -5
- package/dist/store/providers/memory/privacy-token.store.js +47 -0
- package/dist/store/providers/memory/retry.store.js +77 -2
- package/dist/store/providers/memory/sender-key.store.js +6 -1
- package/dist/store/providers/memory/signal.store.js +36 -19
- package/dist/transport/WaComms.js +3 -1
- package/dist/transport/WaWebSocket.js +0 -6
- package/dist/transport/binary/constants.js +1 -31
- package/dist/transport/binary/decoder.js +4 -4
- package/dist/transport/binary/encoder.js +8 -15
- package/dist/transport/binary/index.js +0 -4
- package/dist/transport/node/WaNodeOrchestrator.js +24 -18
- package/dist/transport/node/builders/business.js +137 -0
- package/dist/transport/node/builders/global.js +375 -0
- package/dist/transport/node/builders/index.js +18 -9
- package/dist/transport/node/builders/message.js +64 -245
- package/dist/transport/node/builders/pairing.js +0 -26
- package/dist/transport/node/builders/privacy-token.js +46 -0
- package/dist/transport/node/builders/privacy.js +55 -0
- package/dist/transport/node/builders/profile.js +78 -0
- package/dist/transport/node/builders/retry.js +9 -21
- package/dist/transport/node/builders/usync.js +6 -2
- package/dist/transport/node/helpers.js +20 -1
- package/dist/transport/node/usync.js +2 -32
- package/dist/transport/node/xml.js +35 -14
- package/dist/transport/noise/WaClientPayload.js +13 -13
- package/dist/transport/noise/WaNoiseCert.js +2 -2
- package/dist/transport/noise/WaNoiseSession.js +64 -23
- package/dist/transport/noise/WaNoiseSocket.js +8 -4
- package/dist/transport/stream/parse.js +7 -3
- package/dist/types/appstate/encoding.d.ts +7 -0
- package/dist/types/appstate/index.d.ts +3 -3
- package/dist/types/appstate/utils.d.ts +0 -2
- package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
- package/dist/types/auth/index.d.ts +0 -2
- package/dist/types/auth/types.d.ts +1 -0
- package/dist/types/client/WaClient.d.ts +27 -12
- package/dist/types/client/WaClientFactory.d.ts +12 -4
- package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
- package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -1
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +14 -0
- package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
- package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
- package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
- package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
- package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
- package/dist/types/client/events/devices.d.ts +20 -0
- package/dist/types/client/events/identity.d.ts +9 -0
- package/dist/types/client/events/privacy-token.d.ts +7 -0
- package/dist/types/client/history-sync.d.ts +9 -6
- package/dist/types/client/incoming.d.ts +3 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/mailbox.d.ts +3 -5
- package/dist/types/client/messages.d.ts +1 -2
- package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
- package/dist/types/client/tokens/cs-token.d.ts +10 -0
- package/dist/types/client/tokens/tc-token.d.ts +5 -0
- package/dist/types/client/types.d.ts +51 -3
- package/dist/types/crypto/core/index.d.ts +2 -2
- package/dist/types/crypto/core/nonce.d.ts +2 -0
- package/dist/types/crypto/core/primitives.d.ts +0 -1
- package/dist/types/crypto/core/random.d.ts +1 -0
- package/dist/types/crypto/index.d.ts +1 -0
- package/dist/types/crypto/math/constants.d.ts +4 -2
- package/dist/types/crypto/math/fe.d.ts +30 -0
- package/dist/types/crypto/math/mod.d.ts +0 -2
- package/dist/types/crypto/math/types.d.ts +11 -4
- package/dist/types/index.d.ts +5 -3
- package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
- package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
- package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
- package/dist/types/infra/perf/StoreLock.d.ts +10 -0
- package/dist/types/media/WaMediaCrypto.d.ts +3 -2
- package/dist/types/media/WaMediaTransferClient.d.ts +3 -12
- package/dist/types/media/constants.d.ts +1 -1
- package/dist/types/media/index.d.ts +1 -1
- package/dist/types/media/types.d.ts +10 -2
- package/dist/types/message/content.d.ts +8 -0
- package/dist/types/message/icdc.d.ts +13 -0
- package/dist/types/message/reporting-token.d.ts +0 -1
- package/dist/types/message/types.d.ts +45 -6
- package/dist/types/protocol/appstate.d.ts +0 -11
- package/dist/types/protocol/constants.d.ts +7 -3
- package/dist/types/protocol/defaults.d.ts +6 -0
- package/dist/types/protocol/index.d.ts +1 -2
- package/dist/types/protocol/jid.d.ts +19 -2
- package/dist/types/protocol/message.d.ts +60 -0
- package/dist/types/protocol/nodes.d.ts +2 -0
- package/dist/types/protocol/notification.d.ts +2 -0
- package/dist/types/protocol/privacy-token.d.ts +17 -0
- package/dist/types/protocol/privacy.d.ts +75 -0
- package/dist/types/protocol/stream.d.ts +30 -0
- package/dist/types/retry/codec.d.ts +3 -0
- package/dist/types/retry/index.d.ts +3 -3
- package/dist/types/retry/parse.d.ts +5 -2
- package/dist/types/retry/tracker.d.ts +1 -0
- package/dist/types/retry/types.d.ts +6 -1
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
- package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
- package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
- package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
- package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
- package/dist/types/signal/api/result-map.d.ts +1 -0
- package/dist/types/signal/constants.d.ts +0 -3
- package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
- package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
- package/dist/types/signal/index.d.ts +2 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +10 -4
- package/dist/types/signal/session/resolver.d.ts +7 -2
- package/dist/types/store/contracts/appstate.store.d.ts +1 -1
- package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
- package/dist/types/store/contracts/retry.store.d.ts +7 -0
- package/dist/types/store/contracts/signal.store.d.ts +7 -0
- package/dist/types/store/createStore.d.ts +1 -1
- package/dist/types/store/index.d.ts +5 -13
- package/dist/types/store/locks/appstate.lock.d.ts +3 -0
- package/dist/types/store/locks/auth.lock.d.ts +3 -0
- package/dist/types/store/locks/contact.lock.d.ts +3 -0
- package/dist/types/store/locks/device-list.lock.d.ts +2 -0
- package/dist/types/store/locks/message.lock.d.ts +3 -0
- package/dist/types/store/locks/participants.lock.d.ts +2 -0
- package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
- package/dist/types/store/locks/retry.lock.d.ts +2 -0
- package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
- package/dist/types/store/locks/signal.lock.d.ts +3 -0
- package/dist/types/store/locks/thread.lock.d.ts +3 -0
- package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
- package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
- package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
- package/dist/types/store/providers/memory/signal.store.d.ts +2 -1
- package/dist/types/store/types.d.ts +49 -61
- package/dist/types/transport/WaWebSocket.d.ts +0 -1
- package/dist/types/transport/binary/constants.d.ts +0 -30
- package/dist/types/transport/binary/index.d.ts +0 -1
- package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
- package/dist/types/transport/node/builders/business.d.ts +29 -0
- package/dist/types/transport/node/builders/global.d.ts +102 -0
- package/dist/types/transport/node/builders/index.d.ts +5 -2
- package/dist/types/transport/node/builders/message.d.ts +8 -7
- package/dist/types/transport/node/builders/pairing.d.ts +0 -2
- package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
- package/dist/types/transport/node/builders/privacy.d.ts +7 -0
- package/dist/types/transport/node/builders/profile.d.ts +8 -0
- package/dist/types/transport/node/builders/retry.d.ts +0 -1
- package/dist/types/transport/node/helpers.d.ts +5 -0
- package/dist/types/transport/noise/WaNoiseSession.d.ts +3 -2
- package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
- package/dist/types/util/bytes.d.ts +1 -1
- package/dist/types/util/index.d.ts +5 -0
- package/dist/types/util/primitives.d.ts +0 -1
- package/dist/util/bytes.js +22 -18
- package/dist/util/index.js +23 -0
- package/dist/util/primitives.js +2 -2
- package/package.json +29 -7
- package/proto/index.js +1 -1
- package/dist/crypto/core/constants.js +0 -4
- package/dist/esm/crypto/core/constants.js +0 -1
- package/dist/esm/retry/outbound.js +0 -82
- package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
- package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
- package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
- package/dist/esm/store/providers/sqlite/connection.js +0 -245
- package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
- package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
- package/dist/esm/store/providers/sqlite/message.store.js +0 -132
- package/dist/esm/store/providers/sqlite/migrations.js +0 -347
- package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
- package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
- package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
- package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
- package/dist/esm/store/providers/sqlite/table-names.js +0 -107
- package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
- package/dist/retry/outbound.js +0 -87
- package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
- package/dist/store/providers/sqlite/appstate.store.js +0 -254
- package/dist/store/providers/sqlite/auth.store.js +0 -180
- package/dist/store/providers/sqlite/connection.js +0 -281
- package/dist/store/providers/sqlite/contact.store.js +0 -78
- package/dist/store/providers/sqlite/device-list.store.js +0 -131
- package/dist/store/providers/sqlite/message.store.js +0 -136
- package/dist/store/providers/sqlite/migrations.js +0 -350
- package/dist/store/providers/sqlite/participants.store.js +0 -81
- package/dist/store/providers/sqlite/retry.store.js +0 -145
- package/dist/store/providers/sqlite/sender-key.store.js +0 -202
- package/dist/store/providers/sqlite/signal.store.js +0 -439
- package/dist/store/providers/sqlite/table-names.js +0 -113
- package/dist/store/providers/sqlite/thread.store.js +0 -89
- package/dist/types/appstate/store/sqlite.d.ts +0 -7
- package/dist/types/crypto/core/constants.d.ts +0 -1
- package/dist/types/retry/outbound.d.ts +0 -4
- package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
- package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
- package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
- package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
- package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
- package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
- package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
- package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
- package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { parseSignalAddressFromJid } from '../../protocol/jid.js';
|
|
2
|
+
import { findNodeChild, getNodeChildrenByTag } from '../../transport/node/helpers.js';
|
|
3
|
+
export const DEVICE_NOTIFICATION_ACTIONS = Object.freeze({
|
|
4
|
+
ADD: 'add',
|
|
5
|
+
REMOVE: 'remove',
|
|
6
|
+
UPDATE: 'update'
|
|
7
|
+
});
|
|
8
|
+
export function parseDeviceNotification(node) {
|
|
9
|
+
const stanzaId = node.attrs.id;
|
|
10
|
+
const fromJid = node.attrs.from;
|
|
11
|
+
if (!stanzaId || !fromJid) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
let action;
|
|
15
|
+
let actionNode;
|
|
16
|
+
if (findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.REMOVE)) {
|
|
17
|
+
action = DEVICE_NOTIFICATION_ACTIONS.REMOVE;
|
|
18
|
+
actionNode = findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.REMOVE);
|
|
19
|
+
}
|
|
20
|
+
else if (findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.ADD)) {
|
|
21
|
+
action = DEVICE_NOTIFICATION_ACTIONS.ADD;
|
|
22
|
+
actionNode = findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.ADD);
|
|
23
|
+
}
|
|
24
|
+
else if (findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.UPDATE)) {
|
|
25
|
+
action = DEVICE_NOTIFICATION_ACTIONS.UPDATE;
|
|
26
|
+
actionNode = findNodeChild(node, DEVICE_NOTIFICATION_ACTIONS.UPDATE);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const devices = [];
|
|
32
|
+
if (action !== DEVICE_NOTIFICATION_ACTIONS.UPDATE && actionNode) {
|
|
33
|
+
const deviceNodes = getNodeChildrenByTag(actionNode, 'device');
|
|
34
|
+
for (let index = 0; index < deviceNodes.length; index += 1) {
|
|
35
|
+
const deviceNode = deviceNodes[index];
|
|
36
|
+
const jidAttr = deviceNode.attrs.jid;
|
|
37
|
+
if (!jidAttr) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let deviceId;
|
|
41
|
+
try {
|
|
42
|
+
deviceId = parseSignalAddressFromJid(jidAttr).device;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const keyIndexAttr = deviceNode.attrs['key-index'];
|
|
48
|
+
const parsedKeyIndex = keyIndexAttr === undefined ? null : Number.parseInt(keyIndexAttr, 10);
|
|
49
|
+
const keyIndex = parsedKeyIndex !== null &&
|
|
50
|
+
Number.isSafeInteger(parsedKeyIndex) &&
|
|
51
|
+
parsedKeyIndex >= 0
|
|
52
|
+
? parsedKeyIndex
|
|
53
|
+
: null;
|
|
54
|
+
devices[devices.length] = {
|
|
55
|
+
deviceId,
|
|
56
|
+
keyIndex
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
action,
|
|
62
|
+
stanzaId,
|
|
63
|
+
fromJid,
|
|
64
|
+
lid: node.attrs.lid,
|
|
65
|
+
hash: action === DEVICE_NOTIFICATION_ACTIONS.UPDATE ? actionNode?.attrs.hash : undefined,
|
|
66
|
+
devices
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createUnhandledIncomingNodeEvent } from '../incoming.js';
|
|
1
2
|
import { WA_GROUP_NOTIFICATION_TAGS, WA_NOTIFICATION_TYPES } from '../../protocol/constants.js';
|
|
2
3
|
import { WA_NODE_TAGS } from '../../protocol/nodes.js';
|
|
3
4
|
import { findNodeChild, getNodeChildren, getNodeChildrenByTag } from '../../transport/node/helpers.js';
|
|
@@ -99,15 +100,6 @@ function createBaseGroupEvent(notificationNode, actionNode) {
|
|
|
99
100
|
timestampSeconds: parseOptionalInt(notificationNode.attrs.t)
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
|
-
function createUnhandledStanzaEvent(notificationNode, reason) {
|
|
103
|
-
return {
|
|
104
|
-
rawNode: notificationNode,
|
|
105
|
-
stanzaId: notificationNode.attrs.id,
|
|
106
|
-
chatJid: notificationNode.attrs.from,
|
|
107
|
-
stanzaType: notificationNode.attrs.type,
|
|
108
|
-
reason
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
103
|
function parseCreateGroupAction(notificationNode, actionNode) {
|
|
112
104
|
const groupNode = findNodeChild(actionNode, WA_NODE_TAGS.GROUP);
|
|
113
105
|
if (!groupNode) {
|
|
@@ -413,13 +405,13 @@ export function parseGroupNotificationEvents(notificationNode) {
|
|
|
413
405
|
try {
|
|
414
406
|
const parsedEvent = parseGroupActionNode(notificationNode, actionNode);
|
|
415
407
|
if (!parsedEvent) {
|
|
416
|
-
unhandled.push(
|
|
408
|
+
unhandled.push(createUnhandledIncomingNodeEvent(notificationNode, `notification.${WA_NOTIFICATION_TYPES.GROUP}.${actionNode.tag}.not_supported`));
|
|
417
409
|
continue;
|
|
418
410
|
}
|
|
419
411
|
events.push(parsedEvent);
|
|
420
412
|
}
|
|
421
413
|
catch {
|
|
422
|
-
unhandled.push(
|
|
414
|
+
unhandled.push(createUnhandledIncomingNodeEvent(notificationNode, `notification.${WA_NOTIFICATION_TYPES.GROUP}.${actionNode.tag}.parse_failed`));
|
|
423
415
|
}
|
|
424
416
|
}
|
|
425
417
|
return {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getFirstNodeChild } from '../../transport/node/helpers.js';
|
|
2
|
+
export function parseIdentityChangeNotification(node) {
|
|
3
|
+
const child = getFirstNodeChild(node);
|
|
4
|
+
if (!child || child.tag !== 'identity') {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const fromJid = node.attrs.from;
|
|
8
|
+
const stanzaId = node.attrs.id;
|
|
9
|
+
if (!fromJid || !stanzaId) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
fromJid,
|
|
14
|
+
stanzaId,
|
|
15
|
+
displayName: node.attrs.display_name,
|
|
16
|
+
lid: node.attrs.lid,
|
|
17
|
+
offline: node.attrs.offline
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { WA_PRIVACY_TOKEN_TAGS } from '../../protocol/privacy-token.js';
|
|
2
|
+
import { findNodeChild, getNodeChildren } from '../../transport/node/helpers.js';
|
|
3
|
+
import { toBytesView } from '../../util/bytes.js';
|
|
4
|
+
import { asNumber } from '../../util/coercion.js';
|
|
5
|
+
export function parsePrivacyTokenNotification(node) {
|
|
6
|
+
const tokensNode = findNodeChild(node, WA_PRIVACY_TOKEN_TAGS.TOKENS);
|
|
7
|
+
if (!tokensNode) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const children = getNodeChildren(tokensNode);
|
|
11
|
+
const result = [];
|
|
12
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
13
|
+
const child = children[i];
|
|
14
|
+
if (child.tag !== WA_PRIVACY_TOKEN_TAGS.TOKEN) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const type = child.attrs.type;
|
|
18
|
+
if (!type) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const rawTimestamp = child.attrs.t;
|
|
22
|
+
if (!rawTimestamp) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const content = child.content;
|
|
26
|
+
if (!(content instanceof Uint8Array)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
result[result.length] = {
|
|
30
|
+
type,
|
|
31
|
+
tokenBytes: toBytesView(content),
|
|
32
|
+
timestampS: asNumber(Number(rawTimestamp), 'privacy_token.t')
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -10,6 +10,7 @@ const HANDLED_SYNC_TYPES = new Set([
|
|
|
10
10
|
proto.Message.HistorySyncType.FULL,
|
|
11
11
|
proto.Message.HistorySyncType.PUSH_NAME
|
|
12
12
|
]);
|
|
13
|
+
const HISTORY_SYNC_MAX_PENDING_WRITES = 1024;
|
|
13
14
|
export async function processHistorySyncNotification(deps, notification) {
|
|
14
15
|
const syncType = notification.syncType;
|
|
15
16
|
if (syncType === null || syncType === undefined || !HANDLED_SYNC_TYPES.has(syncType)) {
|
|
@@ -27,19 +28,20 @@ export async function processHistorySyncNotification(deps, notification) {
|
|
|
27
28
|
pushnames: historySync.pushnames.length
|
|
28
29
|
});
|
|
29
30
|
const nowMs = Date.now();
|
|
30
|
-
const
|
|
31
|
+
const pendingWrites = [];
|
|
31
32
|
for (const pn of historySync.pushnames) {
|
|
32
33
|
if (!pn.id) {
|
|
33
34
|
continue;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
pendingWrites[pendingWrites.length] = deps.writeBehind.persistContactAsync({
|
|
36
37
|
jid: pn.id,
|
|
37
38
|
pushName: pn.pushname ?? undefined,
|
|
38
39
|
lastUpdatedMs: nowMs
|
|
39
40
|
});
|
|
41
|
+
if (pendingWrites.length >= HISTORY_SYNC_MAX_PENDING_WRITES) {
|
|
42
|
+
await flushPendingWrites(pendingWrites);
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
|
-
const threads = [];
|
|
42
|
-
const messages = [];
|
|
43
45
|
let messagesCount = 0;
|
|
44
46
|
for (const conversation of historySync.conversations) {
|
|
45
47
|
const threadJid = conversation.id;
|
|
@@ -47,7 +49,7 @@ export async function processHistorySyncNotification(deps, notification) {
|
|
|
47
49
|
deps.logger.debug('skipping history sync conversation without thread jid');
|
|
48
50
|
continue;
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
pendingWrites[pendingWrites.length] = deps.writeBehind.persistThreadAsync({
|
|
51
53
|
jid: threadJid,
|
|
52
54
|
name: conversation.name ?? undefined,
|
|
53
55
|
unreadCount: conversation.unreadCount ?? undefined,
|
|
@@ -57,13 +59,16 @@ export async function processHistorySyncNotification(deps, notification) {
|
|
|
57
59
|
markedAsUnread: conversation.markedAsUnread ?? undefined,
|
|
58
60
|
ephemeralExpiration: conversation.ephemeralExpiration ?? undefined
|
|
59
61
|
});
|
|
62
|
+
if (pendingWrites.length >= HISTORY_SYNC_MAX_PENDING_WRITES) {
|
|
63
|
+
await flushPendingWrites(pendingWrites);
|
|
64
|
+
}
|
|
60
65
|
for (const histMsg of conversation.messages ?? []) {
|
|
61
66
|
const webMsg = histMsg.message;
|
|
62
67
|
if (!webMsg?.key?.id) {
|
|
63
68
|
continue;
|
|
64
69
|
}
|
|
65
70
|
const timestampMs = longToNumber(webMsg.messageTimestamp) * 1000;
|
|
66
|
-
|
|
71
|
+
pendingWrites[pendingWrites.length] = deps.writeBehind.persistMessageAsync({
|
|
67
72
|
id: webMsg.key.id,
|
|
68
73
|
threadJid,
|
|
69
74
|
senderJid: webMsg.key.participant ?? undefined,
|
|
@@ -73,12 +78,35 @@ export async function processHistorySyncNotification(deps, notification) {
|
|
|
73
78
|
? proto.Message.encode(webMsg.message).finish()
|
|
74
79
|
: undefined
|
|
75
80
|
});
|
|
81
|
+
if (pendingWrites.length >= HISTORY_SYNC_MAX_PENDING_WRITES) {
|
|
82
|
+
await flushPendingWrites(pendingWrites);
|
|
83
|
+
}
|
|
76
84
|
messagesCount += 1;
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
if (deps.onPrivacyTokens) {
|
|
88
|
+
const tokenConversations = [];
|
|
89
|
+
for (const conversation of historySync.conversations) {
|
|
90
|
+
if (!conversation.id)
|
|
91
|
+
continue;
|
|
92
|
+
if (conversation.tcToken ||
|
|
93
|
+
conversation.tcTokenTimestamp ||
|
|
94
|
+
conversation.tcTokenSenderTimestamp) {
|
|
95
|
+
tokenConversations[tokenConversations.length] = {
|
|
96
|
+
jid: conversation.id,
|
|
97
|
+
tcToken: conversation.tcToken,
|
|
98
|
+
tcTokenTimestamp: longToNumber(conversation.tcTokenTimestamp) || undefined,
|
|
99
|
+
tcTokenSenderTimestamp: longToNumber(conversation.tcTokenSenderTimestamp) || undefined
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (tokenConversations.length > 0) {
|
|
104
|
+
pendingWrites[pendingWrites.length] = deps.onPrivacyTokens(tokenConversations);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (deps.onNctSalt && historySync.nctSalt) {
|
|
108
|
+
pendingWrites[pendingWrites.length] = deps.onNctSalt(historySync.nctSalt);
|
|
109
|
+
}
|
|
82
110
|
const event = {
|
|
83
111
|
syncType,
|
|
84
112
|
messagesCount,
|
|
@@ -87,8 +115,21 @@ export async function processHistorySyncNotification(deps, notification) {
|
|
|
87
115
|
chunkOrder: historySync.chunkOrder ?? undefined,
|
|
88
116
|
progress: historySync.progress ?? undefined
|
|
89
117
|
};
|
|
118
|
+
await flushPendingWrites(pendingWrites);
|
|
90
119
|
deps.emitEvent('history_sync_chunk', event);
|
|
91
120
|
}
|
|
121
|
+
async function flushPendingWrites(pendingWrites) {
|
|
122
|
+
if (pendingWrites.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const pendingCount = pendingWrites.length;
|
|
126
|
+
const batch = new Array(pendingCount);
|
|
127
|
+
for (let index = 0; index < pendingCount; index += 1) {
|
|
128
|
+
batch[index] = pendingWrites[index];
|
|
129
|
+
}
|
|
130
|
+
pendingWrites.length = 0;
|
|
131
|
+
await Promise.all(batch);
|
|
132
|
+
}
|
|
92
133
|
async function downloadHistorySyncBlob(deps, notification) {
|
|
93
134
|
if (notification.initialHistBootstrapInlinePayload) {
|
|
94
135
|
return decodeProtoBytes(notification.initialHistBootstrapInlinePayload, 'initialHistBootstrapInlinePayload');
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { parseGroupNotificationEvents } from './events/group.js';
|
|
2
|
-
import { WA_NODE_TAGS, WA_NOTIFICATION_TYPES } from '../protocol/constants.js';
|
|
3
|
-
import {
|
|
4
|
-
import { buildNotificationAckNode } from '../transport/node/builders/pairing.js';
|
|
2
|
+
import { WA_DISCONNECT_REASONS, WA_NODE_TAGS, WA_NOTIFICATION_TYPES } from '../protocol/constants.js';
|
|
3
|
+
import { buildAckNode } from '../transport/node/builders/global.js';
|
|
5
4
|
import { getFirstNodeChild, getNodeChildrenNonEmptyAttrValuesByTag } from '../transport/node/helpers.js';
|
|
6
5
|
import { parseOptionalInt, toError } from '../util/primitives.js';
|
|
6
|
+
const FAILURE_REASON_TO_DISCONNECT = {
|
|
7
|
+
401: WA_DISCONNECT_REASONS.FAILURE_NOT_AUTHORIZED,
|
|
8
|
+
403: WA_DISCONNECT_REASONS.FAILURE_LOCKED,
|
|
9
|
+
406: WA_DISCONNECT_REASONS.FAILURE_BANNED,
|
|
10
|
+
405: WA_DISCONNECT_REASONS.FAILURE_CLIENT_TOO_OLD,
|
|
11
|
+
409: WA_DISCONNECT_REASONS.FAILURE_BAD_USER_AGENT,
|
|
12
|
+
503: WA_DISCONNECT_REASONS.FAILURE_SERVICE_UNAVAILABLE
|
|
13
|
+
};
|
|
7
14
|
const LOGOUT_FAILURE_REASONS = new Set([401, 403, 406]);
|
|
8
15
|
const DISCONNECT_FAILURE_REASONS = new Set([405, 409, 503]);
|
|
9
16
|
const CORE_NOTIFICATION_TYPES = new Set([
|
|
@@ -30,6 +37,8 @@ const OUT_OF_SCOPE_NOTIFICATION_TYPES = new Set([
|
|
|
30
37
|
'waffle',
|
|
31
38
|
'hosted'
|
|
32
39
|
]);
|
|
40
|
+
const NOTIFICATION_TYPES_WITH_PARTICIPANT_ACK = new Set(['mediaretry', 'psa']);
|
|
41
|
+
const NOTIFICATION_TYPES_WITHOUT_TYPE_ACK = new Set(['encrypt', 'devices']);
|
|
33
42
|
export function createIncomingBaseEvent(node) {
|
|
34
43
|
return {
|
|
35
44
|
rawNode: node,
|
|
@@ -63,7 +72,9 @@ function classifyNotificationType(notificationType) {
|
|
|
63
72
|
}
|
|
64
73
|
async function applyFailureAction(options, reason, clearStoredCredentials) {
|
|
65
74
|
try {
|
|
66
|
-
|
|
75
|
+
options.stopComms();
|
|
76
|
+
const disconnectReason = FAILURE_REASON_TO_DISCONNECT[reason] ?? WA_DISCONNECT_REASONS.STREAM_ERROR_OTHER;
|
|
77
|
+
await options.disconnect(disconnectReason, clearStoredCredentials, reason);
|
|
67
78
|
if (clearStoredCredentials) {
|
|
68
79
|
await options.clearStoredCredentials();
|
|
69
80
|
}
|
|
@@ -108,11 +119,19 @@ export function createIncomingReceiptHandler(options) {
|
|
|
108
119
|
await options.handleIncomingRetryReceipt(node);
|
|
109
120
|
}
|
|
110
121
|
else {
|
|
111
|
-
await sendSafeAck(options.logger, options.sendNode,
|
|
122
|
+
await sendSafeAck(options.logger, options.sendNode, buildAckNode({
|
|
123
|
+
kind: 'receipt',
|
|
124
|
+
node,
|
|
125
|
+
retryType: true
|
|
126
|
+
}));
|
|
112
127
|
}
|
|
113
128
|
return true;
|
|
114
129
|
}
|
|
115
|
-
await sendSafeAck(options.logger, options.sendNode,
|
|
130
|
+
await sendSafeAck(options.logger, options.sendNode, buildAckNode({
|
|
131
|
+
kind: 'receipt',
|
|
132
|
+
node,
|
|
133
|
+
includeParticipant: receiptType !== 'server-error'
|
|
134
|
+
}));
|
|
116
135
|
return true;
|
|
117
136
|
};
|
|
118
137
|
}
|
|
@@ -138,6 +157,8 @@ export function createIncomingFailureHandler(options) {
|
|
|
138
157
|
export function createIncomingNotificationHandler(options) {
|
|
139
158
|
return async (node) => {
|
|
140
159
|
const notificationType = node.attrs.type ?? '';
|
|
160
|
+
const includeParticipantInAck = NOTIFICATION_TYPES_WITH_PARTICIPANT_ACK.has(notificationType);
|
|
161
|
+
const includeTypeInAck = !NOTIFICATION_TYPES_WITHOUT_TYPE_ACK.has(notificationType);
|
|
141
162
|
const classification = classifyNotificationType(notificationType);
|
|
142
163
|
const firstChildTag = getFirstNodeChild(node)?.tag;
|
|
143
164
|
const baseEvent = createIncomingBaseEvent(node);
|
|
@@ -172,7 +193,12 @@ export function createIncomingNotificationHandler(options) {
|
|
|
172
193
|
reason: `notification.${notificationType || 'unknown'}.not_supported`
|
|
173
194
|
});
|
|
174
195
|
}
|
|
175
|
-
await sendSafeAck(options.logger, options.sendNode,
|
|
196
|
+
await sendSafeAck(options.logger, options.sendNode, buildAckNode({
|
|
197
|
+
kind: 'notification',
|
|
198
|
+
node,
|
|
199
|
+
includeParticipant: includeParticipantInAck,
|
|
200
|
+
includeType: includeTypeInAck
|
|
201
|
+
}));
|
|
176
202
|
if (notificationType === 'server_sync' && serverSyncCollections.length > 0) {
|
|
177
203
|
const collectionsCsv = serverSyncCollections.join(',');
|
|
178
204
|
if (!options.syncAppState) {
|
|
@@ -210,7 +236,11 @@ export function createIncomingGroupNotificationHandler(options) {
|
|
|
210
236
|
reason: `notification.${WA_NOTIFICATION_TYPES.GROUP}.empty`
|
|
211
237
|
});
|
|
212
238
|
}
|
|
213
|
-
await sendSafeAck(options.logger, options.sendNode,
|
|
239
|
+
await sendSafeAck(options.logger, options.sendNode, buildAckNode({
|
|
240
|
+
kind: 'notification',
|
|
241
|
+
node,
|
|
242
|
+
includeParticipant: true
|
|
243
|
+
}));
|
|
214
244
|
return true;
|
|
215
245
|
};
|
|
216
246
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { proto } from '../proto.js';
|
|
2
2
|
import { toError } from '../util/primitives.js';
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
3
|
+
function persistContacts(writeBehind, event, nowMs) {
|
|
4
|
+
const senderJid = event.senderJid;
|
|
5
|
+
const participantJid = event.rawNode.attrs.participant;
|
|
6
|
+
if (!senderJid && !participantJid) {
|
|
6
7
|
return;
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
if (senderJid) {
|
|
10
|
+
writeBehind.persistContact({ jid: senderJid, lastUpdatedMs: nowMs });
|
|
11
|
+
}
|
|
12
|
+
if (participantJid && participantJid !== senderJid) {
|
|
13
|
+
writeBehind.persistContact({ jid: participantJid, lastUpdatedMs: nowMs });
|
|
14
|
+
}
|
|
10
15
|
}
|
|
11
|
-
export
|
|
12
|
-
const { logger,
|
|
16
|
+
export function persistIncomingMailboxEntities(options) {
|
|
17
|
+
const { logger, writeBehind, event } = options;
|
|
13
18
|
const { stanzaId, chatJid } = event;
|
|
14
19
|
if (!stanzaId || !chatJid) {
|
|
15
20
|
return;
|
|
@@ -19,22 +24,18 @@ export async function persistIncomingMailboxEntities(options) {
|
|
|
19
24
|
const messageBytes = event.message
|
|
20
25
|
? proto.Message.encode(event.message).finish()
|
|
21
26
|
: undefined;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
messageBytes
|
|
35
|
-
}),
|
|
36
|
-
persistContacts(contactStore, event, nowMs)
|
|
37
|
-
]);
|
|
27
|
+
writeBehind.persistMessage({
|
|
28
|
+
id: stanzaId,
|
|
29
|
+
threadJid: chatJid,
|
|
30
|
+
senderJid: event.senderJid,
|
|
31
|
+
participantJid: event.rawNode.attrs.participant,
|
|
32
|
+
fromMe: false,
|
|
33
|
+
timestampMs: event.timestampSeconds === undefined ? undefined : event.timestampSeconds * 1000,
|
|
34
|
+
encType: event.encryptionType,
|
|
35
|
+
plaintext: event.plaintext,
|
|
36
|
+
messageBytes
|
|
37
|
+
});
|
|
38
|
+
persistContacts(writeBehind, event, nowMs);
|
|
38
39
|
}
|
|
39
40
|
catch (error) {
|
|
40
41
|
logger.warn('failed to persist incoming mailbox entities', {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
1
2
|
import { parseMediaConnResponse } from '../media/conn.js';
|
|
2
3
|
import { MEDIA_CONN_CACHE_GRACE_MS, MEDIA_UPLOAD_PATHS } from '../media/constants.js';
|
|
3
4
|
import { WaMediaCrypto } from '../media/WaMediaCrypto.js';
|
|
4
5
|
import { isSendMediaMessage } from '../message/content.js';
|
|
5
6
|
import { WA_DEFAULTS } from '../protocol/constants.js';
|
|
6
7
|
import { buildMediaConnIq } from '../transport/node/builders/media.js';
|
|
7
|
-
import { bytesToBase64UrlSafe } from '../util/bytes.js';
|
|
8
|
-
import { TEXT_DECODER, toBytesView } from '../util/bytes.js';
|
|
8
|
+
import { bytesToBase64UrlSafe, TEXT_DECODER, toBytesView } from '../util/bytes.js';
|
|
9
9
|
import { toError } from '../util/primitives.js';
|
|
10
10
|
export async function buildMediaMessageContent(options, content) {
|
|
11
11
|
if (typeof content === 'string') {
|
|
@@ -31,15 +31,29 @@ export async function getMediaConn(options, forceRefresh = false) {
|
|
|
31
31
|
options.setMediaConnCache(mediaConn);
|
|
32
32
|
return mediaConn;
|
|
33
33
|
}
|
|
34
|
+
function resolveUploadType(content) {
|
|
35
|
+
if (content.type === 'video' && content.gifPlayback)
|
|
36
|
+
return 'gif';
|
|
37
|
+
if (content.type === 'audio' && content.ptt)
|
|
38
|
+
return 'ptt';
|
|
39
|
+
return content.type;
|
|
40
|
+
}
|
|
41
|
+
function isReadableStream(value) {
|
|
42
|
+
return (!!value &&
|
|
43
|
+
typeof value === 'object' &&
|
|
44
|
+
'pipe' in value &&
|
|
45
|
+
typeof value.pipe === 'function');
|
|
46
|
+
}
|
|
34
47
|
async function buildMediaMessage(options, content) {
|
|
35
|
-
const
|
|
36
|
-
|
|
48
|
+
const uploaded = isReadableStream(content.media)
|
|
49
|
+
? await uploadMediaStream(options, content, content.media)
|
|
50
|
+
: await uploadMediaBytes(options, content, toBytesView(content.media));
|
|
37
51
|
const mediaKeyTimestamp = Math.floor(Date.now() / 1000);
|
|
38
52
|
const common = {
|
|
39
53
|
url: uploaded.url,
|
|
40
54
|
mimetype: content.mimetype,
|
|
41
55
|
fileSha256: uploaded.fileSha256,
|
|
42
|
-
fileLength:
|
|
56
|
+
fileLength: uploaded.fileLength,
|
|
43
57
|
mediaKey: uploaded.mediaKey,
|
|
44
58
|
fileEncSha256: uploaded.fileEncSha256,
|
|
45
59
|
directPath: uploaded.directPath,
|
|
@@ -67,6 +81,15 @@ async function buildMediaMessage(options, content) {
|
|
|
67
81
|
metadataUrl: uploaded.metadataUrl
|
|
68
82
|
}
|
|
69
83
|
};
|
|
84
|
+
case 'ptv':
|
|
85
|
+
return {
|
|
86
|
+
ptvMessage: {
|
|
87
|
+
...common,
|
|
88
|
+
seconds: content.seconds,
|
|
89
|
+
width: content.width,
|
|
90
|
+
height: content.height
|
|
91
|
+
}
|
|
92
|
+
};
|
|
70
93
|
case 'audio':
|
|
71
94
|
return {
|
|
72
95
|
audioMessage: {
|
|
@@ -93,24 +116,46 @@ async function buildMediaMessage(options, content) {
|
|
|
93
116
|
}
|
|
94
117
|
};
|
|
95
118
|
default:
|
|
96
|
-
throw new Error(`unsupported media type: ${content.type}`);
|
|
119
|
+
throw new Error(`unsupported media message type: ${String(content.type)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function buildUploadUrl(host, uploadType, auth, fileEncSha256) {
|
|
123
|
+
const hashToken = bytesToBase64UrlSafe(fileEncSha256);
|
|
124
|
+
const uploadPath = MEDIA_UPLOAD_PATHS[uploadType];
|
|
125
|
+
if (!uploadPath) {
|
|
126
|
+
throw new Error(`unknown media upload type: ${String(uploadType)}`);
|
|
97
127
|
}
|
|
128
|
+
return `https://${host}${uploadPath}/${hashToken}?auth=${encodeURIComponent(auth)}&token=${encodeURIComponent(hashToken)}`;
|
|
98
129
|
}
|
|
99
|
-
|
|
130
|
+
function parseUploadResponse(body, status) {
|
|
131
|
+
if (status < 200 || status >= 300) {
|
|
132
|
+
throw new Error(`media upload failed with status ${status}`);
|
|
133
|
+
}
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(TEXT_DECODER.decode(body));
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
throw new Error(`media upload returned invalid json: ${toError(error).message}`);
|
|
140
|
+
}
|
|
141
|
+
if (!parsed.url || !parsed.direct_path) {
|
|
142
|
+
throw new Error('media upload response missing url/direct_path');
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
url: parsed.url,
|
|
146
|
+
directPath: parsed.direct_path,
|
|
147
|
+
...(parsed.metadata_url ? { metadataUrl: parsed.metadata_url } : {})
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async function uploadMediaBytes(options, content, mediaBytes) {
|
|
151
|
+
const uploadType = resolveUploadType(content);
|
|
100
152
|
const mediaKey = await WaMediaCrypto.generateMediaKey();
|
|
101
|
-
const uploadType = content.type === 'video' && content.gifPlayback
|
|
102
|
-
? 'gif'
|
|
103
|
-
: content.type === 'audio' && content.ptt
|
|
104
|
-
? 'ptt'
|
|
105
|
-
: content.type;
|
|
106
153
|
const [encrypted, mediaConn] = await Promise.all([
|
|
107
154
|
WaMediaCrypto.encryptBytes(uploadType, mediaKey, mediaBytes),
|
|
108
155
|
getMediaConn(options)
|
|
109
156
|
]);
|
|
110
157
|
const selectedHost = mediaConn.hosts.find((host) => !host.isFallback)?.hostname ?? mediaConn.hosts[0].hostname;
|
|
111
|
-
const
|
|
112
|
-
const hashToken = bytesToBase64UrlSafe(encrypted.fileEncSha256);
|
|
113
|
-
const uploadUrl = `https://${selectedHost}${uploadPath}/${hashToken}?auth=${encodeURIComponent(mediaConn.auth)}&token=${encodeURIComponent(hashToken)}`;
|
|
158
|
+
const uploadUrl = buildUploadUrl(selectedHost, uploadType, mediaConn.auth, encrypted.fileEncSha256);
|
|
114
159
|
options.logger.debug('sending media upload request', {
|
|
115
160
|
mediaType: content.type,
|
|
116
161
|
uploadType,
|
|
@@ -123,26 +168,57 @@ async function uploadMedia(options, content, mediaBytes) {
|
|
|
123
168
|
contentLength: encrypted.ciphertextHmac.byteLength,
|
|
124
169
|
contentType: content.mimetype
|
|
125
170
|
});
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
throw new Error(`media upload failed with status ${uploadResponse.status}`);
|
|
129
|
-
}
|
|
130
|
-
let parsedBody;
|
|
131
|
-
try {
|
|
132
|
-
parsedBody = JSON.parse(TEXT_DECODER.decode(uploadBody));
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
throw new Error(`media upload returned invalid json: ${toError(error).message}`);
|
|
136
|
-
}
|
|
137
|
-
if (!parsedBody.url || !parsedBody.direct_path) {
|
|
138
|
-
throw new Error('media upload response missing url/direct_path');
|
|
139
|
-
}
|
|
171
|
+
const responseBody = await options.mediaTransfer.readResponseBytes(uploadResponse);
|
|
172
|
+
const parsed = parseUploadResponse(responseBody, uploadResponse.status);
|
|
140
173
|
return {
|
|
141
|
-
|
|
142
|
-
directPath: parsedBody.direct_path,
|
|
174
|
+
...parsed,
|
|
143
175
|
mediaKey,
|
|
144
176
|
fileSha256: encrypted.fileSha256,
|
|
145
177
|
fileEncSha256: encrypted.fileEncSha256,
|
|
146
|
-
|
|
178
|
+
fileLength: mediaBytes.byteLength
|
|
147
179
|
};
|
|
148
180
|
}
|
|
181
|
+
async function uploadMediaStream(options, content, stream) {
|
|
182
|
+
const uploadType = resolveUploadType(content);
|
|
183
|
+
const mediaKey = await WaMediaCrypto.generateMediaKey();
|
|
184
|
+
const encResult = await WaMediaCrypto.encryptToFile(uploadType, mediaKey, stream);
|
|
185
|
+
let readStream;
|
|
186
|
+
try {
|
|
187
|
+
const mediaConn = await getMediaConn(options);
|
|
188
|
+
const selectedHost = mediaConn.hosts.find((host) => !host.isFallback)?.hostname ??
|
|
189
|
+
mediaConn.hosts[0].hostname;
|
|
190
|
+
const uploadUrl = buildUploadUrl(selectedHost, uploadType, mediaConn.auth, encResult.fileEncSha256);
|
|
191
|
+
options.logger.debug('sending media stream upload request', {
|
|
192
|
+
mediaType: content.type,
|
|
193
|
+
uploadType,
|
|
194
|
+
host: selectedHost,
|
|
195
|
+
encryptedSize: encResult.fileSize
|
|
196
|
+
});
|
|
197
|
+
readStream = createReadStream(encResult.filePath);
|
|
198
|
+
const uploadResponse = await options.mediaTransfer.uploadStream({
|
|
199
|
+
url: uploadUrl,
|
|
200
|
+
method: 'POST',
|
|
201
|
+
body: readStream,
|
|
202
|
+
contentLength: encResult.fileSize,
|
|
203
|
+
contentType: content.mimetype
|
|
204
|
+
});
|
|
205
|
+
const responseBody = await options.mediaTransfer.readResponseBytes(uploadResponse);
|
|
206
|
+
const parsed = parseUploadResponse(responseBody, uploadResponse.status);
|
|
207
|
+
return {
|
|
208
|
+
...parsed,
|
|
209
|
+
mediaKey,
|
|
210
|
+
fileSha256: encResult.fileSha256,
|
|
211
|
+
fileEncSha256: encResult.fileEncSha256,
|
|
212
|
+
fileLength: encResult.plaintextLength
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
if (readStream && !readStream.closed) {
|
|
217
|
+
await new Promise((resolve) => {
|
|
218
|
+
readStream.once('close', resolve);
|
|
219
|
+
readStream.destroy();
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
await WaMediaCrypto.cleanupEncryptedFile(encResult.filePath);
|
|
223
|
+
}
|
|
224
|
+
}
|