@heavstaltech/baileys 2.3.4 → 3.2.4

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 (133) hide show
  1. package/README.md +226 -53
  2. package/WAProto/index.js +14270 -302
  3. package/engine-requirements.js +10 -0
  4. package/lib/Defaults/baileys-version.json +1 -1
  5. package/lib/Defaults/index.js +118 -79
  6. package/lib/Defaults/phonenumber-mcc.json +223 -0
  7. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  8. package/lib/Signal/Group/ciphertext-message.js +15 -0
  9. package/lib/Signal/Group/group-session-builder.d.ts +14 -0
  10. package/lib/Signal/Group/group-session-builder.js +64 -0
  11. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  12. package/lib/Signal/Group/group_cipher.js +96 -0
  13. package/lib/Signal/Group/index.d.ts +11 -0
  14. package/lib/Signal/Group/index.js +57 -0
  15. package/lib/Signal/Group/keyhelper.d.ts +10 -0
  16. package/lib/Signal/Group/keyhelper.js +55 -0
  17. package/lib/Signal/Group/queue-job.d.ts +1 -0
  18. package/lib/Signal/Group/queue-job.js +57 -0
  19. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  20. package/lib/Signal/Group/sender-chain-key.js +34 -0
  21. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  22. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  23. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  24. package/lib/Signal/Group/sender-key-message.js +69 -0
  25. package/lib/Signal/Group/sender-key-name.d.ts +17 -0
  26. package/lib/Signal/Group/sender-key-name.js +51 -0
  27. package/lib/Signal/Group/sender-key-record.d.ts +30 -0
  28. package/lib/Signal/Group/sender-key-record.js +53 -0
  29. package/lib/Signal/Group/sender-key-state.d.ts +38 -0
  30. package/lib/Signal/Group/sender-key-state.js +99 -0
  31. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  32. package/{WASignalGroup/sender_message_key.js → lib/Signal/Group/sender-message-key.js} +6 -16
  33. package/lib/Signal/libsignal.js +51 -29
  34. package/lib/Socket/business.d.ts +43 -42
  35. package/lib/Socket/chats.d.ts +222 -36
  36. package/lib/Socket/chats.js +186 -153
  37. package/lib/Socket/dugong.d.ts +254 -0
  38. package/lib/Socket/dugong.js +484 -0
  39. package/lib/Socket/groups.d.ts +7 -7
  40. package/lib/Socket/groups.js +37 -35
  41. package/lib/Socket/index.d.ts +52 -51
  42. package/lib/Socket/index.js +1 -0
  43. package/lib/Socket/messages-recv.d.ts +37 -34
  44. package/lib/Socket/messages-recv.js +175 -37
  45. package/lib/Socket/messages-send.d.ts +12 -18
  46. package/lib/Socket/messages-send.js +396 -574
  47. package/lib/Socket/newsletter.d.ts +28 -26
  48. package/lib/Socket/newsletter.js +140 -25
  49. package/lib/Socket/registration.d.ts +52 -49
  50. package/lib/Socket/registration.js +7 -7
  51. package/lib/Socket/socket.d.ts +0 -1
  52. package/lib/Socket/socket.js +47 -198
  53. package/lib/Socket/usync.d.ts +10 -11
  54. package/lib/Store/make-cache-manager-store.d.ts +1 -2
  55. package/lib/Store/make-in-memory-store.d.ts +2 -2
  56. package/lib/Store/make-in-memory-store.js +1 -5
  57. package/lib/Store/make-ordered-dictionary.js +2 -2
  58. package/lib/Types/Auth.d.ts +1 -0
  59. package/lib/Types/Call.d.ts +1 -1
  60. package/lib/Types/Chat.d.ts +7 -12
  61. package/lib/Types/Events.d.ts +2 -17
  62. package/lib/Types/GroupMetadata.d.ts +2 -3
  63. package/lib/Types/Label.d.ts +0 -11
  64. package/lib/Types/Label.js +1 -1
  65. package/lib/Types/LabelAssociation.js +1 -1
  66. package/lib/Types/Message.d.ts +10 -170
  67. package/lib/Types/Newsletter.d.ts +97 -86
  68. package/lib/Types/Newsletter.js +38 -32
  69. package/lib/Types/Socket.d.ts +2 -7
  70. package/lib/Types/index.d.ts +0 -9
  71. package/lib/Types/index.js +1 -1
  72. package/lib/Utils/auth-utils.js +14 -35
  73. package/lib/Utils/business.d.ts +1 -1
  74. package/lib/Utils/business.js +2 -2
  75. package/lib/Utils/chat-utils.d.ts +12 -11
  76. package/lib/Utils/chat-utils.js +36 -52
  77. package/lib/Utils/crypto.d.ts +16 -15
  78. package/lib/Utils/crypto.js +26 -74
  79. package/lib/Utils/decode-wa-message.d.ts +0 -17
  80. package/lib/Utils/decode-wa-message.js +17 -53
  81. package/lib/Utils/event-buffer.js +7 -10
  82. package/lib/Utils/generics.d.ts +17 -13
  83. package/lib/Utils/generics.js +79 -58
  84. package/lib/Utils/history.d.ts +2 -6
  85. package/lib/Utils/history.js +6 -4
  86. package/lib/Utils/logger.d.ts +3 -1
  87. package/lib/Utils/lt-hash.js +12 -12
  88. package/lib/Utils/make-mutex.d.ts +2 -2
  89. package/lib/Utils/messages-media.d.ts +28 -25
  90. package/lib/Utils/messages-media.js +201 -103
  91. package/lib/Utils/messages.js +36 -473
  92. package/lib/Utils/noise-handler.d.ts +5 -4
  93. package/lib/Utils/noise-handler.js +14 -19
  94. package/lib/Utils/process-message.d.ts +5 -5
  95. package/lib/Utils/process-message.js +23 -75
  96. package/lib/Utils/signal.d.ts +1 -2
  97. package/lib/Utils/signal.js +26 -32
  98. package/lib/Utils/use-multi-file-auth-state.d.ts +1 -0
  99. package/lib/Utils/use-multi-file-auth-state.js +66 -242
  100. package/lib/Utils/validate-connection.d.ts +1 -1
  101. package/lib/Utils/validate-connection.js +88 -64
  102. package/lib/WABinary/constants.d.ts +27 -24
  103. package/lib/WABinary/decode.d.ts +2 -1
  104. package/lib/WABinary/decode.js +11 -23
  105. package/lib/WABinary/encode.d.ts +2 -1
  106. package/lib/WABinary/encode.js +147 -134
  107. package/lib/WABinary/generic-utils.d.ts +5 -2
  108. package/lib/WABinary/generic-utils.js +125 -37
  109. package/lib/WABinary/jid-utils.d.ts +1 -1
  110. package/lib/WAM/BinaryInfo.d.ts +11 -2
  111. package/lib/WAM/encode.d.ts +2 -1
  112. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +3 -3
  113. package/lib/WAUSync/USyncUser.d.ts +2 -0
  114. package/lib/index.d.ts +12 -0
  115. package/lib/index.js +12 -0
  116. package/package.json +102 -98
  117. package/WAProto/index.d.ts +0 -50383
  118. package/WASignalGroup/GroupProtocol.js +0 -1697
  119. package/WASignalGroup/ciphertext_message.js +0 -16
  120. package/WASignalGroup/group_cipher.js +0 -120
  121. package/WASignalGroup/group_session_builder.js +0 -46
  122. package/WASignalGroup/index.js +0 -5
  123. package/WASignalGroup/keyhelper.js +0 -21
  124. package/WASignalGroup/protobufs.js +0 -3
  125. package/WASignalGroup/queue_job.js +0 -69
  126. package/WASignalGroup/sender_chain_key.js +0 -50
  127. package/WASignalGroup/sender_key_distribution_message.js +0 -78
  128. package/WASignalGroup/sender_key_message.js +0 -92
  129. package/WASignalGroup/sender_key_name.js +0 -70
  130. package/WASignalGroup/sender_key_record.js +0 -56
  131. package/WASignalGroup/sender_key_state.js +0 -129
  132. package/lib/Utils/use-single-file-auth-state.d.ts +0 -12
  133. package/lib/Utils/use-single-file-auth-state.js +0 -75
@@ -1,7 +1,10 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
1
4
  import { Boom } from '@hapi/boom';
2
5
  import { AxiosRequestConfig } from 'axios';
3
6
  import type { Logger } from 'pino';
4
- import { Readable } from 'stream';
7
+ import { Readable, Transform } from 'stream';
5
8
  import { URL } from 'url';
6
9
  import { proto } from '../../WAProto';
7
10
  import { DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, MediaType, SocketConfig, WAMediaUpload, WAMediaUploadFunction, WAMessageContent } from '../Types';
@@ -10,10 +13,10 @@ export declare const hkdfInfoKey: (type: MediaType) => string;
10
13
  /** generates all the keys required to encrypt/decrypt & sign a media message */
11
14
  export declare function getMediaKeys(buffer: Uint8Array | string | null | undefined, mediaType: MediaType): MediaDecryptionKeyInfo;
12
15
  export declare const extractImageThumb: (bufferOrFilePath: Readable | Buffer | string, width?: number) => Promise<{
13
- buffer: any;
16
+ buffer: Buffer;
14
17
  original: {
15
- width: any;
16
- height: any;
18
+ width: number | undefined;
19
+ height: number | undefined;
17
20
  };
18
21
  }>;
19
22
  export declare const encodeBase64EncodedStringForUpload: (b64: string) => string;
@@ -21,25 +24,25 @@ export declare const generateProfilePicture: (mediaUpload: WAMediaUpload) => Pro
21
24
  img: Buffer;
22
25
  }>;
23
26
  /** gets the SHA256 of the given media message */
24
- export declare const mediaMessageSHA256B64: (message: WAMessageContent) => any;
25
- export declare function getAudioDuration(buffer: Buffer | string | Readable): Promise<any>;
27
+ export declare const mediaMessageSHA256B64: (message: WAMessageContent) => string | null | undefined;
28
+ export declare function getAudioDuration(buffer: Buffer | string | Readable): Promise<number | undefined>;
26
29
  /**
27
30
  referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
28
31
  */
29
- export declare function getAudioWaveform(buffer: Buffer | string | Readable, logger?: Logger): Promise<Uint8Array<ArrayBuffer> | undefined>;
30
- export declare const toReadable: (buffer: Buffer) => any;
31
- export declare const toBuffer: (stream: Readable) => Promise<any>;
32
+ export declare function getAudioWaveform(buffer: Buffer | string | Readable, logger?: Logger): Promise<Uint8Array | undefined>;
33
+ export declare const toReadable: (buffer: Buffer) => Readable;
34
+ export declare const toBuffer: (stream: Readable) => Promise<Buffer>;
32
35
  export declare const getStream: (item: WAMediaUpload, opts?: AxiosRequestConfig) => Promise<{
33
- readonly stream: any;
36
+ readonly stream: Readable;
34
37
  readonly type: "buffer";
35
38
  } | {
36
- readonly stream: any;
39
+ readonly stream: Readable;
37
40
  readonly type: "readable";
38
41
  } | {
39
42
  readonly stream: Readable;
40
43
  readonly type: "remote";
41
44
  } | {
42
- readonly stream: any;
45
+ readonly stream: import("fs").ReadStream;
43
46
  readonly type: "file";
44
47
  }>;
45
48
  /** generates a thumbnail for a given media, if required */
@@ -62,20 +65,20 @@ type EncryptedStreamOptions = {
62
65
  };
63
66
  export declare const prepareStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
64
67
  mediaKey: undefined;
65
- encWriteStream: any;
66
- fileLength: any;
67
- fileSha256: any;
68
+ encWriteStream: Buffer;
69
+ fileLength: number;
70
+ fileSha256: Buffer;
68
71
  fileEncSha256: undefined;
69
72
  bodyPath: string | undefined;
70
73
  didSaveToTmpPath: boolean;
71
74
  }>;
72
75
  export declare const encryptedStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
73
- mediaKey: any;
74
- encWriteStream: any;
76
+ mediaKey: Buffer;
77
+ encWriteStream: Readable;
75
78
  bodyPath: string | undefined;
76
- mac: any;
77
- fileEncSha256: any;
78
- fileSha256: any;
79
+ mac: Buffer;
80
+ fileEncSha256: Buffer;
81
+ fileSha256: Buffer;
79
82
  fileLength: number;
80
83
  didSaveToTmpPath: boolean;
81
84
  }>;
@@ -85,12 +88,12 @@ export type MediaDownloadOptions = {
85
88
  options?: AxiosRequestConfig<any>;
86
89
  };
87
90
  export declare const getUrlFromDirectPath: (directPath: string) => string;
88
- export declare const downloadContentFromMessage: ({ mediaKey, directPath, url }: DownloadableMessage, type: MediaType, opts?: MediaDownloadOptions) => Promise<any>;
91
+ export declare const downloadContentFromMessage: ({ mediaKey, directPath, url }: DownloadableMessage, type: MediaType, opts?: MediaDownloadOptions) => Promise<Transform>;
89
92
  /**
90
93
  * Decrypts and downloads an AES256-CBC encrypted file given the keys.
91
94
  * Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
92
95
  * */
93
- export declare const downloadEncryptedContent: (downloadUrl: string, { cipherKey, iv }: MediaDecryptionKeyInfo, { startByte, endByte, options }?: MediaDownloadOptions) => Promise<any>;
96
+ export declare const downloadEncryptedContent: (downloadUrl: string, { cipherKey, iv }: MediaDecryptionKeyInfo, { startByte, endByte, options }?: MediaDownloadOptions) => Promise<Transform>;
94
97
  export declare function extensionForMediaMessage(message: WAMessageContent): string;
95
98
  export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logger, options }: SocketConfig, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>) => WAMediaUploadFunction;
96
99
  /**
@@ -98,12 +101,12 @@ export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logg
98
101
  */
99
102
  export declare const encryptMediaRetryRequest: (key: proto.IMessageKey, mediaKey: Buffer | Uint8Array, meId: string) => BinaryNode;
100
103
  export declare const decodeMediaRetryNode: (node: BinaryNode) => {
101
- key: import("../Types").WAMessageKey;
104
+ key: proto.IMessageKey;
102
105
  media?: {
103
106
  ciphertext: Uint8Array;
104
107
  iv: Uint8Array;
105
- };
106
- error?: Boom;
108
+ } | undefined;
109
+ error?: Boom<any> | undefined;
107
110
  };
108
111
  export declare const decryptMediaRetryData: ({ ciphertext, iv }: {
109
112
  ciphertext: Uint8Array;
@@ -15,30 +15,15 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
35
25
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = exports.getHttpStream = exports.getStream = exports.toBuffer = exports.toReadable = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.hkdfInfoKey = void 0;
37
- exports.getMediaKeys = getMediaKeys;
38
- exports.getAudioDuration = getAudioDuration;
39
- exports.getAudioWaveform = getAudioWaveform;
40
- exports.generateThumbnail = generateThumbnail;
41
- exports.extensionForMediaMessage = extensionForMediaMessage;
26
+ exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = 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;
42
27
  const boom_1 = require("@hapi/boom");
43
28
  const child_process_1 = require("child_process");
44
29
  const Crypto = __importStar(require("crypto"));
@@ -81,7 +66,7 @@ const hkdfInfoKey = (type) => {
81
66
  };
82
67
  exports.hkdfInfoKey = hkdfInfoKey;
83
68
  /** generates all the keys required to encrypt/decrypt & sign a media message */
84
- async function getMediaKeys(buffer, mediaType) {
69
+ function getMediaKeys(buffer, mediaType) {
85
70
  if (!buffer) {
86
71
  throw new boom_1.Boom('Cannot derive from empty media key');
87
72
  }
@@ -89,13 +74,14 @@ async function getMediaKeys(buffer, mediaType) {
89
74
  buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
90
75
  }
91
76
  // expand using HKDF to 112 bytes, also pass in the relevant app info
92
- const expandedMediaKey = await (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
77
+ const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
93
78
  return {
94
79
  iv: expandedMediaKey.slice(0, 16),
95
80
  cipherKey: expandedMediaKey.slice(16, 48),
96
81
  macKey: expandedMediaKey.slice(48, 80),
97
82
  };
98
83
  }
84
+ exports.getMediaKeys = getMediaKeys;
99
85
  /** Extracts video thumb using FFMPEG */
100
86
  const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
101
87
  const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
@@ -156,23 +142,42 @@ const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
156
142
  .replace(/\=+$/, '')));
157
143
  exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
158
144
  const generateProfilePicture = async (mediaUpload) => {
159
- const bufferOrFilePath = Buffer.isBuffer(mediaUpload)
160
- ? mediaUpload
161
- : typeof mediaUpload === 'object' && 'url' in mediaUpload
162
- ? mediaUpload.url.toString()
163
- : await (0, exports.toBuffer)(mediaUpload.stream);
145
+ var _a, _b;
146
+ let bufferOrFilePath;
147
+ if (Buffer.isBuffer(mediaUpload)) {
148
+ bufferOrFilePath = mediaUpload;
149
+ }
150
+ else if ('url' in mediaUpload) {
151
+ bufferOrFilePath = mediaUpload.url.toString();
152
+ }
153
+ else {
154
+ bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
155
+ }
156
+ const lib = await getImageProcessingLibrary();
164
157
  let img;
165
- const { read, MIME_JPEG, AUTO } = require('jimp');
166
- const jimp = await read(bufferOrFilePath);
167
- const min = jimp.getWidth();
168
- const max = jimp.getHeight();
169
- const cropped = jimp.crop(0, 0, min, max);
170
- img = cropped
171
- .quality(100)
172
- .scaleToFit(720, 720, AUTO)
173
- .getBufferAsync(MIME_JPEG);
158
+ if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
159
+ img = lib.sharp.default(bufferOrFilePath)
160
+ .resize(640, 640)
161
+ .jpeg({
162
+ quality: 50,
163
+ })
164
+ .toBuffer();
165
+ }
166
+ else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
167
+ const { read, MIME_JPEG, RESIZE_BILINEAR } = lib.jimp;
168
+ const jimp = await read(bufferOrFilePath);
169
+ const min = Math.min(jimp.getWidth(), jimp.getHeight());
170
+ const cropped = jimp.crop(0, 0, min, min);
171
+ img = cropped
172
+ .quality(50)
173
+ .resize(640, 640, RESIZE_BILINEAR)
174
+ .getBufferAsync(MIME_JPEG);
175
+ }
176
+ else {
177
+ throw new boom_1.Boom('No image processing library available');
178
+ }
174
179
  return {
175
- img: await img
180
+ img: await img,
176
181
  };
177
182
  };
178
183
  exports.generateProfilePicture = generateProfilePicture;
@@ -183,66 +188,138 @@ const mediaMessageSHA256B64 = (message) => {
183
188
  };
184
189
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
185
190
  async function getAudioDuration(buffer) {
186
- const musicMetadata = await import('music-metadata');
187
- let metadata;
188
- if (Buffer.isBuffer(buffer)) {
189
- metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
190
- }
191
- else if (typeof buffer === 'string') {
192
- const rStream = (0, fs_1.createReadStream)(buffer);
193
- try {
194
- metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
195
- }
196
- finally {
197
- rStream.destroy();
191
+ try {
192
+ const { PassThrough } = require('stream');
193
+ const ff = require('fluent-ffmpeg');
194
+
195
+ return await new Promise((resolve, reject) => {
196
+ const inputStream = new PassThrough();
197
+ inputStream.end(buffer);
198
+
199
+ ff(inputStream)
200
+ .ffprobe((err, data) => {
201
+ if (err) reject(err);
202
+ else resolve(data.format.duration);
203
+ });
204
+ });
205
+ } catch (error) {
206
+ const musicMetadata = await import('music-metadata');
207
+ let metadata;
208
+ if (Buffer.isBuffer(buffer)) {
209
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, {
210
+ duration: true
211
+ });
212
+ } else if (typeof buffer === 'string') {
213
+ const rStream = (0, fs_1.createReadStream)(buffer);
214
+ try {
215
+ metadata = await musicMetadata.parseStream(rStream, undefined, {
216
+ duration: true
217
+ });
218
+ } finally {
219
+ rStream.destroy();
220
+ }
221
+ } else {
222
+ metadata = await musicMetadata.parseStream(buffer, undefined, {
223
+ duration: true
224
+ });
198
225
  }
226
+ return metadata.format.duration;
199
227
  }
200
- else {
201
- metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
202
- }
203
- return metadata.format.duration;
204
228
  }
205
- /**
206
- referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
207
- */
229
+ exports.getAudioDuration = getAudioDuration;
208
230
  async function getAudioWaveform(buffer, logger) {
209
231
  try {
210
- const audioDecode = (buffer) => import('audio-decode').then(({ default: audioDecode }) => audioDecode(buffer));
232
+ const { PassThrough } = require('stream');
233
+ const ff = require('fluent-ffmpeg');
234
+
211
235
  let audioData;
212
236
  if (Buffer.isBuffer(buffer)) {
213
237
  audioData = buffer;
238
+ } else if (typeof buffer === 'string') {
239
+ const rStream = require('fs').createReadStream(buffer);
240
+ audioData = await exports.toBuffer(rStream);
241
+ } else {
242
+ audioData = await exports.toBuffer(buffer);
214
243
  }
215
- else if (typeof buffer === 'string') {
216
- const rStream = (0, fs_1.createReadStream)(buffer);
217
- audioData = await (0, exports.toBuffer)(rStream);
218
- }
219
- else {
220
- audioData = await (0, exports.toBuffer)(buffer);
221
- }
222
- const audioBuffer = await audioDecode(audioData);
223
- const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
224
- const samples = 64; // Number of samples we want to have in our final data set
225
- const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
226
- const filteredData = [];
227
- for (let i = 0; i < samples; i++) {
228
- const blockStart = blockSize * i; // the location of the first sample in the block
229
- let sum = 0;
230
- for (let j = 0; j < blockSize; j++) {
231
- sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
232
- }
233
- filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
234
- }
235
- // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
236
- const multiplier = Math.pow(Math.max(...filteredData), -1);
237
- const normalizedData = filteredData.map((n) => n * multiplier);
238
- // Generate waveform like WhatsApp
239
- const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
240
- return waveform;
244
+
245
+ return await new Promise((resolve, reject) => {
246
+ const inputStream = new PassThrough();
247
+ inputStream.end(audioData);
248
+ const chunks = [];
249
+ const bars = 64;
250
+
251
+ ff(inputStream)
252
+ .audioChannels(1)
253
+ .audioFrequency(16000)
254
+ .format('s16le')
255
+ .on('error', reject)
256
+ .on('end', () => {
257
+ const rawData = Buffer.concat(chunks);
258
+ const samples = rawData.length / 2;
259
+ const amplitudes = [];
260
+
261
+ for (let i = 0; i < samples; i++) {
262
+ amplitudes.push(Math.abs(rawData.readInt16LE(i * 2)) / 32768);
263
+ }
264
+
265
+ const blockSize = Math.floor(amplitudes.length / bars);
266
+ const avg = [];
267
+ for (let i = 0; i < bars; i++) {
268
+ const block = amplitudes.slice(i * blockSize, (i + 1) * blockSize);
269
+ avg.push(block.reduce((a, b) => a + b, 0) / block.length);
270
+ }
271
+
272
+ const max = Math.max(...avg);
273
+ const normalized = avg.map(v => Math.floor((v / max) * 100));
274
+ resolve(new Uint8Array(normalized));
275
+ })
276
+ .pipe()
277
+ .on('data', chunk => chunks.push(chunk));
278
+ });
279
+ } catch (e) {
280
+ logger?.debug(e);
241
281
  }
242
- catch (e) {
243
- logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
282
+ }
283
+ exports.getAudioWaveform = getAudioWaveform;
284
+ async function convertToOpusBuffer(buffer, logger) {
285
+ try {
286
+ const { PassThrough } = require('stream');
287
+ const ff = require('fluent-ffmpeg');
288
+
289
+ return await new Promise((resolve, reject) => {
290
+ const inStream = new PassThrough();
291
+ const outStream = new PassThrough();
292
+ const chunks = [];
293
+ inStream.end(buffer);
294
+
295
+ ff(inStream)
296
+ .noVideo()
297
+ .audioCodec('libopus')
298
+ .format('ogg')
299
+ .audioBitrate('48k')
300
+ .audioChannels(1)
301
+ .audioFrequency(48000)
302
+ .outputOptions([
303
+ '-vn',
304
+ '-b:a 64k',
305
+ '-ac 2',
306
+ '-ar 48000',
307
+ '-map_metadata', '-1',
308
+ '-application', 'voip'
309
+ ])
310
+ .on('error', reject)
311
+ .on('end', () => resolve(Buffer.concat(chunks)))
312
+ .pipe(outStream, {
313
+ end: true
314
+ });
315
+ outStream.on('data', c => chunks.push(c));
316
+ });
317
+ } catch (e) {
318
+ logger?.debug(e);
319
+ throw e;
244
320
  }
245
321
  }
322
+ exports.convertToOpusBuffer = convertToOpusBuffer;
246
323
  const toReadable = (buffer) => {
247
324
  const readable = new stream_1.Readable({ read: () => { } });
248
325
  readable.push(buffer);
@@ -304,6 +381,7 @@ async function generateThumbnail(file, mediaType, options) {
304
381
  originalImageDimensions
305
382
  };
306
383
  }
384
+ exports.generateThumbnail = generateThumbnail;
307
385
  const getHttpStream = async (url, options = {}) => {
308
386
  const { default: axios } = await import('axios');
309
387
  const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
@@ -354,15 +432,28 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
354
432
  }
355
433
  };
356
434
  exports.prepareStream = prepareStream;
357
- const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
435
+ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
358
436
  const { stream, type } = await (0, exports.getStream)(media, opts);
359
- logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
437
+
438
+ let finalStream = stream;
439
+ if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
440
+ try {
441
+ const buffer = await (0, exports.toBuffer)(stream);
442
+ const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
443
+ finalStream = (0, exports.toReadable)(opusBuffer);
444
+ } catch (error) {
445
+ const { stream: newStream } = await (0, exports.getStream)(media, opts);
446
+ finalStream = newStream;
447
+ }
448
+ }
449
+
360
450
  const mediaKey = Crypto.randomBytes(32);
361
- const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
451
+ const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
362
452
  const encWriteStream = new stream_1.Readable({ read: () => { } });
363
453
  let bodyPath;
364
454
  let writeStream;
365
455
  let didSaveToTmpPath = false;
456
+
366
457
  if (type === 'file') {
367
458
  bodyPath = media.url;
368
459
  }
@@ -371,13 +462,15 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
371
462
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
372
463
  didSaveToTmpPath = true;
373
464
  }
465
+
374
466
  let fileLength = 0;
375
467
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
376
468
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
377
469
  let sha256Plain = Crypto.createHash('sha256');
378
470
  let sha256Enc = Crypto.createHash('sha256');
471
+
379
472
  try {
380
- for await (const data of stream) {
473
+ for await (const data of finalStream) {
381
474
  fileLength += data.length;
382
475
  if (type === 'remote'
383
476
  && (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
@@ -386,6 +479,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
386
479
  data: { media, type }
387
480
  });
388
481
  }
482
+
389
483
  sha256Plain = sha256Plain.update(data);
390
484
  if (writeStream) {
391
485
  if (!writeStream.write(data)) {
@@ -394,16 +488,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
394
488
  }
395
489
  onChunk(aes.update(data));
396
490
  }
491
+
397
492
  onChunk(aes.final());
398
493
  const mac = hmac.digest().slice(0, 10);
399
494
  sha256Enc = sha256Enc.update(mac);
400
495
  const fileSha256 = sha256Plain.digest();
401
496
  const fileEncSha256 = sha256Enc.digest();
497
+
402
498
  encWriteStream.push(mac);
403
499
  encWriteStream.push(null);
404
500
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
405
- stream.destroy();
406
- logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
501
+ finalStream.destroy();
502
+
407
503
  return {
408
504
  mediaKey,
409
505
  encWriteStream,
@@ -416,24 +512,24 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
416
512
  };
417
513
  }
418
514
  catch (error) {
419
- // destroy all streams with error
420
515
  encWriteStream.destroy();
421
516
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
422
517
  aes.destroy();
423
518
  hmac.destroy();
424
519
  sha256Plain.destroy();
425
520
  sha256Enc.destroy();
426
- stream.destroy();
521
+ finalStream.destroy();
522
+
427
523
  if (didSaveToTmpPath) {
428
524
  try {
429
525
  await fs_1.promises.unlink(bodyPath);
430
526
  }
431
527
  catch (err) {
432
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
433
528
  }
434
529
  }
435
530
  throw error;
436
531
  }
532
+
437
533
  function onChunk(buff) {
438
534
  sha256Enc = sha256Enc.update(buff);
439
535
  hmac = hmac.update(buff);
@@ -448,9 +544,9 @@ const toSmallestChunkSize = (num) => {
448
544
  };
449
545
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
450
546
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
451
- const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
547
+ const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
452
548
  const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
453
- const keys = await getMediaKeys(mediaKey, type);
549
+ const keys = getMediaKeys(mediaKey, type);
454
550
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
455
551
  };
456
552
  exports.downloadContentFromMessage = downloadContentFromMessage;
@@ -557,6 +653,7 @@ function extensionForMediaMessage(message) {
557
653
  }
558
654
  return extension;
559
655
  }
656
+ exports.extensionForMediaMessage = extensionForMediaMessage;
560
657
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
561
658
  return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
562
659
  var _a, _b;
@@ -634,11 +731,11 @@ const getMediaRetryKey = (mediaKey) => {
634
731
  /**
635
732
  * Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
636
733
  */
637
- const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
734
+ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
638
735
  const recp = { stanzaId: key.id };
639
736
  const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
640
737
  const iv = Crypto.randomBytes(12);
641
- const retryKey = await getMediaRetryKey(mediaKey);
738
+ const retryKey = getMediaRetryKey(mediaKey);
642
739
  const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
643
740
  const req = {
644
741
  tag: 'receipt',
@@ -702,8 +799,8 @@ const decodeMediaRetryNode = (node) => {
702
799
  return event;
703
800
  };
704
801
  exports.decodeMediaRetryNode = decodeMediaRetryNode;
705
- const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
706
- const retryKey = await getMediaRetryKey(mediaKey);
802
+ const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
803
+ const retryKey = getMediaRetryKey(mediaKey);
707
804
  const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
708
805
  return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
709
806
  };
@@ -716,6 +813,7 @@ const MEDIA_RETRY_STATUS_MAP = {
716
813
  [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
717
814
  [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
718
815
  };
816
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
719
817
  function __importStar(arg0) {
720
818
  throw new Error('Function not implemented.');
721
819
  }