@zapo-js/fake-server 0.3.0 → 1.1.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 +96 -8
- package/dist/api/AppStateSyncManager.d.ts +0 -1
- package/dist/api/AppStateSyncManager.js +0 -1
- package/dist/api/FakePairingDriver.d.ts +0 -1
- package/dist/api/FakePairingDriver.js +0 -1
- package/dist/api/FakePeer.d.ts +77 -4
- package/dist/api/FakePeer.js +208 -2
- package/dist/api/FakeServerSession.d.ts +67 -0
- package/dist/api/FakeServerSession.js +293 -0
- package/dist/api/FakeWaServer.d.ts +77 -31
- package/dist/api/FakeWaServer.js +140 -259
- package/dist/api/PreKeyDispenser.d.ts +0 -1
- package/dist/api/PreKeyDispenser.js +0 -1
- package/dist/api/Scenario.d.ts +0 -1
- package/dist/api/Scenario.js +0 -1
- package/dist/api/ServerRegistries.d.ts +0 -1
- package/dist/api/ServerRegistries.js +0 -1
- package/dist/api/iq-handlers.d.ts +1 -1
- package/dist/api/iq-handlers.js +23 -1
- package/dist/{cli.d.ts → bin.d.ts} +0 -1
- package/dist/bin.js +296 -0
- package/dist/esm/api/AppStateSyncManager.js +146 -0
- package/dist/esm/api/FakePairingDriver.js +31 -0
- package/dist/esm/api/FakePeer.js +610 -0
- package/dist/esm/api/FakeServerSession.js +287 -0
- package/dist/esm/api/FakeWaServer.js +528 -0
- package/dist/esm/api/PreKeyDispenser.js +93 -0
- package/dist/esm/api/Scenario.js +32 -0
- package/dist/esm/api/ServerRegistries.js +261 -0
- package/dist/esm/api/iq-handlers.js +515 -0
- package/dist/{cli.js → esm/bin.js} +70 -25
- package/dist/esm/index.js +26 -0
- package/dist/esm/infra/WaFakeConnection.js +49 -0
- package/dist/esm/infra/WaFakeConnectionPipeline.js +235 -0
- package/dist/esm/infra/WaFakeFrameSocket.js +117 -0
- package/dist/esm/infra/WaFakeMediaHttpsServer.js +126 -0
- package/dist/esm/infra/WaFakeNoiseHandshake.js +67 -0
- package/dist/esm/infra/WaFakeTransport.js +31 -0
- package/dist/esm/infra/WaFakeWsServer.js +96 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/protocol/auth/cert-chain.js +50 -0
- package/dist/esm/protocol/auth/client-payload-validate.js +55 -0
- package/dist/esm/protocol/auth/fake-primary-device.js +47 -0
- package/dist/esm/protocol/auth/pair-device.js +87 -0
- package/dist/esm/protocol/auth/success-node.js +26 -0
- package/dist/esm/protocol/iq/abprops.js +30 -0
- package/dist/esm/protocol/iq/appstate-sync.js +146 -0
- package/dist/esm/protocol/iq/business.js +59 -0
- package/dist/esm/protocol/iq/dirty-bits.js +19 -0
- package/dist/esm/protocol/iq/group-ops.js +154 -0
- package/dist/esm/protocol/iq/newsletter.js +14 -0
- package/dist/esm/protocol/iq/prekey-fetch.js +88 -0
- package/dist/esm/protocol/iq/privacy-token.js +26 -0
- package/dist/esm/protocol/iq/privacy.js +123 -0
- package/dist/esm/protocol/iq/profile.js +72 -0
- package/dist/esm/protocol/iq/router.js +117 -0
- package/dist/esm/protocol/iq/usync.js +64 -0
- package/dist/esm/protocol/push/app-state-key-share.js +26 -0
- package/dist/esm/protocol/push/call-failure.js +27 -0
- package/dist/esm/protocol/push/chatstate.js +23 -0
- package/dist/esm/protocol/push/error-stanza.js +13 -0
- package/dist/esm/protocol/push/history-sync.js +111 -0
- package/dist/esm/protocol/push/message.js +38 -0
- package/dist/esm/protocol/push/notification.js +29 -0
- package/dist/esm/protocol/push/presence.js +14 -0
- package/dist/esm/protocol/push/receipt.js +21 -0
- package/dist/esm/protocol/signal/fake-app-state-crypto.js +196 -0
- package/dist/esm/protocol/signal/fake-peer-double-ratchet.js +398 -0
- package/dist/esm/protocol/signal/fake-peer-group-recv-session.js +120 -0
- package/dist/esm/protocol/signal/fake-peer-identity.js +8 -0
- package/dist/esm/protocol/signal/fake-peer-key-bundle.js +25 -0
- package/dist/esm/protocol/signal/fake-sender-key.js +83 -0
- package/dist/esm/protocol/signal/prekey-upload.js +107 -0
- package/dist/esm/protocol/stream/stream-error.js +56 -0
- package/dist/esm/state/fake-app-state-collection.js +134 -0
- package/dist/esm/state/fake-media-store.js +53 -0
- package/dist/esm/transport/codec.js +8 -0
- package/dist/esm/transport/crypto.js +8 -0
- package/dist/esm/transport/protos.js +7 -0
- package/dist/esm/transport/util.js +8 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -2
- package/dist/infra/WaFakeConnection.d.ts +0 -1
- package/dist/infra/WaFakeConnection.js +0 -1
- package/dist/infra/WaFakeConnectionPipeline.d.ts +10 -3
- package/dist/infra/WaFakeConnectionPipeline.js +47 -32
- package/dist/infra/WaFakeFrameSocket.d.ts +0 -1
- package/dist/infra/WaFakeFrameSocket.js +0 -1
- package/dist/infra/WaFakeMediaHttpsServer.d.ts +0 -1
- package/dist/infra/WaFakeMediaHttpsServer.js +0 -1
- package/dist/infra/WaFakeNoiseHandshake.d.ts +8 -10
- package/dist/infra/WaFakeNoiseHandshake.js +19 -24
- package/dist/infra/WaFakeTransport.d.ts +2 -4
- package/dist/infra/WaFakeTransport.js +2 -1
- package/dist/infra/WaFakeWsServer.d.ts +0 -1
- package/dist/infra/WaFakeWsServer.js +0 -1
- package/dist/protocol/auth/cert-chain.d.ts +4 -1
- package/dist/protocol/auth/cert-chain.js +13 -3
- package/dist/protocol/auth/client-payload-validate.d.ts +0 -1
- package/dist/protocol/auth/client-payload-validate.js +0 -1
- package/dist/protocol/auth/fake-primary-device.d.ts +0 -1
- package/dist/protocol/auth/fake-primary-device.js +1 -3
- package/dist/protocol/auth/pair-device.d.ts +0 -1
- package/dist/protocol/auth/pair-device.js +4 -16
- package/dist/protocol/auth/success-node.d.ts +0 -1
- package/dist/protocol/auth/success-node.js +0 -1
- package/dist/protocol/iq/abprops.d.ts +0 -1
- package/dist/protocol/iq/abprops.js +0 -1
- package/dist/protocol/iq/appstate-sync.d.ts +0 -1
- package/dist/protocol/iq/appstate-sync.js +0 -1
- package/dist/protocol/iq/business.d.ts +0 -1
- package/dist/protocol/iq/business.js +0 -1
- package/dist/protocol/iq/dirty-bits.d.ts +0 -1
- package/dist/protocol/iq/dirty-bits.js +0 -1
- package/dist/protocol/iq/group-ops.d.ts +0 -1
- package/dist/protocol/iq/group-ops.js +0 -1
- package/dist/protocol/iq/newsletter.d.ts +0 -1
- package/dist/protocol/iq/newsletter.js +0 -1
- package/dist/protocol/iq/prekey-fetch.d.ts +0 -1
- package/dist/protocol/iq/prekey-fetch.js +0 -1
- package/dist/protocol/iq/privacy-token.d.ts +0 -1
- package/dist/protocol/iq/privacy-token.js +0 -1
- package/dist/protocol/iq/privacy.d.ts +0 -1
- package/dist/protocol/iq/privacy.js +15 -16
- package/dist/protocol/iq/profile.d.ts +0 -1
- package/dist/protocol/iq/profile.js +0 -1
- package/dist/protocol/iq/router.d.ts +7 -2
- package/dist/protocol/iq/router.js +8 -3
- package/dist/protocol/iq/usync.d.ts +0 -1
- package/dist/protocol/iq/usync.js +0 -1
- package/dist/protocol/push/app-state-key-share.d.ts +0 -1
- package/dist/protocol/push/app-state-key-share.js +0 -1
- package/dist/protocol/push/call-failure.d.ts +0 -1
- package/dist/protocol/push/call-failure.js +0 -1
- package/dist/protocol/push/chatstate.d.ts +0 -1
- package/dist/protocol/push/chatstate.js +0 -1
- package/dist/protocol/push/error-stanza.d.ts +0 -1
- package/dist/protocol/push/error-stanza.js +0 -1
- package/dist/protocol/push/history-sync.d.ts +0 -1
- package/dist/protocol/push/history-sync.js +0 -1
- package/dist/protocol/push/message.d.ts +0 -1
- package/dist/protocol/push/message.js +0 -1
- package/dist/protocol/push/notification.d.ts +0 -1
- package/dist/protocol/push/notification.js +0 -1
- package/dist/protocol/push/presence.d.ts +0 -1
- package/dist/protocol/push/presence.js +0 -1
- package/dist/protocol/push/receipt.d.ts +0 -1
- package/dist/protocol/push/receipt.js +0 -1
- package/dist/protocol/signal/fake-app-state-crypto.d.ts +7 -9
- package/dist/protocol/signal/fake-app-state-crypto.js +31 -33
- package/dist/protocol/signal/fake-peer-double-ratchet.d.ts +0 -1
- package/dist/protocol/signal/fake-peer-double-ratchet.js +23 -28
- package/dist/protocol/signal/fake-peer-group-recv-session.d.ts +0 -1
- package/dist/protocol/signal/fake-peer-group-recv-session.js +6 -10
- package/dist/protocol/signal/fake-peer-identity.d.ts +0 -1
- package/dist/protocol/signal/fake-peer-identity.js +0 -1
- package/dist/protocol/signal/fake-peer-key-bundle.d.ts +0 -1
- package/dist/protocol/signal/fake-peer-key-bundle.js +0 -1
- package/dist/protocol/signal/fake-sender-key.d.ts +0 -1
- package/dist/protocol/signal/fake-sender-key.js +5 -9
- package/dist/protocol/signal/prekey-upload.d.ts +0 -1
- package/dist/protocol/signal/prekey-upload.js +0 -1
- package/dist/protocol/stream/stream-error.d.ts +0 -1
- package/dist/protocol/stream/stream-error.js +0 -1
- package/dist/state/fake-app-state-collection.d.ts +0 -1
- package/dist/state/fake-app-state-collection.js +0 -1
- package/dist/state/fake-media-store.d.ts +0 -1
- package/dist/state/fake-media-store.js +2 -2
- package/dist/transport/codec.d.ts +2 -3
- package/dist/transport/codec.js +2 -3
- package/dist/transport/crypto.d.ts +5 -7
- package/dist/transport/crypto.js +6 -11
- package/dist/transport/protos.d.ts +2 -4
- package/dist/transport/protos.js +2 -4
- package/dist/transport/util.d.ts +8 -0
- package/dist/transport/util.js +16 -0
- package/package.json +26 -6
- package/dist/api/AppStateSyncManager.d.ts.map +0 -1
- package/dist/api/AppStateSyncManager.js.map +0 -1
- package/dist/api/FakePairingDriver.d.ts.map +0 -1
- package/dist/api/FakePairingDriver.js.map +0 -1
- package/dist/api/FakePeer.d.ts.map +0 -1
- package/dist/api/FakePeer.js.map +0 -1
- package/dist/api/FakeWaServer.d.ts.map +0 -1
- package/dist/api/FakeWaServer.js.map +0 -1
- package/dist/api/PreKeyDispenser.d.ts.map +0 -1
- package/dist/api/PreKeyDispenser.js.map +0 -1
- package/dist/api/Scenario.d.ts.map +0 -1
- package/dist/api/Scenario.js.map +0 -1
- package/dist/api/ServerRegistries.d.ts.map +0 -1
- package/dist/api/ServerRegistries.js.map +0 -1
- package/dist/api/iq-handlers.d.ts.map +0 -1
- package/dist/api/iq-handlers.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/infra/WaFakeConnection.d.ts.map +0 -1
- package/dist/infra/WaFakeConnection.js.map +0 -1
- package/dist/infra/WaFakeConnectionPipeline.d.ts.map +0 -1
- package/dist/infra/WaFakeConnectionPipeline.js.map +0 -1
- package/dist/infra/WaFakeFrameSocket.d.ts.map +0 -1
- package/dist/infra/WaFakeFrameSocket.js.map +0 -1
- package/dist/infra/WaFakeMediaHttpsServer.d.ts.map +0 -1
- package/dist/infra/WaFakeMediaHttpsServer.js.map +0 -1
- package/dist/infra/WaFakeNoiseHandshake.d.ts.map +0 -1
- package/dist/infra/WaFakeNoiseHandshake.js.map +0 -1
- package/dist/infra/WaFakeTransport.d.ts.map +0 -1
- package/dist/infra/WaFakeTransport.js.map +0 -1
- package/dist/infra/WaFakeWsServer.d.ts.map +0 -1
- package/dist/infra/WaFakeWsServer.js.map +0 -1
- package/dist/protocol/auth/cert-chain.d.ts.map +0 -1
- package/dist/protocol/auth/cert-chain.js.map +0 -1
- package/dist/protocol/auth/client-payload-validate.d.ts.map +0 -1
- package/dist/protocol/auth/client-payload-validate.js.map +0 -1
- package/dist/protocol/auth/fake-primary-device.d.ts.map +0 -1
- package/dist/protocol/auth/fake-primary-device.js.map +0 -1
- package/dist/protocol/auth/pair-device.d.ts.map +0 -1
- package/dist/protocol/auth/pair-device.js.map +0 -1
- package/dist/protocol/auth/success-node.d.ts.map +0 -1
- package/dist/protocol/auth/success-node.js.map +0 -1
- package/dist/protocol/iq/abprops.d.ts.map +0 -1
- package/dist/protocol/iq/abprops.js.map +0 -1
- package/dist/protocol/iq/appstate-sync.d.ts.map +0 -1
- package/dist/protocol/iq/appstate-sync.js.map +0 -1
- package/dist/protocol/iq/business.d.ts.map +0 -1
- package/dist/protocol/iq/business.js.map +0 -1
- package/dist/protocol/iq/dirty-bits.d.ts.map +0 -1
- package/dist/protocol/iq/dirty-bits.js.map +0 -1
- package/dist/protocol/iq/group-ops.d.ts.map +0 -1
- package/dist/protocol/iq/group-ops.js.map +0 -1
- package/dist/protocol/iq/newsletter.d.ts.map +0 -1
- package/dist/protocol/iq/newsletter.js.map +0 -1
- package/dist/protocol/iq/prekey-fetch.d.ts.map +0 -1
- package/dist/protocol/iq/prekey-fetch.js.map +0 -1
- package/dist/protocol/iq/privacy-token.d.ts.map +0 -1
- package/dist/protocol/iq/privacy-token.js.map +0 -1
- package/dist/protocol/iq/privacy.d.ts.map +0 -1
- package/dist/protocol/iq/privacy.js.map +0 -1
- package/dist/protocol/iq/profile.d.ts.map +0 -1
- package/dist/protocol/iq/profile.js.map +0 -1
- package/dist/protocol/iq/router.d.ts.map +0 -1
- package/dist/protocol/iq/router.js.map +0 -1
- package/dist/protocol/iq/usync.d.ts.map +0 -1
- package/dist/protocol/iq/usync.js.map +0 -1
- package/dist/protocol/push/app-state-key-share.d.ts.map +0 -1
- package/dist/protocol/push/app-state-key-share.js.map +0 -1
- package/dist/protocol/push/call-failure.d.ts.map +0 -1
- package/dist/protocol/push/call-failure.js.map +0 -1
- package/dist/protocol/push/chatstate.d.ts.map +0 -1
- package/dist/protocol/push/chatstate.js.map +0 -1
- package/dist/protocol/push/error-stanza.d.ts.map +0 -1
- package/dist/protocol/push/error-stanza.js.map +0 -1
- package/dist/protocol/push/history-sync.d.ts.map +0 -1
- package/dist/protocol/push/history-sync.js.map +0 -1
- package/dist/protocol/push/message.d.ts.map +0 -1
- package/dist/protocol/push/message.js.map +0 -1
- package/dist/protocol/push/notification.d.ts.map +0 -1
- package/dist/protocol/push/notification.js.map +0 -1
- package/dist/protocol/push/presence.d.ts.map +0 -1
- package/dist/protocol/push/presence.js.map +0 -1
- package/dist/protocol/push/receipt.d.ts.map +0 -1
- package/dist/protocol/push/receipt.js.map +0 -1
- package/dist/protocol/signal/fake-app-state-crypto.d.ts.map +0 -1
- package/dist/protocol/signal/fake-app-state-crypto.js.map +0 -1
- package/dist/protocol/signal/fake-peer-double-ratchet.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-double-ratchet.js.map +0 -1
- package/dist/protocol/signal/fake-peer-group-recv-session.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-group-recv-session.js.map +0 -1
- package/dist/protocol/signal/fake-peer-identity.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-identity.js.map +0 -1
- package/dist/protocol/signal/fake-peer-key-bundle.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-key-bundle.js.map +0 -1
- package/dist/protocol/signal/fake-peer-recv-session.d.ts +0 -60
- package/dist/protocol/signal/fake-peer-recv-session.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-recv-session.js +0 -284
- package/dist/protocol/signal/fake-peer-recv-session.js.map +0 -1
- package/dist/protocol/signal/fake-peer-session.d.ts +0 -87
- package/dist/protocol/signal/fake-peer-session.d.ts.map +0 -1
- package/dist/protocol/signal/fake-peer-session.js +0 -207
- package/dist/protocol/signal/fake-peer-session.js.map +0 -1
- package/dist/protocol/signal/fake-sender-key.d.ts.map +0 -1
- package/dist/protocol/signal/fake-sender-key.js.map +0 -1
- package/dist/protocol/signal/prekey-upload.d.ts.map +0 -1
- package/dist/protocol/signal/prekey-upload.js.map +0 -1
- package/dist/protocol/stream/stream-error.d.ts.map +0 -1
- package/dist/protocol/stream/stream-error.js.map +0 -1
- package/dist/state/fake-app-state-collection.d.ts.map +0 -1
- package/dist/state/fake-app-state-collection.js.map +0 -1
- package/dist/state/fake-media-store.d.ts.map +0 -1
- package/dist/state/fake-media-store.js.map +0 -1
- package/dist/transport/codec.d.ts.map +0 -1
- package/dist/transport/codec.js.map +0 -1
- package/dist/transport/crypto.d.ts.map +0 -1
- package/dist/transport/crypto.js.map +0 -1
- package/dist/transport/index.d.ts +0 -4
- package/dist/transport/index.d.ts.map +0 -1
- package/dist/transport/index.js +0 -20
- package/dist/transport/index.js.map +0 -1
- package/dist/transport/protos.d.ts.map +0 -1
- package/dist/transport/protos.js.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Builders/parsers for profile picture and status IQs. */
|
|
2
|
+
import { buildIqResult } from './router.js';
|
|
3
|
+
export function buildGetProfilePictureResult(iq, picture) {
|
|
4
|
+
const attrs = {};
|
|
5
|
+
if (picture.url)
|
|
6
|
+
attrs.url = picture.url;
|
|
7
|
+
if (picture.directPath)
|
|
8
|
+
attrs.direct_path = picture.directPath;
|
|
9
|
+
if (picture.id)
|
|
10
|
+
attrs.id = picture.id;
|
|
11
|
+
if (picture.type)
|
|
12
|
+
attrs.type = picture.type;
|
|
13
|
+
const result = buildIqResult(iq);
|
|
14
|
+
return {
|
|
15
|
+
...result,
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
tag: 'picture',
|
|
19
|
+
attrs
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function buildSetProfilePictureResult(iq, newId) {
|
|
25
|
+
const result = buildIqResult(iq);
|
|
26
|
+
return {
|
|
27
|
+
...result,
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
tag: 'picture',
|
|
31
|
+
attrs: { id: newId }
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function parseGetProfilePictureIq(iq) {
|
|
37
|
+
const targetJid = iq.attrs.target;
|
|
38
|
+
if (!targetJid)
|
|
39
|
+
return null;
|
|
40
|
+
let type = 'preview';
|
|
41
|
+
if (Array.isArray(iq.content)) {
|
|
42
|
+
const picture = iq.content.find((child) => child.tag === 'picture');
|
|
43
|
+
if (picture && picture.attrs.type === 'image') {
|
|
44
|
+
type = 'image';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { targetJid, type };
|
|
48
|
+
}
|
|
49
|
+
export function parseSetProfilePictureIq(iq) {
|
|
50
|
+
if (!Array.isArray(iq.content))
|
|
51
|
+
return null;
|
|
52
|
+
const picture = iq.content.find((child) => child.tag === 'picture');
|
|
53
|
+
if (!picture || !(picture.content instanceof Uint8Array))
|
|
54
|
+
return null;
|
|
55
|
+
return {
|
|
56
|
+
targetJid: iq.attrs.target,
|
|
57
|
+
imageBytes: picture.content
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function parseSetStatusIq(iq) {
|
|
61
|
+
if (!Array.isArray(iq.content))
|
|
62
|
+
return null;
|
|
63
|
+
const status = iq.content.find((child) => child.tag === 'status');
|
|
64
|
+
if (!status)
|
|
65
|
+
return null;
|
|
66
|
+
if (typeof status.content === 'string')
|
|
67
|
+
return { text: status.content };
|
|
68
|
+
if (status.content instanceof Uint8Array) {
|
|
69
|
+
return { text: new TextDecoder().decode(status.content) };
|
|
70
|
+
}
|
|
71
|
+
return { text: '' };
|
|
72
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/** IQ matcher/dispatcher used by the fake server. */
|
|
2
|
+
export class WaFakeIqRouter {
|
|
3
|
+
constructor() {
|
|
4
|
+
/** High-priority handlers override default ones for a test case. */
|
|
5
|
+
this.highPriorityHandlers = [];
|
|
6
|
+
this.handlers = [];
|
|
7
|
+
this.events = {};
|
|
8
|
+
}
|
|
9
|
+
register(handler, options = {}) {
|
|
10
|
+
const list = options.priority === 'high' ? this.highPriorityHandlers : this.handlers;
|
|
11
|
+
list.push(handler);
|
|
12
|
+
return () => {
|
|
13
|
+
const index = list.indexOf(handler);
|
|
14
|
+
if (index >= 0) {
|
|
15
|
+
list.splice(index, 1);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
setEvents(events) {
|
|
20
|
+
this.events = events;
|
|
21
|
+
}
|
|
22
|
+
async route(iq) {
|
|
23
|
+
if (iq.tag !== 'iq') {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
for (const handler of this.highPriorityHandlers) {
|
|
27
|
+
if (matches(iq, handler.matcher)) {
|
|
28
|
+
const response = await handler.respond(iq);
|
|
29
|
+
if (response !== null) {
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const handler of this.handlers) {
|
|
35
|
+
if (matches(iq, handler.matcher)) {
|
|
36
|
+
const response = await handler.respond(iq);
|
|
37
|
+
if (response !== null) {
|
|
38
|
+
return response;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this.events.onUnhandled?.(iq);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function matches(iq, matcher) {
|
|
47
|
+
if (matcher.id !== undefined) {
|
|
48
|
+
if (iq.attrs.id !== matcher.id)
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (matcher.type !== undefined) {
|
|
52
|
+
if (iq.attrs.type !== matcher.type)
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (matcher.xmlns !== undefined) {
|
|
56
|
+
if (iq.attrs.xmlns !== matcher.xmlns)
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (matcher.childTag !== undefined) {
|
|
60
|
+
const children = Array.isArray(iq.content) ? iq.content : null;
|
|
61
|
+
if (!children || children.length === 0)
|
|
62
|
+
return false;
|
|
63
|
+
if (children[0].tag !== matcher.childTag)
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
export function buildIqResult(inbound, options = {}) {
|
|
69
|
+
const id = inbound.attrs.id;
|
|
70
|
+
if (!id) {
|
|
71
|
+
throw new Error('cannot build iq result for inbound iq without an id');
|
|
72
|
+
}
|
|
73
|
+
const attrs = {
|
|
74
|
+
type: 'result',
|
|
75
|
+
id
|
|
76
|
+
};
|
|
77
|
+
if (options.from !== undefined) {
|
|
78
|
+
attrs.from = options.from;
|
|
79
|
+
}
|
|
80
|
+
else if (typeof inbound.attrs.to === 'string') {
|
|
81
|
+
attrs.from = inbound.attrs.to;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
tag: 'iq',
|
|
85
|
+
attrs,
|
|
86
|
+
...(options.content ? { content: options.content } : {})
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function buildIqError(inbound, options) {
|
|
90
|
+
const id = inbound.attrs.id;
|
|
91
|
+
if (!id) {
|
|
92
|
+
throw new Error('cannot build iq error for inbound iq without an id');
|
|
93
|
+
}
|
|
94
|
+
const attrs = {
|
|
95
|
+
type: 'error',
|
|
96
|
+
id
|
|
97
|
+
};
|
|
98
|
+
if (options.from !== undefined) {
|
|
99
|
+
attrs.from = options.from;
|
|
100
|
+
}
|
|
101
|
+
else if (typeof inbound.attrs.to === 'string') {
|
|
102
|
+
attrs.from = inbound.attrs.to;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
tag: 'iq',
|
|
106
|
+
attrs,
|
|
107
|
+
content: [
|
|
108
|
+
{
|
|
109
|
+
tag: 'error',
|
|
110
|
+
attrs: {
|
|
111
|
+
code: String(options.code),
|
|
112
|
+
...(options.text !== undefined ? { text: options.text } : {})
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Builder for `usync` IQ result responses. */
|
|
2
|
+
export function buildUsyncDevicesResult(inboundIq, users) {
|
|
3
|
+
const id = inboundIq.attrs.id;
|
|
4
|
+
if (!id) {
|
|
5
|
+
throw new Error('cannot build usync result without an inbound id');
|
|
6
|
+
}
|
|
7
|
+
const sid = extractUsyncSid(inboundIq) ?? `usync-${id}`;
|
|
8
|
+
const userNodes = users.map((user) => ({
|
|
9
|
+
tag: 'user',
|
|
10
|
+
attrs: { jid: user.userJid },
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
tag: 'devices',
|
|
14
|
+
attrs: {},
|
|
15
|
+
content: [
|
|
16
|
+
{
|
|
17
|
+
tag: 'device-list',
|
|
18
|
+
attrs: {},
|
|
19
|
+
content: (user.deviceIds ?? [0]).map((deviceId) => ({
|
|
20
|
+
tag: 'device',
|
|
21
|
+
attrs: { id: String(deviceId) }
|
|
22
|
+
}))
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}));
|
|
28
|
+
return {
|
|
29
|
+
tag: 'iq',
|
|
30
|
+
attrs: {
|
|
31
|
+
id,
|
|
32
|
+
from: inboundIq.attrs.to ?? 's.whatsapp.net',
|
|
33
|
+
type: 'result'
|
|
34
|
+
},
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
tag: 'usync',
|
|
38
|
+
attrs: {
|
|
39
|
+
sid,
|
|
40
|
+
mode: 'query',
|
|
41
|
+
last: 'true',
|
|
42
|
+
index: '0'
|
|
43
|
+
},
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
tag: 'list',
|
|
47
|
+
attrs: {},
|
|
48
|
+
content: userNodes
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function extractUsyncSid(iq) {
|
|
56
|
+
if (!Array.isArray(iq.content))
|
|
57
|
+
return undefined;
|
|
58
|
+
for (const child of iq.content) {
|
|
59
|
+
if (child.tag === 'usync' && typeof child.attrs.sid === 'string') {
|
|
60
|
+
return child.attrs.sid;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Builder for `APP_STATE_SYNC_KEY_SHARE` protocol messages. */
|
|
2
|
+
import { proto } from '../../transport/protos.js';
|
|
3
|
+
export function buildAppStateSyncKeyShareMessage(input) {
|
|
4
|
+
if (input.keys.length === 0) {
|
|
5
|
+
throw new Error('buildAppStateSyncKeyShareMessage requires at least one key');
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
protocolMessage: {
|
|
9
|
+
type: proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE,
|
|
10
|
+
appStateSyncKeyShare: {
|
|
11
|
+
keys: input.keys.map((key) => ({
|
|
12
|
+
keyId: { keyId: key.keyId },
|
|
13
|
+
keyData: {
|
|
14
|
+
keyData: key.keyData,
|
|
15
|
+
timestamp: key.timestamp ?? Date.now(),
|
|
16
|
+
fingerprint: {
|
|
17
|
+
rawId: key.fingerprint?.rawId ?? 0,
|
|
18
|
+
currentIndex: key.fingerprint?.currentIndex ?? 0,
|
|
19
|
+
deviceIndexes: [...(key.fingerprint?.deviceIndexes ?? [])]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function buildCall(input) {
|
|
2
|
+
const attrs = {
|
|
3
|
+
id: input.id,
|
|
4
|
+
from: input.from
|
|
5
|
+
};
|
|
6
|
+
if (input.to !== undefined)
|
|
7
|
+
attrs.to = input.to;
|
|
8
|
+
if (input.t !== undefined)
|
|
9
|
+
attrs.t = String(input.t);
|
|
10
|
+
return {
|
|
11
|
+
tag: 'call',
|
|
12
|
+
attrs,
|
|
13
|
+
...(input.children ? { content: input.children } : {})
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function buildFailure(input) {
|
|
17
|
+
const attrs = {
|
|
18
|
+
reason: input.reason,
|
|
19
|
+
...(input.extraAttrs ?? {})
|
|
20
|
+
};
|
|
21
|
+
if (input.location !== undefined)
|
|
22
|
+
attrs.location = input.location;
|
|
23
|
+
return {
|
|
24
|
+
tag: 'failure',
|
|
25
|
+
attrs
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Builder for inbound `<chatstate/>` stanzas. */
|
|
2
|
+
export function buildChatstate(input) {
|
|
3
|
+
const attrs = { from: input.from };
|
|
4
|
+
if (input.participant !== undefined) {
|
|
5
|
+
attrs.participant = input.participant;
|
|
6
|
+
}
|
|
7
|
+
let stateChild;
|
|
8
|
+
if (input.state.kind === 'composing') {
|
|
9
|
+
const childAttrs = {};
|
|
10
|
+
if (input.state.media !== undefined) {
|
|
11
|
+
childAttrs.media = input.state.media;
|
|
12
|
+
}
|
|
13
|
+
stateChild = { tag: 'composing', attrs: childAttrs };
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
stateChild = { tag: 'paused', attrs: {} };
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
tag: 'chatstate',
|
|
20
|
+
attrs,
|
|
21
|
+
content: [stateChild]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function buildIncomingErrorStanza(input) {
|
|
2
|
+
const attrs = {
|
|
3
|
+
code: String(input.code)
|
|
4
|
+
};
|
|
5
|
+
if (input.text !== undefined)
|
|
6
|
+
attrs.text = input.text;
|
|
7
|
+
if (input.from !== undefined)
|
|
8
|
+
attrs.from = input.from;
|
|
9
|
+
return {
|
|
10
|
+
tag: 'error',
|
|
11
|
+
attrs
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** History-sync message builders (inline and external blob variants). */
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { deflate } from 'node:zlib';
|
|
4
|
+
import { proto } from '../../transport/protos.js';
|
|
5
|
+
const deflateAsync = promisify(deflate);
|
|
6
|
+
export async function buildHistorySyncMessage(input = {}) {
|
|
7
|
+
const syncType = input.syncType ?? proto.Message.HistorySyncType.INITIAL_BOOTSTRAP;
|
|
8
|
+
const conversations = (input.conversations ?? []).map((conversation) => ({
|
|
9
|
+
id: conversation.id,
|
|
10
|
+
name: conversation.name,
|
|
11
|
+
unreadCount: conversation.unreadCount,
|
|
12
|
+
archived: conversation.archived,
|
|
13
|
+
pinned: conversation.pinned,
|
|
14
|
+
muteEndTime: conversation.muteEndTime,
|
|
15
|
+
markedAsUnread: conversation.markedAsUnread,
|
|
16
|
+
ephemeralExpiration: conversation.ephemeralExpiration,
|
|
17
|
+
messages: (conversation.messages ?? []).map((histMsg) => ({
|
|
18
|
+
message: {
|
|
19
|
+
key: {
|
|
20
|
+
id: histMsg.id,
|
|
21
|
+
fromMe: histMsg.fromMe ?? false,
|
|
22
|
+
remoteJid: conversation.id,
|
|
23
|
+
participant: histMsg.participant
|
|
24
|
+
},
|
|
25
|
+
messageTimestamp: histMsg.timestamp,
|
|
26
|
+
message: histMsg.message
|
|
27
|
+
}
|
|
28
|
+
}))
|
|
29
|
+
}));
|
|
30
|
+
const pushnames = (input.pushnames ?? []).map((entry) => ({
|
|
31
|
+
id: entry.id,
|
|
32
|
+
pushname: entry.pushname
|
|
33
|
+
}));
|
|
34
|
+
const historySync = proto.HistorySync.encode({
|
|
35
|
+
syncType: syncType,
|
|
36
|
+
chunkOrder: input.chunkOrder ?? 0,
|
|
37
|
+
progress: input.progress ?? 100,
|
|
38
|
+
conversations,
|
|
39
|
+
pushnames,
|
|
40
|
+
nctSalt: input.nctSalt
|
|
41
|
+
}).finish();
|
|
42
|
+
const compressed = await deflateAsync(historySync);
|
|
43
|
+
return {
|
|
44
|
+
protocolMessage: {
|
|
45
|
+
type: proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION,
|
|
46
|
+
historySyncNotification: {
|
|
47
|
+
syncType,
|
|
48
|
+
chunkOrder: input.chunkOrder ?? 0,
|
|
49
|
+
progress: input.progress ?? 100,
|
|
50
|
+
initialHistBootstrapInlinePayload: new Uint8Array(compressed)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export async function encodeHistorySyncPlaintext(input = {}) {
|
|
56
|
+
const syncType = input.syncType ?? proto.Message.HistorySyncType.INITIAL_BOOTSTRAP;
|
|
57
|
+
const conversations = (input.conversations ?? []).map((conversation) => ({
|
|
58
|
+
id: conversation.id,
|
|
59
|
+
name: conversation.name,
|
|
60
|
+
unreadCount: conversation.unreadCount,
|
|
61
|
+
archived: conversation.archived,
|
|
62
|
+
pinned: conversation.pinned,
|
|
63
|
+
muteEndTime: conversation.muteEndTime,
|
|
64
|
+
markedAsUnread: conversation.markedAsUnread,
|
|
65
|
+
ephemeralExpiration: conversation.ephemeralExpiration,
|
|
66
|
+
messages: (conversation.messages ?? []).map((histMsg) => ({
|
|
67
|
+
message: {
|
|
68
|
+
key: {
|
|
69
|
+
id: histMsg.id,
|
|
70
|
+
fromMe: histMsg.fromMe ?? false,
|
|
71
|
+
remoteJid: conversation.id,
|
|
72
|
+
participant: histMsg.participant
|
|
73
|
+
},
|
|
74
|
+
messageTimestamp: histMsg.timestamp,
|
|
75
|
+
message: histMsg.message
|
|
76
|
+
}
|
|
77
|
+
}))
|
|
78
|
+
}));
|
|
79
|
+
const pushnames = (input.pushnames ?? []).map((entry) => ({
|
|
80
|
+
id: entry.id,
|
|
81
|
+
pushname: entry.pushname
|
|
82
|
+
}));
|
|
83
|
+
const historySync = proto.HistorySync.encode({
|
|
84
|
+
syncType: syncType,
|
|
85
|
+
chunkOrder: input.chunkOrder ?? 0,
|
|
86
|
+
progress: input.progress ?? 100,
|
|
87
|
+
conversations,
|
|
88
|
+
pushnames,
|
|
89
|
+
nctSalt: input.nctSalt
|
|
90
|
+
}).finish();
|
|
91
|
+
const compressed = await deflateAsync(historySync);
|
|
92
|
+
return new Uint8Array(compressed);
|
|
93
|
+
}
|
|
94
|
+
export function buildHistorySyncExternalMessage(input) {
|
|
95
|
+
const syncType = input.syncType ?? proto.Message.HistorySyncType.INITIAL_BOOTSTRAP;
|
|
96
|
+
return {
|
|
97
|
+
protocolMessage: {
|
|
98
|
+
type: proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION,
|
|
99
|
+
historySyncNotification: {
|
|
100
|
+
syncType,
|
|
101
|
+
chunkOrder: input.chunkOrder ?? 0,
|
|
102
|
+
progress: input.progress ?? 100,
|
|
103
|
+
directPath: input.directPath,
|
|
104
|
+
mediaKey: input.mediaKey,
|
|
105
|
+
fileSha256: input.fileSha256,
|
|
106
|
+
fileEncSha256: input.fileEncSha256,
|
|
107
|
+
fileLength: input.fileLength
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Builder for inbound encrypted `<message/>` stanzas. */
|
|
2
|
+
export function buildMessage(input) {
|
|
3
|
+
const attrs = {
|
|
4
|
+
id: input.id,
|
|
5
|
+
from: input.from,
|
|
6
|
+
t: String(input.t ?? Math.floor(Date.now() / 1000)),
|
|
7
|
+
type: input.type ?? 'text'
|
|
8
|
+
};
|
|
9
|
+
if (input.participant !== undefined)
|
|
10
|
+
attrs.participant = input.participant;
|
|
11
|
+
if (input.notify !== undefined)
|
|
12
|
+
attrs.notify = input.notify;
|
|
13
|
+
if (input.offline !== undefined)
|
|
14
|
+
attrs.offline = String(input.offline);
|
|
15
|
+
const children = input.enc.map((enc) => {
|
|
16
|
+
const encAttrs = {
|
|
17
|
+
v: '2',
|
|
18
|
+
type: enc.type
|
|
19
|
+
};
|
|
20
|
+
if (enc.mediatype !== undefined)
|
|
21
|
+
encAttrs.mediatype = enc.mediatype;
|
|
22
|
+
return {
|
|
23
|
+
tag: 'enc',
|
|
24
|
+
attrs: encAttrs,
|
|
25
|
+
content: enc.ciphertext
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
if (input.extraChildren) {
|
|
29
|
+
for (const extra of input.extraChildren) {
|
|
30
|
+
children.push(extra);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
tag: 'message',
|
|
35
|
+
attrs,
|
|
36
|
+
content: children
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Builders for inbound notification stanzas. */
|
|
2
|
+
export function buildNotification(input) {
|
|
3
|
+
const attrs = {
|
|
4
|
+
id: input.id,
|
|
5
|
+
type: input.type,
|
|
6
|
+
from: input.from ?? 's.whatsapp.net',
|
|
7
|
+
...(input.extraAttrs ?? {})
|
|
8
|
+
};
|
|
9
|
+
if (input.t !== undefined)
|
|
10
|
+
attrs.t = String(input.t);
|
|
11
|
+
if (input.participant !== undefined)
|
|
12
|
+
attrs.participant = input.participant;
|
|
13
|
+
return {
|
|
14
|
+
tag: 'notification',
|
|
15
|
+
attrs,
|
|
16
|
+
...(input.content ? { content: input.content } : {})
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function buildGroupNotification(input) {
|
|
20
|
+
// Group notifications use wire type `w:gp2`.
|
|
21
|
+
return buildNotification({
|
|
22
|
+
id: input.id,
|
|
23
|
+
type: 'w:gp2',
|
|
24
|
+
from: input.groupJid,
|
|
25
|
+
participant: input.participant,
|
|
26
|
+
t: input.t,
|
|
27
|
+
content: input.children
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Builder for inbound `<presence/>` stanzas. */
|
|
2
|
+
export function buildIncomingPresence(input) {
|
|
3
|
+
const attrs = {
|
|
4
|
+
from: input.from,
|
|
5
|
+
type: input.type ?? 'available'
|
|
6
|
+
};
|
|
7
|
+
if (input.last !== undefined) {
|
|
8
|
+
attrs.last = typeof input.last === 'number' ? String(input.last) : input.last;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
tag: 'presence',
|
|
12
|
+
attrs
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Builder for inbound `<receipt/>` stanzas. */
|
|
2
|
+
export function buildReceipt(input) {
|
|
3
|
+
const attrs = {
|
|
4
|
+
id: input.id,
|
|
5
|
+
from: input.from
|
|
6
|
+
};
|
|
7
|
+
if (input.type !== undefined && input.type !== 'delivery') {
|
|
8
|
+
attrs.type = input.type;
|
|
9
|
+
}
|
|
10
|
+
if (input.t !== undefined)
|
|
11
|
+
attrs.t = String(input.t);
|
|
12
|
+
if (input.participant !== undefined)
|
|
13
|
+
attrs.participant = input.participant;
|
|
14
|
+
if (input.recipient !== undefined)
|
|
15
|
+
attrs.recipient = input.recipient;
|
|
16
|
+
return {
|
|
17
|
+
tag: 'receipt',
|
|
18
|
+
attrs,
|
|
19
|
+
...(input.content ? { content: input.content } : {})
|
|
20
|
+
};
|
|
21
|
+
}
|