@zapo-js/fake-server 1.2.0 → 1.3.1
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/dist/api/FakePairingDriver.d.ts +1 -0
- package/dist/api/FakePairingDriver.js +10 -2
- package/dist/api/FakeWaServer.d.ts +17 -0
- package/dist/api/FakeWaServer.js +4 -1
- package/dist/esm/api/FakePairingDriver.js +10 -2
- package/dist/esm/api/FakeWaServer.js +4 -1
- package/dist/index.d.ts +6 -0
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ export interface CompanionPairingMaterial {
|
|
|
15
15
|
export interface FakePairingDriverDeps {
|
|
16
16
|
readonly pipeline: WaFakeConnectionPipeline;
|
|
17
17
|
readonly waitForPairDeviceAck?: (pairDeviceIqId: string) => Promise<void>;
|
|
18
|
+
readonly waitForPairSuccessAck?: (pairSuccessIqId: string) => Promise<void>;
|
|
18
19
|
readonly companionMaterialResolver: () => Promise<CompanionPairingMaterial>;
|
|
19
20
|
}
|
|
20
21
|
export declare class FakePairingDriver {
|
|
@@ -4,6 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.FakePairingDriver = void 0;
|
|
5
5
|
const fake_primary_device_1 = require("../protocol/auth/fake-primary-device");
|
|
6
6
|
const pair_device_1 = require("../protocol/auth/pair-device");
|
|
7
|
+
const stream_error_1 = require("../protocol/stream/stream-error");
|
|
8
|
+
/** `stream:error` code the server sends once the companion has signed its identity. */
|
|
9
|
+
const FORCE_LOGIN_CODE = 515;
|
|
7
10
|
class FakePairingDriver {
|
|
8
11
|
constructor(options, deps) {
|
|
9
12
|
this.primary = null;
|
|
@@ -22,12 +25,17 @@ class FakePairingDriver {
|
|
|
22
25
|
companionIdentityPublicKey: material.identityPublicKey,
|
|
23
26
|
companionDeviceId: this.options.companionDeviceId ?? 1
|
|
24
27
|
});
|
|
25
|
-
|
|
28
|
+
const pairSuccessIq = (0, pair_device_1.buildPairSuccessIq)({
|
|
26
29
|
deviceJid: this.options.deviceJid,
|
|
27
30
|
deviceLid: this.options.deviceLid,
|
|
28
31
|
platform: this.options.platform ?? 'IOS',
|
|
29
32
|
deviceIdentityBytes
|
|
30
|
-
})
|
|
33
|
+
});
|
|
34
|
+
void this.deps
|
|
35
|
+
.waitForPairSuccessAck?.(pairSuccessIq.attrs.id)
|
|
36
|
+
.then(() => this.deps.pipeline.sendStanza((0, stream_error_1.buildStreamErrorCode)(FORCE_LOGIN_CODE)))
|
|
37
|
+
.catch(() => undefined);
|
|
38
|
+
await this.deps.pipeline.sendStanza(pairSuccessIq);
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
41
|
exports.FakePairingDriver = FakePairingDriver;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Agent as HttpsAgent } from 'node:https';
|
|
2
2
|
import { type WaFakeAuthenticatedInfo, WaFakeConnectionPipeline } from '../infra/WaFakeConnectionPipeline';
|
|
3
|
+
import { type FakeNoiseRootCa } from '../protocol/auth/cert-chain';
|
|
3
4
|
import type { ParsedClientPayload } from '../protocol/auth/client-payload-validate';
|
|
4
5
|
import type { BuildSuccessNodeInput } from '../protocol/auth/success-node';
|
|
5
6
|
import type { BuildAbPropsResultInput } from '../protocol/iq/abprops';
|
|
@@ -63,6 +64,22 @@ export interface FakeWaServerOptions {
|
|
|
63
64
|
readonly host?: string;
|
|
64
65
|
readonly port?: number;
|
|
65
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Root of the Noise certificate chain the server presents. Defaults to a
|
|
69
|
+
* fresh random CA per {@link FakeWaServer.listen}, read back from
|
|
70
|
+
* {@link FakeWaServer.noiseRootCa}.
|
|
71
|
+
*
|
|
72
|
+
* A client in a separate process cannot read it back: it has to pin the
|
|
73
|
+
* anchor before it dials, while the server is not listening yet. Pass a CA
|
|
74
|
+
* both sides derive from a shared seed to make it knowable ahead of time.
|
|
75
|
+
*
|
|
76
|
+
* Carries the signing half, unlike the public-only
|
|
77
|
+
* {@link FakeWaServerNoiseRootCa} this server exposes. It signs a chain no
|
|
78
|
+
* real client trusts, so it is test material rather than a secret — but a
|
|
79
|
+
* seed committed beside the tests is the intended source, not one shared
|
|
80
|
+
* with anything that matters.
|
|
81
|
+
*/
|
|
82
|
+
readonly noiseRootCa?: FakeNoiseRootCa;
|
|
66
83
|
}
|
|
67
84
|
export interface FakeSessionKeyInfo {
|
|
68
85
|
readonly clientPayload: ParsedClientPayload;
|
package/dist/api/FakeWaServer.js
CHANGED
|
@@ -372,6 +372,9 @@ class FakeWaServer {
|
|
|
372
372
|
}, {
|
|
373
373
|
timeoutMs: 15000
|
|
374
374
|
});
|
|
375
|
+
},
|
|
376
|
+
waitForPairSuccessAck: async (pairSuccessIqId) => {
|
|
377
|
+
await session.expectIq({ id: pairSuccessIqId }, { timeoutMs: 15000 });
|
|
375
378
|
}
|
|
376
379
|
});
|
|
377
380
|
await driver.run();
|
|
@@ -432,7 +435,7 @@ class FakeWaServer {
|
|
|
432
435
|
}
|
|
433
436
|
;
|
|
434
437
|
[this.rootCa, this.serverStaticKeyPair] = await Promise.all([
|
|
435
|
-
(0, cert_chain_1.generateFakeNoiseRootCa)(),
|
|
438
|
+
this.options.noiseRootCa ?? (0, cert_chain_1.generateFakeNoiseRootCa)(),
|
|
436
439
|
crypto_1.X25519.generateKeyPair()
|
|
437
440
|
]);
|
|
438
441
|
const mediaHandler = this.buildMediaRequestHandler();
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Runs the server side of the QR pairing flow. */
|
|
2
2
|
import { buildAdvSignedDeviceIdentity, generateFakePrimaryDevice } from '../protocol/auth/fake-primary-device.js';
|
|
3
3
|
import { buildPairDeviceIq, buildPairSuccessIq, mintPairingRefs } from '../protocol/auth/pair-device.js';
|
|
4
|
+
import { buildStreamErrorCode } from '../protocol/stream/stream-error.js';
|
|
5
|
+
/** `stream:error` code the server sends once the companion has signed its identity. */
|
|
6
|
+
const FORCE_LOGIN_CODE = 515;
|
|
4
7
|
export class FakePairingDriver {
|
|
5
8
|
constructor(options, deps) {
|
|
6
9
|
this.primary = null;
|
|
@@ -19,11 +22,16 @@ export class FakePairingDriver {
|
|
|
19
22
|
companionIdentityPublicKey: material.identityPublicKey,
|
|
20
23
|
companionDeviceId: this.options.companionDeviceId ?? 1
|
|
21
24
|
});
|
|
22
|
-
|
|
25
|
+
const pairSuccessIq = buildPairSuccessIq({
|
|
23
26
|
deviceJid: this.options.deviceJid,
|
|
24
27
|
deviceLid: this.options.deviceLid,
|
|
25
28
|
platform: this.options.platform ?? 'IOS',
|
|
26
29
|
deviceIdentityBytes
|
|
27
|
-
})
|
|
30
|
+
});
|
|
31
|
+
void this.deps
|
|
32
|
+
.waitForPairSuccessAck?.(pairSuccessIq.attrs.id)
|
|
33
|
+
.then(() => this.deps.pipeline.sendStanza(buildStreamErrorCode(FORCE_LOGIN_CODE)))
|
|
34
|
+
.catch(() => undefined);
|
|
35
|
+
await this.deps.pipeline.sendStanza(pairSuccessIq);
|
|
28
36
|
}
|
|
29
37
|
}
|
|
@@ -368,6 +368,9 @@ export class FakeWaServer {
|
|
|
368
368
|
}, {
|
|
369
369
|
timeoutMs: 15000
|
|
370
370
|
});
|
|
371
|
+
},
|
|
372
|
+
waitForPairSuccessAck: async (pairSuccessIqId) => {
|
|
373
|
+
await session.expectIq({ id: pairSuccessIqId }, { timeoutMs: 15000 });
|
|
371
374
|
}
|
|
372
375
|
});
|
|
373
376
|
await driver.run();
|
|
@@ -428,7 +431,7 @@ export class FakeWaServer {
|
|
|
428
431
|
}
|
|
429
432
|
;
|
|
430
433
|
[this.rootCa, this.serverStaticKeyPair] = await Promise.all([
|
|
431
|
-
generateFakeNoiseRootCa(),
|
|
434
|
+
this.options.noiseRootCa ?? generateFakeNoiseRootCa(),
|
|
432
435
|
X25519.generateKeyPair()
|
|
433
436
|
]);
|
|
434
437
|
const mediaHandler = this.buildMediaRequestHandler();
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export { FakePeer } from './api/FakePeer';
|
|
|
6
6
|
export type { CreateFakePeerOptions, ExpectGroupMessageOptions, ExpectMessageOptions, ReceivedMessage, SendMessageOptions } from './api/FakePeer';
|
|
7
7
|
export { FakeServerSession, FakeWaServer } from './api/FakeWaServer';
|
|
8
8
|
export type { BinaryNode, ExpectIqOptions, ExpectStanzaOptions, FakeSessionKeyInfo, FakeWaServerNoiseRootCa, FakeWaServerOptions, FakeWaServerPipelineListener, StanzaMatcher, WaFakeAuthenticatedInfo, WaFakeConnectionPipeline } from './api/FakeWaServer';
|
|
9
|
+
/**
|
|
10
|
+
* Signing half of the Noise root, needed only to pin
|
|
11
|
+
* {@link FakeWaServerOptions.noiseRootCa}. Readers of `server.noiseRootCa` get
|
|
12
|
+
* the public-only {@link FakeWaServerNoiseRootCa} instead.
|
|
13
|
+
*/
|
|
14
|
+
export type { FakeNoiseRootCa } from './protocol/auth/cert-chain';
|
|
9
15
|
export { IqExpectation, Scenario } from './api/Scenario';
|
|
10
16
|
export type { AuthenticatedPipelineListener, ScenarioServer } from './api/Scenario';
|
|
11
17
|
export { WaFakeConnection } from './infra/WaFakeConnection';
|
package/package.json
CHANGED