alipclutch-baileys 6.7.0 → 7.1.0
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/LICENSE +1 -1
- package/WAProto/index.js +77698 -117050
- package/engine-requirements.js +3 -3
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +6 -4
- package/lib/Defaults/index.js +118 -78
- 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/types.d.ts +1 -0
- package/lib/Socket/Client/types.js +1 -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/Client/websocket.d.ts +1 -0
- package/lib/Socket/Client/websocket.js +1 -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/dugong.d.ts +254 -0
- package/lib/Socket/dugong.js +483 -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 +420 -382
- package/lib/Socket/newsletter.d.ts +37 -39
- package/lib/Socket/newsletter.js +124 -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 +38 -62
- package/lib/Socket/usync.d.ts +4 -3
- package/lib/Socket/usync.js +1 -0
- 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 +76 -96
- 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 -296
- package/lib/Utils/messages.d.ts +10 -13
- package/lib/Utils/messages.js +92 -325
- 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 +6 -51
- package/lib/Utils/validate-connection.d.ts +4 -3
- package/lib/Utils/validate-connection.js +52 -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 -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 +36 -43
- package/package.json +1 -1
- 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/WAProto/p.html +0 -1
- package/lib/Defaults/wileys-version.json +0 -3
- package/lib/WABinary/jid-utils.js.bak +0 -83
- /package/{README.MD → README.md} +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,58 +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
|
-
|
|
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);
|
|
399
281
|
}
|
|
400
|
-
|
|
401
|
-
|
|
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;
|
|
402
320
|
}
|
|
403
321
|
}
|
|
322
|
+
exports.convertToOpusBuffer = convertToOpusBuffer;
|
|
404
323
|
const toReadable = (buffer) => {
|
|
405
324
|
const readable = new stream_1.Readable({ read: () => { } });
|
|
406
325
|
readable.push(buffer);
|
|
@@ -446,28 +365,12 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
446
365
|
}
|
|
447
366
|
}
|
|
448
367
|
else if (mediaType === 'video') {
|
|
368
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
449
369
|
try {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
|
|
454
|
-
await fs_1.promises.writeFile(videoPath, buffer);
|
|
455
|
-
}
|
|
456
|
-
const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
|
|
457
|
-
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
|
|
458
|
-
await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
|
|
459
|
-
const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
|
|
460
|
-
thumbnail = processedThumbnailBuffer.toString('base64');
|
|
461
|
-
if (original.width && original.height) {
|
|
462
|
-
originalImageDimensions = {
|
|
463
|
-
width: original.width,
|
|
464
|
-
height: original.height,
|
|
465
|
-
};
|
|
466
|
-
}
|
|
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');
|
|
467
373
|
await fs_1.promises.unlink(imgFilename);
|
|
468
|
-
if (videoPath !== file) {
|
|
469
|
-
await fs_1.promises.unlink(videoPath);
|
|
470
|
-
}
|
|
471
374
|
}
|
|
472
375
|
catch (err) {
|
|
473
376
|
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
@@ -478,8 +381,10 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
478
381
|
originalImageDimensions
|
|
479
382
|
};
|
|
480
383
|
}
|
|
384
|
+
exports.generateThumbnail = generateThumbnail;
|
|
481
385
|
const getHttpStream = async (url, options = {}) => {
|
|
482
|
-
const
|
|
386
|
+
const { default: axios } = await import('axios');
|
|
387
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
483
388
|
return fetched.data;
|
|
484
389
|
};
|
|
485
390
|
exports.getHttpStream = getHttpStream;
|
|
@@ -494,7 +399,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
494
399
|
bodyPath = media.url;
|
|
495
400
|
}
|
|
496
401
|
else if (saveOriginalFileIfRequired) {
|
|
497
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
402
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
498
403
|
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
499
404
|
didSaveToTmpPath = true;
|
|
500
405
|
}
|
|
@@ -513,6 +418,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
513
418
|
};
|
|
514
419
|
}
|
|
515
420
|
catch (error) {
|
|
421
|
+
// destroy all streams with error
|
|
516
422
|
stream.destroy();
|
|
517
423
|
if (didSaveToTmpPath) {
|
|
518
424
|
try {
|
|
@@ -526,30 +432,45 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
526
432
|
}
|
|
527
433
|
};
|
|
528
434
|
exports.prepareStream = prepareStream;
|
|
529
|
-
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
435
|
+
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
530
436
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
531
|
-
|
|
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
|
+
|
|
532
450
|
const mediaKey = Crypto.randomBytes(32);
|
|
533
|
-
const { cipherKey, iv, macKey } =
|
|
451
|
+
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
534
452
|
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
535
453
|
let bodyPath;
|
|
536
454
|
let writeStream;
|
|
537
455
|
let didSaveToTmpPath = false;
|
|
456
|
+
|
|
538
457
|
if (type === 'file') {
|
|
539
458
|
bodyPath = media.url;
|
|
540
459
|
}
|
|
541
460
|
else if (saveOriginalFileIfRequired) {
|
|
542
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
461
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
543
462
|
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
544
463
|
didSaveToTmpPath = true;
|
|
545
464
|
}
|
|
465
|
+
|
|
546
466
|
let fileLength = 0;
|
|
547
467
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
548
468
|
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
549
469
|
let sha256Plain = Crypto.createHash('sha256');
|
|
550
470
|
let sha256Enc = Crypto.createHash('sha256');
|
|
471
|
+
|
|
551
472
|
try {
|
|
552
|
-
for await (const data of
|
|
473
|
+
for await (const data of finalStream) {
|
|
553
474
|
fileLength += data.length;
|
|
554
475
|
if (type === 'remote'
|
|
555
476
|
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
@@ -558,6 +479,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
558
479
|
data: { media, type }
|
|
559
480
|
});
|
|
560
481
|
}
|
|
482
|
+
|
|
561
483
|
sha256Plain = sha256Plain.update(data);
|
|
562
484
|
if (writeStream) {
|
|
563
485
|
if (!writeStream.write(data)) {
|
|
@@ -566,16 +488,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
566
488
|
}
|
|
567
489
|
onChunk(aes.update(data));
|
|
568
490
|
}
|
|
491
|
+
|
|
569
492
|
onChunk(aes.final());
|
|
570
493
|
const mac = hmac.digest().slice(0, 10);
|
|
571
494
|
sha256Enc = sha256Enc.update(mac);
|
|
572
495
|
const fileSha256 = sha256Plain.digest();
|
|
573
496
|
const fileEncSha256 = sha256Enc.digest();
|
|
497
|
+
|
|
574
498
|
encWriteStream.push(mac);
|
|
575
499
|
encWriteStream.push(null);
|
|
576
500
|
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
577
|
-
|
|
578
|
-
|
|
501
|
+
finalStream.destroy();
|
|
502
|
+
|
|
579
503
|
return {
|
|
580
504
|
mediaKey,
|
|
581
505
|
encWriteStream,
|
|
@@ -594,17 +518,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
594
518
|
hmac.destroy();
|
|
595
519
|
sha256Plain.destroy();
|
|
596
520
|
sha256Enc.destroy();
|
|
597
|
-
|
|
521
|
+
finalStream.destroy();
|
|
522
|
+
|
|
598
523
|
if (didSaveToTmpPath) {
|
|
599
524
|
try {
|
|
600
525
|
await fs_1.promises.unlink(bodyPath);
|
|
601
526
|
}
|
|
602
527
|
catch (err) {
|
|
603
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
604
528
|
}
|
|
605
529
|
}
|
|
606
530
|
throw error;
|
|
607
531
|
}
|
|
532
|
+
|
|
608
533
|
function onChunk(buff) {
|
|
609
534
|
sha256Enc = sha256Enc.update(buff);
|
|
610
535
|
hmac = hmac.update(buff);
|
|
@@ -619,20 +544,21 @@ const toSmallestChunkSize = (num) => {
|
|
|
619
544
|
};
|
|
620
545
|
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
621
546
|
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
622
|
-
const downloadContentFromMessage =
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
if (!downloadUrl) {
|
|
626
|
-
throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
627
|
-
}
|
|
628
|
-
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);
|
|
629
550
|
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
630
551
|
};
|
|
631
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
|
+
* */
|
|
632
557
|
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
633
558
|
let bytesFetched = 0;
|
|
634
559
|
let startChunk = 0;
|
|
635
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
|
|
636
562
|
if (startByte) {
|
|
637
563
|
const chunk = toSmallestChunkSize(startByte || 0);
|
|
638
564
|
if (chunk) {
|
|
@@ -652,6 +578,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
652
578
|
headers.Range += endChunk;
|
|
653
579
|
}
|
|
654
580
|
}
|
|
581
|
+
// download the message
|
|
655
582
|
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
656
583
|
...options || {},
|
|
657
584
|
headers,
|
|
@@ -684,6 +611,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
684
611
|
data = data.slice(AES_CHUNK_SIZE);
|
|
685
612
|
}
|
|
686
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
|
|
687
616
|
if (endByte) {
|
|
688
617
|
aes.setAutoPadding(false);
|
|
689
618
|
}
|
|
@@ -724,9 +653,12 @@ function extensionForMediaMessage(message) {
|
|
|
724
653
|
}
|
|
725
654
|
return extension;
|
|
726
655
|
}
|
|
656
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
727
657
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
728
658
|
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
729
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
|
|
730
662
|
let uploadInfo = await refreshMediaConn(false);
|
|
731
663
|
let urls;
|
|
732
664
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
@@ -744,14 +676,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
744
676
|
}
|
|
745
677
|
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
746
678
|
logger.debug(`uploading to "${hostname}"`);
|
|
747
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
679
|
+
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
748
680
|
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
749
681
|
let result;
|
|
750
682
|
try {
|
|
751
683
|
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
752
684
|
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
753
685
|
}
|
|
754
|
-
const body = await
|
|
686
|
+
const body = await axios.post(url, reqBody, {
|
|
755
687
|
...options,
|
|
756
688
|
headers: {
|
|
757
689
|
...options.headers || {},
|
|
@@ -779,7 +711,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
779
711
|
}
|
|
780
712
|
}
|
|
781
713
|
catch (error) {
|
|
782
|
-
if (
|
|
714
|
+
if (axios.isAxiosError(error)) {
|
|
783
715
|
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
784
716
|
}
|
|
785
717
|
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
@@ -796,11 +728,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
|
|
|
796
728
|
const getMediaRetryKey = (mediaKey) => {
|
|
797
729
|
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
798
730
|
};
|
|
799
|
-
|
|
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) => {
|
|
800
735
|
const recp = { stanzaId: key.id };
|
|
801
736
|
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
802
737
|
const iv = Crypto.randomBytes(12);
|
|
803
|
-
const retryKey =
|
|
738
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
804
739
|
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
805
740
|
const req = {
|
|
806
741
|
tag: 'receipt',
|
|
@@ -810,6 +745,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
810
745
|
type: 'server-error'
|
|
811
746
|
},
|
|
812
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
|
|
813
751
|
{
|
|
814
752
|
tag: 'encrypt',
|
|
815
753
|
attrs: {},
|
|
@@ -823,6 +761,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
823
761
|
attrs: {
|
|
824
762
|
jid: key.remoteJid,
|
|
825
763
|
'from_me': (!!key.fromMe).toString(),
|
|
764
|
+
// @ts-ignore
|
|
826
765
|
participant: key.participant || undefined
|
|
827
766
|
}
|
|
828
767
|
}
|
|
@@ -860,8 +799,8 @@ const decodeMediaRetryNode = (node) => {
|
|
|
860
799
|
return event;
|
|
861
800
|
};
|
|
862
801
|
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
863
|
-
const decryptMediaRetryData =
|
|
864
|
-
const retryKey =
|
|
802
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
803
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
865
804
|
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
866
805
|
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
867
806
|
};
|
|
@@ -874,6 +813,7 @@ const MEDIA_RETRY_STATUS_MAP = {
|
|
|
874
813
|
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
875
814
|
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
876
815
|
};
|
|
816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
877
817
|
function __importStar(arg0) {
|
|
878
818
|
throw new Error('Function not implemented.');
|
|
879
|
-
}
|
|
819
|
+
}
|