zapo-js 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -7
- package/dist/appstate/WaAppStateCrypto.js +18 -25
- package/dist/appstate/WaAppStateSyncClient.js +181 -114
- package/dist/appstate/WaAppStateSyncResponseParser.js +16 -5
- package/dist/appstate/constants.js +4 -3
- package/dist/appstate/utils.js +10 -30
- package/dist/auth/WaAuthClient.js +48 -55
- package/dist/auth/flow/WaAuthCredentialsFlow.js +21 -14
- package/dist/auth/index.js +1 -3
- package/dist/auth/pairing/WaPairingFlow.js +21 -23
- package/dist/auth/pairing/WaQrFlow.js +37 -24
- package/dist/client/WaClient.js +103 -276
- package/dist/client/WaClientFactory.js +227 -110
- package/dist/client/connection/WaConnectionManager.js +292 -0
- package/dist/client/connection/WaKeyShareCoordinator.js +63 -0
- package/dist/client/connection/WaReceiptQueue.js +51 -0
- package/dist/client/coordinators/WaAppStateMutationCoordinator.js +471 -0
- package/dist/client/coordinators/WaGroupCoordinator.js +27 -17
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +231 -686
- package/dist/client/coordinators/WaRetryCoordinator.js +70 -37
- package/dist/client/dirty.js +35 -29
- package/dist/client/events/chat.js +4 -3
- package/dist/client/events/group.js +59 -36
- package/dist/client/history-sync.js +53 -63
- package/dist/client/incoming.js +23 -20
- package/dist/client/mailbox.js +8 -8
- package/dist/client/messages.js +4 -4
- package/dist/client/messaging/fanout.js +189 -0
- package/dist/client/messaging/key-protocol.js +130 -0
- package/dist/client/messaging/participants.js +191 -0
- package/dist/crypto/core/hkdf.js +3 -8
- package/dist/crypto/core/index.js +1 -4
- package/dist/crypto/core/keys.js +2 -3
- package/dist/crypto/core/primitives.js +12 -15
- package/dist/crypto/core/random.js +7 -26
- package/dist/crypto/curves/Ed25519.js +7 -8
- package/dist/crypto/curves/X25519.js +13 -16
- package/dist/crypto/index.js +0 -5
- package/dist/esm/appstate/WaAppStateCrypto.js +6 -13
- package/dist/esm/appstate/WaAppStateSyncClient.js +174 -107
- package/dist/esm/appstate/WaAppStateSyncResponseParser.js +17 -6
- package/dist/esm/appstate/constants.js +3 -2
- package/dist/esm/appstate/utils.js +8 -27
- package/dist/esm/auth/WaAuthClient.js +48 -55
- package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +21 -14
- package/dist/esm/auth/index.js +0 -1
- package/dist/esm/auth/pairing/WaPairingFlow.js +14 -16
- package/dist/esm/auth/pairing/WaQrFlow.js +37 -24
- package/dist/esm/client/WaClient.js +103 -276
- package/dist/esm/client/WaClientFactory.js +227 -110
- package/dist/esm/client/connection/WaConnectionManager.js +288 -0
- package/dist/esm/client/connection/WaKeyShareCoordinator.js +59 -0
- package/dist/esm/client/connection/WaReceiptQueue.js +47 -0
- package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +467 -0
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +20 -10
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +20 -27
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +232 -687
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +71 -38
- package/dist/esm/client/dirty.js +30 -24
- package/dist/esm/client/events/chat.js +4 -3
- package/dist/esm/client/events/group.js +50 -28
- package/dist/esm/client/history-sync.js +50 -60
- package/dist/esm/client/incoming.js +23 -20
- package/dist/esm/client/mailbox.js +8 -8
- package/dist/esm/client/messages.js +1 -1
- package/dist/esm/client/messaging/fanout.js +186 -0
- package/dist/esm/client/messaging/key-protocol.js +127 -0
- package/dist/esm/client/messaging/participants.js +188 -0
- package/dist/esm/crypto/core/hkdf.js +3 -8
- package/dist/esm/crypto/core/index.js +0 -1
- package/dist/esm/crypto/core/keys.js +2 -3
- package/dist/esm/crypto/core/primitives.js +12 -15
- package/dist/esm/crypto/core/random.js +6 -25
- package/dist/esm/crypto/curves/Ed25519.js +4 -5
- package/dist/esm/crypto/curves/X25519.js +10 -13
- package/dist/esm/crypto/index.js +0 -2
- package/dist/esm/infra/log/ConsoleLogger.js +18 -17
- package/dist/esm/infra/log/PinoLogger.js +15 -9
- package/dist/esm/infra/log/types.js +11 -1
- package/dist/esm/infra/perf/BoundedTaskQueue.js +13 -17
- package/dist/esm/media/WaMediaCrypto.js +2 -4
- package/dist/esm/media/WaMediaTransferClient.js +226 -58
- package/dist/esm/media/conn.js +10 -6
- package/dist/esm/media/constants.js +4 -1
- package/dist/esm/message/WaMessageClient.js +4 -13
- package/dist/esm/message/ack.js +6 -6
- package/dist/esm/message/addon-crypto.js +59 -0
- package/dist/esm/message/incoming.js +106 -111
- package/dist/esm/message/index.js +2 -0
- package/dist/esm/message/reporting-token.js +438 -0
- package/dist/esm/message/use-case-secret.js +49 -0
- package/dist/esm/protocol/appstate.js +58 -0
- package/dist/esm/protocol/constants.js +2 -1
- package/dist/esm/protocol/index.js +2 -10
- package/dist/esm/protocol/jid.js +63 -51
- package/dist/esm/protocol/media.js +3 -3
- package/dist/esm/protocol/nodes.js +2 -0
- package/dist/esm/protocol/usync.js +11 -0
- package/dist/esm/retry/index.js +1 -0
- package/dist/esm/retry/outbound.js +4 -5
- package/dist/esm/retry/parse.js +58 -76
- package/dist/esm/retry/replay.js +48 -49
- package/dist/esm/retry/tracker.js +56 -0
- package/dist/esm/signal/api/SignalDeviceSyncApi.js +249 -82
- package/dist/esm/signal/api/SignalDigestSyncApi.js +6 -1
- package/dist/esm/signal/api/SignalIdentitySyncApi.js +49 -34
- package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +70 -62
- package/dist/esm/signal/api/SignalSessionSyncApi.js +23 -30
- package/dist/esm/signal/crypto/WaAdvSignature.js +3 -5
- package/dist/esm/signal/group/SenderKeyChain.js +28 -23
- package/dist/esm/signal/group/SenderKeyCodec.js +2 -4
- package/dist/esm/signal/group/SenderKeyManager.js +26 -16
- package/dist/esm/signal/index.js +1 -0
- package/dist/esm/signal/session/SignalProtocol.js +49 -14
- package/dist/esm/signal/session/SignalRatchet.js +24 -15
- package/dist/esm/signal/session/SignalSession.js +14 -9
- package/dist/esm/signal/session/resolver.js +186 -0
- package/dist/esm/signal/store/sqlite.js +16 -37
- package/dist/esm/store/createStore.js +16 -18
- package/dist/esm/store/noop.store.js +3 -6
- package/dist/esm/store/providers/memory/appstate.store.js +30 -6
- package/dist/esm/store/providers/memory/contact.store.js +5 -0
- package/dist/esm/store/providers/memory/device-list.store.js +3 -30
- package/dist/esm/store/providers/memory/message.store.js +11 -5
- package/dist/esm/store/providers/memory/participants.store.js +1 -8
- package/dist/esm/store/providers/memory/sender-key.store.js +5 -7
- package/dist/esm/store/providers/memory/signal.store.js +13 -1
- package/dist/esm/store/providers/memory/thread.store.js +5 -0
- package/dist/esm/store/providers/sqlite/appstate.store.js +82 -1
- package/dist/esm/store/providers/sqlite/connection.js +18 -13
- package/dist/esm/store/providers/sqlite/contact.store.js +31 -18
- package/dist/esm/store/providers/sqlite/device-list.store.js +7 -35
- package/dist/esm/store/providers/sqlite/message.store.js +45 -32
- package/dist/esm/store/providers/sqlite/migrations.js +1 -1
- package/dist/esm/store/providers/sqlite/participants.store.js +1 -9
- package/dist/esm/store/providers/sqlite/retry.store.js +8 -11
- package/dist/esm/store/providers/sqlite/sender-key.store.js +25 -30
- package/dist/esm/store/providers/sqlite/signal.store.js +104 -22
- package/dist/esm/store/providers/sqlite/table-names.js +107 -0
- package/dist/esm/store/providers/sqlite/thread.store.js +35 -22
- package/dist/esm/transport/WaComms.js +25 -23
- package/dist/esm/transport/WaWebSocket.js +115 -12
- package/dist/esm/transport/binary/decoder.js +4 -4
- package/dist/esm/transport/binary/encoder.js +12 -4
- package/dist/esm/transport/index.js +1 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +2 -8
- package/dist/esm/transport/node/WaNodeOrchestrator.js +2 -4
- package/dist/esm/transport/node/WaNodeTransport.js +0 -3
- package/dist/esm/transport/node/builders/{accountSync.js → account-sync.js} +16 -36
- package/dist/esm/transport/node/builders/index.js +2 -1
- package/dist/esm/transport/node/builders/message.js +9 -0
- package/dist/esm/transport/node/builders/pairing.js +4 -5
- package/dist/esm/transport/node/builders/usync.js +41 -0
- package/dist/esm/transport/node/helpers.js +107 -5
- package/dist/esm/transport/node/usync.js +35 -0
- package/dist/esm/transport/noise/WaFrameCodec.js +48 -33
- package/dist/esm/transport/noise/WaNoiseCert.js +3 -6
- package/dist/esm/transport/noise/WaNoiseSession.js +17 -10
- package/dist/esm/transport/proxy.js +27 -0
- package/dist/esm/transport/stream/parse.js +13 -48
- package/dist/esm/util/bytes.js +50 -32
- package/dist/esm/util/coercion.js +6 -14
- package/dist/esm/util/primitives.js +39 -14
- package/dist/infra/log/ConsoleLogger.js +18 -17
- package/dist/infra/log/PinoLogger.js +15 -9
- package/dist/infra/log/types.js +12 -0
- package/dist/infra/perf/BoundedTaskQueue.js +13 -17
- package/dist/media/WaMediaCrypto.js +1 -3
- package/dist/media/WaMediaTransferClient.js +259 -58
- package/dist/media/conn.js +10 -6
- package/dist/media/constants.js +4 -1
- package/dist/message/WaMessageClient.js +5 -14
- package/dist/message/ack.js +6 -6
- package/dist/message/addon-crypto.js +65 -0
- package/dist/message/incoming.js +104 -109
- package/dist/message/index.js +2 -0
- package/dist/message/reporting-token.js +443 -0
- package/dist/message/use-case-secret.js +55 -0
- package/dist/protocol/appstate.js +59 -1
- package/dist/protocol/constants.js +7 -1
- package/dist/protocol/index.js +20 -42
- package/dist/protocol/jid.js +64 -51
- package/dist/protocol/media.js +3 -3
- package/dist/protocol/nodes.js +2 -0
- package/dist/protocol/usync.js +14 -0
- package/dist/retry/index.js +3 -1
- package/dist/retry/outbound.js +6 -7
- package/dist/retry/parse.js +57 -75
- package/dist/retry/replay.js +46 -47
- package/dist/retry/tracker.js +59 -0
- package/dist/signal/api/SignalDeviceSyncApi.js +247 -80
- package/dist/signal/api/SignalDigestSyncApi.js +6 -1
- package/dist/signal/api/SignalIdentitySyncApi.js +49 -34
- package/dist/signal/api/SignalMissingPreKeysSyncApi.js +67 -59
- package/dist/signal/api/SignalSessionSyncApi.js +23 -30
- package/dist/signal/crypto/WaAdvSignature.js +2 -4
- package/dist/signal/group/SenderKeyChain.js +27 -22
- package/dist/signal/group/SenderKeyCodec.js +1 -3
- package/dist/signal/group/SenderKeyManager.js +26 -16
- package/dist/signal/index.js +3 -1
- package/dist/signal/session/SignalProtocol.js +49 -14
- package/dist/signal/session/SignalRatchet.js +24 -15
- package/dist/signal/session/SignalSession.js +14 -9
- package/dist/signal/session/resolver.js +189 -0
- package/dist/signal/store/sqlite.js +16 -37
- package/dist/store/createStore.js +16 -18
- package/dist/store/noop.store.js +3 -6
- package/dist/store/providers/memory/appstate.store.js +28 -4
- package/dist/store/providers/memory/contact.store.js +5 -0
- package/dist/store/providers/memory/device-list.store.js +3 -30
- package/dist/store/providers/memory/message.store.js +11 -5
- package/dist/store/providers/memory/participants.store.js +1 -8
- package/dist/store/providers/memory/sender-key.store.js +8 -10
- package/dist/store/providers/memory/signal.store.js +21 -9
- package/dist/store/providers/memory/thread.store.js +5 -0
- package/dist/store/providers/sqlite/appstate.store.js +81 -0
- package/dist/store/providers/sqlite/connection.js +18 -13
- package/dist/store/providers/sqlite/contact.store.js +31 -18
- package/dist/store/providers/sqlite/device-list.store.js +7 -35
- package/dist/store/providers/sqlite/message.store.js +45 -32
- package/dist/store/providers/sqlite/migrations.js +1 -1
- package/dist/store/providers/sqlite/participants.store.js +1 -9
- package/dist/store/providers/sqlite/retry.store.js +8 -11
- package/dist/store/providers/sqlite/sender-key.store.js +24 -29
- package/dist/store/providers/sqlite/signal.store.js +105 -23
- package/dist/store/providers/sqlite/table-names.js +113 -0
- package/dist/store/providers/sqlite/thread.store.js +35 -22
- package/dist/transport/WaComms.js +27 -25
- package/dist/transport/WaWebSocket.js +148 -12
- package/dist/transport/binary/decoder.js +4 -4
- package/dist/transport/binary/encoder.js +12 -4
- package/dist/transport/index.js +7 -1
- package/dist/transport/keepalive/WaKeepAlive.js +1 -7
- package/dist/transport/node/WaNodeOrchestrator.js +2 -4
- package/dist/transport/node/WaNodeTransport.js +0 -3
- package/dist/transport/node/builders/{accountSync.js → account-sync.js} +15 -35
- package/dist/transport/node/builders/index.js +12 -9
- package/dist/transport/node/builders/message.js +9 -0
- package/dist/transport/node/builders/pairing.js +4 -5
- package/dist/transport/node/builders/usync.js +45 -0
- package/dist/transport/node/helpers.js +112 -4
- package/dist/transport/node/usync.js +38 -0
- package/dist/transport/noise/WaFrameCodec.js +47 -32
- package/dist/transport/noise/WaNoiseCert.js +5 -8
- package/dist/transport/noise/WaNoiseSession.js +17 -10
- package/dist/transport/proxy.js +34 -0
- package/dist/transport/stream/parse.js +17 -53
- package/dist/types/appstate/WaAppStateCrypto.d.ts +0 -1
- package/dist/types/appstate/WaAppStateSyncClient.d.ts +5 -2
- package/dist/types/appstate/constants.d.ts +1 -0
- package/dist/types/appstate/store/sqlite.d.ts +4 -18
- package/dist/types/appstate/utils.d.ts +0 -1
- package/dist/types/auth/WaAuthClient.d.ts +10 -12
- package/dist/types/auth/index.d.ts +0 -2
- package/dist/types/auth/pairing/WaQrFlow.d.ts +1 -1
- package/dist/types/auth/types.d.ts +6 -9
- package/dist/types/client/WaClient.d.ts +27 -25
- package/dist/types/client/WaClientFactory.d.ts +22 -23
- package/dist/types/client/connection/WaConnectionManager.d.ts +64 -0
- package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +14 -0
- package/dist/types/client/connection/WaReceiptQueue.d.ts +13 -0
- package/dist/types/client/coordinators/WaAppStateMutationCoordinator.d.ts +46 -0
- package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +0 -1
- package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +18 -41
- package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +2 -0
- package/dist/types/client/dirty.d.ts +1 -0
- package/dist/types/client/events/group.d.ts +2 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/messaging/fanout.d.ts +14 -0
- package/dist/types/client/messaging/key-protocol.d.ts +18 -0
- package/dist/types/client/messaging/participants.d.ts +13 -0
- package/dist/types/client/types.d.ts +24 -1
- package/dist/types/crypto/core/hkdf.d.ts +0 -6
- package/dist/types/crypto/core/index.d.ts +0 -1
- package/dist/types/crypto/core/random.d.ts +1 -7
- package/dist/types/crypto/index.d.ts +0 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/infra/log/ConsoleLogger.d.ts +2 -1
- package/dist/types/infra/log/PinoLogger.d.ts +1 -1
- package/dist/types/infra/log/types.d.ts +1 -0
- package/dist/types/infra/perf/BoundedTaskQueue.d.ts +1 -1
- package/dist/types/media/WaMediaTransferClient.d.ts +13 -3
- package/dist/types/media/types.d.ts +5 -0
- package/dist/types/message/addon-crypto.d.ts +25 -0
- package/dist/types/message/index.d.ts +2 -0
- package/dist/types/message/reporting-token.d.ts +19 -0
- package/dist/types/message/use-case-secret.d.ts +20 -0
- package/dist/types/protocol/appstate.d.ts +58 -0
- package/dist/types/protocol/constants.d.ts +2 -1
- package/dist/types/protocol/index.d.ts +2 -10
- package/dist/types/protocol/jid.d.ts +3 -3
- package/dist/types/protocol/nodes.d.ts +2 -0
- package/dist/types/protocol/usync.d.ts +11 -0
- package/dist/types/retry/index.d.ts +1 -0
- package/dist/types/retry/replay.d.ts +0 -4
- package/dist/types/retry/tracker.d.ts +19 -0
- package/dist/types/retry/types.d.ts +4 -3
- package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +13 -1
- package/dist/types/signal/group/SenderKeyCodec.d.ts +4 -6
- package/dist/types/signal/index.d.ts +1 -0
- package/dist/types/signal/session/SignalProtocol.d.ts +9 -0
- package/dist/types/signal/session/resolver.d.ts +17 -0
- package/dist/types/store/contracts/appstate.store.d.ts +3 -0
- package/dist/types/store/contracts/contact.store.d.ts +1 -0
- package/dist/types/store/contracts/device-list.store.d.ts +0 -3
- package/dist/types/store/contracts/message.store.d.ts +1 -0
- package/dist/types/store/contracts/participants.store.d.ts +0 -1
- package/dist/types/store/contracts/sender-key.store.d.ts +0 -1
- package/dist/types/store/contracts/signal.store.d.ts +6 -0
- package/dist/types/store/contracts/thread.store.d.ts +1 -0
- package/dist/types/store/index.d.ts +1 -1
- package/dist/types/store/providers/memory/appstate.store.d.ts +2 -0
- package/dist/types/store/providers/memory/contact.store.d.ts +1 -0
- package/dist/types/store/providers/memory/device-list.store.d.ts +0 -3
- package/dist/types/store/providers/memory/message.store.d.ts +1 -0
- package/dist/types/store/providers/memory/participants.store.d.ts +0 -1
- package/dist/types/store/providers/memory/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/memory/signal.store.d.ts +6 -0
- package/dist/types/store/providers/memory/thread.store.d.ts +1 -0
- package/dist/types/store/providers/sqlite/appstate.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/contact.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -3
- package/dist/types/store/providers/sqlite/message.store.d.ts +2 -0
- package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -1
- package/dist/types/store/providers/sqlite/signal.store.d.ts +7 -0
- package/dist/types/store/providers/sqlite/table-names.d.ts +5 -0
- package/dist/types/store/providers/sqlite/thread.store.d.ts +2 -0
- package/dist/types/store/types.d.ts +3 -0
- package/dist/types/transport/WaWebSocket.d.ts +3 -0
- package/dist/types/transport/index.d.ts +2 -1
- package/dist/types/transport/keepalive/WaKeepAlive.d.ts +0 -1
- package/dist/types/transport/node/WaNodeTransport.d.ts +0 -9
- package/dist/types/transport/node/builders/group.d.ts +4 -6
- package/dist/types/transport/node/builders/index.d.ts +2 -1
- package/dist/types/transport/node/builders/message.d.ts +14 -25
- package/dist/types/transport/node/builders/retry.d.ts +2 -4
- package/dist/types/transport/node/builders/usync.d.ts +21 -0
- package/dist/types/transport/node/helpers.d.ts +8 -0
- package/dist/types/transport/node/usync.d.ts +2 -0
- package/dist/types/transport/noise/WaFrameCodec.d.ts +3 -0
- package/dist/types/transport/noise/WaNoiseSession.d.ts +1 -0
- package/dist/types/transport/proxy.d.ts +6 -0
- package/dist/types/transport/stream/parse.d.ts +0 -1
- package/dist/types/transport/types.d.ts +18 -1
- package/dist/types/util/bytes.d.ts +5 -0
- package/dist/types/util/primitives.d.ts +3 -0
- package/dist/util/bytes.js +55 -33
- package/dist/util/coercion.js +6 -14
- package/dist/util/primitives.js +42 -14
- package/package.json +27 -9
- package/proto/index.d.ts +1090 -1048
- package/proto/index.js +1 -1
- package/scripts/check-node-version.cjs +0 -1
- package/dist/crypto/core/encoding.js +0 -29
- package/dist/esm/crypto/core/encoding.js +0 -25
- package/dist/esm/util/base64.js +0 -18
- package/dist/esm/util/signal-address.js +0 -5
- package/dist/types/crypto/core/encoding.d.ts +0 -11
- package/dist/types/util/base64.d.ts +0 -4
- package/dist/types/util/signal-address.d.ts +0 -2
- package/dist/util/base64.js +0 -24
- package/dist/util/signal-address.js +0 -8
- /package/dist/types/transport/node/builders/{accountSync.d.ts → account-sync.d.ts} +0 -0
|
@@ -4,27 +4,95 @@ import { WaMediaCrypto } from './WaMediaCrypto.js';
|
|
|
4
4
|
import { WA_DEFAULTS } from '../protocol/constants.js';
|
|
5
5
|
import { EMPTY_BYTES, readAllBytes } from '../util/bytes.js';
|
|
6
6
|
import { toError } from '../util/primitives.js';
|
|
7
|
+
const GOT_OPTIONAL_MODULE = 'got';
|
|
8
|
+
function normalizeHeaderRecord(headers) {
|
|
9
|
+
if (!headers) {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
const normalized = {};
|
|
13
|
+
for (const key in headers) {
|
|
14
|
+
normalized[key.toLowerCase()] = headers[key];
|
|
15
|
+
}
|
|
16
|
+
return normalized;
|
|
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
|
+
}
|
|
7
68
|
export class WaMediaTransferClient {
|
|
8
69
|
constructor(options = {}) {
|
|
9
70
|
this.logger = options.logger;
|
|
10
71
|
this.defaultHosts = options.defaultHosts ?? DEFAULT_MEDIA_HOSTS;
|
|
11
72
|
this.defaultTimeoutMs = options.defaultTimeoutMs ?? WA_DEFAULTS.MEDIA_TIMEOUT_MS;
|
|
12
73
|
this.defaultMaxReadBytes = options.defaultMaxReadBytes;
|
|
13
|
-
this.defaultHeaders = options.defaultHeaders
|
|
74
|
+
this.defaultHeaders = normalizeHeaderRecord(options.defaultHeaders);
|
|
75
|
+
this.defaultUploadDispatcher = options.defaultUploadDispatcher;
|
|
76
|
+
this.defaultDownloadDispatcher = options.defaultDownloadDispatcher;
|
|
77
|
+
this.defaultUploadAgent = options.defaultUploadAgent;
|
|
78
|
+
this.defaultDownloadAgent = options.defaultDownloadAgent;
|
|
79
|
+
this.gotModulePromise = null;
|
|
14
80
|
}
|
|
15
81
|
async downloadStream(request) {
|
|
16
82
|
const { urls, headers, timeoutMs } = this.resolveTransferRequest(request);
|
|
83
|
+
const dispatcher = request.dispatcher ?? this.defaultDownloadDispatcher;
|
|
84
|
+
const agent = request.agent ?? this.defaultDownloadAgent;
|
|
17
85
|
this.logger?.debug('media download stream start', {
|
|
18
86
|
urls: urls.length,
|
|
19
87
|
timeoutMs
|
|
20
88
|
});
|
|
21
89
|
return this.executeTransfer(urls, timeoutMs, request.signal, {
|
|
22
90
|
responseLog: 'media download stream response',
|
|
23
|
-
send: (url, signal) =>
|
|
91
|
+
send: (url, signal) => this.transferRequest(url, {
|
|
24
92
|
method: 'GET',
|
|
25
93
|
headers,
|
|
26
94
|
signal
|
|
27
|
-
})
|
|
95
|
+
}, dispatcher, agent)
|
|
28
96
|
});
|
|
29
97
|
}
|
|
30
98
|
async downloadBytes(request) {
|
|
@@ -43,6 +111,8 @@ export class WaMediaTransferClient {
|
|
|
43
111
|
? String(request.contentLength)
|
|
44
112
|
: undefined
|
|
45
113
|
});
|
|
114
|
+
const dispatcher = request.dispatcher ?? this.defaultUploadDispatcher;
|
|
115
|
+
const agent = request.agent ?? this.defaultUploadAgent;
|
|
46
116
|
const uploadUrls = bodyIsBytes ? urls : urls.slice(0, 1);
|
|
47
117
|
if (!bodyIsBytes && urls.length > 1) {
|
|
48
118
|
this.logger?.warn('upload stream fallback disabled for non-replayable body', {
|
|
@@ -59,20 +129,20 @@ export class WaMediaTransferClient {
|
|
|
59
129
|
responseLog: 'media upload stream response',
|
|
60
130
|
send: async (url, signal) => {
|
|
61
131
|
if (bodyIsBytes) {
|
|
62
|
-
return
|
|
132
|
+
return this.transferRequest(url, {
|
|
63
133
|
method,
|
|
64
134
|
headers,
|
|
65
135
|
signal,
|
|
66
136
|
body: request.body
|
|
67
|
-
});
|
|
137
|
+
}, dispatcher, agent);
|
|
68
138
|
}
|
|
69
|
-
return
|
|
139
|
+
return this.transferRequest(url, {
|
|
70
140
|
method,
|
|
71
141
|
headers,
|
|
72
142
|
signal,
|
|
73
143
|
body: request.body,
|
|
74
144
|
duplex: 'half'
|
|
75
|
-
});
|
|
145
|
+
}, dispatcher, agent);
|
|
76
146
|
}
|
|
77
147
|
});
|
|
78
148
|
}
|
|
@@ -89,6 +159,8 @@ export class WaMediaTransferClient {
|
|
|
89
159
|
directPath: request.directPath,
|
|
90
160
|
hosts: request.hosts,
|
|
91
161
|
headers: request.headers,
|
|
162
|
+
dispatcher: request.dispatcher,
|
|
163
|
+
agent: request.agent,
|
|
92
164
|
timeoutMs: request.timeoutMs,
|
|
93
165
|
signal: request.signal,
|
|
94
166
|
method: request.method,
|
|
@@ -118,10 +190,8 @@ export class WaMediaTransferClient {
|
|
|
118
190
|
});
|
|
119
191
|
const decrypted = await this.downloadAndDecryptStream(request);
|
|
120
192
|
try {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
decrypted.metadata
|
|
124
|
-
]);
|
|
193
|
+
const plaintext = await this.readAllBytesWithLimit(decrypted.plaintext, request.maxBytes);
|
|
194
|
+
await decrypted.metadata;
|
|
125
195
|
this.logger?.info('media encrypted download completed', {
|
|
126
196
|
byteLength: plaintext.byteLength
|
|
127
197
|
});
|
|
@@ -157,11 +227,133 @@ export class WaMediaTransferClient {
|
|
|
157
227
|
}
|
|
158
228
|
return this.readAllBytesWithLimit(response.body, maxBytes);
|
|
159
229
|
}
|
|
230
|
+
async transferRequest(url, init, dispatcher, agent) {
|
|
231
|
+
if (agent) {
|
|
232
|
+
return this.gotWithAgent(url, init, agent);
|
|
233
|
+
}
|
|
234
|
+
return this.fetchWithDispatcher(url, init, dispatcher);
|
|
235
|
+
}
|
|
236
|
+
async fetchWithDispatcher(url, init, dispatcher) {
|
|
237
|
+
const response = !dispatcher
|
|
238
|
+
? await fetch(url, init)
|
|
239
|
+
: await fetch(url, {
|
|
240
|
+
...init,
|
|
241
|
+
dispatcher
|
|
242
|
+
});
|
|
243
|
+
return this.toFetchTransferResponse(response);
|
|
244
|
+
}
|
|
245
|
+
toFetchTransferResponse(response) {
|
|
246
|
+
return {
|
|
247
|
+
status: response.status,
|
|
248
|
+
ok: response.ok,
|
|
249
|
+
headers: this.headersToRecord(response.headers),
|
|
250
|
+
body: response.body
|
|
251
|
+
? Readable.fromWeb(response.body)
|
|
252
|
+
: null,
|
|
253
|
+
cancel: async () => {
|
|
254
|
+
if (!response.body) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
await response.body.cancel();
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// ignore cancel errors from remote resets
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
async gotWithAgent(url, init, agent) {
|
|
267
|
+
const got = await this.loadGotModule();
|
|
268
|
+
const urlObj = new URL(url);
|
|
269
|
+
const gotAgent = urlObj.protocol === 'http:'
|
|
270
|
+
? { http: agent }
|
|
271
|
+
: urlObj.protocol === 'https:'
|
|
272
|
+
? { https: agent }
|
|
273
|
+
: { http: agent, https: agent };
|
|
274
|
+
return new Promise((resolve, reject) => {
|
|
275
|
+
const request = got.stream(url, {
|
|
276
|
+
method: init.method,
|
|
277
|
+
headers: (init.headers ?? {}),
|
|
278
|
+
body: init.body,
|
|
279
|
+
signal: init.signal,
|
|
280
|
+
throwHttpErrors: false,
|
|
281
|
+
retry: { limit: 0 },
|
|
282
|
+
agent: gotAgent
|
|
283
|
+
});
|
|
284
|
+
const onError = (error) => {
|
|
285
|
+
request.off('response', onResponse);
|
|
286
|
+
reject(toError(error));
|
|
287
|
+
};
|
|
288
|
+
const onResponse = (incoming) => {
|
|
289
|
+
request.off('error', onError);
|
|
290
|
+
resolve(this.toGotTransferResponse(incoming));
|
|
291
|
+
};
|
|
292
|
+
request.once('error', onError);
|
|
293
|
+
request.once('response', onResponse);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
async loadGotModule() {
|
|
297
|
+
if (!this.gotModulePromise) {
|
|
298
|
+
this.gotModulePromise = loadOptionalGotModule().catch((error) => {
|
|
299
|
+
this.gotModulePromise = null;
|
|
300
|
+
throw error;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return this.gotModulePromise;
|
|
304
|
+
}
|
|
305
|
+
toGotTransferResponse(incoming) {
|
|
306
|
+
if (!incoming || typeof incoming !== 'object') {
|
|
307
|
+
throw new Error('invalid got response object');
|
|
308
|
+
}
|
|
309
|
+
const stream = incoming;
|
|
310
|
+
const status = typeof stream.statusCode === 'number' &&
|
|
311
|
+
Number.isFinite(stream.statusCode) &&
|
|
312
|
+
stream.statusCode >= 100 &&
|
|
313
|
+
stream.statusCode <= 599
|
|
314
|
+
? stream.statusCode
|
|
315
|
+
: 500;
|
|
316
|
+
const headers = {};
|
|
317
|
+
if (stream.headers && typeof stream.headers === 'object') {
|
|
318
|
+
const input = stream.headers;
|
|
319
|
+
for (const key in input) {
|
|
320
|
+
const value = input[key];
|
|
321
|
+
if (typeof value === 'string') {
|
|
322
|
+
headers[key] = value;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (Array.isArray(value)) {
|
|
326
|
+
headers[key] = value.join(', ');
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (value !== undefined && value !== null) {
|
|
330
|
+
headers[key] = String(value);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
status,
|
|
336
|
+
ok: status >= 200 && status < 300,
|
|
337
|
+
headers,
|
|
338
|
+
body: stream,
|
|
339
|
+
cancel: async () => {
|
|
340
|
+
stream.destroy();
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
160
344
|
resolveTransferRequest(request, extraHeaders) {
|
|
161
|
-
const headers = this.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
headers[key.toLowerCase()] =
|
|
345
|
+
const headers = { ...this.defaultHeaders };
|
|
346
|
+
if (request.headers) {
|
|
347
|
+
for (const key in request.headers) {
|
|
348
|
+
headers[key.toLowerCase()] = request.headers[key];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (extraHeaders) {
|
|
352
|
+
for (const key in extraHeaders) {
|
|
353
|
+
const value = extraHeaders[key];
|
|
354
|
+
if (value !== undefined) {
|
|
355
|
+
headers[key.toLowerCase()] = value;
|
|
356
|
+
}
|
|
165
357
|
}
|
|
166
358
|
}
|
|
167
359
|
return {
|
|
@@ -174,9 +366,9 @@ export class WaMediaTransferClient {
|
|
|
174
366
|
const result = await this.fetchWithFallback(urls, timeoutMs, signal, options.send);
|
|
175
367
|
this.logger?.trace(options.responseLog, {
|
|
176
368
|
url: result.url,
|
|
177
|
-
status: result.
|
|
369
|
+
status: result.status
|
|
178
370
|
});
|
|
179
|
-
return
|
|
371
|
+
return result;
|
|
180
372
|
}
|
|
181
373
|
async prepareEncryptedUpload(request, mediaKey) {
|
|
182
374
|
if (request.plaintext instanceof Uint8Array) {
|
|
@@ -219,34 +411,26 @@ export class WaMediaTransferClient {
|
|
|
219
411
|
}
|
|
220
412
|
resolveUrls(url, directPath, hosts) {
|
|
221
413
|
const resolved = [];
|
|
222
|
-
if (url)
|
|
414
|
+
if (url && resolved.indexOf(url) === -1)
|
|
223
415
|
resolved.push(url);
|
|
224
|
-
}
|
|
225
416
|
if (directPath) {
|
|
226
417
|
if (directPath.startsWith('https://') || directPath.startsWith('http://')) {
|
|
227
|
-
resolved.
|
|
418
|
+
if (resolved.indexOf(directPath) === -1)
|
|
419
|
+
resolved.push(directPath);
|
|
228
420
|
}
|
|
229
421
|
else {
|
|
230
422
|
const normalizedPath = directPath.startsWith('/') ? directPath : `/${directPath}`;
|
|
231
423
|
for (const host of hosts ?? this.defaultHosts) {
|
|
232
|
-
|
|
424
|
+
const candidate = `https://${host}${normalizedPath}`;
|
|
425
|
+
if (resolved.indexOf(candidate) === -1)
|
|
426
|
+
resolved.push(candidate);
|
|
233
427
|
}
|
|
234
428
|
}
|
|
235
429
|
}
|
|
236
430
|
if (resolved.length === 0) {
|
|
237
431
|
throw new Error('missing transfer url/directPath');
|
|
238
432
|
}
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
mergeHeaders(headers) {
|
|
242
|
-
const merged = {};
|
|
243
|
-
for (const [key, value] of Object.entries(this.defaultHeaders)) {
|
|
244
|
-
merged[key.toLowerCase()] = value;
|
|
245
|
-
}
|
|
246
|
-
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
247
|
-
merged[key.toLowerCase()] = value;
|
|
248
|
-
}
|
|
249
|
-
return merged;
|
|
433
|
+
return resolved;
|
|
250
434
|
}
|
|
251
435
|
readAllBytesWithLimit(stream, maxBytes) {
|
|
252
436
|
return readAllBytes(stream, {
|
|
@@ -262,9 +446,15 @@ export class WaMediaTransferClient {
|
|
|
262
446
|
const response = await send(url, abort.signal);
|
|
263
447
|
const shouldFallback = response.status >= 500 && index < urls.length - 1;
|
|
264
448
|
if (!shouldFallback) {
|
|
265
|
-
return {
|
|
449
|
+
return {
|
|
450
|
+
url,
|
|
451
|
+
status: response.status,
|
|
452
|
+
ok: response.ok,
|
|
453
|
+
headers: response.headers,
|
|
454
|
+
body: response.body
|
|
455
|
+
};
|
|
266
456
|
}
|
|
267
|
-
await
|
|
457
|
+
await response.cancel();
|
|
268
458
|
this.logger?.warn('transfer fallback to next host', {
|
|
269
459
|
url,
|
|
270
460
|
status: response.status
|
|
@@ -316,35 +506,13 @@ export class WaMediaTransferClient {
|
|
|
316
506
|
}
|
|
317
507
|
};
|
|
318
508
|
}
|
|
319
|
-
toResponse(url, response) {
|
|
320
|
-
return {
|
|
321
|
-
url,
|
|
322
|
-
status: response.status,
|
|
323
|
-
ok: response.ok,
|
|
324
|
-
headers: this.headersToRecord(response.headers),
|
|
325
|
-
body: response.body
|
|
326
|
-
? Readable.fromWeb(response.body)
|
|
327
|
-
: null
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
509
|
headersToRecord(headers) {
|
|
331
510
|
const output = {};
|
|
332
|
-
|
|
511
|
+
headers.forEach((value, key) => {
|
|
333
512
|
output[key] = value;
|
|
334
|
-
}
|
|
513
|
+
});
|
|
335
514
|
return output;
|
|
336
515
|
}
|
|
337
|
-
async cancelWebBody(body) {
|
|
338
|
-
if (!body) {
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
try {
|
|
342
|
-
await body.cancel();
|
|
343
|
-
}
|
|
344
|
-
catch {
|
|
345
|
-
// ignore cancel errors from remote resets
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
516
|
async drainBody(body) {
|
|
349
517
|
if (!body) {
|
|
350
518
|
return;
|
package/dist/esm/media/conn.js
CHANGED
|
@@ -16,12 +16,16 @@ export function parseMediaConnResponse(node, nowMs) {
|
|
|
16
16
|
throw new Error('media_conn response has invalid ttl');
|
|
17
17
|
}
|
|
18
18
|
const expiresAtMs = ttlRaw >= 1000000000 ? ttlRaw * 1000 : nowMs + ttlRaw * 1000;
|
|
19
|
-
const hosts =
|
|
20
|
-
|
|
21
|
-
hostname
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
const hosts = [];
|
|
20
|
+
for (const host of getNodeChildrenByTag(mediaConnNode, WA_NODE_TAGS.HOST)) {
|
|
21
|
+
const hostname = host.attrs.hostname;
|
|
22
|
+
if (hostname) {
|
|
23
|
+
hosts.push({
|
|
24
|
+
hostname,
|
|
25
|
+
isFallback: host.attrs.type === 'fallback'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
25
29
|
if (hosts.length === 0) {
|
|
26
30
|
throw new Error('media_conn response contains no hosts');
|
|
27
31
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export const DEFAULT_MEDIA_HOSTS = [
|
|
1
|
+
export const DEFAULT_MEDIA_HOSTS = Object.freeze([
|
|
2
|
+
'mmg.whatsapp.net',
|
|
3
|
+
'mmg-fallback.whatsapp.net'
|
|
4
|
+
]);
|
|
2
5
|
export const MEDIA_CONN_CACHE_GRACE_MS = 30000;
|
|
3
6
|
export const MEDIA_HKDF_SIZE = 112;
|
|
4
7
|
export const IV_SIZE = 16;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describeAckNode, isAckOrReceiptNode, isNegativeAckNode, isRetryableNegativeAck } from './ack.js';
|
|
2
2
|
import { WA_DEFAULTS, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_NODE_TAGS } from '../protocol/constants.js';
|
|
3
|
-
import { parseOptionalInt } from '../transport/stream/parse.js';
|
|
4
3
|
import { delay } from '../util/async.js';
|
|
5
|
-
import { toError } from '../util/primitives.js';
|
|
4
|
+
import { parseOptionalInt, toError } from '../util/primitives.js';
|
|
5
|
+
const WA_RETRYABLE_PUBLISH_ERROR_RE = /timeout|socket|connection|closed/i;
|
|
6
6
|
class MessagePublishNackError extends Error {
|
|
7
7
|
constructor(message, retryable) {
|
|
8
8
|
super(message);
|
|
@@ -102,12 +102,7 @@ export class WaMessageClient {
|
|
|
102
102
|
}
|
|
103
103
|
async sendEncrypted(input) {
|
|
104
104
|
const node = this.buildEncryptedMessageNode(input);
|
|
105
|
-
this.
|
|
106
|
-
to: node.attrs.to,
|
|
107
|
-
type: node.attrs.type,
|
|
108
|
-
id: node.attrs.id
|
|
109
|
-
});
|
|
110
|
-
await this.sendNode(node);
|
|
105
|
+
await this.sendMessageNode(node);
|
|
111
106
|
}
|
|
112
107
|
buildEncryptedMessageNode(input) {
|
|
113
108
|
const attrs = {
|
|
@@ -186,11 +181,7 @@ export class WaMessageClient {
|
|
|
186
181
|
});
|
|
187
182
|
}
|
|
188
183
|
isRetryablePublishError(error) {
|
|
189
|
-
|
|
190
|
-
return (message.includes('timeout') ||
|
|
191
|
-
message.includes('socket') ||
|
|
192
|
-
message.includes('connection') ||
|
|
193
|
-
message.includes('closed'));
|
|
184
|
+
return WA_RETRYABLE_PUBLISH_ERROR_RE.test(error.message);
|
|
194
185
|
}
|
|
195
186
|
extractAckMetadata(ackNode) {
|
|
196
187
|
const addressingModeRaw = ackNode.attrs.addressing_mode;
|
package/dist/esm/message/ack.js
CHANGED
|
@@ -25,22 +25,22 @@ export function isRetryableNegativeAck(node) {
|
|
|
25
25
|
return false;
|
|
26
26
|
}
|
|
27
27
|
export function describeAckNode(node) {
|
|
28
|
-
|
|
28
|
+
let description = `tag=${node.tag}`;
|
|
29
29
|
const id = node.attrs.id;
|
|
30
30
|
const type = node.attrs.type;
|
|
31
31
|
const ackClass = node.attrs.class;
|
|
32
32
|
const code = node.attrs.code;
|
|
33
33
|
if (id) {
|
|
34
|
-
|
|
34
|
+
description += ` id=${id}`;
|
|
35
35
|
}
|
|
36
36
|
if (type) {
|
|
37
|
-
|
|
37
|
+
description += ` type=${type}`;
|
|
38
38
|
}
|
|
39
39
|
if (ackClass) {
|
|
40
|
-
|
|
40
|
+
description += ` class=${ackClass}`;
|
|
41
41
|
}
|
|
42
42
|
if (code) {
|
|
43
|
-
|
|
43
|
+
description += ` code=${code}`;
|
|
44
44
|
}
|
|
45
|
-
return
|
|
45
|
+
return description;
|
|
46
46
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { aesGcmDecrypt, aesGcmEncrypt, importAesGcmKey } from '../crypto/index.js';
|
|
2
|
+
import { assertMessageSecret, createUseCaseSecret, WA_USE_CASE_SECRET_MODIFICATION_TYPES } from './use-case-secret.js';
|
|
3
|
+
import { EMPTY_BYTES, TEXT_ENCODER, toBytesView } from '../util/bytes.js';
|
|
4
|
+
const WA_ADDON_ENCRYPTION_NONCE_BYTES = 12;
|
|
5
|
+
export function shouldUseAddonAdditionalData(modificationType) {
|
|
6
|
+
return (modificationType === WA_USE_CASE_SECRET_MODIFICATION_TYPES.POLL_VOTE ||
|
|
7
|
+
modificationType === WA_USE_CASE_SECRET_MODIFICATION_TYPES.EVENT_RESPONSE);
|
|
8
|
+
}
|
|
9
|
+
export function buildAddonAdditionalData(stanzaId, addOnSenderJid) {
|
|
10
|
+
if (!stanzaId.trim()) {
|
|
11
|
+
throw new Error('stanza id must be a non-empty string');
|
|
12
|
+
}
|
|
13
|
+
if (!addOnSenderJid.trim()) {
|
|
14
|
+
throw new Error('addon sender jid must be a non-empty string');
|
|
15
|
+
}
|
|
16
|
+
return TEXT_ENCODER.encode(`${stanzaId}\u0000${addOnSenderJid}`);
|
|
17
|
+
}
|
|
18
|
+
export async function encryptAddonPayload(input) {
|
|
19
|
+
const secret = await createUseCaseSecret({
|
|
20
|
+
messageSecret: assertMessageSecret(input.messageSecret),
|
|
21
|
+
stanzaId: input.stanzaId,
|
|
22
|
+
parentMsgOriginalSender: input.parentMsgOriginalSender,
|
|
23
|
+
modificationSender: input.modificationSender,
|
|
24
|
+
modificationType: input.modificationType
|
|
25
|
+
});
|
|
26
|
+
const key = await importAesGcmKey(secret, ['encrypt']);
|
|
27
|
+
const iv = assertAddonIv(input.iv);
|
|
28
|
+
const additionalData = resolveAddonAdditionalData(input);
|
|
29
|
+
return aesGcmEncrypt(key, iv, toBytesView(input.payload), additionalData);
|
|
30
|
+
}
|
|
31
|
+
export async function decryptAddonPayload(input) {
|
|
32
|
+
const secret = await createUseCaseSecret({
|
|
33
|
+
messageSecret: assertMessageSecret(input.messageSecret),
|
|
34
|
+
stanzaId: input.stanzaId,
|
|
35
|
+
parentMsgOriginalSender: input.parentMsgOriginalSender,
|
|
36
|
+
modificationSender: input.modificationSender,
|
|
37
|
+
modificationType: input.modificationType
|
|
38
|
+
});
|
|
39
|
+
const key = await importAesGcmKey(secret, ['decrypt']);
|
|
40
|
+
const iv = assertAddonIv(input.iv);
|
|
41
|
+
const additionalData = resolveAddonAdditionalData(input);
|
|
42
|
+
return aesGcmDecrypt(key, iv, toBytesView(input.ciphertext), additionalData);
|
|
43
|
+
}
|
|
44
|
+
function assertAddonIv(iv) {
|
|
45
|
+
const normalized = toBytesView(iv);
|
|
46
|
+
if (normalized.byteLength !== WA_ADDON_ENCRYPTION_NONCE_BYTES) {
|
|
47
|
+
throw new Error(`addon iv must be ${WA_ADDON_ENCRYPTION_NONCE_BYTES} bytes (got ${normalized.byteLength})`);
|
|
48
|
+
}
|
|
49
|
+
return normalized;
|
|
50
|
+
}
|
|
51
|
+
function resolveAddonAdditionalData(input) {
|
|
52
|
+
if (input.additionalData) {
|
|
53
|
+
return toBytesView(input.additionalData);
|
|
54
|
+
}
|
|
55
|
+
if (!shouldUseAddonAdditionalData(input.modificationType)) {
|
|
56
|
+
return EMPTY_BYTES;
|
|
57
|
+
}
|
|
58
|
+
return buildAddonAdditionalData(input.stanzaId, input.modificationSender);
|
|
59
|
+
}
|