@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.
Files changed (50) hide show
  1. package/LICENSE +4 -1
  2. package/README.md +202 -277
  3. package/lib/Defaults/index.js +1 -1
  4. package/lib/Socket/graphql.js +716 -0
  5. package/lib/Socket/index.js +7 -1
  6. package/lib/Socket/interop.js +463 -0
  7. package/lib/Socket/messages-send.js +7 -6
  8. package/lib/Socket/mex.js +51 -39
  9. package/lib/Socket/newsletter.js +725 -258
  10. package/lib/Socket/privacy.js +318 -0
  11. package/lib/Socket/socket.js +143 -17
  12. package/lib/Socket/username.js +225 -136
  13. package/lib/Store/make-in-memory-store.js +47 -1
  14. package/lib/Types/Mex.js +76 -2
  15. package/lib/Utils/messages-media.js +82 -0
  16. package/lib/Utils/messages.js +86 -2
  17. package/lib/Utils/sticker.js +110 -0
  18. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
  19. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  20. package/lib/WAUSync/Protocols/USyncContactProtocol.js +52 -50
  21. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +55 -52
  22. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +28 -25
  23. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
  24. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
  25. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  26. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
  27. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -36
  28. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  29. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -23
  30. package/lib/WAUSync/Protocols/index.js +12 -6
  31. package/lib/WAUSync/USyncQuery.js +149 -96
  32. package/lib/WAUSync/USyncUser.js +54 -29
  33. package/lib/WAUSync/index.js +3 -4
  34. package/lib/index.js +2 -3
  35. package/package.json +19 -20
  36. package/WAProto/fix-import.js +0 -29
  37. package/lib/Defaults/baileys-version.json +0 -3
  38. package/lib/Defaults/phonenumber-mcc.json +0 -223
  39. package/lib/Signal/Group/queue-job.js +0 -57
  40. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  41. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  42. package/lib/Socket/Client/web-socket-client.js +0 -62
  43. package/lib/Socket/community.js +0 -392
  44. package/lib/Socket/dugong.js +0 -637
  45. package/lib/Socket/registration.js +0 -167
  46. package/lib/Socket/usync.js +0 -69
  47. package/lib/Types/Newsletter.js +0 -38
  48. package/lib/Utils/baileys-event-stream.js +0 -63
  49. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
  50. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
@@ -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
- m = await prepareWAMessageMedia(message, options);
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
- import { USyncUser } from '../USyncUser.js';
1
+ import { assertNodeErrorFree } from '../../WABinary/index.js'
2
+
3
3
  export class USyncContactProtocol {
4
- constructor() {
5
- this.name = 'contact';
6
- }
7
- getQueryElement() {
8
- return {
9
- tag: 'contact',
10
- attrs: {}
11
- };
12
- }
13
- getUserElement(user) {
14
- if (user.phone) {
15
- return {
16
- tag: 'contact',
17
- attrs: {},
18
- content: user.phone
19
- };
20
- }
21
- if (user.username) {
22
- return {
23
- tag: 'contact',
24
- attrs: {
25
- username: user.username,
26
- ...(user.usernameKey ? { pin: user.usernameKey } : {}),
27
- ...(user.lid ? { lid: user.lid } : {})
28
- }
29
- };
30
- }
31
- if (user.type) {
32
- return {
33
- tag: 'contact',
34
- attrs: {
35
- type: user.type
36
- }
37
- };
38
- }
39
- return {
40
- tag: 'contact',
41
- attrs: {}
42
- };
43
- }
44
- parser(node) {
45
- if (node.tag === 'contact') {
46
- assertNodeErrorFree(node);
47
- return node?.attrs?.type === 'in';
48
- }
49
- return false;
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
- constructor() {
4
- this.name = 'devices';
5
- }
6
- getQueryElement() {
7
- return {
8
- tag: 'devices',
9
- attrs: {
10
- version: '2'
11
- }
12
- };
13
- }
14
- getUserElement( /* user: USyncUser */) {
15
- //TODO: Implement device phashing, ts and expectedTs
16
- //TODO: if all are not present, return null <- current behavior
17
- //TODO: otherwise return a node w tag 'devices' w those as attrs
18
- return null;
19
- }
20
- parser(node) {
21
- const deviceList = [];
22
- let keyIndex = undefined;
23
- if (node.tag === 'devices') {
24
- assertNodeErrorFree(node);
25
- const deviceListNode = getBinaryNodeChild(node, 'device-list');
26
- const keyIndexNode = getBinaryNodeChild(node, 'key-index-list');
27
- if (Array.isArray(deviceListNode?.content)) {
28
- for (const { tag, attrs } of deviceListNode.content) {
29
- const id = +attrs.id;
30
- const keyIndex = +attrs['key-index'];
31
- if (tag === 'device') {
32
- deviceList.push({
33
- id,
34
- keyIndex,
35
- isHosted: !!(attrs['is_hosted'] && attrs['is_hosted'] === 'true')
36
- });
37
- }
38
- }
39
- }
40
- if (keyIndexNode?.tag === 'key-index-list') {
41
- keyIndex = {
42
- timestamp: +keyIndexNode.attrs['ts'],
43
- signedKeyIndex: keyIndexNode?.content,
44
- expectedTimestamp: keyIndexNode.attrs['expected_ts'] ? +keyIndexNode.attrs['expected_ts'] : undefined
45
- };
46
- }
47
- }
48
- return {
49
- deviceList,
50
- keyIndex
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
- constructor() {
4
- this.name = 'disappearing_mode';
5
- }
6
- getQueryElement() {
7
- return {
8
- tag: 'disappearing_mode',
9
- attrs: {}
10
- };
11
- }
12
- getUserElement() {
13
- return null;
14
- }
15
- parser(node) {
16
- if (node.tag === 'disappearing_mode') {
17
- assertNodeErrorFree(node);
18
- const duration = +node?.attrs.duration;
19
- const setAt = new Date(+(node?.attrs.t || 0) * 1000);
20
- return {
21
- duration,
22
- setAt
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
+ }