zapo-js 1.4.0 → 1.5.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/dist/appstate/types.d.ts +1 -2
- package/dist/auth/WaAuthClient.d.ts +10 -0
- package/dist/auth/WaAuthClient.js +17 -8
- package/dist/auth/credentials-flow.d.ts +8 -0
- package/dist/auth/credentials-flow.js +35 -2
- package/dist/auth/pairing/companion-host.d.ts +105 -0
- package/dist/auth/pairing/companion-host.js +148 -0
- package/dist/auth/types.d.ts +20 -9
- package/dist/client/WaClient.d.ts +15 -5
- package/dist/client/WaClient.js +46 -12
- package/dist/client/WaClientFactory.d.ts +3 -0
- package/dist/client/WaClientFactory.js +24 -6
- package/dist/client/coordinators/WaAppStateMutationCoordinator.d.ts +8 -0
- package/dist/client/coordinators/WaAppStateMutationCoordinator.js +37 -1
- package/dist/client/coordinators/WaGroupCoordinator.js +6 -1
- package/dist/client/coordinators/WaMessageDispatchCoordinator.d.ts +3 -1
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +13 -3
- package/dist/client/coordinators/WaMobileCoordinator.d.ts +192 -0
- package/dist/client/coordinators/WaMobileCoordinator.js +645 -0
- package/dist/client/messaging/companion-host.d.ts +43 -0
- package/dist/client/messaging/companion-host.js +61 -0
- package/dist/client/messaging/key-protocol.js +25 -1
- package/dist/client/persistence/companion-host.d.ts +36 -0
- package/dist/client/persistence/companion-host.js +57 -0
- package/dist/client/plugins/install.d.ts +2 -1
- package/dist/client/plugins/install.js +44 -11
- package/dist/client/types.d.ts +71 -7
- package/dist/esm/auth/WaAuthClient.js +18 -9
- package/dist/esm/auth/credentials-flow.js +36 -3
- package/dist/esm/auth/pairing/companion-host.js +140 -0
- package/dist/esm/client/WaClient.js +46 -12
- package/dist/esm/client/WaClientFactory.js +25 -7
- package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +37 -1
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +6 -1
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +14 -4
- package/dist/esm/client/coordinators/WaMobileCoordinator.js +641 -0
- package/dist/esm/client/messaging/companion-host.js +56 -0
- package/dist/esm/client/messaging/key-protocol.js +25 -1
- package/dist/esm/client/persistence/companion-host.js +54 -0
- package/dist/esm/client/plugins/install.js +44 -11
- package/dist/esm/index.js +5 -2
- package/dist/esm/message/WaMessageClient.js +3 -2
- package/dist/esm/message/context-info.js +4 -0
- package/dist/esm/protocol/constants.js +4 -3
- package/dist/esm/protocol/device-identity.js +18 -0
- package/dist/esm/protocol/group.js +6 -0
- package/dist/esm/protocol/message.js +12 -0
- package/dist/esm/protocol/nodes.js +15 -1
- package/dist/esm/retry/replay.js +3 -3
- package/dist/esm/signal/attestation/WaAdvSignature.js +67 -2
- package/dist/esm/signal/attestation/constants.js +2 -0
- package/dist/esm/signal/index.js +1 -0
- package/dist/esm/transport/index.js +1 -1
- package/dist/esm/transport/node/builders/group.js +4 -3
- package/dist/esm/transport/node/builders/mobile.js +113 -0
- package/dist/esm/transport/noise/WaClientPayload.js +16 -7
- package/dist/esm/transport/wa-version-fetcher.js +152 -0
- package/dist/esm/util/index.js +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +13 -4
- package/dist/message/WaMessageClient.js +2 -1
- package/dist/message/context-info.d.ts +2 -0
- package/dist/message/context-info.js +5 -0
- package/dist/protocol/constants.d.ts +6 -4
- package/dist/protocol/constants.js +8 -2
- package/dist/protocol/device-identity.d.ts +25 -0
- package/dist/protocol/device-identity.js +21 -0
- package/dist/protocol/group.d.ts +6 -0
- package/dist/protocol/group.js +7 -1
- package/dist/protocol/message.d.ts +14 -0
- package/dist/protocol/message.js +13 -1
- package/dist/protocol/nodes.d.ts +14 -0
- package/dist/protocol/nodes.js +15 -1
- package/dist/retry/replay.js +2 -2
- package/dist/signal/attestation/WaAdvSignature.d.ts +50 -1
- package/dist/signal/attestation/WaAdvSignature.js +71 -1
- package/dist/signal/attestation/constants.d.ts +2 -0
- package/dist/signal/attestation/constants.js +3 -1
- package/dist/signal/index.d.ts +1 -0
- package/dist/signal/index.js +13 -1
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +4 -3
- package/dist/transport/node/builders/group.js +4 -3
- package/dist/transport/node/builders/mobile.d.ts +68 -0
- package/dist/transport/node/builders/mobile.js +120 -0
- package/dist/transport/noise/WaClientPayload.js +16 -7
- package/dist/transport/wa-version-fetcher.d.ts +92 -0
- package/dist/transport/wa-version-fetcher.js +156 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +3 -1
- package/package.json +1 -1
- package/dist/esm/transport/wa-web-version-fetcher.js +0 -91
- package/dist/transport/wa-web-version-fetcher.d.ts +0 -44
- package/dist/transport/wa-web-version-fetcher.js +0 -94
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { promisify } from 'node:util';
|
|
2
|
+
import { deflate } from 'node:zlib';
|
|
3
|
+
import { proto } from '../../proto.js';
|
|
4
|
+
const deflateAsync = promisify(deflate);
|
|
5
|
+
/**
|
|
6
|
+
* Serializes a `HistorySync` and zlib-deflates it. The phone uses DEFLATE
|
|
7
|
+
* level 1; any zlib-framed level inflates identically, so it is only a
|
|
8
|
+
* size/speed tradeoff.
|
|
9
|
+
*/
|
|
10
|
+
export async function encodeHistorySync(content) {
|
|
11
|
+
const serialized = proto.HistorySync.encode(content).finish();
|
|
12
|
+
const compressed = await deflateAsync(serialized, { level: 1 });
|
|
13
|
+
return new Uint8Array(compressed);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a deflated `HistorySync` inline in a `HISTORY_SYNC_NOTIFICATION` protocol
|
|
17
|
+
* message. Only small syncs are inlined; larger ones ride an external
|
|
18
|
+
* `md-msg-hist` MMS blob referenced by the same notification.
|
|
19
|
+
*/
|
|
20
|
+
export function buildInlineHistorySyncNotification(syncType, deflatedPayload, options = {}) {
|
|
21
|
+
return {
|
|
22
|
+
type: proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION,
|
|
23
|
+
historySyncNotification: {
|
|
24
|
+
syncType,
|
|
25
|
+
chunkOrder: options.chunkOrder ?? 0,
|
|
26
|
+
progress: options.progress ?? 100,
|
|
27
|
+
initialHistBootstrapInlinePayload: deflatedPayload
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds the `INITIAL_BOOTSTRAP` `HISTORY_SYNC_NOTIFICATION` a mobile-primary
|
|
33
|
+
* pushes to a freshly-linked companion: a deflated `HistorySync` wrapped in a
|
|
34
|
+
* protocol message for delivery as an encrypted peer message. Note
|
|
35
|
+
* `HistorySync.syncType` and `HistorySyncNotification.syncType` are distinct
|
|
36
|
+
* enum types with shared values, so each field uses its own.
|
|
37
|
+
*/
|
|
38
|
+
export async function buildHistorySyncBootstrapMessage(input = {}) {
|
|
39
|
+
const historySync = {
|
|
40
|
+
syncType: proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP,
|
|
41
|
+
chunkOrder: 0,
|
|
42
|
+
progress: 100,
|
|
43
|
+
conversations: input.conversations ? [...input.conversations] : [],
|
|
44
|
+
pushnames: input.pushnames ? [...input.pushnames] : [],
|
|
45
|
+
phoneNumberToLidMappings: (input.phoneNumberToLidMappings ?? []).map((mapping) => ({
|
|
46
|
+
pnJid: mapping.pnJid,
|
|
47
|
+
lidJid: mapping.lidJid
|
|
48
|
+
})),
|
|
49
|
+
...(input.companionMetaNonce !== undefined
|
|
50
|
+
? { companionMetaNonce: input.companionMetaNonce }
|
|
51
|
+
: {})
|
|
52
|
+
};
|
|
53
|
+
const payload = await encodeHistorySync(historySync);
|
|
54
|
+
const message = buildInlineHistorySyncNotification(proto.Message.HistorySyncType.INITIAL_BOOTSTRAP, payload);
|
|
55
|
+
return { message, payloadBytes: payload.byteLength };
|
|
56
|
+
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { proto } from '../../proto.js';
|
|
2
2
|
import { normalizeDeviceJid } from '../../protocol/jid.js';
|
|
3
3
|
import { bytesToHex } from '../../util/bytes.js';
|
|
4
|
+
/**
|
|
5
|
+
* Valid app-state sync key ids are exactly 6 bytes: a 2-byte device id followed
|
|
6
|
+
* by a 4-byte big-endian epoch (matching the phone primary's `crypto_info`
|
|
7
|
+
* (device_id, epoch) schema and WhatsApp Web's `handleAppStateSyncKeyShare`,
|
|
8
|
+
* which fatally rejects any share whose keyId byte length is not 6). A primary
|
|
9
|
+
* must never emit a malformed key, so legacy/short key ids are dropped from
|
|
10
|
+
* outgoing shares rather than poisoning the peer's syncd engine.
|
|
11
|
+
*/
|
|
12
|
+
const APP_STATE_SYNC_KEY_ID_LENGTH = 6;
|
|
4
13
|
export function createAppStateSyncKeyProtocol(options) {
|
|
5
14
|
const { publishProtocolMessageToDevice, fanoutResolver, getCurrentCredentials, logger } = options;
|
|
6
15
|
const requireCurrentIdentity = (context) => {
|
|
@@ -64,7 +73,12 @@ export function createAppStateSyncKeyProtocol(options) {
|
|
|
64
73
|
const seenKeyIds = new Set();
|
|
65
74
|
const keyShareEntries = [];
|
|
66
75
|
let sharedKeyCount = 0;
|
|
76
|
+
const droppedKeyIds = [];
|
|
67
77
|
for (const key of keys) {
|
|
78
|
+
if (key.keyId.byteLength !== APP_STATE_SYNC_KEY_ID_LENGTH) {
|
|
79
|
+
droppedKeyIds.push(bytesToHex(key.keyId));
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
68
82
|
const keyHex = bytesToHex(key.keyId);
|
|
69
83
|
if (seenKeyIds.has(keyHex)) {
|
|
70
84
|
continue;
|
|
@@ -81,7 +95,10 @@ export function createAppStateSyncKeyProtocol(options) {
|
|
|
81
95
|
});
|
|
82
96
|
}
|
|
83
97
|
for (const keyId of missingKeyIds) {
|
|
84
|
-
if (keyId.byteLength
|
|
98
|
+
if (keyId.byteLength !== APP_STATE_SYNC_KEY_ID_LENGTH) {
|
|
99
|
+
if (keyId.byteLength > 0) {
|
|
100
|
+
droppedKeyIds.push(bytesToHex(keyId));
|
|
101
|
+
}
|
|
85
102
|
continue;
|
|
86
103
|
}
|
|
87
104
|
const keyHex = bytesToHex(keyId);
|
|
@@ -93,6 +110,13 @@ export function createAppStateSyncKeyProtocol(options) {
|
|
|
93
110
|
keyId: { keyId }
|
|
94
111
|
});
|
|
95
112
|
}
|
|
113
|
+
if (droppedKeyIds.length > 0) {
|
|
114
|
+
logger.warn('app-state refusing to share malformed sync keys: keyId byte length must be 6', {
|
|
115
|
+
droppedCount: droppedKeyIds.length,
|
|
116
|
+
totalExpected: keys.length + missingKeyIds.length,
|
|
117
|
+
sample: droppedKeyIds.slice(0, 5)
|
|
118
|
+
});
|
|
119
|
+
}
|
|
96
120
|
const protocolMessage = {
|
|
97
121
|
type: proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE,
|
|
98
122
|
appStateSyncKeyShare: {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { base64ToBytes, bytesToBase64 } from '../../util/bytes.js';
|
|
4
|
+
/**
|
|
5
|
+
* File-backed {@link CompanionHostPersistence}: stores the ADV epoch as JSON at
|
|
6
|
+
* `filePath` (the companion identity keys are base64-encoded). Zero native
|
|
7
|
+
* dependencies - the state is tiny (the epoch header plus the linked-companion
|
|
8
|
+
* list). For a database-backed store, implement the two-method
|
|
9
|
+
* `CompanionHostPersistence` contract directly against your DB; there is no need
|
|
10
|
+
* for a dedicated core store domain.
|
|
11
|
+
*/
|
|
12
|
+
export function createFileCompanionHostPersistence(filePath) {
|
|
13
|
+
return {
|
|
14
|
+
async load() {
|
|
15
|
+
let raw;
|
|
16
|
+
try {
|
|
17
|
+
raw = await readFile(filePath, 'utf8');
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code === 'ENOENT') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
const parsed = JSON.parse(raw);
|
|
26
|
+
return {
|
|
27
|
+
rawId: parsed.rawId,
|
|
28
|
+
currentKeyIndex: parsed.currentKeyIndex,
|
|
29
|
+
companions: parsed.companions.map((companion) => ({
|
|
30
|
+
deviceJid: companion.deviceJid,
|
|
31
|
+
keyIndex: companion.keyIndex,
|
|
32
|
+
companionIdentityPublicKey: base64ToBytes(companion.companionIdentityPublicKey),
|
|
33
|
+
addedAtSeconds: companion.addedAtSeconds
|
|
34
|
+
}))
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
async save(state) {
|
|
38
|
+
const serialized = {
|
|
39
|
+
rawId: state.rawId,
|
|
40
|
+
currentKeyIndex: state.currentKeyIndex,
|
|
41
|
+
companions: state.companions.map((companion) => ({
|
|
42
|
+
deviceJid: companion.deviceJid,
|
|
43
|
+
keyIndex: companion.keyIndex,
|
|
44
|
+
companionIdentityPublicKey: bytesToBase64(companion.companionIdentityPublicKey),
|
|
45
|
+
addedAtSeconds: companion.addedAtSeconds
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
49
|
+
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
50
|
+
await writeFile(tempPath, JSON.stringify(serialized), 'utf8');
|
|
51
|
+
await rename(tempPath, filePath);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
import { isWaClientExposePluginDefinition } from '../plugins/types.js';
|
|
2
2
|
import { toError } from '../../util/primitives.js';
|
|
3
|
+
const PLUGIN_REGISTRY = Symbol('waClientPluginRegistry');
|
|
4
|
+
/**
|
|
5
|
+
* Per-client store for exposed-plugin state that must survive a
|
|
6
|
+
* disconnect/connect cycle. Each `exposeAs` property is defined on the client
|
|
7
|
+
* exactly once (a non-configurable getter reading `instances`); reinstalls
|
|
8
|
+
* only repopulate the slot, so plugins can be torn down on disconnect and
|
|
9
|
+
* rebuilt on the next connect without redefining reserved members.
|
|
10
|
+
*/
|
|
11
|
+
function getPluginRegistry(client) {
|
|
12
|
+
const holder = client;
|
|
13
|
+
const existing = holder[PLUGIN_REGISTRY];
|
|
14
|
+
if (existing) {
|
|
15
|
+
return existing;
|
|
16
|
+
}
|
|
17
|
+
const registry = { instances: new Map(), exposedDefined: new Set() };
|
|
18
|
+
Object.defineProperty(client, PLUGIN_REGISTRY, {
|
|
19
|
+
value: registry,
|
|
20
|
+
enumerable: false,
|
|
21
|
+
configurable: false,
|
|
22
|
+
writable: false
|
|
23
|
+
});
|
|
24
|
+
return registry;
|
|
25
|
+
}
|
|
3
26
|
/**
|
|
4
27
|
* Installs {@link WaClientOptions.plugins} on `client`. Returns a dispose
|
|
5
|
-
* function invoked by {@link WaClient.disconnect}.
|
|
28
|
+
* function invoked by {@link WaClient.disconnect}. Safe to call again after a
|
|
29
|
+
* dispose to reinstall the same plugins on reconnect.
|
|
6
30
|
*/
|
|
7
31
|
export function installWaClientPlugins(client, input, plugins) {
|
|
32
|
+
const registry = getPluginRegistry(client);
|
|
8
33
|
const seenIds = new Set();
|
|
9
34
|
const seenExposeAs = new Set();
|
|
10
35
|
const disposeCallbacks = [];
|
|
@@ -37,24 +62,32 @@ export function installWaClientPlugins(client, input, plugins) {
|
|
|
37
62
|
logger: input.logger.child({ plugin: plugin.id })
|
|
38
63
|
};
|
|
39
64
|
if (isWaClientExposePluginDefinition(plugin)) {
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
const exposeAs = plugin.exposeAs;
|
|
66
|
+
if (seenExposeAs.has(exposeAs)) {
|
|
67
|
+
throw new Error(`duplicate wa client plugin exposeAs: ${exposeAs}`);
|
|
42
68
|
}
|
|
43
|
-
seenExposeAs.add(
|
|
44
|
-
if (
|
|
45
|
-
|
|
69
|
+
seenExposeAs.add(exposeAs);
|
|
70
|
+
if (!registry.exposedDefined.has(exposeAs)) {
|
|
71
|
+
if (exposeAs in client) {
|
|
72
|
+
throw new Error(`wa client plugin exposeAs "${exposeAs}" collides with a reserved client member`);
|
|
73
|
+
}
|
|
74
|
+
registry.exposedDefined.add(exposeAs);
|
|
75
|
+
Object.defineProperty(client, exposeAs, {
|
|
76
|
+
get: () => registry.instances.get(exposeAs),
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: false
|
|
79
|
+
});
|
|
46
80
|
}
|
|
47
81
|
const instance = plugin.setup(pluginCtx);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
configurable: false
|
|
82
|
+
registry.instances.set(exposeAs, instance);
|
|
83
|
+
registerDispose(() => {
|
|
84
|
+
registry.instances.delete(exposeAs);
|
|
52
85
|
});
|
|
53
86
|
if (plugin.dispose) {
|
|
54
87
|
const dispose = plugin.dispose;
|
|
55
88
|
registerDispose(() => dispose(instance, pluginCtx));
|
|
56
89
|
}
|
|
57
|
-
pluginCtx.logger.debug('wa client plugin installed', { exposeAs
|
|
90
|
+
pluginCtx.logger.debug('wa client plugin installed', { exposeAs });
|
|
58
91
|
}
|
|
59
92
|
else {
|
|
60
93
|
plugin.setup(pluginCtx);
|
package/dist/esm/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
export { WaClient } from './client/index.js';
|
|
2
2
|
export { defineWaClientPlugin } from './client/plugins/index.js';
|
|
3
3
|
export { downloadMediaMessage } from './client/media.js';
|
|
4
|
+
export { createFileCompanionHostPersistence } from './client/persistence/companion-host.js';
|
|
4
5
|
export { parseUsyncResultEnvelope } from './transport/node/builders/usync.js';
|
|
5
|
-
export { getContentType, resolveMessageTarget } from './message/encode/content.js';
|
|
6
|
+
export { getContentType, resolveEncMediaType, resolveMessageTarget, unwrapMessage } from './message/encode/content.js';
|
|
7
|
+
export { getContextInfo } from './message/context-info.js';
|
|
6
8
|
export { resolveMediaPayload } from './message/encode/media-payload.js';
|
|
7
9
|
export { unpadPkcs7, writeRandomPadMax16 } from './message/encode/padding.js';
|
|
8
|
-
export { fetchLatestWaWebVersion } from './transport/wa-
|
|
10
|
+
export { fetchLatestWaWebVersion, fetchLatestWaMobileVersion } from './transport/wa-version-fetcher.js';
|
|
9
11
|
export { ConsoleLogger } from './infra/log/ConsoleLogger.js';
|
|
10
12
|
export { PinoLogger, createPinoLogger } from './infra/log/PinoLogger.js';
|
|
11
13
|
export { createNoopLogger } from './infra/log/types.js';
|
|
14
|
+
export { WA_VERSION } from './version-spec.js';
|
|
12
15
|
export { createStore, WaAuthMemoryStore } from './store/index.js';
|
|
13
16
|
export { delay } from './util/async.js';
|
|
14
17
|
export { buildDeviceJid, canonicalizeSignalJid, canonicalizeSignalServer, getLoginIdentity, getWaCompanionPlatformId, getWaMediaHkdfInfo, isBotJid, isBroadcastJid, isGroupJid, isGroupOrBroadcastJid, isHostedDeviceId, isHostedDeviceJid, isHostedServer, isLidJid, isNewsletterJid, isStatusBroadcastJid, isUserJid, normalizeDeviceJid, normalizeRecipientJid, parseJidFull, parsePhoneJid, parseSignalAddressFromJid, signalAddressKey, splitJid, toUserJid, WA_ACCOUNT_SYNC_PROTOCOLS, WA_APP_STATE_COLLECTIONS, WA_APP_STATE_COLLECTION_STATES, WA_APP_STATE_ERROR_CODES, WA_APP_STATE_KDF_INFO, WA_APP_STATE_KEY_TYPES, WA_APP_STATE_SYNC_DATA_TYPE, WA_BROWSERS, WA_BUSINESS_HOURS_DAYS, WA_BUSINESS_HOURS_MODES, WA_COMPANION_PLATFORM_IDS, WA_DEFAULTS, WA_DIRTY_PROTOCOLS, WA_DIRTY_TYPES, WA_DISCONNECT_REASONS, WA_IQ_TYPES, WA_LOGOUT_REASONS, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_MEDIA_HKDF_INFO, WA_NODE_TAGS, WA_PAIRING_KDF_INFO, WA_PREVIEW_MEDIA_HKDF_INFO, WA_READY_STATES, WA_RETRYABLE_ACK_CODES, WA_SIGNALING, WA_STREAM_SIGNALING, WA_SUPPORTED_DIRTY_TYPES, WA_PRIVACY_CATEGORIES, WA_PRIVACY_CATEGORY_TO_SETTING, WA_PRIVACY_DISALLOWED_LIST_CATEGORIES, WA_PRIVACY_SETTING_TO_CATEGORY, WA_PRIVACY_TAGS, WA_PRIVACY_VALUES, WA_XMLNS } from './protocol/index.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describeAckNode, isAckOrReceiptNode, isNegativeAckNode, isRetryableNegativeAck } from './primitives/ack.js';
|
|
2
|
-
import { WA_DEFAULTS, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_NODE_TAGS } from '../protocol/constants.js';
|
|
2
|
+
import { WA_ADDRESSING_MODES, WA_DEFAULTS, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_NODE_TAGS } from '../protocol/constants.js';
|
|
3
3
|
import { buildReceiptNode } from '../transport/node/builders/global.js';
|
|
4
4
|
import { delay } from '../util/async.js';
|
|
5
5
|
import { parseOptionalInt, toError } from '../util/primitives.js';
|
|
@@ -226,7 +226,8 @@ export class WaMessageClient {
|
|
|
226
226
|
}
|
|
227
227
|
extractAckMetadata(ackNode) {
|
|
228
228
|
const addressingModeRaw = ackNode.attrs.addressing_mode;
|
|
229
|
-
const addressingMode = addressingModeRaw ===
|
|
229
|
+
const addressingMode = addressingModeRaw === WA_ADDRESSING_MODES.PN ||
|
|
230
|
+
addressingModeRaw === WA_ADDRESSING_MODES.LID
|
|
230
231
|
? addressingModeRaw
|
|
231
232
|
: undefined;
|
|
232
233
|
return {
|
|
@@ -85,6 +85,10 @@ function pickContextInfoTarget(message) {
|
|
|
85
85
|
}
|
|
86
86
|
return null;
|
|
87
87
|
}
|
|
88
|
+
/** Reads the `contextInfo` off a message's first content submessage (null when absent). */
|
|
89
|
+
export function getContextInfo(message) {
|
|
90
|
+
return pickContextInfoTarget(message)?.contextInfo ?? null;
|
|
91
|
+
}
|
|
88
92
|
export function resolveSendContextInfo(input) {
|
|
89
93
|
const ctx = {
|
|
90
94
|
...(input.contentLevel ?? {}),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export { getWaCompanionPlatformId, WA_BROWSERS, WA_COMPANION_PLATFORM_IDS } from './browser.js';
|
|
1
|
+
export { getWaBrowserDisplayName, getWaCompanionPlatformId, WA_BROWSERS, WA_COMPANION_PLATFORM_IDS } from './browser.js';
|
|
2
|
+
export { resolveWaDeviceIdentity } from './device-identity.js';
|
|
2
3
|
export { WA_SIGNALING, WA_PAIRING_KDF_INFO } from './auth.js';
|
|
3
4
|
export { WA_CONNECTION_REASONS, WA_DISCONNECT_REASONS, WA_FAILURE_REASONS, WA_LOGOUT_REASONS, WA_READY_STATES, WA_STREAM_SIGNALING } from './stream.js';
|
|
4
5
|
export { WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from './nodes.js';
|
|
5
6
|
export { WA_CALL_CHILD_TAGS, WA_CALL_NODE_ATTRS, WA_CALL_PAYLOAD_TAGS, WA_CALL_RECEIPT_PAYLOAD_TAGS } from './call.js';
|
|
6
|
-
export { WA_EDIT_ATTRS, WA_ENC_MEDIA_TYPES, WA_EVENT_META_TYPES, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_NACK_REASONS, WA_POLL_META_TYPES, WA_RETRYABLE_ACK_CODES, WA_STANZA_MSG_TYPES } from './message.js';
|
|
7
|
+
export { WA_ADDRESSING_MODES, WA_EDIT_ATTRS, WA_ENC_CIPHERTEXT_TYPES, WA_ENC_MEDIA_TYPES, WA_EVENT_META_TYPES, WA_MESSAGE_TAGS, WA_MESSAGE_TYPES, WA_NACK_REASONS, WA_POLL_META_TYPES, WA_RETRYABLE_ACK_CODES, WA_STANZA_MSG_TYPES } from './message.js';
|
|
7
8
|
export { WA_APP_STATE_COLLECTIONS, WA_APP_STATE_COLLECTION_STATES, WA_APP_STATE_ERROR_CODES, WA_APP_STATE_KDF_INFO, WA_APP_STATE_KEY_TYPES, WA_APP_STATE_SYNC_DATA_TYPE } from './appstate.js';
|
|
8
9
|
export { getWaMediaHkdfInfo, WA_MEDIA_HKDF_INFO, WA_PREVIEW_MEDIA_HKDF_INFO } from './media.js';
|
|
9
10
|
export { WA_ACCOUNT_SYNC_PROTOCOLS, WA_DIRTY_PROTOCOLS, WA_DIRTY_TYPES, WA_SUPPORTED_DIRTY_TYPES } from './dirty.js';
|
|
@@ -17,6 +18,6 @@ export { WA_BIZ_BOT_TYPES, WA_BOT_DEFAULT_CAPABILITIES, WA_BOT_HKDF_INFO, WA_BOT
|
|
|
17
18
|
export { WA_STATUS_DISTRIBUTION_SETTINGS } from './status.js';
|
|
18
19
|
export { WA_EMAIL_CONTEXTS, WA_EMAIL_ERROR_CODES, WA_EMAIL_LIMITS, WA_EMAIL_TAGS, WA_EMAIL_XMLNS } from './email.js';
|
|
19
20
|
export { AB_PROP_CONFIGS, resolveAbPropNameByCode, WA_ABPROPS_PROTOCOL_VERSION, WA_ABPROPS_REFRESH_BOUNDS } from './abprops.js';
|
|
20
|
-
export { WA_GROUP_PARTICIPANT_TYPES } from './group.js';
|
|
21
|
+
export { WA_GROUP_MEMBERSHIP_ACTION_TAGS, WA_GROUP_PARTICIPANT_TYPES } from './group.js';
|
|
21
22
|
export { WA_USYNC_CONTEXTS, WA_USYNC_DEFAULTS, WA_USYNC_MODES } from './usync.js';
|
|
22
23
|
export { WA_NEWSLETTER_FETCH_KEY_TYPES, WA_NEWSLETTER_MUTE_TYPES, WA_NEWSLETTER_MUTE_VALUES, WA_NEWSLETTER_PICTURE_TYPES, WA_NEWSLETTER_RECEIVE_TYPES, WA_NEWSLETTER_ROLES, WA_NEWSLETTER_SEND_TYPES, WA_NEWSLETTER_STATE_TYPES, WA_NEWSLETTER_VERIFICATION_STATES, WA_NEWSLETTER_VIEW_ROLES } from './newsletter.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getWaCompanionPlatformId } from './browser.js';
|
|
2
|
+
import { WA_DEFAULTS } from './defaults.js';
|
|
3
|
+
import { getRuntimeOsDisplayName } from '../util/runtime.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the device identity from raw options, applying the shared defaults:
|
|
6
|
+
* browser falls back to {@link WA_DEFAULTS}.DEVICE_BROWSER, OS name to the
|
|
7
|
+
* detected runtime OS, and platform id is inferred from the browser. This is
|
|
8
|
+
* the single source of truth used by both the client factory and the auth
|
|
9
|
+
* client so the pairing payload and any analytics/telemetry agree.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveWaDeviceIdentity(options) {
|
|
12
|
+
const browser = options.deviceBrowser ?? WA_DEFAULTS.DEVICE_BROWSER;
|
|
13
|
+
return Object.freeze({
|
|
14
|
+
browser,
|
|
15
|
+
osDisplayName: options.deviceOsDisplayName ?? getRuntimeOsDisplayName(),
|
|
16
|
+
platform: options.devicePlatform ?? getWaCompanionPlatformId(browser)
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -3,3 +3,9 @@ export const WA_GROUP_PARTICIPANT_TYPES = Object.freeze({
|
|
|
3
3
|
ADMIN: 'admin',
|
|
4
4
|
REGULAR: 'participant'
|
|
5
5
|
});
|
|
6
|
+
/** `<membership_requests_action>` child tags for approving/rejecting group join requests. */
|
|
7
|
+
export const WA_GROUP_MEMBERSHIP_ACTION_TAGS = Object.freeze({
|
|
8
|
+
REQUESTS_ACTION: 'membership_requests_action',
|
|
9
|
+
APPROVE: 'approve',
|
|
10
|
+
REJECT: 'reject'
|
|
11
|
+
});
|
|
@@ -5,6 +5,18 @@ export const WA_MESSAGE_TAGS = Object.freeze({
|
|
|
5
5
|
ACK: 'ack',
|
|
6
6
|
ERROR: 'error'
|
|
7
7
|
});
|
|
8
|
+
/** `<enc type>` ciphertext kinds (Signal `msg`/`pkmsg`, group `skmsg`, message-secret `msmsg`). */
|
|
9
|
+
export const WA_ENC_CIPHERTEXT_TYPES = Object.freeze({
|
|
10
|
+
MESSAGE: 'msg',
|
|
11
|
+
PREKEY: 'pkmsg',
|
|
12
|
+
SENDER_KEY: 'skmsg',
|
|
13
|
+
MESSAGE_SECRET: 'msmsg'
|
|
14
|
+
});
|
|
15
|
+
/** `addressing_mode` stanza attr: phone-number vs LID addressing. */
|
|
16
|
+
export const WA_ADDRESSING_MODES = Object.freeze({
|
|
17
|
+
PN: 'pn',
|
|
18
|
+
LID: 'lid'
|
|
19
|
+
});
|
|
8
20
|
export const WA_MESSAGE_TYPES = Object.freeze({
|
|
9
21
|
ENC_VERSION: '2',
|
|
10
22
|
MEDIA_NOTIFY: 'medianotify',
|
|
@@ -10,6 +10,7 @@ export const WA_NODE_TAGS = Object.freeze({
|
|
|
10
10
|
NOTIFICATION: 'notification',
|
|
11
11
|
SUCCESS: 'success',
|
|
12
12
|
INFO_BULLETIN: 'ib',
|
|
13
|
+
OFFLINE: 'offline',
|
|
13
14
|
DIRTY: 'dirty',
|
|
14
15
|
EDGE_ROUTING: 'edge_routing',
|
|
15
16
|
ROUTING_INFO: 'routing_info',
|
|
@@ -80,7 +81,20 @@ export const WA_NODE_TAGS = Object.freeze({
|
|
|
80
81
|
USERNAME: 'username',
|
|
81
82
|
TEXT_STATUS: 'text_status',
|
|
82
83
|
DISAPPEARING_MODE: 'disappearing_mode',
|
|
83
|
-
BUSINESS: 'business'
|
|
84
|
+
BUSINESS: 'business',
|
|
85
|
+
PUB_KEY: 'pub-key',
|
|
86
|
+
KEY_INDEX_LIST: 'key-index-list',
|
|
87
|
+
CLIENT_PROPS: 'client-props',
|
|
88
|
+
PEM: 'pem',
|
|
89
|
+
TTL: 'ttl',
|
|
90
|
+
KEY_ID: 'key_id',
|
|
91
|
+
REMOVE_COMPANION_DEVICE: 'remove-companion-device',
|
|
92
|
+
PRIMARY_IDENTITY_PUB: 'primary_identity_pub',
|
|
93
|
+
COMPANION_IDENTITY_PUBLIC: 'companion_identity_public',
|
|
94
|
+
COMPANION_SERVER_AUTH_KEY_PUB: 'companion_server_auth_key_pub',
|
|
95
|
+
LINK_CODE_PAIRING_WRAPPED_PRIMARY_EPHEMERAL_PUB: 'link_code_pairing_wrapped_primary_ephemeral_pub',
|
|
96
|
+
LINK_CODE_PAIRING_WRAPPED_COMPANION_EPHEMERAL_PUB: 'link_code_pairing_wrapped_companion_ephemeral_pub',
|
|
97
|
+
LINK_CODE_PAIRING_WRAPPED_KEY_BUNDLE: 'link_code_pairing_wrapped_key_bundle'
|
|
84
98
|
});
|
|
85
99
|
export const WA_IQ_TYPES = Object.freeze({
|
|
86
100
|
GET: 'get',
|
package/dist/esm/retry/replay.js
CHANGED
|
@@ -2,7 +2,7 @@ import { injectDeviceListMetadata } from '../message/crypto/icdc.js';
|
|
|
2
2
|
import { wrapDeviceSentMessage } from '../message/encode/device-sent.js';
|
|
3
3
|
import { unpadPkcs7, writeRandomPadMax16 } from '../message/encode/padding.js';
|
|
4
4
|
import { proto } from '../proto.js';
|
|
5
|
-
import { WA_DEFAULTS, WA_NODE_TAGS } from '../protocol/constants.js';
|
|
5
|
+
import { WA_ADDRESSING_MODES, WA_DEFAULTS, WA_NODE_TAGS } from '../protocol/constants.js';
|
|
6
6
|
import { isGroupOrBroadcastJid, isHostedDeviceJid, isStatusBroadcastJid, normalizeDeviceJid, parseJidFull, toUserJid } from '../protocol/jid.js';
|
|
7
7
|
import { decodeRetryReplayPayload } from './codec.js';
|
|
8
8
|
import { decodeBinaryNode } from '../transport/binary/index.js';
|
|
@@ -197,8 +197,8 @@ export class WaRetryReplayService {
|
|
|
197
197
|
addressingMode: isStatus
|
|
198
198
|
? undefined
|
|
199
199
|
: requesterAddress.server === WA_DEFAULTS.LID_SERVER
|
|
200
|
-
?
|
|
201
|
-
:
|
|
200
|
+
? WA_ADDRESSING_MODES.LID
|
|
201
|
+
: WA_ADDRESSING_MODES.PN,
|
|
202
202
|
encType: encrypted.type,
|
|
203
203
|
ciphertext: encrypted.ciphertext,
|
|
204
204
|
retryCount,
|
|
@@ -1,17 +1,82 @@
|
|
|
1
1
|
import { hmacSha256Sign, toRawPubKey, xeddsaSign, xeddsaVerify } from '../../crypto/index.js';
|
|
2
|
-
import { ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, ADV_PREFIX_HOSTED_DEVICE_SIGNATURE } from '../attestation/constants.js';
|
|
2
|
+
import { ADV_PREFIX_ACCOUNT_KEY_INDEX, ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_KEY_INDEX, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, ADV_PREFIX_HOSTED_DEVICE_SIGNATURE } from '../attestation/constants.js';
|
|
3
3
|
import { concatBytes } from '../../util/bytes.js';
|
|
4
|
-
export { ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE } from '../attestation/constants.js';
|
|
4
|
+
export { ADV_PREFIX_ACCOUNT_KEY_INDEX, ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE } from '../attestation/constants.js';
|
|
5
|
+
/**
|
|
6
|
+
* Companion-side check that the primary's account key signed a device identity.
|
|
7
|
+
* Verifies `accountSignature` over `prefix || details || identityPublicKey`
|
|
8
|
+
* against the account signature public key. Inverse of
|
|
9
|
+
* {@link generateDeviceIdentityAccountSignature}.
|
|
10
|
+
*/
|
|
5
11
|
export async function verifyDeviceIdentityAccountSignature(details, accountSignature, identityPublicKey, accountSignatureKey, isHosted = false) {
|
|
6
12
|
const prefix = isHosted ? ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE : ADV_PREFIX_ACCOUNT_SIGNATURE;
|
|
7
13
|
const message = concatBytes([prefix, details, identityPublicKey]);
|
|
8
14
|
return xeddsaVerify(toRawPubKey(accountSignatureKey), message, accountSignature);
|
|
9
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Companion-side signature proving possession of the identity private key after
|
|
18
|
+
* adopting a primary-signed identity. Signs
|
|
19
|
+
* `prefix || details || identityKeyPair.pubKey || accountSignatureKey`, and is
|
|
20
|
+
* verified by the primary via {@link verifyDeviceSignature}.
|
|
21
|
+
*/
|
|
10
22
|
export async function generateDeviceSignature(details, identityKeyPair, accountSignatureKey, isHosted = false) {
|
|
11
23
|
const prefix = isHosted ? ADV_PREFIX_HOSTED_DEVICE_SIGNATURE : ADV_PREFIX_DEVICE_SIGNATURE;
|
|
12
24
|
const message = concatBytes([prefix, details, identityKeyPair.pubKey, accountSignatureKey]);
|
|
13
25
|
return xeddsaSign(identityKeyPair.privKey, message);
|
|
14
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* HMAC-SHA256 over an `ADVSignedDeviceIdentity` (or hosted-prefixed variant)
|
|
29
|
+
* keyed by the shared ADV secret, binding the signed identity to the pairing
|
|
30
|
+
* secret inside `ADVSignedDeviceIdentityHMAC`.
|
|
31
|
+
*/
|
|
15
32
|
export function computeAdvIdentityHmac(secretKey, details) {
|
|
16
33
|
return hmacSha256Sign(secretKey, details);
|
|
17
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Primary-side counterpart to {@link verifyDeviceIdentityAccountSignature}.
|
|
37
|
+
* Signs a companion's `ADVDeviceIdentity` details with the account (primary)
|
|
38
|
+
* identity key so a linking companion can prove the primary authorized this
|
|
39
|
+
* device. The signed message is `prefix || details || companionIdentityPublicKey`.
|
|
40
|
+
*
|
|
41
|
+
* `accountIdentityKeyPair` is the primary's own Signal identity key pair; its
|
|
42
|
+
* public half is what ships as `ADVSignedDeviceIdentity.accountSignatureKey`.
|
|
43
|
+
* Pass `companionIdentityPublicKey` in the exact byte form the companion will
|
|
44
|
+
* present at verification (the value carried in its pairing QR / key bundle).
|
|
45
|
+
*/
|
|
46
|
+
export async function generateDeviceIdentityAccountSignature(details, companionIdentityPublicKey, accountIdentityKeyPair, isHosted = false) {
|
|
47
|
+
const prefix = isHosted ? ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE : ADV_PREFIX_ACCOUNT_SIGNATURE;
|
|
48
|
+
const message = concatBytes([prefix, details, companionIdentityPublicKey]);
|
|
49
|
+
return xeddsaSign(accountIdentityKeyPair.privKey, message);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Primary-side counterpart to {@link generateDeviceSignature}. Verifies the
|
|
53
|
+
* device signature a companion returns after adopting a signed identity, which
|
|
54
|
+
* proves the companion holds the identity private key it registered. The signed
|
|
55
|
+
* message is `prefix || details || companionIdentityPublicKey || accountSignatureKey`.
|
|
56
|
+
*/
|
|
57
|
+
export async function verifyDeviceSignature(details, deviceSignature, companionIdentityPublicKey, accountSignatureKey, isHosted = false) {
|
|
58
|
+
const prefix = isHosted ? ADV_PREFIX_HOSTED_DEVICE_SIGNATURE : ADV_PREFIX_DEVICE_SIGNATURE;
|
|
59
|
+
const message = concatBytes([prefix, details, companionIdentityPublicKey, accountSignatureKey]);
|
|
60
|
+
return xeddsaVerify(toRawPubKey(companionIdentityPublicKey), message, deviceSignature);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Signs an `ADVKeyIndexList` details blob with the account (primary) identity
|
|
64
|
+
* key. A primary republishes this list whenever its companion set changes so
|
|
65
|
+
* every device can validate the current set of key indexes. The signed message
|
|
66
|
+
* is `prefix || keyIndexListDetails`.
|
|
67
|
+
*/
|
|
68
|
+
export async function signKeyIndexList(keyIndexListDetails, accountIdentityKeyPair, isHosted = false) {
|
|
69
|
+
const prefix = isHosted ? ADV_PREFIX_HOSTED_ACCOUNT_KEY_INDEX : ADV_PREFIX_ACCOUNT_KEY_INDEX;
|
|
70
|
+
const message = concatBytes([prefix, keyIndexListDetails]);
|
|
71
|
+
return xeddsaSign(accountIdentityKeyPair.privKey, message);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Verifies an `ADVSignedKeyIndexList` account signature against the primary's
|
|
75
|
+
* account signature key. Inverse of {@link signKeyIndexList}; used by a device
|
|
76
|
+
* to validate a key-index list published by the primary.
|
|
77
|
+
*/
|
|
78
|
+
export async function verifyKeyIndexListSignature(keyIndexListDetails, accountSignature, accountSignatureKey, isHosted = false) {
|
|
79
|
+
const prefix = isHosted ? ADV_PREFIX_HOSTED_ACCOUNT_KEY_INDEX : ADV_PREFIX_ACCOUNT_KEY_INDEX;
|
|
80
|
+
const message = concatBytes([prefix, keyIndexListDetails]);
|
|
81
|
+
return xeddsaVerify(toRawPubKey(accountSignatureKey), message, accountSignature);
|
|
82
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export const ADV_PREFIX_ACCOUNT_SIGNATURE = new Uint8Array([6, 0]);
|
|
2
2
|
export const ADV_PREFIX_DEVICE_SIGNATURE = new Uint8Array([6, 1]);
|
|
3
|
+
export const ADV_PREFIX_ACCOUNT_KEY_INDEX = new Uint8Array([6, 2]);
|
|
3
4
|
export const ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE = new Uint8Array([6, 5]);
|
|
4
5
|
export const ADV_PREFIX_HOSTED_DEVICE_SIGNATURE = new Uint8Array([6, 6]);
|
|
6
|
+
export const ADV_PREFIX_HOSTED_ACCOUNT_KEY_INDEX = new Uint8Array([6, 7]);
|
package/dist/esm/signal/index.js
CHANGED
|
@@ -14,3 +14,4 @@ export { SenderKeyManager } from './group/SenderKeyManager.js';
|
|
|
14
14
|
export { createAndStoreInitialKeys } from './registration/utils.js';
|
|
15
15
|
export { SignalProtocol } from './session/SignalProtocol.js';
|
|
16
16
|
export { createSignalSessionResolver } from './session/resolver.js';
|
|
17
|
+
export { ADV_PREFIX_ACCOUNT_KEY_INDEX, ADV_PREFIX_ACCOUNT_SIGNATURE, ADV_PREFIX_DEVICE_SIGNATURE, ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, computeAdvIdentityHmac, generateDeviceIdentityAccountSignature, generateDeviceSignature, signKeyIndexList, verifyDeviceIdentityAccountSignature, verifyDeviceSignature, verifyKeyIndexListSignature } from './attestation/WaAdvSignature.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { decodeBinaryNode, decodeBinaryNodeStanza, encodeBinaryNode, encodeBinaryNodeStanza } from './binary/index.js';
|
|
2
2
|
export { isProxyAgent, isProxyDispatcher, isProxyTransport, toProxyAgent, toProxyDispatcher } from './proxy.js';
|
|
3
|
-
export { fetchLatestWaWebVersion } from './wa-
|
|
3
|
+
export { fetchLatestWaWebVersion, fetchLatestWaMobileVersion } from './wa-version-fetcher.js';
|
|
4
4
|
export { WaComms } from './WaComms.js';
|
|
5
5
|
export { verifyNoiseCertificateChain } from './noise/WaNoiseCert.js';
|
|
6
6
|
export { WaNoiseHandshake } from './noise/WaNoiseHandshake.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WA_DEFAULTS } from '../../../protocol/defaults.js';
|
|
2
|
+
import { WA_GROUP_MEMBERSHIP_ACTION_TAGS } from '../../../protocol/group.js';
|
|
2
3
|
import { WA_IQ_TYPES, WA_XMLNS } from '../../../protocol/nodes.js';
|
|
3
4
|
import { buildIqNode } from '../../node/query.js';
|
|
4
5
|
export function buildCreateGroupIq(input) {
|
|
@@ -76,20 +77,20 @@ export function buildMembershipRequestsActionIq(input) {
|
|
|
76
77
|
const children = [];
|
|
77
78
|
if (approve.length > 0) {
|
|
78
79
|
children.push({
|
|
79
|
-
tag:
|
|
80
|
+
tag: WA_GROUP_MEMBERSHIP_ACTION_TAGS.APPROVE,
|
|
80
81
|
attrs: {},
|
|
81
82
|
content: approve.map((jid) => ({ tag: 'participant', attrs: { jid } }))
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
if (reject.length > 0) {
|
|
85
86
|
children.push({
|
|
86
|
-
tag:
|
|
87
|
+
tag: WA_GROUP_MEMBERSHIP_ACTION_TAGS.REJECT,
|
|
87
88
|
attrs: {},
|
|
88
89
|
content: reject.map((jid) => ({ tag: 'participant', attrs: { jid } }))
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
return buildIqNode(WA_IQ_TYPES.SET, input.groupJid, WA_XMLNS.GROUPS, [
|
|
92
|
-
{ tag:
|
|
93
|
+
{ tag: WA_GROUP_MEMBERSHIP_ACTION_TAGS.REQUESTS_ACTION, attrs: {}, content: children }
|
|
93
94
|
]);
|
|
94
95
|
}
|
|
95
96
|
export function buildCancelMembershipRequestsIq(input) {
|