cuki-bailx 1.1.2 → 1.2.3
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/WAProto/index.js +79296 -118676
- package/engine-requirements.js +1 -1
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.d.ts +6 -4
- package/lib/Defaults/index.js +102 -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} +2 -12
- package/lib/Socket/business.d.ts +58 -59
- package/lib/Socket/chats.d.ts +27 -29
- package/lib/Socket/chats.js +90 -97
- package/lib/Socket/dugong.d.ts +219 -0
- package/lib/Socket/dugong.js +441 -0
- package/lib/Socket/groups.d.ts +32 -41
- package/lib/Socket/groups.js +5 -20
- package/lib/Socket/index.d.ts +64 -63
- package/lib/Socket/index.js +2 -2
- package/lib/Socket/messages-recv.js +65 -9
- package/lib/Socket/messages-send.d.ts +47 -49
- package/lib/Socket/messages-send.js +312 -379
- package/lib/Socket/newsletter.d.ts +37 -39
- package/lib/Socket/newsletter.js +40 -54
- 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 +32 -39
- package/lib/Socket/socket.js.bak +630 -0
- 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 +11 -13
- 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 +13 -0
- package/lib/Types/Newsletter.js +17 -3
- 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 +23 -73
- 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 +115 -263
- package/lib/Utils/messages.d.ts +10 -8
- package/lib/Utils/messages.js +72 -298
- 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 +23 -74
- package/lib/Utils/signal.d.ts +1 -2
- package/lib/Utils/signal.js +35 -37
- 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 +4 -4
- 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 +17 -39
- package/lib/WABinary/generic-utils.d.ts +3 -1
- package/lib/WABinary/generic-utils.js +85 -2
- 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 +7 -21
- package/lib/index.js.bak +48 -0
- package/package.json +103 -111
- package/LICENSE +0 -21
- 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/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,25 +188,32 @@ const mediaMessageSHA256B64 = (message) => {
|
|
|
349
188
|
};
|
|
350
189
|
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
|
|
351
190
|
async function getAudioDuration(buffer) {
|
|
352
|
-
const musicMetadata = await
|
|
191
|
+
const musicMetadata = await import('music-metadata');
|
|
353
192
|
let metadata;
|
|
354
|
-
const options = {
|
|
355
|
-
duration: true
|
|
356
|
-
};
|
|
357
193
|
if (Buffer.isBuffer(buffer)) {
|
|
358
|
-
metadata = await musicMetadata.parseBuffer(buffer, undefined,
|
|
194
|
+
metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
|
|
359
195
|
}
|
|
360
196
|
else if (typeof buffer === 'string') {
|
|
361
|
-
|
|
197
|
+
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
198
|
+
try {
|
|
199
|
+
metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
rStream.destroy();
|
|
203
|
+
}
|
|
362
204
|
}
|
|
363
205
|
else {
|
|
364
|
-
metadata = await musicMetadata.parseStream(buffer, undefined,
|
|
206
|
+
metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
|
|
365
207
|
}
|
|
366
208
|
return metadata.format.duration;
|
|
367
209
|
}
|
|
210
|
+
exports.getAudioDuration = getAudioDuration;
|
|
211
|
+
/**
|
|
212
|
+
referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
|
|
213
|
+
*/
|
|
368
214
|
async function getAudioWaveform(buffer, logger) {
|
|
369
215
|
try {
|
|
370
|
-
const
|
|
216
|
+
const audioDecode = (buffer) => import('audio-decode').then(({ default: audioDecode }) => audioDecode(buffer));
|
|
371
217
|
let audioData;
|
|
372
218
|
if (Buffer.isBuffer(buffer)) {
|
|
373
219
|
audioData = buffer;
|
|
@@ -379,21 +225,23 @@ async function getAudioWaveform(buffer, logger) {
|
|
|
379
225
|
else {
|
|
380
226
|
audioData = await (0, exports.toBuffer)(buffer);
|
|
381
227
|
}
|
|
382
|
-
const audioBuffer = await
|
|
383
|
-
const rawData = audioBuffer.getChannelData(0);
|
|
384
|
-
const samples = 64;
|
|
385
|
-
const blockSize = Math.floor(rawData.length / samples);
|
|
228
|
+
const audioBuffer = await audioDecode(audioData);
|
|
229
|
+
const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
|
|
230
|
+
const samples = 64; // Number of samples we want to have in our final data set
|
|
231
|
+
const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
|
|
386
232
|
const filteredData = [];
|
|
387
233
|
for (let i = 0; i < samples; i++) {
|
|
388
|
-
const blockStart = blockSize * i;
|
|
234
|
+
const blockStart = blockSize * i; // the location of the first sample in the block
|
|
389
235
|
let sum = 0;
|
|
390
236
|
for (let j = 0; j < blockSize; j++) {
|
|
391
|
-
sum = sum + Math.abs(rawData[blockStart + j]);
|
|
237
|
+
sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
|
|
392
238
|
}
|
|
393
|
-
filteredData.push(sum / blockSize);
|
|
239
|
+
filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
|
|
394
240
|
}
|
|
241
|
+
// This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
|
|
395
242
|
const multiplier = Math.pow(Math.max(...filteredData), -1);
|
|
396
243
|
const normalizedData = filteredData.map((n) => n * multiplier);
|
|
244
|
+
// Generate waveform like WhatsApp
|
|
397
245
|
const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
|
|
398
246
|
return waveform;
|
|
399
247
|
}
|
|
@@ -401,6 +249,7 @@ async function getAudioWaveform(buffer, logger) {
|
|
|
401
249
|
logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
|
|
402
250
|
}
|
|
403
251
|
}
|
|
252
|
+
exports.getAudioWaveform = getAudioWaveform;
|
|
404
253
|
const toReadable = (buffer) => {
|
|
405
254
|
const readable = new stream_1.Readable({ read: () => { } });
|
|
406
255
|
readable.push(buffer);
|
|
@@ -446,28 +295,12 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
446
295
|
}
|
|
447
296
|
}
|
|
448
297
|
else if (mediaType === 'video') {
|
|
298
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
449
299
|
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
|
-
}
|
|
300
|
+
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
301
|
+
const buff = await fs_1.promises.readFile(imgFilename);
|
|
302
|
+
thumbnail = buff.toString('base64');
|
|
467
303
|
await fs_1.promises.unlink(imgFilename);
|
|
468
|
-
if (videoPath !== file) {
|
|
469
|
-
await fs_1.promises.unlink(videoPath);
|
|
470
|
-
}
|
|
471
304
|
}
|
|
472
305
|
catch (err) {
|
|
473
306
|
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
@@ -478,8 +311,10 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
478
311
|
originalImageDimensions
|
|
479
312
|
};
|
|
480
313
|
}
|
|
314
|
+
exports.generateThumbnail = generateThumbnail;
|
|
481
315
|
const getHttpStream = async (url, options = {}) => {
|
|
482
|
-
const
|
|
316
|
+
const { default: axios } = await import('axios');
|
|
317
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
483
318
|
return fetched.data;
|
|
484
319
|
};
|
|
485
320
|
exports.getHttpStream = getHttpStream;
|
|
@@ -494,7 +329,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
494
329
|
bodyPath = media.url;
|
|
495
330
|
}
|
|
496
331
|
else if (saveOriginalFileIfRequired) {
|
|
497
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
332
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
498
333
|
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
499
334
|
didSaveToTmpPath = true;
|
|
500
335
|
}
|
|
@@ -513,6 +348,7 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
|
|
|
513
348
|
};
|
|
514
349
|
}
|
|
515
350
|
catch (error) {
|
|
351
|
+
// destroy all streams with error
|
|
516
352
|
stream.destroy();
|
|
517
353
|
if (didSaveToTmpPath) {
|
|
518
354
|
try {
|
|
@@ -530,7 +366,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
530
366
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
531
367
|
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
532
368
|
const mediaKey = Crypto.randomBytes(32);
|
|
533
|
-
const { cipherKey, iv, macKey } =
|
|
369
|
+
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
534
370
|
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
535
371
|
let bodyPath;
|
|
536
372
|
let writeStream;
|
|
@@ -539,7 +375,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
539
375
|
bodyPath = media.url;
|
|
540
376
|
}
|
|
541
377
|
else if (saveOriginalFileIfRequired) {
|
|
542
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.
|
|
378
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
543
379
|
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
544
380
|
didSaveToTmpPath = true;
|
|
545
381
|
}
|
|
@@ -588,6 +424,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
588
424
|
};
|
|
589
425
|
}
|
|
590
426
|
catch (error) {
|
|
427
|
+
// destroy all streams with error
|
|
591
428
|
encWriteStream.destroy();
|
|
592
429
|
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
|
593
430
|
aes.destroy();
|
|
@@ -619,20 +456,21 @@ const toSmallestChunkSize = (num) => {
|
|
|
619
456
|
};
|
|
620
457
|
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
621
458
|
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);
|
|
459
|
+
const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
460
|
+
const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
|
|
461
|
+
const keys = getMediaKeys(mediaKey, type);
|
|
629
462
|
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
630
463
|
};
|
|
631
464
|
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
465
|
+
/**
|
|
466
|
+
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
467
|
+
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
468
|
+
* */
|
|
632
469
|
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
633
470
|
let bytesFetched = 0;
|
|
634
471
|
let startChunk = 0;
|
|
635
472
|
let firstBlockIsIV = false;
|
|
473
|
+
// if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
|
|
636
474
|
if (startByte) {
|
|
637
475
|
const chunk = toSmallestChunkSize(startByte || 0);
|
|
638
476
|
if (chunk) {
|
|
@@ -652,6 +490,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
652
490
|
headers.Range += endChunk;
|
|
653
491
|
}
|
|
654
492
|
}
|
|
493
|
+
// download the message
|
|
655
494
|
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
656
495
|
...options || {},
|
|
657
496
|
headers,
|
|
@@ -684,6 +523,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
684
523
|
data = data.slice(AES_CHUNK_SIZE);
|
|
685
524
|
}
|
|
686
525
|
aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
|
|
526
|
+
// if an end byte that is not EOF is specified
|
|
527
|
+
// stop auto padding (PKCS7) -- otherwise throws an error for decryption
|
|
687
528
|
if (endByte) {
|
|
688
529
|
aes.setAutoPadding(false);
|
|
689
530
|
}
|
|
@@ -724,9 +565,12 @@ function extensionForMediaMessage(message) {
|
|
|
724
565
|
}
|
|
725
566
|
return extension;
|
|
726
567
|
}
|
|
568
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
727
569
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
728
570
|
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
729
571
|
var _a, _b;
|
|
572
|
+
const { default: axios } = await import('axios');
|
|
573
|
+
// send a query JSON to obtain the url & auth token to upload our media
|
|
730
574
|
let uploadInfo = await refreshMediaConn(false);
|
|
731
575
|
let urls;
|
|
732
576
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
@@ -744,14 +588,14 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
744
588
|
}
|
|
745
589
|
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
746
590
|
logger.debug(`uploading to "${hostname}"`);
|
|
747
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
591
|
+
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
748
592
|
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
749
593
|
let result;
|
|
750
594
|
try {
|
|
751
595
|
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
752
596
|
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
753
597
|
}
|
|
754
|
-
const body = await
|
|
598
|
+
const body = await axios.post(url, reqBody, {
|
|
755
599
|
...options,
|
|
756
600
|
headers: {
|
|
757
601
|
...options.headers || {},
|
|
@@ -779,7 +623,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
779
623
|
}
|
|
780
624
|
}
|
|
781
625
|
catch (error) {
|
|
782
|
-
if (
|
|
626
|
+
if (axios.isAxiosError(error)) {
|
|
783
627
|
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
784
628
|
}
|
|
785
629
|
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
@@ -796,11 +640,14 @@ exports.getWAUploadToServer = getWAUploadToServer;
|
|
|
796
640
|
const getMediaRetryKey = (mediaKey) => {
|
|
797
641
|
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
798
642
|
};
|
|
799
|
-
|
|
643
|
+
/**
|
|
644
|
+
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
645
|
+
*/
|
|
646
|
+
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
800
647
|
const recp = { stanzaId: key.id };
|
|
801
648
|
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
802
649
|
const iv = Crypto.randomBytes(12);
|
|
803
|
-
const retryKey =
|
|
650
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
804
651
|
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
805
652
|
const req = {
|
|
806
653
|
tag: 'receipt',
|
|
@@ -810,6 +657,9 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
810
657
|
type: 'server-error'
|
|
811
658
|
},
|
|
812
659
|
content: [
|
|
660
|
+
// this encrypt node is actually pretty useless
|
|
661
|
+
// the media is returned even without this node
|
|
662
|
+
// keeping it here to maintain parity with WA Web
|
|
813
663
|
{
|
|
814
664
|
tag: 'encrypt',
|
|
815
665
|
attrs: {},
|
|
@@ -823,6 +673,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
823
673
|
attrs: {
|
|
824
674
|
jid: key.remoteJid,
|
|
825
675
|
'from_me': (!!key.fromMe).toString(),
|
|
676
|
+
// @ts-ignore
|
|
826
677
|
participant: key.participant || undefined
|
|
827
678
|
}
|
|
828
679
|
}
|
|
@@ -860,8 +711,8 @@ const decodeMediaRetryNode = (node) => {
|
|
|
860
711
|
return event;
|
|
861
712
|
};
|
|
862
713
|
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
863
|
-
const decryptMediaRetryData =
|
|
864
|
-
const retryKey =
|
|
714
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
715
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
865
716
|
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
866
717
|
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
867
718
|
};
|
|
@@ -874,6 +725,7 @@ const MEDIA_RETRY_STATUS_MAP = {
|
|
|
874
725
|
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
875
726
|
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
876
727
|
};
|
|
728
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
877
729
|
function __importStar(arg0) {
|
|
878
730
|
throw new Error('Function not implemented.');
|
|
879
|
-
}
|
|
731
|
+
}
|