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
|
@@ -167,14 +167,22 @@ function writeListSize(size, writer) {
|
|
|
167
167
|
writer.writeUint16(size);
|
|
168
168
|
}
|
|
169
169
|
function writeNodeInternal(node, writer) {
|
|
170
|
-
|
|
170
|
+
let attrsLen = 0;
|
|
171
|
+
for (const key in node.attrs) {
|
|
172
|
+
if (Object.prototype.hasOwnProperty.call(node.attrs, key)) {
|
|
173
|
+
attrsLen += 1;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
171
176
|
const hasContent = node.content !== null && node.content !== undefined;
|
|
172
|
-
const listSize = 1 +
|
|
177
|
+
const listSize = 1 + attrsLen * 2 + (hasContent ? 1 : 0);
|
|
173
178
|
writeListSize(listSize, writer);
|
|
174
179
|
writeString(node.tag, writer);
|
|
175
|
-
for (const
|
|
180
|
+
for (const key in node.attrs) {
|
|
181
|
+
if (!Object.prototype.hasOwnProperty.call(node.attrs, key)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
176
184
|
writeString(key, writer);
|
|
177
|
-
writeString(
|
|
185
|
+
writeString(node.attrs[key], writer);
|
|
178
186
|
}
|
|
179
187
|
if (!hasContent) {
|
|
180
188
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../../protocol/constants.js';
|
|
2
|
-
import { toError } from '../../util/primitives.js';
|
|
2
|
+
import { normalizeNonNegativeInteger, toError } from '../../util/primitives.js';
|
|
3
3
|
const KEEPALIVE_DEFAULT_JITTER_RATIO = 0.1;
|
|
4
4
|
const KEEPALIVE_DEFAULT_MIN_JITTER_MS = 250;
|
|
5
5
|
const KEEPALIVE_MAX_JITTER_RATIO = 0.5;
|
|
@@ -12,7 +12,7 @@ export class WaKeepAlive {
|
|
|
12
12
|
this.timeoutMs = options.timeoutMs ?? WA_DEFAULTS.DEAD_SOCKET_TIMEOUT_MS;
|
|
13
13
|
this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
|
|
14
14
|
this.jitterRatio = this.normalizeJitterRatio(options.jitterRatio);
|
|
15
|
-
this.minJitterMs =
|
|
15
|
+
this.minJitterMs = normalizeNonNegativeInteger(options.minJitterMs, KEEPALIVE_DEFAULT_MIN_JITTER_MS);
|
|
16
16
|
this.timer = null;
|
|
17
17
|
this.generation = 0;
|
|
18
18
|
this.inFlight = false;
|
|
@@ -110,12 +110,6 @@ export class WaKeepAlive {
|
|
|
110
110
|
const normalized = value;
|
|
111
111
|
return Math.min(Math.max(normalized, 0), KEEPALIVE_MAX_JITTER_RATIO);
|
|
112
112
|
}
|
|
113
|
-
normalizeMinJitterMs(value) {
|
|
114
|
-
if (!Number.isFinite(value)) {
|
|
115
|
-
return KEEPALIVE_DEFAULT_MIN_JITTER_MS;
|
|
116
|
-
}
|
|
117
|
-
return Math.max(0, Math.trunc(value));
|
|
118
|
-
}
|
|
119
113
|
computeNextDelayMs() {
|
|
120
114
|
if (this.intervalMs <= 0) {
|
|
121
115
|
return 0;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../../protocol/constants.js';
|
|
2
2
|
import { toError } from '../../util/primitives.js';
|
|
3
|
+
import { formatNodeIdPrefixFromSeed } from './helpers.js';
|
|
3
4
|
export class WaNodeOrchestrator {
|
|
4
5
|
constructor(options) {
|
|
5
6
|
this.logger = options.logger;
|
|
@@ -133,10 +134,7 @@ export class WaNodeOrchestrator {
|
|
|
133
134
|
return this.stanzaPrefix;
|
|
134
135
|
}
|
|
135
136
|
generateStanzaPrefix() {
|
|
136
|
-
const
|
|
137
|
-
const left = seed[0] * 256 + seed[1];
|
|
138
|
-
const right = seed[2] * 256 + seed[3];
|
|
139
|
-
const prefix = `${left}.${right}-`;
|
|
137
|
+
const prefix = formatNodeIdPrefixFromSeed(crypto.getRandomValues(new Uint8Array(4)));
|
|
140
138
|
this.logger.debug('generated stanza prefix', { prefix });
|
|
141
139
|
return prefix;
|
|
142
140
|
}
|
|
@@ -9,9 +9,6 @@ export class WaNodeTransport extends EventEmitter {
|
|
|
9
9
|
this.logger = logger;
|
|
10
10
|
this.comms = null;
|
|
11
11
|
}
|
|
12
|
-
on(event, listener) {
|
|
13
|
-
return super.on(event, listener);
|
|
14
|
-
}
|
|
15
12
|
bindComms(comms) {
|
|
16
13
|
this.comms = comms;
|
|
17
14
|
this.logger.debug('node transport bindComms', { connected: comms !== null });
|
|
@@ -1,42 +1,22 @@
|
|
|
1
|
-
import { WA_DEFAULTS, WA_NODE_TAGS, WA_XMLNS } from '../../../protocol/constants.js';
|
|
1
|
+
import { WA_DEFAULTS, WA_NODE_TAGS, WA_USYNC_CONTEXTS, WA_XMLNS } from '../../../protocol/constants.js';
|
|
2
|
+
import { buildUsyncIq } from '../../node/builders/usync.js';
|
|
2
3
|
import { buildIqNode } from '../../node/query.js';
|
|
3
4
|
export function buildAccountDevicesSyncIq(userJids, sid) {
|
|
4
|
-
return
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
context: WA_NODE_TAGS.NOTIFICATION
|
|
13
|
-
},
|
|
14
|
-
content: [
|
|
15
|
-
{
|
|
16
|
-
tag: WA_NODE_TAGS.QUERY,
|
|
17
|
-
attrs: {},
|
|
18
|
-
content: [
|
|
19
|
-
{
|
|
20
|
-
tag: WA_NODE_TAGS.DEVICES,
|
|
21
|
-
attrs: {
|
|
22
|
-
version: '2'
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
tag: WA_NODE_TAGS.LIST,
|
|
29
|
-
attrs: {},
|
|
30
|
-
content: userJids.map((jid) => ({
|
|
31
|
-
tag: WA_NODE_TAGS.USER,
|
|
32
|
-
attrs: {
|
|
33
|
-
jid
|
|
34
|
-
}
|
|
35
|
-
}))
|
|
5
|
+
return buildUsyncIq({
|
|
6
|
+
sid,
|
|
7
|
+
context: WA_USYNC_CONTEXTS.NOTIFICATION,
|
|
8
|
+
queryProtocolNodes: [
|
|
9
|
+
{
|
|
10
|
+
tag: WA_NODE_TAGS.DEVICES,
|
|
11
|
+
attrs: {
|
|
12
|
+
version: '2'
|
|
36
13
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
users: userJids.map((jid) => ({
|
|
17
|
+
jid
|
|
18
|
+
}))
|
|
19
|
+
});
|
|
40
20
|
}
|
|
41
21
|
export function buildAccountPictureSyncIq(meJid) {
|
|
42
22
|
return buildIqNode('get', WA_DEFAULTS.HOST_DOMAIN, WA_XMLNS.PROFILE_PICTURE, [
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { buildAccountBlocklistSyncIq, buildAccountDevicesSyncIq, buildAccountPictureSyncIq, buildAccountPrivacySyncIq, buildClearDirtyBitsIq, buildGroupsDirtySyncIq, buildNewsletterMetadataSyncIq } from '../../node/builders/
|
|
1
|
+
export { buildAccountBlocklistSyncIq, buildAccountDevicesSyncIq, buildAccountPictureSyncIq, buildAccountPrivacySyncIq, buildClearDirtyBitsIq, buildGroupsDirtySyncIq, buildNewsletterMetadataSyncIq } from '../../node/builders/account-sync.js';
|
|
2
2
|
export { buildCompanionFinishRequestNode, buildCompanionHelloRequestNode, buildGetCountryCodeRequestNode, buildIqResultNode, buildNotificationAckNode } from '../../node/builders/pairing.js';
|
|
3
3
|
export { buildMediaConnIq } from '../../node/builders/media.js';
|
|
4
4
|
export { buildDirectMessageFanoutNode, buildGroupDirectMessageNode, buildGroupRetryMessageNode, buildGroupSenderKeyMessageNode, buildInboundDeliveryReceiptNode, buildInboundMessageAckNode, buildInboundReceiptAckNode, buildInboundRetryReceiptNode, buildInboundRetryReceiptAckNode } from '../../node/builders/message.js';
|
|
5
5
|
export { buildRetryReceiptNode } from '../../node/builders/retry.js';
|
|
6
6
|
export { buildMissingPreKeysFetchIq, buildPreKeyUploadIq, buildSignedPreKeyRotateIq } from '../../node/builders/prekeys.js';
|
|
7
7
|
export { buildCreateGroupIq, buildGroupParticipantChangeIq, buildLeaveGroupIq } from '../../node/builders/group.js';
|
|
8
|
+
export { buildUsyncIq, buildUsyncUserNode } from '../../node/builders/usync.js';
|
|
@@ -39,6 +39,9 @@ export function buildDirectMessageFanoutNode(input) {
|
|
|
39
39
|
content: input.deviceIdentity
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
if (input.reportingNode) {
|
|
43
|
+
content.push(input.reportingNode);
|
|
44
|
+
}
|
|
42
45
|
return {
|
|
43
46
|
tag: WA_MESSAGE_TAGS.MESSAGE,
|
|
44
47
|
attrs,
|
|
@@ -97,6 +100,9 @@ export function buildGroupSenderKeyMessageNode(input) {
|
|
|
97
100
|
content: input.deviceIdentity
|
|
98
101
|
});
|
|
99
102
|
}
|
|
103
|
+
if (input.reportingNode) {
|
|
104
|
+
content.push(input.reportingNode);
|
|
105
|
+
}
|
|
100
106
|
return {
|
|
101
107
|
tag: WA_MESSAGE_TAGS.MESSAGE,
|
|
102
108
|
attrs,
|
|
@@ -149,6 +155,9 @@ export function buildGroupDirectMessageNode(input) {
|
|
|
149
155
|
content: input.deviceIdentity
|
|
150
156
|
});
|
|
151
157
|
}
|
|
158
|
+
if (input.reportingNode) {
|
|
159
|
+
content.push(input.reportingNode);
|
|
160
|
+
}
|
|
152
161
|
return {
|
|
153
162
|
tag: WA_MESSAGE_TAGS.MESSAGE,
|
|
154
163
|
attrs,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_SIGNALING, WA_XMLNS } from '../../../protocol/constants.js';
|
|
2
|
-
|
|
3
|
-
const NOTIFICATION_CLASS = WA_NODE_TAGS.NOTIFICATION;
|
|
2
|
+
import { ZERO_BYTES } from '../../../util/bytes.js';
|
|
4
3
|
export function buildCompanionHelloRequestNode(args) {
|
|
5
4
|
return {
|
|
6
5
|
tag: WA_NODE_TAGS.IQ,
|
|
@@ -43,7 +42,7 @@ export function buildCompanionHelloRequestNode(args) {
|
|
|
43
42
|
{
|
|
44
43
|
tag: 'link_code_pairing_nonce',
|
|
45
44
|
attrs: {},
|
|
46
|
-
content:
|
|
45
|
+
content: ZERO_BYTES
|
|
47
46
|
}
|
|
48
47
|
]
|
|
49
48
|
}
|
|
@@ -107,8 +106,8 @@ export function buildCompanionFinishRequestNode(args) {
|
|
|
107
106
|
export function buildNotificationAckNode(node, typeOverride) {
|
|
108
107
|
const attrs = {
|
|
109
108
|
to: node.attrs.from ?? WA_DEFAULTS.HOST_DOMAIN,
|
|
110
|
-
class:
|
|
111
|
-
type: typeOverride ?? node.attrs.type ??
|
|
109
|
+
class: WA_NODE_TAGS.NOTIFICATION,
|
|
110
|
+
type: typeOverride ?? node.attrs.type ?? WA_NODE_TAGS.NOTIFICATION
|
|
112
111
|
};
|
|
113
112
|
if (node.attrs.id) {
|
|
114
113
|
attrs.id = node.attrs.id;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { WA_DEFAULTS, WA_NODE_TAGS, WA_USYNC_CONTEXTS, WA_USYNC_DEFAULTS, WA_USYNC_MODES, WA_XMLNS } from '../../../protocol/constants.js';
|
|
2
|
+
import { buildIqNode } from '../../node/query.js';
|
|
3
|
+
export function buildUsyncUserNode(input) {
|
|
4
|
+
return {
|
|
5
|
+
tag: WA_NODE_TAGS.USER,
|
|
6
|
+
attrs: {
|
|
7
|
+
...input.attrs,
|
|
8
|
+
jid: input.jid
|
|
9
|
+
},
|
|
10
|
+
...(input.content !== undefined ? { content: input.content } : {})
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function buildUsyncIq(input) {
|
|
14
|
+
if (input.queryProtocolNodes.length === 0) {
|
|
15
|
+
throw new Error('usync query must include at least one protocol node');
|
|
16
|
+
}
|
|
17
|
+
return buildIqNode('get', input.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN, WA_XMLNS.USYNC, [
|
|
18
|
+
{
|
|
19
|
+
tag: WA_NODE_TAGS.USYNC,
|
|
20
|
+
attrs: {
|
|
21
|
+
sid: input.sid,
|
|
22
|
+
index: input.index ?? WA_USYNC_DEFAULTS.INDEX,
|
|
23
|
+
last: input.last ?? WA_USYNC_DEFAULTS.LAST,
|
|
24
|
+
mode: input.mode ?? WA_USYNC_MODES.QUERY,
|
|
25
|
+
context: input.context ?? WA_USYNC_CONTEXTS.INTERACTIVE
|
|
26
|
+
},
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
tag: WA_NODE_TAGS.QUERY,
|
|
30
|
+
attrs: {},
|
|
31
|
+
content: [...input.queryProtocolNodes]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
tag: WA_NODE_TAGS.LIST,
|
|
35
|
+
attrs: {},
|
|
36
|
+
content: input.users.map((user) => buildUsyncUserNode(user))
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
@@ -1,15 +1,112 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { base64ToBytesChecked, TEXT_DECODER, TEXT_ENCODER } from '../../util/bytes.js';
|
|
2
|
+
const EMPTY_NODE_CHILDREN = Object.freeze([]);
|
|
3
|
+
const EMPTY_NODE_TAGS = Object.freeze([]);
|
|
4
|
+
const EMPTY_NODE_VALUES = Object.freeze([]);
|
|
2
5
|
export function getNodeChildren(node) {
|
|
3
|
-
return Array.isArray(node.content) ? node.content :
|
|
6
|
+
return Array.isArray(node.content) ? node.content : EMPTY_NODE_CHILDREN;
|
|
4
7
|
}
|
|
5
8
|
export function findNodeChild(node, tag) {
|
|
6
|
-
|
|
9
|
+
const content = node.content;
|
|
10
|
+
if (!Array.isArray(content))
|
|
11
|
+
return undefined;
|
|
12
|
+
for (let i = 0; i < content.length; i++) {
|
|
13
|
+
if (content[i].tag === tag)
|
|
14
|
+
return content[i];
|
|
15
|
+
}
|
|
7
16
|
}
|
|
8
17
|
export function getFirstNodeChild(node) {
|
|
9
18
|
return getNodeChildren(node)[0];
|
|
10
19
|
}
|
|
11
20
|
export function getNodeChildrenByTag(node, tag) {
|
|
12
|
-
|
|
21
|
+
const content = node.content;
|
|
22
|
+
if (!Array.isArray(content))
|
|
23
|
+
return EMPTY_NODE_CHILDREN;
|
|
24
|
+
let tagged = null;
|
|
25
|
+
for (let i = 0; i < content.length; i++) {
|
|
26
|
+
if (content[i].tag !== tag)
|
|
27
|
+
continue;
|
|
28
|
+
if (!tagged)
|
|
29
|
+
tagged = [];
|
|
30
|
+
tagged.push(content[i]);
|
|
31
|
+
}
|
|
32
|
+
return tagged ?? EMPTY_NODE_CHILDREN;
|
|
33
|
+
}
|
|
34
|
+
export function getNodeChildrenByTagFromChildren(node, tag) {
|
|
35
|
+
let tagged = null;
|
|
36
|
+
const content = node.content;
|
|
37
|
+
if (!Array.isArray(content))
|
|
38
|
+
return EMPTY_NODE_CHILDREN;
|
|
39
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
40
|
+
const nested = content[i].content;
|
|
41
|
+
if (!Array.isArray(nested))
|
|
42
|
+
continue;
|
|
43
|
+
for (let j = 0; j < nested.length; j += 1) {
|
|
44
|
+
if (nested[j].tag !== tag)
|
|
45
|
+
continue;
|
|
46
|
+
if (!tagged)
|
|
47
|
+
tagged = [];
|
|
48
|
+
tagged.push(nested[j]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return tagged ?? EMPTY_NODE_CHILDREN;
|
|
52
|
+
}
|
|
53
|
+
export function getNodeChildrenTags(node) {
|
|
54
|
+
const content = node.content;
|
|
55
|
+
if (!Array.isArray(content) || content.length === 0)
|
|
56
|
+
return EMPTY_NODE_TAGS;
|
|
57
|
+
return content.map((c) => c.tag);
|
|
58
|
+
}
|
|
59
|
+
export function getNodeChildrenNonEmptyAttrValuesByTag(node, tag, attr) {
|
|
60
|
+
let values = null;
|
|
61
|
+
const children = getNodeChildren(node);
|
|
62
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
63
|
+
const child = children[index];
|
|
64
|
+
if (child.tag !== tag) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const value = child.attrs[attr];
|
|
68
|
+
if (!value) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (!values) {
|
|
72
|
+
values = [];
|
|
73
|
+
}
|
|
74
|
+
values.push(value);
|
|
75
|
+
}
|
|
76
|
+
return values ?? EMPTY_NODE_VALUES;
|
|
77
|
+
}
|
|
78
|
+
export function getNodeChildrenNonEmptyUtf8ByTag(node, tag, field) {
|
|
79
|
+
let values = null;
|
|
80
|
+
const children = getNodeChildren(node);
|
|
81
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
82
|
+
const child = children[index];
|
|
83
|
+
if (child.tag !== tag) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const raw = child.content;
|
|
87
|
+
if (raw === null || raw === undefined) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (raw instanceof Uint8Array && raw.length === 0) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const value = TEXT_DECODER.decode(decodeNodeContentUtf8OrBytes(raw, field));
|
|
94
|
+
if (value.length === 0) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!values) {
|
|
98
|
+
values = [];
|
|
99
|
+
}
|
|
100
|
+
values.push(value);
|
|
101
|
+
}
|
|
102
|
+
return values ?? EMPTY_NODE_VALUES;
|
|
103
|
+
}
|
|
104
|
+
export function findNodeChildrenByTags(node, tags) {
|
|
105
|
+
const out = new Array(tags.length);
|
|
106
|
+
for (let index = 0; index < tags.length; index += 1) {
|
|
107
|
+
out[index] = findNodeChild(node, tags[index]);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
13
110
|
}
|
|
14
111
|
export function hasNodeChild(node, tag) {
|
|
15
112
|
return findNodeChild(node, tag) !== undefined;
|
|
@@ -28,10 +125,15 @@ export function decodeNodeContentBase64OrBytes(value, field) {
|
|
|
28
125
|
throw new Error(`missing binary node content for ${field}`);
|
|
29
126
|
}
|
|
30
127
|
if (typeof value === 'string') {
|
|
31
|
-
return
|
|
128
|
+
return base64ToBytesChecked(value, field);
|
|
32
129
|
}
|
|
33
130
|
if (value instanceof Uint8Array) {
|
|
34
131
|
return value;
|
|
35
132
|
}
|
|
36
133
|
throw new Error(`missing binary node content for ${field}`);
|
|
37
134
|
}
|
|
135
|
+
export function formatNodeIdPrefixFromSeed(seed) {
|
|
136
|
+
const left = ((seed[0] << 8) | seed[1]) >>> 0;
|
|
137
|
+
const right = ((seed[2] << 8) | seed[3]) >>> 0;
|
|
138
|
+
return `${left}.${right}-`;
|
|
139
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { randomBytesAsync } from '../../crypto/index.js';
|
|
2
|
+
import { formatNodeIdPrefixFromSeed } from './helpers.js';
|
|
3
|
+
export function createUsyncSidGenerator() {
|
|
4
|
+
const state = {
|
|
5
|
+
prefix: null,
|
|
6
|
+
prefixPromise: null,
|
|
7
|
+
counter: 1
|
|
8
|
+
};
|
|
9
|
+
return async () => {
|
|
10
|
+
const prefix = await getUsyncPrefix(state);
|
|
11
|
+
const sid = `${prefix}${state.counter}`;
|
|
12
|
+
state.counter += 1;
|
|
13
|
+
return sid;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function getUsyncPrefix(state) {
|
|
17
|
+
if (state.prefix) {
|
|
18
|
+
return state.prefix;
|
|
19
|
+
}
|
|
20
|
+
if (!state.prefixPromise) {
|
|
21
|
+
state.prefixPromise = buildUsyncPrefix()
|
|
22
|
+
.then((prefix) => {
|
|
23
|
+
state.prefix = prefix;
|
|
24
|
+
return prefix;
|
|
25
|
+
})
|
|
26
|
+
.finally(() => {
|
|
27
|
+
state.prefixPromise = null;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return state.prefixPromise;
|
|
31
|
+
}
|
|
32
|
+
async function buildUsyncPrefix() {
|
|
33
|
+
const seed = await randomBytesAsync(4);
|
|
34
|
+
return formatNodeIdPrefixFromSeed(seed);
|
|
35
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EMPTY_BYTES, toBytesView } from '../../util/bytes.js';
|
|
2
2
|
const WA_MAX_FRAME_LENGTH = (1 << 24) - 1;
|
|
3
3
|
function frameLength(header) {
|
|
4
4
|
return (header[0] << 16) | (header[1] << 8) | header[2];
|
|
@@ -15,6 +15,31 @@ export class WaFrameCodec {
|
|
|
15
15
|
this.maxFrameLength = maxFrameLength;
|
|
16
16
|
this.introSent = false;
|
|
17
17
|
this.buffered = EMPTY_BYTES;
|
|
18
|
+
this.bufferedLength = 0;
|
|
19
|
+
}
|
|
20
|
+
assertFrameLength(length) {
|
|
21
|
+
if (length <= this.maxFrameLength) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`incoming frame is too large: ${length} bytes (max allowed: ${this.maxFrameLength})`);
|
|
25
|
+
}
|
|
26
|
+
appendBuffered(chunk) {
|
|
27
|
+
if (chunk.length === 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (this.bufferedLength === 0) {
|
|
31
|
+
this.buffered = chunk;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const nextLength = this.bufferedLength + chunk.length;
|
|
35
|
+
if (this.buffered.length < nextLength) {
|
|
36
|
+
const nextBuffered = new Uint8Array(Math.max(nextLength, this.bufferedLength * 2));
|
|
37
|
+
nextBuffered.set(this.buffered.subarray(0, this.bufferedLength));
|
|
38
|
+
this.buffered = nextBuffered;
|
|
39
|
+
}
|
|
40
|
+
this.buffered.set(chunk, this.bufferedLength);
|
|
41
|
+
}
|
|
42
|
+
this.bufferedLength += chunk.length;
|
|
18
43
|
}
|
|
19
44
|
encodeFrame(frame) {
|
|
20
45
|
if (frame.length > this.maxFrameLength) {
|
|
@@ -45,67 +70,56 @@ export class WaFrameCodec {
|
|
|
45
70
|
}
|
|
46
71
|
const frames = [];
|
|
47
72
|
let chunkOffset = 0;
|
|
48
|
-
if (this.
|
|
49
|
-
if (this.
|
|
50
|
-
const missingHeaderBytes = 3 - this.
|
|
73
|
+
if (this.bufferedLength > 0) {
|
|
74
|
+
if (this.bufferedLength < 3) {
|
|
75
|
+
const missingHeaderBytes = 3 - this.bufferedLength;
|
|
51
76
|
if (chunk.length < missingHeaderBytes) {
|
|
52
|
-
this.
|
|
77
|
+
this.appendBuffered(chunk);
|
|
53
78
|
return frames;
|
|
54
79
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const length = frameLength(header);
|
|
59
|
-
if (length > this.maxFrameLength) {
|
|
60
|
-
throw new Error(`incoming frame is too large: ${length} bytes (max allowed: ${this.maxFrameLength})`);
|
|
61
|
-
}
|
|
80
|
+
this.appendBuffered(chunk.subarray(0, missingHeaderBytes));
|
|
81
|
+
const length = frameLength(this.buffered);
|
|
82
|
+
this.assertFrameLength(length);
|
|
62
83
|
const remainingAfterHeader = chunk.length - missingHeaderBytes;
|
|
63
84
|
if (remainingAfterHeader < length) {
|
|
64
|
-
|
|
65
|
-
nextBuffered.set(header, 0);
|
|
66
|
-
nextBuffered.set(chunk.subarray(missingHeaderBytes), 3);
|
|
67
|
-
this.buffered = nextBuffered;
|
|
85
|
+
this.appendBuffered(chunk.subarray(missingHeaderBytes));
|
|
68
86
|
return frames;
|
|
69
87
|
}
|
|
70
88
|
frames.push(chunk.subarray(missingHeaderBytes, missingHeaderBytes + length));
|
|
71
89
|
chunkOffset = missingHeaderBytes + length;
|
|
72
|
-
this.buffered = EMPTY_BYTES;
|
|
73
90
|
}
|
|
74
91
|
else {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
throw new Error(`incoming frame is too large: ${length} bytes (max allowed: ${this.maxFrameLength})`);
|
|
79
|
-
}
|
|
80
|
-
const bufferedPayloadLength = this.buffered.length - 3;
|
|
92
|
+
const length = frameLength(this.buffered);
|
|
93
|
+
this.assertFrameLength(length);
|
|
94
|
+
const bufferedPayloadLength = this.bufferedLength - 3;
|
|
81
95
|
const missingPayloadBytes = length - bufferedPayloadLength;
|
|
82
96
|
if (missingPayloadBytes > chunk.length) {
|
|
83
|
-
this.
|
|
97
|
+
this.appendBuffered(chunk);
|
|
84
98
|
return frames;
|
|
85
99
|
}
|
|
86
|
-
if (
|
|
100
|
+
if (missingPayloadBytes === 0) {
|
|
101
|
+
frames.push(this.buffered.subarray(3, 3 + length));
|
|
102
|
+
}
|
|
103
|
+
else if (bufferedPayloadLength === 0) {
|
|
87
104
|
frames.push(chunk.subarray(0, missingPayloadBytes));
|
|
88
105
|
}
|
|
89
106
|
else {
|
|
90
107
|
const frame = new Uint8Array(length);
|
|
91
|
-
frame.set(this.buffered.subarray(3
|
|
92
|
-
|
|
93
|
-
frame.set(chunk.subarray(0, missingPayloadBytes), bufferedPayloadLength);
|
|
94
|
-
}
|
|
108
|
+
frame.set(this.buffered.subarray(3, this.bufferedLength));
|
|
109
|
+
frame.set(chunk.subarray(0, missingPayloadBytes), bufferedPayloadLength);
|
|
95
110
|
frames.push(frame);
|
|
96
111
|
}
|
|
97
112
|
chunkOffset = missingPayloadBytes;
|
|
98
|
-
this.buffered = EMPTY_BYTES;
|
|
99
113
|
}
|
|
114
|
+
this.buffered = EMPTY_BYTES;
|
|
115
|
+
this.bufferedLength = 0;
|
|
100
116
|
}
|
|
101
117
|
const remainingChunk = chunk.subarray(chunkOffset);
|
|
102
118
|
let offset = 0;
|
|
103
119
|
while (remainingChunk.length - offset >= 3) {
|
|
104
120
|
const header = remainingChunk.subarray(offset, offset + 3);
|
|
105
121
|
const length = frameLength(header);
|
|
106
|
-
|
|
107
|
-
throw new Error(`incoming frame is too large: ${length} bytes (max allowed: ${this.maxFrameLength})`);
|
|
108
|
-
}
|
|
122
|
+
this.assertFrameLength(length);
|
|
109
123
|
if (remainingChunk.length - offset - 3 < length) {
|
|
110
124
|
break;
|
|
111
125
|
}
|
|
@@ -116,6 +130,7 @@ export class WaFrameCodec {
|
|
|
116
130
|
}
|
|
117
131
|
this.buffered =
|
|
118
132
|
offset >= remainingChunk.length ? EMPTY_BYTES : remainingChunk.subarray(offset);
|
|
133
|
+
this.bufferedLength = this.buffered.length;
|
|
119
134
|
return frames;
|
|
120
135
|
}
|
|
121
136
|
}
|
|
@@ -2,12 +2,11 @@ import { ed25519VerifyRaw, toSerializedPubKey } from '../../crypto/index.js';
|
|
|
2
2
|
import { montgomeryToEdwardsPublic } from '../../crypto/curves/X25519.js';
|
|
3
3
|
import { proto } from '../../proto.js';
|
|
4
4
|
import { ROOT_CA_PUBLIC_KEY_HEX, ROOT_CA_SERIAL } from '../noise/constants.js';
|
|
5
|
-
import { decodeProtoBytes } from '../../util/
|
|
6
|
-
import { hexToBytes, uint8Equal } from '../../util/bytes.js';
|
|
5
|
+
import { assertByteLength, decodeProtoBytes, hexToBytes, uint8Equal } from '../../util/bytes.js';
|
|
7
6
|
import { toSafeNumber } from '../../util/primitives.js';
|
|
8
7
|
async function verifySignalVariant(serializedPublicKey, message, signatureInput) {
|
|
9
8
|
const publicKey = toSerializedPubKey(serializedPublicKey);
|
|
10
|
-
if (signatureInput
|
|
9
|
+
if (!assertByteLength(signatureInput, 64, 'invalid certificate signature size', false)) {
|
|
11
10
|
return false;
|
|
12
11
|
}
|
|
13
12
|
const signature = new Uint8Array(signatureInput);
|
|
@@ -26,9 +25,7 @@ function parseNoiseCertificate(certificate) {
|
|
|
26
25
|
}
|
|
27
26
|
const detailsBytes = decodeProtoBytes(certificate.details, 'certificate.details');
|
|
28
27
|
const signatureBytes = decodeProtoBytes(certificate.signature, 'certificate.signature');
|
|
29
|
-
|
|
30
|
-
throw new Error('invalid certificate signature size');
|
|
31
|
-
}
|
|
28
|
+
assertByteLength(signatureBytes, 64, 'invalid certificate signature size');
|
|
32
29
|
const details = proto.CertChain.NoiseCertificate.Details.decode(detailsBytes);
|
|
33
30
|
const serial = toSafeNumber(details.serial, 'certificate.serial');
|
|
34
31
|
const issuerSerial = toSafeNumber(details.issuerSerial, 'certificate.issuerSerial');
|
|
@@ -48,12 +48,9 @@ function buildRoutingInfoPrefix(routingInfo) {
|
|
|
48
48
|
}
|
|
49
49
|
export class WaNoiseSession {
|
|
50
50
|
constructor(sendWire, logger = new ConsoleLogger('info')) {
|
|
51
|
-
this.sendWire = sendWire;
|
|
52
|
-
this.logger = logger;
|
|
53
|
-
this.writeQueue = new BoundedTaskQueue(4096, 1);
|
|
54
|
-
this.readQueue = new BoundedTaskQueue(4096, 1);
|
|
55
51
|
this.frameCodec = null;
|
|
56
52
|
this.handshakeInbox = [];
|
|
53
|
+
this.handshakeInboxHead = 0;
|
|
57
54
|
this.handshakeWaiter = null;
|
|
58
55
|
this.handshakeRejecter = null;
|
|
59
56
|
this.pendingDecryptedFrames = [];
|
|
@@ -61,6 +58,10 @@ export class WaNoiseSession {
|
|
|
61
58
|
this.noiseSocket = null;
|
|
62
59
|
this.serverStaticKey = null;
|
|
63
60
|
this.handshakeFrameTimeoutMs = WA_DEFAULTS.CONNECT_TIMEOUT_MS;
|
|
61
|
+
this.sendWire = sendWire;
|
|
62
|
+
this.logger = logger;
|
|
63
|
+
this.writeQueue = new BoundedTaskQueue(4096, 1);
|
|
64
|
+
this.readQueue = new BoundedTaskQueue(4096, 1);
|
|
64
65
|
}
|
|
65
66
|
async start(config) {
|
|
66
67
|
this.reset();
|
|
@@ -144,7 +145,7 @@ export class WaNoiseSession {
|
|
|
144
145
|
reset() {
|
|
145
146
|
this.logger.trace('noise session reset');
|
|
146
147
|
this.frameCodec = null;
|
|
147
|
-
this.handshakeInbox =
|
|
148
|
+
this.handshakeInbox.length = this.handshakeInboxHead = 0;
|
|
148
149
|
this.handshakeWaiter = null;
|
|
149
150
|
this.handshakeRejecter = null;
|
|
150
151
|
this.pendingDecryptedFrames = [];
|
|
@@ -275,8 +276,13 @@ export class WaNoiseSession {
|
|
|
275
276
|
if (this.closedError) {
|
|
276
277
|
throw this.closedError;
|
|
277
278
|
}
|
|
278
|
-
const queued = this.handshakeInbox.
|
|
279
|
+
const queued = this.handshakeInboxHead < this.handshakeInbox.length
|
|
280
|
+
? this.handshakeInbox[this.handshakeInboxHead++]
|
|
281
|
+
: undefined;
|
|
279
282
|
if (queued) {
|
|
283
|
+
if (this.handshakeInboxHead === this.handshakeInbox.length) {
|
|
284
|
+
this.handshakeInbox.length = this.handshakeInboxHead = 0;
|
|
285
|
+
}
|
|
280
286
|
this.logger.trace('noise handshake frame consumed from queue');
|
|
281
287
|
return queued;
|
|
282
288
|
}
|
|
@@ -307,16 +313,17 @@ export class WaNoiseSession {
|
|
|
307
313
|
});
|
|
308
314
|
}
|
|
309
315
|
async decodeBufferedPostHandshakeFrames() {
|
|
310
|
-
if (!this.noiseSocket || this.handshakeInbox.length
|
|
316
|
+
if (!this.noiseSocket || this.handshakeInboxHead >= this.handshakeInbox.length) {
|
|
311
317
|
return;
|
|
312
318
|
}
|
|
313
319
|
this.logger.debug('decoding buffered post-handshake frames', {
|
|
314
|
-
count: this.handshakeInbox.length
|
|
320
|
+
count: this.handshakeInbox.length - this.handshakeInboxHead
|
|
315
321
|
});
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
for (let index = this.handshakeInboxHead; index < this.handshakeInbox.length; index += 1) {
|
|
323
|
+
const frame = this.handshakeInbox[index];
|
|
318
324
|
const decrypted = await this.readQueue.enqueue(() => this.noiseSocket.decrypt(frame));
|
|
319
325
|
this.pendingDecryptedFrames.push(decrypted);
|
|
320
326
|
}
|
|
327
|
+
this.handshakeInbox.length = this.handshakeInboxHead = 0;
|
|
321
328
|
}
|
|
322
329
|
}
|