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
|
@@ -46,7 +46,7 @@ export function decodeSignalSignedPreKeyRow(row) {
|
|
|
46
46
|
uploaded: toBoolOrUndef(row.uploaded)
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
function encodeSignalSessionSnapshot(session) {
|
|
49
|
+
export function encodeSignalSessionSnapshot(session) {
|
|
50
50
|
return {
|
|
51
51
|
sessionVersion: 3,
|
|
52
52
|
localRegistrationId: session.local.regId,
|
|
@@ -56,13 +56,7 @@ function encodeSignalSessionSnapshot(session) {
|
|
|
56
56
|
rootKey: session.rootKey,
|
|
57
57
|
previousCounter: session.prevSendChainHighestIndex,
|
|
58
58
|
senderChain: encodeSignalSendChain(session.sendChain),
|
|
59
|
-
receiverChains:
|
|
60
|
-
const src = session.recvChains;
|
|
61
|
-
const arr = new Array(src.length);
|
|
62
|
-
for (let i = 0; i < src.length; i += 1)
|
|
63
|
-
arr[i] = encodeSignalRecvChain(src[i]);
|
|
64
|
-
return arr;
|
|
65
|
-
})(),
|
|
59
|
+
receiverChains: session.recvChains,
|
|
66
60
|
pendingPreKey: session.initialExchangeInfo
|
|
67
61
|
? {
|
|
68
62
|
preKeyId: session.initialExchangeInfo.remoteOneTimeId ?? undefined,
|
|
@@ -84,30 +78,17 @@ function encodeSignalSendChain(chain) {
|
|
|
84
78
|
messageKeys: []
|
|
85
79
|
};
|
|
86
80
|
}
|
|
87
|
-
function encodeSignalRecvChain(chain) {
|
|
81
|
+
export function encodeSignalRecvChain(chain) {
|
|
88
82
|
return {
|
|
89
83
|
senderRatchetKey: chain.ratchetPubKey,
|
|
90
84
|
chainKey: {
|
|
91
85
|
index: chain.nextMsgIndex,
|
|
92
86
|
key: chain.chainKey
|
|
93
87
|
},
|
|
94
|
-
messageKeys:
|
|
95
|
-
const src = chain.unusedMsgKeys ?? [];
|
|
96
|
-
const arr = new Array(src.length);
|
|
97
|
-
for (let i = 0; i < src.length; i += 1) {
|
|
98
|
-
const messageKey = src[i];
|
|
99
|
-
arr[i] = {
|
|
100
|
-
index: messageKey.index,
|
|
101
|
-
cipherKey: messageKey.cipherKey,
|
|
102
|
-
macKey: messageKey.macKey,
|
|
103
|
-
iv: messageKey.iv
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
return arr;
|
|
107
|
-
})()
|
|
88
|
+
messageKeys: chain.unusedMsgKeys
|
|
108
89
|
};
|
|
109
90
|
}
|
|
110
|
-
function decodeSignalMessageKey(messageKey, field) {
|
|
91
|
+
export function decodeSignalMessageKey(messageKey, field) {
|
|
111
92
|
const cipherKey = asBytes(messageKey.cipherKey, `${field}.cipherKey`);
|
|
112
93
|
assertByteLength(cipherKey, 32, `invalid ${field}.cipherKey length ${cipherKey.byteLength}`);
|
|
113
94
|
const macKey = asBytes(messageKey.macKey, `${field}.macKey`);
|
|
@@ -121,7 +102,7 @@ function decodeSignalMessageKey(messageKey, field) {
|
|
|
121
102
|
iv
|
|
122
103
|
};
|
|
123
104
|
}
|
|
124
|
-
function decodeSignalRecvChain(chain, field) {
|
|
105
|
+
export function decodeSignalRecvChain(chain, field) {
|
|
125
106
|
const chainKey = chain.chainKey;
|
|
126
107
|
if (!chainKey) {
|
|
127
108
|
throw new Error(`missing ${field}.chainKey`);
|
|
@@ -134,13 +115,7 @@ function decodeSignalRecvChain(chain, field) {
|
|
|
134
115
|
ratchetPubKey,
|
|
135
116
|
nextMsgIndex: asNumber(chainKey.index, `${field}.chainKey.index`),
|
|
136
117
|
chainKey: chainKeyBytes,
|
|
137
|
-
unusedMsgKeys:
|
|
138
|
-
const src = chain.messageKeys ?? [];
|
|
139
|
-
const arr = new Array(src.length);
|
|
140
|
-
for (let i = 0; i < src.length; i += 1)
|
|
141
|
-
arr[i] = decodeSignalMessageKey(src[i], `${field}.messageKeys[${i}]`);
|
|
142
|
-
return arr;
|
|
143
|
-
})()
|
|
118
|
+
unusedMsgKeys: chain.messageKeys ?? []
|
|
144
119
|
};
|
|
145
120
|
}
|
|
146
121
|
function decodeSignalSendChain(chain, field) {
|
|
@@ -166,7 +141,7 @@ function decodeSignalSendChain(chain, field) {
|
|
|
166
141
|
chainKey: chainKeyBytes
|
|
167
142
|
};
|
|
168
143
|
}
|
|
169
|
-
function decodeSignalSessionSnapshot(session, field) {
|
|
144
|
+
export function decodeSignalSessionSnapshot(session, field) {
|
|
170
145
|
const senderChain = session.senderChain;
|
|
171
146
|
if (!senderChain) {
|
|
172
147
|
throw new Error(`missing ${field}.senderChain`);
|
|
@@ -199,13 +174,7 @@ function decodeSignalSessionSnapshot(session, field) {
|
|
|
199
174
|
},
|
|
200
175
|
rootKey,
|
|
201
176
|
sendChain: decodeSignalSendChain(senderChain, `${field}.senderChain`),
|
|
202
|
-
recvChains:
|
|
203
|
-
const src = session.receiverChains ?? [];
|
|
204
|
-
const arr = new Array(src.length);
|
|
205
|
-
for (let i = 0; i < src.length; i += 1)
|
|
206
|
-
arr[i] = decodeSignalRecvChain(src[i], `${field}.receiverChains[${i}]`);
|
|
207
|
-
return arr;
|
|
208
|
-
})(),
|
|
177
|
+
recvChains: session.receiverChains ?? [],
|
|
209
178
|
initialExchangeInfo: pendingPreKey
|
|
210
179
|
? {
|
|
211
180
|
remoteOneTimeId: asOptionalNumber(pendingPreKey.preKeyId, `${field}.pendingPreKey.preKeyId`) ??
|
|
@@ -221,13 +190,7 @@ function decodeSignalSessionSnapshot(session, field) {
|
|
|
221
190
|
export function encodeSignalSessionRecord(record) {
|
|
222
191
|
return proto.RecordStructure.encode({
|
|
223
192
|
currentSession: encodeSignalSessionSnapshot(record),
|
|
224
|
-
previousSessions:
|
|
225
|
-
const src = record.prevSessions;
|
|
226
|
-
const arr = new Array(src.length);
|
|
227
|
-
for (let i = 0; i < src.length; i += 1)
|
|
228
|
-
arr[i] = encodeSignalSessionSnapshot(src[i]);
|
|
229
|
-
return arr;
|
|
230
|
-
})()
|
|
193
|
+
previousSessions: record.prevSessions
|
|
231
194
|
}).finish();
|
|
232
195
|
}
|
|
233
196
|
export function decodeSignalSessionRecord(raw) {
|
|
@@ -238,13 +201,7 @@ export function decodeSignalSessionRecord(raw) {
|
|
|
238
201
|
const current = decodeSignalSessionSnapshot(decoded.currentSession, 'signal_sessions.currentSession');
|
|
239
202
|
return {
|
|
240
203
|
...current,
|
|
241
|
-
prevSessions:
|
|
242
|
-
const src = decoded.previousSessions ?? [];
|
|
243
|
-
const arr = new Array(src.length);
|
|
244
|
-
for (let i = 0; i < src.length; i += 1)
|
|
245
|
-
arr[i] = decodeSignalSessionSnapshot(src[i], `signal_sessions.previousSessions[${i}]`);
|
|
246
|
-
return arr;
|
|
247
|
-
})()
|
|
204
|
+
prevSessions: decoded.previousSessions ?? []
|
|
248
205
|
};
|
|
249
206
|
}
|
|
250
207
|
export function encodeSenderKeyRecord(record) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { hkdf,
|
|
1
|
+
import { hkdf, hmacSign, importHmacKey } from '../../crypto/index.js';
|
|
2
2
|
import { CHAIN_KEY_LABEL, MAX_UNUSED_KEYS, MESSAGE_KEY_LABEL, SENDER_KEY_FUTURE_MESSAGES_MAX, WHISPER_GROUP_INFO } from '../constants.js';
|
|
3
3
|
import { assertByteLength, removeAt } from '../../util/bytes.js';
|
|
4
|
-
export async function selectMessageKey(senderKey, targetIteration) {
|
|
4
|
+
export async function selectMessageKey(senderKey, targetIteration, futureMessagesMax) {
|
|
5
5
|
const delta = targetIteration - senderKey.iteration;
|
|
6
|
-
if (delta > SENDER_KEY_FUTURE_MESSAGES_MAX) {
|
|
6
|
+
if (delta > (futureMessagesMax ?? SENDER_KEY_FUTURE_MESSAGES_MAX)) {
|
|
7
7
|
throw new Error('sender key message is too far in future');
|
|
8
8
|
}
|
|
9
9
|
const currentUnused = senderKey.unusedMessageKeys ?? [];
|
|
@@ -2,7 +2,7 @@ import { readVersionedContent, toSerializedPubKey } from '../../crypto/index.js'
|
|
|
2
2
|
import { proto } from '../../proto.js';
|
|
3
3
|
import { SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
|
|
4
4
|
import { SIGNAL_GROUP_VERSION } from '../constants.js';
|
|
5
|
-
import { assertByteLength
|
|
5
|
+
import { assertByteLength } from '../../util/bytes.js';
|
|
6
6
|
export function parseDistributionPayload(payload) {
|
|
7
7
|
const body = readVersionedContent(payload, SIGNAL_GROUP_VERSION, 0);
|
|
8
8
|
const decoded = proto.SenderKeyDistributionMessage.decode(body);
|
|
@@ -16,13 +16,12 @@ export function parseDistributionPayload(payload) {
|
|
|
16
16
|
decoded.signingKey === undefined) {
|
|
17
17
|
throw new Error('invalid sender key distribution message');
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
assertByteLength(chainKey, 32, 'sender key distribution chainKey must be 32 bytes');
|
|
19
|
+
assertByteLength(decoded.chainKey, 32, 'sender key distribution chainKey must be 32 bytes');
|
|
21
20
|
return {
|
|
22
21
|
keyId: decoded.id,
|
|
23
22
|
iteration: decoded.iteration,
|
|
24
|
-
chainKey,
|
|
25
|
-
signingPublicKey: toSerializedPubKey(
|
|
23
|
+
chainKey: decoded.chainKey,
|
|
24
|
+
signingPublicKey: toSerializedPubKey(decoded.signingKey)
|
|
26
25
|
};
|
|
27
26
|
}
|
|
28
27
|
export function parseSenderKeyMessage(versionContentMac) {
|
|
@@ -39,7 +38,7 @@ export function parseSenderKeyMessage(versionContentMac) {
|
|
|
39
38
|
return {
|
|
40
39
|
keyId: decoded.id,
|
|
41
40
|
iteration: decoded.iteration,
|
|
42
|
-
ciphertext:
|
|
41
|
+
ciphertext: decoded.ciphertext,
|
|
43
42
|
versionContentMac
|
|
44
43
|
};
|
|
45
44
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { aesCbcDecrypt, aesCbcEncrypt, importAesCbcKey,
|
|
1
|
+
import { aesCbcDecrypt, aesCbcEncrypt, importAesCbcKey, prependVersion, randomBytesAsync, randomIntAsync, toRawPubKey, toSerializedPubKey, X25519, xeddsaSign, xeddsaVerify } from '../../crypto/index.js';
|
|
2
2
|
import { StoreLock } from '../../infra/perf/StoreLock.js';
|
|
3
3
|
import { proto } from '../../proto.js';
|
|
4
4
|
import { signalAddressKey } from '../../protocol/jid.js';
|
|
5
5
|
import { SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
|
|
6
6
|
import { SIGNAL_GROUP_VERSION } from '../constants.js';
|
|
7
|
-
import { signSignalMessage, verifySignalSignature } from '../crypto/WaAdvSignature.js';
|
|
8
7
|
import { deriveSenderKeyMsgKey, selectMessageKey } from '../group/SenderKeyChain.js';
|
|
9
8
|
import { parseDistributionPayload, parseSenderKeyMessage } from '../group/SenderKeyCodec.js';
|
|
10
9
|
import { concatBytes } from '../../util/bytes.js';
|
|
@@ -26,9 +25,11 @@ async function aesCbcDecryptFromSeed(seed, ciphertext) {
|
|
|
26
25
|
return aesCbcDecrypt(await importAesCbcKey(keyBytes), iv, ciphertext);
|
|
27
26
|
}
|
|
28
27
|
export class SenderKeyManager {
|
|
29
|
-
constructor(store) {
|
|
28
|
+
constructor(store, options) {
|
|
30
29
|
this.senderLock = new StoreLock();
|
|
31
30
|
this.store = store;
|
|
31
|
+
this.getFutureMessagesMax = options?.getFutureMessagesMax;
|
|
32
|
+
this.skipSignatureVerification = options?.skipSignatureVerification === true;
|
|
32
33
|
}
|
|
33
34
|
async prepareGroupEncryption(groupId, sender, plaintext) {
|
|
34
35
|
return this.runWithSenderLock(groupId, sender, async () => {
|
|
@@ -59,7 +60,7 @@ export class SenderKeyManager {
|
|
|
59
60
|
ciphertext: messagePayload
|
|
60
61
|
}).finish();
|
|
61
62
|
const versionedContent = prependVersion(senderKeyMessage, SIGNAL_GROUP_VERSION);
|
|
62
|
-
const signature = await
|
|
63
|
+
const signature = await xeddsaSign(senderKey.signingPrivateKey, versionedContent);
|
|
63
64
|
if (signature.length !== SIGNAL_SIGNATURE_LENGTH) {
|
|
64
65
|
throw new Error(`invalid sender key signature length ${signature.length}`);
|
|
65
66
|
}
|
|
@@ -163,13 +164,15 @@ export class SenderKeyManager {
|
|
|
163
164
|
parsed.iteration !== payload.iteration) {
|
|
164
165
|
throw new Error('sender key iteration mismatch');
|
|
165
166
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
if (!this.skipSignatureVerification) {
|
|
168
|
+
const signedContent = parsed.versionContentMac.subarray(0, parsed.versionContentMac.length - SIGNAL_SIGNATURE_LENGTH);
|
|
169
|
+
const signature = parsed.versionContentMac.subarray(parsed.versionContentMac.length - SIGNAL_SIGNATURE_LENGTH);
|
|
170
|
+
const validSignature = await xeddsaVerify(toRawPubKey(senderKey.signingPublicKey), signedContent, signature);
|
|
171
|
+
if (!validSignature) {
|
|
172
|
+
throw new Error('invalid sender key signature');
|
|
173
|
+
}
|
|
171
174
|
}
|
|
172
|
-
const selected = await selectMessageKey(senderKey, parsed.iteration);
|
|
175
|
+
const selected = await selectMessageKey(senderKey, parsed.iteration, this.getFutureMessagesMax?.());
|
|
173
176
|
// Keep decrypt + persist ordered: failed decrypt must not advance sender-key state.
|
|
174
177
|
const plaintext = await aesCbcDecryptFromSeed(selected.messageKey.seed, parsed.ciphertext);
|
|
175
178
|
await this.store.upsertSenderKey(selected.updatedRecord);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { randomIntAsync } from '../../crypto/index.js';
|
|
1
|
+
import { randomIntAsync, xeddsaSign } from '../../crypto/index.js';
|
|
2
2
|
import { toSerializedPubKey } from '../../crypto/core/keys.js';
|
|
3
3
|
import { X25519 } from '../../crypto/curves/X25519.js';
|
|
4
|
-
import { signSignalMessage } from '../crypto/WaAdvSignature.js';
|
|
5
4
|
export async function generateRegistrationInfo() {
|
|
6
5
|
const [registrationId, identityKeyPair] = await Promise.all([
|
|
7
6
|
generateRegistrationId(),
|
|
@@ -22,7 +21,7 @@ export async function generatePreKeyPair(keyId) {
|
|
|
22
21
|
export async function generateSignedPreKey(keyId, signingPrivateKey) {
|
|
23
22
|
const keyPair = await X25519.generateKeyPair();
|
|
24
23
|
const serializedPubKey = toSerializedPubKey(keyPair.pubKey);
|
|
25
|
-
const signature = await
|
|
24
|
+
const signature = await xeddsaSign(signingPrivateKey, serializedPubKey);
|
|
26
25
|
return {
|
|
27
26
|
keyId,
|
|
28
27
|
keyPair,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generatePreKeyPair, generateRegistrationInfo, generateSignedPreKey } from '../registration/keygen.js';
|
|
2
|
-
export async function createAndStoreInitialKeys(store) {
|
|
2
|
+
export async function createAndStoreInitialKeys(store, preKeyStore) {
|
|
3
3
|
const [registrationInfo, firstPreKey] = await Promise.all([
|
|
4
4
|
generateRegistrationInfo(),
|
|
5
5
|
generatePreKeyPair(1)
|
|
@@ -8,7 +8,7 @@ export async function createAndStoreInitialKeys(store) {
|
|
|
8
8
|
// Keep writes ordered so partial commit failures don't leave split registration bootstrap state.
|
|
9
9
|
await store.setRegistrationInfo(registrationInfo);
|
|
10
10
|
await store.setSignedPreKey(signedPreKey);
|
|
11
|
-
await
|
|
11
|
+
await preKeyStore.getOrGenSinglePreKey(async () => firstPreKey);
|
|
12
12
|
return {
|
|
13
13
|
registrationInfo,
|
|
14
14
|
signedPreKey,
|
|
@@ -2,6 +2,7 @@ import { toSerializedPubKey } from '../../crypto/index.js';
|
|
|
2
2
|
import { ConsoleLogger } from '../../infra/log/ConsoleLogger.js';
|
|
3
3
|
import { StoreLock } from '../../infra/perf/StoreLock.js';
|
|
4
4
|
import { MAX_PREV_SESSIONS } from '../constants.js';
|
|
5
|
+
import { encodeSignalSessionSnapshot } from '../encoding.js';
|
|
5
6
|
import { decryptMsg, decryptMsgFromSession, encryptMsg } from '../session/SignalRatchet.js';
|
|
6
7
|
import { deserializeMsg, deserializePkMsg, requirePreKey, requireSignedPreKey } from '../session/SignalSerializer.js';
|
|
7
8
|
import { detachSession, findMatchingSession, generateSerializedKeyPair, initiateSessionIncoming, initiateSessionOutgoing, requireLocalIdentity, toSerializedKeyPair } from '../session/SignalSession.js';
|
|
@@ -13,15 +14,15 @@ function signalAddressLockKey(address) {
|
|
|
13
14
|
return `signal:${signalAddressMapKey(address)}`;
|
|
14
15
|
}
|
|
15
16
|
export class SignalProtocol {
|
|
16
|
-
constructor(
|
|
17
|
-
this.
|
|
17
|
+
constructor(stores, logger = new ConsoleLogger('info')) {
|
|
18
|
+
this.stores = stores;
|
|
18
19
|
this.logger = logger;
|
|
19
20
|
this.sessionMutationLock = new StoreLock();
|
|
20
21
|
}
|
|
21
22
|
async establishOutgoingSession(address, remoteBundle, options = {}) {
|
|
22
23
|
return this.runWithAddressLock(address, async () => {
|
|
23
24
|
if (options.reuseExisting) {
|
|
24
|
-
const existing = await this.
|
|
25
|
+
const existing = await this.stores.session.getSession(address);
|
|
25
26
|
if (existing) {
|
|
26
27
|
const remoteIdentity = toSerializedPubKey(remoteBundle.identity);
|
|
27
28
|
if (!uint8Equal(existing.remote.pubKey, remoteIdentity)) {
|
|
@@ -31,13 +32,13 @@ export class SignalProtocol {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
const [local, localOneTimeBase] = await Promise.all([
|
|
34
|
-
requireLocalIdentity(this.
|
|
35
|
+
requireLocalIdentity(this.stores.signal),
|
|
35
36
|
generateSerializedKeyPair()
|
|
36
37
|
]);
|
|
37
38
|
const session = await initiateSessionOutgoing(local, remoteBundle, localOneTimeBase);
|
|
38
39
|
// Keep writes ordered: a stored session without matching remote identity causes false mismatch checks.
|
|
39
|
-
await this.
|
|
40
|
-
await this.
|
|
40
|
+
await this.stores.identity.setRemoteIdentity(address, session.remote.pubKey);
|
|
41
|
+
await this.stores.session.setSession(address, session);
|
|
41
42
|
return session;
|
|
42
43
|
});
|
|
43
44
|
}
|
|
@@ -85,7 +86,7 @@ export class SignalProtocol {
|
|
|
85
86
|
}
|
|
86
87
|
uniqueAddressKeys.length = uniqueAddressCount;
|
|
87
88
|
uniqueAddresses.length = uniqueAddressCount;
|
|
88
|
-
const currentSessions = await this.
|
|
89
|
+
const currentSessions = await this.stores.session.getSessionsBatch(uniqueAddresses);
|
|
89
90
|
const latestSessionByAddress = new Map();
|
|
90
91
|
for (let index = 0; index < uniqueAddressCount; index += 1) {
|
|
91
92
|
const addressKey = uniqueAddressKeys[index];
|
|
@@ -139,7 +140,7 @@ export class SignalProtocol {
|
|
|
139
140
|
identityUpdates[identityIndex] = update;
|
|
140
141
|
identityIndex += 1;
|
|
141
142
|
}
|
|
142
|
-
await this.
|
|
143
|
+
await this.stores.identity.setRemoteIdentities(identityUpdates);
|
|
143
144
|
}
|
|
144
145
|
const sessionUpdates = new Array(sessionUpdatesByAddress.size);
|
|
145
146
|
let sessionIndex = 0;
|
|
@@ -147,13 +148,13 @@ export class SignalProtocol {
|
|
|
147
148
|
sessionUpdates[sessionIndex] = update;
|
|
148
149
|
sessionIndex += 1;
|
|
149
150
|
}
|
|
150
|
-
await this.
|
|
151
|
+
await this.stores.session.setSessionsBatch(sessionUpdates);
|
|
151
152
|
return results;
|
|
152
153
|
});
|
|
153
154
|
}
|
|
154
155
|
async decryptMessage(address, envelope) {
|
|
155
156
|
return this.runWithAddressLock(address, async () => {
|
|
156
|
-
const currentSession = await this.
|
|
157
|
+
const currentSession = await this.stores.session.getSession(address);
|
|
157
158
|
let outcome;
|
|
158
159
|
if (envelope.type === 'pkmsg') {
|
|
159
160
|
const parsedPk = deserializePkMsg(envelope.ciphertext);
|
|
@@ -172,9 +173,9 @@ export class SignalProtocol {
|
|
|
172
173
|
const identityChanged = !currentSession || !uint8Equal(currentSession.remote.pubKey, nextRemoteIdentity);
|
|
173
174
|
// Keep writes ordered for consistency with resolver identity checks.
|
|
174
175
|
if (identityChanged) {
|
|
175
|
-
await this.
|
|
176
|
+
await this.stores.identity.setRemoteIdentity(address, nextRemoteIdentity);
|
|
176
177
|
}
|
|
177
|
-
await this.
|
|
178
|
+
await this.stores.session.setSession(address, outcome.updatedSession);
|
|
178
179
|
return outcome.plaintext;
|
|
179
180
|
});
|
|
180
181
|
}
|
|
@@ -192,11 +193,11 @@ export class SignalProtocol {
|
|
|
192
193
|
};
|
|
193
194
|
}
|
|
194
195
|
const [local, signedPreKey, oneTimePreKey] = await Promise.all([
|
|
195
|
-
requireLocalIdentity(this.
|
|
196
|
-
requireSignedPreKey(this.
|
|
196
|
+
requireLocalIdentity(this.stores.signal),
|
|
197
|
+
requireSignedPreKey(this.stores.signal, parsed.localSignedPreKeyId),
|
|
197
198
|
parsed.localOneTimeKeyId === null || parsed.localOneTimeKeyId === undefined
|
|
198
199
|
? Promise.resolve(null)
|
|
199
|
-
: requirePreKey(this.
|
|
200
|
+
: requirePreKey(this.stores.preKey, parsed.localOneTimeKeyId)
|
|
200
201
|
]);
|
|
201
202
|
const incoming = await initiateSessionIncoming(local, parsed.remote, parsed.sessionBaseKey, {
|
|
202
203
|
signed: toSerializedKeyPair(signedPreKey.keyPair),
|
|
@@ -210,7 +211,7 @@ export class SignalProtocol {
|
|
|
210
211
|
? {
|
|
211
212
|
...incoming,
|
|
212
213
|
prevSessions: [
|
|
213
|
-
detachSession(currentSession),
|
|
214
|
+
encodeSignalSessionSnapshot(detachSession(currentSession)),
|
|
214
215
|
...currentSession.prevSessions.slice(0, MAX_PREV_SESSIONS - 1)
|
|
215
216
|
]
|
|
216
217
|
}
|
|
@@ -218,7 +219,7 @@ export class SignalProtocol {
|
|
|
218
219
|
const [updatedSession, plaintext] = await decryptMsgFromSession(baseSession, parsed);
|
|
219
220
|
// Only consume one-time prekeys after successful decrypt/session materialization.
|
|
220
221
|
if (parsed.localOneTimeKeyId !== null && parsed.localOneTimeKeyId !== undefined) {
|
|
221
|
-
await this.
|
|
222
|
+
await this.stores.preKey.consumePreKeyById(parsed.localOneTimeKeyId);
|
|
222
223
|
}
|
|
223
224
|
return {
|
|
224
225
|
updatedSession,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { aesCbcDecrypt, aesCbcEncrypt, hkdf, importAesCbcKey, importHmacKey,
|
|
1
|
+
import { aesCbcDecrypt, aesCbcEncrypt, hkdf, hmacSign, importAesCbcKey, importHmacKey, prependVersion, toSerializedPubKey } from '../../crypto/index.js';
|
|
2
2
|
import { proto } from '../../proto.js';
|
|
3
3
|
import { CHAIN_KEY_LABEL, FUTURE_MESSAGES_MAX, MAX_UNUSED_KEYS, MESSAGE_KEY_LABEL, SIGNAL_MAC_SIZE, SIGNAL_VERSION } from '../constants.js';
|
|
4
|
-
import {
|
|
4
|
+
import { decodeSignalMessageKey, decodeSignalRecvChain, decodeSignalSessionSnapshot, encodeSignalRecvChain, encodeSignalSessionSnapshot } from '../encoding.js';
|
|
5
|
+
import { calculateRatchet, detachSession, generateSerializedKeyPair, snapshotToRecord } from '../session/SignalSession.js';
|
|
5
6
|
import { concatBytes, removeAt, uint8Equal } from '../../util/bytes.js';
|
|
6
7
|
import { toError } from '../../util/primitives.js';
|
|
7
8
|
const MAX_TRACKED_RECV_CHAINS = 4;
|
|
@@ -35,7 +36,7 @@ export async function selectMessageKey(chain, targetCounter) {
|
|
|
35
36
|
if (idx === -1) {
|
|
36
37
|
throw new Error('duplicate message');
|
|
37
38
|
}
|
|
38
|
-
const messageKey = unused[idx];
|
|
39
|
+
const messageKey = decodeSignalMessageKey(unused[idx], `unusedMsgKeys[${idx}]`);
|
|
39
40
|
const nextUnused = removeAt(unused, idx);
|
|
40
41
|
return {
|
|
41
42
|
messageKey,
|
|
@@ -73,7 +74,12 @@ export async function selectMessageKey(chain, targetCounter) {
|
|
|
73
74
|
overflow -= 1;
|
|
74
75
|
}
|
|
75
76
|
else {
|
|
76
|
-
nextUnused.push(
|
|
77
|
+
nextUnused.push({
|
|
78
|
+
index: currentMessageKey.index,
|
|
79
|
+
cipherKey: currentMessageKey.cipherKey,
|
|
80
|
+
macKey: currentMessageKey.macKey,
|
|
81
|
+
iv: currentMessageKey.iv
|
|
82
|
+
});
|
|
77
83
|
}
|
|
78
84
|
const derived = await deriveMsgKeyFromState(counter, chainState);
|
|
79
85
|
currentMessageKey = derived.messageKey;
|
|
@@ -174,13 +180,14 @@ export async function decryptMsg(session, parsed, onPrevSessionDecryptError) {
|
|
|
174
180
|
}
|
|
175
181
|
catch (error) {
|
|
176
182
|
for (let i = 0; i < session.prevSessions.length; i += 1) {
|
|
177
|
-
const
|
|
183
|
+
const decodedPrev = decodeSignalSessionSnapshot(session.prevSessions[i], `prevSessions[${i}]`);
|
|
184
|
+
const prevSession = snapshotToRecord(decodedPrev);
|
|
178
185
|
try {
|
|
179
186
|
const [updatedPrev, plaintext] = await decryptMsgFromSession(prevSession, parsed);
|
|
180
187
|
const updatedSession = {
|
|
181
188
|
...updatedPrev,
|
|
182
189
|
prevSessions: [
|
|
183
|
-
detachSession(session),
|
|
190
|
+
encodeSignalSessionSnapshot(detachSession(session)),
|
|
184
191
|
...session.prevSessions.slice(0, i),
|
|
185
192
|
...session.prevSessions.slice(i + 1)
|
|
186
193
|
]
|
|
@@ -207,7 +214,10 @@ export async function decryptMsg(session, parsed, onPrevSessionDecryptError) {
|
|
|
207
214
|
}
|
|
208
215
|
export async function decryptMsgFromSession(session, message) {
|
|
209
216
|
const ratchetPubKey = toSerializedPubKey(message.ratchetPubKey);
|
|
210
|
-
const recvChainIndex = session.recvChains.findIndex((
|
|
217
|
+
const recvChainIndex = session.recvChains.findIndex((raw) => {
|
|
218
|
+
const key = raw.senderRatchetKey;
|
|
219
|
+
return key !== null && key !== undefined && uint8Equal(key, ratchetPubKey);
|
|
220
|
+
});
|
|
211
221
|
let selectedMessageKey;
|
|
212
222
|
let updatedSession;
|
|
213
223
|
if (recvChainIndex === -1) {
|
|
@@ -225,7 +235,7 @@ export async function decryptMsgFromSession(session, message) {
|
|
|
225
235
|
selectedMessageKey = selected.messageKey;
|
|
226
236
|
const sendRatchet = await calculateRatchet(recvRatchet.rootKey, newSendRatchet, ratchetPubKey);
|
|
227
237
|
const nextRecvChains = session.recvChains.slice(-MAX_TRACKED_RECV_CHAINS);
|
|
228
|
-
nextRecvChains.push(selected.updatedChain);
|
|
238
|
+
nextRecvChains.push(encodeSignalRecvChain(selected.updatedChain));
|
|
229
239
|
updatedSession = {
|
|
230
240
|
...session,
|
|
231
241
|
rootKey: sendRatchet.rootKey,
|
|
@@ -240,10 +250,11 @@ export async function decryptMsgFromSession(session, message) {
|
|
|
240
250
|
};
|
|
241
251
|
}
|
|
242
252
|
else {
|
|
243
|
-
const
|
|
253
|
+
const decoded = decodeSignalRecvChain(session.recvChains[recvChainIndex], `recvChains[${recvChainIndex}]`);
|
|
254
|
+
const selected = await selectMessageKey(decoded, message.counter);
|
|
244
255
|
selectedMessageKey = selected.messageKey;
|
|
245
256
|
const nextRecvChains = session.recvChains.slice();
|
|
246
|
-
nextRecvChains[recvChainIndex] = selected.updatedChain;
|
|
257
|
+
nextRecvChains[recvChainIndex] = encodeSignalRecvChain(selected.updatedChain);
|
|
247
258
|
updatedSession = {
|
|
248
259
|
...session,
|
|
249
260
|
recvChains: nextRecvChains
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readVersionedContent, toSerializedPubKey } from '../../crypto/index.js';
|
|
2
2
|
import { proto } from '../../proto.js';
|
|
3
3
|
import { SIGNAL_MAC_SIZE, SIGNAL_VERSION } from '../constants.js';
|
|
4
|
-
import { toBytesView } from '../../util/bytes.js';
|
|
5
4
|
export function deserializeMsg(versionContentMac) {
|
|
6
5
|
const content = readVersionedContent(versionContentMac, SIGNAL_VERSION, SIGNAL_MAC_SIZE);
|
|
7
6
|
const parsed = proto.SignalMessage.decode(content);
|
|
@@ -14,9 +13,9 @@ export function deserializeMsg(versionContentMac) {
|
|
|
14
13
|
throw new Error('invalid signal message');
|
|
15
14
|
}
|
|
16
15
|
return {
|
|
17
|
-
ratchetPubKey: toSerializedPubKey(
|
|
16
|
+
ratchetPubKey: toSerializedPubKey(parsed.ratchetKey),
|
|
18
17
|
counter: parsed.counter,
|
|
19
|
-
ciphertext:
|
|
18
|
+
ciphertext: parsed.ciphertext,
|
|
20
19
|
versionContentMac
|
|
21
20
|
};
|
|
22
21
|
}
|
|
@@ -35,14 +34,14 @@ export function deserializePkMsg(versionContent) {
|
|
|
35
34
|
parsed.message === undefined) {
|
|
36
35
|
throw new Error('invalid prekey signal message');
|
|
37
36
|
}
|
|
38
|
-
const signal = deserializeMsg(
|
|
37
|
+
const signal = deserializeMsg(parsed.message);
|
|
39
38
|
return {
|
|
40
39
|
...signal,
|
|
41
40
|
remote: {
|
|
42
41
|
regId: parsed.registrationId,
|
|
43
|
-
pubKey: toSerializedPubKey(
|
|
42
|
+
pubKey: toSerializedPubKey(parsed.identityKey)
|
|
44
43
|
},
|
|
45
|
-
sessionBaseKey: toSerializedPubKey(
|
|
44
|
+
sessionBaseKey: toSerializedPubKey(parsed.baseKey),
|
|
46
45
|
localSignedPreKeyId: parsed.signedPreKeyId,
|
|
47
46
|
localOneTimeKeyId: parsed.preKeyId ?? null
|
|
48
47
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hkdfSplit, toRawPubKey, toSerializedPubKey, X25519 } from '../../crypto/index.js';
|
|
2
2
|
import { SIGNAL_PREFIX } from '../constants.js';
|
|
3
|
+
import { decodeSignalSessionSnapshot, encodeSignalSessionSnapshot } from '../encoding.js';
|
|
3
4
|
import { concatBytes, uint8Equal } from '../../util/bytes.js';
|
|
4
5
|
export function snapshotToRecord(snapshot) {
|
|
5
6
|
return {
|
|
@@ -21,19 +22,21 @@ export function findMatchingSession(session, sessionBaseKey) {
|
|
|
21
22
|
return session;
|
|
22
23
|
}
|
|
23
24
|
for (let index = 0; index < session.prevSessions.length; index += 1) {
|
|
24
|
-
const
|
|
25
|
-
if (!
|
|
26
|
-
!uint8Equal(previousSession.aliceBaseKey, serializedBaseKey)) {
|
|
25
|
+
const rawPrev = session.prevSessions[index];
|
|
26
|
+
if (!rawPrev.aliceBaseKey || !uint8Equal(rawPrev.aliceBaseKey, serializedBaseKey)) {
|
|
27
27
|
continue;
|
|
28
28
|
}
|
|
29
|
-
const
|
|
29
|
+
const decoded = decodeSignalSessionSnapshot(rawPrev, `prevSessions[${index}]`);
|
|
30
|
+
const prevSessions = [
|
|
31
|
+
encodeSignalSessionSnapshot(detachSession(session))
|
|
32
|
+
];
|
|
30
33
|
for (let i = 0; i < session.prevSessions.length; i += 1) {
|
|
31
34
|
if (i !== index) {
|
|
32
35
|
prevSessions.push(session.prevSessions[i]);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
return {
|
|
36
|
-
...
|
|
39
|
+
...decoded,
|
|
37
40
|
prevSessions
|
|
38
41
|
};
|
|
39
42
|
}
|
|
@@ -73,10 +76,9 @@ export async function initiateSessionOutgoing(local, remoteBundle, localOneTimeB
|
|
|
73
76
|
]);
|
|
74
77
|
const [rootKey, chainKey] = await hkdfSplit(secret, null, 'WhisperText');
|
|
75
78
|
const recvChain = {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
unusedMsgKeys: []
|
|
79
|
+
senderRatchetKey: remoteRatchetKey,
|
|
80
|
+
chainKey: { index: 0, key: chainKey },
|
|
81
|
+
messageKeys: []
|
|
80
82
|
};
|
|
81
83
|
const sendRatchet = await generateSerializedKeyPair();
|
|
82
84
|
const sendRatchetResult = await calculateRatchet(rootKey, sendRatchet, remoteRatchetKey);
|
|
@@ -4,7 +4,7 @@ import { normalizeDeviceJid, parseSignalAddressFromJid, signalAddressKey } from
|
|
|
4
4
|
import { bytesToHex, uint8Equal } from '../../util/bytes.js';
|
|
5
5
|
import { toError } from '../../util/primitives.js';
|
|
6
6
|
export function createSignalSessionResolver(options) {
|
|
7
|
-
const { signalProtocol,
|
|
7
|
+
const { signalProtocol, sessionStore, identityStore, signalIdentitySync, signalSessionSync, logger } = options;
|
|
8
8
|
const dedup = new PromiseDedup();
|
|
9
9
|
const ensureSessionInternal = async (address, jid, expectedIdentity, reasonIdentity = false, prefetchedBundle) => {
|
|
10
10
|
const expectedSerializedIdentity = expectedIdentity
|
|
@@ -13,9 +13,9 @@ export function createSignalSessionResolver(options) {
|
|
|
13
13
|
if (reasonIdentity) {
|
|
14
14
|
await signalIdentitySync.syncIdentityKeys([jid]);
|
|
15
15
|
}
|
|
16
|
-
if (await
|
|
16
|
+
if (await sessionStore.hasSession(address)) {
|
|
17
17
|
if (expectedSerializedIdentity) {
|
|
18
|
-
const storedIdentity = await
|
|
18
|
+
const storedIdentity = await identityStore.getRemoteIdentity(address);
|
|
19
19
|
if (!storedIdentity || !uint8Equal(storedIdentity, expectedSerializedIdentity)) {
|
|
20
20
|
throw new Error('identity mismatch');
|
|
21
21
|
}
|
|
@@ -38,7 +38,7 @@ export function createSignalSessionResolver(options) {
|
|
|
38
38
|
}
|
|
39
39
|
const remoteIdentity = toSerializedPubKey(fetched.bundle.identity);
|
|
40
40
|
if (reasonIdentity) {
|
|
41
|
-
const storedIdentity = await
|
|
41
|
+
const storedIdentity = await identityStore.getRemoteIdentity(address);
|
|
42
42
|
if (storedIdentity && !uint8Equal(remoteIdentity, storedIdentity)) {
|
|
43
43
|
throw new Error('identity mismatch');
|
|
44
44
|
}
|
|
@@ -96,7 +96,7 @@ export function createSignalSessionResolver(options) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
const resolvedByIndex = (await
|
|
99
|
+
const resolvedByIndex = (await sessionStore.getSessionsBatch(normalizedTargetAddresses));
|
|
100
100
|
const collectResolvedTargets = () => {
|
|
101
101
|
const resolvedTargets = new Array(normalizedTargetJids.length);
|
|
102
102
|
let resolvedTargetCount = 0;
|
|
@@ -199,7 +199,7 @@ export function createSignalSessionResolver(options) {
|
|
|
199
199
|
for (let i = 0; i < fallbackIndices.length; i++) {
|
|
200
200
|
fallbackAddresses[i] = normalizedTargetAddresses[fallbackIndices[i]];
|
|
201
201
|
}
|
|
202
|
-
const fallbackSessions = await
|
|
202
|
+
const fallbackSessions = await sessionStore.getSessionsBatch(fallbackAddresses);
|
|
203
203
|
for (let i = 0; i < fallbackIndices.length; i++) {
|
|
204
204
|
const session = fallbackSessions[i];
|
|
205
205
|
if (session) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|