@zervonex/baileys 0.0.0-stage → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3203 -2
- package/WAProto/WAProtoCompile.js +291 -0
- package/WAProto/fetcher.js +69 -0
- package/WAProto/index.js +88 -0
- package/WAProto/parser.js +313 -0
- package/engine-requirements.js +10 -0
- package/lib/Builders/AIRich.js +590 -0
- package/lib/Builders/base.js +130 -0
- package/lib/Builders/builders.js +448 -0
- package/lib/Builders/index.js +3 -0
- package/lib/Defaults/index.js +225 -0
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/index.js +2 -0
- package/lib/Signal/libsignal.js +523 -0
- package/lib/Signal/lid-mapping.js +283 -0
- package/lib/Socket/Client/index.js +2 -0
- package/lib/Socket/Client/types.js +10 -0
- package/lib/Socket/Client/websocket.js +84 -0
- package/lib/Socket/business.js +152 -0
- package/lib/Socket/chats.js +855 -0
- package/lib/Socket/communities.js +147 -0
- package/lib/Socket/groups.js +294 -0
- package/lib/Socket/index.js +15 -0
- package/lib/Socket/messages-recv.js +904 -0
- package/lib/Socket/messages-send.js +693 -0
- package/lib/Socket/mex.js +34 -0
- package/lib/Socket/newsletter.js +752 -0
- package/lib/Socket/nexus-handler.js +55 -0
- package/lib/Socket/registration.js +155 -0
- package/lib/Socket/socket.js +798 -0
- package/lib/Socket/spam-report.js +65 -0
- package/lib/Socket/username.js +82 -0
- package/lib/Store/index.js +6 -0
- package/lib/Store/make-cache-manager-store.js +81 -0
- package/lib/Store/make-in-memory-store.js +425 -0
- package/lib/Store/make-ordered-dictionary.js +82 -0
- package/lib/Store/object-repository.js +31 -0
- package/lib/Store/reporting-info-store.js +38 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +15 -0
- package/lib/Types/Newsletter.js +100 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +14 -0
- package/lib/Types/State.js +26 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +30 -0
- package/lib/Utils/auth-utils.js +142 -0
- package/lib/Utils/baileys-event-stream.js +33 -0
- package/lib/Utils/bot-capabilities.js +40 -0
- package/lib/Utils/bot-planning-replay.js +44 -0
- package/lib/Utils/browser-utils.js +26 -0
- package/lib/Utils/business.js +75 -0
- package/lib/Utils/chat-utils.js +316 -0
- package/lib/Utils/companion-reg-client-utils.js +20 -0
- package/lib/Utils/consumer-application.js +38 -0
- package/lib/Utils/crypto.js +52 -0
- package/lib/Utils/decode-wa-message.js +197 -0
- package/lib/Utils/event-buffer.js +273 -0
- package/lib/Utils/extras.js +186 -0
- package/lib/Utils/generics.js +195 -0
- package/lib/Utils/history.js +51 -0
- package/lib/Utils/identity-change-handler.js +19 -0
- package/lib/Utils/index.js +39 -0
- package/lib/Utils/key-store.js +3 -0
- package/lib/Utils/link-preview.js +51 -0
- package/lib/Utils/logger.js +2 -0
- package/lib/Utils/lt-hash.js +3 -0
- package/lib/Utils/make-mutex.js +16 -0
- package/lib/Utils/message-composer.js +59 -0
- package/lib/Utils/message-retry-manager.js +48 -0
- package/lib/Utils/messages-media.js +520 -0
- package/lib/Utils/messages.js +742 -0
- package/lib/Utils/meta-ai-msmsg.js +122 -0
- package/lib/Utils/meta-compositing.js +75 -0
- package/lib/Utils/modern-messages.js +235 -0
- package/lib/Utils/native-flow.js +55 -0
- package/lib/Utils/noise-handler.js +161 -0
- package/lib/Utils/pre-key-manager.js +76 -0
- package/lib/Utils/process-message.js +399 -0
- package/lib/Utils/reporting-utils.js +171 -0
- package/lib/Utils/signal.js +167 -0
- package/lib/Utils/spam-report-utils.js +142 -0
- package/lib/Utils/sync-action-utils.js +33 -0
- package/lib/Utils/tc-token-utils.js +102 -0
- package/lib/Utils/use-multi-file-auth-state.js +307 -0
- package/lib/Utils/validate-connection.js +181 -0
- package/lib/WABinary/constants.js +1321 -0
- package/lib/WABinary/decode.js +152 -0
- package/lib/WABinary/encode.js +140 -0
- package/lib/WABinary/generic-utils.js +179 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +235 -0
- package/lib/WABinary/types.js +4 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +3 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +48 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +23 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +28 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +15 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +24 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +9 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +21 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +19 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +19 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +22 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +16 -0
- package/lib/WAUSync/Protocols/index.js +12 -0
- package/lib/WAUSync/USyncQuery.js +100 -0
- package/lib/WAUSync/USyncUser.js +20 -0
- package/lib/WAUSync/index.js +3 -0
- package/lib/index.js +68 -0
- package/package.json +216 -5
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { BinaryInfo } from './BinaryInfo.js';
|
|
2
|
+
import { FLAG_BYTE, FLAG_EVENT, FLAG_EXTENDED, FLAG_FIELD, FLAG_GLOBAL, WEB_EVENTS, WEB_GLOBALS } from './constants.js';
|
|
3
|
+
const getHeaderBitLength = (key) => (key < 256 ? 2 : 3);
|
|
4
|
+
export const encodeWAM = (binaryInfo) => {
|
|
5
|
+
binaryInfo.buffer = [];
|
|
6
|
+
encodeWAMHeader(binaryInfo);
|
|
7
|
+
encodeEvents(binaryInfo);
|
|
8
|
+
const totalSize = binaryInfo.buffer.map(a => a.length).reduce((a, b) => a + b);
|
|
9
|
+
const buffer = Buffer.alloc(totalSize);
|
|
10
|
+
let offset = 0;
|
|
11
|
+
for (const buffer_ of binaryInfo.buffer) {
|
|
12
|
+
buffer_.copy(buffer, offset);
|
|
13
|
+
offset += buffer_.length;
|
|
14
|
+
}
|
|
15
|
+
return buffer;
|
|
16
|
+
};
|
|
17
|
+
function encodeWAMHeader(binaryInfo) {
|
|
18
|
+
const headerBuffer = Buffer.alloc(8); // starting buffer
|
|
19
|
+
headerBuffer.write('WAM', 0, 'utf8');
|
|
20
|
+
headerBuffer.writeUInt8(binaryInfo.protocolVersion, 3);
|
|
21
|
+
headerBuffer.writeUInt8(1, 4); //random flag
|
|
22
|
+
headerBuffer.writeUInt16BE(binaryInfo.sequence, 5);
|
|
23
|
+
headerBuffer.writeUInt8(0, 7); // regular channel
|
|
24
|
+
binaryInfo.buffer.push(headerBuffer);
|
|
25
|
+
}
|
|
26
|
+
function encodeGlobalAttributes(binaryInfo, globals) {
|
|
27
|
+
for (const [key, _value] of Object.entries(globals)) {
|
|
28
|
+
const id = WEB_GLOBALS.find(a => a?.name === key).id;
|
|
29
|
+
let value = _value;
|
|
30
|
+
if (typeof value === 'boolean') {
|
|
31
|
+
value = value ? 1 : 0;
|
|
32
|
+
}
|
|
33
|
+
binaryInfo.buffer.push(serializeData(id, value, FLAG_GLOBAL));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function encodeEvents(binaryInfo) {
|
|
37
|
+
for (const [name, { props, globals }] of binaryInfo.events.map(a => Object.entries(a)[0])) {
|
|
38
|
+
encodeGlobalAttributes(binaryInfo, globals);
|
|
39
|
+
const event = WEB_EVENTS.find(a => a.name === name);
|
|
40
|
+
const props_ = Object.entries(props);
|
|
41
|
+
let extended = false;
|
|
42
|
+
for (const [, value] of props_) {
|
|
43
|
+
extended || (extended = value !== null);
|
|
44
|
+
}
|
|
45
|
+
const eventFlag = extended ? FLAG_EVENT : FLAG_EVENT | FLAG_EXTENDED;
|
|
46
|
+
binaryInfo.buffer.push(serializeData(event.id, -event.weight, eventFlag));
|
|
47
|
+
for (let i = 0; i < props_.length; i++) {
|
|
48
|
+
const [key, _value] = props_[i];
|
|
49
|
+
const id = event.props[key]?.[0];
|
|
50
|
+
extended = i < props_.length - 1;
|
|
51
|
+
let value = _value;
|
|
52
|
+
if (typeof value === 'boolean') {
|
|
53
|
+
value = value ? 1 : 0;
|
|
54
|
+
}
|
|
55
|
+
const fieldFlag = extended ? FLAG_EVENT : FLAG_FIELD | FLAG_EXTENDED;
|
|
56
|
+
binaryInfo.buffer.push(serializeData(id, value, fieldFlag));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function serializeData(key, value, flag) {
|
|
61
|
+
const bufferLength = getHeaderBitLength(key);
|
|
62
|
+
let buffer;
|
|
63
|
+
let offset = 0;
|
|
64
|
+
if (value === null) {
|
|
65
|
+
if (flag === FLAG_GLOBAL) {
|
|
66
|
+
buffer = Buffer.alloc(bufferLength);
|
|
67
|
+
offset = serializeHeader(buffer, offset, key, flag);
|
|
68
|
+
return buffer;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (typeof value === 'number' && Number.isInteger(value)) {
|
|
72
|
+
// is number
|
|
73
|
+
if (value === 0 || value === 1) {
|
|
74
|
+
buffer = Buffer.alloc(bufferLength);
|
|
75
|
+
offset = serializeHeader(buffer, offset, key, flag | ((value + 1) << 4));
|
|
76
|
+
return buffer;
|
|
77
|
+
}
|
|
78
|
+
else if (-128 <= value && value < 128) {
|
|
79
|
+
buffer = Buffer.alloc(bufferLength + 1);
|
|
80
|
+
offset = serializeHeader(buffer, offset, key, flag | (3 << 4));
|
|
81
|
+
buffer.writeInt8(value, offset);
|
|
82
|
+
return buffer;
|
|
83
|
+
}
|
|
84
|
+
else if (-32768 <= value && value < 32768) {
|
|
85
|
+
buffer = Buffer.alloc(bufferLength + 2);
|
|
86
|
+
offset = serializeHeader(buffer, offset, key, flag | (4 << 4));
|
|
87
|
+
buffer.writeInt16LE(value, offset);
|
|
88
|
+
return buffer;
|
|
89
|
+
}
|
|
90
|
+
else if (-2147483648 <= value && value < 2147483648) {
|
|
91
|
+
buffer = Buffer.alloc(bufferLength + 4);
|
|
92
|
+
offset = serializeHeader(buffer, offset, key, flag | (5 << 4));
|
|
93
|
+
buffer.writeInt32LE(value, offset);
|
|
94
|
+
return buffer;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
buffer = Buffer.alloc(bufferLength + 8);
|
|
98
|
+
offset = serializeHeader(buffer, offset, key, flag | (7 << 4));
|
|
99
|
+
buffer.writeDoubleLE(value, offset);
|
|
100
|
+
return buffer;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (typeof value === 'number') {
|
|
104
|
+
// is float
|
|
105
|
+
buffer = Buffer.alloc(bufferLength + 8);
|
|
106
|
+
offset = serializeHeader(buffer, offset, key, flag | (7 << 4));
|
|
107
|
+
buffer.writeDoubleLE(value, offset);
|
|
108
|
+
return buffer;
|
|
109
|
+
}
|
|
110
|
+
else if (typeof value === 'string') {
|
|
111
|
+
// is string
|
|
112
|
+
const utf8Bytes = Buffer.byteLength(value, 'utf8');
|
|
113
|
+
if (utf8Bytes < 256) {
|
|
114
|
+
buffer = Buffer.alloc(bufferLength + 1 + utf8Bytes);
|
|
115
|
+
offset = serializeHeader(buffer, offset, key, flag | (8 << 4));
|
|
116
|
+
buffer.writeUint8(utf8Bytes, offset++);
|
|
117
|
+
}
|
|
118
|
+
else if (utf8Bytes < 65536) {
|
|
119
|
+
buffer = Buffer.alloc(bufferLength + 2 + utf8Bytes);
|
|
120
|
+
offset = serializeHeader(buffer, offset, key, flag | (9 << 4));
|
|
121
|
+
buffer.writeUInt16LE(utf8Bytes, offset);
|
|
122
|
+
offset += 2;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
buffer = Buffer.alloc(bufferLength + 4 + utf8Bytes);
|
|
126
|
+
offset = serializeHeader(buffer, offset, key, flag | (10 << 4));
|
|
127
|
+
buffer.writeUInt32LE(utf8Bytes, offset);
|
|
128
|
+
offset += 4;
|
|
129
|
+
}
|
|
130
|
+
buffer.write(value, offset, 'utf8');
|
|
131
|
+
return buffer;
|
|
132
|
+
}
|
|
133
|
+
throw 'missing';
|
|
134
|
+
}
|
|
135
|
+
function serializeHeader(buffer, offset, key, flag) {
|
|
136
|
+
if (key < 256) {
|
|
137
|
+
buffer.writeUInt8(flag, offset);
|
|
138
|
+
offset += 1;
|
|
139
|
+
buffer.writeUInt8(key, offset);
|
|
140
|
+
offset += 1;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
buffer.writeUInt8(flag | FLAG_BYTE, offset);
|
|
144
|
+
offset += 1;
|
|
145
|
+
buffer.writeUInt16LE(key, offset);
|
|
146
|
+
offset += 2;
|
|
147
|
+
}
|
|
148
|
+
return offset;
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=encode.js.map
|
package/lib/WAM/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncBotProfileProtocol {
|
|
4
|
+
constructor() { this.name = 'bot'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'bot', attrs: {}, content: [{ tag: 'profile', attrs: { v: '1' } }] }; }
|
|
7
|
+
|
|
8
|
+
getUserElement(user) { return { tag: 'bot', attrs: {}, content: [{ tag: 'profile', attrs: { persona_id: user.personaId } }] }; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
const botNode = getBinaryNodeChild(node, 'bot');
|
|
12
|
+
const profile = getBinaryNodeChild(botNode, 'profile');
|
|
13
|
+
const commandsNode = getBinaryNodeChild(profile, 'commands');
|
|
14
|
+
const promptsNode = getBinaryNodeChild(profile, 'prompts');
|
|
15
|
+
const commands = getBinaryNodeChildren(commandsNode, 'command').map(c => ({ name: getBinaryNodeChildString(c, 'name'), description: getBinaryNodeChildString(c, 'description') }));
|
|
16
|
+
const prompts = getBinaryNodeChildren(promptsNode, 'prompt').map(p => `${getBinaryNodeChildString(p, 'emoji')} ${getBinaryNodeChildString(p, 'text')}`);
|
|
17
|
+
return {
|
|
18
|
+
isDefault: !!getBinaryNodeChild(profile, 'default'),
|
|
19
|
+
jid: node.attrs.jid,
|
|
20
|
+
name: getBinaryNodeChildString(profile, 'name'),
|
|
21
|
+
attributes: getBinaryNodeChildString(profile, 'attributes'),
|
|
22
|
+
description: getBinaryNodeChildString(profile, 'description'),
|
|
23
|
+
category: getBinaryNodeChildString(profile, 'category'),
|
|
24
|
+
personaId: profile.attrs['persona_id'],
|
|
25
|
+
commandsDescription: getBinaryNodeChildString(commandsNode, 'description'),
|
|
26
|
+
commands,
|
|
27
|
+
prompts
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { assertNodeErrorFree, getBinaryNodeChild, getBinaryNodeChildren } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncBusinessProtocol {
|
|
4
|
+
constructor(profileVersion = '2') { this.name = 'business'; this.profileVersion = profileVersion; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'business', attrs: {}, content: [{ tag: 'verified_name', attrs: {} }, { tag: 'profile', attrs: { v: this.profileVersion } }] }; }
|
|
7
|
+
|
|
8
|
+
getUserElement(user) {
|
|
9
|
+
const children = [];
|
|
10
|
+
if (user.verifiedNameSerial) children.push({ tag: 'verified_name', attrs: { serial: user.verifiedNameSerial } });
|
|
11
|
+
if (user.businessProfileTag) children.push({ tag: 'profile', attrs: { tag: user.businessProfileTag } });
|
|
12
|
+
return children.length > 0 ? { tag: 'business', attrs: {}, content: children } : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
parser(node) {
|
|
16
|
+
if (node.tag !== 'business') return null;
|
|
17
|
+
assertNodeErrorFree(node);
|
|
18
|
+
const verifiedNameNode = getBinaryNodeChild(node, 'verified_name');
|
|
19
|
+
const profileNode = getBinaryNodeChild(node, 'profile');
|
|
20
|
+
|
|
21
|
+
let businessHours;
|
|
22
|
+
if (profileNode) {
|
|
23
|
+
const bhNode = getBinaryNodeChild(profileNode, 'business_hours');
|
|
24
|
+
if (bhNode) businessHours = { timezone: bhNode.attrs?.timezone ?? null, config: getBinaryNodeChildren(bhNode, 'business_hours_config').map(({ attrs }) => ({ dayOfWeek: attrs?.day_of_week ?? null, openTime: attrs?.open_time ?? null, closeTime: attrs?.close_time ?? null, mode: attrs?.mode ?? null })) };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const addressNode = profileNode ? getBinaryNodeChild(profileNode, 'address') : null;
|
|
28
|
+
const businessAddress = addressNode?.content ? (Buffer.isBuffer(addressNode.content) ? addressNode.content.toString() : String(addressNode.content)) : (profileNode?.attrs?.address ?? null);
|
|
29
|
+
const catalogStatus = profileNode ? { exists: profileNode.attrs?.catalog_exists === 'true' || profileNode.attrs?.catalog_exists === true, sendAll: profileNode.attrs?.catalog_send_all === 'true' || profileNode.attrs?.catalog_send_all === true } : null;
|
|
30
|
+
const cartEnabled = profileNode?.attrs?.cart_enabled !== undefined ? profileNode.attrs.cart_enabled === 'true' || profileNode.attrs.cart_enabled === true : null;
|
|
31
|
+
const webCartEnabled = profileNode?.attrs?.web_cart_enabled !== undefined ? profileNode.attrs.web_cart_enabled === 'true' || profileNode.attrs.web_cart_enabled === true : null;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
verifiedName: verifiedNameNode?.content ?? null,
|
|
35
|
+
verifiedLevel: verifiedNameNode?.attrs?.verified_level ?? null,
|
|
36
|
+
verifiedNameLevel: verifiedNameNode?.attrs?.verified_level ?? null,
|
|
37
|
+
profileTag: profileNode?.attrs?.tag ?? null,
|
|
38
|
+
pnJid: node.attrs?.pn_jid ?? null,
|
|
39
|
+
businessHours: businessHours ?? null,
|
|
40
|
+
businessAddress,
|
|
41
|
+
catalogStatus,
|
|
42
|
+
cartEnabled,
|
|
43
|
+
webCartEnabled,
|
|
44
|
+
webCartOnOff: profileNode?.attrs?.web_cart_on_off ?? null,
|
|
45
|
+
commerceExperience: profileNode?.attrs?.commerce_experience ?? null
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncContactProtocol {
|
|
4
|
+
constructor() { this.name = 'contact'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'contact', attrs: {} }; }
|
|
7
|
+
|
|
8
|
+
getUserElement(user) {
|
|
9
|
+
if (user.phone) return { tag: 'contact', attrs: {}, content: user.phone };
|
|
10
|
+
if (user.username) return { tag: 'contact', attrs: { username: user.username, ...(user.usernameKey ? { pin: user.usernameKey } : {}), ...(user.lid ? { lid: user.lid } : {}) } };
|
|
11
|
+
if (user.type) return { tag: 'contact', attrs: { type: user.type } };
|
|
12
|
+
return { tag: 'contact', attrs: {} };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
parser(node) {
|
|
16
|
+
if (node.tag !== 'contact') return false;
|
|
17
|
+
assertNodeErrorFree(node);
|
|
18
|
+
const inWA = node?.attrs?.type === 'in';
|
|
19
|
+
const restrictionType = node?.attrs?.stella_addressbook_restriction_type;
|
|
20
|
+
if (restrictionType !== undefined) return { inWA, stellaAddressbookRestrictionType: restrictionType };
|
|
21
|
+
return inWA;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { assertNodeErrorFree, getBinaryNodeChild } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncDeviceProtocol {
|
|
4
|
+
constructor() { this.name = 'devices'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'devices', attrs: { version: '2' } }; }
|
|
7
|
+
|
|
8
|
+
getUserElement() { return null; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
const deviceList = [];
|
|
12
|
+
let keyIndex;
|
|
13
|
+
if (node.tag === 'devices') {
|
|
14
|
+
assertNodeErrorFree(node);
|
|
15
|
+
const deviceListNode = getBinaryNodeChild(node, 'device-list');
|
|
16
|
+
const keyIndexNode = getBinaryNodeChild(node, 'key-index-list');
|
|
17
|
+
if (Array.isArray(deviceListNode?.content)) {
|
|
18
|
+
for (const { tag, attrs } of deviceListNode.content) {
|
|
19
|
+
if (tag === 'device') deviceList.push({ id: +attrs.id, keyIndex: +attrs['key-index'], isHosted: attrs['is_hosted'] === 'true' });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (keyIndexNode?.tag === 'key-index-list') {
|
|
23
|
+
keyIndex = { timestamp: +keyIndexNode.attrs['ts'], signedKeyIndex: keyIndexNode?.content, expectedTimestamp: keyIndexNode.attrs['expected_ts'] ? +keyIndexNode.attrs['expected_ts'] : undefined };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { deviceList, keyIndex };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncDisappearingModeProtocol {
|
|
4
|
+
constructor() { this.name = 'disappearing_mode'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'disappearing_mode', attrs: {} }; }
|
|
7
|
+
|
|
8
|
+
getUserElement() { return null; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
if (node.tag !== 'disappearing_mode') return;
|
|
12
|
+
assertNodeErrorFree(node);
|
|
13
|
+
return { duration: +node.attrs.duration, setAt: new Date(+(node.attrs.t || 0) * 1000) };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getBinaryNodeChild } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export const USYNC_FEATURES = ['document', 'encrypt', 'encrypt_blist', 'encrypt_contact', 'encrypt_group_gen2', 'encrypt_image', 'encrypt_location', 'encrypt_url', 'encrypt_v2', 'voip', 'voip_legacy', 'multi_agent', 'bot_eligible'];
|
|
4
|
+
|
|
5
|
+
const CAMEL_MAP = { encrypt_v2: 'encryptV2', voip_legacy: 'voipLegacy', multi_agent: 'multiAgent', bot_eligible: 'botEligible', encrypt_blist: 'encryptBlist', encrypt_contact: 'encryptContact', encrypt_group_gen2: 'encryptGroupGen2', encrypt_image: 'encryptImage', encrypt_location: 'encryptLocation', encrypt_url: 'encryptUrl' };
|
|
6
|
+
|
|
7
|
+
export class USyncFeatureProtocol {
|
|
8
|
+
constructor(features) { this.name = 'feature'; this.features = features?.length ? features : USYNC_FEATURES; }
|
|
9
|
+
|
|
10
|
+
getQueryElement() { return { tag: 'feature', attrs: {}, content: this.features.map(f => ({ tag: f, attrs: {} })) }; }
|
|
11
|
+
|
|
12
|
+
getUserElement() { return null; }
|
|
13
|
+
|
|
14
|
+
parser(node) {
|
|
15
|
+
if (node.tag !== 'feature') return null;
|
|
16
|
+
const errorNode = getBinaryNodeChild(node, 'error');
|
|
17
|
+
if (errorNode) return { errorCode: errorNode.attrs?.code ? +errorNode.attrs.code : undefined, errorText: errorNode.attrs?.text };
|
|
18
|
+
const features = {};
|
|
19
|
+
for (const child of (Array.isArray(node.content) ? node.content : [])) {
|
|
20
|
+
if (child?.attrs && child.attrs.value !== undefined) features[CAMEL_MAP[child.tag] || child.tag] = child.attrs.value;
|
|
21
|
+
}
|
|
22
|
+
return features;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export class USyncLIDProtocol {
|
|
2
|
+
constructor() { this.name = 'lid'; }
|
|
3
|
+
|
|
4
|
+
getQueryElement() { return { tag: 'lid', attrs: {} }; }
|
|
5
|
+
|
|
6
|
+
getUserElement(user) { return user.lid ? { tag: 'lid', attrs: { jid: user.lid } } : null; }
|
|
7
|
+
|
|
8
|
+
parser(node) { return node.tag === 'lid' ? node.attrs.val : null; }
|
|
9
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncPictureProtocol {
|
|
4
|
+
constructor(type = 'image') { this.name = 'picture'; this.type = type; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'picture', attrs: { type: this.type } }; }
|
|
7
|
+
|
|
8
|
+
getUserElement(user) {
|
|
9
|
+
const attrs = {};
|
|
10
|
+
if (user.pictureId != null) attrs.id = String(user.pictureId);
|
|
11
|
+
return Object.keys(attrs).length > 0 ? { tag: 'picture', attrs } : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
parser(node) {
|
|
15
|
+
if (node.tag !== 'picture') return null;
|
|
16
|
+
assertNodeErrorFree(node);
|
|
17
|
+
const id = node.attrs?.id ?? null, directPath = node.attrs?.direct_path ?? null, hash = node.attrs?.hash ?? null;
|
|
18
|
+
if (!id && !directPath) return null;
|
|
19
|
+
return { id, directPath, hash };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncSidelistProtocol {
|
|
4
|
+
constructor(useLidAddressing = true) { this.name = 'sidelist'; this.useLidAddressing = useLidAddressing; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() {
|
|
7
|
+
const attrs = {};
|
|
8
|
+
if (this.useLidAddressing) attrs.addressing_mode = 'lid';
|
|
9
|
+
return { tag: 'sidelist', attrs };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getUserElement(user) { return user.sidelistDelete ? { tag: 'sidelist', attrs: { type: 'delete' } } : null; }
|
|
13
|
+
|
|
14
|
+
parser(node) {
|
|
15
|
+
if (node.tag !== 'sidelist' && node.tag !== 'side_list') return null;
|
|
16
|
+
assertNodeErrorFree(node);
|
|
17
|
+
return { type: node.attrs?.type ?? null };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncStatusProtocol {
|
|
4
|
+
constructor() { this.name = 'status'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'status', attrs: {} }; }
|
|
7
|
+
|
|
8
|
+
getUserElement() { return null; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
if (node.tag !== 'status') return;
|
|
12
|
+
assertNodeErrorFree(node);
|
|
13
|
+
const setAt = new Date(+(node.attrs.t || 0) * 1000);
|
|
14
|
+
let status = node.content?.toString() ?? null;
|
|
15
|
+
if (!status) status = (node.attrs?.code && +node.attrs.code === 401) ? '' : null;
|
|
16
|
+
else if (status.length === 0) status = null;
|
|
17
|
+
return { status, setAt };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { assertNodeErrorFree, getBinaryNodeChild } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncTextStatusProtocol {
|
|
4
|
+
constructor() { this.name = 'text_status'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'text_status', attrs: {} }; }
|
|
7
|
+
|
|
8
|
+
getUserElement() { return null; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
if (node.tag !== 'text_status') return null;
|
|
12
|
+
assertNodeErrorFree(node);
|
|
13
|
+
const lastUpdateTimeSec = node.attrs?.last_update_time ? +node.attrs.last_update_time : 0;
|
|
14
|
+
const ephemeralDurationSec = node.attrs?.ephemeral_duration_sec ? +node.attrs.ephemeral_duration_sec : 0;
|
|
15
|
+
return {
|
|
16
|
+
text: node.attrs?.text ?? null,
|
|
17
|
+
emoji: getBinaryNodeChild(node, 'emoji')?.attrs?.content ?? null,
|
|
18
|
+
setAt: new Date(lastUpdateTimeSec * 1000),
|
|
19
|
+
expiresAt: ephemeralDurationSec > 0 ? new Date((lastUpdateTimeSec + ephemeralDurationSec) * 1000) : null
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
export class USyncUsernameProtocol {
|
|
4
|
+
constructor() { this.name = 'username'; }
|
|
5
|
+
|
|
6
|
+
getQueryElement() { return { tag: 'username', attrs: {} }; }
|
|
7
|
+
|
|
8
|
+
getUserElement(user) { void user; return null; }
|
|
9
|
+
|
|
10
|
+
parser(node) {
|
|
11
|
+
if (node.tag !== 'username') return null;
|
|
12
|
+
assertNodeErrorFree(node);
|
|
13
|
+
const username = node.content != null ? node.content.toString() : null;
|
|
14
|
+
return username && username.length > 0 ? username : null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './USyncDeviceProtocol.js';
|
|
2
|
+
export * from './USyncContactProtocol.js';
|
|
3
|
+
export * from './USyncStatusProtocol.js';
|
|
4
|
+
export * from './USyncDisappearingModeProtocol.js';
|
|
5
|
+
export * from './USyncUsernameProtocol.js';
|
|
6
|
+
export * from './USyncBotProfileProtocol.js';
|
|
7
|
+
export * from './USyncLIDProtocol.js';
|
|
8
|
+
export * from './USyncBusinessProtocol.js';
|
|
9
|
+
export * from './USyncPictureProtocol.js';
|
|
10
|
+
export * from './USyncTextStatusProtocol.js';
|
|
11
|
+
export * from './USyncSidelistProtocol.js';
|
|
12
|
+
export * from './USyncFeatureProtocol.js';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getBinaryNodeChild } from '../WABinary/index.js';
|
|
2
|
+
import { USyncContactProtocol } from './Protocols/USyncContactProtocol.js';
|
|
3
|
+
import { USyncDeviceProtocol } from './Protocols/USyncDeviceProtocol.js';
|
|
4
|
+
import { USyncDisappearingModeProtocol } from './Protocols/USyncDisappearingModeProtocol.js';
|
|
5
|
+
import { USyncStatusProtocol } from './Protocols/USyncStatusProtocol.js';
|
|
6
|
+
import { USyncUsernameProtocol } from './Protocols/USyncUsernameProtocol.js';
|
|
7
|
+
import { USyncBotProfileProtocol } from './Protocols/USyncBotProfileProtocol.js';
|
|
8
|
+
import { USyncLIDProtocol } from './Protocols/USyncLIDProtocol.js';
|
|
9
|
+
import { USyncBusinessProtocol } from './Protocols/USyncBusinessProtocol.js';
|
|
10
|
+
import { USyncPictureProtocol } from './Protocols/USyncPictureProtocol.js';
|
|
11
|
+
import { USyncTextStatusProtocol } from './Protocols/USyncTextStatusProtocol.js';
|
|
12
|
+
import { USyncSidelistProtocol } from './Protocols/USyncSidelistProtocol.js';
|
|
13
|
+
import { USyncFeatureProtocol } from './Protocols/USyncFeatureProtocol.js';
|
|
14
|
+
|
|
15
|
+
export class USyncQuery {
|
|
16
|
+
constructor() { this.protocols = []; this.users = []; this.context = 'interactive'; this.mode = 'query'; }
|
|
17
|
+
|
|
18
|
+
withMode(mode) { this.mode = mode; return this; }
|
|
19
|
+
withContext(context) { this.context = context; return this; }
|
|
20
|
+
withUser(user) { this.users.push(user); return this; }
|
|
21
|
+
|
|
22
|
+
parseUSyncQueryResult(result) {
|
|
23
|
+
if (!result || result.attrs.type !== 'result') return;
|
|
24
|
+
|
|
25
|
+
const protocolMap = Object.fromEntries(this.protocols.map(p => [p.name, p.parser.bind(p)]));
|
|
26
|
+
const queryResult = { errors: {}, refresh: {}, list: [], sideList: [] };
|
|
27
|
+
const usyncNode = getBinaryNodeChild(result, 'usync');
|
|
28
|
+
|
|
29
|
+
// Collect per-protocol errors and refresh hints from the result node
|
|
30
|
+
const resultNode = usyncNode ? getBinaryNodeChild(usyncNode, 'result') : undefined;
|
|
31
|
+
if (resultNode) {
|
|
32
|
+
for (const protocol of this.protocols) {
|
|
33
|
+
const pNode = getBinaryNodeChild(resultNode, protocol.name);
|
|
34
|
+
if (!pNode) continue;
|
|
35
|
+
const errorNode = getBinaryNodeChild(pNode, 'error');
|
|
36
|
+
if (errorNode) queryResult.errors[protocol.name] = { errorCode: errorNode.attrs.code ? +errorNode.attrs.code : undefined, errorText: errorNode.attrs.text, errorBackoff: errorNode.attrs.backoff ? +errorNode.attrs.backoff : undefined };
|
|
37
|
+
else if (pNode.attrs.refresh !== undefined) queryResult.refresh[protocol.name] = +pNode.attrs.refresh;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const parseUserNodes = nodes => nodes.reduce((acc, node) => {
|
|
42
|
+
const id = node?.attrs?.jid;
|
|
43
|
+
if (!id) return acc;
|
|
44
|
+
|
|
45
|
+
// 401/403/405 on the <user> node means blocked-by
|
|
46
|
+
const userErrCode = node.attrs?.error ? parseInt(node.attrs.error, 10) : 0;
|
|
47
|
+
const isBlockedByAttr = userErrCode === 401 || userErrCode === 403 || userErrCode === 405;
|
|
48
|
+
|
|
49
|
+
const data = Array.isArray(node.content)
|
|
50
|
+
? Object.fromEntries(node.content.map(content => {
|
|
51
|
+
const tag = content.tag;
|
|
52
|
+
// Extract privacy token inline without a registered protocol
|
|
53
|
+
if (tag === 'privacy') {
|
|
54
|
+
const tokenNode = getBinaryNodeChild(content, 'token');
|
|
55
|
+
const modeTsNode = getBinaryNodeChild(content, 'mode_ts');
|
|
56
|
+
const tokenVal = tokenNode?.content || content.attrs?.token;
|
|
57
|
+
if (!tokenVal) return ['privacy', null];
|
|
58
|
+
return ['privacy', { token: Buffer.isBuffer(tokenVal) || tokenVal instanceof Uint8Array ? Buffer.from(tokenVal) : tokenVal, modeTs: modeTsNode?.content?.toString?.() || modeTsNode?.attrs?.value || content.attrs?.mode_ts || null }];
|
|
59
|
+
}
|
|
60
|
+
const parser = protocolMap[tag];
|
|
61
|
+
if (!parser) return [tag, null];
|
|
62
|
+
try { return [tag, parser(content)]; }
|
|
63
|
+
catch (err) {
|
|
64
|
+
const code = err?.data ?? err?.output?.payload?.data;
|
|
65
|
+
if (code === 401 || code === 403 || code === 405) return ['isBlockedByContact', true];
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}).filter(([, v]) => v !== null))
|
|
69
|
+
: {};
|
|
70
|
+
|
|
71
|
+
if (isBlockedByAttr) data.isBlockedByContact = true;
|
|
72
|
+
|
|
73
|
+
// Remap snake_case key to camelCase
|
|
74
|
+
if ('disappearing_mode' in data) { data.disappearingMode = data.disappearing_mode; delete data.disappearing_mode; }
|
|
75
|
+
|
|
76
|
+
acc.push({ ...data, id });
|
|
77
|
+
return acc;
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
const listNode = usyncNode ? getBinaryNodeChild(usyncNode, 'list') : undefined;
|
|
81
|
+
const sideListNode = usyncNode ? getBinaryNodeChild(usyncNode, 'side_list') : undefined;
|
|
82
|
+
if (listNode?.content && Array.isArray(listNode.content)) queryResult.list = parseUserNodes(listNode.content);
|
|
83
|
+
if (sideListNode?.content && Array.isArray(sideListNode.content)) queryResult.sideList = parseUserNodes(sideListNode.content);
|
|
84
|
+
|
|
85
|
+
return queryResult;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
withDeviceProtocol() { this.protocols.push(new USyncDeviceProtocol()); return this; }
|
|
89
|
+
withContactProtocol() { this.protocols.push(new USyncContactProtocol()); return this; }
|
|
90
|
+
withStatusProtocol() { this.protocols.push(new USyncStatusProtocol()); return this; }
|
|
91
|
+
withDisappearingModeProtocol() { this.protocols.push(new USyncDisappearingModeProtocol()); return this; }
|
|
92
|
+
withBotProfileProtocol() { this.protocols.push(new USyncBotProfileProtocol()); return this; }
|
|
93
|
+
withLIDProtocol() { this.protocols.push(new USyncLIDProtocol()); return this; }
|
|
94
|
+
withUsernameProtocol() { this.protocols.push(new USyncUsernameProtocol()); return this; }
|
|
95
|
+
withBusinessProtocol(profileVersion) { this.protocols.push(new USyncBusinessProtocol(profileVersion)); return this; }
|
|
96
|
+
withPictureProtocol(type) { this.protocols.push(new USyncPictureProtocol(type)); return this; }
|
|
97
|
+
withTextStatusProtocol() { this.protocols.push(new USyncTextStatusProtocol()); return this; }
|
|
98
|
+
withSidelistProtocol(useLidAddressing) { this.protocols.push(new USyncSidelistProtocol(useLidAddressing)); return this; }
|
|
99
|
+
withFeatureProtocol(features) { this.protocols.push(new USyncFeatureProtocol(features)); return this; }
|
|
100
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class USyncUser {
|
|
2
|
+
withId(id) { this.id = id; return this; }
|
|
3
|
+
withLid(lid) { this.lid = lid; return this; }
|
|
4
|
+
withPhone(phone) { this.phone = phone; return this; }
|
|
5
|
+
withUsername(username) { this.username = username; return this; }
|
|
6
|
+
withUsernameKey(usernameKey) { this.usernameKey = usernameKey; return this; }
|
|
7
|
+
withType(type) { this.type = type; return this; }
|
|
8
|
+
withPersonaId(personaId) { this.personaId = personaId; return this; }
|
|
9
|
+
withPictureId(pictureId) { this.pictureId = pictureId; return this; }
|
|
10
|
+
withTcToken(tcToken) { this.tcToken = tcToken; return this; }
|
|
11
|
+
withPnJid(pnJid) { this.pnJid = pnJid; return this; }
|
|
12
|
+
withDeviceHash(deviceHash) { this.deviceHash = deviceHash; return this; }
|
|
13
|
+
withTs(ts) { this.ts = ts; return this; }
|
|
14
|
+
withExpectedTs(expectedTs) { this.expectedTs = expectedTs; return this; }
|
|
15
|
+
withVerifiedNameSerial(serial) { this.verifiedNameSerial = serial; return this; }
|
|
16
|
+
withBusinessProfileTag(tag) { this.businessProfileTag = tag; return this; }
|
|
17
|
+
withSidelistDelete(del = true) { this.sidelistDelete = del; return this; }
|
|
18
|
+
// At least one addressable field required for a valid usync user
|
|
19
|
+
validate() { return !!(this.id || this.phone || this.username || this.pnJid); }
|
|
20
|
+
}
|