@ryuu-reinzz/baileys 3.0.0-beta.2 → 3.0.0-beta.21

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.
@@ -3,15 +3,6 @@ import haruka from "@ryuu-reinzz/haruka-lib";
3
3
  import {
4
4
  Boom
5
5
  } from '@hapi/boom';
6
- import {
7
- proto,
8
- generateWAMessageFromContent,
9
- jidDecode,
10
- downloadContentFromMessage,
11
- prepareWAMessageMedia,
12
- generateMessageID,
13
- generateWAMessage
14
- } from '@ryuu-reinzz/baileys';
15
6
  import {
16
7
  proto
17
8
  } from '../../WAProto/index.js';
@@ -40,12 +31,22 @@ import {
40
31
  parseAndInjectE2ESessions,
41
32
  unixTimestampSeconds
42
33
  } from '../Utils/index.js';
34
+ import {
35
+ generateWAMessageFromContent,
36
+ downloadContentFromMessage,
37
+ prepareWAMessageMedia,
38
+ generateMessageID
39
+ } from '@ryuu-reinzz/baileys';
43
40
  import {
44
41
  getUrlInfo
45
42
  } from '../Utils/link-preview.js';
46
43
  import {
47
44
  makeKeyedMutex
48
45
  } from '../Utils/make-mutex.js';
46
+ import {
47
+ getMessageReportingToken,
48
+ shouldIncludeReportingToken
49
+ } from '../Utils/reporting-utils.js';
49
50
  import {
50
51
  areJidsSameUser,
51
52
  getBinaryNodeChild,
@@ -92,7 +93,7 @@ export const makeMessagesSocket = (config) => {
92
93
  const {
93
94
  ev,
94
95
  authState,
95
- processingMutex,
96
+ messageMutex,
96
97
  signalRepository,
97
98
  upsertMessage,
98
99
  query,
@@ -374,6 +375,29 @@ export const makeMessagesSocket = (config) => {
374
375
  }
375
376
  return deviceResults;
376
377
  };
378
+ /**
379
+ * Update Member Label
380
+ */
381
+ const updateMemberLabel = (jid, memberLabel) => {
382
+ return relayMessage(jid, {
383
+ protocolMessage: {
384
+ type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
385
+ memberLabel: {
386
+ label: memberLabel?.slice(0, 30),
387
+ labelTimestamp: unixTimestampSeconds()
388
+ }
389
+ }
390
+ }, {
391
+ additionalNodes: [{
392
+ tag: 'meta',
393
+ attrs: {
394
+ tag_reason: 'user_update',
395
+ appdata: 'member_tag'
396
+ },
397
+ content: undefined
398
+ }]
399
+ });
400
+ };
377
401
  const assertSessions = async (jids, force) => {
378
402
  let didFetchNewSession = false;
379
403
  const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
@@ -490,59 +514,72 @@ export const makeMessagesSocket = (config) => {
490
514
  recipientJid: jid,
491
515
  message: patchedMessage
492
516
  }) => {
493
- if (!jid)
494
- return null;
495
- let msgToEncrypt = patchedMessage;
496
- if (dsmMessage) {
497
- const {
498
- user: targetUser
499
- } = jidDecode(jid);
500
- const {
501
- user: ownPnUser
502
- } = jidDecode(meId);
503
- const ownLidUser = meLidUser;
504
- const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
505
- const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
506
- if (isOwnUser && !isExactSenderDevice) {
507
- msgToEncrypt = dsmMessage;
508
- logger.debug({
509
- jid,
510
- targetUser
511
- }, 'Using DSM for own device');
512
- }
513
- }
514
- const bytes = encodeWAMessage(msgToEncrypt);
515
- const mutexKey = jid;
516
- const node = await encryptionMutex.mutex(mutexKey, async () => {
517
- const {
518
- type,
519
- ciphertext
520
- } = await signalRepository.encryptMessage({
521
- jid,
522
- data: bytes
523
- });
524
- if (type === 'pkmsg') {
525
- shouldIncludeDeviceIdentity = true;
517
+ try {
518
+ if (!jid)
519
+ return null;
520
+ let msgToEncrypt = patchedMessage;
521
+ if (dsmMessage) {
522
+ const {
523
+ user: targetUser
524
+ } = jidDecode(jid);
525
+ const {
526
+ user: ownPnUser
527
+ } = jidDecode(meId);
528
+ const ownLidUser = meLidUser;
529
+ const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
530
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
531
+ if (isOwnUser && !isExactSenderDevice) {
532
+ msgToEncrypt = dsmMessage;
533
+ logger.debug({
534
+ jid,
535
+ targetUser
536
+ }, 'Using DSM for own device');
537
+ }
526
538
  }
527
- return {
528
- tag: 'to',
529
- attrs: {
530
- jid
531
- },
532
- content: [{
533
- tag: 'enc',
539
+ const bytes = encodeWAMessage(msgToEncrypt);
540
+ const mutexKey = jid;
541
+ const node = await encryptionMutex.mutex(mutexKey, async () => {
542
+ const {
543
+ type,
544
+ ciphertext
545
+ } = await signalRepository.encryptMessage({
546
+ jid,
547
+ data: bytes
548
+ });
549
+ if (type === 'pkmsg') {
550
+ shouldIncludeDeviceIdentity = true;
551
+ }
552
+ return {
553
+ tag: 'to',
534
554
  attrs: {
535
- v: '2',
536
- type,
537
- ...(extraAttrs || {})
555
+ jid
538
556
  },
539
- content: ciphertext
540
- }]
541
- };
542
- });
543
- return node;
557
+ content: [{
558
+ tag: 'enc',
559
+ attrs: {
560
+ v: '2',
561
+ type,
562
+ ...(extraAttrs || {})
563
+ },
564
+ content: ciphertext
565
+ }]
566
+ };
567
+ });
568
+ return node;
569
+ } catch (err) {
570
+ logger.error({
571
+ jid,
572
+ err
573
+ }, 'Failed to encrypt for recipient');
574
+ return null;
575
+ }
544
576
  });
545
577
  const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
578
+ if (recipientJids.length > 0 && nodes.length === 0) {
579
+ throw new Boom('All encryptions failed', {
580
+ statusCode: 500
581
+ });
582
+ }
546
583
  return {
547
584
  nodes,
548
585
  shouldIncludeDeviceIdentity
@@ -579,6 +616,7 @@ export const makeMessagesSocket = (config) => {
579
616
  const destinationJid = !isStatus ? finalJid : statusJid;
580
617
  const binaryNodeContent = [];
581
618
  const devices = [];
619
+ let reportingMessage;
582
620
  const meMsg = {
583
621
  deviceSentMessage: {
584
622
  destinationJid,
@@ -633,7 +671,7 @@ export const makeMessagesSocket = (config) => {
633
671
  await sendNode(stanza);
634
672
  return;
635
673
  }
636
- if (normalizeMessageContent(message)?.pinInChatMessage) {
674
+ if (normalizeMessageContent(message)?.pinInChatMessage || normalizeMessageContent(message)?.reactionMessage) {
637
675
  extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
638
676
  }
639
677
  if (isGroupOrStatus && !isRetryResend) {
@@ -683,6 +721,7 @@ export const makeMessagesSocket = (config) => {
683
721
  throw new Boom('Per-jid patching is not supported in groups');
684
722
  }
685
723
  const bytes = encodeWAMessage(patched);
724
+ reportingMessage = patched;
686
725
  const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
687
726
  const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
688
727
  const {
@@ -756,6 +795,12 @@ export const makeMessagesSocket = (config) => {
756
795
  const {
757
796
  user: ownUser
758
797
  } = jidDecode(ownId);
798
+ if (!participant) {
799
+ const patchedForReporting = await patchMessageBeforeSending(message, [jid]);
800
+ reportingMessage = Array.isArray(patchedForReporting) ?
801
+ patchedForReporting.find(item => item.recipientJid === jid) || patchedForReporting[0] :
802
+ patchedForReporting;
803
+ }
759
804
  if (!isRetryResend) {
760
805
  const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
761
806
  devices.push({
@@ -920,6 +965,33 @@ export const makeMessagesSocket = (config) => {
920
965
  jid
921
966
  }, 'adding device identity');
922
967
  }
968
+ if (!isNewsletter &&
969
+ !isRetryResend &&
970
+ reportingMessage?.messageContextInfo?.messageSecret &&
971
+ shouldIncludeReportingToken(reportingMessage)) {
972
+ try {
973
+ const encoded = encodeWAMessage(reportingMessage);
974
+ const reportingKey = {
975
+ id: msgId,
976
+ fromMe: true,
977
+ remoteJid: destinationJid,
978
+ participant: participant?.jid
979
+ };
980
+ const reportingNode = await getMessageReportingToken(encoded, reportingMessage, reportingKey);
981
+ if (reportingNode) {
982
+ ;
983
+ stanza.content.push(reportingNode);
984
+ logger.trace({
985
+ jid
986
+ }, 'added reporting token to message');
987
+ }
988
+ } catch (error) {
989
+ logger.warn({
990
+ jid,
991
+ trace: error?.stack
992
+ }, 'failed to attach reporting token');
993
+ }
994
+ }
923
995
  const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {};
924
996
  const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
925
997
  if (tcTokenBuffer) {
@@ -946,13 +1018,22 @@ export const makeMessagesSocket = (config) => {
946
1018
  return msgId;
947
1019
  };
948
1020
  const getMessageType = (message) => {
949
- if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
1021
+ const normalizedMessage = normalizeMessageContent(message);
1022
+ if (!normalizedMessage)
1023
+ return 'text';
1024
+ if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) {
1025
+ return 'reaction';
1026
+ }
1027
+ if (normalizedMessage.pollCreationMessage ||
1028
+ normalizedMessage.pollCreationMessageV2 ||
1029
+ normalizedMessage.pollCreationMessageV3 ||
1030
+ normalizedMessage.pollUpdateMessage) {
950
1031
  return 'poll';
951
1032
  }
952
- if (message.eventMessage) {
1033
+ if (normalizedMessage.eventMessage) {
953
1034
  return 'event';
954
1035
  }
955
- if (getMediaType(message) !== '') {
1036
+ if (getMediaType(normalizedMessage) !== '') {
956
1037
  return 'media';
957
1038
  }
958
1039
  return 'text';
@@ -1016,27 +1097,28 @@ export const makeMessagesSocket = (config) => {
1016
1097
  return result;
1017
1098
  };
1018
1099
  const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
1019
- const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
1100
+ const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
1101
+ sock.waUploadToServer = waUploadToServer;
1102
+ sock.relayMessage = relayMessage;
1020
1103
  return {
1021
1104
  ...sock,
1022
1105
  getPrivacyTokens,
1023
1106
  assertSessions,
1024
- relayMessage,
1025
1107
  sendReceipt,
1026
1108
  sendReceipts,
1027
1109
  readMessages,
1028
1110
  refreshMediaConn,
1029
- waUploadToServer,
1030
1111
  fetchPrivacySettings,
1031
1112
  sendPeerDataOperationMessage,
1032
1113
  createParticipantNodes,
1033
1114
  getUSyncDevices,
1034
1115
  messageRetryManager,
1116
+ updateMemberLabel,
1035
1117
  updateMediaMessage: async (message) => {
1036
1118
  const content = assertMediaContent(message.message);
1037
1119
  const mediaKey = content.mediaKey;
1038
1120
  const meId = authState.creds.me.id;
1039
- const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
1121
+ const node = encryptMediaRetryRequest(message.key, mediaKey, meId);
1040
1122
  let error = undefined;
1041
1123
  await Promise.all([
1042
1124
  sendNode(node),
@@ -1047,7 +1129,7 @@ export const makeMessagesSocket = (config) => {
1047
1129
  error = result.error;
1048
1130
  } else {
1049
1131
  try {
1050
- const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id);
1132
+ const media = decryptMediaRetryData(result.media, mediaKey, result.key.id);
1051
1133
  if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
1052
1134
  const resultStr = proto.MediaRetryNotification.ResultType[media.result];
1053
1135
  throw new Boom(`Media re-upload failed by device (${resultStr})`, {
@@ -1081,92 +1163,92 @@ export const makeMessagesSocket = (config) => {
1081
1163
  return message;
1082
1164
  },
1083
1165
  sendMessage: async (jid, content, options = {}) => {
1084
- if (Array.isArray(content.buttons)) {
1085
- await sock.sendButton(jid, content = {}, options = {});
1086
- } else {
1087
- const userJid = authState.creds.me.id;
1088
- if (typeof content === 'object' &&
1089
- 'disappearingMessagesInChat' in content &&
1090
- typeof content['disappearingMessagesInChat'] !== 'undefined' &&
1091
- isJidGroup(jid)) {
1092
- const {
1093
- disappearingMessagesInChat
1094
- } = content;
1095
- const value = typeof disappearingMessagesInChat === 'boolean' ?
1096
- disappearingMessagesInChat ?
1097
- WA_DEFAULT_EPHEMERAL :
1098
- 0 :
1099
- disappearingMessagesInChat;
1100
- await groupToggleEphemeral(jid, value);
1166
+ if (Array.isArray(content.buttons)) {
1167
+ return await sock.sendButton(jid, content, options);
1101
1168
  } else {
1102
- const fullMsg = await generateWAMessage(jid, content, {
1169
+ const userJid = authState.creds.me.id;
1170
+ if (typeof content === 'object' &&
1171
+ 'disappearingMessagesInChat' in content &&
1172
+ typeof content['disappearingMessagesInChat'] !== 'undefined' &&
1173
+ isJidGroup(jid)) {
1174
+ const {
1175
+ disappearingMessagesInChat
1176
+ } = content;
1177
+ const value = typeof disappearingMessagesInChat === 'boolean' ?
1178
+ disappearingMessagesInChat ?
1179
+ WA_DEFAULT_EPHEMERAL :
1180
+ 0 :
1181
+ disappearingMessagesInChat;
1182
+ await groupToggleEphemeral(jid, value);
1183
+ } else {
1184
+ const fullMsg = await generateWAMessage(jid, content, {
1185
+ logger,
1186
+ userJid,
1187
+ getUrlInfo: text => getUrlInfo(text, {
1188
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1189
+ fetchOpts: {
1190
+ timeout: 3000,
1191
+ ...(httpRequestOptions || {})
1192
+ },
1103
1193
  logger,
1104
- userJid,
1105
- getUrlInfo: text => getUrlInfo(text, {
1106
- thumbnailWidth: linkPreviewImageThumbnailWidth,
1107
- fetchOpts: {
1108
- timeout: 3000,
1109
- ...(httpRequestOptions || {})
1110
- },
1111
- logger,
1112
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1113
- }),
1114
- //TODO: CACHE
1115
- getProfilePicUrl: sock.profilePictureUrl,
1116
- getCallLink: sock.createCallLink,
1117
- upload: waUploadToServer,
1118
- mediaCache: config.mediaCache,
1119
- options: config.options,
1120
- messageId: generateMessageIDV2(sock.user?.id),
1121
- ...options
1194
+ uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1195
+ }),
1196
+ //TODO: CACHE
1197
+ getProfilePicUrl: sock.profilePictureUrl,
1198
+ getCallLink: sock.createCallLink,
1199
+ upload: waUploadToServer,
1200
+ mediaCache: config.mediaCache,
1201
+ options: config.options,
1202
+ messageId: generateMessageIDV2(sock.user?.id),
1203
+ ...options
1204
+ });
1205
+ const isEventMsg = 'event' in content && !!content.event;
1206
+ const isDeleteMsg = 'delete' in content && !!content.delete;
1207
+ const isEditMsg = 'edit' in content && !!content.edit;
1208
+ const isPinMsg = 'pin' in content && !!content.pin;
1209
+ const isPollMessage = 'poll' in content && !!content.poll;
1210
+ const additionalAttributes = {};
1211
+ const additionalNodes = [];
1212
+ // required for delete
1213
+ if (isDeleteMsg) {
1214
+ // if the chat is a group, and I am not the author, then delete the message as an admin
1215
+ if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
1216
+ additionalAttributes.edit = '8';
1217
+ } else {
1218
+ additionalAttributes.edit = '7';
1219
+ }
1220
+ } else if (isEditMsg) {
1221
+ additionalAttributes.edit = '1';
1222
+ } else if (isPinMsg) {
1223
+ additionalAttributes.edit = '2';
1224
+ } else if (isPollMessage) {
1225
+ additionalNodes.push({
1226
+ tag: 'meta',
1227
+ attrs: {
1228
+ polltype: 'creation'
1229
+ }
1122
1230
  });
1123
- const isEventMsg = 'event' in content && !!content.event;
1124
- const isDeleteMsg = 'delete' in content && !!content.delete;
1125
- const isEditMsg = 'edit' in content && !!content.edit;
1126
- const isPinMsg = 'pin' in content && !!content.pin;
1127
- const isPollMessage = 'poll' in content && !!content.poll;
1128
- const additionalAttributes = {};
1129
- const additionalNodes = [];
1130
- // required for delete
1131
- if (isDeleteMsg) {
1132
- // if the chat is a group, and I am not the author, then delete the message as an admin
1133
- if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
1134
- additionalAttributes.edit = '8';
1135
- } else {
1136
- additionalAttributes.edit = '7';
1231
+ } else if (isEventMsg) {
1232
+ additionalNodes.push({
1233
+ tag: 'meta',
1234
+ attrs: {
1235
+ event_type: 'creation'
1137
1236
  }
1138
- } else if (isEditMsg) {
1139
- additionalAttributes.edit = '1';
1140
- } else if (isPinMsg) {
1141
- additionalAttributes.edit = '2';
1142
- } else if (isPollMessage) {
1143
- additionalNodes.push({
1144
- tag: 'meta',
1145
- attrs: {
1146
- polltype: 'creation'
1147
- }
1148
- });
1149
- } else if (isEventMsg) {
1150
- additionalNodes.push({
1151
- tag: 'meta',
1152
- attrs: {
1153
- event_type: 'creation'
1154
- }
1155
- });
1156
- }
1157
- await relayMessage(jid, fullMsg.message, {
1158
- messageId: fullMsg.key.id,
1159
- useCachedGroupMetadata: options.useCachedGroupMetadata,
1160
- additionalAttributes,
1161
- statusJidList: options.statusJidList,
1162
- additionalNodes
1163
1237
  });
1164
- if (config.emitOwnEvents) {
1165
- process.nextTick(async () => {
1166
- await processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1167
- });
1168
- }
1169
- return fullMsg;
1238
+ }
1239
+ await relayMessage(jid, fullMsg.message, {
1240
+ messageId: fullMsg.key.id,
1241
+ useCachedGroupMetadata: options.useCachedGroupMetadata,
1242
+ additionalAttributes,
1243
+ statusJidList: options.statusJidList,
1244
+ additionalNodes
1245
+ });
1246
+ if (config.emitOwnEvents) {
1247
+ process.nextTick(async () => {
1248
+ await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1249
+ });
1250
+ }
1251
+ return fullMsg;
1170
1252
  }
1171
1253
  }
1172
1254
  }