@zapo-js/fake-server 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 +176 -0
- package/dist/api/AppStateSyncManager.d.ts +27 -0
- package/dist/api/AppStateSyncManager.d.ts.map +1 -0
- package/dist/api/AppStateSyncManager.js +151 -0
- package/dist/api/AppStateSyncManager.js.map +1 -0
- package/dist/api/FakePairingDriver.d.ts +27 -0
- package/dist/api/FakePairingDriver.d.ts.map +1 -0
- package/dist/api/FakePairingDriver.js +36 -0
- package/dist/api/FakePairingDriver.js.map +1 -0
- package/dist/api/FakePeer.d.ts +143 -0
- package/dist/api/FakePeer.d.ts.map +1 -0
- package/dist/api/FakePeer.js +408 -0
- package/dist/api/FakePeer.js.map +1 -0
- package/dist/api/FakeWaServer.d.ts +167 -0
- package/dist/api/FakeWaServer.d.ts.map +1 -0
- package/dist/api/FakeWaServer.js +652 -0
- package/dist/api/FakeWaServer.js.map +1 -0
- package/dist/api/PreKeyDispenser.d.ts +23 -0
- package/dist/api/PreKeyDispenser.d.ts.map +1 -0
- package/dist/api/PreKeyDispenser.js +98 -0
- package/dist/api/PreKeyDispenser.js.map +1 -0
- package/dist/api/Scenario.d.ts +24 -0
- package/dist/api/Scenario.d.ts.map +1 -0
- package/dist/api/Scenario.js +38 -0
- package/dist/api/Scenario.js.map +1 -0
- package/dist/api/ServerRegistries.d.ts +110 -0
- package/dist/api/ServerRegistries.d.ts.map +1 -0
- package/dist/api/ServerRegistries.js +268 -0
- package/dist/api/ServerRegistries.js.map +1 -0
- package/dist/api/iq-handlers.d.ts +47 -0
- package/dist/api/iq-handlers.d.ts.map +1 -0
- package/dist/api/iq-handlers.js +498 -0
- package/dist/api/iq-handlers.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +249 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/WaFakeConnection.d.ts +23 -0
- package/dist/infra/WaFakeConnection.d.ts.map +1 -0
- package/dist/infra/WaFakeConnection.js +54 -0
- package/dist/infra/WaFakeConnection.js.map +1 -0
- package/dist/infra/WaFakeConnectionPipeline.d.ts +51 -0
- package/dist/infra/WaFakeConnectionPipeline.d.ts.map +1 -0
- package/dist/infra/WaFakeConnectionPipeline.js +224 -0
- package/dist/infra/WaFakeConnectionPipeline.js.map +1 -0
- package/dist/infra/WaFakeFrameSocket.d.ts +29 -0
- package/dist/infra/WaFakeFrameSocket.d.ts.map +1 -0
- package/dist/infra/WaFakeFrameSocket.js +122 -0
- package/dist/infra/WaFakeFrameSocket.js.map +1 -0
- package/dist/infra/WaFakeMediaHttpsServer.d.ts +16 -0
- package/dist/infra/WaFakeMediaHttpsServer.d.ts.map +1 -0
- package/dist/infra/WaFakeMediaHttpsServer.js +131 -0
- package/dist/infra/WaFakeMediaHttpsServer.js.map +1 -0
- package/dist/infra/WaFakeNoiseHandshake.d.ts +23 -0
- package/dist/infra/WaFakeNoiseHandshake.d.ts.map +1 -0
- package/dist/infra/WaFakeNoiseHandshake.js +76 -0
- package/dist/infra/WaFakeNoiseHandshake.js.map +1 -0
- package/dist/infra/WaFakeTransport.d.ts +15 -0
- package/dist/infra/WaFakeTransport.d.ts.map +1 -0
- package/dist/infra/WaFakeTransport.js +34 -0
- package/dist/infra/WaFakeTransport.js.map +1 -0
- package/dist/infra/WaFakeWsServer.d.ts +29 -0
- package/dist/infra/WaFakeWsServer.d.ts.map +1 -0
- package/dist/infra/WaFakeWsServer.js +101 -0
- package/dist/infra/WaFakeWsServer.js.map +1 -0
- package/dist/protocol/auth/cert-chain.d.ts +18 -0
- package/dist/protocol/auth/cert-chain.d.ts.map +1 -0
- package/dist/protocol/auth/cert-chain.js +44 -0
- package/dist/protocol/auth/cert-chain.js.map +1 -0
- package/dist/protocol/auth/client-payload-validate.d.ts +21 -0
- package/dist/protocol/auth/client-payload-validate.d.ts.map +1 -0
- package/dist/protocol/auth/client-payload-validate.js +61 -0
- package/dist/protocol/auth/client-payload-validate.js.map +1 -0
- package/dist/protocol/auth/fake-primary-device.d.ts +19 -0
- package/dist/protocol/auth/fake-primary-device.d.ts.map +1 -0
- package/dist/protocol/auth/fake-primary-device.js +53 -0
- package/dist/protocol/auth/fake-primary-device.js.map +1 -0
- package/dist/protocol/auth/pair-device.d.ts +26 -0
- package/dist/protocol/auth/pair-device.d.ts.map +1 -0
- package/dist/protocol/auth/pair-device.js +104 -0
- package/dist/protocol/auth/pair-device.js.map +1 -0
- package/dist/protocol/auth/success-node.d.ts +15 -0
- package/dist/protocol/auth/success-node.d.ts.map +1 -0
- package/dist/protocol/auth/success-node.js +30 -0
- package/dist/protocol/auth/success-node.js.map +1 -0
- package/dist/protocol/iq/abprops.d.ts +14 -0
- package/dist/protocol/iq/abprops.d.ts.map +1 -0
- package/dist/protocol/iq/abprops.js +34 -0
- package/dist/protocol/iq/abprops.js.map +1 -0
- package/dist/protocol/iq/appstate-sync.d.ts +38 -0
- package/dist/protocol/iq/appstate-sync.d.ts.map +1 -0
- package/dist/protocol/iq/appstate-sync.js +154 -0
- package/dist/protocol/iq/appstate-sync.js.map +1 -0
- package/dist/protocol/iq/business.d.ts +13 -0
- package/dist/protocol/iq/business.d.ts.map +1 -0
- package/dist/protocol/iq/business.js +64 -0
- package/dist/protocol/iq/business.js.map +1 -0
- package/dist/protocol/iq/dirty-bits.d.ts +8 -0
- package/dist/protocol/iq/dirty-bits.d.ts.map +1 -0
- package/dist/protocol/iq/dirty-bits.js +23 -0
- package/dist/protocol/iq/dirty-bits.js.map +1 -0
- package/dist/protocol/iq/group-ops.d.ts +34 -0
- package/dist/protocol/iq/group-ops.d.ts.map +1 -0
- package/dist/protocol/iq/group-ops.js +164 -0
- package/dist/protocol/iq/group-ops.js.map +1 -0
- package/dist/protocol/iq/newsletter.d.ts +4 -0
- package/dist/protocol/iq/newsletter.d.ts.map +1 -0
- package/dist/protocol/iq/newsletter.js +18 -0
- package/dist/protocol/iq/newsletter.js.map +1 -0
- package/dist/protocol/iq/prekey-fetch.d.ts +18 -0
- package/dist/protocol/iq/prekey-fetch.d.ts.map +1 -0
- package/dist/protocol/iq/prekey-fetch.js +92 -0
- package/dist/protocol/iq/prekey-fetch.js.map +1 -0
- package/dist/protocol/iq/privacy-token.d.ts +9 -0
- package/dist/protocol/iq/privacy-token.d.ts.map +1 -0
- package/dist/protocol/iq/privacy-token.js +30 -0
- package/dist/protocol/iq/privacy-token.js.map +1 -0
- package/dist/protocol/iq/privacy.d.ts +22 -0
- package/dist/protocol/iq/privacy.d.ts.map +1 -0
- package/dist/protocol/iq/privacy.js +133 -0
- package/dist/protocol/iq/privacy.js.map +1 -0
- package/dist/protocol/iq/profile.d.ts +22 -0
- package/dist/protocol/iq/profile.d.ts.map +1 -0
- package/dist/protocol/iq/profile.js +80 -0
- package/dist/protocol/iq/profile.js.map +1 -0
- package/dist/protocol/iq/router.d.ts +39 -0
- package/dist/protocol/iq/router.d.ts.map +1 -0
- package/dist/protocol/iq/router.js +118 -0
- package/dist/protocol/iq/router.js.map +1 -0
- package/dist/protocol/iq/usync.d.ts +8 -0
- package/dist/protocol/iq/usync.d.ts.map +1 -0
- package/dist/protocol/iq/usync.js +68 -0
- package/dist/protocol/iq/usync.js.map +1 -0
- package/dist/protocol/push/app-state-key-share.d.ts +17 -0
- package/dist/protocol/push/app-state-key-share.d.ts.map +1 -0
- package/dist/protocol/push/app-state-key-share.js +30 -0
- package/dist/protocol/push/app-state-key-share.js.map +1 -0
- package/dist/protocol/push/call-failure.d.ts +16 -0
- package/dist/protocol/push/call-failure.d.ts.map +1 -0
- package/dist/protocol/push/call-failure.js +32 -0
- package/dist/protocol/push/call-failure.js.map +1 -0
- package/dist/protocol/push/chatstate.d.ts +15 -0
- package/dist/protocol/push/chatstate.d.ts.map +1 -0
- package/dist/protocol/push/chatstate.js +27 -0
- package/dist/protocol/push/chatstate.js.map +1 -0
- package/dist/protocol/push/error-stanza.d.ts +8 -0
- package/dist/protocol/push/error-stanza.d.ts.map +1 -0
- package/dist/protocol/push/error-stanza.js +17 -0
- package/dist/protocol/push/error-stanza.js.map +1 -0
- package/dist/protocol/push/history-sync.d.ts +46 -0
- package/dist/protocol/push/history-sync.d.ts.map +1 -0
- package/dist/protocol/push/history-sync.js +117 -0
- package/dist/protocol/push/history-sync.js.map +1 -0
- package/dist/protocol/push/message.d.ts +21 -0
- package/dist/protocol/push/message.d.ts.map +1 -0
- package/dist/protocol/push/message.js +42 -0
- package/dist/protocol/push/message.js.map +1 -0
- package/dist/protocol/push/notification.d.ts +21 -0
- package/dist/protocol/push/notification.d.ts.map +1 -0
- package/dist/protocol/push/notification.js +34 -0
- package/dist/protocol/push/notification.js.map +1 -0
- package/dist/protocol/push/presence.d.ts +11 -0
- package/dist/protocol/push/presence.d.ts.map +1 -0
- package/dist/protocol/push/presence.js +18 -0
- package/dist/protocol/push/presence.js.map +1 -0
- package/dist/protocol/push/receipt.d.ts +14 -0
- package/dist/protocol/push/receipt.d.ts.map +1 -0
- package/dist/protocol/push/receipt.js +25 -0
- package/dist/protocol/push/receipt.js.map +1 -0
- package/dist/protocol/signal/fake-app-state-crypto.d.ts +49 -0
- package/dist/protocol/signal/fake-app-state-crypto.d.ts.map +1 -0
- package/dist/protocol/signal/fake-app-state-crypto.js +202 -0
- package/dist/protocol/signal/fake-app-state-crypto.js.map +1 -0
- package/dist/protocol/signal/fake-peer-double-ratchet.d.ts +38 -0
- package/dist/protocol/signal/fake-peer-double-ratchet.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-double-ratchet.js +408 -0
- package/dist/protocol/signal/fake-peer-double-ratchet.js.map +1 -0
- package/dist/protocol/signal/fake-peer-group-recv-session.d.ts +10 -0
- package/dist/protocol/signal/fake-peer-group-recv-session.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-group-recv-session.js +129 -0
- package/dist/protocol/signal/fake-peer-group-recv-session.js.map +1 -0
- package/dist/protocol/signal/fake-peer-identity.d.ts +7 -0
- package/dist/protocol/signal/fake-peer-identity.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-identity.js +12 -0
- package/dist/protocol/signal/fake-peer-identity.js.map +1 -0
- package/dist/protocol/signal/fake-peer-key-bundle.d.ts +24 -0
- package/dist/protocol/signal/fake-peer-key-bundle.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-key-bundle.js +29 -0
- package/dist/protocol/signal/fake-peer-key-bundle.js.map +1 -0
- package/dist/protocol/signal/fake-peer-recv-session.d.ts +60 -0
- package/dist/protocol/signal/fake-peer-recv-session.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-recv-session.js +284 -0
- package/dist/protocol/signal/fake-peer-recv-session.js.map +1 -0
- package/dist/protocol/signal/fake-peer-session.d.ts +87 -0
- package/dist/protocol/signal/fake-peer-session.d.ts.map +1 -0
- package/dist/protocol/signal/fake-peer-session.js +207 -0
- package/dist/protocol/signal/fake-peer-session.js.map +1 -0
- package/dist/protocol/signal/fake-sender-key.d.ts +15 -0
- package/dist/protocol/signal/fake-sender-key.d.ts.map +1 -0
- package/dist/protocol/signal/fake-sender-key.js +91 -0
- package/dist/protocol/signal/fake-sender-key.js.map +1 -0
- package/dist/protocol/signal/prekey-upload.d.ts +22 -0
- package/dist/protocol/signal/prekey-upload.d.ts.map +1 -0
- package/dist/protocol/signal/prekey-upload.js +113 -0
- package/dist/protocol/signal/prekey-upload.js.map +1 -0
- package/dist/protocol/stream/stream-error.d.ts +8 -0
- package/dist/protocol/stream/stream-error.d.ts.map +1 -0
- package/dist/protocol/stream/stream-error.js +64 -0
- package/dist/protocol/stream/stream-error.js.map +1 -0
- package/dist/state/fake-app-state-collection.d.ts +35 -0
- package/dist/state/fake-app-state-collection.d.ts.map +1 -0
- package/dist/state/fake-app-state-collection.js +139 -0
- package/dist/state/fake-app-state-collection.js.map +1 -0
- package/dist/state/fake-media-store.d.ts +35 -0
- package/dist/state/fake-media-store.d.ts.map +1 -0
- package/dist/state/fake-media-store.js +57 -0
- package/dist/state/fake-media-store.js.map +1 -0
- package/dist/transport/codec.d.ts +10 -0
- package/dist/transport/codec.d.ts.map +1 -0
- package/dist/transport/codec.js +17 -0
- package/dist/transport/codec.js.map +1 -0
- package/dist/transport/crypto.d.ts +11 -0
- package/dist/transport/crypto.d.ts.map +1 -0
- package/dist/transport/crypto.js +36 -0
- package/dist/transport/crypto.js.map +1 -0
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +20 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/protos.d.ts +10 -0
- package/dist/transport/protos.d.ts.map +1 -0
- package/dist/transport/protos.js +13 -0
- package/dist/transport/protos.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Generates Signal prekey bundles for fake peers. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.generateFakePeerKeyBundle = generateFakePeerKeyBundle;
|
|
5
|
+
const crypto_1 = require("../../transport/crypto");
|
|
6
|
+
async function generateFakePeerKeyBundle(options = {}) {
|
|
7
|
+
const identityKeyPair = options.identityKeyPair ?? (await crypto_1.X25519.generateKeyPair());
|
|
8
|
+
const signedPreKeyKeyPair = await crypto_1.X25519.generateKeyPair();
|
|
9
|
+
const signedPreKeyId = options.signedPreKeyId ?? 1;
|
|
10
|
+
const signedPreKeySerialized = (0, crypto_1.toSerializedPubKey)(signedPreKeyKeyPair.pubKey);
|
|
11
|
+
const signedPreKeySignature = await (0, crypto_1.xeddsaSign)(identityKeyPair.privKey, signedPreKeySerialized);
|
|
12
|
+
const oneTimeCount = options.oneTimePreKeyCount ?? 4;
|
|
13
|
+
const firstId = options.firstOneTimePreKeyId ?? 1;
|
|
14
|
+
const oneTimePreKeys = await Promise.all(Array.from({ length: oneTimeCount }, async (_, idx) => ({
|
|
15
|
+
id: firstId + idx,
|
|
16
|
+
keyPair: await crypto_1.X25519.generateKeyPair()
|
|
17
|
+
})));
|
|
18
|
+
return {
|
|
19
|
+
registrationId: options.registrationId ?? Math.floor(Math.random() * 0x3fff) + 1,
|
|
20
|
+
identityKeyPair,
|
|
21
|
+
signedPreKey: {
|
|
22
|
+
id: signedPreKeyId,
|
|
23
|
+
keyPair: signedPreKeyKeyPair,
|
|
24
|
+
signature: signedPreKeySignature
|
|
25
|
+
},
|
|
26
|
+
oneTimePreKeys
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=fake-peer-key-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-peer-key-bundle.js","sourceRoot":"","sources":["../../../src/protocol/signal/fake-peer-key-bundle.ts"],"names":[],"mappings":";AAAA,sDAAsD;;AA0BtD,8DA4BC;AApDD,mDAAmG;AAwB5F,KAAK,UAAU,yBAAyB,CAC3C,UAA4C,EAAE;IAE9C,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,MAAM,eAAM,CAAC,eAAe,EAAE,CAAC,CAAA;IACnF,MAAM,mBAAmB,GAAG,MAAM,eAAM,CAAC,eAAe,EAAE,CAAA;IAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,CAAA;IAClD,MAAM,sBAAsB,GAAG,IAAA,2BAAkB,EAAC,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAC7E,MAAM,qBAAqB,GAAG,MAAM,IAAA,mBAAU,EAAC,eAAe,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAA;IAE/F,MAAM,YAAY,GAAG,OAAO,CAAC,kBAAkB,IAAI,CAAC,CAAA;IACpD,MAAM,OAAO,GAAG,OAAO,CAAC,oBAAoB,IAAI,CAAC,CAAA;IACjD,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACpD,EAAE,EAAE,OAAO,GAAG,GAAG;QACjB,OAAO,EAAE,MAAM,eAAM,CAAC,eAAe,EAAE;KAC1C,CAAC,CAAC,CACN,CAAA;IAED,OAAO;QACH,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;QAChF,eAAe;QACf,YAAY,EAAE;YACV,EAAE,EAAE,cAAc;YAClB,OAAO,EAAE,mBAAmB;YAC5B,SAAS,EAAE,qBAAqB;SACnC;QACD,cAAc;KACjB,CAAA;AACL,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fake-peer-side Signal Protocol RECEIVE session.
|
|
3
|
+
*
|
|
4
|
+
* Decrypts inbound `PreKeySignalMessage` (`pkmsg`) and `SignalMessage`
|
|
5
|
+
* (`msg`) ciphertexts the real `WaClient` sends to the peer. Pairs with
|
|
6
|
+
* `FakePeerSession` (the encrypter half) so a fake peer can carry both
|
|
7
|
+
* sides of a 1:1 signal conversation.
|
|
8
|
+
*
|
|
9
|
+
* Sources:
|
|
10
|
+
* /deobfuscated/WASignal/WASignalWhitepaper.js
|
|
11
|
+
* (initiateSessionIncoming, deriveMsgKey)
|
|
12
|
+
* /deobfuscated/WASignal/WASignalCipher.js
|
|
13
|
+
* /deobfuscated/pb/WASignalWhisperTextProtocol_pb.js
|
|
14
|
+
*
|
|
15
|
+
* Cross-checked against the lib's `initiateSessionIncoming` /
|
|
16
|
+
* `decryptMsg` (`src/signal/session/SignalSession.ts`,
|
|
17
|
+
* `src/signal/session/SignalRatchet.ts`).
|
|
18
|
+
*
|
|
19
|
+
* Scope: a single chain of pkmsg + subsequent msgs from the client. We
|
|
20
|
+
* do NOT implement the full Double Ratchet rotation across multiple
|
|
21
|
+
* client→server message bursts (no recv-chain-replace on new ratchet
|
|
22
|
+
* keys). The first message uses the "Bob role" X3DH and after that we
|
|
23
|
+
* keep deriving from the same chain key. This is enough for tests that
|
|
24
|
+
* send 1-N messages in the same chain, which covers the common
|
|
25
|
+
* outbound-test scenario.
|
|
26
|
+
*/
|
|
27
|
+
import type { FakePeerKeyBundle } from './fake-peer-key-bundle';
|
|
28
|
+
export declare class FakePeerRecvSessionError extends Error {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Per-(remote-identity) recv state on the fake peer side.
|
|
33
|
+
*
|
|
34
|
+
* The session is bootstrapped lazily on the first inbound `pkmsg` for
|
|
35
|
+
* a given remote identity, and reused for subsequent `msg` ciphertexts
|
|
36
|
+
* in the same Double Ratchet chain.
|
|
37
|
+
*/
|
|
38
|
+
export declare class FakePeerRecvSession {
|
|
39
|
+
private readonly keyBundle;
|
|
40
|
+
/** 33-byte serialized remote identity pubkey (set on first pkmsg). */
|
|
41
|
+
private remoteIdentityPub;
|
|
42
|
+
private recvChain;
|
|
43
|
+
/** Root key from the X3DH derivation, used for the first DR step. */
|
|
44
|
+
private bootstrapRootKey;
|
|
45
|
+
constructor(keyBundle: FakePeerKeyBundle);
|
|
46
|
+
/**
|
|
47
|
+
* Decrypts a `<enc type="pkmsg"/>` payload. Bootstraps the recv
|
|
48
|
+
* session via the X3DH responder ("Bob") flow on the first call,
|
|
49
|
+
* then derives the message key and returns the (still padded)
|
|
50
|
+
* plaintext bytes.
|
|
51
|
+
*/
|
|
52
|
+
decryptPreKeyMessage(envelope: Uint8Array): Promise<Uint8Array>;
|
|
53
|
+
/**
|
|
54
|
+
* Decrypts a `<enc type="msg"/>` payload. Requires the recv chain
|
|
55
|
+
* to have been established by a prior `decryptPreKeyMessage` call.
|
|
56
|
+
*/
|
|
57
|
+
decryptMessage(envelope: Uint8Array): Promise<Uint8Array>;
|
|
58
|
+
private decryptInnerSignalMessage;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=fake-peer-recv-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-peer-recv-session.d.ts","sourceRoot":"","sources":["../../../src/protocol/signal/fake-peer-recv-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAgBH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAQ/D,qBAAa,wBAAyB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAIrC;AASD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,sEAAsE;IACtE,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,SAAS,CAAyB;IAC1C,qEAAqE;IACrE,OAAO,CAAC,gBAAgB,CAA0B;gBAE/B,SAAS,EAAE,iBAAiB;IAI/C;;;;;OAKG;IACU,oBAAoB,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAgE5E;;;OAGG;IACU,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YASxD,yBAAyB;CAyG1C"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fake-peer-side Signal Protocol RECEIVE session.
|
|
4
|
+
*
|
|
5
|
+
* Decrypts inbound `PreKeySignalMessage` (`pkmsg`) and `SignalMessage`
|
|
6
|
+
* (`msg`) ciphertexts the real `WaClient` sends to the peer. Pairs with
|
|
7
|
+
* `FakePeerSession` (the encrypter half) so a fake peer can carry both
|
|
8
|
+
* sides of a 1:1 signal conversation.
|
|
9
|
+
*
|
|
10
|
+
* Sources:
|
|
11
|
+
* /deobfuscated/WASignal/WASignalWhitepaper.js
|
|
12
|
+
* (initiateSessionIncoming, deriveMsgKey)
|
|
13
|
+
* /deobfuscated/WASignal/WASignalCipher.js
|
|
14
|
+
* /deobfuscated/pb/WASignalWhisperTextProtocol_pb.js
|
|
15
|
+
*
|
|
16
|
+
* Cross-checked against the lib's `initiateSessionIncoming` /
|
|
17
|
+
* `decryptMsg` (`src/signal/session/SignalSession.ts`,
|
|
18
|
+
* `src/signal/session/SignalRatchet.ts`).
|
|
19
|
+
*
|
|
20
|
+
* Scope: a single chain of pkmsg + subsequent msgs from the client. We
|
|
21
|
+
* do NOT implement the full Double Ratchet rotation across multiple
|
|
22
|
+
* client→server message bursts (no recv-chain-replace on new ratchet
|
|
23
|
+
* keys). The first message uses the "Bob role" X3DH and after that we
|
|
24
|
+
* keep deriving from the same chain key. This is enough for tests that
|
|
25
|
+
* send 1-N messages in the same chain, which covers the common
|
|
26
|
+
* outbound-test scenario.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.FakePeerRecvSession = exports.FakePeerRecvSessionError = void 0;
|
|
30
|
+
const crypto_1 = require("../../transport/crypto");
|
|
31
|
+
const protos_1 = require("../../transport/protos");
|
|
32
|
+
const SIGNAL_VERSION = 3;
|
|
33
|
+
const SIGNAL_MAC_SIZE = 8;
|
|
34
|
+
const SIGNAL_PREFIX_FF = new Uint8Array(32).fill(0xff);
|
|
35
|
+
const MESSAGE_KEY_LABEL = new Uint8Array([1]);
|
|
36
|
+
const CHAIN_KEY_LABEL = new Uint8Array([2]);
|
|
37
|
+
class FakePeerRecvSessionError extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = 'FakePeerRecvSessionError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.FakePeerRecvSessionError = FakePeerRecvSessionError;
|
|
44
|
+
/**
|
|
45
|
+
* Per-(remote-identity) recv state on the fake peer side.
|
|
46
|
+
*
|
|
47
|
+
* The session is bootstrapped lazily on the first inbound `pkmsg` for
|
|
48
|
+
* a given remote identity, and reused for subsequent `msg` ciphertexts
|
|
49
|
+
* in the same Double Ratchet chain.
|
|
50
|
+
*/
|
|
51
|
+
class FakePeerRecvSession {
|
|
52
|
+
constructor(keyBundle) {
|
|
53
|
+
/** 33-byte serialized remote identity pubkey (set on first pkmsg). */
|
|
54
|
+
this.remoteIdentityPub = null;
|
|
55
|
+
this.recvChain = null;
|
|
56
|
+
/** Root key from the X3DH derivation, used for the first DR step. */
|
|
57
|
+
this.bootstrapRootKey = null;
|
|
58
|
+
this.keyBundle = keyBundle;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Decrypts a `<enc type="pkmsg"/>` payload. Bootstraps the recv
|
|
62
|
+
* session via the X3DH responder ("Bob") flow on the first call,
|
|
63
|
+
* then derives the message key and returns the (still padded)
|
|
64
|
+
* plaintext bytes.
|
|
65
|
+
*/
|
|
66
|
+
async decryptPreKeyMessage(envelope) {
|
|
67
|
+
const body = readVersionedBody(envelope, 0);
|
|
68
|
+
const preKeyMessage = protos_1.proto.PreKeySignalMessage.decode(body);
|
|
69
|
+
const baseKey = requireBytes(preKeyMessage.baseKey, 'baseKey');
|
|
70
|
+
const remoteIdentity = requireBytes(preKeyMessage.identityKey, 'identityKey');
|
|
71
|
+
const innerMessage = requireBytes(preKeyMessage.message, 'message');
|
|
72
|
+
const signedPreKeyId = preKeyMessage.signedPreKeyId;
|
|
73
|
+
if (signedPreKeyId === null || signedPreKeyId === undefined) {
|
|
74
|
+
throw new FakePeerRecvSessionError('PreKeySignalMessage missing signedPreKeyId');
|
|
75
|
+
}
|
|
76
|
+
if (signedPreKeyId !== this.keyBundle.signedPreKey.id) {
|
|
77
|
+
throw new FakePeerRecvSessionError(`signedPreKeyId mismatch: got ${signedPreKeyId}, expected ${this.keyBundle.signedPreKey.id}`);
|
|
78
|
+
}
|
|
79
|
+
const oneTimePreKeyId = preKeyMessage.preKeyId;
|
|
80
|
+
let oneTimePrivKey = null;
|
|
81
|
+
if (oneTimePreKeyId !== null && oneTimePreKeyId !== undefined) {
|
|
82
|
+
const oneTimeKeyEntry = this.keyBundle.oneTimePreKeys.find((entry) => entry.id === oneTimePreKeyId);
|
|
83
|
+
if (!oneTimeKeyEntry) {
|
|
84
|
+
throw new FakePeerRecvSessionError(`unknown one-time preKeyId ${oneTimePreKeyId}`);
|
|
85
|
+
}
|
|
86
|
+
oneTimePrivKey = oneTimeKeyEntry.keyPair.privKey;
|
|
87
|
+
}
|
|
88
|
+
// Bob-role X3DH:
|
|
89
|
+
// DH1 = ECDH(signedPreKey.priv, remote.identityPub)
|
|
90
|
+
// DH2 = ECDH(identity.priv, baseKey)
|
|
91
|
+
// DH3 = ECDH(signedPreKey.priv, baseKey)
|
|
92
|
+
// DH4 = ECDH(oneTimePreKey.priv, baseKey) [optional]
|
|
93
|
+
const remoteIdentityRaw = (0, crypto_1.toRawPubKey)(remoteIdentity);
|
|
94
|
+
const baseKeyRaw = (0, crypto_1.toRawPubKey)(baseKey);
|
|
95
|
+
const signedPriv = this.keyBundle.signedPreKey.keyPair.privKey;
|
|
96
|
+
const identityPriv = this.keyBundle.identityKeyPair.privKey;
|
|
97
|
+
const [dh1, dh2, dh3, dh4] = await Promise.all([
|
|
98
|
+
crypto_1.X25519.scalarMult(signedPriv, remoteIdentityRaw),
|
|
99
|
+
crypto_1.X25519.scalarMult(identityPriv, baseKeyRaw),
|
|
100
|
+
crypto_1.X25519.scalarMult(signedPriv, baseKeyRaw),
|
|
101
|
+
oneTimePrivKey
|
|
102
|
+
? crypto_1.X25519.scalarMult(oneTimePrivKey, baseKeyRaw)
|
|
103
|
+
: Promise.resolve(null)
|
|
104
|
+
]);
|
|
105
|
+
const sharedParts = [SIGNAL_PREFIX_FF, dh1, dh2, dh3];
|
|
106
|
+
if (dh4)
|
|
107
|
+
sharedParts.push(dh4);
|
|
108
|
+
const shared = concatBytes(sharedParts);
|
|
109
|
+
const [rootKey] = await (0, crypto_1.hkdfSplit)(shared, null, 'WhisperText');
|
|
110
|
+
// The first inbound message kicks the Double Ratchet once: the
|
|
111
|
+
// inner SignalMessage carries Alice's fresh sendRatchet pubkey,
|
|
112
|
+
// which we mix with our signedPreKey privkey via calculateRatchet
|
|
113
|
+
// to derive the recv chain key. (See SignalSession.calculateRatchet
|
|
114
|
+
// and decryptMsgFromSession in the lib.)
|
|
115
|
+
this.remoteIdentityPub = (0, crypto_1.toSerializedPubKey)(remoteIdentity);
|
|
116
|
+
this.bootstrapRootKey = rootKey;
|
|
117
|
+
return this.decryptInnerSignalMessage(innerMessage, true);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Decrypts a `<enc type="msg"/>` payload. Requires the recv chain
|
|
121
|
+
* to have been established by a prior `decryptPreKeyMessage` call.
|
|
122
|
+
*/
|
|
123
|
+
async decryptMessage(envelope) {
|
|
124
|
+
if (!this.recvChain) {
|
|
125
|
+
throw new FakePeerRecvSessionError('recv session is not initialized — call decryptPreKeyMessage first');
|
|
126
|
+
}
|
|
127
|
+
return this.decryptInnerSignalMessage(envelope, false);
|
|
128
|
+
}
|
|
129
|
+
async decryptInnerSignalMessage(signalMessageBytes, isBootstrap) {
|
|
130
|
+
if (signalMessageBytes.byteLength < 1 + SIGNAL_MAC_SIZE) {
|
|
131
|
+
throw new FakePeerRecvSessionError('signal message too short');
|
|
132
|
+
}
|
|
133
|
+
const versionByte = signalMessageBytes[0];
|
|
134
|
+
if (versionByte >>> 4 !== SIGNAL_VERSION) {
|
|
135
|
+
throw new FakePeerRecvSessionError(`unsupported signal version ${versionByte >>> 4}`);
|
|
136
|
+
}
|
|
137
|
+
const macStart = signalMessageBytes.byteLength - SIGNAL_MAC_SIZE;
|
|
138
|
+
const versionedBody = signalMessageBytes.subarray(0, macStart);
|
|
139
|
+
const macBytes = signalMessageBytes.subarray(macStart);
|
|
140
|
+
const protoBody = versionedBody.subarray(1);
|
|
141
|
+
const signalMessage = protos_1.proto.SignalMessage.decode(protoBody);
|
|
142
|
+
const ratchetKey = requireBytes(signalMessage.ratchetKey, 'ratchetKey');
|
|
143
|
+
const counter = signalMessage.counter;
|
|
144
|
+
if (counter === null || counter === undefined) {
|
|
145
|
+
throw new FakePeerRecvSessionError('SignalMessage missing counter');
|
|
146
|
+
}
|
|
147
|
+
const ciphertext = requireBytes(signalMessage.ciphertext, 'ciphertext');
|
|
148
|
+
// Bootstrap or reuse the recv chain.
|
|
149
|
+
if (isBootstrap) {
|
|
150
|
+
if (!this.bootstrapRootKey) {
|
|
151
|
+
throw new FakePeerRecvSessionError('bootstrap rootKey missing');
|
|
152
|
+
}
|
|
153
|
+
// Mirror the lib's `calculateRatchet`:
|
|
154
|
+
// sharedSecret = ECDH(signedPreKey.priv, alice.ratchetPub)
|
|
155
|
+
// [_, chainKey] = HKDF(sharedSecret, rootKey, "WhisperRatchet")
|
|
156
|
+
const ratchetRaw = (0, crypto_1.toRawPubKey)(ratchetKey);
|
|
157
|
+
const ratchetShared = await crypto_1.X25519.scalarMult(this.keyBundle.signedPreKey.keyPair.privKey, ratchetRaw);
|
|
158
|
+
const [, chainKey] = await (0, crypto_1.hkdfSplit)(ratchetShared, this.bootstrapRootKey, 'WhisperRatchet');
|
|
159
|
+
this.recvChain = {
|
|
160
|
+
ratchetPubKey: (0, crypto_1.toSerializedPubKey)(ratchetKey),
|
|
161
|
+
chainKey,
|
|
162
|
+
nextIndex: 0
|
|
163
|
+
};
|
|
164
|
+
this.bootstrapRootKey = null;
|
|
165
|
+
}
|
|
166
|
+
else if (!this.recvChain) {
|
|
167
|
+
throw new FakePeerRecvSessionError('recv chain not bootstrapped');
|
|
168
|
+
}
|
|
169
|
+
else if (!uint8Equal(this.recvChain.ratchetPubKey, (0, crypto_1.toSerializedPubKey)(ratchetKey))) {
|
|
170
|
+
throw new FakePeerRecvSessionError('recv chain ratchet rotation is not implemented in the fake peer');
|
|
171
|
+
}
|
|
172
|
+
// Walk the chain forward to the requested counter (no out-of-order).
|
|
173
|
+
if (counter < this.recvChain.nextIndex) {
|
|
174
|
+
throw new FakePeerRecvSessionError(`out-of-order recv counter ${counter} < ${this.recvChain.nextIndex}`);
|
|
175
|
+
}
|
|
176
|
+
let chainKey = this.recvChain.chainKey;
|
|
177
|
+
let messageKey = null;
|
|
178
|
+
let nextIndex = this.recvChain.nextIndex;
|
|
179
|
+
while (nextIndex <= counter) {
|
|
180
|
+
const derived = await deriveMessageKey(chainKey);
|
|
181
|
+
chainKey = derived.nextChainKey;
|
|
182
|
+
if (nextIndex === counter) {
|
|
183
|
+
messageKey = derived.messageKey;
|
|
184
|
+
}
|
|
185
|
+
nextIndex += 1;
|
|
186
|
+
}
|
|
187
|
+
if (!messageKey) {
|
|
188
|
+
throw new FakePeerRecvSessionError('failed to derive message key');
|
|
189
|
+
}
|
|
190
|
+
this.recvChain = {
|
|
191
|
+
ratchetPubKey: this.recvChain.ratchetPubKey,
|
|
192
|
+
chainKey,
|
|
193
|
+
nextIndex
|
|
194
|
+
};
|
|
195
|
+
// Verify MAC.
|
|
196
|
+
if (!this.remoteIdentityPub) {
|
|
197
|
+
throw new FakePeerRecvSessionError('remoteIdentityPub not set');
|
|
198
|
+
}
|
|
199
|
+
const localPub = (0, crypto_1.toSerializedPubKey)(this.keyBundle.identityKeyPair.pubKey);
|
|
200
|
+
const macInput = concatBytes([this.remoteIdentityPub, localPub, versionedBody]);
|
|
201
|
+
const macKeyHandle = await (0, crypto_1.importHmacKey)(messageKey.macKey);
|
|
202
|
+
const expectedFullMac = await (0, crypto_1.hmacSign)(macKeyHandle, macInput);
|
|
203
|
+
const expectedMac = expectedFullMac.subarray(0, SIGNAL_MAC_SIZE);
|
|
204
|
+
if (!uint8Equal(expectedMac, macBytes)) {
|
|
205
|
+
throw new FakePeerRecvSessionError('signal message MAC mismatch');
|
|
206
|
+
}
|
|
207
|
+
// Decrypt the AES-CBC ciphertext.
|
|
208
|
+
const cipherKeyHandle = await (0, crypto_1.importAesCbcKey)(messageKey.cipherKey);
|
|
209
|
+
const padded = await (0, crypto_1.aesCbcDecrypt)(cipherKeyHandle, messageKey.iv, ciphertext);
|
|
210
|
+
return unpadPkcs7(padded);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.FakePeerRecvSession = FakePeerRecvSession;
|
|
214
|
+
async function deriveMessageKey(chainKey) {
|
|
215
|
+
const hmacKey = await (0, crypto_1.importHmacKey)(chainKey);
|
|
216
|
+
const [messageInputKey, nextChainRaw] = await Promise.all([
|
|
217
|
+
(0, crypto_1.hmacSign)(hmacKey, MESSAGE_KEY_LABEL),
|
|
218
|
+
(0, crypto_1.hmacSign)(hmacKey, CHAIN_KEY_LABEL)
|
|
219
|
+
]);
|
|
220
|
+
const expanded = await (0, crypto_1.hkdf)(messageInputKey, null, 'WhisperMessageKeys', 80);
|
|
221
|
+
return {
|
|
222
|
+
nextChainKey: nextChainRaw.subarray(0, 32),
|
|
223
|
+
messageKey: {
|
|
224
|
+
cipherKey: expanded.subarray(0, 32),
|
|
225
|
+
macKey: expanded.subarray(32, 64),
|
|
226
|
+
iv: expanded.subarray(64, 80)
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function readVersionedBody(envelope, suffixLength) {
|
|
231
|
+
if (envelope.byteLength < 1) {
|
|
232
|
+
throw new FakePeerRecvSessionError('signal envelope is empty');
|
|
233
|
+
}
|
|
234
|
+
const version = envelope[0] >>> 4;
|
|
235
|
+
if (version !== SIGNAL_VERSION) {
|
|
236
|
+
throw new FakePeerRecvSessionError(`unsupported signal version ${version}`);
|
|
237
|
+
}
|
|
238
|
+
const bodyEnd = envelope.byteLength - suffixLength;
|
|
239
|
+
if (bodyEnd <= 1) {
|
|
240
|
+
throw new FakePeerRecvSessionError('invalid signal envelope length');
|
|
241
|
+
}
|
|
242
|
+
return envelope.subarray(1, bodyEnd);
|
|
243
|
+
}
|
|
244
|
+
function unpadPkcs7(padded) {
|
|
245
|
+
if (padded.byteLength === 0)
|
|
246
|
+
return padded;
|
|
247
|
+
const padLen = padded[padded.byteLength - 1];
|
|
248
|
+
if (padLen === 0 || padLen > 16)
|
|
249
|
+
return padded;
|
|
250
|
+
if (padLen > padded.byteLength)
|
|
251
|
+
return padded;
|
|
252
|
+
return padded.subarray(0, padded.byteLength - padLen);
|
|
253
|
+
}
|
|
254
|
+
function uint8Equal(a, b) {
|
|
255
|
+
if (a.byteLength !== b.byteLength)
|
|
256
|
+
return false;
|
|
257
|
+
for (let i = 0; i < a.byteLength; i += 1) {
|
|
258
|
+
if (a[i] !== b[i])
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
function concatBytes(parts) {
|
|
264
|
+
let total = 0;
|
|
265
|
+
for (const p of parts)
|
|
266
|
+
total += p.byteLength;
|
|
267
|
+
const out = new Uint8Array(total);
|
|
268
|
+
let offset = 0;
|
|
269
|
+
for (const p of parts) {
|
|
270
|
+
out.set(p, offset);
|
|
271
|
+
offset += p.byteLength;
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
function requireBytes(value, label) {
|
|
276
|
+
if (!value)
|
|
277
|
+
throw new FakePeerRecvSessionError(`${label} missing`);
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
// CryptoKey is referenced via the `CryptoKey` type-only import above.
|
|
281
|
+
// The `void` is just to satisfy ts(6133) in case the file is compiled
|
|
282
|
+
// without consumers.
|
|
283
|
+
void null;
|
|
284
|
+
//# sourceMappingURL=fake-peer-recv-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-peer-recv-session.js","sourceRoot":"","sources":["../../../src/protocol/signal/fake-peer-recv-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fake-peer-side Signal Protocol session.
|
|
3
|
+
*
|
|
4
|
+
* This is the encrypter half: a fake peer (acting as "Alice") sends messages
|
|
5
|
+
* to the real `WaClient` (acting as "Bob"). It implements just enough of
|
|
6
|
+
* the WhatsApp Web Signal Protocol to:
|
|
7
|
+
*
|
|
8
|
+
* 1. Run X3DH against the client's prekey bundle (captured from the
|
|
9
|
+
* client's PreKey upload IQ).
|
|
10
|
+
* 2. Maintain a sending chain key.
|
|
11
|
+
* 3. Encrypt a plaintext into a `PreKeySignalMessage` (first message)
|
|
12
|
+
* or `SignalMessage` (subsequent messages).
|
|
13
|
+
*
|
|
14
|
+
* Sources:
|
|
15
|
+
* /deobfuscated/WASignal/WASignalWhitepaper.js (X3DH inputs)
|
|
16
|
+
* /deobfuscated/WASignal/WASignalSessions.js (session structure)
|
|
17
|
+
* /deobfuscated/WASignal/WASignalCipher.js (encrypt path)
|
|
18
|
+
* /deobfuscated/pb/WASignalWhisperTextProtocol_pb.js (protobuf shapes)
|
|
19
|
+
*
|
|
20
|
+
* Cross-checked against the lib's `initiateSessionOutgoing` /
|
|
21
|
+
* `encryptMsg` (`src/signal/session/SignalSession.ts`,
|
|
22
|
+
* `src/signal/session/SignalRatchet.ts`) — the byte-level recipe is the
|
|
23
|
+
* same; the only difference is that this fake-peer implementation does
|
|
24
|
+
* **not** persist sessions or implement the receive ratchet (the fake
|
|
25
|
+
* server doesn't need to handle inbound messages from the real client to
|
|
26
|
+
* make Phase 8 work).
|
|
27
|
+
*/
|
|
28
|
+
import { type CryptoKey, type SignalKeyPair } from '../../transport/crypto';
|
|
29
|
+
import type { ClientPreKeyBundle } from './prekey-upload';
|
|
30
|
+
export interface FakePeerIdentity {
|
|
31
|
+
/** Long-term identity keypair. */
|
|
32
|
+
readonly identityKeyPair: SignalKeyPair;
|
|
33
|
+
/** Registration id used in PreKeySignalMessage. */
|
|
34
|
+
readonly registrationId: number;
|
|
35
|
+
}
|
|
36
|
+
export declare function generateFakePeerIdentity(): Promise<FakePeerIdentity>;
|
|
37
|
+
export declare class FakePeerSession {
|
|
38
|
+
private readonly identity;
|
|
39
|
+
/** 33-byte serialized peer (local) static identity public key. */
|
|
40
|
+
private readonly localPub;
|
|
41
|
+
/** 33-byte serialized client (remote) static identity public key. */
|
|
42
|
+
private readonly remotePub;
|
|
43
|
+
private sendChain;
|
|
44
|
+
private rootKey;
|
|
45
|
+
private firstMessageHeader;
|
|
46
|
+
private constructor();
|
|
47
|
+
get registrationId(): number;
|
|
48
|
+
/**
|
|
49
|
+
* Initiates a new outgoing session against the client's prekey bundle.
|
|
50
|
+
*
|
|
51
|
+
* Mirrors the X3DH initiator path of `initiateSessionOutgoing` (lib)
|
|
52
|
+
* and the deobfuscated `WASignalSessions.initiateSessionOutgoing`:
|
|
53
|
+
*
|
|
54
|
+
* localOneTimeBase = generate ephemeral keypair (Alice's "base key")
|
|
55
|
+
*
|
|
56
|
+
* DH1 = ECDH(local.identity.priv, remote.signedPreKey.pub)
|
|
57
|
+
* DH2 = ECDH(localOneTimeBase.priv, remote.identity.pub)
|
|
58
|
+
* DH3 = ECDH(localOneTimeBase.priv, remote.signedPreKey.pub)
|
|
59
|
+
* DH4 = ECDH(localOneTimeBase.priv, remote.oneTimePreKey.pub) [optional]
|
|
60
|
+
*
|
|
61
|
+
* secret = 0xFF*32 || DH1 || DH2 || DH3 || [DH4]
|
|
62
|
+
* [rootKey, chainKey] = HKDF_split(secret, salt=null, info="WhisperText")
|
|
63
|
+
*
|
|
64
|
+
* Then a single send-ratchet kick:
|
|
65
|
+
* sendRatchetKeyPair = generateKeyPair()
|
|
66
|
+
* sharedSecret = ECDH(sendRatchetKeyPair.priv, remoteRatchetKey)
|
|
67
|
+
* [rootKey, chainKey] = HKDF_split(sharedSecret, salt=rootKey, info="WhisperRatchet")
|
|
68
|
+
*
|
|
69
|
+
* Where remoteRatchetKey = remote.signedPreKey.pub (no separate
|
|
70
|
+
* ratchet key in the upload IQ — this matches the lib's behavior).
|
|
71
|
+
*/
|
|
72
|
+
static initiate(identity: FakePeerIdentity, bundle: ClientPreKeyBundle, oneTimePreKey?: {
|
|
73
|
+
readonly keyId: number;
|
|
74
|
+
readonly publicKey: Uint8Array;
|
|
75
|
+
}): Promise<FakePeerSession>;
|
|
76
|
+
/**
|
|
77
|
+
* Encrypts a plaintext message and returns either a `pkmsg` (first
|
|
78
|
+
* message in the session — wraps the SignalMessage in a
|
|
79
|
+
* PreKeySignalMessage envelope) or `msg` (subsequent messages).
|
|
80
|
+
*/
|
|
81
|
+
encrypt(plaintext: Uint8Array): Promise<{
|
|
82
|
+
readonly type: 'pkmsg' | 'msg';
|
|
83
|
+
readonly ciphertext: Uint8Array;
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
export type { CryptoKey };
|
|
87
|
+
//# sourceMappingURL=fake-peer-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-peer-session.d.ts","sourceRoot":"","sources":["../../../src/protocol/signal/fake-peer-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAEH,KAAK,SAAS,EAOd,KAAK,aAAa,EAIrB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAQzD,MAAM,WAAW,gBAAgB;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAA;IACvC,mDAAmD;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAClC;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAM1E;AAmBD,qBAAa,eAAe;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,kBAAkB,CAA4B;IAEtD,OAAO;IAgBP,IAAW,cAAc,IAAI,MAAM,CAElC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;WACiB,QAAQ,CACxB,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;KAAE,GAC3E,OAAO,CAAC,eAAe,CAAC;IA0D3B;;;;OAIG;IACU,OAAO,CAChB,SAAS,EAAE,UAAU,GACtB,OAAO,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;QAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;KAAE,CAAC;CAoDlF;AA4CD,YAAY,EAAE,SAAS,EAAE,CAAA"}
|