@nerxa/socketon 0.0.0-stage → 1.21.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/EXPERIMENTAL.md +350 -0
- package/LICENSE +24 -0
- package/README.md +6317 -2
- package/WAProto/index.d.ts +17301 -0
- package/WAProto/index.js +125088 -0
- package/engine-requirements.js +14 -0
- package/package.json +100 -4
- package/src/Defaults/index.d.ts +152 -0
- package/src/Defaults/index.js +164 -0
- package/src/MessageBuilder/bot-signature.d.ts +22 -0
- package/src/MessageBuilder/bot-signature.js +122 -0
- package/src/MessageBuilder/extras.d.ts +449 -0
- package/src/MessageBuilder/extras.js +1356 -0
- package/src/MessageBuilder/index.d.ts +210 -0
- package/src/MessageBuilder/index.js +3594 -0
- package/src/MessageBuilder/metaai.d.ts +438 -0
- package/src/MessageBuilder/metaai.js +890 -0
- package/src/Signal/Group/ciphertext-message.d.ts +9 -0
- package/src/Signal/Group/ciphertext-message.js +11 -0
- package/src/Signal/Group/group-session-builder.d.ts +7 -0
- package/src/Signal/Group/group-session-builder.js +27 -0
- package/src/Signal/Group/group_cipher.d.ts +11 -0
- package/src/Signal/Group/group_cipher.js +78 -0
- package/src/Signal/Group/index.d.ts +11 -0
- package/src/Signal/Group/index.js +11 -0
- package/src/Signal/Group/keyhelper.d.ts +6 -0
- package/src/Signal/Group/keyhelper.js +17 -0
- package/src/Signal/Group/sender-chain-key.d.ts +13 -0
- package/src/Signal/Group/sender-chain-key.js +25 -0
- package/src/Signal/Group/sender-key-distribution-message.d.ts +16 -0
- package/src/Signal/Group/sender-key-distribution-message.js +62 -0
- package/src/Signal/Group/sender-key-message.d.ts +18 -0
- package/src/Signal/Group/sender-key-message.js +65 -0
- package/src/Signal/Group/sender-key-name.d.ts +11 -0
- package/src/Signal/Group/sender-key-name.js +47 -0
- package/src/Signal/Group/sender-key-record.d.ts +12 -0
- package/src/Signal/Group/sender-key-record.js +40 -0
- package/src/Signal/Group/sender-key-state.d.ts +16 -0
- package/src/Signal/Group/sender-key-state.js +83 -0
- package/src/Signal/Group/sender-message-key.d.ts +11 -0
- package/src/Signal/Group/sender-message-key.js +25 -0
- package/src/Signal/libsignal.d.ts +54 -0
- package/src/Signal/libsignal.js +427 -0
- package/src/Signal/lid-mapping.d.ts +20 -0
- package/src/Signal/lid-mapping.js +274 -0
- package/src/Socket/Client/index.d.ts +2 -0
- package/src/Socket/Client/index.js +3 -0
- package/src/Socket/Client/tcp.js +177 -0
- package/src/Socket/Client/types.d.ts +5 -0
- package/src/Socket/Client/types.js +9 -0
- package/src/Socket/Client/websocket.d.ts +12 -0
- package/src/Socket/Client/websocket.js +53 -0
- package/src/Socket/business.d.ts +431 -0
- package/src/Socket/business.js +379 -0
- package/src/Socket/chats.d.ts +247 -0
- package/src/Socket/chats.js +1484 -0
- package/src/Socket/communities.d.ts +598 -0
- package/src/Socket/communities.js +421 -0
- package/src/Socket/email.js +145 -0
- package/src/Socket/groups.d.ts +298 -0
- package/src/Socket/groups.js +339 -0
- package/src/Socket/index.d.ts +581 -0
- package/src/Socket/index.js +37 -0
- package/src/Socket/messages-recv.d.ts +370 -0
- package/src/Socket/messages-recv.js +1864 -0
- package/src/Socket/messages-send.d.ts +390 -0
- package/src/Socket/messages-send.js +1574 -0
- package/src/Socket/mex.d.ts +1 -0
- package/src/Socket/mex.js +44 -0
- package/src/Socket/mobile-builders.js +72 -0
- package/src/Socket/mobile.js +424 -0
- package/src/Socket/newsletter.d.ts +468 -0
- package/src/Socket/newsletter.js +671 -0
- package/src/Socket/socket.d.ts +77 -0
- package/src/Socket/socket.js +1106 -0
- package/src/Store/index.d.ts +3 -0
- package/src/Store/index.js +3 -0
- package/src/Store/make-in-memory-store.d.ts +62 -0
- package/src/Store/make-in-memory-store.js +396 -0
- package/src/Store/make-ordered-dictionary.d.ts +12 -0
- package/src/Store/make-ordered-dictionary.js +78 -0
- package/src/Store/object-repository.d.ts +10 -0
- package/src/Store/object-repository.js +23 -0
- package/src/Types/Auth.d.ts +1 -0
- package/src/Types/Auth.js +1 -0
- package/src/Types/Bussines.d.ts +1 -0
- package/src/Types/Bussines.js +1 -0
- package/src/Types/Call.d.ts +1 -0
- package/src/Types/Call.js +1 -0
- package/src/Types/Chat.d.ts +2 -0
- package/src/Types/Chat.js +24 -0
- package/src/Types/Contact.d.ts +1 -0
- package/src/Types/Contact.js +1 -0
- package/src/Types/Events.d.ts +1 -0
- package/src/Types/Events.js +0 -0
- package/src/Types/GroupMetadata.d.ts +5 -0
- package/src/Types/GroupMetadata.js +6 -0
- package/src/Types/Label.d.ts +2 -0
- package/src/Types/Label.js +24 -0
- package/src/Types/LabelAssociation.d.ts +2 -0
- package/src/Types/LabelAssociation.js +6 -0
- package/src/Types/Message.d.ts +13 -0
- package/src/Types/Message.js +23 -0
- package/src/Types/Mex.d.ts +2 -0
- package/src/Types/Mex.js +95 -0
- package/src/Types/Product.d.ts +1 -0
- package/src/Types/Product.js +1 -0
- package/src/Types/Signal.d.ts +1 -0
- package/src/Types/Signal.js +0 -0
- package/src/Types/Socket.d.ts +1 -0
- package/src/Types/Socket.js +0 -0
- package/src/Types/State.d.ts +5 -0
- package/src/Types/State.js +54 -0
- package/src/Types/USync.d.ts +1 -0
- package/src/Types/USync.js +0 -0
- package/src/Types/index.d.ts +13 -0
- package/src/Types/index.js +25 -0
- package/src/Utils/auth-store.d.ts +29 -0
- package/src/Utils/auth-store.js +76 -0
- package/src/Utils/auth-utils.d.ts +58 -0
- package/src/Utils/auth-utils.js +273 -0
- package/src/Utils/browser-utils.d.ts +9 -0
- package/src/Utils/browser-utils.js +28 -0
- package/src/Utils/business.d.ts +49 -0
- package/src/Utils/business.js +226 -0
- package/src/Utils/chat-utils.d.ts +408 -0
- package/src/Utils/chat-utils.js +846 -0
- package/src/Utils/companion-reg-client-utils.d.ts +4 -0
- package/src/Utils/companion-reg-client-utils.js +39 -0
- package/src/Utils/crypto.d.ts +39 -0
- package/src/Utils/crypto.js +110 -0
- package/src/Utils/decode-wa-message.d.ts +99 -0
- package/src/Utils/decode-wa-message.js +373 -0
- package/src/Utils/event-buffer.d.ts +22 -0
- package/src/Utils/event-buffer.js +624 -0
- package/src/Utils/generics.d.ts +63 -0
- package/src/Utils/generics.js +375 -0
- package/src/Utils/group-metadata-cache.d.ts +4 -0
- package/src/Utils/group-metadata-cache.js +25 -0
- package/src/Utils/history.d.ts +75 -0
- package/src/Utils/history.js +131 -0
- package/src/Utils/html-app.d.ts +19 -0
- package/src/Utils/html-app.js +96 -0
- package/src/Utils/html-multiplayer.d.ts +10 -0
- package/src/Utils/html-multiplayer.js +94 -0
- package/src/Utils/identity-change-handler.d.ts +13 -0
- package/src/Utils/identity-change-handler.js +48 -0
- package/src/Utils/index.d.ts +44 -0
- package/src/Utils/index.js +44 -0
- package/src/Utils/link-preview-metadata.d.ts +47 -0
- package/src/Utils/link-preview-metadata.js +88 -0
- package/src/Utils/link-preview.d.ts +12 -0
- package/src/Utils/link-preview.js +79 -0
- package/src/Utils/logger.d.ts +2 -0
- package/src/Utils/logger.js +2 -0
- package/src/Utils/lt-hash.d.ts +6 -0
- package/src/Utils/lt-hash.js +3 -0
- package/src/Utils/make-mutex.d.ts +6 -0
- package/src/Utils/make-mutex.js +32 -0
- package/src/Utils/message-retry-manager.d.ts +79 -0
- package/src/Utils/message-retry-manager.js +255 -0
- package/src/Utils/messages-media.d.ts +136 -0
- package/src/Utils/messages-media.js +814 -0
- package/src/Utils/messages.d.ts +62 -0
- package/src/Utils/messages.js +2223 -0
- package/src/Utils/mobile-companion-crypto.js +191 -0
- package/src/Utils/modern-messages.d.ts +150 -0
- package/src/Utils/modern-messages.js +496 -0
- package/src/Utils/native-flow.d.ts +11 -0
- package/src/Utils/native-flow.js +115 -0
- package/src/Utils/newsletter-status.d.ts +158 -0
- package/src/Utils/newsletter-status.js +651 -0
- package/src/Utils/noise-handler.d.ts +20 -0
- package/src/Utils/noise-handler.js +200 -0
- package/src/Utils/offline-node-processor.d.ts +9 -0
- package/src/Utils/offline-node-processor.js +33 -0
- package/src/Utils/optional-media.d.ts +3 -0
- package/src/Utils/optional-media.js +45 -0
- package/src/Utils/payment-messages.d.ts +66 -0
- package/src/Utils/payment-messages.js +160 -0
- package/src/Utils/pre-key-manager.d.ts +25 -0
- package/src/Utils/pre-key-manager.js +95 -0
- package/src/Utils/process-message.d.ts +60 -0
- package/src/Utils/process-message.js +688 -0
- package/src/Utils/reporting-utils.d.ts +12 -0
- package/src/Utils/reporting-utils.js +256 -0
- package/src/Utils/scheduled-message.d.ts +51 -0
- package/src/Utils/scheduled-message.js +112 -0
- package/src/Utils/sender-key-memory.d.ts +19 -0
- package/src/Utils/sender-key-memory.js +51 -0
- package/src/Utils/signal.d.ts +82 -0
- package/src/Utils/signal.js +193 -0
- package/src/Utils/stanza-ack.d.ts +16 -0
- package/src/Utils/stanza-ack.js +30 -0
- package/src/Utils/status-stickers.d.ts +127 -0
- package/src/Utils/status-stickers.js +260 -0
- package/src/Utils/sync-action-utils.d.ts +2 -0
- package/src/Utils/sync-action-utils.js +44 -0
- package/src/Utils/tc-token-utils.d.ts +29 -0
- package/src/Utils/tc-token-utils.js +155 -0
- package/src/Utils/ttl-cache.d.ts +28 -0
- package/src/Utils/ttl-cache.js +120 -0
- package/src/Utils/use-mongo-auth-state.d.ts +21 -0
- package/src/Utils/use-mongo-auth-state.js +67 -0
- package/src/Utils/use-multi-file-auth-state.d.ts +11 -0
- package/src/Utils/use-multi-file-auth-state.js +106 -0
- package/src/Utils/use-mysql-auth-state.d.ts +19 -0
- package/src/Utils/use-mysql-auth-state.js +79 -0
- package/src/Utils/use-postgres-auth-state.d.ts +19 -0
- package/src/Utils/use-postgres-auth-state.js +79 -0
- package/src/Utils/use-redis-auth-state.d.ts +19 -0
- package/src/Utils/use-redis-auth-state.js +89 -0
- package/src/Utils/use-single-file-auth-state.d.ts +10 -0
- package/src/Utils/use-single-file-auth-state.js +108 -0
- package/src/Utils/use-sqlite-auth-state.d.ts +12 -0
- package/src/Utils/use-sqlite-auth-state.js +120 -0
- package/src/Utils/useNekoDBAuth.d.ts +19 -0
- package/src/Utils/useNekoDBAuth.js +111 -0
- package/src/Utils/username.d.ts +12 -0
- package/src/Utils/username.js +58 -0
- package/src/Utils/validate-connection.d.ts +43 -0
- package/src/Utils/validate-connection.js +277 -0
- package/src/Utils/voice-recognition.d.ts +53 -0
- package/src/Utils/voice-recognition.js +219 -0
- package/src/Voip/audio-feeder.d.ts +24 -0
- package/src/Voip/audio-feeder.js +268 -0
- package/src/Voip/index.d.ts +88 -0
- package/src/Voip/index.js +936 -0
- package/src/Voip/relay-transport.d.ts +5 -0
- package/src/Voip/relay-transport.js +824 -0
- package/src/Voip/signaling.d.ts +11 -0
- package/src/Voip/signaling.js +1099 -0
- package/src/Voip/types.d.ts +2 -0
- package/src/Voip/types.js +12 -0
- package/src/Voip/video-feeder.d.ts +24 -0
- package/src/Voip/video-feeder.js +268 -0
- package/src/Voip/wasm-engine.d.ts +26 -0
- package/src/Voip/wasm-engine.js +1307 -0
- package/src/Voip/worker-bootstrap.js +1023 -0
- package/src/WABinary/constants.d.ts +22 -0
- package/src/WABinary/constants.js +1300 -0
- package/src/WABinary/decode.d.ts +9 -0
- package/src/WABinary/decode.js +261 -0
- package/src/WABinary/encode.d.ts +2 -0
- package/src/WABinary/encode.js +219 -0
- package/src/WABinary/generic-utils.d.ts +76 -0
- package/src/WABinary/generic-utils.js +214 -0
- package/src/WABinary/index.d.ts +5 -0
- package/src/WABinary/index.js +5 -0
- package/src/WABinary/jid-utils.d.ts +30 -0
- package/src/WABinary/jid-utils.js +97 -0
- package/src/WABinary/types.d.ts +1 -0
- package/src/WABinary/types.js +0 -0
- package/src/WAM/BinaryInfo.d.ts +7 -0
- package/src/WAM/BinaryInfo.js +9 -0
- package/src/WAM/constants.d.ts +34926 -0
- package/src/WAM/constants.js +22852 -0
- package/src/WAM/encode.d.ts +1 -0
- package/src/WAM/encode.js +148 -0
- package/src/WAM/index.d.ts +3 -0
- package/src/WAM/index.js +3 -0
- package/src/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
- package/src/WAUSync/Protocols/USyncContactProtocol.js +50 -0
- package/src/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
- package/src/WAUSync/Protocols/USyncDeviceProtocol.js +51 -0
- package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
- package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
- package/src/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
- package/src/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
- package/src/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
- package/src/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
- package/src/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
- package/src/WAUSync/Protocols/UsyncBotProfileProtocol.js +49 -0
- package/src/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
- package/src/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
- package/src/WAUSync/Protocols/index.d.ts +5 -0
- package/src/WAUSync/Protocols/index.js +5 -0
- package/src/WAUSync/USyncQuery.d.ts +20 -0
- package/src/WAUSync/USyncQuery.js +93 -0
- package/src/WAUSync/USyncUser.d.ts +16 -0
- package/src/WAUSync/USyncUser.js +30 -0
- package/src/WAUSync/index.d.ts +3 -0
- package/src/WAUSync/index.js +3 -0
- package/src/assets/wasm/README.md +76 -0
- package/src/assets/wasm/loader.js +5 -0
- package/src/assets/wasm/whatsapp.wasm +0 -0
- package/src/assets/wasm/worker-modules.js +273 -0
- package/src/index.d.ts +43 -0
- package/src/index.js +48 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { KEY_BUNDLE_TYPE } from '../Defaults/index.js';
|
|
2
|
+
import { assertNodeErrorFree, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildUInt, getServerFromDomainType, jidDecode, S_WHATSAPP_NET, WAJIDDomains } from '../WABinary/index.js';
|
|
3
|
+
import { Curve, generateSignalPubKey } from './crypto.js';
|
|
4
|
+
import { encodeBigEndian } from './generics.js';
|
|
5
|
+
function chunk(array, size) {
|
|
6
|
+
const chunks = [];
|
|
7
|
+
for (let i = 0; i < array.length; i += size) {
|
|
8
|
+
chunks.push(array.slice(i, i + size));
|
|
9
|
+
}
|
|
10
|
+
return chunks;
|
|
11
|
+
}
|
|
12
|
+
export const createSignalIdentity = (wid, accountSignatureKey) => {
|
|
13
|
+
return {
|
|
14
|
+
identifier: { name: wid, deviceId: 0 },
|
|
15
|
+
identifierKey: generateSignalPubKey(accountSignatureKey)
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export const getPreKeys = async ({ get }, min, limit) => {
|
|
19
|
+
const idList = [];
|
|
20
|
+
for (let id = min; id < limit; id++) {
|
|
21
|
+
idList.push(id.toString());
|
|
22
|
+
}
|
|
23
|
+
return get('pre-key', idList);
|
|
24
|
+
};
|
|
25
|
+
export const generateOrGetPreKeys = (creds, range) => {
|
|
26
|
+
const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId;
|
|
27
|
+
const remaining = range - avaliable;
|
|
28
|
+
const lastPreKeyId = creds.nextPreKeyId + remaining - 1;
|
|
29
|
+
const newPreKeys = {};
|
|
30
|
+
if (remaining > 0) {
|
|
31
|
+
for (let i = creds.nextPreKeyId; i <= lastPreKeyId; i++) {
|
|
32
|
+
newPreKeys[i] = Curve.generateKeyPair();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
newPreKeys,
|
|
37
|
+
lastPreKeyId,
|
|
38
|
+
preKeysRange: [creds.firstUnuploadedPreKeyId, range]
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export const xmppSignedPreKey = (key) => ({
|
|
42
|
+
tag: 'skey',
|
|
43
|
+
attrs: {},
|
|
44
|
+
content: [
|
|
45
|
+
{ tag: 'id', attrs: {}, content: encodeBigEndian(key.keyId, 3) },
|
|
46
|
+
{ tag: 'value', attrs: {}, content: key.keyPair.public },
|
|
47
|
+
{ tag: 'signature', attrs: {}, content: key.signature }
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
export const xmppPreKey = (pair, id) => ({
|
|
51
|
+
tag: 'key',
|
|
52
|
+
attrs: {},
|
|
53
|
+
content: [
|
|
54
|
+
{ tag: 'id', attrs: {}, content: encodeBigEndian(id, 3) },
|
|
55
|
+
{ tag: 'value', attrs: {}, content: pair.public }
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
const isValidUInt = (n) => typeof n === 'number' && Number.isInteger(n);
|
|
59
|
+
export const extractE2ESessionFromRetryReceipt = (receipt) => {
|
|
60
|
+
const keysNode = getBinaryNodeChild(receipt, 'keys');
|
|
61
|
+
if (!keysNode)
|
|
62
|
+
return null;
|
|
63
|
+
const typeBuf = getBinaryNodeChildBuffer(keysNode, 'type');
|
|
64
|
+
if (!typeBuf || typeBuf.length !== 1 || typeBuf[0] !== KEY_BUNDLE_TYPE[0])
|
|
65
|
+
return null;
|
|
66
|
+
const identity = getBinaryNodeChildBuffer(keysNode, 'identity');
|
|
67
|
+
const skey = getBinaryNodeChild(keysNode, 'skey');
|
|
68
|
+
if (!identity || identity.length !== 32 || !skey)
|
|
69
|
+
return null;
|
|
70
|
+
const registrationId = getBinaryNodeChildUInt(receipt, 'registration', 4);
|
|
71
|
+
if (!isValidUInt(registrationId))
|
|
72
|
+
return null;
|
|
73
|
+
const signedPubKey = getBinaryNodeChildBuffer(skey, 'value');
|
|
74
|
+
const signedSig = getBinaryNodeChildBuffer(skey, 'signature');
|
|
75
|
+
const signedKeyId = getBinaryNodeChildUInt(skey, 'id', 3);
|
|
76
|
+
if (!signedPubKey || signedPubKey.length !== 32 || !signedSig || !isValidUInt(signedKeyId)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const preKeyNode = getBinaryNodeChild(keysNode, 'key');
|
|
80
|
+
let preKey;
|
|
81
|
+
if (preKeyNode) {
|
|
82
|
+
const preKeyPub = getBinaryNodeChildBuffer(preKeyNode, 'value');
|
|
83
|
+
const preKeyId = getBinaryNodeChildUInt(preKeyNode, 'id', 3);
|
|
84
|
+
if (!preKeyPub || preKeyPub.length !== 32 || !isValidUInt(preKeyId)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
preKey = { keyId: preKeyId, publicKey: generateSignalPubKey(preKeyPub) };
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
registrationId,
|
|
91
|
+
identityKey: generateSignalPubKey(identity),
|
|
92
|
+
signedPreKey: {
|
|
93
|
+
keyId: signedKeyId,
|
|
94
|
+
publicKey: generateSignalPubKey(signedPubKey),
|
|
95
|
+
signature: signedSig
|
|
96
|
+
},
|
|
97
|
+
preKey
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export const parseAndInjectE2ESessions = async (node, repository) => {
|
|
101
|
+
const extractKey = (key) => key
|
|
102
|
+
? {
|
|
103
|
+
keyId: getBinaryNodeChildUInt(key, 'id', 3),
|
|
104
|
+
publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')),
|
|
105
|
+
signature: getBinaryNodeChildBuffer(key, 'signature')
|
|
106
|
+
}
|
|
107
|
+
: undefined;
|
|
108
|
+
const nodes = getBinaryNodeChildren(getBinaryNodeChild(node, 'list'), 'user');
|
|
109
|
+
for (const node of nodes) {
|
|
110
|
+
assertNodeErrorFree(node);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const chunkSize = 100;
|
|
114
|
+
const chunks = chunk(nodes, chunkSize);
|
|
115
|
+
for (const nodesChunk of chunks) {
|
|
116
|
+
for (const node of nodesChunk) {
|
|
117
|
+
const signedKey = getBinaryNodeChild(node, 'skey');
|
|
118
|
+
const key = getBinaryNodeChild(node, 'key');
|
|
119
|
+
const identity = getBinaryNodeChildBuffer(node, 'identity');
|
|
120
|
+
const jid = node.attrs.jid;
|
|
121
|
+
const registrationId = getBinaryNodeChildUInt(node, 'registration', 4);
|
|
122
|
+
await repository.injectE2ESession({
|
|
123
|
+
jid,
|
|
124
|
+
session: {
|
|
125
|
+
registrationId: registrationId,
|
|
126
|
+
identityKey: generateSignalPubKey(identity),
|
|
127
|
+
signedPreKey: extractKey(signedKey),
|
|
128
|
+
preKey: extractKey(key)
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
export const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
|
|
135
|
+
const { user: myUser, device: myDevice } = jidDecode(myJid);
|
|
136
|
+
const extracted = [];
|
|
137
|
+
for (const userResult of result) {
|
|
138
|
+
const { devices, id } = userResult;
|
|
139
|
+
const decoded = jidDecode(id), { user, server } = decoded;
|
|
140
|
+
let { domainType } = decoded;
|
|
141
|
+
const deviceList = devices?.deviceList;
|
|
142
|
+
if (!Array.isArray(deviceList))
|
|
143
|
+
continue;
|
|
144
|
+
for (const { id: device, keyIndex, isHosted } of deviceList) {
|
|
145
|
+
if ((!excludeZeroDevices || device !== 0) &&
|
|
146
|
+
((myUser !== user && myLid !== user) || myDevice !== device) &&
|
|
147
|
+
(device === 0 || !!keyIndex)
|
|
148
|
+
) {
|
|
149
|
+
if (isHosted) {
|
|
150
|
+
domainType = domainType === WAJIDDomains.LID ? WAJIDDomains.HOSTED_LID : WAJIDDomains.HOSTED;
|
|
151
|
+
}
|
|
152
|
+
extracted.push({
|
|
153
|
+
user,
|
|
154
|
+
device,
|
|
155
|
+
domainType,
|
|
156
|
+
server: getServerFromDomainType(server, domainType)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return extracted;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const getNextPreKeys = async ({ creds, keys }, count) => {
|
|
165
|
+
const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(creds, count);
|
|
166
|
+
const update = {
|
|
167
|
+
nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
|
|
168
|
+
firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
|
|
169
|
+
};
|
|
170
|
+
await keys.set({ 'pre-key': newPreKeys });
|
|
171
|
+
const preKeys = await getPreKeys(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1]);
|
|
172
|
+
return { update, preKeys };
|
|
173
|
+
};
|
|
174
|
+
export const getNextPreKeysNode = async (state, count) => {
|
|
175
|
+
const { creds } = state;
|
|
176
|
+
const { update, preKeys } = await getNextPreKeys(state, count);
|
|
177
|
+
const node = {
|
|
178
|
+
tag: 'iq',
|
|
179
|
+
attrs: {
|
|
180
|
+
xmlns: 'encrypt',
|
|
181
|
+
type: 'set',
|
|
182
|
+
to: S_WHATSAPP_NET
|
|
183
|
+
},
|
|
184
|
+
content: [
|
|
185
|
+
{ tag: 'registration', attrs: {}, content: encodeBigEndian(creds.registrationId) },
|
|
186
|
+
{ tag: 'type', attrs: {}, content: KEY_BUNDLE_TYPE },
|
|
187
|
+
{ tag: 'identity', attrs: {}, content: creds.signedIdentityKey.public },
|
|
188
|
+
{ tag: 'list', attrs: {}, content: Object.keys(preKeys).map(k => xmppPreKey(preKeys[+k], +k)) },
|
|
189
|
+
xmppSignedPreKey(creds.signedPreKey)
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
return { update, node };
|
|
193
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an ACK stanza for a received node.
|
|
3
|
+
* Pure function -- no I/O, no side effects.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors WhatsApp Web's ACK construction:
|
|
6
|
+
* - WAWebHandleMsgSendAck.sendAck / sendNack
|
|
7
|
+
* - WAWebCreateNackFromStanza.createNackFromStanza
|
|
8
|
+
*/
|
|
9
|
+
export function buildAckStanza(node: any, errorCode: any, meId: any): {
|
|
10
|
+
tag: string;
|
|
11
|
+
attrs: {
|
|
12
|
+
id: any;
|
|
13
|
+
to: any;
|
|
14
|
+
class: any;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
export function buildAckStanza(node, errorCode, meId) {
|
|
3
|
+
const { tag, attrs } = node;
|
|
4
|
+
const stanza = {
|
|
5
|
+
tag: 'ack',
|
|
6
|
+
attrs: {
|
|
7
|
+
id: attrs.id,
|
|
8
|
+
to: attrs.from,
|
|
9
|
+
class: tag
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
if (errorCode) {
|
|
13
|
+
stanza.attrs.error = errorCode.toString();
|
|
14
|
+
}
|
|
15
|
+
if (attrs.participant) {
|
|
16
|
+
stanza.attrs.participant = attrs.participant;
|
|
17
|
+
}
|
|
18
|
+
if (attrs.recipient) {
|
|
19
|
+
stanza.attrs.recipient = attrs.recipient;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (attrs.type) {
|
|
23
|
+
stanza.attrs.type = attrs.type;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (tag === 'message' && meId) {
|
|
27
|
+
stanza.attrs.from = meId;
|
|
28
|
+
}
|
|
29
|
+
return stanza;
|
|
30
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { proto } from '../../WAProto/index.js';
|
|
2
|
+
|
|
3
|
+
export declare const StatusLinkType: Readonly<{
|
|
4
|
+
RASTERIZED_LINK_PREVIEW: 1;
|
|
5
|
+
RASTERIZED_LINK_TRUNCATED: 2;
|
|
6
|
+
RASTERIZED_LINK_FULL_URL: 3;
|
|
7
|
+
}>;
|
|
8
|
+
|
|
9
|
+
export interface StickerArea {
|
|
10
|
+
/** Distance from the left edge, as a fraction of the media width. */
|
|
11
|
+
x: number;
|
|
12
|
+
/** Distance from the top edge, as a fraction of the media height. */
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare const STICKER_DEFAULT_AREA: Readonly<StickerArea>;
|
|
19
|
+
|
|
20
|
+
export declare function stickerArea(area?: StickerArea): proto.IPoint[];
|
|
21
|
+
|
|
22
|
+
export declare function locationSticker(options: {
|
|
23
|
+
latitude: number;
|
|
24
|
+
longitude: number;
|
|
25
|
+
name?: string;
|
|
26
|
+
area?: StickerArea | proto.IPoint[];
|
|
27
|
+
skipConfirmation?: boolean;
|
|
28
|
+
}): proto.IInteractiveAnnotation;
|
|
29
|
+
|
|
30
|
+
export declare function channelSticker(options: {
|
|
31
|
+
jid: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
serverMessageId?: number;
|
|
34
|
+
accessibilityText?: string;
|
|
35
|
+
area?: StickerArea | proto.IPoint[];
|
|
36
|
+
}): proto.IInteractiveAnnotation;
|
|
37
|
+
|
|
38
|
+
export declare function linkSticker(options: {
|
|
39
|
+
url: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
area?: StickerArea | proto.IPoint[];
|
|
42
|
+
linkType?: number;
|
|
43
|
+
}): proto.IInteractiveAnnotation;
|
|
44
|
+
|
|
45
|
+
export declare function musicSticker(options: {
|
|
46
|
+
songId?: string;
|
|
47
|
+
title?: string;
|
|
48
|
+
author?: string;
|
|
49
|
+
mediaId?: string;
|
|
50
|
+
artworkDirectPath?: string;
|
|
51
|
+
artworkSha256?: Buffer | string;
|
|
52
|
+
artworkEncSha256?: Buffer | string;
|
|
53
|
+
artworkMediaKey?: Buffer | string;
|
|
54
|
+
artistAttribution?: string;
|
|
55
|
+
countryBlocklist?: Buffer | string;
|
|
56
|
+
isExplicit?: boolean;
|
|
57
|
+
startTimeMs?: number;
|
|
58
|
+
derivedStartTimeMs?: number;
|
|
59
|
+
durationMs?: number;
|
|
60
|
+
area?: StickerArea | proto.IPoint[];
|
|
61
|
+
}): proto.IInteractiveAnnotation;
|
|
62
|
+
|
|
63
|
+
export declare function messageSticker(options: {
|
|
64
|
+
stanzaId?: string;
|
|
65
|
+
message: proto.IMessage;
|
|
66
|
+
area?: StickerArea | proto.IPoint[];
|
|
67
|
+
}): proto.IInteractiveAnnotation;
|
|
68
|
+
|
|
69
|
+
export declare function normalizeStickers(
|
|
70
|
+
stickers: proto.IInteractiveAnnotation | proto.IInteractiveAnnotation[]
|
|
71
|
+
): proto.InteractiveAnnotation[];
|
|
72
|
+
|
|
73
|
+
export interface ReadSticker {
|
|
74
|
+
kind: 'location' | 'channel' | 'link' | 'music' | 'message' | 'unknown';
|
|
75
|
+
area?: StickerArea;
|
|
76
|
+
location?: proto.ILocation;
|
|
77
|
+
channel?: proto.ContextInfo.IForwardedNewsletterMessageInfo;
|
|
78
|
+
link?: { url?: string; title?: string; linkType?: number };
|
|
79
|
+
music?: { songId?: string; title?: string; author?: string };
|
|
80
|
+
message?: proto.IEmbeddedMessage;
|
|
81
|
+
annotation: proto.IInteractiveAnnotation;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export declare function readStickers(message: any): ReadSticker[];
|
|
85
|
+
|
|
86
|
+
export declare const MusicMessageStyle: Readonly<{ UNKNOWN: 0; VINYL: 1 }>;
|
|
87
|
+
|
|
88
|
+
export interface MusicMessageOptions {
|
|
89
|
+
songId?: string;
|
|
90
|
+
mediaId?: string;
|
|
91
|
+
title?: string;
|
|
92
|
+
author?: string;
|
|
93
|
+
artistAttribution?: string;
|
|
94
|
+
artworkDirectPath?: string;
|
|
95
|
+
artworkSha256?: Buffer | string;
|
|
96
|
+
artworkEncSha256?: Buffer | string;
|
|
97
|
+
artworkMediaKey?: Buffer | string;
|
|
98
|
+
countryBlocklist?: Buffer | string;
|
|
99
|
+
isExplicit?: boolean;
|
|
100
|
+
startTimeMs?: number;
|
|
101
|
+
derivedStartTimeMs?: number;
|
|
102
|
+
durationMs?: number;
|
|
103
|
+
songUri?: string;
|
|
104
|
+
artworkUri?: string;
|
|
105
|
+
style?: number;
|
|
106
|
+
contextInfo?: proto.IContextInfo;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export declare function buildMusicMessage(options?: MusicMessageOptions): proto.Message.IMusicMessage;
|
|
110
|
+
|
|
111
|
+
export declare function readMusicMessage(msg: any): {
|
|
112
|
+
songId?: string;
|
|
113
|
+
mediaId?: string;
|
|
114
|
+
title?: string;
|
|
115
|
+
author?: string;
|
|
116
|
+
artistAttribution?: string;
|
|
117
|
+
isExplicit?: boolean;
|
|
118
|
+
startTimeMs?: number | string;
|
|
119
|
+
durationMs?: number | string;
|
|
120
|
+
songUri?: string;
|
|
121
|
+
artworkUri?: string;
|
|
122
|
+
style?: number;
|
|
123
|
+
embeddedMusic: proto.IEmbeddedMusic;
|
|
124
|
+
} | null;
|
|
125
|
+
|
|
126
|
+
export declare const MUSIC_ALLOWED_HOSTS: readonly string[];
|
|
127
|
+
export declare function isMusicHostAllowed(value?: unknown): boolean;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { proto } from '../../WAProto/index.js'
|
|
2
|
+
|
|
3
|
+
export const StatusLinkType = Object.freeze({
|
|
4
|
+
RASTERIZED_LINK_PREVIEW: 1,
|
|
5
|
+
RASTERIZED_LINK_TRUNCATED: 2,
|
|
6
|
+
RASTERIZED_LINK_FULL_URL: 3
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
export const STICKER_DEFAULT_AREA = Object.freeze({ x: 0.25, y: 0.4, width: 0.5, height: 0.2 })
|
|
10
|
+
|
|
11
|
+
const trimUndefined = (object) => {
|
|
12
|
+
for (const key of Object.keys(object)) {
|
|
13
|
+
if (object[key] === undefined) {
|
|
14
|
+
delete object[key]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return object
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const fraction = (value, name) => {
|
|
21
|
+
const number = Number(value)
|
|
22
|
+
if (!Number.isFinite(number) || number < 0 || number > 1) {
|
|
23
|
+
throw new TypeError(`${name} must be between 0 and 1, the client reads these as a fraction of the media`)
|
|
24
|
+
}
|
|
25
|
+
return number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const stickerArea = ({ x, y, width, height } = STICKER_DEFAULT_AREA) => {
|
|
29
|
+
const left = fraction(x, 'x')
|
|
30
|
+
const top = fraction(y, 'y')
|
|
31
|
+
const right = fraction(left + Number(width), 'x + width')
|
|
32
|
+
const bottom = fraction(top + Number(height), 'y + height')
|
|
33
|
+
if (right <= left || bottom <= top) {
|
|
34
|
+
throw new TypeError('a sticker area needs a positive width and height')
|
|
35
|
+
}
|
|
36
|
+
return [
|
|
37
|
+
{ x: left, y: top },
|
|
38
|
+
{ x: right, y: top },
|
|
39
|
+
{ x: right, y: bottom },
|
|
40
|
+
{ x: left, y: bottom }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const annotation = (area, fields) => ({
|
|
45
|
+
polygonVertices: Array.isArray(area) ? area : stickerArea(area),
|
|
46
|
+
...fields
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
export const locationSticker = ({ latitude, longitude, name, area, skipConfirmation } = {}) => {
|
|
50
|
+
const degreesLatitude = Number(latitude)
|
|
51
|
+
const degreesLongitude = Number(longitude)
|
|
52
|
+
if (!Number.isFinite(degreesLatitude) || !Number.isFinite(degreesLongitude)) {
|
|
53
|
+
throw new TypeError('locationSticker needs a numeric latitude and longitude')
|
|
54
|
+
}
|
|
55
|
+
return annotation(area, {
|
|
56
|
+
location: { degreesLatitude, degreesLongitude, ...(name ? { name } : {}) },
|
|
57
|
+
...(skipConfirmation === undefined ? {} : { shouldSkipConfirmation: !!skipConfirmation })
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const channelSticker = ({ jid, name, serverMessageId = 0, accessibilityText, area } = {}) => {
|
|
62
|
+
if (typeof jid !== 'string' || !jid.endsWith('@newsletter')) {
|
|
63
|
+
throw new TypeError('channelSticker needs the channel jid, the one ending in @newsletter')
|
|
64
|
+
}
|
|
65
|
+
return annotation(area, {
|
|
66
|
+
newsletter: {
|
|
67
|
+
newsletterJid: jid,
|
|
68
|
+
serverMessageId: Number(serverMessageId),
|
|
69
|
+
...(name ? { newsletterName: name } : {}),
|
|
70
|
+
...(accessibilityText ? { accessibilityText } : {})
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const linkSticker = ({ url, title, area, linkType = StatusLinkType.RASTERIZED_LINK_PREVIEW } = {}) => {
|
|
76
|
+
if (typeof url !== 'string' || !url) {
|
|
77
|
+
throw new TypeError('linkSticker needs a url')
|
|
78
|
+
}
|
|
79
|
+
return annotation(area, {
|
|
80
|
+
tapAction: { tapUrl: url, ...(title ? { title } : {}) },
|
|
81
|
+
statusLinkType: linkType
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const musicSticker = ({
|
|
86
|
+
songId,
|
|
87
|
+
title,
|
|
88
|
+
author,
|
|
89
|
+
mediaId,
|
|
90
|
+
artworkDirectPath,
|
|
91
|
+
artworkSha256,
|
|
92
|
+
artworkEncSha256,
|
|
93
|
+
artworkMediaKey,
|
|
94
|
+
artistAttribution,
|
|
95
|
+
countryBlocklist,
|
|
96
|
+
isExplicit,
|
|
97
|
+
startTimeMs = 0,
|
|
98
|
+
derivedStartTimeMs,
|
|
99
|
+
durationMs,
|
|
100
|
+
area
|
|
101
|
+
} = {}) => {
|
|
102
|
+
if (!songId && !mediaId) {
|
|
103
|
+
throw new TypeError('musicSticker needs at least a songId or a musicContentMediaId')
|
|
104
|
+
}
|
|
105
|
+
const bytes = value => (value === undefined ? undefined : Buffer.isBuffer(value) ? value : Buffer.from(value, 'base64'))
|
|
106
|
+
const embeddedMusic = {
|
|
107
|
+
...(songId ? { songId: String(songId) } : {}),
|
|
108
|
+
...(mediaId ? { musicContentMediaId: String(mediaId) } : {}),
|
|
109
|
+
...(title ? { title } : {}),
|
|
110
|
+
...(author ? { author } : {}),
|
|
111
|
+
...(artistAttribution ? { artistAttribution } : {}),
|
|
112
|
+
...(artworkDirectPath ? { artworkDirectPath } : {}),
|
|
113
|
+
...(isExplicit === undefined ? {} : { isExplicit: !!isExplicit }),
|
|
114
|
+
musicSongStartTimeInMs: Number(startTimeMs),
|
|
115
|
+
...(derivedStartTimeMs === undefined ? {} : { derivedContentStartTimeInMs: Number(derivedStartTimeMs) }),
|
|
116
|
+
...(durationMs === undefined ? {} : { overlapDurationInMs: Number(durationMs) })
|
|
117
|
+
}
|
|
118
|
+
for (const [key, value] of [
|
|
119
|
+
['artworkSha256', artworkSha256],
|
|
120
|
+
['artworkEncSha256', artworkEncSha256],
|
|
121
|
+
['artworkMediaKey', artworkMediaKey],
|
|
122
|
+
['countryBlocklist', countryBlocklist]
|
|
123
|
+
]) {
|
|
124
|
+
const buffer = bytes(value)
|
|
125
|
+
if (buffer) {
|
|
126
|
+
embeddedMusic[key] = buffer
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return annotation(area, { embeddedContent: { embeddedMusic } })
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const messageSticker = ({ stanzaId, message, area } = {}) => {
|
|
133
|
+
if (!message) {
|
|
134
|
+
throw new TypeError('messageSticker needs the message it embeds')
|
|
135
|
+
}
|
|
136
|
+
return annotation(area, {
|
|
137
|
+
embeddedContent: { embeddedMessage: { ...(stanzaId ? { stanzaId } : {}), message } }
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const ACTIONS = ['location', 'newsletter', 'embeddedAction', 'tapAction']
|
|
142
|
+
|
|
143
|
+
export const normalizeStickers = (stickers) => {
|
|
144
|
+
const list = Array.isArray(stickers) ? stickers : [stickers]
|
|
145
|
+
return list.filter(Boolean).map((sticker, index) => {
|
|
146
|
+
const vertices = sticker.polygonVertices
|
|
147
|
+
if (!Array.isArray(vertices) || vertices.length !== 4) {
|
|
148
|
+
throw new TypeError(`sticker ${index} needs four polygonVertices, the client reads corner 0 and corner 2`)
|
|
149
|
+
}
|
|
150
|
+
const actions = ACTIONS.filter(name => sticker[name] !== undefined && sticker[name] !== null)
|
|
151
|
+
if (actions.length > 1) {
|
|
152
|
+
throw new TypeError(`sticker ${index} sets ${actions.join(' and ')}, but the client reads only one action per sticker`)
|
|
153
|
+
}
|
|
154
|
+
return proto.InteractiveAnnotation.fromObject(sticker)
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const readStickers = (message) => {
|
|
159
|
+
const media = message?.imageMessage ?? message?.videoMessage ?? message
|
|
160
|
+
const annotations = media?.interactiveAnnotations
|
|
161
|
+
if (!Array.isArray(annotations) || !annotations.length) {
|
|
162
|
+
return []
|
|
163
|
+
}
|
|
164
|
+
return annotations.map(item => {
|
|
165
|
+
const [topLeft, , bottomRight] = item.polygonVertices ?? []
|
|
166
|
+
const music = item.embeddedContent?.embeddedMusic
|
|
167
|
+
return {
|
|
168
|
+
kind: item.location
|
|
169
|
+
? 'location'
|
|
170
|
+
: item.newsletter
|
|
171
|
+
? 'channel'
|
|
172
|
+
: item.tapAction
|
|
173
|
+
? 'link'
|
|
174
|
+
: music
|
|
175
|
+
? 'music'
|
|
176
|
+
: item.embeddedContent?.embeddedMessage
|
|
177
|
+
? 'message'
|
|
178
|
+
: 'unknown',
|
|
179
|
+
area: topLeft && bottomRight
|
|
180
|
+
? { x: topLeft.x, y: topLeft.y, width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y }
|
|
181
|
+
: undefined,
|
|
182
|
+
location: item.location ?? undefined,
|
|
183
|
+
channel: item.newsletter ?? undefined,
|
|
184
|
+
link: item.tapAction ? { url: item.tapAction.tapUrl, title: item.tapAction.title, linkType: item.statusLinkType } : undefined,
|
|
185
|
+
music: music ? { songId: music.songId, title: music.title, author: music.author } : undefined,
|
|
186
|
+
message: item.embeddedContent?.embeddedMessage ?? undefined,
|
|
187
|
+
annotation: item
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const MusicMessageStyle = Object.freeze({ UNKNOWN: 0, VINYL: 1 })
|
|
193
|
+
|
|
194
|
+
export const MUSIC_ALLOWED_HOSTS = Object.freeze([
|
|
195
|
+
'.whatsapp.net',
|
|
196
|
+
'.whatsapp.com',
|
|
197
|
+
'.fbcdn.net',
|
|
198
|
+
'.facebook.com',
|
|
199
|
+
'.instagram.com',
|
|
200
|
+
'.cdninstagram.com'
|
|
201
|
+
])
|
|
202
|
+
|
|
203
|
+
export const isMusicHostAllowed = (value) => {
|
|
204
|
+
let host
|
|
205
|
+
try {
|
|
206
|
+
host = new URL(String(value)).hostname.toLowerCase()
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
211
|
+
return MUSIC_ALLOWED_HOSTS.some(suffix => host.endsWith(suffix) || host === suffix.slice(1))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const assertMusicHost = (value, label) => {
|
|
215
|
+
if (value === undefined) {
|
|
216
|
+
return undefined
|
|
217
|
+
}
|
|
218
|
+
if (!isMusicHostAllowed(value)) {
|
|
219
|
+
throw new TypeError(
|
|
220
|
+
`${label} must be hosted on ${MUSIC_ALLOWED_HOSTS.join(', ')} — the client refuses any other host `
|
|
221
|
+
+ 'and draws nothing. Both uris come from Meta music catalog entries, so carry them over from a '
|
|
222
|
+
+ 'message you received rather than pointing at your own file'
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
return value
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const embeddedMusicOf = (options) => musicSticker(options).embeddedContent.embeddedMusic
|
|
229
|
+
|
|
230
|
+
export const buildMusicMessage = ({ songUri, artworkUri, style = MusicMessageStyle.VINYL, contextInfo, ...music } = {}) =>
|
|
231
|
+
trimUndefined({
|
|
232
|
+
embeddedMusic: embeddedMusicOf(music),
|
|
233
|
+
songUri: assertMusicHost(songUri, 'songUri'),
|
|
234
|
+
artworkUri: assertMusicHost(artworkUri, 'artworkUri'),
|
|
235
|
+
style,
|
|
236
|
+
contextInfo
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
export const readMusicMessage = (msg) => {
|
|
240
|
+
const message = msg?.message ?? msg
|
|
241
|
+
const music = message?.musicMessage
|
|
242
|
+
if (!music) {
|
|
243
|
+
return null
|
|
244
|
+
}
|
|
245
|
+
const embedded = music.embeddedMusic ?? {}
|
|
246
|
+
return {
|
|
247
|
+
songId: embedded.songId,
|
|
248
|
+
mediaId: embedded.musicContentMediaId,
|
|
249
|
+
title: embedded.title,
|
|
250
|
+
author: embedded.author,
|
|
251
|
+
artistAttribution: embedded.artistAttribution,
|
|
252
|
+
isExplicit: embedded.isExplicit,
|
|
253
|
+
startTimeMs: embedded.musicSongStartTimeInMs,
|
|
254
|
+
durationMs: embedded.overlapDurationInMs,
|
|
255
|
+
songUri: music.songUri,
|
|
256
|
+
artworkUri: music.artworkUri,
|
|
257
|
+
style: music.style,
|
|
258
|
+
embeddedMusic: embedded
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isLidUser, isPnUser } from '../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export const processContactAction = (action, id, logger) => {
|
|
4
|
+
const results = [];
|
|
5
|
+
if (!id) {
|
|
6
|
+
logger?.warn({ hasFullName: !!action.fullName, hasLidJid: !!action.lidJid, hasPnJid: !!action.pnJid }, 'contactAction sync: missing id in index');
|
|
7
|
+
return results;
|
|
8
|
+
}
|
|
9
|
+
const lidJid = action.lidJid;
|
|
10
|
+
const idIsPn = isPnUser(id);
|
|
11
|
+
|
|
12
|
+
const phoneNumber = idIsPn ? id : action.pnJid || undefined;
|
|
13
|
+
|
|
14
|
+
results.push({
|
|
15
|
+
event: 'contacts.upsert',
|
|
16
|
+
data: [
|
|
17
|
+
{
|
|
18
|
+
id,
|
|
19
|
+
name: action.fullName || action.firstName || action.username || undefined,
|
|
20
|
+
username: action.username || undefined,
|
|
21
|
+
lid: lidJid || undefined,
|
|
22
|
+
phoneNumber
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (lidJid && isLidUser(lidJid) && idIsPn) {
|
|
28
|
+
results.push({
|
|
29
|
+
event: 'lid-mapping.update',
|
|
30
|
+
data: { lid: lidJid, pn: id }
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return results;
|
|
34
|
+
};
|
|
35
|
+
export const emitSyncActionResults = (ev, results) => {
|
|
36
|
+
for (const result of results) {
|
|
37
|
+
if (result.event === 'contacts.upsert') {
|
|
38
|
+
ev.emit('contacts.upsert', result.data);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
ev.emit('lid-mapping.update', result.data);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|