alipclutch-baileys 8.5.3 → 8.5.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.
- package/engine-requirements.js +10 -0
- package/lib/Defaults/baileys-version.json +2 -2
- package/lib/Defaults/index.d.ts +7 -16
- package/lib/Defaults/index.js +119 -90
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Socket/Client/abstract-socket-client.d.ts +17 -0
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.d.ts +3 -2
- package/lib/Socket/Client/index.js +3 -2
- package/lib/Socket/Client/mobile-socket-client.d.ts +13 -0
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/web-socket-client.d.ts +12 -0
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/business.d.ts +58 -59
- package/lib/Socket/chats.d.ts +230 -45
- package/lib/Socket/chats.js +238 -139
- package/lib/Socket/groups.d.ts +32 -41
- package/lib/Socket/groups.js +23 -38
- package/lib/Socket/index.d.ts +64 -63
- package/lib/Socket/index.js +3 -2
- package/lib/Socket/messages-recv.js +65 -9
- package/lib/Socket/messages-send.d.ts +47 -49
- package/lib/Socket/messages-send.js +395 -543
- package/lib/Socket/newsletter.d.ts +37 -39
- package/lib/Socket/newsletter.js +123 -88
- package/lib/Socket/registration.d.ts +267 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/setup.d.ts +253 -0
- package/lib/Socket/setup.js +4 -5
- package/lib/Socket/socket.d.ts +43 -270
- package/lib/Socket/socket.js +19 -8
- package/lib/Socket/usync.d.ts +3 -3
- package/lib/Store/index.d.ts +2 -1
- package/lib/Store/index.js +3 -1
- package/lib/Store/make-cache-manager-store.d.ts +13 -0
- package/lib/Store/make-cache-manager-store.js +83 -0
- package/lib/Store/make-in-memory-store.d.ts +24 -24
- package/lib/Store/make-in-memory-store.js +14 -26
- package/lib/Store/make-ordered-dictionary.d.ts +1 -1
- package/lib/Store/make-ordered-dictionary.js +2 -2
- package/lib/Types/Auth.d.ts +7 -0
- package/lib/Types/Call.d.ts +1 -1
- package/lib/Types/Chat.d.ts +7 -14
- package/lib/Types/Contact.d.ts +1 -5
- package/lib/Types/Events.d.ts +2 -44
- package/lib/Types/GroupMetadata.d.ts +2 -11
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Message.d.ts +21 -148
- package/lib/Types/Message.js +2 -0
- package/lib/Types/Newsletter.d.ts +97 -73
- package/lib/Types/Newsletter.js +38 -18
- package/lib/Types/Socket.d.ts +9 -17
- package/lib/Types/index.d.ts +1 -8
- package/lib/Types/index.js +2 -2
- package/lib/Utils/auth-utils.d.ts +3 -3
- package/lib/Utils/auth-utils.js +13 -6
- package/lib/Utils/business.js +2 -2
- package/lib/Utils/chat-utils.d.ts +16 -15
- package/lib/Utils/chat-utils.js +35 -36
- package/lib/Utils/crypto.d.ts +16 -15
- package/lib/Utils/crypto.js +29 -71
- package/lib/Utils/decode-wa-message.d.ts +6 -22
- package/lib/Utils/decode-wa-message.js +56 -65
- package/lib/Utils/event-buffer.d.ts +2 -2
- package/lib/Utils/event-buffer.js +7 -11
- package/lib/Utils/generics.d.ts +20 -17
- package/lib/Utils/generics.js +75 -95
- package/lib/Utils/history.d.ts +0 -4
- package/lib/Utils/history.js +6 -4
- package/lib/Utils/link-preview.d.ts +2 -2
- package/lib/Utils/link-preview.js +1 -34
- package/lib/Utils/logger.d.ts +3 -10
- package/lib/Utils/lt-hash.d.ts +2 -2
- package/lib/Utils/lt-hash.js +6 -6
- package/lib/Utils/make-mutex.d.ts +2 -2
- package/lib/Utils/messages-media.d.ts +24 -28
- package/lib/Utils/messages-media.js +111 -272
- package/lib/Utils/messages.d.ts +10 -13
- package/lib/Utils/messages.js +51 -336
- package/lib/Utils/noise-handler.d.ts +12 -10
- package/lib/Utils/noise-handler.js +23 -18
- package/lib/Utils/process-message.d.ts +4 -5
- package/lib/Utils/process-message.js +25 -108
- package/lib/Utils/signal.d.ts +1 -2
- package/lib/Utils/signal.js +26 -26
- package/lib/Utils/use-multi-file-auth-state.d.ts +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +0 -6
- package/lib/Utils/validate-connection.d.ts +4 -3
- package/lib/Utils/validate-connection.js +1 -1
- package/lib/WABinary/constants.d.ts +27 -24
- package/lib/WABinary/constants.js +13 -1276
- package/lib/WABinary/decode.d.ts +4 -3
- package/lib/WABinary/decode.js +13 -26
- package/lib/WABinary/encode.d.ts +2 -1
- package/lib/WABinary/encode.js +152 -137
- package/lib/WABinary/generic-utils.d.ts +4 -1
- package/lib/WABinary/generic-utils.js +125 -37
- package/lib/WABinary/jid-utils.d.ts +5 -11
- package/lib/WABinary/jid-utils.js +5 -28
- package/lib/WAM/BinaryInfo.d.ts +11 -2
- package/lib/WAM/encode.d.ts +2 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +15 -27
- package/package.json +31 -18
- package/WAProto/GenerateStatics.sh +0 -4
- package/WAProto/WAProto.proto +0 -4775
- package/WAProto/index.d.ts +0 -55057
- package/WAProto/index.ts.ts +0 -53473
- package/lib/Socket/setup.ts +0 -623
- package/lib/WABinary/jid-utils.js.bak +0 -83
|
@@ -15,47 +15,23 @@ 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) ||
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
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;
|
|
37
24
|
};
|
|
38
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
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.
|
|
40
|
-
exports.getMediaKeys = getMediaKeys;
|
|
41
|
-
exports.uploadFile = uploadFile;
|
|
42
|
-
exports.vid2jpg = vid2jpg;
|
|
43
|
-
exports.getAudioDuration = getAudioDuration;
|
|
44
|
-
exports.getAudioWaveform = getAudioWaveform;
|
|
45
|
-
exports.generateThumbnail = generateThumbnail;
|
|
46
|
-
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;
|
|
47
27
|
const boom_1 = require("@hapi/boom");
|
|
48
|
-
const
|
|
49
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
50
|
-
const cheerio = __importStar(require("cheerio"));
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
51
29
|
const Crypto = __importStar(require("crypto"));
|
|
52
30
|
const events_1 = require("events");
|
|
53
31
|
const fs_1 = require("fs");
|
|
54
32
|
const os_1 = require("os");
|
|
55
33
|
const path_1 = require("path");
|
|
56
|
-
const jimp_1 = __importDefault(require("jimp"));
|
|
57
34
|
const stream_1 = require("stream");
|
|
58
|
-
const child_process_1 = require("child_process");
|
|
59
35
|
const WAProto_1 = require("../../WAProto");
|
|
60
36
|
const Defaults_1 = require("../Defaults");
|
|
61
37
|
const WABinary_1 = require("../WABinary");
|
|
@@ -65,11 +41,13 @@ const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
|
|
|
65
41
|
const getImageProcessingLibrary = async () => {
|
|
66
42
|
const [_jimp, sharp] = await Promise.all([
|
|
67
43
|
(async () => {
|
|
68
|
-
const jimp = await (
|
|
44
|
+
const jimp = await (import('jimp')
|
|
45
|
+
.catch(() => { }));
|
|
69
46
|
return jimp;
|
|
70
47
|
})(),
|
|
71
48
|
(async () => {
|
|
72
|
-
const sharp = await (
|
|
49
|
+
const sharp = await (import('sharp')
|
|
50
|
+
.catch(() => { }));
|
|
73
51
|
return sharp;
|
|
74
52
|
})()
|
|
75
53
|
]);
|
|
@@ -88,7 +66,7 @@ const hkdfInfoKey = (type) => {
|
|
|
88
66
|
};
|
|
89
67
|
exports.hkdfInfoKey = hkdfInfoKey;
|
|
90
68
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
91
|
-
|
|
69
|
+
function getMediaKeys(buffer, mediaType) {
|
|
92
70
|
if (!buffer) {
|
|
93
71
|
throw new boom_1.Boom('Cannot derive from empty media key');
|
|
94
72
|
}
|
|
@@ -96,183 +74,26 @@ async function getMediaKeys(buffer, mediaType) {
|
|
|
96
74
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
97
75
|
}
|
|
98
76
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
99
|
-
const expandedMediaKey =
|
|
77
|
+
const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
|
|
100
78
|
return {
|
|
101
79
|
iv: expandedMediaKey.slice(0, 16),
|
|
102
80
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
103
81
|
macKey: expandedMediaKey.slice(48, 80),
|
|
104
82
|
};
|
|
105
83
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
name: "catbox",
|
|
115
|
-
url: "https://catbox.moe/user/api.php",
|
|
116
|
-
buildForm: () => {
|
|
117
|
-
const form = new form_data_1.default();
|
|
118
|
-
form.append("fileToUpload", buffer, {
|
|
119
|
-
filename: `file.${ext}`,
|
|
120
|
-
contentType: mime || "application/octet-stream"
|
|
121
|
-
});
|
|
122
|
-
form.append("reqtype", "fileupload");
|
|
123
|
-
return form;
|
|
124
|
-
},
|
|
125
|
-
parseResponse: res => res.data
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: "pdi.moe",
|
|
129
|
-
url: "https://scdn.pdi.moe/upload",
|
|
130
|
-
buildForm: () => {
|
|
131
|
-
const form = new form_data_1.default();
|
|
132
|
-
form.append("file", buffer, {
|
|
133
|
-
filename: `file.${ext}`,
|
|
134
|
-
contentType: mime
|
|
135
|
-
});
|
|
136
|
-
return form;
|
|
137
|
-
},
|
|
138
|
-
parseResponse: res => res.data.result.url
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
name: "qu.ax",
|
|
142
|
-
url: "https://qu.ax/upload.php",
|
|
143
|
-
buildForm: () => {
|
|
144
|
-
const form = new form_data_1.default();
|
|
145
|
-
form.append("files[]", buffer, {
|
|
146
|
-
filename: `file.${ext}`,
|
|
147
|
-
contentType: mime || "application/octet-stream"
|
|
148
|
-
});
|
|
149
|
-
return form;
|
|
150
|
-
},
|
|
151
|
-
parseResponse: res => {
|
|
152
|
-
var _a, _b, _c;
|
|
153
|
-
if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
|
|
154
|
-
throw new Error("Failed to get URL from qu.ax");
|
|
155
|
-
return res.data.files[0].url;
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: "uguu.se",
|
|
160
|
-
url: "https://uguu.se/upload.php",
|
|
161
|
-
buildForm: () => {
|
|
162
|
-
const form = new form_data_1.default();
|
|
163
|
-
form.append("files[]", buffer, {
|
|
164
|
-
filename: `file.${ext}`,
|
|
165
|
-
contentType: mime || "application/octet-stream"
|
|
166
|
-
});
|
|
167
|
-
return form;
|
|
168
|
-
},
|
|
169
|
-
parseResponse: res => {
|
|
170
|
-
var _a, _b, _c;
|
|
171
|
-
if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
|
|
172
|
-
throw new Error("Failed to get URL from uguu.se");
|
|
173
|
-
return res.data.files[0].url;
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: "tmpfiles",
|
|
178
|
-
url: "https://tmpfiles.org/api/v1/upload",
|
|
179
|
-
buildForm: () => {
|
|
180
|
-
const form = new form_data_1.default();
|
|
181
|
-
form.append("file", buffer, {
|
|
182
|
-
filename: `file.${ext}`,
|
|
183
|
-
contentType: mime
|
|
184
|
-
});
|
|
185
|
-
return form;
|
|
186
|
-
},
|
|
187
|
-
parseResponse: res => {
|
|
188
|
-
const match = res.data.data.url.match(/https:\/\/tmpfiles\.org\/(.*)/);
|
|
189
|
-
if (!match)
|
|
190
|
-
throw new Error("Failed to parse tmpfiles URL.");
|
|
191
|
-
return `https://tmpfiles.org/dl/${match[1]}`;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
];
|
|
195
|
-
for (const service of services) {
|
|
196
|
-
try {
|
|
197
|
-
const form = service.buildForm();
|
|
198
|
-
const res = await axios_1.default.post(service.url, form, {
|
|
199
|
-
headers: form.getHeaders()
|
|
200
|
-
});
|
|
201
|
-
const url = service.parseResponse(res);
|
|
202
|
-
return url;
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
logger === null || logger === void 0 ? void 0 : logger.debug(`[${service.name}] eror:`, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
throw new Error("All upload services failed.");
|
|
209
|
-
}
|
|
210
|
-
async function vid2jpg(videoUrl) {
|
|
211
|
-
try {
|
|
212
|
-
const { data } = await axios_1.default.get(`https://ezgif.com/video-to-jpg?url=${encodeURIComponent(videoUrl)}`);
|
|
213
|
-
const $ = cheerio.load(data);
|
|
214
|
-
const fileToken = $('input[name="file"]').attr("value");
|
|
215
|
-
if (!fileToken) {
|
|
216
|
-
throw new Error("Failed to retrieve file token. The video URL may be invalid or inaccessible.");
|
|
217
|
-
}
|
|
218
|
-
const formData = new URLSearchParams();
|
|
219
|
-
formData.append("file", fileToken);
|
|
220
|
-
formData.append("end", "1");
|
|
221
|
-
formData.append("video-to-jpg", "Convert to JPG!");
|
|
222
|
-
const convert = await axios_1.default.post(`https://ezgif.com/video-to-jpg/${fileToken}`, formData);
|
|
223
|
-
const $2 = cheerio.load(convert.data);
|
|
224
|
-
let imageUrl = $2("#output img").first().attr("src");
|
|
225
|
-
if (!imageUrl) {
|
|
226
|
-
throw new Error("Could not locate the converted image output.");
|
|
227
|
-
}
|
|
228
|
-
if (imageUrl.startsWith("//")) {
|
|
229
|
-
imageUrl = "https:" + imageUrl;
|
|
84
|
+
exports.getMediaKeys = getMediaKeys;
|
|
85
|
+
/** Extracts video thumb using FFMPEG */
|
|
86
|
+
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
|
|
87
|
+
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
|
|
88
|
+
(0, child_process_1.exec)(cmd, (err) => {
|
|
89
|
+
if (err) {
|
|
90
|
+
reject(err);
|
|
230
91
|
}
|
|
231
|
-
else
|
|
232
|
-
|
|
233
|
-
if (cdnMatch) {
|
|
234
|
-
imageUrl = "https://" + imageUrl.slice(2);
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
imageUrl = "https://ezgif.com" + imageUrl;
|
|
238
|
-
}
|
|
92
|
+
else {
|
|
93
|
+
resolve();
|
|
239
94
|
}
|
|
240
|
-
return imageUrl;
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
throw new Error("Failed to convert video to JPG: " + error.message);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Extracts video thumbnail using FFmpeg
|
|
248
|
-
*/
|
|
249
|
-
const extractVideoThumb = async (videoPath, time = '00:00:00', size = { width: 256 }) => {
|
|
250
|
-
return new Promise((resolve, reject) => {
|
|
251
|
-
const args = [
|
|
252
|
-
'-ss', time,
|
|
253
|
-
'-i', videoPath,
|
|
254
|
-
'-y',
|
|
255
|
-
'-vf', `scale=${size.width}:-1`,
|
|
256
|
-
'-vframes', '1',
|
|
257
|
-
'-f', 'image2',
|
|
258
|
-
'-vcodec', 'mjpeg',
|
|
259
|
-
'pipe:1'
|
|
260
|
-
];
|
|
261
|
-
const ffmpeg = (0, child_process_1.spawn)('ffmpeg', args);
|
|
262
|
-
const chunks = [];
|
|
263
|
-
let errorOutput = '';
|
|
264
|
-
ffmpeg.stdout.on('data', chunk => chunks.push(chunk));
|
|
265
|
-
ffmpeg.stderr.on('data', data => {
|
|
266
|
-
errorOutput += data.toString();
|
|
267
|
-
});
|
|
268
|
-
ffmpeg.on('error', reject);
|
|
269
|
-
ffmpeg.on('close', code => {
|
|
270
|
-
if (code === 0) return resolve(Buffer.concat(chunks));
|
|
271
|
-
reject(new Error(`ffmpeg exited with code ${code}\n${errorOutput}`));
|
|
272
|
-
});
|
|
273
95
|
});
|
|
274
|
-
};
|
|
275
|
-
exports.extractVideoThumb = extractVideoThumb;
|
|
96
|
+
});
|
|
276
97
|
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
277
98
|
var _a, _b;
|
|
278
99
|
if (bufferOrFilePath instanceof stream_1.Readable) {
|
|
@@ -321,8 +142,8 @@ const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
|
|
|
321
142
|
.replace(/\=+$/, '')));
|
|
322
143
|
exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
|
|
323
144
|
const generateProfilePicture = async (mediaUpload) => {
|
|
145
|
+
var _a, _b;
|
|
324
146
|
let bufferOrFilePath;
|
|
325
|
-
let img;
|
|
326
147
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
327
148
|
bufferOrFilePath = mediaUpload;
|
|
328
149
|
}
|
|
@@ -332,11 +153,29 @@ const generateProfilePicture = async (mediaUpload) => {
|
|
|
332
153
|
else {
|
|
333
154
|
bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
|
|
334
155
|
}
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
.
|
|
339
|
-
|
|
156
|
+
const lib = await getImageProcessingLibrary();
|
|
157
|
+
let img;
|
|
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
|
+
}
|
|
340
179
|
return {
|
|
341
180
|
img: await img,
|
|
342
181
|
};
|
|
@@ -526,28 +365,12 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
526
365
|
}
|
|
527
366
|
}
|
|
528
367
|
else if (mediaType === 'video') {
|
|
368
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
529
369
|
try {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
|
|
534
|
-
await fs_1.promises.writeFile(videoPath, buffer);
|
|
535
|
-
}
|
|
536
|
-
const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
|
|
537
|
-
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
|
|
538
|
-
await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
|
|
539
|
-
const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
|
|
540
|
-
thumbnail = processedThumbnailBuffer.toString('base64');
|
|
541
|
-
if (original.width && original.height) {
|
|
542
|
-
originalImageDimensions = {
|
|
543
|
-
width: original.width,
|
|
544
|
-
height: original.height,
|
|
545
|
-
};
|
|
546
|
-
}
|
|
370
|
+
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
371
|
+
const buff = await fs_1.promises.readFile(imgFilename);
|
|
372
|
+
thumbnail = buff.toString('base64');
|
|
547
373
|
await fs_1.promises.unlink(imgFilename);
|
|
548
|
-
if (videoPath !== file) {
|
|
549
|
-
await fs_1.promises.unlink(videoPath);
|
|
550
|
-
}
|
|
551
374
|
}
|
|
552
375
|
catch (err) {
|
|
553
376
|
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
@@ -558,8 +381,10 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
558
381
|
originalImageDimensions
|
|
559
382
|
};
|
|
560
383
|
}
|
|
384
|
+
exports.generateThumbnail = generateThumbnail;
|
|
561
385
|
const getHttpStream = async (url, options = {}) => {
|
|
562
|
-
const
|
|
386
|
+
const { default: axios } = await import('axios');
|
|
387
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
563
388
|
return fetched.data;
|
|
564
389
|
};
|
|
565
390
|
exports.getHttpStream = getHttpStream;
|
|
@@ -574,7 +399,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
574
399
|
bodyPath = media.url;
|
|
575
400
|
}
|
|
576
401
|
else if (saveOriginalFileIfRequired) {
|
|
577
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
402
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
578
403
|
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
579
404
|
didSaveToTmpPath = true;
|
|
580
405
|
}
|
|
@@ -593,6 +418,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
593
418
|
};
|
|
594
419
|
}
|
|
595
420
|
catch (error) {
|
|
421
|
+
// destroy all streams with error
|
|
596
422
|
stream.destroy();
|
|
597
423
|
if (didSaveToTmpPath) {
|
|
598
424
|
try {
|
|
@@ -608,53 +434,52 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
608
434
|
exports.prepareStream = prepareStream;
|
|
609
435
|
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
610
436
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
let finalStream = stream;
|
|
614
|
-
|
|
615
|
-
// Tambahan untuk konversi audio jadi Opus (PTT)
|
|
437
|
+
|
|
438
|
+
let finalStream = stream;
|
|
616
439
|
if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
|
|
617
440
|
try {
|
|
618
441
|
const buffer = await (0, exports.toBuffer)(stream);
|
|
619
442
|
const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
|
|
620
443
|
finalStream = (0, exports.toReadable)(opusBuffer);
|
|
621
|
-
logger?.debug('converted audio to Opus');
|
|
622
444
|
} catch (error) {
|
|
623
|
-
logger?.error('failed to convert audio to Opus, fallback to original stream');
|
|
624
445
|
const { stream: newStream } = await (0, exports.getStream)(media, opts);
|
|
625
446
|
finalStream = newStream;
|
|
626
447
|
}
|
|
627
448
|
}
|
|
628
449
|
|
|
629
450
|
const mediaKey = Crypto.randomBytes(32);
|
|
630
|
-
const { cipherKey, iv, macKey } =
|
|
451
|
+
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
631
452
|
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
632
453
|
let bodyPath;
|
|
633
454
|
let writeStream;
|
|
634
455
|
let didSaveToTmpPath = false;
|
|
635
|
-
|
|
456
|
+
|
|
636
457
|
if (type === 'file') {
|
|
637
458
|
bodyPath = media.url;
|
|
638
|
-
}
|
|
639
|
-
|
|
459
|
+
}
|
|
460
|
+
else if (saveOriginalFileIfRequired) {
|
|
461
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
640
462
|
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
641
463
|
didSaveToTmpPath = true;
|
|
642
464
|
}
|
|
643
|
-
|
|
465
|
+
|
|
644
466
|
let fileLength = 0;
|
|
645
467
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
646
468
|
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
647
469
|
let sha256Plain = Crypto.createHash('sha256');
|
|
648
470
|
let sha256Enc = Crypto.createHash('sha256');
|
|
649
|
-
|
|
471
|
+
|
|
650
472
|
try {
|
|
651
473
|
for await (const data of finalStream) {
|
|
652
474
|
fileLength += data.length;
|
|
653
|
-
if (type === 'remote'
|
|
475
|
+
if (type === 'remote'
|
|
476
|
+
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
477
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
654
478
|
throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
|
|
655
479
|
data: { media, type }
|
|
656
480
|
});
|
|
657
481
|
}
|
|
482
|
+
|
|
658
483
|
sha256Plain = sha256Plain.update(data);
|
|
659
484
|
if (writeStream) {
|
|
660
485
|
if (!writeStream.write(data)) {
|
|
@@ -663,20 +488,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
663
488
|
}
|
|
664
489
|
onChunk(aes.update(data));
|
|
665
490
|
}
|
|
666
|
-
|
|
491
|
+
|
|
667
492
|
onChunk(aes.final());
|
|
668
493
|
const mac = hmac.digest().slice(0, 10);
|
|
669
494
|
sha256Enc = sha256Enc.update(mac);
|
|
670
495
|
const fileSha256 = sha256Plain.digest();
|
|
671
496
|
const fileEncSha256 = sha256Enc.digest();
|
|
672
|
-
|
|
497
|
+
|
|
673
498
|
encWriteStream.push(mac);
|
|
674
499
|
encWriteStream.push(null);
|
|
675
|
-
writeStream
|
|
500
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
676
501
|
finalStream.destroy();
|
|
677
|
-
|
|
678
|
-
logger?.debug('encrypted data successfully');
|
|
679
|
-
|
|
502
|
+
|
|
680
503
|
return {
|
|
681
504
|
mediaKey,
|
|
682
505
|
encWriteStream,
|
|
@@ -687,25 +510,26 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
687
510
|
fileLength,
|
|
688
511
|
didSaveToTmpPath
|
|
689
512
|
};
|
|
690
|
-
}
|
|
513
|
+
}
|
|
514
|
+
catch (error) {
|
|
691
515
|
encWriteStream.destroy();
|
|
692
|
-
writeStream
|
|
516
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
|
693
517
|
aes.destroy();
|
|
694
518
|
hmac.destroy();
|
|
695
519
|
sha256Plain.destroy();
|
|
696
520
|
sha256Enc.destroy();
|
|
697
521
|
finalStream.destroy();
|
|
698
|
-
|
|
522
|
+
|
|
699
523
|
if (didSaveToTmpPath) {
|
|
700
524
|
try {
|
|
701
525
|
await fs_1.promises.unlink(bodyPath);
|
|
702
|
-
}
|
|
703
|
-
|
|
526
|
+
}
|
|
527
|
+
catch (err) {
|
|
704
528
|
}
|
|
705
529
|
}
|
|
706
530
|
throw error;
|
|
707
531
|
}
|
|
708
|
-
|
|
532
|
+
|
|
709
533
|
function onChunk(buff) {
|
|
710
534
|
sha256Enc = sha256Enc.update(buff);
|
|
711
535
|
hmac = hmac.update(buff);
|
|
@@ -720,20 +544,21 @@ const toSmallestChunkSize = (num) => {
|
|
|
720
544
|
};
|
|
721
545
|
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
722
546
|
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
723
|
-
const downloadContentFromMessage =
|
|
724
|
-
const
|
|
725
|
-
const
|
|
726
|
-
if (!downloadUrl) {
|
|
727
|
-
throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
728
|
-
}
|
|
729
|
-
const keys = await getMediaKeys(mediaKey, type);
|
|
547
|
+
const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
548
|
+
const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
|
|
549
|
+
const keys = getMediaKeys(mediaKey, type);
|
|
730
550
|
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
731
551
|
};
|
|
732
552
|
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
553
|
+
/**
|
|
554
|
+
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
555
|
+
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
556
|
+
* */
|
|
733
557
|
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
734
558
|
let bytesFetched = 0;
|
|
735
559
|
let startChunk = 0;
|
|
736
560
|
let firstBlockIsIV = false;
|
|
561
|
+
// if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
|
|
737
562
|
if (startByte) {
|
|
738
563
|
const chunk = toSmallestChunkSize(startByte || 0);
|
|
739
564
|
if (chunk) {
|
|
@@ -753,6 +578,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
753
578
|
headers.Range += endChunk;
|
|
754
579
|
}
|
|
755
580
|
}
|
|
581
|
+
// download the message
|
|
756
582
|
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
757
583
|
...options || {},
|
|
758
584
|
headers,
|
|
@@ -785,6 +611,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
785
611
|
data = data.slice(AES_CHUNK_SIZE);
|
|
786
612
|
}
|
|
787
613
|
aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
|
|
614
|
+
// if an end byte that is not EOF is specified
|
|
615
|
+
// stop auto padding (PKCS7) -- otherwise throws an error for decryption
|
|
788
616
|
if (endByte) {
|
|
789
617
|
aes.setAutoPadding(false);
|
|
790
618
|
}
|
|
@@ -825,9 +653,12 @@ function extensionForMediaMessage(message) {
|
|
|
825
653
|
}
|
|
826
654
|
return extension;
|
|
827
655
|
}
|
|
656
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
828
657
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
829
658
|
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
830
659
|
var _a, _b;
|
|
660
|
+
const { default: axios } = await import('axios');
|
|
661
|
+
// send a query JSON to obtain the url & auth token to upload our media
|
|
831
662
|
let uploadInfo = await refreshMediaConn(false);
|
|
832
663
|
let urls;
|
|
833
664
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
@@ -845,14 +676,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
845
676
|
}
|
|
846
677
|
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
847
678
|
logger.debug(`uploading to "${hostname}"`);
|
|
848
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
679
|
+
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
849
680
|
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
850
681
|
let result;
|
|
851
682
|
try {
|
|
852
683
|
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
853
684
|
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
854
685
|
}
|
|
855
|
-
const body = await
|
|
686
|
+
const body = await axios.post(url, reqBody, {
|
|
856
687
|
...options,
|
|
857
688
|
headers: {
|
|
858
689
|
...options.headers || {},
|
|
@@ -880,7 +711,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
880
711
|
}
|
|
881
712
|
}
|
|
882
713
|
catch (error) {
|
|
883
|
-
if (
|
|
714
|
+
if (axios.isAxiosError(error)) {
|
|
884
715
|
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
885
716
|
}
|
|
886
717
|
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
@@ -897,11 +728,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
|
|
|
897
728
|
const getMediaRetryKey = (mediaKey) => {
|
|
898
729
|
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
899
730
|
};
|
|
900
|
-
|
|
731
|
+
/**
|
|
732
|
+
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
733
|
+
*/
|
|
734
|
+
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
901
735
|
const recp = { stanzaId: key.id };
|
|
902
736
|
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
903
737
|
const iv = Crypto.randomBytes(12);
|
|
904
|
-
const retryKey =
|
|
738
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
905
739
|
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
906
740
|
const req = {
|
|
907
741
|
tag: 'receipt',
|
|
@@ -911,6 +745,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
911
745
|
type: 'server-error'
|
|
912
746
|
},
|
|
913
747
|
content: [
|
|
748
|
+
// this encrypt node is actually pretty useless
|
|
749
|
+
// the media is returned even without this node
|
|
750
|
+
// keeping it here to maintain parity with WA Web
|
|
914
751
|
{
|
|
915
752
|
tag: 'encrypt',
|
|
916
753
|
attrs: {},
|
|
@@ -924,6 +761,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
924
761
|
attrs: {
|
|
925
762
|
jid: key.remoteJid,
|
|
926
763
|
'from_me': (!!key.fromMe).toString(),
|
|
764
|
+
// @ts-ignore
|
|
927
765
|
participant: key.participant || undefined
|
|
928
766
|
}
|
|
929
767
|
}
|
|
@@ -961,8 +799,8 @@ const decodeMediaRetryNode = (node) => {
|
|
|
961
799
|
return event;
|
|
962
800
|
};
|
|
963
801
|
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
964
|
-
const decryptMediaRetryData =
|
|
965
|
-
const retryKey =
|
|
802
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
803
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
966
804
|
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
967
805
|
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
968
806
|
};
|
|
@@ -975,6 +813,7 @@ const MEDIA_RETRY_STATUS_MAP = {
|
|
|
975
813
|
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
976
814
|
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
977
815
|
};
|
|
816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
978
817
|
function __importStar(arg0) {
|
|
979
818
|
throw new Error('Function not implemented.');
|
|
980
|
-
}
|
|
819
|
+
}
|