@modzneverdie/baileys 17.1.12 → 17.1.17
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/README.md +364 -0
- package/engine-requirements.js +4 -4
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.d.ts +6 -4
- package/lib/Defaults/index.js +119 -78
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +2 -1
- 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/{websocket.d.ts → web-socket-client.d.ts} +1 -2
- package/lib/Socket/Client/{websocket.js → web-socket-client.js} +5 -54
- 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/{setup.ts → dugong.d.ts} +52 -17
- package/lib/Socket/dugong.js +484 -0
- 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 +399 -415
- package/lib/Socket/newsletter.d.ts +37 -39
- package/lib/Socket/newsletter.js +136 -71
- package/lib/Socket/registration.d.ts +267 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +10 -10
- package/lib/Socket/socket.js +617 -754
- 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 +84 -102
- 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 +236 -298
- package/lib/Utils/messages.d.ts +10 -8
- package/lib/Utils/messages.js +60 -304
- 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 -89
- 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 +76 -20
- 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 -10
- package/lib/WABinary/jid-utils.js +5 -26
- 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 +2 -6
- package/lib/index.js +6 -20
- package/package.json +105 -107
- 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.js +0 -433
- package/lib/WABinary/jid-utils.js.bak +0 -83
- /package/lib/Socket/Client/{types.js → abstract-socket-client.js} +0 -0
|
@@ -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
|
};
|
|
@@ -349,60 +188,138 @@ const mediaMessageSHA256B64 = (message) => {
|
|
|
349
188
|
};
|
|
350
189
|
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
|
|
351
190
|
async function getAudioDuration(buffer) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return metadata.format.duration;
|
|
365
227
|
}
|
|
366
|
-
return metadata.format.duration;
|
|
367
228
|
}
|
|
229
|
+
exports.getAudioDuration = getAudioDuration;
|
|
368
230
|
async function getAudioWaveform(buffer, logger) {
|
|
369
231
|
try {
|
|
370
|
-
const {
|
|
232
|
+
const { PassThrough } = require('stream');
|
|
233
|
+
const ff = require('fluent-ffmpeg');
|
|
234
|
+
|
|
371
235
|
let audioData;
|
|
372
236
|
if (Buffer.isBuffer(buffer)) {
|
|
373
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);
|
|
374
243
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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);
|
|
401
281
|
}
|
|
402
|
-
|
|
403
|
-
|
|
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;
|
|
404
320
|
}
|
|
405
321
|
}
|
|
322
|
+
exports.convertToOpusBuffer = convertToOpusBuffer;
|
|
406
323
|
const toReadable = (buffer) => {
|
|
407
324
|
const readable = new stream_1.Readable({ read: () => { } });
|
|
408
325
|
readable.push(buffer);
|
|
@@ -448,28 +365,12 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
448
365
|
}
|
|
449
366
|
}
|
|
450
367
|
else if (mediaType === 'video') {
|
|
368
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
451
369
|
try {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
|
|
456
|
-
await fs_1.promises.writeFile(videoPath, buffer);
|
|
457
|
-
}
|
|
458
|
-
const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
|
|
459
|
-
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
|
|
460
|
-
await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
|
|
461
|
-
const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
|
|
462
|
-
thumbnail = processedThumbnailBuffer.toString('base64');
|
|
463
|
-
if (original.width && original.height) {
|
|
464
|
-
originalImageDimensions = {
|
|
465
|
-
width: original.width,
|
|
466
|
-
height: original.height,
|
|
467
|
-
};
|
|
468
|
-
}
|
|
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');
|
|
469
373
|
await fs_1.promises.unlink(imgFilename);
|
|
470
|
-
if (videoPath !== file) {
|
|
471
|
-
await fs_1.promises.unlink(videoPath);
|
|
472
|
-
}
|
|
473
374
|
}
|
|
474
375
|
catch (err) {
|
|
475
376
|
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
@@ -480,8 +381,10 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
480
381
|
originalImageDimensions
|
|
481
382
|
};
|
|
482
383
|
}
|
|
384
|
+
exports.generateThumbnail = generateThumbnail;
|
|
483
385
|
const getHttpStream = async (url, options = {}) => {
|
|
484
|
-
const
|
|
386
|
+
const { default: axios } = await import('axios');
|
|
387
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
485
388
|
return fetched.data;
|
|
486
389
|
};
|
|
487
390
|
exports.getHttpStream = getHttpStream;
|
|
@@ -496,7 +399,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
496
399
|
bodyPath = media.url;
|
|
497
400
|
}
|
|
498
401
|
else if (saveOriginalFileIfRequired) {
|
|
499
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
402
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
500
403
|
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
501
404
|
didSaveToTmpPath = true;
|
|
502
405
|
}
|
|
@@ -515,6 +418,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
515
418
|
};
|
|
516
419
|
}
|
|
517
420
|
catch (error) {
|
|
421
|
+
// destroy all streams with error
|
|
518
422
|
stream.destroy();
|
|
519
423
|
if (didSaveToTmpPath) {
|
|
520
424
|
try {
|
|
@@ -528,30 +432,45 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
528
432
|
}
|
|
529
433
|
};
|
|
530
434
|
exports.prepareStream = prepareStream;
|
|
531
|
-
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
435
|
+
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
532
436
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
533
|
-
|
|
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
|
+
|
|
534
450
|
const mediaKey = Crypto.randomBytes(32);
|
|
535
|
-
const { cipherKey, iv, macKey } =
|
|
451
|
+
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
536
452
|
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
537
453
|
let bodyPath;
|
|
538
454
|
let writeStream;
|
|
539
455
|
let didSaveToTmpPath = false;
|
|
456
|
+
|
|
540
457
|
if (type === 'file') {
|
|
541
458
|
bodyPath = media.url;
|
|
542
459
|
}
|
|
543
460
|
else if (saveOriginalFileIfRequired) {
|
|
544
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
461
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
545
462
|
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
546
463
|
didSaveToTmpPath = true;
|
|
547
464
|
}
|
|
465
|
+
|
|
548
466
|
let fileLength = 0;
|
|
549
467
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
550
468
|
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
551
469
|
let sha256Plain = Crypto.createHash('sha256');
|
|
552
470
|
let sha256Enc = Crypto.createHash('sha256');
|
|
471
|
+
|
|
553
472
|
try {
|
|
554
|
-
for await (const data of
|
|
473
|
+
for await (const data of finalStream) {
|
|
555
474
|
fileLength += data.length;
|
|
556
475
|
if (type === 'remote'
|
|
557
476
|
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
@@ -560,6 +479,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
560
479
|
data: { media, type }
|
|
561
480
|
});
|
|
562
481
|
}
|
|
482
|
+
|
|
563
483
|
sha256Plain = sha256Plain.update(data);
|
|
564
484
|
if (writeStream) {
|
|
565
485
|
if (!writeStream.write(data)) {
|
|
@@ -568,16 +488,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
568
488
|
}
|
|
569
489
|
onChunk(aes.update(data));
|
|
570
490
|
}
|
|
491
|
+
|
|
571
492
|
onChunk(aes.final());
|
|
572
493
|
const mac = hmac.digest().slice(0, 10);
|
|
573
494
|
sha256Enc = sha256Enc.update(mac);
|
|
574
495
|
const fileSha256 = sha256Plain.digest();
|
|
575
496
|
const fileEncSha256 = sha256Enc.digest();
|
|
497
|
+
|
|
576
498
|
encWriteStream.push(mac);
|
|
577
499
|
encWriteStream.push(null);
|
|
578
500
|
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
579
|
-
|
|
580
|
-
|
|
501
|
+
finalStream.destroy();
|
|
502
|
+
|
|
581
503
|
return {
|
|
582
504
|
mediaKey,
|
|
583
505
|
encWriteStream,
|
|
@@ -596,17 +518,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
596
518
|
hmac.destroy();
|
|
597
519
|
sha256Plain.destroy();
|
|
598
520
|
sha256Enc.destroy();
|
|
599
|
-
|
|
521
|
+
finalStream.destroy();
|
|
522
|
+
|
|
600
523
|
if (didSaveToTmpPath) {
|
|
601
524
|
try {
|
|
602
525
|
await fs_1.promises.unlink(bodyPath);
|
|
603
526
|
}
|
|
604
527
|
catch (err) {
|
|
605
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
606
528
|
}
|
|
607
529
|
}
|
|
608
530
|
throw error;
|
|
609
531
|
}
|
|
532
|
+
|
|
610
533
|
function onChunk(buff) {
|
|
611
534
|
sha256Enc = sha256Enc.update(buff);
|
|
612
535
|
hmac = hmac.update(buff);
|
|
@@ -621,20 +544,21 @@ const toSmallestChunkSize = (num) => {
|
|
|
621
544
|
};
|
|
622
545
|
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
623
546
|
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
624
|
-
const downloadContentFromMessage =
|
|
625
|
-
const
|
|
626
|
-
const
|
|
627
|
-
if (!downloadUrl) {
|
|
628
|
-
throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
629
|
-
}
|
|
630
|
-
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);
|
|
631
550
|
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
632
551
|
};
|
|
633
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
|
+
* */
|
|
634
557
|
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
635
558
|
let bytesFetched = 0;
|
|
636
559
|
let startChunk = 0;
|
|
637
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
|
|
638
562
|
if (startByte) {
|
|
639
563
|
const chunk = toSmallestChunkSize(startByte || 0);
|
|
640
564
|
if (chunk) {
|
|
@@ -654,6 +578,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
654
578
|
headers.Range += endChunk;
|
|
655
579
|
}
|
|
656
580
|
}
|
|
581
|
+
// download the message
|
|
657
582
|
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
658
583
|
...options || {},
|
|
659
584
|
headers,
|
|
@@ -686,6 +611,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
686
611
|
data = data.slice(AES_CHUNK_SIZE);
|
|
687
612
|
}
|
|
688
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
|
|
689
616
|
if (endByte) {
|
|
690
617
|
aes.setAutoPadding(false);
|
|
691
618
|
}
|
|
@@ -726,9 +653,12 @@ function extensionForMediaMessage(message) {
|
|
|
726
653
|
}
|
|
727
654
|
return extension;
|
|
728
655
|
}
|
|
656
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
729
657
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
730
658
|
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
731
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
|
|
732
662
|
let uploadInfo = await refreshMediaConn(false);
|
|
733
663
|
let urls;
|
|
734
664
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
@@ -746,14 +676,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
746
676
|
}
|
|
747
677
|
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
748
678
|
logger.debug(`uploading to "${hostname}"`);
|
|
749
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
679
|
+
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
750
680
|
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
751
681
|
let result;
|
|
752
682
|
try {
|
|
753
683
|
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
754
684
|
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
755
685
|
}
|
|
756
|
-
const body = await
|
|
686
|
+
const body = await axios.post(url, reqBody, {
|
|
757
687
|
...options,
|
|
758
688
|
headers: {
|
|
759
689
|
...options.headers || {},
|
|
@@ -781,7 +711,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
781
711
|
}
|
|
782
712
|
}
|
|
783
713
|
catch (error) {
|
|
784
|
-
if (
|
|
714
|
+
if (axios.isAxiosError(error)) {
|
|
785
715
|
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
786
716
|
}
|
|
787
717
|
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
@@ -798,11 +728,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
|
|
|
798
728
|
const getMediaRetryKey = (mediaKey) => {
|
|
799
729
|
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
800
730
|
};
|
|
801
|
-
|
|
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) => {
|
|
802
735
|
const recp = { stanzaId: key.id };
|
|
803
736
|
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
804
737
|
const iv = Crypto.randomBytes(12);
|
|
805
|
-
const retryKey =
|
|
738
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
806
739
|
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
807
740
|
const req = {
|
|
808
741
|
tag: 'receipt',
|
|
@@ -812,6 +745,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
812
745
|
type: 'server-error'
|
|
813
746
|
},
|
|
814
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
|
|
815
751
|
{
|
|
816
752
|
tag: 'encrypt',
|
|
817
753
|
attrs: {},
|
|
@@ -825,6 +761,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
825
761
|
attrs: {
|
|
826
762
|
jid: key.remoteJid,
|
|
827
763
|
'from_me': (!!key.fromMe).toString(),
|
|
764
|
+
// @ts-ignore
|
|
828
765
|
participant: key.participant || undefined
|
|
829
766
|
}
|
|
830
767
|
}
|
|
@@ -862,8 +799,8 @@ const decodeMediaRetryNode = (node) => {
|
|
|
862
799
|
return event;
|
|
863
800
|
};
|
|
864
801
|
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
865
|
-
const decryptMediaRetryData =
|
|
866
|
-
const retryKey =
|
|
802
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
803
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
867
804
|
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
868
805
|
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
869
806
|
};
|
|
@@ -876,6 +813,7 @@ const MEDIA_RETRY_STATUS_MAP = {
|
|
|
876
813
|
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
877
814
|
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
878
815
|
};
|
|
816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
879
817
|
function __importStar(arg0) {
|
|
880
818
|
throw new Error('Function not implemented.');
|
|
881
|
-
}
|
|
819
|
+
}
|