@violetix/baileys 0.5.5 → 0.6.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.
Files changed (80) hide show
  1. package/README.md +1530 -2009
  2. package/WAProto/index.d.ts +14030 -14586
  3. package/WAProto/index.js +58426 -88874
  4. package/lib/Defaults/index.d.ts +2 -7
  5. package/lib/Defaults/index.js +5 -20
  6. package/lib/Signal/Group/sender-key-message.js +19 -1
  7. package/lib/Signal/libsignal.js +82 -29
  8. package/lib/Signal/xeddsa-fast.js +114 -0
  9. package/lib/Socket/Client/types.js +6 -8
  10. package/lib/Socket/Client/websocket.js +3 -38
  11. package/lib/Socket/business.d.ts +0 -3
  12. package/lib/Socket/chats.d.ts +0 -3
  13. package/lib/Socket/chats.js +18 -45
  14. package/lib/Socket/communities.d.ts +0 -3
  15. package/lib/Socket/graphql.js +3 -7
  16. package/lib/Socket/groups.d.ts +0 -3
  17. package/lib/Socket/groups.js +3 -8
  18. package/lib/Socket/index.d.ts +15 -17
  19. package/lib/Socket/messages-recv.d.ts +0 -3
  20. package/lib/Socket/messages-recv.js +43 -127
  21. package/lib/Socket/messages-send.d.ts +0 -4
  22. package/lib/Socket/messages-send.js +63 -191
  23. package/lib/Socket/newsletter.d.ts +0 -3
  24. package/lib/Socket/newsletter.js +1 -2
  25. package/lib/Socket/newsletter.js.map +1 -1
  26. package/lib/Socket/socket.d.ts +0 -9
  27. package/lib/Socket/socket.js +53 -341
  28. package/lib/Store/make-in-memory-store.js +30 -41
  29. package/lib/Types/Auth.d.ts +2 -60
  30. package/lib/Types/Bussines.d.ts +2 -9
  31. package/lib/Types/Call.d.ts +2 -22
  32. package/lib/Types/Chat.d.ts +1 -2
  33. package/lib/Types/Contact.d.ts +2 -11
  34. package/lib/Types/Events.d.ts +2 -41
  35. package/lib/Types/GroupMetadata.d.ts +2 -36
  36. package/lib/Types/Message.d.ts +1 -11
  37. package/lib/Types/Product.d.ts +2 -5
  38. package/lib/Types/Signal.d.ts +2 -10
  39. package/lib/Types/Socket.d.ts +2 -33
  40. package/lib/Types/USync.d.ts +2 -9
  41. package/lib/Types/index.d.ts +1 -3
  42. package/lib/Utils/auth-utils.d.ts +2 -3
  43. package/lib/Utils/auth-utils.js +53 -37
  44. package/lib/Utils/business.js +11 -25
  45. package/lib/Utils/chat-utils.js +4 -6
  46. package/lib/Utils/decode-wa-message.js +2 -2
  47. package/lib/Utils/event-buffer.js +12 -21
  48. package/lib/Utils/generics.d.ts +5 -5
  49. package/lib/Utils/generics.js +7 -25
  50. package/lib/Utils/history.d.ts +1 -2
  51. package/lib/Utils/history.js +83 -137
  52. package/lib/Utils/index.d.ts +0 -4
  53. package/lib/Utils/index.js +0 -4
  54. package/lib/Utils/listener-guard.js +0 -2
  55. package/lib/Utils/message-retry-manager.js +0 -20
  56. package/lib/Utils/messages-media.d.ts +8 -39
  57. package/lib/Utils/messages-media.js +89 -218
  58. package/lib/Utils/messages.d.ts +0 -1
  59. package/lib/Utils/messages.js +36 -122
  60. package/lib/Utils/process-message.d.ts +0 -18
  61. package/lib/Utils/process-message.js +47 -99
  62. package/lib/Utils/rich-message-utils.js +4 -3
  63. package/lib/Utils/use-multi-file-auth-state.d.ts +3 -5
  64. package/lib/Utils/use-multi-file-auth-state.js +6 -27
  65. package/lib/Utils/use-single-file-auth-state.d.ts +1 -1
  66. package/lib/Utils/use-single-file-auth-state.js +3 -12
  67. package/lib/WABinary/types.d.ts +2 -6
  68. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +3 -6
  69. package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -3
  70. package/lib/WAUSync/USyncQuery.d.ts +1 -1
  71. package/lib/WAUSync/USyncQuery.js +4 -7
  72. package/package.json +107 -123
  73. package/lib/Utils/a2ui.d.ts +0 -50
  74. package/lib/Utils/a2ui.js +0 -168
  75. package/lib/Utils/anchor-guard.d.ts +0 -71
  76. package/lib/Utils/anchor-guard.js +0 -404
  77. package/lib/Utils/connection-manager.d.ts +0 -44
  78. package/lib/Utils/connection-manager.js +0 -258
  79. package/lib/Utils/ignore-key.d.ts +0 -51
  80. package/lib/Utils/ignore-key.js +0 -176
@@ -6,7 +6,6 @@ import { proto } from '../../WAProto/index.js';
6
6
  import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, DONATE_URL, LIBRARY_NAME, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
7
7
  import { AssociationType, ButtonHeaderType, ButtonType, CarouselCardType, ListType, ProtocolType, WAMessageStatus, WAProto } from '../Types/index.js';
8
8
  import { isLidUser, isPnUser, isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
9
- import { buildA2UIWidget } from './a2ui.js';
10
9
  import { sha256 } from './crypto.js';
11
10
  import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
12
11
  import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getImageProcessingLibrary, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
@@ -50,7 +49,7 @@ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) =>
50
49
  const assertColor = async (color) => {
51
50
  let assertedColor;
52
51
  if (typeof color === 'number') {
53
- assertedColor = color >>> 0;
52
+ assertedColor = color > 0 ? color : 0xffffffff + Number(color) + 1;
54
53
  }
55
54
  else {
56
55
  let hex = color.trim().replace('#', '');
@@ -58,18 +57,8 @@ const assertColor = async (color) => {
58
57
  hex = 'FF' + hex.padStart(6, '0');
59
58
  }
60
59
  assertedColor = parseInt(hex, 16);
60
+ return assertedColor;
61
61
  }
62
- return assertedColor;
63
- };
64
- /**
65
- * Option identifier for an image poll: WhatsApp hashes the option name, appends the base64
66
- * media hash, and hashes that — `sha256(hex(sha256(name)) + base64(fileSha256))`. A vote carries
67
- * this hash, not the name, so it has to match byte for byte.
68
- */
69
- export const hashImagePollOption = (optionName, fileSha256) => {
70
- const nameHash = sha256(Buffer.from(String(optionName), 'utf-8')).toString('hex');
71
- const mediaHashB64 = fileSha256 ? Buffer.from(fileSha256).toString('base64') : '';
72
- return sha256(Buffer.from(nameHash + mediaHashB64, 'utf-8')).toString('hex');
73
62
  };
74
63
  export const prepareWAMessageMedia = async (message, options) => {
75
64
  const logger = options.logger;
@@ -88,12 +77,11 @@ export const prepareWAMessageMedia = async (message, options) => {
88
77
  };
89
78
  delete uploadData[mediaType];
90
79
  // check if cacheable + generate cache key
91
- const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
92
80
  const cacheableKey = typeof uploadData.media === 'object' &&
93
81
  'url' in uploadData.media &&
94
82
  !!uploadData.media.url &&
95
83
  !!options.mediaCache &&
96
- JSON.stringify([mediaType, options.mediaTypeOverride || mediaType, isNewsletter, uploadData.media.url.toString()]);
84
+ mediaType + ':' + uploadData.media.url.toString();
97
85
  if (mediaType === 'document' && !uploadData.fileName) {
98
86
  uploadData.fileName = 'file';
99
87
  }
@@ -105,12 +93,12 @@ export const prepareWAMessageMedia = async (message, options) => {
105
93
  if (mediaBuff) {
106
94
  logger?.debug({ cacheableKey }, 'got media cache hit');
107
95
  const obj = proto.Message.decode(mediaBuff);
108
- // ptv entries are cached after videoMessage was renamed to ptvMessage
109
- const key = obj.ptvMessage ? 'ptvMessage' : `${mediaType}Message`;
96
+ const key = `${mediaType}Message`;
110
97
  Object.assign(obj[key], { ...uploadData, media: undefined });
111
98
  return obj;
112
99
  }
113
100
  }
101
+ const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
114
102
  if (isNewsletter) {
115
103
  logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
116
104
  const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
@@ -151,9 +139,9 @@ export const prepareWAMessageMedia = async (message, options) => {
151
139
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
152
140
  const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
153
141
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
154
- const requiresAudioBackground = options.backgroundColor != null && mediaType === 'audio' && uploadData.ptt === true;
142
+ const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
155
143
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
156
- const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength, streamingSidecar } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
144
+ const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
157
145
  logger,
158
146
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
159
147
  opts: options.options
@@ -219,7 +207,6 @@ export const prepareWAMessageMedia = async (message, options) => {
219
207
  fileSha256,
220
208
  fileLength,
221
209
  mediaKeyTimestamp: unixTimestampSeconds(),
222
- ...(streamingSidecar ? { streamingSidecar } : {}),
223
210
  ...uploadData,
224
211
  media: undefined
225
212
  })
@@ -259,7 +246,7 @@ const prepareProductMessage = async (message, options) => {
259
246
  */
260
247
  // Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
261
248
  const prepareStickerPackMessage = async (message, options) => {
262
- const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: cv3inx', description = '🏷️ violetix/baileys' } = message;
249
+ const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: itsliaaa', description = '🏷️ itsliaaa/baileys' } = message;
263
250
  if (stickers.length > 60) {
264
251
  throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
265
252
  }
@@ -665,42 +652,46 @@ export const generateWAMessageContent = async (message, options) => {
665
652
  thumbnailEncSha256: imageMessage.fileEncSha256
666
653
  };
667
654
  }
668
- if (options.backgroundColor != null) {
655
+ if (options.backgroundColor) {
669
656
  extContent.backgroundArgb = await assertColor(options.backgroundColor);
670
657
  }
671
658
  if (options.font) {
672
659
  extContent.font = options.font;
673
660
  }
674
- if (options.textColorArgb != null) {
661
+ if (options.textColorArgb) {
675
662
  extContent.textArgb = await assertColor(options.textColorArgb);
676
663
  }
677
664
  m.extendedTextMessage = extContent;
678
665
  }
679
- // Lia@Changes 08-09-26 --- Accept group status content as { groupStatusMessage | groupStatusMessageV2 | groupStatus: { text|image|video|audio } }
680
666
  else if (hasNonNullishProperty(message, 'groupStatusMessage') ||
681
- hasNonNullishProperty(message, 'groupStatusMessageV2') ||
682
- (hasNonNullishProperty(message, 'groupStatus') && typeof message.groupStatus === 'object')) {
683
- const inner = message.groupStatusMessageV2 || message.groupStatusMessage || message.groupStatus;
667
+ hasNonNullishProperty(message, 'groupStatusMessageV2')) {
668
+ const inner = hasNonNullishProperty(message, 'groupStatusMessageV2')
669
+ ? message.groupStatusMessageV2
670
+ : message.groupStatusMessage;
684
671
  const innerMessage = inner?.message || inner;
685
672
  if (!innerMessage || typeof innerMessage !== 'object') {
686
673
  throw new Boom('Invalid group status message', { statusCode: 400 }); // Lia@Note 08-09-26 --- To avoid bug 👀
687
674
  }
688
675
  const { backgroundColor, font, color, ...contentBody } = innerMessage;
689
- if (backgroundColor) {
690
- options.backgroundColor = backgroundColor;
691
- }
692
- if (font !== undefined) {
693
- options.font = font;
694
- }
695
- if (color) {
696
- options.textColorArgb = color;
697
- }
676
+ if (backgroundColor) options.backgroundColor = backgroundColor;
677
+ if (font !== undefined) options.font = font;
678
+ if (color) options.textColorArgb = color;
698
679
  m = await generateWAMessageContent(contentBody, options);
699
680
  if (!hasOptionalProperty(m, 'groupStatusMessageV2')) {
700
681
  message.groupStatus = true; // Lia@Note 08-09-26 --- let the wrap below normalize it into groupStatusMessageV2
701
682
  }
702
- else {
703
- delete message.groupStatus; // Lia@Note 08-09-26 --- already wrapped, don't wrap twice
683
+ }
684
+ // Lia@Changes 08-09-26 --- Accept nested group status content { groupStatus: { text|image|video|audio } }
685
+ else if (hasNonNullishProperty(message, 'groupStatus') &&
686
+ message.groupStatus &&
687
+ typeof message.groupStatus === 'object') {
688
+ const { backgroundColor, font, color, ...contentBody } = message.groupStatus;
689
+ if (backgroundColor) options.backgroundColor = backgroundColor;
690
+ if (font !== undefined) options.font = font;
691
+ if (color) options.textColorArgb = color;
692
+ m = await generateWAMessageContent(contentBody, options);
693
+ if (!hasOptionalProperty(m, 'groupStatusMessageV2')) {
694
+ message.groupStatus = true;
704
695
  }
705
696
  }
706
697
  else if (hasNonNullishProperty(message, 'contacts')) {
@@ -885,10 +876,6 @@ export const generateWAMessageContent = async (message, options) => {
885
876
  selectableOptionsCount: 1
886
877
  };
887
878
  }
888
- else if (message.poll.hideVoter || message.poll.canAddOption) {
889
- // only poll v6 carries hideParticipantName / allowAddOption; older versions drop them
890
- m.pollCreationMessageV6 = pollCreationMessage;
891
- }
892
879
  else if (message.poll.selectableCount === 1) {
893
880
  //poll v3 is for single select polls
894
881
  m.pollCreationMessageV3 = pollCreationMessage;
@@ -903,36 +890,6 @@ export const generateWAMessageContent = async (message, options) => {
903
890
  messageSecret: message.poll.messageSecret || randomBytes(32)
904
891
  };
905
892
  }
906
- // Image poll: the parent carries only the option names and their hashes. The images
907
- // themselves travel as separate pollCreationOptionImageMessage children, associated back
908
- // to this message by MEDIA_POLL — sendMessage sends those after the parent.
909
- else if (hasNonNullishProperty(message, 'imagePoll')) {
910
- if (!Array.isArray(message.imagePoll.options) || !message.imagePoll.options.length) {
911
- throw new Boom('Invalid imagePoll options', { statusCode: 400 });
912
- }
913
- const selectableOptionsCount = message.imagePoll.selectableCount ?? 1;
914
- if (selectableOptionsCount < 0 || selectableOptionsCount > message.imagePoll.options.length) {
915
- throw new Boom(`imagePoll.selectableCount should be >= 0 and <= ${message.imagePoll.options.length}`, {
916
- statusCode: 400
917
- });
918
- }
919
- const missingHash = message.imagePoll.options.find(option => !option.optionHash);
920
- if (missingHash) {
921
- throw new Boom('imagePoll options must be prepared with hashImagePollOption; send via sendMessage instead of building the content by hand', { statusCode: 400 });
922
- }
923
- m.pollCreationMessageV3 = {
924
- name: message.imagePoll.name,
925
- selectableOptionsCount,
926
- options: message.imagePoll.options.map(option => ({
927
- optionName: option.optionName,
928
- optionHash: option.optionHash
929
- })),
930
- pollContentType: proto.Message.PollContentType.IMAGE
931
- };
932
- m.messageContextInfo = {
933
- messageSecret: message.imagePoll.messageSecret || randomBytes(32)
934
- };
935
- }
936
893
  // Lia@Changes 08-02-26 --- Add poll result snapshot message
937
894
  else if (hasNonNullishProperty(message, 'pollResult')) {
938
895
  const pollResultSnapshotMessage = {
@@ -1036,12 +993,6 @@ export const generateWAMessageContent = async (message, options) => {
1036
993
  }
1037
994
  };
1038
995
  }
1039
- // An A2UI widget has no base content of its own — the interactive chain below replaces `m`
1040
- // wholesale. Without this it falls through to the media branch and is rejected as a media
1041
- // message, so a widget would need a dummy `text` to send at all.
1042
- else if (hasNonNullishProperty(message, 'a2ui')) {
1043
- m = {};
1044
- }
1045
996
  else {
1046
997
  m = await prepareWAMessageMedia(message, options);
1047
998
  }
@@ -1165,31 +1116,6 @@ export const generateWAMessageContent = async (message, options) => {
1165
1116
  }
1166
1117
  };
1167
1118
  }
1168
- // A2UI widget. `nativeFlowMessage` is always set, even empty: it is what the client keys the
1169
- // interactive render off, and it is also what makes the socket attach the <biz> node.
1170
- else if (hasNonNullishProperty(message, 'a2ui')) {
1171
- const interactiveMessage = {
1172
- bloksWidget: buildA2UIWidget(message.a2ui, {
1173
- type: message.a2uiType,
1174
- wrapped: message.a2uiWrapped !== false
1175
- }),
1176
- nativeFlowMessage: hasNonNullishProperty(message, 'nativeFlow')
1177
- ? prepareNativeFlowButtons(message)
1178
- : { messageParamsJson: '' }
1179
- };
1180
- // singleScreen drops the surrounding bubble so the widget is the whole message
1181
- if (!message.singleScreen) {
1182
- interactiveMessage.header = { hasMediaAttachment: false };
1183
- interactiveMessage.body = { text: message.text || '' };
1184
- interactiveMessage.footer = { text: message.footer || '' };
1185
- }
1186
- m = {
1187
- interactiveMessage,
1188
- messageContextInfo: {
1189
- messageSecret: message.messageSecret || randomBytes(32)
1190
- }
1191
- };
1192
- }
1193
1119
  else if (hasNonNullishProperty(message, 'nativeFlow')) {
1194
1120
  const interactiveMessage = {
1195
1121
  nativeFlowMessage: prepareNativeFlowButtons(message)
@@ -1547,17 +1473,10 @@ export const generateWAMessageFromContent = (jid, message, options) => {
1547
1473
  // newsletters don't support ephemeral messages
1548
1474
  !isNewsletter) {
1549
1475
  /* @ts-ignore */
1550
- // WA Web stamps the chat's disappearing-mode setting alongside the TTL; without it the
1551
- // peer warns that the message will not disappear. Callers pass the setting timestamp
1552
- // when they track it (there is no chat store here), the trigger defaults to CHAT_SETTING.
1553
1476
  innerMessage[key].contextInfo = {
1554
1477
  ...(innerMessage[key].contextInfo || {}),
1555
- expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL,
1556
- ...(options.ephemeralSettingTimestamp ? { ephemeralSettingTimestamp: options.ephemeralSettingTimestamp } : {}),
1557
- disappearingMode: {
1558
- initiator: proto.DisappearingMode.Initiator.CHANGED_IN_CHAT,
1559
- trigger: options.disappearingModeTrigger ?? proto.DisappearingMode.Trigger.CHAT_SETTING
1560
- }
1478
+ expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
1479
+ //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
1561
1480
  };
1562
1481
  }
1563
1482
  // Lia@Changes 30-01-26 --- Add deviceListMetadata inside messageContextInfo for private chat
@@ -1743,12 +1662,9 @@ export const updateMessageWithEventResponse = (msg, update) => {
1743
1662
  * @returns A list of options & their voters
1744
1663
  */
1745
1664
  export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1746
- message = normalizeMessageContent(message);
1747
1665
  const opts = message?.pollCreationMessage?.options ||
1748
1666
  message?.pollCreationMessageV2?.options ||
1749
1667
  message?.pollCreationMessageV3?.options ||
1750
- message?.pollCreationMessageV5?.options ||
1751
- message?.pollCreationMessageV6?.options ||
1752
1668
  [];
1753
1669
  const voteHashMap = opts.reduce((acc, opt) => {
1754
1670
  const hash = sha256(Buffer.from(opt.optionName || '')).toString();
@@ -1794,10 +1710,7 @@ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1794
1710
  };
1795
1711
  }
1796
1712
  for (const update of eventResponses || []) {
1797
- const response = update.response?.response ?? update.eventResponse;
1798
- const responseType = typeof response === 'number'
1799
- ? proto.Message.EventResponseMessage.EventResponseType[response]
1800
- : response || 'UNKNOWN';
1713
+ const responseType = update.eventResponse || 'UNKNOWN';
1801
1714
  if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1802
1715
  responseMap[responseType].responders.push(getKeyAuthor(update.eventResponseMessageKey, meId));
1803
1716
  }
@@ -1828,8 +1741,9 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404];
1828
1741
  */
1829
1742
  export const downloadMediaMessage = async (message, type, options, ctx) => {
1830
1743
  const result = await downloadMsg().catch(async (error) => {
1831
- const status = error?.output?.statusCode ?? error?.status;
1832
- if (ctx && REUPLOAD_REQUIRED_STATUS.includes(status)) {
1744
+ if (ctx &&
1745
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1746
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1833
1747
  ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1834
1748
  // request reupload
1835
1749
  message = await ctx.reuploadRequest(message);
@@ -1957,4 +1871,4 @@ export const shouldIncludeBizBinaryNode = (message) => !!(message.buttonsMessage
1957
1871
  message.templateMessage ||
1958
1872
  (message.interactiveMessage &&
1959
1873
  message.interactiveMessage.nativeFlowMessage));
1960
- //# sourceMappingURL=messages.js.map
1874
+ //# sourceMappingURL=messages.js.map
@@ -19,24 +19,6 @@ export function decryptPollVote({ encPayload, encIv }: {
19
19
  * @param ctx additional info about the event required for decryption
20
20
  * @returns event response message
21
21
  */
22
- export function decryptPollVoteWithFallback(vote: {
23
- encPayload: Uint8Array;
24
- encIv: Uint8Array;
25
- }, ctx: {
26
- pollCreatorJids: (string | undefined | null)[];
27
- voterJids: (string | undefined | null)[];
28
- pollMsgId: string;
29
- pollEncKey: Uint8Array;
30
- }): proto.Message.PollVoteMessage;
31
- export function decryptEventResponseWithFallback(response: {
32
- encPayload: Uint8Array;
33
- encIv: Uint8Array;
34
- }, ctx: {
35
- eventCreatorJids: (string | undefined | null)[];
36
- responderJids: (string | undefined | null)[];
37
- eventMsgId: string;
38
- eventEncKey: Uint8Array;
39
- }): proto.Message.EventResponseMessage;
40
22
  export function decryptEventResponse({ encPayload, encIv }: {
41
23
  encPayload: any;
42
24
  encIv: any;
@@ -114,10 +114,7 @@ export const isRealMessage = (message) => {
114
114
  hasSomeContent &&
115
115
  !normalizedContent?.protocolMessage &&
116
116
  !normalizedContent?.reactionMessage &&
117
- !normalizedContent?.pollUpdateMessage &&
118
- // edit envelopes and event responses are not new chat messages (unread/timestamp bump)
119
- !normalizedContent?.secretEncryptedMessage &&
120
- !normalizedContent?.encEventResponseMessage);
117
+ !normalizedContent?.pollUpdateMessage);
121
118
  };
122
119
  export const shouldIncrementChatUnread = (message) => !message.key.fromMe && !message.messageStubType;
123
120
  /**
@@ -163,41 +160,6 @@ export function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsg
163
160
  return Buffer.from(txt);
164
161
  }
165
162
  }
166
- const uniqueJids = (jids) => [...new Set(jids.filter(j => typeof j === 'string' && j.length > 0))];
167
- /**
168
- * Try every (creator, voter) pair until one decrypts. Voters derive the key from the creator
169
- * JID in `pollCreationMessageKey` (LID after the addressing migration, PN before), while the
170
- * poll secret may have been stored under the other form, so a single pair is not enough.
171
- */
172
- export function decryptPollVoteWithFallback(vote, { pollCreatorJids, voterJids, pollMsgId, pollEncKey }) {
173
- let lastErr;
174
- for (const pollCreatorJid of uniqueJids(pollCreatorJids)) {
175
- for (const voterJid of uniqueJids(voterJids)) {
176
- try {
177
- return decryptPollVote(vote, { pollCreatorJid, pollMsgId, pollEncKey, voterJid });
178
- }
179
- catch (err) {
180
- lastErr = err;
181
- }
182
- }
183
- }
184
- throw lastErr || new Boom('no jid candidates to decrypt poll vote', { statusCode: 400 });
185
- }
186
- /** Same candidate walk as {@link decryptPollVoteWithFallback} for event responses. */
187
- export function decryptEventResponseWithFallback(response, { eventCreatorJids, responderJids, eventMsgId, eventEncKey }) {
188
- let lastErr;
189
- for (const eventCreatorJid of uniqueJids(eventCreatorJids)) {
190
- for (const responderJid of uniqueJids(responderJids)) {
191
- try {
192
- return decryptEventResponse(response, { eventCreatorJid, eventMsgId, eventEncKey, responderJid });
193
- }
194
- catch (err) {
195
- lastErr = err;
196
- }
197
- }
198
- }
199
- throw lastErr || new Boom('no jid candidates to decrypt event response', { statusCode: 400 });
200
- }
201
163
  /**
202
164
  * Decrypt an event response
203
165
  * @param response encrypted event response
@@ -348,14 +310,14 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
348
310
  switch (protocolMsg.type) {
349
311
  case proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION:
350
312
  const histNotification = protocolMsg.historySyncNotification;
351
- const process = shouldProcessHistoryMsg;
313
+ const process = false; // shouldProcessHistoryMsg; // FORCE DISABLED
352
314
  const isLatest = !creds.processedHistoryMessages?.length;
353
315
  logger?.info({
354
316
  histNotification,
355
317
  process,
356
318
  id: message.key.id,
357
319
  isLatest
358
- }, 'got history notification');
320
+ }, 'got history notification (ignored by force)');
359
321
  if (process) {
360
322
  // TODO: investigate
361
323
  if (histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND) {
@@ -535,34 +497,23 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
535
497
  if (eventMsg) {
536
498
  try {
537
499
  const meIdNormalised = jidNormalizedUser(meId);
538
- const meLidNormalised = creds.me.lid ? jidNormalizedUser(creds.me.lid) : undefined;
539
- // the responder encrypted with whichever form of the creator JID it holds (PN or
540
- // LID); try the PN form first (previous behaviour), then the other form
541
- const eventCreatorKey = jidNormalizedUser(creationMsgKey.participant || creationMsgKey.remoteJid);
542
- const eventCreatorAlt = isLidUser(eventCreatorKey)
500
+ // all jids need to be PN
501
+ const eventCreatorKey = creationMsgKey.participant || creationMsgKey.remoteJid;
502
+ const eventCreatorPn = isLidUser(eventCreatorKey)
543
503
  ? await signalRepository.lidMapping.getPNForLID(eventCreatorKey)
544
- : await signalRepository.lidMapping.getLIDForPN(eventCreatorKey);
545
- const eventCreatorAltNorm = eventCreatorAlt ? jidNormalizedUser(eventCreatorAlt) : undefined;
546
- const eventCreatorJids = creationMsgKey.fromMe
547
- ? [meIdNormalised, meLidNormalised]
548
- : isLidUser(eventCreatorKey)
549
- ? [eventCreatorAltNorm, eventCreatorKey]
550
- : [eventCreatorKey, eventCreatorAltNorm];
551
- const responderJids = [
552
- getKeyAuthor(message.key, meIdNormalised),
553
- jidNormalizedUser(message.key.participant || message.key.remoteJid || ''),
554
- message.key.fromMe ? meLidNormalised : undefined
555
- ];
504
+ : eventCreatorKey;
505
+ const eventCreatorJid = getKeyAuthor({ remoteJid: jidNormalizedUser(eventCreatorPn), fromMe: meIdNormalised === eventCreatorPn }, meIdNormalised);
506
+ const responderJid = getKeyAuthor(message.key, meIdNormalised);
556
507
  const eventEncKey = eventMsg?.messageContextInfo?.messageSecret;
557
508
  if (!eventEncKey) {
558
509
  logger?.warn({ creationMsgKey }, 'event response: missing messageSecret for decryption');
559
510
  }
560
511
  else {
561
- const responseMsg = decryptEventResponseWithFallback(encEventResponse, {
512
+ const responseMsg = decryptEventResponse(encEventResponse, {
562
513
  eventEncKey,
563
- eventCreatorJids,
514
+ eventCreatorJid,
564
515
  eventMsgId: creationMsgKey.id,
565
- responderJids
516
+ responderJid
566
517
  });
567
518
  const eventResponse = {
568
519
  eventResponseMessageKey: message.key,
@@ -741,38 +692,28 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
741
692
  emitGroupRequestJoin(participant, action, method);
742
693
  break;
743
694
  }
744
- }
745
- else if (content?.pollUpdateMessage) {
746
- const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey;
747
- // the poll secret lives on the creation message; without it there is nothing to decrypt with
748
- const pollMsg = creationMsgKey ? await getMessage(creationMsgKey) : undefined;
749
- const pollEncKey = pollMsg?.messageContextInfo?.messageSecret;
750
- if (!pollEncKey) {
751
- logger?.debug({ creationMsgKey }, 'poll creation message or its secret not found, cannot decrypt vote');
752
- }
753
- else {
695
+ } /* else if(content?.pollUpdateMessage) {
696
+ const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
697
+ // we need to fetch the poll creation message to get the poll enc key
698
+ // TODO: make standalone, remove getMessage reference
699
+ // TODO: Remove entirely
700
+ const pollMsg = await getMessage(creationMsgKey)
701
+ if(pollMsg) {
702
+ const meIdNormalised = jidNormalizedUser(meId)
703
+ const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
704
+ const voterJid = getKeyAuthor(message.key, meIdNormalised)
705
+ const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
706
+
754
707
  try {
755
- const meIdNormalised = jidNormalizedUser(meId);
756
- const meLidNormalised = creds.me.lid ? jidNormalizedUser(creds.me.lid) : undefined;
757
- // voters derive the key from whichever form (PN or LID) of the creator JID they hold
758
- const creatorPrimary = jidNormalizedUser(creationMsgKey.participant || creationMsgKey.remoteJid || '');
759
- const creatorAlt = isLidUser(creatorPrimary)
760
- ? await signalRepository.lidMapping.getPNForLID(creatorPrimary)
761
- : await signalRepository.lidMapping.getLIDForPN(creatorPrimary);
762
- const pollCreatorJids = creationMsgKey.fromMe
763
- ? [meIdNormalised, meLidNormalised]
764
- : [getKeyAuthor(creationMsgKey, meIdNormalised), creatorPrimary, creatorAlt ? jidNormalizedUser(creatorAlt) : undefined];
765
- const voterJids = [
766
- getKeyAuthor(message.key, meIdNormalised),
767
- jidNormalizedUser(message.key.participant || message.key.remoteJid || ''),
768
- message.key.fromMe ? meLidNormalised : undefined
769
- ];
770
- const vote = decryptPollVoteWithFallback(content.pollUpdateMessage.vote, {
771
- pollEncKey,
772
- pollCreatorJids,
773
- voterJids,
774
- pollMsgId: creationMsgKey.id
775
- });
708
+ const voteMsg = decryptPollVote(
709
+ content.pollUpdateMessage.vote!,
710
+ {
711
+ pollEncKey,
712
+ pollCreatorJid,
713
+ pollMsgId: creationMsgKey.id!,
714
+ voterJid,
715
+ }
716
+ )
776
717
  ev.emit('messages.update', [
777
718
  {
778
719
  key: creationMsgKey,
@@ -780,19 +721,26 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
780
721
  pollUpdates: [
781
722
  {
782
723
  pollUpdateMessageKey: message.key,
783
- vote,
784
- senderTimestampMs: toNumber(content.pollUpdateMessage.senderTimestampMs)
724
+ vote: voteMsg,
725
+ senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
785
726
  }
786
727
  ]
787
728
  }
788
729
  }
789
- ]);
790
- }
791
- catch (err) {
792
- logger?.warn({ err, creationMsgKey }, 'failed to decrypt poll vote');
730
+ ])
731
+ } catch(err) {
732
+ logger?.warn(
733
+ { err, creationMsgKey },
734
+ 'failed to decrypt poll vote'
735
+ )
793
736
  }
737
+ } else {
738
+ logger?.warn(
739
+ { creationMsgKey },
740
+ 'poll creation message not found, cannot decrypt update'
741
+ )
794
742
  }
795
- }
743
+ } */
796
744
  if (Object.keys(chat).length > 1) {
797
745
  ev.emit('chats.update', [chat]);
798
746
  }
@@ -99,7 +99,7 @@ export const toUnified = (submessages, uuid) => ({
99
99
  })
100
100
  });
101
101
  export const prepareRichResponseMessage = (content) => {
102
- const { alignment, code, contentText, disclaimerText, footerText, headerText, imageText, inlineImage, inlineVideo, items, language = 'javascript', latex, links, noHeading, posts, products, suggested, richResponse, table, tapLinkUrl, title } = content;
102
+ const { alignment, code, contentText, disclaimerText, footerText, headerText, imageText, inlineImage, inlineVideo, items, language, latex, links, noHeading, posts, products, suggested, richResponse, table, tapLinkUrl, title } = content;
103
103
  let submessages = [];
104
104
  if (Array.isArray(richResponse)) {
105
105
  submessages = richResponse.map((submessage) => {
@@ -198,6 +198,7 @@ export const prepareRichResponseMessage = (content) => {
198
198
  });
199
199
  }
200
200
  if (code) {
201
+ language ||= 'javascript';
201
202
  submessages.push({
202
203
  messageType: RichSubMessageType.CODE,
203
204
  codeMetadata: {
@@ -236,7 +237,7 @@ export const prepareRichResponseMessage = (content) => {
236
237
  submessages.push({
237
238
  messageType: RichSubMessageType.LATEX,
238
239
  latexMetadata: {
239
- text: contentText,
240
+ text,
240
241
  expressions: latex
241
242
  }
242
243
  });
@@ -366,4 +367,4 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
366
367
  message: { richResponseMessage }
367
368
  }
368
369
  });
369
- //# sourceMappingURL=rich-message-utils.js.map
370
+ //# sourceMappingURL=rich-message-utils.js.map
@@ -1,4 +1,4 @@
1
- export function useMultiFileAuthState(folder: any, logger?: any): Promise<{
1
+ export function useMultiFileAuthState(folder: any): Promise<{
2
2
  state: {
3
3
  creds: any;
4
4
  keys: {
@@ -6,8 +6,6 @@ export function useMultiFileAuthState(folder: any, logger?: any): Promise<{
6
6
  set: (data: any) => Promise<void>;
7
7
  };
8
8
  };
9
- saveCreds: () => void;
10
- _flushCreds: () => Promise<void>;
11
- _destroy: () => void;
9
+ saveCreds: () => Promise<any>;
12
10
  }>;
13
- //# sourceMappingURL=use-multi-file-auth-state.d.ts.map
11
+ //# sourceMappingURL=use-multi-file-auth-state.d.ts.map