@alannxd/baileys 6.1.4 → 6.1.6
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 +4 -1
- package/README.md +202 -277
- package/lib/Defaults/index.js +1 -1
- package/lib/Socket/graphql.js +716 -0
- package/lib/Socket/index.js +7 -1
- package/lib/Socket/interop.js +463 -0
- package/lib/Socket/messages-send.js +7 -6
- package/lib/Socket/mex.js +51 -39
- package/lib/Socket/newsletter.js +725 -258
- package/lib/Socket/privacy.js +318 -0
- package/lib/Socket/socket.js +143 -17
- package/lib/Socket/username.js +225 -136
- package/lib/Store/make-in-memory-store.js +47 -1
- package/lib/Types/Mex.js +76 -2
- package/lib/Utils/messages-media.js +82 -0
- package/lib/Utils/messages.js +86 -2
- package/lib/Utils/sticker.js +110 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +52 -50
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +55 -52
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +28 -25
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -36
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -23
- package/lib/WAUSync/Protocols/index.js +12 -6
- package/lib/WAUSync/USyncQuery.js +149 -96
- package/lib/WAUSync/USyncUser.js +54 -29
- package/lib/WAUSync/index.js +3 -4
- package/lib/index.js +2 -3
- package/package.json +19 -20
- package/WAProto/fix-import.js +0 -29
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/community.js +0 -392
- package/lib/Socket/dugong.js +0 -637
- package/lib/Socket/registration.js +0 -167
- package/lib/Socket/usync.js +0 -69
- package/lib/Types/Newsletter.js +0 -38
- package/lib/Utils/baileys-event-stream.js +0 -63
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
package/lib/Utils/messages.js
CHANGED
|
@@ -8,7 +8,8 @@ import { WAMessageStatus, WAProto } from '../Types/index.js';
|
|
|
8
8
|
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
|
|
9
9
|
import { sha256 } from './crypto.js';
|
|
10
10
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
11
|
-
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
11
|
+
import { buildZipArchive, downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData, resolveStickerBuffer } from './messages-media.js';
|
|
12
|
+
import { makeSticker } from './sticker.js';
|
|
12
13
|
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
13
14
|
const MIMETYPE_MAP = {
|
|
14
15
|
image: 'image/jpeg',
|
|
@@ -18,6 +19,34 @@ const MIMETYPE_MAP = {
|
|
|
18
19
|
sticker: 'image/webp',
|
|
19
20
|
'product-catalog-image': 'image/jpeg'
|
|
20
21
|
};
|
|
22
|
+
const RAW_PROTO_MESSAGE_KEYS = [
|
|
23
|
+
'conversation', 'senderKeyDistributionMessage', 'imageMessage', 'contactMessage', 'locationMessage',
|
|
24
|
+
'extendedTextMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'call', 'chat', 'protocolMessage',
|
|
25
|
+
'contactsArrayMessage', 'highlyStructuredMessage', 'fastRatchetKeySenderKeyDistributionMessage',
|
|
26
|
+
'sendPaymentMessage', 'liveLocationMessage', 'requestPaymentMessage', 'declinePaymentRequestMessage',
|
|
27
|
+
'cancelPaymentRequestMessage', 'templateMessage', 'stickerMessage', 'groupInviteMessage',
|
|
28
|
+
'templateButtonReplyMessage', 'productMessage', 'deviceSentMessage', 'messageContextInfo', 'listMessage',
|
|
29
|
+
'viewOnceMessage', 'orderMessage', 'listResponseMessage', 'ephemeralMessage', 'invoiceMessage',
|
|
30
|
+
'buttonsMessage', 'buttonsResponseMessage', 'paymentInviteMessage', 'interactiveMessage', 'reactionMessage',
|
|
31
|
+
'stickerSyncRmrMessage', 'interactiveResponseMessage', 'pollCreationMessage', 'pollUpdateMessage',
|
|
32
|
+
'keepInChatMessage', 'documentWithCaptionMessage', 'requestPhoneNumberMessage', 'viewOnceMessageV2',
|
|
33
|
+
'encReactionMessage', 'editedMessage', 'viewOnceMessageV2Extension', 'pollCreationMessageV2',
|
|
34
|
+
'scheduledCallCreationMessage', 'groupMentionedMessage', 'pinInChatMessage', 'pollCreationMessageV3',
|
|
35
|
+
'scheduledCallEditMessage', 'ptvMessage', 'botInvokeMessage', 'callLogMesssage', 'messageHistoryBundle',
|
|
36
|
+
'encCommentMessage', 'bcallMessage', 'lottieStickerMessage', 'eventMessage', 'encEventResponseMessage',
|
|
37
|
+
'commentMessage', 'newsletterAdminInviteMessage', 'placeholderMessage', 'secretEncryptedMessage',
|
|
38
|
+
'albumMessage', 'eventCoverImage', 'stickerPackMessage', 'statusMentionMessage', 'pollResultSnapshotMessage',
|
|
39
|
+
'pollCreationOptionImageMessage', 'associatedChildMessage', 'groupStatusMentionMessage',
|
|
40
|
+
'pollCreationMessageV4', 'statusAddYours', 'groupStatusMessage', 'richResponseMessage',
|
|
41
|
+
'statusNotificationMessage', 'limitSharingMessage', 'botTaskMessage', 'questionMessage',
|
|
42
|
+
'messageHistoryNotice', 'groupStatusMessageV2', 'botForwardedMessage', 'statusQuestionAnswerMessage',
|
|
43
|
+
'questionReplyMessage', 'questionResponseMessage', 'statusQuotedMessage', 'statusStickerInteractionMessage',
|
|
44
|
+
'pollCreationMessageV5', 'newsletterFollowerInviteMessageV2', 'pollResultSnapshotMessageV3',
|
|
45
|
+
'newsletterAdminProfileMessage', 'newsletterAdminProfileMessageV2', 'spoilerMessage',
|
|
46
|
+
'pollCreationMessageV6', 'conditionalRevealMessage', 'pollAddOptionMessage', 'eventInviteMessage',
|
|
47
|
+
'groupRootKeyShare', 'paymentReminderMessage', 'splitPaymentMessage', 'newsletterAdminProfileStatusMessage',
|
|
48
|
+
'rootSecretDistributeMessage'
|
|
49
|
+
];
|
|
21
50
|
const MessageTypeProto = {
|
|
22
51
|
image: WAProto.Message.ImageMessage,
|
|
23
52
|
video: WAProto.Message.VideoMessage,
|
|
@@ -633,6 +662,13 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
633
662
|
}
|
|
634
663
|
})
|
|
635
664
|
}
|
|
665
|
+
else if ('botInvoke' in message && !!message.botInvoke) {
|
|
666
|
+
m = {
|
|
667
|
+
botInvokeMessage: {
|
|
668
|
+
message: message.botInvoke
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
636
672
|
else if (hasNonNullishProperty(message, 'text')) {
|
|
637
673
|
const extContent = { text: message.text };
|
|
638
674
|
let urlInfo = message.linkPreview;
|
|
@@ -845,8 +881,56 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
845
881
|
}
|
|
846
882
|
};
|
|
847
883
|
}
|
|
884
|
+
else if (hasNonNullishProperty(message, 'stickerPacks')) {
|
|
885
|
+
const pack = message.stickerPacks;
|
|
886
|
+
const rawStickers = Array.isArray(pack.stickers) ? pack.stickers : [];
|
|
887
|
+
if (rawStickers.length === 0) {
|
|
888
|
+
throw new Boom('stickerPacks.stickers must have at least one sticker', { statusCode: 400 });
|
|
889
|
+
}
|
|
890
|
+
const stickerBuffers = await Promise.all(rawStickers.map(s => resolveStickerBuffer(s, options.options)));
|
|
891
|
+
const zipEntries = stickerBuffers.map((data, i) => ({ name: `sticker_${i}.webp`, data }));
|
|
892
|
+
const archive = buildZipArchive(zipEntries);
|
|
893
|
+
const packName = pack.name || 'Sticker Pack';
|
|
894
|
+
const captionParts = [];
|
|
895
|
+
if (pack.publisher) captionParts.push(`Publisher: ${pack.publisher}`);
|
|
896
|
+
if (pack.author) captionParts.push(`Author: ${pack.author}`);
|
|
897
|
+
// sent as a plain .zip document through the normal, well-tested upload path
|
|
898
|
+
m = await prepareWAMessageMedia({
|
|
899
|
+
document: archive,
|
|
900
|
+
mimetype: 'application/zip',
|
|
901
|
+
fileName: `${packName}.zip`,
|
|
902
|
+
caption: captionParts.length ? captionParts.join('\n') : undefined
|
|
903
|
+
}, options);
|
|
904
|
+
}
|
|
905
|
+
else if (hasNonNullishProperty(message, 'sticker') && (message.pack || message.author || message.isPrivate || message.premium || message.animated)) {
|
|
906
|
+
const rawBuffer = await resolveStickerBuffer(message.sticker, options.options);
|
|
907
|
+
const finalWebp = await makeSticker(rawBuffer, {
|
|
908
|
+
pack: message.pack || '',
|
|
909
|
+
author: message.author || '',
|
|
910
|
+
emojis: message.emojis || [],
|
|
911
|
+
isPrivate: !!message.isPrivate,
|
|
912
|
+
animated: !!message.animated,
|
|
913
|
+
quality: message.quality || 60
|
|
914
|
+
});
|
|
915
|
+
m = await prepareWAMessageMedia({ sticker: finalWebp }, options);
|
|
916
|
+
if (m.stickerMessage) {
|
|
917
|
+
if (message.premium) {
|
|
918
|
+
m.stickerMessage.premium = typeof message.premium === 'number' ? message.premium : 1;
|
|
919
|
+
}
|
|
920
|
+
if (message.isPrivate) {
|
|
921
|
+
m.stickerMessage.isAvatar = true;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
848
925
|
else {
|
|
849
|
-
|
|
926
|
+
const rawProtoKey = RAW_PROTO_MESSAGE_KEYS.find(k => hasNonNullishProperty(message, k));
|
|
927
|
+
if (rawProtoKey) {
|
|
928
|
+
const built = proto.Message.fromObject({ [rawProtoKey]: message[rawProtoKey] });
|
|
929
|
+
m = { [rawProtoKey]: built[rawProtoKey] };
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
m = await prepareWAMessageMedia(message, options);
|
|
933
|
+
}
|
|
850
934
|
}
|
|
851
935
|
if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
852
936
|
m = { viewOnceMessage: { message: m } };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
|
|
5
|
+
const runFfmpeg = (input, args) => new Promise((resolve, reject) => {
|
|
6
|
+
const proc = spawn('ffmpeg', ['-hide_banner', '-loglevel', 'error', '-i', 'pipe:0', ...args, 'pipe:1'], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
7
|
+
const outChunks = [];
|
|
8
|
+
const errChunks = [];
|
|
9
|
+
proc.stdout.on('data', chunk => outChunks.push(chunk));
|
|
10
|
+
proc.stderr.on('data', chunk => errChunks.push(chunk));
|
|
11
|
+
proc.on('error', err => reject(new Boom(`ffmpeg failed to start: ${err.message}`, { statusCode: 500 })));
|
|
12
|
+
proc.on('close', code => {
|
|
13
|
+
if (code !== 0) {
|
|
14
|
+
reject(new Boom(`ffmpeg exited with code ${code}: ${Buffer.concat(errChunks).toString('utf8').slice(0, 500)}`, { statusCode: 500 }));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
resolve(Buffer.concat(outChunks));
|
|
18
|
+
});
|
|
19
|
+
proc.stdin.on('error', () => { });
|
|
20
|
+
proc.stdin.end(input);
|
|
21
|
+
});
|
|
22
|
+
export const convertToWebp = async (buffer, { animated = false, quality = 60 } = {}) => {
|
|
23
|
+
const scalePad = "scale='min(512,iw)':'min(512,ih)':force_original_aspect_ratio=decrease,format=rgba,pad=512:512:-1:-1:color=#00000000";
|
|
24
|
+
const args = animated
|
|
25
|
+
? ['-vf', `${scalePad},fps=15`, '-loop', '0', '-preset', 'default', '-an', '-vsync', '0', '-vcodec', 'libwebp', '-q:v', String(quality), '-f', 'webp']
|
|
26
|
+
: ['-vf', `${scalePad}`, '-vframes', '1', '-vcodec', 'libwebp', '-q:v', String(quality), '-f', 'webp'];
|
|
27
|
+
return runFfmpeg(buffer, args);
|
|
28
|
+
};
|
|
29
|
+
const readChunks = (buf) => {
|
|
30
|
+
const chunks = [];
|
|
31
|
+
let offset = 12;
|
|
32
|
+
while (offset + 8 <= buf.length) {
|
|
33
|
+
const fourCC = buf.toString('ascii', offset, offset + 4);
|
|
34
|
+
const size = buf.readUInt32LE(offset + 4);
|
|
35
|
+
const dataStart = offset + 8;
|
|
36
|
+
const data = buf.subarray(dataStart, dataStart + size);
|
|
37
|
+
chunks.push({ fourCC, data });
|
|
38
|
+
offset = dataStart + size + (size % 2);
|
|
39
|
+
}
|
|
40
|
+
return chunks;
|
|
41
|
+
};
|
|
42
|
+
const buildChunk = (fourCC, data) => {
|
|
43
|
+
const header = Buffer.alloc(8);
|
|
44
|
+
header.write(fourCC, 0, 4, 'ascii');
|
|
45
|
+
header.writeUInt32LE(data.length, 4);
|
|
46
|
+
const pad = data.length % 2 === 1 ? Buffer.from([0]) : Buffer.alloc(0);
|
|
47
|
+
return Buffer.concat([header, data, pad]);
|
|
48
|
+
};
|
|
49
|
+
const buildExifChunkData = (json) => {
|
|
50
|
+
const header = Buffer.from([0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
|
|
51
|
+
const payload = Buffer.from(JSON.stringify(json), 'utf8');
|
|
52
|
+
header.writeUInt32LE(payload.length, 14);
|
|
53
|
+
return Buffer.concat([header, payload]);
|
|
54
|
+
};
|
|
55
|
+
export const writeExifToWebp = (webpBuffer, { packId, packName = '', publisher = '', emojis = [], isAvatar = false } = {}) => {
|
|
56
|
+
if (webpBuffer.toString('ascii', 0, 4) !== 'RIFF' || webpBuffer.toString('ascii', 8, 12) !== 'WEBP') {
|
|
57
|
+
throw new Boom('writeExifToWebp: not a valid webp buffer', { statusCode: 400 });
|
|
58
|
+
}
|
|
59
|
+
const chunks = readChunks(webpBuffer);
|
|
60
|
+
const exifData = buildExifChunkData({
|
|
61
|
+
'sticker-pack-id': packId || randomUUID(),
|
|
62
|
+
'sticker-pack-name': packName,
|
|
63
|
+
'sticker-pack-publisher': publisher,
|
|
64
|
+
emojis: emojis.length ? emojis : ['🤖'],
|
|
65
|
+
'is-avatar-sticker': isAvatar ? 1 : 0
|
|
66
|
+
});
|
|
67
|
+
let vp8x = chunks.find(c => c.fourCC === 'VP8X');
|
|
68
|
+
const otherChunks = chunks.filter(c => c.fourCC !== 'VP8X' && c.fourCC !== 'EXIF');
|
|
69
|
+
if (!vp8x) {
|
|
70
|
+
const img = otherChunks.find(c => c.fourCC === 'VP8 ' || c.fourCC === 'VP8L');
|
|
71
|
+
if (!img) {
|
|
72
|
+
throw new Boom('writeExifToWebp: no VP8/VP8L image data found', { statusCode: 400 });
|
|
73
|
+
}
|
|
74
|
+
let width;
|
|
75
|
+
let height;
|
|
76
|
+
if (img.fourCC === 'VP8 ') {
|
|
77
|
+
width = (img.data.readUInt16LE(6) & 0x3fff);
|
|
78
|
+
height = (img.data.readUInt16LE(8) & 0x3fff);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const b = img.data;
|
|
82
|
+
width = 1 + (((b[2] & 0x3f) << 8) | b[1]);
|
|
83
|
+
height = 1 + (((b[4] & 0xf) << 10) | (b[3] << 2) | ((b[2] & 0xc0) >> 6));
|
|
84
|
+
}
|
|
85
|
+
const flags = Buffer.alloc(4);
|
|
86
|
+
flags[0] = 0x08;
|
|
87
|
+
const dims = Buffer.alloc(6);
|
|
88
|
+
dims.writeUIntLE(width - 1, 0, 3);
|
|
89
|
+
dims.writeUIntLE(height - 1, 3, 3);
|
|
90
|
+
vp8x = { fourCC: 'VP8X', data: Buffer.concat([flags, dims]) };
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const flagsByte = vp8x.data[0] | 0x08;
|
|
94
|
+
vp8x = { fourCC: 'VP8X', data: Buffer.concat([Buffer.from([flagsByte]), vp8x.data.subarray(1)]) };
|
|
95
|
+
}
|
|
96
|
+
const rebuilt = [vp8x, ...otherChunks, { fourCC: 'EXIF', data: exifData }];
|
|
97
|
+
const chunkBuffers = rebuilt.map(c => buildChunk(c.fourCC, c.data));
|
|
98
|
+
const payload = Buffer.concat(chunkBuffers);
|
|
99
|
+
const riffSize = 4 + payload.length;
|
|
100
|
+
const out = Buffer.alloc(8 + 4 + payload.length);
|
|
101
|
+
out.write('RIFF', 0, 4, 'ascii');
|
|
102
|
+
out.writeUInt32LE(riffSize, 4);
|
|
103
|
+
out.write('WEBP', 8, 4, 'ascii');
|
|
104
|
+
payload.copy(out, 12);
|
|
105
|
+
return out;
|
|
106
|
+
};
|
|
107
|
+
export const makeSticker = async (buffer, { pack = '', author = '', emojis = [], isPrivate = false, animated = false, quality = 60 } = {}) => {
|
|
108
|
+
const webp = await convertToWebp(buffer, { animated, quality });
|
|
109
|
+
return writeExifToWebp(webp, { packName: pack, publisher: author, emojis, isAvatar: isPrivate });
|
|
110
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString } from '../../WABinary/index.js'
|
|
2
|
+
|
|
3
|
+
export class USyncBotProfileProtocol {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = 'bot'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getQueryElement() {
|
|
9
|
+
return {
|
|
10
|
+
tag: 'bot',
|
|
11
|
+
attrs: {},
|
|
12
|
+
content: [{ tag: 'profile', attrs: { v: '1' } }]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getUserElement(user) {
|
|
17
|
+
return {
|
|
18
|
+
tag: 'bot',
|
|
19
|
+
attrs: {},
|
|
20
|
+
content: [{ tag: 'profile', attrs: { persona_id: user.personaId } }]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
parser(node) {
|
|
25
|
+
const botNode = getBinaryNodeChild(node, 'bot')
|
|
26
|
+
const profile = getBinaryNodeChild(botNode, 'profile')
|
|
27
|
+
const commandsNode = getBinaryNodeChild(profile, 'commands')
|
|
28
|
+
const promptsNode = getBinaryNodeChild(profile, 'prompts')
|
|
29
|
+
const commands = []
|
|
30
|
+
const prompts = []
|
|
31
|
+
for (const command of getBinaryNodeChildren(commandsNode, 'command')) {
|
|
32
|
+
commands.push({
|
|
33
|
+
name: getBinaryNodeChildString(command, 'name'),
|
|
34
|
+
description: getBinaryNodeChildString(command, 'description')
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
for (const prompt of getBinaryNodeChildren(promptsNode, 'prompt')) {
|
|
38
|
+
prompts.push(`${getBinaryNodeChildString(prompt, 'emoji')} ${getBinaryNodeChildString(prompt, 'text')}`)
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
isDefault: !!getBinaryNodeChild(profile, 'default'),
|
|
42
|
+
jid: node.attrs.jid,
|
|
43
|
+
name: getBinaryNodeChildString(profile, 'name'),
|
|
44
|
+
attributes: getBinaryNodeChildString(profile, 'attributes'),
|
|
45
|
+
description: getBinaryNodeChildString(profile, 'description'),
|
|
46
|
+
category: getBinaryNodeChildString(profile, 'category'),
|
|
47
|
+
personaId: profile.attrs['persona_id'],
|
|
48
|
+
commandsDescription: getBinaryNodeChildString(commandsNode, 'description'),
|
|
49
|
+
commands,
|
|
50
|
+
prompts
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { assertNodeErrorFree, getBinaryNodeChild } from '../../WABinary/index.js'
|
|
2
|
+
|
|
3
|
+
export class USyncBusinessProtocol {
|
|
4
|
+
constructor(profileVersion = '2') {
|
|
5
|
+
this.name = 'business'
|
|
6
|
+
this.profileVersion = profileVersion
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getQueryElement() {
|
|
10
|
+
return {
|
|
11
|
+
tag: 'business',
|
|
12
|
+
attrs: {},
|
|
13
|
+
content: [
|
|
14
|
+
{ tag: 'verified_name', attrs: {} },
|
|
15
|
+
{ tag: 'profile', attrs: { v: this.profileVersion } }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getUserElement(user) {
|
|
21
|
+
const children = []
|
|
22
|
+
if (user.verifiedNameSerial) {
|
|
23
|
+
children.push({ tag: 'verified_name', attrs: { serial: user.verifiedNameSerial } })
|
|
24
|
+
}
|
|
25
|
+
if (user.businessProfileTag) {
|
|
26
|
+
children.push({ tag: 'profile', attrs: { tag: user.businessProfileTag } })
|
|
27
|
+
}
|
|
28
|
+
return children.length > 0 ? { tag: 'business', attrs: {}, content: children } : null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
parser(node) {
|
|
32
|
+
if (node.tag !== 'business') return null
|
|
33
|
+
assertNodeErrorFree(node)
|
|
34
|
+
const verifiedNameNode = getBinaryNodeChild(node, 'verified_name')
|
|
35
|
+
const profileNode = getBinaryNodeChild(node, 'profile')
|
|
36
|
+
return {
|
|
37
|
+
verifiedName: verifiedNameNode?.content ?? null,
|
|
38
|
+
verifiedLevel: verifiedNameNode?.attrs?.verified_level ?? null,
|
|
39
|
+
profileTag: profileNode?.attrs?.tag ?? null,
|
|
40
|
+
pnJid: node.attrs?.pn_jid ?? null
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,52 +1,54 @@
|
|
|
1
|
-
import { assertNodeErrorFree } from '../../WABinary/index.js'
|
|
2
|
-
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js'
|
|
2
|
+
|
|
3
3
|
export class USyncContactProtocol {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = 'contact'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getQueryElement() {
|
|
9
|
+
return {
|
|
10
|
+
tag: 'contact',
|
|
11
|
+
attrs: {}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getUserElement(user) {
|
|
16
|
+
if (user.phone) {
|
|
17
|
+
return {
|
|
18
|
+
tag: 'contact',
|
|
19
|
+
attrs: {},
|
|
20
|
+
content: user.phone
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (user.username) {
|
|
24
|
+
return {
|
|
25
|
+
tag: 'contact',
|
|
26
|
+
attrs: {
|
|
27
|
+
username: user.username,
|
|
28
|
+
...(user.usernameKey ? { pin: user.usernameKey } : {}),
|
|
29
|
+
...(user.lid ? { lid: user.lid } : {})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (user.type) {
|
|
34
|
+
return {
|
|
35
|
+
tag: 'contact',
|
|
36
|
+
attrs: {
|
|
37
|
+
type: user.type
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
tag: 'contact',
|
|
43
|
+
attrs: {}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
parser(node) {
|
|
48
|
+
if (node.tag === 'contact') {
|
|
49
|
+
assertNodeErrorFree(node)
|
|
50
|
+
return node?.attrs?.type === 'in'
|
|
51
|
+
}
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
|
-
//# sourceMappingURL=USyncContactProtocol.js.map
|
|
@@ -1,54 +1,57 @@
|
|
|
1
|
-
import { assertNodeErrorFree, getBinaryNodeChild } from '../../WABinary/index.js'
|
|
1
|
+
import { assertNodeErrorFree, getBinaryNodeChild } from '../../WABinary/index.js'
|
|
2
|
+
|
|
2
3
|
export class USyncDeviceProtocol {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = 'devices'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getQueryElement() {
|
|
9
|
+
return {
|
|
10
|
+
tag: 'devices',
|
|
11
|
+
attrs: {
|
|
12
|
+
version: '2'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getUserElement(/* user */) {
|
|
18
|
+
//TODO: Implement device phashing, ts and expectedTs
|
|
19
|
+
//TODO: if all are not present, return null <- current behavior
|
|
20
|
+
//TODO: otherwise return a node w tag 'devices' w those as attrs
|
|
21
|
+
return null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
parser(node) {
|
|
25
|
+
const deviceList = []
|
|
26
|
+
let keyIndex = undefined
|
|
27
|
+
if (node.tag === 'devices') {
|
|
28
|
+
assertNodeErrorFree(node)
|
|
29
|
+
const deviceListNode = getBinaryNodeChild(node, 'device-list')
|
|
30
|
+
const keyIndexNode = getBinaryNodeChild(node, 'key-index-list')
|
|
31
|
+
if (Array.isArray(deviceListNode?.content)) {
|
|
32
|
+
for (const { tag, attrs } of deviceListNode.content) {
|
|
33
|
+
const id = +attrs.id
|
|
34
|
+
const keyIndex = +attrs['key-index']
|
|
35
|
+
if (tag === 'device') {
|
|
36
|
+
deviceList.push({
|
|
37
|
+
id,
|
|
38
|
+
keyIndex,
|
|
39
|
+
isHosted: !!(attrs['is_hosted'] && attrs['is_hosted'] === 'true')
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (keyIndexNode?.tag === 'key-index-list') {
|
|
45
|
+
keyIndex = {
|
|
46
|
+
timestamp: +keyIndexNode.attrs['ts'],
|
|
47
|
+
signedKeyIndex: keyIndexNode?.content,
|
|
48
|
+
expectedTimestamp: keyIndexNode.attrs['expected_ts'] ? +keyIndexNode.attrs['expected_ts'] : undefined
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
deviceList,
|
|
54
|
+
keyIndex
|
|
55
|
+
}
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
|
-
//# sourceMappingURL=USyncDeviceProtocol.js.map
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
import { assertNodeErrorFree } from '../../WABinary/index.js'
|
|
1
|
+
import { assertNodeErrorFree } from '../../WABinary/index.js'
|
|
2
|
+
|
|
2
3
|
export class USyncDisappearingModeProtocol {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
4
|
+
constructor() {
|
|
5
|
+
this.name = 'disappearing_mode'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getQueryElement() {
|
|
9
|
+
return {
|
|
10
|
+
tag: 'disappearing_mode',
|
|
11
|
+
attrs: {}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getUserElement() {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
parser(node) {
|
|
20
|
+
if (node.tag === 'disappearing_mode') {
|
|
21
|
+
assertNodeErrorFree(node)
|
|
22
|
+
const duration = +node?.attrs.duration
|
|
23
|
+
const setAt = new Date(+(node?.attrs.t || 0) * 1000)
|
|
24
|
+
return {
|
|
25
|
+
duration,
|
|
26
|
+
setAt
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
|
-
//# sourceMappingURL=USyncDisappearingModeProtocol.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getBinaryNodeChild } from '../../WABinary/index.js'
|
|
2
|
+
|
|
3
|
+
// Device feature flags that can be queried, ported from WhatsApp Web's
|
|
4
|
+
// WAWebUsyncFeature module.
|
|
5
|
+
export const USYNC_FEATURES = [
|
|
6
|
+
'document',
|
|
7
|
+
'encrypt',
|
|
8
|
+
'encrypt_blist',
|
|
9
|
+
'encrypt_contact',
|
|
10
|
+
'encrypt_group_gen2',
|
|
11
|
+
'encrypt_image',
|
|
12
|
+
'encrypt_location',
|
|
13
|
+
'encrypt_url',
|
|
14
|
+
'encrypt_v2',
|
|
15
|
+
'voip',
|
|
16
|
+
'multi_agent'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
export class USyncFeatureProtocol {
|
|
20
|
+
/**
|
|
21
|
+
* @param {string[]} [features] feature names to query (defaults to all known)
|
|
22
|
+
*/
|
|
23
|
+
constructor(features) {
|
|
24
|
+
this.name = 'feature'
|
|
25
|
+
this.features = features && features.length ? features : USYNC_FEATURES
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getQueryElement() {
|
|
29
|
+
return {
|
|
30
|
+
tag: 'feature',
|
|
31
|
+
attrs: {},
|
|
32
|
+
content: this.features.map(feature => ({ tag: feature, attrs: {} }))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getUserElement() {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
parser(node) {
|
|
41
|
+
if (node.tag !== 'feature') return null
|
|
42
|
+
const errorNode = getBinaryNodeChild(node, 'error')
|
|
43
|
+
if (errorNode) {
|
|
44
|
+
return {
|
|
45
|
+
errorCode: errorNode.attrs?.code ? +errorNode.attrs.code : undefined,
|
|
46
|
+
errorText: errorNode.attrs?.text
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const features = {}
|
|
50
|
+
const children = Array.isArray(node.content) ? node.content : []
|
|
51
|
+
for (const child of children) {
|
|
52
|
+
if (child?.attrs && child.attrs.value !== undefined) {
|
|
53
|
+
features[child.tag] = child.attrs.value
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return features
|
|
57
|
+
}
|
|
58
|
+
}
|