@d0v3riz/baileys 6.7.2 → 6.7.5

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 (41) hide show
  1. package/README.md +4 -3
  2. package/lib/Defaults/baileys-version.json +1 -1
  3. package/lib/Socket/business.d.ts +2 -0
  4. package/lib/Socket/business.js +1 -0
  5. package/lib/Socket/chats.d.ts +5 -6
  6. package/lib/Socket/chats.js +7 -2
  7. package/lib/Socket/groups.d.ts +1 -0
  8. package/lib/Socket/groups.js +2 -1
  9. package/lib/Socket/index.d.ts +2 -0
  10. package/lib/Socket/messages-recv.d.ts +1 -0
  11. package/lib/Socket/messages-recv.js +32 -15
  12. package/lib/Socket/messages-send.d.ts +1 -0
  13. package/lib/Socket/messages-send.js +8 -3
  14. package/lib/Socket/registration.d.ts +2 -0
  15. package/lib/Socket/socket.js +16 -3
  16. package/lib/Store/make-in-memory-store.d.ts +2 -2
  17. package/lib/Store/make-in-memory-store.js +6 -43
  18. package/lib/Types/Auth.d.ts +1 -0
  19. package/lib/Types/Chat.d.ts +1 -0
  20. package/lib/Types/Events.d.ts +8 -1
  21. package/lib/Types/GroupMetadata.d.ts +3 -1
  22. package/lib/Types/index.d.ts +7 -0
  23. package/lib/Utils/auth-utils.js +1 -0
  24. package/lib/Utils/crypto.d.ts +1 -1
  25. package/lib/Utils/crypto.js +4 -2
  26. package/lib/Utils/generics.d.ts +4 -9
  27. package/lib/Utils/generics.js +34 -8
  28. package/lib/Utils/messages-media.d.ts +1 -0
  29. package/lib/Utils/messages-media.js +8 -14
  30. package/lib/Utils/messages.d.ts +2 -1
  31. package/lib/Utils/messages.js +9 -7
  32. package/lib/Utils/noise-handler.d.ts +3 -2
  33. package/lib/Utils/noise-handler.js +18 -5
  34. package/lib/Utils/process-message.js +15 -2
  35. package/lib/Utils/signal.js +26 -16
  36. package/lib/Utils/use-multi-file-auth-state.js +16 -3
  37. package/lib/WABinary/decode.d.ts +2 -2
  38. package/lib/WABinary/decode.js +6 -4
  39. package/lib/WABinary/encode.d.ts +1 -1
  40. package/lib/WABinary/encode.js +8 -4
  41. package/package.json +9 -7
@@ -2,16 +2,10 @@
2
2
  import { AxiosRequestConfig } from 'axios';
3
3
  import { Logger } from 'pino';
4
4
  import { proto } from '../../WAProto';
5
- import { BaileysEventEmitter, BaileysEventMap, WACallUpdateType, WAVersion } from '../Types';
5
+ import { BaileysEventEmitter, BaileysEventMap, BrowsersMap, WACallUpdateType, WAVersion } from '../Types';
6
6
  import { BinaryNode } from '../WABinary';
7
- export declare const Browsers: {
8
- ubuntu: (browser: any) => [string, string, string];
9
- macOS: (browser: any) => [string, string, string];
10
- baileys: (browser: any) => [string, string, string];
11
- windows: (browser: any) => [string, string, string];
12
- /** The appropriate browser based on your OS & release */
13
- appropriate: (browser: any) => [string, string, string];
14
- };
7
+ export declare const Browsers: BrowsersMap;
8
+ export declare const getPlatformId: (browser: string) => any;
15
9
  export declare const BufferJSON: {
16
10
  replacer: (k: any, value: any) => any;
17
11
  reviver: (_: any, value: any) => any;
@@ -38,6 +32,7 @@ export declare const delayCancellable: (ms: number) => {
38
32
  cancel: () => void;
39
33
  };
40
34
  export declare function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v: T) => void, reject: (error: any) => void) => void): Promise<T>;
35
+ export declare const generateMessageIDV2: (userId?: string) => string;
41
36
  export declare const generateMessageID: () => string;
42
37
  export declare function bindWaitForEvent<T extends keyof BaileysEventMap>(ev: BaileysEventEmitter, event: T): (check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => Promise<void>;
43
38
  export declare const bindWaitForConnectionUpdate: (ev: BaileysEventEmitter) => (check: (u: Partial<import("../Types").ConnectionState>) => boolean | undefined, timeoutMs?: number) => Promise<void>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.Browsers = void 0;
6
+ exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.generateMessageIDV2 = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const crypto_1 = require("crypto");
@@ -16,16 +16,24 @@ const PLATFORM_MAP = {
16
16
  'aix': 'AIX',
17
17
  'darwin': 'Mac OS',
18
18
  'win32': 'Windows',
19
- 'android': 'Android'
19
+ 'android': 'Android',
20
+ 'freebsd': 'FreeBSD',
21
+ 'openbsd': 'OpenBSD',
22
+ 'sunos': 'Solaris'
20
23
  };
21
24
  exports.Browsers = {
22
- ubuntu: browser => ['Ubuntu', browser, '20.0.04'],
23
- macOS: browser => ['Mac OS', browser, '10.15.7'],
24
- baileys: browser => ['Baileys', browser, '4.0.0'],
25
- windows: browser => ['Windows', browser, '10.0.22621'],
25
+ ubuntu: (browser) => ['Ubuntu', browser, '22.04.4'],
26
+ macOS: (browser) => ['Mac OS', browser, '14.4.1'],
27
+ baileys: (browser) => ['Baileys', browser, '6.5.0'],
28
+ windows: (browser) => ['Windows', browser, '10.0.22631'],
26
29
  /** The appropriate browser based on your OS & release */
27
- appropriate: browser => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
30
+ appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
28
31
  };
32
+ const getPlatformId = (browser) => {
33
+ const platformType = WAProto_1.proto.DeviceProps.PlatformType[browser.toUpperCase()];
34
+ return platformType ? platformType.toString().charCodeAt(0).toString() : '49'; //chrome
35
+ };
36
+ exports.getPlatformId = getPlatformId;
29
37
  exports.BufferJSON = {
30
38
  replacer: (k, value) => {
31
39
  if (Buffer.isBuffer(value) || value instanceof Uint8Array || (value === null || value === void 0 ? void 0 : value.type) === 'Buffer') {
@@ -147,8 +155,26 @@ async function promiseTimeout(ms, promise) {
147
155
  return p;
148
156
  }
149
157
  exports.promiseTimeout = promiseTimeout;
158
+ // inspired from whatsmeow code
159
+ // https://github.com/tulir/whatsmeow/blob/64bc969fbe78d31ae0dd443b8d4c80a5d026d07a/send.go#L42
160
+ const generateMessageIDV2 = (userId) => {
161
+ const data = Buffer.alloc(8 + 20 + 16);
162
+ data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
163
+ if (userId) {
164
+ const id = (0, WABinary_1.jidDecode)(userId);
165
+ if (id === null || id === void 0 ? void 0 : id.user) {
166
+ data.write(id.user, 8);
167
+ data.write('@c.us', 8 + id.user.length);
168
+ }
169
+ }
170
+ const random = (0, crypto_1.randomBytes)(16);
171
+ random.copy(data, 28);
172
+ const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
173
+ return (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + hash.toString('hex').toUpperCase().substring(0, 18);
174
+ };
175
+ exports.generateMessageIDV2 = generateMessageIDV2;
150
176
  // generate a random ID to attach to a message
151
- const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(6).toString('hex').toUpperCase();
177
+ const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
152
178
  exports.generateMessageID = generateMessageID;
153
179
  function bindWaitForEvent(ev, event) {
154
180
  return async (check, timeoutMs) => {
@@ -93,6 +93,7 @@ export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logg
93
93
  export declare const encryptMediaRetryRequest: (key: proto.IMessageKey, mediaKey: Buffer | Uint8Array, meId: string) => BinaryNode;
94
94
  export declare const decodeMediaRetryNode: (node: BinaryNode) => {
95
95
  key: proto.IMessageKey;
96
+ /** generates all the keys required to encrypt/decrypt & sign a media message */
96
97
  media?: {
97
98
  ciphertext: Uint8Array;
98
99
  iv: Uint8Array;
@@ -22,9 +22,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.getHttpStream = exports.generateThumbnail = exports.getStream = exports.toBuffer = exports.toReadable = exports.getAudioWaveform = exports.getAudioDuration = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.getMediaKeys = exports.hkdfInfoKey = void 0;
27
30
  const boom_1 = require("@hapi/boom");
31
+ const axios_1 = __importDefault(require("axios"));
28
32
  const child_process_1 = require("child_process");
29
33
  const Crypto = __importStar(require("crypto"));
30
34
  const events_1 = require("events");
@@ -313,8 +317,7 @@ async function generateThumbnail(file, mediaType, options) {
313
317
  }
314
318
  exports.generateThumbnail = generateThumbnail;
315
319
  const getHttpStream = async (url, options = {}) => {
316
- const { default: axios } = await import('axios');
317
- const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
320
+ const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
318
321
  return fetched.data;
319
322
  };
320
323
  exports.getHttpStream = getHttpStream;
@@ -525,27 +528,18 @@ exports.extensionForMediaMessage = extensionForMediaMessage;
525
528
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
526
529
  return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
527
530
  var _a, _b;
528
- const { default: axios } = await import('axios');
529
531
  // send a query JSON to obtain the url & auth token to upload our media
530
532
  let uploadInfo = await refreshMediaConn(false);
531
533
  let urls;
532
534
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
533
- const chunks = [];
534
- for await (const chunk of stream) {
535
- chunks.push(chunk);
536
- }
537
- const reqBody = Buffer.concat(chunks);
538
535
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
539
- for (const { hostname, maxContentLengthBytes } of hosts) {
536
+ for (const { hostname } of hosts) {
540
537
  logger.debug(`uploading to "${hostname}"`);
541
538
  const auth = encodeURIComponent(uploadInfo.auth); // the auth token
542
539
  const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
543
540
  let result;
544
541
  try {
545
- if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
546
- throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
547
- }
548
- const body = await axios.post(url, reqBody, {
542
+ const body = await axios_1.default.post(url, stream, {
549
543
  ...options,
550
544
  headers: {
551
545
  ...options.headers || {},
@@ -572,7 +566,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
572
566
  }
573
567
  }
574
568
  catch (error) {
575
- if (axios.isAxiosError(error)) {
569
+ if (axios_1.default.isAxiosError(error)) {
576
570
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
577
571
  }
578
572
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import { Logger } from 'pino';
4
+ import { type Transform } from 'stream';
4
5
  import { proto } from '../../WAProto';
5
6
  import { AnyMediaMessageContent, AnyMessageContent, MediaGenerationOptions, MessageContentGenerationOptions, MessageGenerationOptions, MessageGenerationOptionsFromContent, MessageUserReceipt, WAMessage, WAMessageContent, WAProto } from '../Types';
6
7
  import { MediaDownloadOptions } from './messages-media';
@@ -70,7 +71,7 @@ type DownloadMediaMessageContext = {
70
71
  /**
71
72
  * Downloads the given message. Throws an error if it's not a media message
72
73
  */
73
- export declare const downloadMediaMessage: (message: WAMessage, type: 'buffer' | 'stream', options: MediaDownloadOptions, ctx?: DownloadMediaMessageContext) => Promise<Buffer | import("stream").Transform>;
74
+ export declare const downloadMediaMessage: <Type extends "stream" | "buffer">(message: WAMessage, type: Type, options: MediaDownloadOptions, ctx?: DownloadMediaMessageContext) => Promise<Type extends "buffer" ? Buffer : Transform>;
74
75
  /** Checks whether the given message is a media message; if it is returns the inner content */
75
76
  export declare const assertMediaContent: (content: proto.IMessage | null | undefined) => proto.Message.IVideoMessage | proto.Message.IImageMessage | proto.Message.IAudioMessage | proto.Message.IDocumentMessage | proto.Message.IStickerMessage;
76
77
  export {};
@@ -326,6 +326,10 @@ const generateWAMessageContent = async (message, options) => {
326
326
  break;
327
327
  }
328
328
  }
329
+ else if ('ptv' in message && message.ptv) {
330
+ const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
331
+ m.ptvMessage = videoMessage;
332
+ }
329
333
  else if ('product' in message) {
330
334
  const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
331
335
  m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
@@ -706,12 +710,9 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404];
706
710
  * Downloads the given message. Throws an error if it's not a media message
707
711
  */
708
712
  const downloadMediaMessage = async (message, type, options, ctx) => {
709
- var _a;
710
- try {
711
- const result = await downloadMsg();
712
- return result;
713
- }
714
- catch (error) {
713
+ const result = await downloadMsg()
714
+ .catch(async (error) => {
715
+ var _a;
715
716
  if (ctx) {
716
717
  if (axios_1.default.isAxiosError(error)) {
717
718
  // check if the message requires a reupload
@@ -725,7 +726,8 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
725
726
  }
726
727
  }
727
728
  throw error;
728
- }
729
+ });
730
+ return result;
729
731
  async function downloadMsg() {
730
732
  const mContent = (0, exports.extractMessageContent)(message.message);
731
733
  if (!mContent) {
@@ -3,11 +3,12 @@ import { Logger } from 'pino';
3
3
  import { proto } from '../../WAProto';
4
4
  import { KeyPair } from '../Types';
5
5
  import { BinaryNode } from '../WABinary';
6
- export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, }: {
6
+ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }: {
7
7
  keyPair: KeyPair;
8
8
  NOISE_HEADER: Uint8Array;
9
9
  mobile: boolean;
10
10
  logger: Logger;
11
+ routingInfo?: Buffer | undefined;
11
12
  }) => {
12
13
  encrypt: (plaintext: Uint8Array) => Buffer;
13
14
  decrypt: (ciphertext: Uint8Array) => Buffer;
@@ -16,5 +17,5 @@ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public
16
17
  finishInit: () => void;
17
18
  processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => Buffer;
18
19
  encodeFrame: (data: Buffer | Uint8Array) => Buffer;
19
- decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => void;
20
+ decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => Promise<void>;
20
21
  };
@@ -11,7 +11,7 @@ const generateIV = (counter) => {
11
11
  new DataView(iv).setUint32(8, counter);
12
12
  return new Uint8Array(iv);
13
13
  };
14
- const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, }) => {
14
+ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }) => {
15
15
  logger = logger.child({ class: 'ns' });
16
16
  const authenticate = (data) => {
17
17
  if (!isFinished) {
@@ -101,10 +101,23 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
101
101
  if (isFinished) {
102
102
  data = encrypt(data);
103
103
  }
104
- const introSize = sentIntro ? 0 : NOISE_HEADER.length;
104
+ let header;
105
+ if (routingInfo) {
106
+ header = Buffer.alloc(7);
107
+ header.write('ED', 0, 'utf8');
108
+ header.writeUint8(0, 2);
109
+ header.writeUint8(1, 3);
110
+ header.writeUint8(routingInfo.byteLength >> 16, 4);
111
+ header.writeUint16BE(routingInfo.byteLength & 65535, 5);
112
+ header = Buffer.concat([header, routingInfo, NOISE_HEADER]);
113
+ }
114
+ else {
115
+ header = Buffer.from(NOISE_HEADER);
116
+ }
117
+ const introSize = sentIntro ? 0 : header.length;
105
118
  const frame = Buffer.alloc(introSize + 3 + data.byteLength);
106
119
  if (!sentIntro) {
107
- frame.set(NOISE_HEADER);
120
+ frame.set(header);
108
121
  sentIntro = true;
109
122
  }
110
123
  frame.writeUInt8(data.byteLength >> 16, introSize);
@@ -112,7 +125,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
112
125
  frame.set(data, introSize + 3);
113
126
  return frame;
114
127
  },
115
- decodeFrame: (newData, onFrame) => {
128
+ decodeFrame: async (newData, onFrame) => {
116
129
  var _a;
117
130
  // the binary protocol uses its own framing mechanism
118
131
  // on top of the WS frames
@@ -130,7 +143,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
130
143
  inBytes = inBytes.slice(size + 3);
131
144
  if (isFinished) {
132
145
  const result = decrypt(frame);
133
- frame = (0, WABinary_1.decodeBinaryNode)(result);
146
+ frame = await (0, WABinary_1.decodeBinaryNode)(result);
134
147
  }
135
148
  logger.trace({ msg: (_a = frame === null || frame === void 0 ? void 0 : frame.attrs) === null || _a === void 0 ? void 0 : _a.id }, 'recv frame');
136
149
  onFrame(frame);
@@ -103,7 +103,7 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
103
103
  }
104
104
  exports.decryptPollVote = decryptPollVote;
105
105
  const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, keyStore, logger, options, getMessage }) => {
106
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
107
107
  const meId = creds.me.id;
108
108
  const { accountSettings } = creds;
109
109
  const chat = { id: (0, WABinary_1.jidNormalizedUser)((0, exports.getChatId)(message.key)) };
@@ -220,8 +220,15 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
220
220
  var _a;
221
221
  ev.emit('groups.update', [{ id: jid, ...update, author: (_a = message.participant) !== null && _a !== void 0 ? _a : undefined }]);
222
222
  };
223
+ const emitGroupRequestJoin = (participant, action, method) => {
224
+ ev.emit('group.join-request', { id: jid, author: message.participant, participant, action, method: method });
225
+ };
223
226
  const participantsIncludesMe = () => participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid));
224
227
  switch (message.messageStubType) {
228
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
229
+ participants = message.messageStubParameters || [];
230
+ emitParticipantsUpdate('modify');
231
+ break;
225
232
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
226
233
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
227
234
  participants = message.messageStubParameters || [];
@@ -273,6 +280,12 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
273
280
  const approvalMode = (_j = message.messageStubParameters) === null || _j === void 0 ? void 0 : _j[0];
274
281
  emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' });
275
282
  break;
283
+ case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
284
+ const participant = (_k = message.messageStubParameters) === null || _k === void 0 ? void 0 : _k[0];
285
+ const action = (_l = message.messageStubParameters) === null || _l === void 0 ? void 0 : _l[1];
286
+ const method = (_m = message.messageStubParameters) === null || _m === void 0 ? void 0 : _m[2];
287
+ emitGroupRequestJoin(participant, action, method);
288
+ break;
276
289
  }
277
290
  }
278
291
  else if (content === null || content === void 0 ? void 0 : content.pollUpdateMessage) {
@@ -283,7 +296,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
283
296
  const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId);
284
297
  const pollCreatorJid = (0, generics_1.getKeyAuthor)(creationMsgKey, meIdNormalised);
285
298
  const voterJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised);
286
- const pollEncKey = (_k = pollMsg.messageContextInfo) === null || _k === void 0 ? void 0 : _k.messageSecret;
299
+ const pollEncKey = (_o = pollMsg.messageContextInfo) === null || _o === void 0 ? void 0 : _o.messageSecret;
287
300
  try {
288
301
  const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
289
302
  pollEncKey,
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNextPreKeysNode = exports.getNextPreKeys = exports.extractDeviceJids = exports.parseAndInjectE2ESessions = exports.xmppPreKey = exports.xmppSignedPreKey = exports.generateOrGetPreKeys = exports.getPreKeys = exports.createSignalIdentity = void 0;
4
+ const lodash_1 = require("lodash");
4
5
  const Defaults_1 = require("../Defaults");
5
6
  const WABinary_1 = require("../WABinary");
6
7
  const crypto_1 = require("./crypto");
@@ -66,22 +67,31 @@ const parseAndInjectE2ESessions = async (node, repository) => {
66
67
  for (const node of nodes) {
67
68
  (0, WABinary_1.assertNodeErrorFree)(node);
68
69
  }
69
- await Promise.all(nodes.map(async (node) => {
70
- const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey');
71
- const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key');
72
- const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity');
73
- const jid = node.attrs.jid;
74
- const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4);
75
- await repository.injectE2ESession({
76
- jid,
77
- session: {
78
- registrationId: registrationId,
79
- identityKey: (0, crypto_1.generateSignalPubKey)(identity),
80
- signedPreKey: extractKey(signedKey),
81
- preKey: extractKey(key)
82
- }
83
- });
84
- }));
70
+ // Most of the work in repository.injectE2ESession is CPU intensive, not IO
71
+ // So Promise.all doesn't really help here,
72
+ // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
73
+ // This way we chunk it in smaller parts and between those parts we can yield to the event loop
74
+ // It's rare case when you need to E2E sessions for so many users, but it's possible
75
+ const chunkSize = 100;
76
+ const chunks = (0, lodash_1.chunk)(nodes, chunkSize);
77
+ for (const nodesChunk of chunks) {
78
+ await Promise.all(nodesChunk.map(async (node) => {
79
+ const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey');
80
+ const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key');
81
+ const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity');
82
+ const jid = node.attrs.jid;
83
+ const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4);
84
+ await repository.injectE2ESession({
85
+ jid,
86
+ session: {
87
+ registrationId: registrationId,
88
+ identityKey: (0, crypto_1.generateSignalPubKey)(identity),
89
+ signedPreKey: extractKey(signedKey),
90
+ preKey: extractKey(key)
91
+ }
92
+ });
93
+ }));
94
+ }
85
95
  };
86
96
  exports.parseAndInjectE2ESessions = parseAndInjectE2ESessions;
87
97
  const extractDeviceJids = (result, myJid, excludeZeroDevices) => {
@@ -1,11 +1,21 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.useMultiFileAuthState = void 0;
7
+ const async_lock_1 = __importDefault(require("async-lock"));
4
8
  const promises_1 = require("fs/promises");
5
9
  const path_1 = require("path");
6
10
  const WAProto_1 = require("../../WAProto");
7
11
  const auth_utils_1 = require("./auth-utils");
8
12
  const generics_1 = require("./generics");
13
+ // We need to lock files due to the fact that we are using async functions to read and write files
14
+ // https://github.com/WhiskeySockets/Baileys/issues/794
15
+ // https://github.com/nodejs/node/issues/26338
16
+ // Default pending is 1000, set it to infinity
17
+ // https://github.com/rogierschouten/async-lock/issues/63
18
+ const fileLock = new async_lock_1.default({ maxPending: Infinity });
9
19
  /**
10
20
  * stores the full authentication state in a single folder.
11
21
  * Far more efficient than singlefileauthstate
@@ -15,11 +25,13 @@ const generics_1 = require("./generics");
15
25
  * */
16
26
  const useMultiFileAuthState = async (folder) => {
17
27
  const writeData = (data, file) => {
18
- return (0, promises_1.writeFile)((0, path_1.join)(folder, fixFileName(file)), JSON.stringify(data, generics_1.BufferJSON.replacer));
28
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
29
+ return fileLock.acquire(filePath, () => (0, promises_1.writeFile)((0, path_1.join)(filePath), JSON.stringify(data, generics_1.BufferJSON.replacer)));
19
30
  };
20
31
  const readData = async (file) => {
21
32
  try {
22
- const data = await (0, promises_1.readFile)((0, path_1.join)(folder, fixFileName(file)), { encoding: 'utf-8' });
33
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
34
+ const data = await fileLock.acquire(filePath, () => (0, promises_1.readFile)(filePath, { encoding: 'utf-8' }));
23
35
  return JSON.parse(data, generics_1.BufferJSON.reviver);
24
36
  }
25
37
  catch (error) {
@@ -28,7 +40,8 @@ const useMultiFileAuthState = async (folder) => {
28
40
  };
29
41
  const removeData = async (file) => {
30
42
  try {
31
- await (0, promises_1.unlink)((0, path_1.join)(folder, fixFileName(file)));
43
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
44
+ await fileLock.acquire(filePath, () => (0, promises_1.unlink)(filePath));
32
45
  }
33
46
  catch (_a) {
34
47
  }
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import type { BinaryNode, BinaryNodeCodingOptions } from './types';
3
- export declare const decompressingIfRequired: (buffer: Buffer) => Buffer;
3
+ export declare const decompressingIfRequired: (buffer: Buffer) => Promise<Buffer>;
4
4
  export declare const decodeDecompressedBinaryNode: (buffer: Buffer, opts: Pick<BinaryNodeCodingOptions, 'DOUBLE_BYTE_TOKENS' | 'SINGLE_BYTE_TOKENS' | 'TAGS'>, indexRef?: {
5
5
  index: number;
6
6
  }) => BinaryNode;
7
- export declare const decodeBinaryNode: (buff: Buffer) => BinaryNode;
7
+ export declare const decodeBinaryNode: (buff: Buffer) => Promise<BinaryNode>;
@@ -24,12 +24,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.decodeBinaryNode = exports.decodeDecompressedBinaryNode = exports.decompressingIfRequired = void 0;
27
+ const util_1 = require("util");
27
28
  const zlib_1 = require("zlib");
28
29
  const constants = __importStar(require("./constants"));
29
30
  const jid_utils_1 = require("./jid-utils");
30
- const decompressingIfRequired = (buffer) => {
31
+ const inflatePromise = (0, util_1.promisify)(zlib_1.inflate);
32
+ const decompressingIfRequired = async (buffer) => {
31
33
  if (2 & buffer.readUInt8()) {
32
- buffer = (0, zlib_1.inflateSync)(buffer.slice(1));
34
+ buffer = await inflatePromise(buffer.slice(1));
33
35
  }
34
36
  else { // nodes with no compression have a 0x00 prefix, we remove that
35
37
  buffer = buffer.slice(1);
@@ -245,8 +247,8 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
245
247
  };
246
248
  };
247
249
  exports.decodeDecompressedBinaryNode = decodeDecompressedBinaryNode;
248
- const decodeBinaryNode = (buff) => {
249
- const decompBuff = (0, exports.decompressingIfRequired)(buff);
250
+ const decodeBinaryNode = async (buff) => {
251
+ const decompBuff = await (0, exports.decompressingIfRequired)(buff);
250
252
  return (0, exports.decodeDecompressedBinaryNode)(decompBuff, constants);
251
253
  };
252
254
  exports.decodeBinaryNode = decodeBinaryNode;
@@ -1,3 +1,3 @@
1
1
  /// <reference types="node" />
2
2
  import type { BinaryNode, BinaryNodeCodingOptions } from './types';
3
- export declare const encodeBinaryNode: ({ tag, attrs, content }: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => Buffer;
3
+ export declare const encodeBinaryNode: (node: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => Buffer;
@@ -26,7 +26,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.encodeBinaryNode = void 0;
27
27
  const constants = __importStar(require("./constants"));
28
28
  const jid_utils_1 = require("./jid-utils");
29
- const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0]) => {
29
+ const encodeBinaryNode = (node, opts = constants, buffer = [0]) => {
30
+ const encoded = encodeBinaryNodeInner(node, opts, buffer);
31
+ return Buffer.from(encoded);
32
+ };
33
+ exports.encodeBinaryNode = encodeBinaryNode;
34
+ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
30
35
  const { TAGS, TOKEN_MAP } = opts;
31
36
  const pushByte = (value) => buffer.push(value & 0xff);
32
37
  const pushInt = (value, n, littleEndian = false) => {
@@ -214,7 +219,7 @@ const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0
214
219
  else if (Array.isArray(content)) {
215
220
  writeListStart(content.length);
216
221
  for (const item of content) {
217
- (0, exports.encodeBinaryNode)(item, opts, buffer);
222
+ encodeBinaryNodeInner(item, opts, buffer);
218
223
  }
219
224
  }
220
225
  else if (typeof content === 'undefined') {
@@ -223,6 +228,5 @@ const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0
223
228
  else {
224
229
  throw new Error(`invalid children for header "${tag}": ${content} (${typeof content})`);
225
230
  }
226
- return Buffer.from(buffer);
231
+ return buffer;
227
232
  };
228
- exports.encodeBinaryNode = encodeBinaryNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d0v3riz/baileys",
3
- "version": "6.7.2",
3
+ "version": "6.7.5",
4
4
  "description": "WhatsApp API",
5
5
  "keywords": [
6
6
  "whatsapp",
@@ -46,17 +46,19 @@
46
46
  "@adiwajshing/keyed-db": "^0.2.4",
47
47
  "@d0v3riz/ws": "^8.13.0",
48
48
  "@hapi/boom": "^9.1.3",
49
+ "async-lock": "^1.4.1",
49
50
  "audio-decode": "^2.1.3",
50
- "axios": "^1.3.3",
51
+ "axios": "^1.6.0",
51
52
  "cache-manager": "4.0.1",
52
53
  "futoin-hkdf": "^1.5.1",
53
54
  "libphonenumber-js": "^1.10.20",
54
55
  "libsignal": "https://github.com/d0v3riz/libsignal-node.git",
56
+ "lodash": "^4.17.21",
55
57
  "music-metadata": "^7.12.3",
56
58
  "node-cache": "^5.1.2",
57
59
  "pino": "^7.0.0",
58
60
  "protobufjs": "^7.2.4",
59
- "uuid": "^9.0.0",
61
+ "uuid": "^10.0.0",
60
62
  "ws": "^8.13.0"
61
63
  },
62
64
  "devDependencies": {
@@ -70,22 +72,22 @@
70
72
  "eslint": "^8.0.0",
71
73
  "jest": "^27.0.6",
72
74
  "jimp": "^0.16.1",
75
+ "json": "^11.0.0",
73
76
  "link-preview-js": "^3.0.0",
74
77
  "open": "^8.4.2",
75
78
  "qrcode-terminal": "^0.12.0",
76
79
  "release-it": "^15.10.3",
77
- "sharp": "^0.30.5",
80
+ "sharp": "^0.32.6",
78
81
  "ts-jest": "^27.0.3",
79
82
  "ts-node": "^10.8.1",
80
83
  "typedoc": "^0.24.7",
81
- "typescript": "^4.6.4",
82
- "json": "^11.0.0"
84
+ "typescript": "^4.6.4"
83
85
  },
84
86
  "peerDependencies": {
85
87
  "jimp": "^0.16.1",
86
88
  "link-preview-js": "^3.0.0",
87
89
  "qrcode-terminal": "^0.12.0",
88
- "sharp": "^0.32.2"
90
+ "sharp": "^0.32.6"
89
91
  },
90
92
  "peerDependenciesMeta": {
91
93
  "jimp": {