zapo-js 0.2.0 → 0.3.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 +7 -3
- package/dist/appstate/WaAppStateCrypto.js +49 -41
- package/dist/appstate/WaAppStateSyncClient.js +79 -42
- package/dist/appstate/index.js +2 -2
- package/dist/auth/WaAuthClient.js +20 -11
- package/dist/auth/{flow/WaAuthCredentialsFlow.js → credentials-flow.js} +83 -18
- package/dist/auth/pairing/WaPairingFlow.js +26 -29
- package/dist/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +29 -13
- package/dist/client/WaClient.js +115 -75
- package/dist/client/WaClientFactory.js +113 -30
- package/dist/client/connection/WaConnectionManager.js +4 -1
- package/dist/client/coordinators/WaAbPropsCoordinator.js +141 -0
- package/dist/client/coordinators/WaBusinessCoordinator.js +3 -12
- package/dist/client/coordinators/WaEmailCoordinator.js +63 -0
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +33 -8
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +55 -25
- package/dist/client/coordinators/WaOfflineResumeCoordinator.js +114 -0
- package/dist/client/coordinators/WaPassiveTasksCoordinator.js +38 -20
- package/dist/client/coordinators/WaProfileCoordinator.js +3 -1
- package/dist/client/coordinators/WaRetryCoordinator.js +11 -9
- package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +22 -4
- package/dist/client/dirty.js +1 -1
- package/dist/client/events/abprops.js +43 -0
- package/dist/client/events/privacy-token.js +1 -2
- package/dist/client/events/registration.js +42 -0
- package/dist/client/incoming.js +37 -0
- package/dist/client/mailbox.js +17 -1
- package/dist/client/media.js +243 -0
- package/dist/client/messages.js +163 -86
- package/dist/crypto/core/index.js +4 -1
- package/dist/crypto/core/random.js +3 -9
- package/dist/crypto/core/xeddsa.js +57 -0
- package/dist/crypto/curves/X25519.js +18 -0
- package/dist/crypto/curves/constants.js +2 -1
- package/dist/esm/appstate/WaAppStateCrypto.js +39 -31
- package/dist/esm/appstate/WaAppStateSyncClient.js +68 -31
- package/dist/esm/appstate/index.js +1 -1
- package/dist/esm/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +1 -1
- package/dist/esm/auth/WaAuthClient.js +17 -8
- package/dist/esm/auth/{flow/WaAuthCredentialsFlow.js → credentials-flow.js} +83 -18
- package/dist/esm/auth/pairing/WaPairingFlow.js +25 -28
- package/dist/esm/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +20 -6
- package/dist/esm/client/WaClient.js +116 -76
- package/dist/esm/client/WaClientFactory.js +114 -31
- package/dist/esm/client/connection/WaConnectionManager.js +4 -1
- package/dist/esm/client/coordinators/WaAbPropsCoordinator.js +137 -0
- package/dist/esm/client/coordinators/WaBusinessCoordinator.js +4 -13
- package/dist/esm/client/coordinators/WaEmailCoordinator.js +60 -0
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +35 -10
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +47 -17
- package/dist/esm/client/coordinators/WaOfflineResumeCoordinator.js +110 -0
- package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +38 -20
- package/dist/esm/client/coordinators/WaProfileCoordinator.js +3 -1
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +11 -9
- package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +24 -6
- package/dist/esm/client/dirty.js +1 -1
- package/dist/esm/client/events/abprops.js +40 -0
- package/dist/esm/client/events/privacy-token.js +1 -2
- package/dist/esm/client/events/registration.js +39 -0
- package/dist/esm/client/incoming.js +36 -0
- package/dist/esm/client/mailbox.js +17 -1
- package/dist/esm/client/media.js +234 -0
- package/dist/esm/client/messages.js +162 -85
- package/dist/esm/crypto/core/index.js +1 -0
- package/dist/esm/crypto/core/random.js +2 -7
- package/dist/esm/crypto/core/xeddsa.js +53 -0
- package/dist/esm/crypto/curves/X25519.js +20 -2
- package/dist/esm/crypto/curves/constants.js +1 -0
- package/dist/esm/infra/perf/StoreLock.js +7 -4
- package/dist/esm/media/WaMediaCrypto.js +257 -62
- package/dist/esm/media/WaMediaTransferClient.js +47 -190
- package/dist/esm/media/constants.js +2 -0
- package/dist/esm/media/processor.js +1 -0
- package/dist/esm/message/addon-crypto.js +130 -3
- package/dist/esm/message/content.js +12 -6
- package/dist/esm/message/icdc.js +8 -8
- package/dist/esm/message/incoming.js +14 -12
- package/dist/esm/message/phash.js +32 -12
- package/dist/esm/message/reporting-token.js +3 -3
- package/dist/esm/message/use-case-secret.js +1 -1
- package/dist/esm/protocol/abprops.js +159 -0
- package/dist/esm/protocol/browser.js +14 -0
- package/dist/esm/protocol/constants.js +3 -1
- package/dist/esm/protocol/email.js +30 -0
- package/dist/esm/protocol/jid.js +44 -10
- package/dist/esm/protocol/nodes.js +6 -2
- package/dist/esm/protocol/notification.js +7 -1
- package/dist/esm/retry/reason.js +1 -1
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +5 -2
- package/dist/esm/signal/api/SignalDigestSyncApi.js +8 -6
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +4 -4
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +1 -1
- package/dist/esm/signal/api/SignalSessionSyncApi.js +1 -1
- package/dist/esm/signal/crypto/WaAdvSignature.js +5 -51
- package/dist/esm/signal/crypto/constants.js +0 -4
- package/dist/esm/signal/encoding.js +11 -54
- package/dist/esm/signal/group/SenderKeyChain.js +3 -3
- package/dist/esm/signal/group/SenderKeyCodec.js +5 -6
- package/dist/esm/signal/group/SenderKeyManager.js +13 -10
- package/dist/esm/signal/registration/keygen.js +2 -3
- package/dist/esm/signal/registration/utils.js +2 -2
- package/dist/esm/signal/session/SignalProtocol.js +18 -17
- package/dist/esm/signal/session/SignalRatchet.js +21 -10
- package/dist/esm/signal/session/SignalSerializer.js +5 -6
- package/dist/esm/signal/session/SignalSession.js +11 -9
- package/dist/esm/signal/session/resolver.js +6 -6
- package/dist/esm/store/contracts/identity.store.js +1 -0
- package/dist/esm/store/contracts/message-secret.store.js +1 -0
- package/dist/esm/store/contracts/pre-key.store.js +1 -0
- package/dist/esm/store/contracts/session.store.js +1 -0
- package/dist/esm/store/createStore.js +48 -12
- package/dist/esm/store/index.js +4 -0
- package/dist/esm/store/locks/identity.lock.js +16 -0
- package/dist/esm/store/locks/message-secret.lock.js +17 -0
- package/dist/esm/store/locks/pre-key.lock.js +27 -0
- package/dist/esm/store/locks/session.lock.js +19 -0
- package/dist/esm/store/locks/signal.lock.js +0 -24
- package/dist/esm/store/noop.store.js +20 -0
- package/dist/esm/store/providers/memory/device-list.store.js +3 -0
- package/dist/esm/store/providers/memory/identity.store.js +31 -0
- package/dist/esm/store/providers/memory/message-secret.store.js +81 -0
- package/dist/esm/store/providers/memory/participants.store.js +3 -0
- package/dist/esm/store/providers/memory/pre-key.store.js +97 -0
- package/dist/esm/store/providers/memory/retry.store.js +25 -11
- package/dist/esm/store/providers/memory/session.store.js +45 -0
- package/dist/esm/store/providers/memory/signal.store.js +1 -164
- package/dist/esm/transport/WaComms.js +4 -3
- package/dist/esm/transport/WaWebSocket.js +9 -1
- package/dist/esm/transport/index.js +6 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +17 -8
- package/dist/esm/transport/node/WaMobileTcpSocket.js +114 -0
- package/dist/esm/transport/node/WaNodeOrchestrator.js +17 -8
- package/dist/esm/transport/node/builders/abprops.js +20 -0
- package/dist/esm/transport/node/builders/device.js +11 -0
- package/dist/esm/transport/node/builders/email.js +65 -0
- package/dist/esm/transport/node/builders/offline.js +14 -0
- package/dist/esm/transport/node/builders/prekeys.js +37 -40
- package/dist/esm/transport/node/builders/presence.js +13 -0
- package/dist/esm/transport/node/builders/privacy-token.js +19 -23
- package/dist/esm/transport/node/builders/retry.js +1 -1
- package/dist/esm/transport/node/helpers.js +24 -0
- package/dist/esm/transport/node/mex/argo-decoder.js +152 -0
- package/dist/esm/transport/node/mex/client.js +83 -0
- package/dist/esm/transport/node/mex/persist-ids.js +10 -0
- package/dist/esm/transport/noise/WaClientPayload.js +15 -10
- package/dist/esm/transport/noise/WaFrameCodec.js +2 -2
- package/dist/esm/transport/noise/WaMobileClientPayload.js +53 -0
- package/dist/esm/transport/noise/WaNoiseCert.js +9 -27
- package/dist/esm/transport/noise/WaNoiseSession.js +12 -11
- package/dist/infra/perf/StoreLock.js +7 -4
- package/dist/media/WaMediaCrypto.js +253 -58
- package/dist/media/WaMediaTransferClient.js +50 -223
- package/dist/media/constants.js +3 -1
- package/dist/media/processor.js +2 -0
- package/dist/message/addon-crypto.js +131 -0
- package/dist/message/content.js +13 -5
- package/dist/message/icdc.js +8 -8
- package/dist/message/incoming.js +14 -12
- package/dist/message/phash.js +32 -12
- package/dist/message/reporting-token.js +2 -2
- package/dist/message/use-case-secret.js +1 -1
- package/dist/protocol/abprops.js +163 -0
- package/dist/protocol/browser.js +15 -0
- package/dist/protocol/constants.js +14 -2
- package/dist/protocol/email.js +33 -0
- package/dist/protocol/jid.js +45 -10
- package/dist/protocol/nodes.js +6 -2
- package/dist/protocol/notification.js +8 -2
- package/dist/retry/reason.js +1 -1
- package/dist/signal/api/SignalDeviceSyncApi.js +5 -2
- package/dist/signal/api/SignalDigestSyncApi.js +8 -6
- package/dist/signal/api/SignalIdentitySyncApi.js +4 -4
- package/dist/signal/crypto/WaAdvSignature.js +2 -50
- package/dist/signal/crypto/constants.js +1 -5
- package/dist/signal/encoding.js +11 -49
- package/dist/signal/group/SenderKeyChain.js +2 -2
- package/dist/signal/group/SenderKeyCodec.js +4 -5
- package/dist/signal/group/SenderKeyManager.js +12 -9
- package/dist/signal/registration/keygen.js +1 -2
- package/dist/signal/registration/utils.js +2 -2
- package/dist/signal/session/SignalProtocol.js +18 -17
- package/dist/signal/session/SignalRatchet.js +19 -8
- package/dist/signal/session/SignalSerializer.js +5 -6
- package/dist/signal/session/SignalSession.js +11 -9
- package/dist/signal/session/resolver.js +6 -6
- package/dist/store/contracts/identity.store.js +2 -0
- package/dist/store/contracts/message-secret.store.js +2 -0
- package/dist/store/contracts/pre-key.store.js +2 -0
- package/dist/store/contracts/session.store.js +2 -0
- package/dist/store/createStore.js +47 -11
- package/dist/store/index.js +9 -1
- package/dist/store/locks/identity.lock.js +19 -0
- package/dist/store/locks/message-secret.lock.js +20 -0
- package/dist/store/locks/pre-key.lock.js +30 -0
- package/dist/store/locks/session.lock.js +22 -0
- package/dist/store/locks/signal.lock.js +0 -24
- package/dist/store/noop.store.js +21 -1
- package/dist/store/providers/memory/device-list.store.js +3 -0
- package/dist/store/providers/memory/identity.store.js +35 -0
- package/dist/store/providers/memory/message-secret.store.js +85 -0
- package/dist/store/providers/memory/participants.store.js +3 -0
- package/dist/store/providers/memory/pre-key.store.js +101 -0
- package/dist/store/providers/memory/retry.store.js +24 -10
- package/dist/store/providers/memory/session.store.js +49 -0
- package/dist/store/providers/memory/signal.store.js +1 -164
- package/dist/transport/WaComms.js +4 -3
- package/dist/transport/WaWebSocket.js +9 -1
- package/dist/transport/index.js +17 -1
- package/dist/transport/keepalive/WaKeepAlive.js +17 -8
- package/dist/transport/node/WaMobileTcpSocket.js +118 -0
- package/dist/transport/node/WaNodeOrchestrator.js +16 -7
- package/dist/transport/node/builders/abprops.js +23 -0
- package/dist/transport/node/builders/device.js +14 -0
- package/dist/transport/node/builders/email.js +72 -0
- package/dist/transport/node/builders/offline.js +17 -0
- package/dist/transport/node/builders/prekeys.js +36 -39
- package/dist/transport/node/builders/presence.js +16 -0
- package/dist/transport/node/builders/privacy-token.js +18 -22
- package/dist/transport/node/builders/retry.js +1 -1
- package/dist/transport/node/helpers.js +26 -0
- package/dist/transport/node/mex/argo-decoder.js +189 -0
- package/dist/transport/node/mex/client.js +86 -0
- package/dist/transport/node/mex/persist-ids.js +13 -0
- package/dist/transport/noise/WaClientPayload.js +14 -9
- package/dist/transport/noise/WaFrameCodec.js +1 -1
- package/dist/transport/noise/WaMobileClientPayload.js +56 -0
- package/dist/transport/noise/WaNoiseCert.js +8 -26
- package/dist/transport/noise/WaNoiseSession.js +11 -10
- package/dist/types/appstate/WaAppStateCrypto.d.ts +11 -8
- package/dist/types/appstate/WaAppStateSyncClient.d.ts +6 -2
- package/dist/types/appstate/index.d.ts +1 -1
- package/dist/types/appstate/{WaAppStateSyncResponseParser.d.ts → response-parser.d.ts} +1 -1
- package/dist/types/appstate/types.d.ts +1 -1
- package/dist/types/auth/WaAuthClient.d.ts +9 -3
- package/dist/types/auth/credentials-flow.d.ts +20 -0
- package/dist/types/auth/pairing/WaPairingFlow.d.ts +3 -2
- package/dist/types/auth/pairing/{WaPairingCodeCrypto.d.ts → pairing-code-crypto.d.ts} +6 -1
- package/dist/types/auth/types.d.ts +40 -0
- package/dist/types/client/WaClient.d.ts +19 -8
- package/dist/types/client/WaClientFactory.d.ts +10 -4
- package/dist/types/client/coordinators/WaAbPropsCoordinator.d.ts +26 -0
- package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +1 -1
- package/dist/types/client/coordinators/WaEmailCoordinator.d.ts +24 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +6 -1
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +15 -2
- package/dist/types/client/coordinators/WaOfflineResumeCoordinator.d.ts +31 -0
- package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +13 -2
- package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +1 -1
- package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +4 -2
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
- package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +11 -1
- package/dist/types/client/dirty.d.ts +3 -1
- package/dist/types/client/events/abprops.d.ts +14 -0
- package/dist/types/client/events/registration.d.ts +17 -0
- package/dist/types/client/incoming.d.ts +6 -1
- package/dist/types/client/mailbox.d.ts +2 -0
- package/dist/types/client/media.d.ts +31 -0
- package/dist/types/client/messages.d.ts +2 -0
- package/dist/types/client/persistence/WriteBehindPersistence.d.ts +1 -1
- package/dist/types/client/types.d.ts +100 -1
- package/dist/types/crypto/core/index.d.ts +1 -0
- package/dist/types/crypto/core/primitives.d.ts +1 -1
- package/dist/types/crypto/core/random.d.ts +1 -1
- package/dist/types/crypto/core/xeddsa.d.ts +2 -0
- package/dist/types/crypto/curves/constants.d.ts +1 -0
- package/dist/types/crypto/index.d.ts +1 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/infra/log/ConsoleLogger.d.ts +1 -1
- package/dist/types/infra/log/PinoLogger.d.ts +1 -1
- package/dist/types/infra/perf/StoreLock.d.ts +1 -0
- package/dist/types/media/WaMediaCrypto.d.ts +15 -6
- package/dist/types/media/WaMediaTransferClient.d.ts +3 -11
- package/dist/types/media/constants.d.ts +2 -0
- package/dist/types/media/index.d.ts +1 -0
- package/dist/types/media/processor.d.ts +28 -0
- package/dist/types/media/types.d.ts +9 -3
- package/dist/types/message/addon-crypto.d.ts +34 -3
- package/dist/types/message/content.d.ts +3 -1
- package/dist/types/message/icdc.d.ts +4 -4
- package/dist/types/message/types.d.ts +16 -24
- package/dist/types/protocol/abprops.d.ts +142 -0
- package/dist/types/protocol/browser.d.ts +1 -0
- package/dist/types/protocol/constants.d.ts +5 -1
- package/dist/types/protocol/email.d.ts +32 -0
- package/dist/types/protocol/jid.d.ts +1 -0
- package/dist/types/protocol/nodes.d.ts +4 -0
- package/dist/types/protocol/notification.d.ts +6 -0
- package/dist/types/protocol/stream.d.ts +1 -0
- package/dist/types/retry/reason.d.ts +1 -1
- package/dist/types/signal/api/SignalDigestSyncApi.d.ts +3 -0
- package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +3 -3
- package/dist/types/signal/crypto/WaAdvSignature.d.ts +0 -2
- package/dist/types/signal/crypto/constants.d.ts +0 -1
- package/dist/types/signal/encoding.d.ts +7 -1
- package/dist/types/signal/group/SenderKeyChain.d.ts +1 -1
- package/dist/types/signal/group/SenderKeyManager.d.ts +7 -2
- package/dist/types/signal/registration/utils.d.ts +2 -1
- package/dist/types/signal/session/SignalProtocol.d.ts +11 -2
- package/dist/types/signal/session/SignalSerializer.d.ts +2 -1
- package/dist/types/signal/session/resolver.d.ts +4 -2
- package/dist/types/signal/types.d.ts +16 -4
- package/dist/types/store/contracts/identity.store.d.ts +11 -0
- package/dist/types/store/contracts/message-secret.store.d.ts +16 -0
- package/dist/types/store/contracts/pre-key.store.d.ts +13 -0
- package/dist/types/store/contracts/session.store.d.ts +14 -0
- package/dist/types/store/contracts/signal.store.d.ts +1 -34
- package/dist/types/store/index.d.ts +9 -1
- package/dist/types/store/locks/identity.lock.d.ts +3 -0
- package/dist/types/store/locks/message-secret.lock.d.ts +3 -0
- package/dist/types/store/locks/pre-key.lock.d.ts +3 -0
- package/dist/types/store/locks/session.lock.d.ts +3 -0
- package/dist/types/store/noop.store.d.ts +4 -0
- package/dist/types/store/providers/memory/identity.store.d.ts +18 -0
- package/dist/types/store/providers/memory/message-secret.store.d.ts +21 -0
- package/dist/types/store/providers/memory/pre-key.store.d.ts +23 -0
- package/dist/types/store/providers/memory/retry.store.d.ts +7 -1
- package/dist/types/store/providers/memory/session.store.d.ts +21 -0
- package/dist/types/store/providers/memory/signal.store.d.ts +3 -45
- package/dist/types/store/providers/memory/thread.store.d.ts +1 -1
- package/dist/types/store/types.d.ts +21 -1
- package/dist/types/transport/WaWebSocket.d.ts +1 -0
- package/dist/types/transport/index.d.ts +8 -1
- package/dist/types/transport/keepalive/WaKeepAlive.d.ts +4 -1
- package/dist/types/transport/node/WaMobileTcpSocket.d.ts +18 -0
- package/dist/types/transport/node/WaNodeOrchestrator.d.ts +6 -2
- package/dist/types/transport/node/builders/abprops.d.ts +5 -0
- package/dist/types/transport/node/builders/device.d.ts +2 -0
- package/dist/types/transport/node/builders/email.d.ts +11 -0
- package/dist/types/transport/node/builders/offline.d.ts +2 -0
- package/dist/types/transport/node/builders/prekeys.d.ts +4 -3
- package/dist/types/transport/node/builders/presence.d.ts +6 -0
- package/dist/types/transport/node/helpers.d.ts +3 -0
- package/dist/types/transport/node/mex/argo-decoder.d.ts +11 -0
- package/dist/types/transport/node/mex/client.d.ts +18 -0
- package/dist/types/transport/node/mex/persist-ids.d.ts +14 -0
- package/dist/types/transport/noise/WaMobileClientPayload.d.ts +29 -0
- package/dist/types/transport/noise/WaNoiseCert.d.ts +7 -1
- package/dist/types/transport/noise/WaNoiseSession.d.ts +1 -0
- package/dist/types/transport/types.d.ts +8 -0
- package/package.json +6 -4
- package/dist/auth/pairing/constants.js +0 -5
- package/dist/client/connection/WaKeyShareCoordinator.js +0 -63
- package/dist/esm/auth/pairing/constants.js +0 -2
- package/dist/esm/client/connection/WaKeyShareCoordinator.js +0 -59
- package/dist/esm/transport/node/builders/index.js +0 -11
- package/dist/transport/node/builders/index.js +0 -51
- package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +0 -14
- package/dist/types/auth/pairing/constants.d.ts +0 -2
- package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +0 -14
- package/dist/types/transport/node/builders/index.d.ts +0 -11
- /package/dist/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import https from 'node:https';
|
|
2
3
|
import { DEFAULT_MEDIA_HOSTS } from './constants.js';
|
|
3
4
|
import { WaMediaCrypto } from './WaMediaCrypto.js';
|
|
4
5
|
import { WA_DEFAULTS } from '../protocol/constants.js';
|
|
5
6
|
import { EMPTY_BYTES, readAllBytes } from '../util/bytes.js';
|
|
6
7
|
import { toError } from '../util/primitives.js';
|
|
7
|
-
const GOT_OPTIONAL_MODULE = 'got';
|
|
8
8
|
function normalizeHeaderRecord(headers) {
|
|
9
9
|
if (!headers) {
|
|
10
10
|
return {};
|
|
@@ -15,56 +15,6 @@ function normalizeHeaderRecord(headers) {
|
|
|
15
15
|
}
|
|
16
16
|
return normalized;
|
|
17
17
|
}
|
|
18
|
-
function asOptionalGotModule(loaded) {
|
|
19
|
-
if (loaded && typeof loaded === 'object') {
|
|
20
|
-
const direct = loaded.stream;
|
|
21
|
-
if (typeof direct === 'function') {
|
|
22
|
-
return loaded;
|
|
23
|
-
}
|
|
24
|
-
const fallback = loaded.default;
|
|
25
|
-
if (fallback &&
|
|
26
|
-
typeof fallback === 'object' &&
|
|
27
|
-
'stream' in fallback &&
|
|
28
|
-
typeof fallback.stream === 'function') {
|
|
29
|
-
return fallback;
|
|
30
|
-
}
|
|
31
|
-
if (typeof fallback === 'function' && 'stream' in fallback) {
|
|
32
|
-
const maybeStream = fallback.stream;
|
|
33
|
-
if (typeof maybeStream === 'function') {
|
|
34
|
-
return fallback;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (typeof loaded === 'function' && 'stream' in loaded) {
|
|
39
|
-
const maybeStream = loaded.stream;
|
|
40
|
-
if (typeof maybeStream === 'function') {
|
|
41
|
-
return loaded;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
async function loadOptionalGotModule() {
|
|
47
|
-
try {
|
|
48
|
-
const loaded = await import(GOT_OPTIONAL_MODULE);
|
|
49
|
-
const module = asOptionalGotModule(loaded);
|
|
50
|
-
if (module) {
|
|
51
|
-
return module;
|
|
52
|
-
}
|
|
53
|
-
throw new Error('invalid got module export');
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
const normalized = toError(error);
|
|
57
|
-
const code = normalized.code;
|
|
58
|
-
const message = normalized.message ?? '';
|
|
59
|
-
const isModuleNotFound = (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') &&
|
|
60
|
-
(message.includes(`'${GOT_OPTIONAL_MODULE}'`) ||
|
|
61
|
-
message.includes(`"${GOT_OPTIONAL_MODULE}"`));
|
|
62
|
-
if (isModuleNotFound) {
|
|
63
|
-
throw new Error('optional dependency "got" is not installed. Install with: npm i got');
|
|
64
|
-
}
|
|
65
|
-
throw normalized;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
18
|
export class WaMediaTransferClient {
|
|
69
19
|
constructor(options = {}) {
|
|
70
20
|
this.logger = options.logger;
|
|
@@ -72,25 +22,18 @@ export class WaMediaTransferClient {
|
|
|
72
22
|
this.defaultTimeoutMs = options.defaultTimeoutMs ?? WA_DEFAULTS.MEDIA_TIMEOUT_MS;
|
|
73
23
|
this.defaultMaxReadBytes = options.defaultMaxReadBytes;
|
|
74
24
|
this.defaultHeaders = normalizeHeaderRecord(options.defaultHeaders);
|
|
75
|
-
this.defaultUploadDispatcher = options.defaultUploadDispatcher;
|
|
76
|
-
this.defaultDownloadDispatcher = options.defaultDownloadDispatcher;
|
|
77
25
|
this.defaultUploadAgent = options.defaultUploadAgent;
|
|
78
26
|
this.defaultDownloadAgent = options.defaultDownloadAgent;
|
|
79
|
-
this.
|
|
27
|
+
this.skipMacVerification = options.skipMacVerification === true;
|
|
80
28
|
}
|
|
81
29
|
async downloadStream(request) {
|
|
82
30
|
const { urls, headers, timeoutMs } = this.resolveTransferRequest(request);
|
|
83
|
-
const dispatcher = request.dispatcher ?? this.defaultDownloadDispatcher;
|
|
84
31
|
const agent = request.agent ?? this.defaultDownloadAgent;
|
|
85
32
|
this.logger?.debug('media download stream start', {
|
|
86
33
|
urls: urls.length,
|
|
87
34
|
timeoutMs
|
|
88
35
|
});
|
|
89
|
-
const result = await this.fetchWithFallback(urls, timeoutMs, request.signal, (url, signal) => this.
|
|
90
|
-
method: 'GET',
|
|
91
|
-
headers,
|
|
92
|
-
signal
|
|
93
|
-
}, dispatcher, agent));
|
|
36
|
+
const result = await this.fetchWithFallback(urls, timeoutMs, request.signal, (url, signal) => this.httpRequest(url, { method: 'GET', headers, signal }, agent));
|
|
94
37
|
this.logger?.trace('media download stream response', {
|
|
95
38
|
url: result.url,
|
|
96
39
|
status: result.status
|
|
@@ -115,7 +58,6 @@ export class WaMediaTransferClient {
|
|
|
115
58
|
? String(request.contentLength)
|
|
116
59
|
: undefined
|
|
117
60
|
});
|
|
118
|
-
const dispatcher = request.dispatcher ?? this.defaultUploadDispatcher;
|
|
119
61
|
const agent = request.agent ?? this.defaultUploadAgent;
|
|
120
62
|
const uploadUrls = bodyIsBytes ? urls : urls.slice(0, 1);
|
|
121
63
|
if (!bodyIsBytes && urls.length > 1) {
|
|
@@ -129,23 +71,7 @@ export class WaMediaTransferClient {
|
|
|
129
71
|
timeoutMs,
|
|
130
72
|
method
|
|
131
73
|
});
|
|
132
|
-
const result = await this.fetchWithFallback(uploadUrls, timeoutMs, request.signal,
|
|
133
|
-
if (bodyIsBytes) {
|
|
134
|
-
return this.transferRequest(url, {
|
|
135
|
-
method,
|
|
136
|
-
headers,
|
|
137
|
-
signal,
|
|
138
|
-
body: request.body
|
|
139
|
-
}, dispatcher, agent);
|
|
140
|
-
}
|
|
141
|
-
return this.transferRequest(url, {
|
|
142
|
-
method,
|
|
143
|
-
headers,
|
|
144
|
-
signal,
|
|
145
|
-
body: request.body,
|
|
146
|
-
duplex: 'half'
|
|
147
|
-
}, dispatcher, agent);
|
|
148
|
-
});
|
|
74
|
+
const result = await this.fetchWithFallback(uploadUrls, timeoutMs, request.signal, (url, signal) => this.httpRequest(url, { method, headers, signal, body: request.body }, agent));
|
|
149
75
|
this.logger?.trace('media upload stream response', {
|
|
150
76
|
url: result.url,
|
|
151
77
|
status: result.status
|
|
@@ -165,7 +91,6 @@ export class WaMediaTransferClient {
|
|
|
165
91
|
directPath: request.directPath,
|
|
166
92
|
hosts: request.hosts,
|
|
167
93
|
headers: request.headers,
|
|
168
|
-
dispatcher: request.dispatcher,
|
|
169
94
|
agent: request.agent,
|
|
170
95
|
timeoutMs: request.timeoutMs,
|
|
171
96
|
signal: request.signal,
|
|
@@ -221,7 +146,8 @@ export class WaMediaTransferClient {
|
|
|
221
146
|
mediaType: request.mediaType,
|
|
222
147
|
mediaKey: request.mediaKey,
|
|
223
148
|
expectedFileSha256: request.fileSha256,
|
|
224
|
-
expectedFileEncSha256: request.fileEncSha256
|
|
149
|
+
expectedFileEncSha256: request.fileEncSha256,
|
|
150
|
+
skipMacVerification: this.skipMacVerification
|
|
225
151
|
});
|
|
226
152
|
decrypted.metadata.catch(() => undefined);
|
|
227
153
|
this.logger?.debug('media encrypted download stream ready', {
|
|
@@ -238,119 +164,50 @@ export class WaMediaTransferClient {
|
|
|
238
164
|
}
|
|
239
165
|
return readAllBytes(response.body, { maxBytes: maxBytes ?? this.defaultMaxReadBytes });
|
|
240
166
|
}
|
|
241
|
-
async
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
return this.fetchWithDispatcher(url, init, dispatcher);
|
|
246
|
-
}
|
|
247
|
-
async fetchWithDispatcher(url, init, dispatcher) {
|
|
248
|
-
const response = !dispatcher
|
|
249
|
-
? await fetch(url, init)
|
|
250
|
-
: await fetch(url, {
|
|
251
|
-
...init,
|
|
252
|
-
dispatcher
|
|
253
|
-
});
|
|
254
|
-
return this.toFetchTransferResponse(response);
|
|
255
|
-
}
|
|
256
|
-
toFetchTransferResponse(response) {
|
|
257
|
-
return {
|
|
258
|
-
status: response.status,
|
|
259
|
-
ok: response.ok,
|
|
260
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
261
|
-
body: response.body
|
|
262
|
-
? Readable.fromWeb(response.body)
|
|
263
|
-
: null,
|
|
264
|
-
cancel: async () => {
|
|
265
|
-
if (!response.body) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
try {
|
|
269
|
-
await response.body.cancel();
|
|
270
|
-
}
|
|
271
|
-
catch {
|
|
272
|
-
// ignore cancel errors from remote resets
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
async gotWithAgent(url, init, agent) {
|
|
278
|
-
const got = await this.loadGotModule();
|
|
279
|
-
const urlObj = new URL(url);
|
|
280
|
-
const gotAgent = urlObj.protocol === 'http:'
|
|
281
|
-
? { http: agent }
|
|
282
|
-
: urlObj.protocol === 'https:'
|
|
283
|
-
? { https: agent }
|
|
284
|
-
: { http: agent, https: agent };
|
|
167
|
+
async httpRequest(url, init, agent) {
|
|
168
|
+
const parsed = new URL(url);
|
|
169
|
+
const transport = parsed.protocol === 'https:' ? https : http;
|
|
285
170
|
return new Promise((resolve, reject) => {
|
|
286
|
-
const
|
|
287
|
-
method: init.method,
|
|
288
|
-
headers:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
};
|
|
303
|
-
request.once('error', onError);
|
|
304
|
-
request.once('response', onResponse);
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
async loadGotModule() {
|
|
308
|
-
if (!this.gotModulePromise) {
|
|
309
|
-
this.gotModulePromise = loadOptionalGotModule().catch((error) => {
|
|
310
|
-
this.gotModulePromise = null;
|
|
311
|
-
throw error;
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
return this.gotModulePromise;
|
|
315
|
-
}
|
|
316
|
-
toGotTransferResponse(incoming) {
|
|
317
|
-
if (!incoming || typeof incoming !== 'object') {
|
|
318
|
-
throw new Error('invalid got response object');
|
|
319
|
-
}
|
|
320
|
-
const stream = incoming;
|
|
321
|
-
const status = typeof stream.statusCode === 'number' &&
|
|
322
|
-
Number.isFinite(stream.statusCode) &&
|
|
323
|
-
stream.statusCode >= 100 &&
|
|
324
|
-
stream.statusCode <= 599
|
|
325
|
-
? stream.statusCode
|
|
326
|
-
: 500;
|
|
327
|
-
const headers = {};
|
|
328
|
-
if (stream.headers && typeof stream.headers === 'object') {
|
|
329
|
-
const input = stream.headers;
|
|
330
|
-
for (const key in input) {
|
|
331
|
-
const value = input[key];
|
|
332
|
-
if (typeof value === 'string') {
|
|
333
|
-
headers[key] = value;
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
if (Array.isArray(value)) {
|
|
337
|
-
headers[key] = value.join(', ');
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
if (value !== undefined && value !== null) {
|
|
341
|
-
headers[key] = String(value);
|
|
171
|
+
const req = transport.request(url, {
|
|
172
|
+
method: init.method ?? 'GET',
|
|
173
|
+
headers: init.headers,
|
|
174
|
+
signal: init.signal ?? undefined,
|
|
175
|
+
agent: agent ?? undefined
|
|
176
|
+
}, (res) => {
|
|
177
|
+
const status = res.statusCode ?? 500;
|
|
178
|
+
const headers = {};
|
|
179
|
+
for (const key in res.headers) {
|
|
180
|
+
const value = res.headers[key];
|
|
181
|
+
if (typeof value === 'string') {
|
|
182
|
+
headers[key] = value;
|
|
183
|
+
}
|
|
184
|
+
else if (Array.isArray(value)) {
|
|
185
|
+
headers[key] = value.join(', ');
|
|
186
|
+
}
|
|
342
187
|
}
|
|
188
|
+
resolve({
|
|
189
|
+
status,
|
|
190
|
+
ok: status >= 200 && status < 300,
|
|
191
|
+
headers,
|
|
192
|
+
body: res,
|
|
193
|
+
cancel: async () => {
|
|
194
|
+
res.destroy();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
req.on('error', (error) => reject(toError(error)));
|
|
199
|
+
const body = init.body;
|
|
200
|
+
if (body instanceof Uint8Array) {
|
|
201
|
+
req.end(body);
|
|
343
202
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
ok: status >= 200 && status < 300,
|
|
348
|
-
headers,
|
|
349
|
-
body: stream,
|
|
350
|
-
cancel: async () => {
|
|
351
|
-
stream.destroy();
|
|
203
|
+
else if (body) {
|
|
204
|
+
body.on('error', (err) => req.destroy(toError(err)));
|
|
205
|
+
body.pipe(req);
|
|
352
206
|
}
|
|
353
|
-
|
|
207
|
+
else {
|
|
208
|
+
req.end();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
354
211
|
}
|
|
355
212
|
resolveTransferRequest(request, extraHeaders) {
|
|
356
213
|
const headers = { ...this.defaultHeaders };
|
|
@@ -10,6 +10,8 @@ export const ENC_KEY_END = 48;
|
|
|
10
10
|
export const MAC_KEY_START = 48;
|
|
11
11
|
export const MAC_KEY_END = 80;
|
|
12
12
|
export const HMAC_TRUNCATED_SIZE = 10;
|
|
13
|
+
export const SIDECAR_CHUNK_SIZE = 65536;
|
|
14
|
+
export const SIDECAR_HMAC_SIZE = 10;
|
|
13
15
|
export const MEDIA_UPLOAD_PATHS = Object.freeze({
|
|
14
16
|
image: '/mms/image',
|
|
15
17
|
video: '/mms/video',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { aesGcmDecrypt, aesGcmEncrypt, importAesGcmKey } from '../crypto/index.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { aesGcmDecrypt, aesGcmEncrypt, importAesGcmKey, sha256 } from '../crypto/index.js';
|
|
2
|
+
import { unwrapMessage } from './content.js';
|
|
3
|
+
import { assertMessageSecret, createUseCaseSecret, WA_MESSAGE_SECRET_BYTES, WA_USE_CASE_SECRET_MODIFICATION_TYPES } from './use-case-secret.js';
|
|
4
|
+
import { proto } from '../proto.js';
|
|
5
|
+
import { bytesToHex, EMPTY_BYTES, TEXT_ENCODER, toBytesView } from '../util/bytes.js';
|
|
4
6
|
const WA_ADDON_ENCRYPTION_NONCE_BYTES = 12;
|
|
5
7
|
export function shouldUseAddonAdditionalData(modificationType) {
|
|
6
8
|
return (modificationType === WA_USE_CASE_SECRET_MODIFICATION_TYPES.POLL_VOTE ||
|
|
@@ -41,6 +43,131 @@ export async function decryptAddonPayload(input) {
|
|
|
41
43
|
const additionalData = resolveAddonAdditionalData(input);
|
|
42
44
|
return aesGcmDecrypt(key, iv, toBytesView(input.ciphertext), additionalData);
|
|
43
45
|
}
|
|
46
|
+
export function identifyEncryptedAddon(message) {
|
|
47
|
+
const msg = unwrapMessage(message);
|
|
48
|
+
if (msg.encReactionMessage) {
|
|
49
|
+
const { targetMessageKey, encPayload, encIv } = msg.encReactionMessage;
|
|
50
|
+
if (targetMessageKey && encPayload && encIv) {
|
|
51
|
+
return {
|
|
52
|
+
kind: 'reaction',
|
|
53
|
+
targetMessageKey,
|
|
54
|
+
encPayload: encPayload,
|
|
55
|
+
encIv: encIv,
|
|
56
|
+
modificationType: WA_USE_CASE_SECRET_MODIFICATION_TYPES.ENC_REACTION,
|
|
57
|
+
raw: message
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (msg.pollUpdateMessage) {
|
|
62
|
+
const { pollCreationMessageKey, vote } = msg.pollUpdateMessage;
|
|
63
|
+
if (pollCreationMessageKey && vote?.encPayload && vote.encIv) {
|
|
64
|
+
return {
|
|
65
|
+
kind: 'poll_vote',
|
|
66
|
+
targetMessageKey: pollCreationMessageKey,
|
|
67
|
+
encPayload: vote.encPayload,
|
|
68
|
+
encIv: vote.encIv,
|
|
69
|
+
modificationType: WA_USE_CASE_SECRET_MODIFICATION_TYPES.POLL_VOTE,
|
|
70
|
+
raw: message
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (msg.encEventResponseMessage) {
|
|
75
|
+
const { eventCreationMessageKey, encPayload, encIv } = msg.encEventResponseMessage;
|
|
76
|
+
if (eventCreationMessageKey && encPayload && encIv) {
|
|
77
|
+
return {
|
|
78
|
+
kind: 'event_response',
|
|
79
|
+
targetMessageKey: eventCreationMessageKey,
|
|
80
|
+
encPayload: encPayload,
|
|
81
|
+
encIv: encIv,
|
|
82
|
+
modificationType: WA_USE_CASE_SECRET_MODIFICATION_TYPES.EVENT_RESPONSE,
|
|
83
|
+
raw: message
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (msg.encCommentMessage) {
|
|
88
|
+
const { targetMessageKey, encPayload, encIv } = msg.encCommentMessage;
|
|
89
|
+
if (targetMessageKey && encPayload && encIv) {
|
|
90
|
+
return {
|
|
91
|
+
kind: 'comment',
|
|
92
|
+
targetMessageKey,
|
|
93
|
+
encPayload: encPayload,
|
|
94
|
+
encIv: encIv,
|
|
95
|
+
modificationType: WA_USE_CASE_SECRET_MODIFICATION_TYPES.ENC_COMMENT,
|
|
96
|
+
raw: message
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
export function decodeAddonPlaintext(kind, plaintext) {
|
|
103
|
+
switch (kind) {
|
|
104
|
+
case 'reaction':
|
|
105
|
+
return { kind, reaction: proto.Message.ReactionMessage.decode(plaintext) };
|
|
106
|
+
case 'poll_vote':
|
|
107
|
+
return {
|
|
108
|
+
kind,
|
|
109
|
+
pollVote: proto.Message.PollVoteMessage.decode(plaintext),
|
|
110
|
+
selectedOptionNames: null
|
|
111
|
+
};
|
|
112
|
+
case 'event_response':
|
|
113
|
+
return { kind, eventResponse: proto.Message.EventResponseMessage.decode(plaintext) };
|
|
114
|
+
case 'comment':
|
|
115
|
+
return { kind, comment: proto.Message.CommentMessage.decode(plaintext) };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export async function resolveParentMessageSecret(targetMessageId, messageSecretStore, messageStore) {
|
|
119
|
+
const cached = await messageSecretStore.get(targetMessageId);
|
|
120
|
+
if (cached)
|
|
121
|
+
return cached;
|
|
122
|
+
const record = await messageStore.getById(targetMessageId);
|
|
123
|
+
if (!record?.messageBytes)
|
|
124
|
+
return null;
|
|
125
|
+
try {
|
|
126
|
+
const decoded = proto.Message.decode(record.messageBytes);
|
|
127
|
+
const secret = decoded.messageContextInfo?.messageSecret;
|
|
128
|
+
if (!secret || secret.byteLength !== WA_MESSAGE_SECRET_BYTES)
|
|
129
|
+
return null;
|
|
130
|
+
return { secret, senderJid: record.senderJid ?? '' };
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function resolvePollOptionNames(selectedOptions, pollCreationMessageId, messageStore) {
|
|
137
|
+
const record = await messageStore.getById(pollCreationMessageId);
|
|
138
|
+
if (!record?.messageBytes)
|
|
139
|
+
return null;
|
|
140
|
+
let decoded;
|
|
141
|
+
try {
|
|
142
|
+
decoded = proto.Message.decode(record.messageBytes);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const pollMsg = unwrapMessage(decoded);
|
|
148
|
+
const options = pollMsg.pollCreationMessage?.options ??
|
|
149
|
+
pollMsg.pollCreationMessageV2?.options ??
|
|
150
|
+
pollMsg.pollCreationMessageV3?.options ??
|
|
151
|
+
pollMsg.pollCreationMessageV5?.options;
|
|
152
|
+
if (!options || options.length === 0)
|
|
153
|
+
return null;
|
|
154
|
+
const hashToName = new Map();
|
|
155
|
+
for (const option of options) {
|
|
156
|
+
if (!option.optionName)
|
|
157
|
+
continue;
|
|
158
|
+
const hash = await sha256(TEXT_ENCODER.encode(option.optionName));
|
|
159
|
+
hashToName.set(bytesToHex(hash), option.optionName);
|
|
160
|
+
}
|
|
161
|
+
const names = [];
|
|
162
|
+
for (const selected of selectedOptions) {
|
|
163
|
+
const hex = bytesToHex(selected);
|
|
164
|
+
const name = hashToName.get(hex);
|
|
165
|
+
if (!name)
|
|
166
|
+
return null;
|
|
167
|
+
names.push(name);
|
|
168
|
+
}
|
|
169
|
+
return names;
|
|
170
|
+
}
|
|
44
171
|
function assertAddonIv(iv) {
|
|
45
172
|
const normalized = toBytesView(iv);
|
|
46
173
|
if (normalized.byteLength !== WA_ADDON_ENCRYPTION_NONCE_BYTES) {
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { proto } from '../proto.js';
|
|
2
2
|
import { WA_EDIT_ATTRS, WA_ENC_MEDIA_TYPES, WA_EVENT_META_TYPES, WA_POLL_META_TYPES, WA_STANZA_MSG_TYPES } from '../protocol/constants.js';
|
|
3
3
|
export function isSendMediaMessage(content) {
|
|
4
|
-
return
|
|
5
|
-
typeof content === 'object' &&
|
|
6
|
-
'type' in content &&
|
|
7
|
-
'media' in content &&
|
|
8
|
-
'mimetype' in content);
|
|
4
|
+
return !!content && typeof content === 'object' && 'type' in content && 'media' in content;
|
|
9
5
|
}
|
|
10
|
-
function unwrapMessage(message) {
|
|
6
|
+
export function unwrapMessage(message) {
|
|
11
7
|
let msg = message;
|
|
12
8
|
for (;;) {
|
|
13
9
|
const inner = msg.ephemeralMessage?.message ??
|
|
@@ -70,6 +66,16 @@ export function resolveMessageTypeAttr(message) {
|
|
|
70
66
|
return WA_STANZA_MSG_TYPES.MEDIA;
|
|
71
67
|
}
|
|
72
68
|
const REVOKED_REACTION_TEXT = '';
|
|
69
|
+
export function needsSecretPersistence(message) {
|
|
70
|
+
const msg = unwrapMessage(message);
|
|
71
|
+
return !!(msg.pollCreationMessage ||
|
|
72
|
+
msg.pollCreationMessageV2 ||
|
|
73
|
+
msg.pollCreationMessageV3 ||
|
|
74
|
+
msg.pollCreationMessageV4 ||
|
|
75
|
+
msg.pollCreationMessageV5 ||
|
|
76
|
+
msg.pollCreationMessageV6 ||
|
|
77
|
+
msg.eventMessage);
|
|
78
|
+
}
|
|
73
79
|
export function resolveEditAttr(message, subtype) {
|
|
74
80
|
const msg = unwrapMessage(message);
|
|
75
81
|
if (msg.protocolMessage) {
|
package/dist/esm/message/icdc.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { sha256, toRawPubKey } from '../crypto/index.js';
|
|
2
2
|
import { parseSignalAddressFromJid } from '../protocol/jid.js';
|
|
3
3
|
import { concatBytes } from '../util/bytes.js';
|
|
4
|
-
const
|
|
4
|
+
const ICDC_DEFAULT_HASH_LENGTH = 8;
|
|
5
5
|
const ICDC_FRESHNESS_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1000;
|
|
6
6
|
const DEVICE_LIST_METADATA_VERSION = 2;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
export async function computeDeviceKeyHash(identityKeys, hashLength) {
|
|
8
|
+
const length = hashLength ?? ICDC_DEFAULT_HASH_LENGTH;
|
|
9
9
|
if (identityKeys.length === 0) {
|
|
10
|
-
return
|
|
10
|
+
return new Uint8Array(length);
|
|
11
11
|
}
|
|
12
12
|
const rawKeys = new Array(identityKeys.length);
|
|
13
13
|
for (let i = 0; i < identityKeys.length; i += 1) {
|
|
@@ -16,9 +16,9 @@ export async function computeDeviceKeyHash(identityKeys) {
|
|
|
16
16
|
}
|
|
17
17
|
const combined = concatBytes(rawKeys);
|
|
18
18
|
const hash = await sha256(combined);
|
|
19
|
-
return hash.subarray(0,
|
|
19
|
+
return hash.subarray(0, length);
|
|
20
20
|
}
|
|
21
|
-
export async function resolveIcdcMeta(deviceJids,
|
|
21
|
+
export async function resolveIcdcMeta(deviceJids, identityStore, updatedAtMs, localIdentity, hashLength) {
|
|
22
22
|
if (deviceJids.length === 0) {
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
@@ -26,7 +26,7 @@ export async function resolveIcdcMeta(deviceJids, signalStore, updatedAtMs, loca
|
|
|
26
26
|
for (let i = 0; i < deviceJids.length; i += 1) {
|
|
27
27
|
addresses[i] = parseSignalAddressFromJid(deviceJids[i]);
|
|
28
28
|
}
|
|
29
|
-
const remoteKeys = await
|
|
29
|
+
const remoteKeys = await identityStore.getRemoteIdentities(addresses);
|
|
30
30
|
const keys = [];
|
|
31
31
|
for (let i = 0; i < addresses.length; i += 1) {
|
|
32
32
|
const key = remoteKeys[i];
|
|
@@ -42,7 +42,7 @@ export async function resolveIcdcMeta(deviceJids, signalStore, updatedAtMs, loca
|
|
|
42
42
|
if (keys.length === 0) {
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
-
const keyHash = await computeDeviceKeyHash(keys);
|
|
45
|
+
const keyHash = await computeDeviceKeyHash(keys, hashLength);
|
|
46
46
|
const timestamp = updatedAtMs !== undefined && Date.now() - updatedAtMs < ICDC_FRESHNESS_THRESHOLD_MS
|
|
47
47
|
? Math.floor(updatedAtMs / 1000)
|
|
48
48
|
: undefined;
|
|
@@ -48,14 +48,6 @@ function buildIncomingEventRawNode(node) {
|
|
|
48
48
|
content: children
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
function buildBaseIncomingEvent(node) {
|
|
52
|
-
return {
|
|
53
|
-
rawNode: buildIncomingEventRawNode(node),
|
|
54
|
-
stanzaId: node.attrs.id,
|
|
55
|
-
chatJid: node.attrs.from,
|
|
56
|
-
stanzaType: node.attrs.type
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
51
|
function pickSenderKeyDistributionPayload(message) {
|
|
60
52
|
const direct = pickDirectSenderKeyDistributionPayload(message);
|
|
61
53
|
if (direct) {
|
|
@@ -181,7 +173,10 @@ async function decryptAndProcessEncNode(node, encNode, encType, senderJid, optio
|
|
|
181
173
|
if (shouldEmitIncomingMessage(message)) {
|
|
182
174
|
const chatJid = node.attrs.from;
|
|
183
175
|
options.emitIncomingMessage?.({
|
|
184
|
-
|
|
176
|
+
rawNode: buildIncomingEventRawNode(node),
|
|
177
|
+
stanzaId: node.attrs.id,
|
|
178
|
+
chatJid,
|
|
179
|
+
stanzaType: node.attrs.type,
|
|
185
180
|
timestampSeconds: parseOptionalInt(node.attrs.t),
|
|
186
181
|
senderJid,
|
|
187
182
|
encryptionType: encType,
|
|
@@ -202,7 +197,10 @@ async function decryptAndProcessEncNode(node, encNode, encType, senderJid, optio
|
|
|
202
197
|
message: toError(error).message
|
|
203
198
|
});
|
|
204
199
|
options.emitUnhandledStanza?.({
|
|
205
|
-
|
|
200
|
+
rawNode: buildIncomingEventRawNode(node),
|
|
201
|
+
stanzaId: node.attrs.id,
|
|
202
|
+
chatJid: node.attrs.from,
|
|
203
|
+
stanzaType: node.attrs.type,
|
|
206
204
|
reason: `message.decrypt_failed.${encType}`
|
|
207
205
|
});
|
|
208
206
|
return { success: false, encType, error };
|
|
@@ -233,7 +231,10 @@ export async function handleIncomingMessageAck(node, options) {
|
|
|
233
231
|
case 'skmsg': {
|
|
234
232
|
if (!senderJid || !node.attrs.from || !options.senderKeyManager) {
|
|
235
233
|
options.emitUnhandledStanza?.({
|
|
236
|
-
|
|
234
|
+
rawNode: buildIncomingEventRawNode(node),
|
|
235
|
+
stanzaId: node.attrs.id,
|
|
236
|
+
chatJid: node.attrs.from,
|
|
237
|
+
stanzaType: node.attrs.type,
|
|
237
238
|
reason: 'message.skmsg.missing_group_context'
|
|
238
239
|
});
|
|
239
240
|
continue;
|
|
@@ -275,7 +276,8 @@ export async function handleIncomingMessageAck(node, options) {
|
|
|
275
276
|
});
|
|
276
277
|
}
|
|
277
278
|
if (encCount > 0 && !hasSuccessfulDecrypt && firstDecryptFailure) {
|
|
278
|
-
|
|
279
|
+
await sendRetryReceiptForDecryptFailure(node, options, firstDecryptFailure.error, firstDecryptFailure.encType);
|
|
280
|
+
shouldSendStandardReceipt = false;
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
283
|
const id = node.attrs.id;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { sha256 } from '../crypto/core/index.js';
|
|
2
|
-
import { splitJid } from '../protocol/jid.js';
|
|
3
2
|
import { bytesToBase64, TEXT_ENCODER } from '../util/bytes.js';
|
|
4
3
|
export async function computePhashV2(participants) {
|
|
5
4
|
if (participants.length === 0) {
|
|
@@ -13,15 +12,36 @@ export async function computePhashV2(participants) {
|
|
|
13
12
|
return `2:${bytesToBase64(digest.subarray(0, 6))}`;
|
|
14
13
|
}
|
|
15
14
|
function toPhashCanonicalWid(jid) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
const atIndex = jid.indexOf('@');
|
|
16
|
+
if (atIndex < 1 || atIndex >= jid.length - 1)
|
|
17
|
+
return jid;
|
|
18
|
+
const colonIndex = jid.indexOf(':', 0);
|
|
19
|
+
const userEnd = colonIndex >= 0 && colonIndex < atIndex ? colonIndex : atIndex;
|
|
20
|
+
const hasZeroAgent = userEnd >= 2 && jid.charCodeAt(userEnd - 2) === 46 && jid.charCodeAt(userEnd - 1) === 48;
|
|
21
|
+
const baseUserEnd = hasZeroAgent ? userEnd - 2 : userEnd;
|
|
22
|
+
const baseUser = jid.slice(0, baseUserEnd);
|
|
23
|
+
let device = 0;
|
|
24
|
+
if (colonIndex >= 0 && colonIndex < atIndex) {
|
|
25
|
+
for (let i = colonIndex + 1; i < atIndex; i += 1) {
|
|
26
|
+
const digit = jid.charCodeAt(i) - 48;
|
|
27
|
+
if (digit < 0 || digit > 9) {
|
|
28
|
+
device = 0;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
device = device * 10 + digit;
|
|
32
|
+
if (device > Number.MAX_SAFE_INTEGER) {
|
|
33
|
+
device = 0;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const serverStart = atIndex + 1;
|
|
39
|
+
const serverLen = jid.length - serverStart;
|
|
40
|
+
const isCUs = serverLen === 4 &&
|
|
41
|
+
jid.charCodeAt(serverStart) === 99 &&
|
|
42
|
+
jid.charCodeAt(serverStart + 1) === 46 &&
|
|
43
|
+
jid.charCodeAt(serverStart + 2) === 117 &&
|
|
44
|
+
jid.charCodeAt(serverStart + 3) === 115;
|
|
45
|
+
const normalizedServer = isCUs ? 's.whatsapp.net' : jid.slice(serverStart);
|
|
46
|
+
return `${baseUser}.0:${device}@${normalizedServer}`;
|
|
27
47
|
}
|