@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,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Per-connection lifecycle pipeline (Noise handshake + stanza loop). */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.WaFakeConnectionPipeline = void 0;
|
|
5
|
+
const cert_chain_1 = require("../protocol/auth/cert-chain");
|
|
6
|
+
const client_payload_validate_1 = require("../protocol/auth/client-payload-validate");
|
|
7
|
+
const success_node_1 = require("../protocol/auth/success-node");
|
|
8
|
+
const codec_1 = require("../transport/codec");
|
|
9
|
+
const crypto_1 = require("../transport/crypto");
|
|
10
|
+
const protos_1 = require("../transport/protos");
|
|
11
|
+
const WaFakeFrameSocket_1 = require("./WaFakeFrameSocket");
|
|
12
|
+
const WaFakeNoiseHandshake_1 = require("./WaFakeNoiseHandshake");
|
|
13
|
+
const WaFakeTransport_1 = require("./WaFakeTransport");
|
|
14
|
+
const NOISE_XX_NAME = new TextEncoder().encode('Noise_XX_25519_AESGCM_SHA256\0\0\0\0');
|
|
15
|
+
const NOISE_IK_NAME = new TextEncoder().encode('Noise_IK_25519_AESGCM_SHA256\0\0\0\0');
|
|
16
|
+
const PROLOGUE = new Uint8Array([0x57, 0x41, 0x06, 0x03]);
|
|
17
|
+
class WaFakeConnectionPipeline {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.events = {};
|
|
20
|
+
this.state = { kind: 'awaiting_prologue' };
|
|
21
|
+
this.chain = Promise.resolve();
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.frameSocket = new WaFakeFrameSocket_1.WaFakeFrameSocket(config.connection);
|
|
24
|
+
this.frameSocket.setHandlers({
|
|
25
|
+
onPrologue: () => this.onPrologue(),
|
|
26
|
+
onFrame: (frame) => this.scheduleFrame(frame),
|
|
27
|
+
onClose: (info) => {
|
|
28
|
+
this.state = { kind: 'closed' };
|
|
29
|
+
this.events.onClose?.(info);
|
|
30
|
+
},
|
|
31
|
+
onError: (error) => this.events.onError?.(error)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
setEvents(events) {
|
|
35
|
+
this.events = events;
|
|
36
|
+
}
|
|
37
|
+
isAuthenticated() {
|
|
38
|
+
return this.state.kind === 'authenticated';
|
|
39
|
+
}
|
|
40
|
+
async sendStanza(node) {
|
|
41
|
+
if (this.state.kind !== 'authenticated') {
|
|
42
|
+
throw new Error(`cannot send stanza while pipeline is in state "${this.state.kind}"`);
|
|
43
|
+
}
|
|
44
|
+
const stanza = (0, codec_1.encodeBinaryNodeStanza)(node);
|
|
45
|
+
// Keep outbound encrypted frames in FIFO order across concurrent callers.
|
|
46
|
+
const ciphertext = await this.state.transport.encryptFrame(stanza);
|
|
47
|
+
this.frameSocket.sendFrame(ciphertext);
|
|
48
|
+
}
|
|
49
|
+
onPrologue() {
|
|
50
|
+
if (this.state.kind !== 'awaiting_prologue') {
|
|
51
|
+
this.events.onError?.(new Error('received second prologue from client'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.state = { kind: 'awaiting_client_hello' };
|
|
55
|
+
}
|
|
56
|
+
scheduleFrame(frame) {
|
|
57
|
+
this.chain = this.chain.then(() => this.handleFrame(frame));
|
|
58
|
+
}
|
|
59
|
+
async handleFrame(frame) {
|
|
60
|
+
try {
|
|
61
|
+
switch (this.state.kind) {
|
|
62
|
+
case 'awaiting_client_hello':
|
|
63
|
+
await this.handleClientHello(frame);
|
|
64
|
+
return;
|
|
65
|
+
case 'awaiting_client_finish':
|
|
66
|
+
await this.handleClientFinish(frame, this.state.handshake, this.state.serverEphemeralKeyPair);
|
|
67
|
+
return;
|
|
68
|
+
case 'authenticated':
|
|
69
|
+
await this.handleAuthenticatedFrame(frame, this.state.transport);
|
|
70
|
+
return;
|
|
71
|
+
default:
|
|
72
|
+
this.events.onError?.(new Error(`unexpected frame in state "${this.state.kind}"`));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
this.fail(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async handleClientHello(frame) {
|
|
80
|
+
const parsed = protos_1.proto.HandshakeMessage.decode(frame);
|
|
81
|
+
const clientHello = parsed.clientHello;
|
|
82
|
+
if (!clientHello?.ephemeral) {
|
|
83
|
+
throw new Error('ClientHello missing ephemeral');
|
|
84
|
+
}
|
|
85
|
+
// IK includes encrypted static+payload in ClientHello; XX does not.
|
|
86
|
+
if (clientHello.static && clientHello.payload) {
|
|
87
|
+
await this.handleIkClientHello(clientHello);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
await this.handleXxClientHello(clientHello.ephemeral);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async handleXxClientHello(clientEphemeralPub) {
|
|
94
|
+
const handshake = new WaFakeNoiseHandshake_1.WaFakeNoiseHandshake();
|
|
95
|
+
await handshake.start(NOISE_XX_NAME, PROLOGUE);
|
|
96
|
+
await handshake.authenticate(clientEphemeralPub);
|
|
97
|
+
const serverEphemeral = await crypto_1.X25519.generateKeyPair();
|
|
98
|
+
await handshake.authenticate(serverEphemeral.pubKey);
|
|
99
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(serverEphemeral.privKey, clientEphemeralPub));
|
|
100
|
+
const encryptedServerStatic = await handshake.encrypt(this.config.serverStaticKeyPair.pubKey);
|
|
101
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(this.config.serverStaticKeyPair.privKey, clientEphemeralPub));
|
|
102
|
+
const certChain = await (0, cert_chain_1.buildFakeCertChain)({
|
|
103
|
+
root: this.config.rootCa,
|
|
104
|
+
leafKey: this.config.serverStaticKeyPair.pubKey
|
|
105
|
+
});
|
|
106
|
+
const encryptedCertPayload = await handshake.encrypt(certChain.encoded);
|
|
107
|
+
const serverHello = protos_1.proto.HandshakeMessage.encode({
|
|
108
|
+
serverHello: {
|
|
109
|
+
ephemeral: serverEphemeral.pubKey,
|
|
110
|
+
static: encryptedServerStatic,
|
|
111
|
+
payload: encryptedCertPayload
|
|
112
|
+
}
|
|
113
|
+
}).finish();
|
|
114
|
+
this.frameSocket.sendFrame(serverHello);
|
|
115
|
+
this.state = {
|
|
116
|
+
kind: 'awaiting_client_finish',
|
|
117
|
+
handshake,
|
|
118
|
+
serverEphemeralKeyPair: serverEphemeral,
|
|
119
|
+
clientEphemeralPub
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Server-side IK path used when the client already cached our static key. */
|
|
123
|
+
async handleIkClientHello(clientHello) {
|
|
124
|
+
if (!clientHello.ephemeral || !clientHello.static || !clientHello.payload) {
|
|
125
|
+
throw new Error('IK ClientHello missing ephemeral/static/payload');
|
|
126
|
+
}
|
|
127
|
+
const clientEphemeralPub = clientHello.ephemeral;
|
|
128
|
+
const encryptedClientStatic = clientHello.static;
|
|
129
|
+
const encryptedClientPayload = clientHello.payload;
|
|
130
|
+
const handshake = new WaFakeNoiseHandshake_1.WaFakeNoiseHandshake();
|
|
131
|
+
await handshake.start(NOISE_IK_NAME, PROLOGUE);
|
|
132
|
+
await handshake.authenticate(this.config.serverStaticKeyPair.pubKey);
|
|
133
|
+
await handshake.authenticate(clientEphemeralPub);
|
|
134
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(this.config.serverStaticKeyPair.privKey, clientEphemeralPub));
|
|
135
|
+
const clientStaticKey = await handshake.decrypt(encryptedClientStatic);
|
|
136
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(this.config.serverStaticKeyPair.privKey, clientStaticKey));
|
|
137
|
+
const clientPayloadBytes = await handshake.decrypt(encryptedClientPayload);
|
|
138
|
+
const clientPayload = (0, client_payload_validate_1.parseClientPayload)(clientPayloadBytes);
|
|
139
|
+
const serverEphemeral = await crypto_1.X25519.generateKeyPair();
|
|
140
|
+
await handshake.authenticate(serverEphemeral.pubKey);
|
|
141
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(serverEphemeral.privKey, clientEphemeralPub));
|
|
142
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(serverEphemeral.privKey, clientStaticKey));
|
|
143
|
+
const certChain = await (0, cert_chain_1.buildFakeCertChain)({
|
|
144
|
+
root: this.config.rootCa,
|
|
145
|
+
leafKey: this.config.serverStaticKeyPair.pubKey
|
|
146
|
+
});
|
|
147
|
+
const encryptedCertPayload = await handshake.encrypt(certChain.encoded);
|
|
148
|
+
const serverHello = protos_1.proto.HandshakeMessage.encode({
|
|
149
|
+
serverHello: {
|
|
150
|
+
ephemeral: serverEphemeral.pubKey,
|
|
151
|
+
payload: encryptedCertPayload
|
|
152
|
+
}
|
|
153
|
+
}).finish();
|
|
154
|
+
this.frameSocket.sendFrame(serverHello);
|
|
155
|
+
const keys = await handshake.finish();
|
|
156
|
+
const transport = new WaFakeTransport_1.WaFakeTransport({
|
|
157
|
+
recvKey: keys.recvKey,
|
|
158
|
+
sendKey: keys.sendKey
|
|
159
|
+
});
|
|
160
|
+
this.state = { kind: 'authenticated', transport };
|
|
161
|
+
await this.sendStanza((0, success_node_1.buildSuccessNode)(this.config.successNodeAttributes));
|
|
162
|
+
this.events.onAuthenticated?.({ clientPayload, clientStaticKey });
|
|
163
|
+
}
|
|
164
|
+
async handleClientFinish(frame, handshake, serverEphemeralKeyPair) {
|
|
165
|
+
const parsed = protos_1.proto.HandshakeMessage.decode(frame);
|
|
166
|
+
const clientFinish = parsed.clientFinish;
|
|
167
|
+
if (!clientFinish?.static || !clientFinish.payload) {
|
|
168
|
+
throw new Error('ClientFinish missing static/payload');
|
|
169
|
+
}
|
|
170
|
+
const clientStaticKey = await handshake.decrypt(clientFinish.static);
|
|
171
|
+
await handshake.mixIntoKey(await crypto_1.X25519.scalarMult(serverEphemeralKeyPair.privKey, clientStaticKey));
|
|
172
|
+
const clientPayloadBytes = await handshake.decrypt(clientFinish.payload);
|
|
173
|
+
const clientPayload = (0, client_payload_validate_1.parseClientPayload)(clientPayloadBytes);
|
|
174
|
+
const keys = await handshake.finish();
|
|
175
|
+
const transport = new WaFakeTransport_1.WaFakeTransport({
|
|
176
|
+
recvKey: keys.recvKey,
|
|
177
|
+
sendKey: keys.sendKey
|
|
178
|
+
});
|
|
179
|
+
this.state = { kind: 'authenticated', transport };
|
|
180
|
+
await this.sendStanza((0, success_node_1.buildSuccessNode)(this.config.successNodeAttributes));
|
|
181
|
+
this.events.onAuthenticated?.({ clientPayload, clientStaticKey });
|
|
182
|
+
}
|
|
183
|
+
async handleAuthenticatedFrame(frame, transport) {
|
|
184
|
+
const stanzaBytes = await transport.decryptFrame(frame);
|
|
185
|
+
const node = await (0, codec_1.decodeBinaryNodeStanza)(stanzaBytes);
|
|
186
|
+
this.events.onStanza?.(node);
|
|
187
|
+
if (node.tag === 'iq') {
|
|
188
|
+
const response = await this.config.iqRouter.route(node);
|
|
189
|
+
if (response !== null) {
|
|
190
|
+
await this.sendStanza(response);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.events.onUnhandledStanza?.(node);
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Mirror the minimal ack shape that resolves the lib pending publish.
|
|
198
|
+
if (node.tag === 'message' && node.attrs.id) {
|
|
199
|
+
const messageType = node.attrs.type ?? 'text';
|
|
200
|
+
const from = node.attrs.to ?? 's.whatsapp.net';
|
|
201
|
+
const ackAttrs = {
|
|
202
|
+
id: node.attrs.id,
|
|
203
|
+
class: 'receipt',
|
|
204
|
+
type: messageType,
|
|
205
|
+
from
|
|
206
|
+
};
|
|
207
|
+
if (node.attrs.participant) {
|
|
208
|
+
ackAttrs.participant = node.attrs.participant;
|
|
209
|
+
}
|
|
210
|
+
await this.sendStanza({
|
|
211
|
+
tag: 'ack',
|
|
212
|
+
attrs: ackAttrs
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
fail(error) {
|
|
217
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
218
|
+
this.events.onError?.(err);
|
|
219
|
+
this.state = { kind: 'closed' };
|
|
220
|
+
this.config.connection.close(1011, err.message.slice(0, 120));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exports.WaFakeConnectionPipeline = WaFakeConnectionPipeline;
|
|
224
|
+
//# sourceMappingURL=WaFakeConnectionPipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeConnectionPipeline.js","sourceRoot":"","sources":["../../src/infra/WaFakeConnectionPipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** WhatsApp frame codec (prologue + 3-byte length-prefixed frames). */
|
|
2
|
+
import type { WaFakeConnection } from './WaFakeConnection';
|
|
3
|
+
export interface WaFakeClientPrologue {
|
|
4
|
+
readonly protocolVersion: number;
|
|
5
|
+
readonly dictVersion: number;
|
|
6
|
+
readonly routingInfo: Uint8Array | null;
|
|
7
|
+
}
|
|
8
|
+
export interface WaFakeFrameSocketHandlers {
|
|
9
|
+
readonly onPrologue?: (prologue: WaFakeClientPrologue) => void;
|
|
10
|
+
readonly onFrame?: (frame: Uint8Array) => void;
|
|
11
|
+
readonly onClose?: (info: {
|
|
12
|
+
readonly code: number;
|
|
13
|
+
readonly reason: string;
|
|
14
|
+
}) => void;
|
|
15
|
+
readonly onError?: (error: Error) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare class WaFakeFrameSocket {
|
|
18
|
+
private readonly connection;
|
|
19
|
+
private handlers;
|
|
20
|
+
private inboundBuffer;
|
|
21
|
+
private prologueParsed;
|
|
22
|
+
constructor(connection: WaFakeConnection);
|
|
23
|
+
setHandlers(handlers: WaFakeFrameSocketHandlers): void;
|
|
24
|
+
sendFrame(body: Uint8Array): void;
|
|
25
|
+
private handleInboundBytes;
|
|
26
|
+
private tryParsePrologue;
|
|
27
|
+
private drainFrames;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=WaFakeFrameSocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeFrameSocket.d.ts","sourceRoot":"","sources":["../../src/infra/WaFakeFrameSocket.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAS1D,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG,IAAI,CAAA;CAC1C;AAED,MAAM,WAAW,yBAAyB;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAC5C;AAED,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,cAAc,CAAQ;gBAEX,UAAU,EAAE,gBAAgB;IASxC,WAAW,CAAC,QAAQ,EAAE,yBAAyB,GAAG,IAAI;IAItD,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAYxC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,gBAAgB;IAuCxB,OAAO,CAAC,WAAW;CAmBtB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** WhatsApp frame codec (prologue + 3-byte length-prefixed frames). */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.WaFakeFrameSocket = void 0;
|
|
5
|
+
const PROLOGUE_W = 0x57;
|
|
6
|
+
const PROLOGUE_A = 0x41;
|
|
7
|
+
const ROUTING_MAGIC = 0xed;
|
|
8
|
+
const VERSION_HEADER_LENGTH = 4;
|
|
9
|
+
const FRAME_LENGTH_PREFIX_BYTES = 3;
|
|
10
|
+
const MAX_FRAME_LENGTH = 1 << 24;
|
|
11
|
+
class WaFakeFrameSocket {
|
|
12
|
+
constructor(connection) {
|
|
13
|
+
this.handlers = {};
|
|
14
|
+
this.inboundBuffer = new Uint8Array(0);
|
|
15
|
+
this.prologueParsed = false;
|
|
16
|
+
this.connection = connection;
|
|
17
|
+
this.connection.setHandlers({
|
|
18
|
+
onFrame: (bytes) => this.handleInboundBytes(bytes),
|
|
19
|
+
onClose: (info) => this.handlers.onClose?.(info),
|
|
20
|
+
onError: (error) => this.handlers.onError?.(error)
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
setHandlers(handlers) {
|
|
24
|
+
this.handlers = handlers;
|
|
25
|
+
}
|
|
26
|
+
sendFrame(body) {
|
|
27
|
+
if (body.byteLength >= MAX_FRAME_LENGTH) {
|
|
28
|
+
throw new Error(`frame too large: ${body.byteLength} bytes`);
|
|
29
|
+
}
|
|
30
|
+
const out = new Uint8Array(FRAME_LENGTH_PREFIX_BYTES + body.byteLength);
|
|
31
|
+
out[0] = (body.byteLength >> 16) & 0xff;
|
|
32
|
+
out[1] = (body.byteLength >> 8) & 0xff;
|
|
33
|
+
out[2] = body.byteLength & 0xff;
|
|
34
|
+
out.set(body, FRAME_LENGTH_PREFIX_BYTES);
|
|
35
|
+
this.connection.sendFrame(out);
|
|
36
|
+
}
|
|
37
|
+
handleInboundBytes(chunk) {
|
|
38
|
+
try {
|
|
39
|
+
this.inboundBuffer = concatBytes(this.inboundBuffer, chunk);
|
|
40
|
+
if (!this.prologueParsed) {
|
|
41
|
+
if (!this.tryParsePrologue()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.drainFrames();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
this.handlers.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
tryParsePrologue() {
|
|
52
|
+
const buffer = this.inboundBuffer;
|
|
53
|
+
let offset = 0;
|
|
54
|
+
let routingInfo = null;
|
|
55
|
+
if (buffer.byteLength === 0) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (buffer[0] === ROUTING_MAGIC) {
|
|
59
|
+
if (buffer.byteLength < 4) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const routingLen = (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
|
63
|
+
if (buffer.byteLength < 4 + routingLen + VERSION_HEADER_LENGTH) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
routingInfo = buffer.slice(4, 4 + routingLen);
|
|
67
|
+
offset = 4 + routingLen;
|
|
68
|
+
}
|
|
69
|
+
else if (buffer.byteLength < VERSION_HEADER_LENGTH) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const versionStart = offset;
|
|
73
|
+
const w = buffer[versionStart];
|
|
74
|
+
const a = buffer[versionStart + 1];
|
|
75
|
+
if (w !== PROLOGUE_W || a !== PROLOGUE_A) {
|
|
76
|
+
throw new Error(`invalid prologue magic: expected "WA", got ${hex(w)} ${hex(a)}`);
|
|
77
|
+
}
|
|
78
|
+
const protocolVersion = buffer[versionStart + 2];
|
|
79
|
+
const dictVersion = buffer[versionStart + 3];
|
|
80
|
+
offset = versionStart + VERSION_HEADER_LENGTH;
|
|
81
|
+
this.inboundBuffer = buffer.slice(offset);
|
|
82
|
+
this.prologueParsed = true;
|
|
83
|
+
this.handlers.onPrologue?.({ protocolVersion, dictVersion, routingInfo });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
drainFrames() {
|
|
87
|
+
while (true) {
|
|
88
|
+
const buffer = this.inboundBuffer;
|
|
89
|
+
if (buffer.byteLength < FRAME_LENGTH_PREFIX_BYTES) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const length = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
|
93
|
+
if (length >= MAX_FRAME_LENGTH) {
|
|
94
|
+
throw new Error(`frame too large: ${length} bytes`);
|
|
95
|
+
}
|
|
96
|
+
const total = FRAME_LENGTH_PREFIX_BYTES + length;
|
|
97
|
+
if (buffer.byteLength < total) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const body = buffer.slice(FRAME_LENGTH_PREFIX_BYTES, total);
|
|
101
|
+
this.inboundBuffer = buffer.slice(total);
|
|
102
|
+
this.handlers.onFrame?.(body);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.WaFakeFrameSocket = WaFakeFrameSocket;
|
|
107
|
+
function concatBytes(a, b) {
|
|
108
|
+
if (a.byteLength === 0)
|
|
109
|
+
return b;
|
|
110
|
+
if (b.byteLength === 0)
|
|
111
|
+
return a;
|
|
112
|
+
const out = new Uint8Array(a.byteLength + b.byteLength);
|
|
113
|
+
out.set(a, 0);
|
|
114
|
+
out.set(b, a.byteLength);
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
function hex(byte) {
|
|
118
|
+
if (byte === undefined)
|
|
119
|
+
return 'undefined';
|
|
120
|
+
return `0x${byte.toString(16).padStart(2, '0')}`;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=WaFakeFrameSocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeFrameSocket.js","sourceRoot":"","sources":["../../src/infra/WaFakeFrameSocket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** HTTPS listener used by fake media upload/download flows. */
|
|
2
|
+
import type { WaFakeHttpRequestHandler } from './WaFakeWsServer';
|
|
3
|
+
export interface WaFakeMediaHttpsServerListenInfo {
|
|
4
|
+
readonly host: string;
|
|
5
|
+
readonly port: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class WaFakeMediaHttpsServer {
|
|
8
|
+
private server;
|
|
9
|
+
private listenInfo;
|
|
10
|
+
private requestHandler;
|
|
11
|
+
setRequestHandler(handler: WaFakeHttpRequestHandler | null): void;
|
|
12
|
+
listen(host?: string, port?: number): Promise<WaFakeMediaHttpsServerListenInfo>;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
get info(): WaFakeMediaHttpsServerListenInfo | null;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=WaFakeMediaHttpsServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeMediaHttpsServer.d.ts","sourceRoot":"","sources":["../../src/infra/WaFakeMediaHttpsServer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAK/D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAqDhE,MAAM,WAAW,gCAAgC;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACxB;AAED,qBAAa,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAgD;IAClE,OAAO,CAAC,cAAc,CAAwC;IAEvD,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,IAAI;IAI3D,MAAM,CAAC,IAAI,SAAc,EAAE,IAAI,SAAI,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAqD/E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYnC,IAAW,IAAI,IAAI,gCAAgC,GAAG,IAAI,CAEzD;CACJ"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** HTTPS listener used by fake media upload/download flows. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.WaFakeMediaHttpsServer = void 0;
|
|
5
|
+
const node_https_1 = require("node:https");
|
|
6
|
+
const FAKE_MEDIA_TLS_KEY_PEM = `-----BEGIN PRIVATE KEY-----
|
|
7
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3xTRqB/wZbz/w
|
|
8
|
+
pQgcOfCfizS0MrtVR0ulBa1vK4OlU1FXJNC0dtTKLs/jMWNqwYWXxSoGEHHfhUIS
|
|
9
|
+
PgZ08nauCJs83ZFAQC1Es1sN1R32YokPmKOCTHHh8f5/uX3h5oUD/xr3gwOVs4c2
|
|
10
|
+
ISmk1OTmp77KolxZXHOnlnHweO6DK0CqfT+53RzKj5rz4d7inyMk5ctk+JjHZd8e
|
|
11
|
+
q46e4MH4ZWPM+ehwRwgWMQ2E1bFjVQsBMvtAkUxOEx+B2/Cys6jEUFo/ABkQxXt+
|
|
12
|
+
InqWnYKHbPOToKmpPxDjT54OpVZs4IRtbkTrgEMMz3/c5g4XamGUHLqkI0GBESK2
|
|
13
|
+
16STZettAgMBAAECggEAAr6CDGOfMMzRkdyeWyKosPKMIGbY+wNiSSbsabim4BO3
|
|
14
|
+
LkLQgSK1d3fF3+KrDj6/DUJUti2/oZEKGoKwUn6T14BmV+7qvjX1WN8kqNsGYLXP
|
|
15
|
+
XFB0jinpkf6XhPKUn7olCGdwglgR28XknLBXsmG6eMK5ODgiZi0Zqng9WPCSP3Aa
|
|
16
|
+
5q7iSeJF0FsbQ1OdQT3t98WhnSN9t0TzLyNUqXWDBDIrrtT3O7B7theS+3LRhodE
|
|
17
|
+
VFROogp4hfo6pBNweki08uFD250OP6iGpYsE0xY6NIfyebGS2iBmbDKQmMkWLdf0
|
|
18
|
+
mSlvYoksnDan4tJMiXAbb39wLdJEa+x98Qzxq0iJyQKBgQDeBQSgVd7j99W0bdzo
|
|
19
|
+
fnDgnjJS606UrWID/RyTEIMfq5Jf2sM2vTJ2/w4X1JoUxxQCJbFmoJs9RXn52XUa
|
|
20
|
+
3/GaUbr3akUVjMb93JlbWTQVoKipMM6HGCee4rj69qdsmA8iJrnloGFpymLThcfm
|
|
21
|
+
xZB535vbG3DrYRM8MH/crDQH2QKBgQDT5YlXskOxx/iVxpko4uacIBqHnPGbCPnK
|
|
22
|
+
LXMaa5vrjGgWNK0ajj+0MFdpEl+HXC7ZDISmSRKExrMDaWkjoXzXhxz1BmHVdN3O
|
|
23
|
+
lOZY6gY+WeQUPn2sfqROBAV7B66LmRjbLdK9kwqrD3nhED6XWR+ZuXaH0dMQ2UMe
|
|
24
|
+
T9E1ixr3tQKBgQChrYvR6taWsosYioy9bh5rJCjHg33E/YIMH41odzTVok7EqP1R
|
|
25
|
+
5nNSfqhXqEXQbazfZ22Jq9mAxBBwZvBFcuFxHKWHuQa4C715buTqxcoNGeLY2qb7
|
|
26
|
+
cBaiOL62W1pO1Wjn2MW1N5bYwD45hQmuvx5X8gOAirovXpDwWu0x2OFG+QKBgAxE
|
|
27
|
+
U4kiJs0Z+IgjMSauzA7pxN9o9Iu3H07XBrzW0fX28OeoMQVCiumRit3oVGNvsL6b
|
|
28
|
+
/OnrfQj2v9JIve90H9gSWFjO/8bttxGIiTVIhwgBCDUr0Pa1dimWDgMrVK18NXYq
|
|
29
|
+
1vJmms2AXdvrptP4Mt4hYH1IZmGpUjtk/4WMAgmpAoGAKJXzDPY5ll9Ebjz28u3W
|
|
30
|
+
sPZdIz90rpRIBnyDC/AwtEzliU2PkuGpqe1ZJaP6cmPTxf/Bv8hfUMXknURpOShE
|
|
31
|
+
Uusyt3/4dGRMY+XXKuTPMZA8sbIEatA2z2e6oBoyj9avzEKAwDsReuPyyX6BubTx
|
|
32
|
+
rLSyj/PpCngrQw7YXsQc6Wc=
|
|
33
|
+
-----END PRIVATE KEY-----
|
|
34
|
+
`;
|
|
35
|
+
const FAKE_MEDIA_TLS_CERT_PEM = `-----BEGIN CERTIFICATE-----
|
|
36
|
+
MIIDGTCCAgGgAwIBAgIUCb8Qbq/uzK9W14G057lmny5p4kIwDQYJKoZIhvcNAQEL
|
|
37
|
+
BQAwGzEZMBcGA1UEAwwQZmFrZS1tZWRpYS5sb2NhbDAgFw0yNjA0MDgyMjAzMDRa
|
|
38
|
+
GA8yMTI2MDMxNTIyMDMwNFowGzEZMBcGA1UEAwwQZmFrZS1tZWRpYS5sb2NhbDCC
|
|
39
|
+
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALfFNGoH/BlvP/ClCBw58J+L
|
|
40
|
+
NLQyu1VHS6UFrW8rg6VTUVck0LR21Mouz+MxY2rBhZfFKgYQcd+FQhI+BnTydq4I
|
|
41
|
+
mzzdkUBALUSzWw3VHfZiiQ+Yo4JMceHx/n+5feHmhQP/GveDA5WzhzYhKaTU5Oan
|
|
42
|
+
vsqiXFlcc6eWcfB47oMrQKp9P7ndHMqPmvPh3uKfIyTly2T4mMdl3x6rjp7gwfhl
|
|
43
|
+
Y8z56HBHCBYxDYTVsWNVCwEy+0CRTE4TH4Hb8LKzqMRQWj8AGRDFe34iepadgods
|
|
44
|
+
85Ogqak/EONPng6lVmzghG1uROuAQwzPf9zmDhdqYZQcuqQjQYERIrbXpJNl620C
|
|
45
|
+
AwEAAaNTMFEwHQYDVR0OBBYEFG3DX82mLaatjTwwspHIj2pOD8CnMB8GA1UdIwQY
|
|
46
|
+
MBaAFG3DX82mLaatjTwwspHIj2pOD8CnMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
|
47
|
+
hvcNAQELBQADggEBAEqIu6mXgvSrGyQxRp6cJVg5OhBpwxH/V0IFe2H7xPBxreDS
|
|
48
|
+
e9yb/ESLRFxpfeWhLXOBEsOGbrF8HvZ0zNTHW+MtIkJB/hhYVzDJyhEpf9jWvpaM
|
|
49
|
+
H6CyzWIZgrXMmyeh0WkmVWoYyvlQrz9yJP63VfzCTCO6YBo02S+kKAyJiM9l8ZW5
|
|
50
|
+
8vALhsyrGSMDnxQSixdc4L/Migam1LHxqwApzDvTdfXNiqjWEmfbw7sQKjd8EHad
|
|
51
|
+
KxNzgzzCRBSkeLe9YoXxLkKRvYeBM/xiv0AVp/ABedHj0xj3ybvvdjowui1uCBip
|
|
52
|
+
BoMF3OiuOeaTubj+tDzpZcauS4L+OyUPjsKqFoM=
|
|
53
|
+
-----END CERTIFICATE-----
|
|
54
|
+
`;
|
|
55
|
+
class WaFakeMediaHttpsServer {
|
|
56
|
+
constructor() {
|
|
57
|
+
this.server = null;
|
|
58
|
+
this.listenInfo = null;
|
|
59
|
+
this.requestHandler = null;
|
|
60
|
+
}
|
|
61
|
+
setRequestHandler(handler) {
|
|
62
|
+
this.requestHandler = handler;
|
|
63
|
+
}
|
|
64
|
+
async listen(host = '127.0.0.1', port = 0) {
|
|
65
|
+
if (this.server) {
|
|
66
|
+
throw new Error('fake media https server is already listening');
|
|
67
|
+
}
|
|
68
|
+
const server = (0, node_https_1.createServer)({
|
|
69
|
+
key: FAKE_MEDIA_TLS_KEY_PEM,
|
|
70
|
+
cert: FAKE_MEDIA_TLS_CERT_PEM
|
|
71
|
+
}, (req, res) => {
|
|
72
|
+
const handler = this.requestHandler;
|
|
73
|
+
if (!handler) {
|
|
74
|
+
res.statusCode = 404;
|
|
75
|
+
res.end();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const result = handler(req, res);
|
|
80
|
+
if (result instanceof Promise) {
|
|
81
|
+
result.catch((error) => {
|
|
82
|
+
if (!res.headersSent) {
|
|
83
|
+
res.statusCode = 500;
|
|
84
|
+
}
|
|
85
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!res.headersSent) {
|
|
91
|
+
res.statusCode = 500;
|
|
92
|
+
}
|
|
93
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
await new Promise((resolve, reject) => {
|
|
97
|
+
const onError = (error) => {
|
|
98
|
+
server.off('listening', onListening);
|
|
99
|
+
reject(error);
|
|
100
|
+
};
|
|
101
|
+
const onListening = () => {
|
|
102
|
+
server.off('error', onError);
|
|
103
|
+
resolve();
|
|
104
|
+
};
|
|
105
|
+
server.once('error', onError);
|
|
106
|
+
server.once('listening', onListening);
|
|
107
|
+
server.listen(port, host);
|
|
108
|
+
});
|
|
109
|
+
const address = server.address();
|
|
110
|
+
this.server = server;
|
|
111
|
+
this.listenInfo = { host: address.address, port: address.port };
|
|
112
|
+
return this.listenInfo;
|
|
113
|
+
}
|
|
114
|
+
async close() {
|
|
115
|
+
const server = this.server;
|
|
116
|
+
if (!server)
|
|
117
|
+
return;
|
|
118
|
+
await new Promise((resolve, reject) => {
|
|
119
|
+
server.close((error) => (error ? reject(error) : resolve()));
|
|
120
|
+
});
|
|
121
|
+
// Force any keep-alive sockets to close so the test process can exit.
|
|
122
|
+
server.closeAllConnections?.();
|
|
123
|
+
this.server = null;
|
|
124
|
+
this.listenInfo = null;
|
|
125
|
+
}
|
|
126
|
+
get info() {
|
|
127
|
+
return this.listenInfo;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.WaFakeMediaHttpsServer = WaFakeMediaHttpsServer;
|
|
131
|
+
//# sourceMappingURL=WaFakeMediaHttpsServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeMediaHttpsServer.js","sourceRoot":"","sources":["../../src/infra/WaFakeMediaHttpsServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Responder-side Noise handshake primitives for fake server pipelines. */
|
|
2
|
+
import { type CryptoKey } from '../transport/crypto';
|
|
3
|
+
export interface WaFakeNoiseHandshakeFinishKeys {
|
|
4
|
+
readonly recvKey: CryptoKey;
|
|
5
|
+
readonly sendKey: CryptoKey;
|
|
6
|
+
readonly recvKeyBytes: Uint8Array;
|
|
7
|
+
readonly sendKeyBytes: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
export declare class WaFakeNoiseHandshake {
|
|
10
|
+
private hash;
|
|
11
|
+
private chainingKey;
|
|
12
|
+
private cipherKey;
|
|
13
|
+
private nonceCounter;
|
|
14
|
+
start(name: Uint8Array, prologue: Uint8Array): Promise<void>;
|
|
15
|
+
authenticate(data: Uint8Array): Promise<void>;
|
|
16
|
+
mixIntoKey(input: Uint8Array): Promise<void>;
|
|
17
|
+
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
|
|
18
|
+
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
|
|
19
|
+
/** Derives transport keys (`first -> recv`, `second -> send` for responder role). */
|
|
20
|
+
finish(): Promise<WaFakeNoiseHandshakeFinishKeys>;
|
|
21
|
+
private buildNonceIv;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=WaFakeNoiseHandshake.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WaFakeNoiseHandshake.d.ts","sourceRoot":"","sources":["../../src/infra/WaFakeNoiseHandshake.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,EAGH,KAAK,SAAS,EAIjB,MAAM,qBAAqB,CAAA;AAI5B,MAAM,WAAW,8BAA8B;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAA;CACpC;AAED,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,YAAY,CAAI;IAEX,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7C,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAWnD,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAWjE,qFAAqF;IACxE,MAAM,IAAI,OAAO,CAAC,8BAA8B,CAAC;IAc9D,OAAO,CAAC,YAAY;CAMvB"}
|