@hbmodsofc/baileys 1.7.7 → 2.0.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 +157084 -24729
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +8 -12
- package/lib/Defaults/index.js +124 -90
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/Group/group_cipher.d.ts +1 -0
- package/lib/Signal/Group/group_cipher.js +39 -28
- package/lib/Signal/Group/queue-job.d.ts +1 -0
- package/lib/Signal/Group/queue-job.js +57 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +1 -1
- package/lib/Signal/Group/sender-chain-key.js +2 -9
- package/lib/Signal/Group/sender-key-distribution-message.js +3 -3
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-state.d.ts +4 -4
- package/lib/Signal/Group/sender-key-state.js +16 -47
- package/lib/Signal/libsignal.d.ts +3 -7
- package/lib/Signal/libsignal.js +39 -224
- package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +3 -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 -1
- package/lib/Socket/Client/{websocket.js → web-socket-client.js} +16 -10
- package/lib/Socket/business.d.ts +78 -94
- package/lib/Socket/business.js +11 -130
- package/lib/Socket/chats.d.ts +233 -63
- package/lib/Socket/chats.js +184 -234
- package/lib/Socket/groups.d.ts +41 -62
- package/lib/Socket/groups.js +64 -76
- package/lib/Socket/hbmods.d.ts +253 -0
- package/lib/Socket/hbmods.js +1 -0
- package/lib/Socket/index.d.ts +83 -129
- package/lib/Socket/index.js +6 -13
- package/lib/Socket/messages-recv.d.ts +48 -59
- package/lib/Socket/messages-recv.js +371 -516
- package/lib/Socket/messages-send.d.ts +67 -86
- package/lib/Socket/messages-send.js +1 -1091
- package/lib/Socket/newsletter.d.ts +64 -76
- package/lib/Socket/newsletter.js +1 -184
- package/lib/Socket/registration.d.ts +267 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +13 -19
- package/lib/Socket/socket.js +1 -805
- package/lib/Socket/usync.d.ts +36 -0
- package/lib/Socket/usync.js +70 -0
- package/lib/Types/Auth.d.ts +10 -4
- package/lib/Types/Call.d.ts +1 -1
- package/lib/Types/Chat.d.ts +9 -29
- package/lib/Types/Chat.js +1 -7
- package/lib/Types/Contact.d.ts +1 -5
- package/lib/Types/Events.d.ts +14 -55
- package/lib/Types/GroupMetadata.d.ts +5 -15
- package/lib/Types/Label.d.ts +0 -11
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Message.d.ts +49 -75
- package/lib/Types/Message.js +7 -10
- package/lib/Types/Newsletter.d.ts +98 -129
- package/lib/Types/Newsletter.js +38 -33
- package/lib/Types/Product.d.ts +1 -1
- package/lib/Types/Signal.d.ts +1 -29
- package/lib/Types/Socket.d.ts +22 -48
- package/lib/Types/State.d.ts +2 -13
- package/lib/Types/State.js +0 -12
- package/lib/Types/USync.d.ts +1 -1
- package/lib/Types/index.d.ts +3 -10
- package/lib/Types/index.js +2 -2
- package/lib/Utils/auth-utils.d.ts +3 -3
- package/lib/Utils/auth-utils.js +102 -378
- package/lib/Utils/baileys-event-stream.js +1 -1
- package/lib/Utils/business.d.ts +2 -2
- package/lib/Utils/business.js +13 -19
- package/lib/Utils/chat-utils.d.ts +22 -21
- package/lib/Utils/chat-utils.js +154 -201
- package/lib/Utils/crypto.d.ts +19 -18
- package/lib/Utils/crypto.js +37 -78
- package/lib/Utils/decode-wa-message.d.ts +7 -34
- package/lib/Utils/decode-wa-message.js +66 -138
- package/lib/Utils/event-buffer.d.ts +8 -6
- package/lib/Utils/event-buffer.js +43 -81
- package/lib/Utils/generics.d.ts +27 -27
- package/lib/Utils/generics.js +133 -128
- package/lib/Utils/history.d.ts +5 -9
- package/lib/Utils/history.js +23 -17
- package/lib/Utils/index.d.ts +0 -2
- package/lib/Utils/index.js +0 -2
- package/lib/Utils/link-preview.d.ts +4 -4
- package/lib/Utils/link-preview.js +12 -40
- package/lib/Utils/logger.d.ts +3 -11
- package/lib/Utils/lt-hash.d.ts +8 -8
- package/lib/Utils/lt-hash.js +24 -23
- package/lib/Utils/make-mutex.d.ts +2 -2
- package/lib/Utils/make-mutex.js +2 -3
- package/lib/Utils/messages-media.d.ts +41 -37
- package/lib/Utils/messages-media.js +368 -252
- package/lib/Utils/messages.d.ts +15 -13
- package/lib/Utils/messages.js +261 -274
- package/lib/Utils/noise-handler.d.ts +15 -13
- package/lib/Utils/noise-handler.js +26 -20
- package/lib/Utils/process-message.d.ts +8 -9
- package/lib/Utils/process-message.js +93 -157
- package/lib/Utils/signal.d.ts +5 -6
- package/lib/Utils/signal.js +29 -37
- package/lib/Utils/use-multi-file-auth-state.d.ts +2 -1
- package/lib/Utils/use-multi-file-auth-state.js +7 -12
- package/lib/Utils/validate-connection.d.ts +6 -5
- package/lib/Utils/validate-connection.js +97 -39
- 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 +14 -28
- package/lib/WABinary/encode.d.ts +2 -1
- package/lib/WABinary/encode.js +147 -134
- package/lib/WABinary/generic-utils.d.ts +7 -4
- package/lib/WABinary/generic-utils.js +125 -40
- package/lib/WABinary/jid-utils.d.ts +8 -13
- package/lib/WABinary/jid-utils.js +16 -27
- package/lib/WAM/BinaryInfo.d.ts +11 -2
- package/lib/WAM/constants.d.ts +2 -3
- package/lib/WAM/constants.js +2359 -2252
- package/lib/WAM/encode.d.ts +2 -1
- package/lib/WAM/encode.js +11 -8
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +4 -3
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -5
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +5 -5
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +6 -5
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +2 -2
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +1 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +3 -4
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +3 -11
- package/lib/WAUSync/USyncQuery.d.ts +2 -2
- package/lib/WAUSync/USyncQuery.js +15 -19
- package/lib/WAUSync/USyncUser.d.ts +5 -5
- package/lib/WAUSync/index.d.ts +1 -1
- package/lib/WAUSync/index.js +1 -1
- package/package.json +102 -102
- package/lib/Signal/lid-mapping.d.ts +0 -26
- package/lib/Signal/lid-mapping.js +0 -146
- package/lib/Socket/communities.d.ts +0 -232
- package/lib/Socket/communities.js +0 -402
- package/lib/Socket/mex.d.ts +0 -2
- package/lib/Socket/mex.js +0 -45
- package/lib/Types/Bussines.d.ts +0 -24
- package/lib/Types/Bussines.js +0 -2
- package/lib/Utils/lidToJid-test.d.ts +0 -11
- package/lib/Utils/lidToJid-test.js +0 -27
- package/lib/Utils/message-retry-manager.d.ts +0 -81
- package/lib/Utils/message-retry-manager.js +0 -152
- /package/lib/Socket/Client/{types.js → abstract-socket-client.js} +0 -0
|
@@ -15,35 +15,16 @@ 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.getHttpStream = exports.getStream = exports.toBuffer = exports.toReadable = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.
|
|
40
|
-
exports.getMediaKeys = getMediaKeys;
|
|
41
|
-
exports.getAudioDuration = getAudioDuration;
|
|
42
|
-
exports.getAudioWaveform = getAudioWaveform;
|
|
43
|
-
exports.generateThumbnail = generateThumbnail;
|
|
44
|
-
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;
|
|
45
27
|
const boom_1 = require("@hapi/boom");
|
|
46
|
-
const axios_1 = __importDefault(require("axios"));
|
|
47
28
|
const child_process_1 = require("child_process");
|
|
48
29
|
const Crypto = __importStar(require("crypto"));
|
|
49
30
|
const events_1 = require("events");
|
|
@@ -51,18 +32,29 @@ const fs_1 = require("fs");
|
|
|
51
32
|
const os_1 = require("os");
|
|
52
33
|
const path_1 = require("path");
|
|
53
34
|
const stream_1 = require("stream");
|
|
54
|
-
const
|
|
35
|
+
const WAProto_1 = require("../../WAProto");
|
|
55
36
|
const Defaults_1 = require("../Defaults");
|
|
56
37
|
const WABinary_1 = require("../WABinary");
|
|
57
38
|
const crypto_1 = require("./crypto");
|
|
58
39
|
const generics_1 = require("./generics");
|
|
59
40
|
const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
|
|
60
41
|
const getImageProcessingLibrary = async () => {
|
|
61
|
-
|
|
62
|
-
|
|
42
|
+
const [_jimp, sharp] = await Promise.all([
|
|
43
|
+
(async () => {
|
|
44
|
+
const jimp = await (import('jimp')
|
|
45
|
+
.catch(() => { }));
|
|
46
|
+
return jimp;
|
|
47
|
+
})(),
|
|
48
|
+
(async () => {
|
|
49
|
+
const sharp = await (import('sharp')
|
|
50
|
+
.catch(() => { }));
|
|
51
|
+
return sharp;
|
|
52
|
+
})()
|
|
53
|
+
]);
|
|
63
54
|
if (sharp) {
|
|
64
55
|
return { sharp };
|
|
65
56
|
}
|
|
57
|
+
const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
|
|
66
58
|
if (jimp) {
|
|
67
59
|
return { jimp };
|
|
68
60
|
}
|
|
@@ -73,47 +65,8 @@ const hkdfInfoKey = (type) => {
|
|
|
73
65
|
return `WhatsApp ${hkdfInfo} Keys`;
|
|
74
66
|
};
|
|
75
67
|
exports.hkdfInfoKey = hkdfInfoKey;
|
|
76
|
-
const getRawMediaUploadData = async (media, mediaType, logger) => {
|
|
77
|
-
const { stream } = await (0, exports.getStream)(media);
|
|
78
|
-
logger?.debug('got stream for raw upload');
|
|
79
|
-
const hasher = Crypto.createHash('sha256');
|
|
80
|
-
const filePath = (0, path_1.join)((0, os_1.tmpdir)(), mediaType + (0, generics_1.generateMessageIDV2)());
|
|
81
|
-
const fileWriteStream = (0, fs_1.createWriteStream)(filePath);
|
|
82
|
-
let fileLength = 0;
|
|
83
|
-
try {
|
|
84
|
-
for await (const data of stream) {
|
|
85
|
-
fileLength += data.length;
|
|
86
|
-
hasher.update(data);
|
|
87
|
-
if (!fileWriteStream.write(data)) {
|
|
88
|
-
await (0, events_1.once)(fileWriteStream, 'drain');
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
fileWriteStream.end();
|
|
92
|
-
await (0, events_1.once)(fileWriteStream, 'finish');
|
|
93
|
-
stream.destroy();
|
|
94
|
-
const fileSha256 = hasher.digest();
|
|
95
|
-
logger?.debug('hashed data for raw upload');
|
|
96
|
-
return {
|
|
97
|
-
filePath: filePath,
|
|
98
|
-
fileSha256,
|
|
99
|
-
fileLength
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
fileWriteStream.destroy();
|
|
104
|
-
stream.destroy();
|
|
105
|
-
try {
|
|
106
|
-
await fs_1.promises.unlink(filePath);
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
//
|
|
110
|
-
}
|
|
111
|
-
throw error;
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
exports.getRawMediaUploadData = getRawMediaUploadData;
|
|
115
68
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
116
|
-
|
|
69
|
+
function getMediaKeys(buffer, mediaType) {
|
|
117
70
|
if (!buffer) {
|
|
118
71
|
throw new boom_1.Boom('Cannot derive from empty media key');
|
|
119
72
|
}
|
|
@@ -121,17 +74,18 @@ async function getMediaKeys(buffer, mediaType) {
|
|
|
121
74
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
122
75
|
}
|
|
123
76
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
124
|
-
const expandedMediaKey =
|
|
77
|
+
const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
|
|
125
78
|
return {
|
|
126
79
|
iv: expandedMediaKey.slice(0, 16),
|
|
127
80
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
128
|
-
macKey: expandedMediaKey.slice(48, 80)
|
|
81
|
+
macKey: expandedMediaKey.slice(48, 80),
|
|
129
82
|
};
|
|
130
83
|
}
|
|
84
|
+
exports.getMediaKeys = getMediaKeys;
|
|
131
85
|
/** Extracts video thumb using FFMPEG */
|
|
132
86
|
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
|
|
133
87
|
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
|
|
134
|
-
(0, child_process_1.exec)(cmd, err => {
|
|
88
|
+
(0, child_process_1.exec)(cmd, (err) => {
|
|
135
89
|
if (err) {
|
|
136
90
|
reject(err);
|
|
137
91
|
}
|
|
@@ -141,33 +95,37 @@ const extractVideoThumb = async (path, destPath, time, size) => new Promise((res
|
|
|
141
95
|
});
|
|
142
96
|
});
|
|
143
97
|
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
144
|
-
|
|
145
|
-
// This will have positive speed and performance impacts as well as minimizing RAM usage.
|
|
98
|
+
var _a, _b;
|
|
146
99
|
if (bufferOrFilePath instanceof stream_1.Readable) {
|
|
147
100
|
bufferOrFilePath = await (0, exports.toBuffer)(bufferOrFilePath);
|
|
148
101
|
}
|
|
149
102
|
const lib = await getImageProcessingLibrary();
|
|
150
|
-
if ('sharp' in lib && typeof lib.sharp
|
|
103
|
+
if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
|
|
151
104
|
const img = lib.sharp.default(bufferOrFilePath);
|
|
152
105
|
const dimensions = await img.metadata();
|
|
153
|
-
const buffer = await img
|
|
106
|
+
const buffer = await img
|
|
107
|
+
.resize(width)
|
|
108
|
+
.jpeg({ quality: 50 })
|
|
109
|
+
.toBuffer();
|
|
154
110
|
return {
|
|
155
111
|
buffer,
|
|
156
112
|
original: {
|
|
157
113
|
width: dimensions.width,
|
|
158
|
-
height: dimensions.height
|
|
159
|
-
}
|
|
114
|
+
height: dimensions.height,
|
|
115
|
+
},
|
|
160
116
|
};
|
|
161
117
|
}
|
|
162
|
-
else if ('jimp' in lib && typeof lib.jimp
|
|
163
|
-
const
|
|
118
|
+
else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
|
|
119
|
+
const { read, MIME_JPEG, RESIZE_BILINEAR, AUTO } = lib.jimp;
|
|
120
|
+
const jimp = await read(bufferOrFilePath);
|
|
164
121
|
const dimensions = {
|
|
165
|
-
width: jimp.
|
|
166
|
-
height: jimp.
|
|
122
|
+
width: jimp.getWidth(),
|
|
123
|
+
height: jimp.getHeight()
|
|
167
124
|
};
|
|
168
125
|
const buffer = await jimp
|
|
169
|
-
.
|
|
170
|
-
.
|
|
126
|
+
.quality(50)
|
|
127
|
+
.resize(width, AUTO, RESIZE_BILINEAR)
|
|
128
|
+
.getBufferAsync(MIME_JPEG);
|
|
171
129
|
return {
|
|
172
130
|
buffer,
|
|
173
131
|
original: dimensions
|
|
@@ -178,110 +136,190 @@ const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
|
178
136
|
}
|
|
179
137
|
};
|
|
180
138
|
exports.extractImageThumb = extractImageThumb;
|
|
181
|
-
const encodeBase64EncodedStringForUpload = (b64) => encodeURIComponent(b64
|
|
139
|
+
const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
|
|
140
|
+
.replace(/\+/g, '-')
|
|
141
|
+
.replace(/\//g, '_')
|
|
142
|
+
.replace(/\=+$/, '')));
|
|
182
143
|
exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
|
|
183
|
-
const generateProfilePicture = async (mediaUpload
|
|
184
|
-
|
|
185
|
-
|
|
144
|
+
const generateProfilePicture = async (mediaUpload) => {
|
|
145
|
+
var _a, _b;
|
|
146
|
+
let bufferOrFilePath;
|
|
186
147
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
187
|
-
|
|
148
|
+
bufferOrFilePath = mediaUpload;
|
|
149
|
+
}
|
|
150
|
+
else if ('url' in mediaUpload) {
|
|
151
|
+
bufferOrFilePath = mediaUpload.url.toString();
|
|
188
152
|
}
|
|
189
153
|
else {
|
|
190
|
-
|
|
191
|
-
const { stream } = await (0, exports.getStream)(mediaUpload);
|
|
192
|
-
// Convert the resulting stream to a buffer
|
|
193
|
-
buffer = await (0, exports.toBuffer)(stream);
|
|
154
|
+
bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
|
|
194
155
|
}
|
|
195
156
|
const lib = await getImageProcessingLibrary();
|
|
196
157
|
let img;
|
|
197
|
-
if ('sharp' in lib && typeof lib.sharp
|
|
198
|
-
img = lib.sharp
|
|
199
|
-
.
|
|
200
|
-
.resize(w, h)
|
|
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)
|
|
201
161
|
.jpeg({
|
|
202
|
-
quality: 50
|
|
162
|
+
quality: 50,
|
|
203
163
|
})
|
|
204
164
|
.toBuffer();
|
|
205
165
|
}
|
|
206
|
-
else if ('jimp' in lib && typeof lib.jimp
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
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);
|
|
211
175
|
}
|
|
212
176
|
else {
|
|
213
177
|
throw new boom_1.Boom('No image processing library available');
|
|
214
178
|
}
|
|
215
179
|
return {
|
|
216
|
-
img: await img
|
|
180
|
+
img: await img,
|
|
217
181
|
};
|
|
218
182
|
};
|
|
219
183
|
exports.generateProfilePicture = generateProfilePicture;
|
|
220
184
|
/** gets the SHA256 of the given media message */
|
|
221
185
|
const mediaMessageSHA256B64 = (message) => {
|
|
222
186
|
const media = Object.values(message)[0];
|
|
223
|
-
return media
|
|
187
|
+
return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
|
|
224
188
|
};
|
|
225
189
|
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
|
|
226
190
|
async function getAudioDuration(buffer) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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;
|
|
240
227
|
}
|
|
241
|
-
return metadata.format.duration;
|
|
242
228
|
}
|
|
243
|
-
|
|
244
|
-
referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
|
|
245
|
-
*/
|
|
229
|
+
exports.getAudioDuration = getAudioDuration;
|
|
246
230
|
async function getAudioWaveform(buffer, logger) {
|
|
247
231
|
try {
|
|
248
|
-
|
|
249
|
-
const
|
|
232
|
+
const { PassThrough } = require('stream');
|
|
233
|
+
const ff = require('fluent-ffmpeg');
|
|
234
|
+
|
|
250
235
|
let audioData;
|
|
251
236
|
if (Buffer.isBuffer(buffer)) {
|
|
252
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);
|
|
253
243
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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);
|
|
280
281
|
}
|
|
281
|
-
|
|
282
|
-
|
|
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;
|
|
283
320
|
}
|
|
284
321
|
}
|
|
322
|
+
exports.convertToOpusBuffer = convertToOpusBuffer;
|
|
285
323
|
const toReadable = (buffer) => {
|
|
286
324
|
const readable = new stream_1.Readable({ read: () => { } });
|
|
287
325
|
readable.push(buffer);
|
|
@@ -305,12 +343,7 @@ const getStream = async (item, opts) => {
|
|
|
305
343
|
if ('stream' in item) {
|
|
306
344
|
return { stream: item.stream, type: 'readable' };
|
|
307
345
|
}
|
|
308
|
-
|
|
309
|
-
if (urlStr.startsWith('data:')) {
|
|
310
|
-
const buffer = Buffer.from(urlStr.split(',')[1], 'base64');
|
|
311
|
-
return { stream: (0, exports.toReadable)(buffer), type: 'buffer' };
|
|
312
|
-
}
|
|
313
|
-
if (urlStr.startsWith('http://') || urlStr.startsWith('https://')) {
|
|
346
|
+
if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
|
|
314
347
|
return { stream: await (0, exports.getHttpStream)(item.url, opts), type: 'remote' };
|
|
315
348
|
}
|
|
316
349
|
return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
|
|
@@ -318,6 +351,7 @@ const getStream = async (item, opts) => {
|
|
|
318
351
|
exports.getStream = getStream;
|
|
319
352
|
/** generates a thumbnail for a given media, if required */
|
|
320
353
|
async function generateThumbnail(file, mediaType, options) {
|
|
354
|
+
var _a;
|
|
321
355
|
let thumbnail;
|
|
322
356
|
let originalImageDimensions;
|
|
323
357
|
if (mediaType === 'image') {
|
|
@@ -326,12 +360,12 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
326
360
|
if (original.width && original.height) {
|
|
327
361
|
originalImageDimensions = {
|
|
328
362
|
width: original.width,
|
|
329
|
-
height: original.height
|
|
363
|
+
height: original.height,
|
|
330
364
|
};
|
|
331
365
|
}
|
|
332
366
|
}
|
|
333
367
|
else if (mediaType === 'video') {
|
|
334
|
-
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.
|
|
368
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
335
369
|
try {
|
|
336
370
|
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
337
371
|
const buff = await fs_1.promises.readFile(imgFilename);
|
|
@@ -339,7 +373,7 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
339
373
|
await fs_1.promises.unlink(imgFilename);
|
|
340
374
|
}
|
|
341
375
|
catch (err) {
|
|
342
|
-
options.logger
|
|
376
|
+
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
343
377
|
}
|
|
344
378
|
}
|
|
345
379
|
return {
|
|
@@ -347,90 +381,160 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
347
381
|
originalImageDimensions
|
|
348
382
|
};
|
|
349
383
|
}
|
|
384
|
+
exports.generateThumbnail = generateThumbnail;
|
|
350
385
|
const getHttpStream = async (url, options = {}) => {
|
|
351
|
-
const
|
|
386
|
+
const { default: axios } = await import('axios');
|
|
387
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
352
388
|
return fetched.data;
|
|
353
389
|
};
|
|
354
390
|
exports.getHttpStream = getHttpStream;
|
|
355
|
-
const
|
|
391
|
+
const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
356
392
|
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
357
|
-
logger
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
393
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
394
|
+
let bodyPath;
|
|
395
|
+
let didSaveToTmpPath = false;
|
|
396
|
+
try {
|
|
397
|
+
const buffer = await (0, exports.toBuffer)(stream);
|
|
398
|
+
if (type === 'file') {
|
|
399
|
+
bodyPath = media.url;
|
|
400
|
+
}
|
|
401
|
+
else if (saveOriginalFileIfRequired) {
|
|
402
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
403
|
+
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
404
|
+
didSaveToTmpPath = true;
|
|
405
|
+
}
|
|
406
|
+
const fileLength = buffer.length;
|
|
407
|
+
const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
|
|
408
|
+
stream === null || stream === void 0 ? void 0 : stream.destroy();
|
|
409
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
|
|
410
|
+
return {
|
|
411
|
+
mediaKey: undefined,
|
|
412
|
+
encWriteStream: buffer,
|
|
413
|
+
fileLength,
|
|
414
|
+
fileSha256,
|
|
415
|
+
fileEncSha256: undefined,
|
|
416
|
+
bodyPath,
|
|
417
|
+
didSaveToTmpPath
|
|
418
|
+
};
|
|
367
419
|
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
// destroy all streams with error
|
|
422
|
+
stream.destroy();
|
|
423
|
+
if (didSaveToTmpPath) {
|
|
424
|
+
try {
|
|
425
|
+
await fs_1.promises.unlink(bodyPath);
|
|
426
|
+
}
|
|
427
|
+
catch (err) {
|
|
428
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
exports.prepareStream = prepareStream;
|
|
435
|
+
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
436
|
+
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
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
|
+
|
|
450
|
+
const mediaKey = Crypto.randomBytes(32);
|
|
451
|
+
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
452
|
+
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
453
|
+
let bodyPath;
|
|
454
|
+
let writeStream;
|
|
455
|
+
let didSaveToTmpPath = false;
|
|
456
|
+
|
|
457
|
+
if (type === 'file') {
|
|
458
|
+
bodyPath = media.url;
|
|
459
|
+
}
|
|
460
|
+
else if (saveOriginalFileIfRequired) {
|
|
461
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
462
|
+
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
463
|
+
didSaveToTmpPath = true;
|
|
464
|
+
}
|
|
465
|
+
|
|
368
466
|
let fileLength = 0;
|
|
369
467
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
sha256Enc.update(buff);
|
|
375
|
-
hmac.update(buff);
|
|
376
|
-
encFileWriteStream.write(buff);
|
|
377
|
-
};
|
|
468
|
+
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
469
|
+
let sha256Plain = Crypto.createHash('sha256');
|
|
470
|
+
let sha256Enc = Crypto.createHash('sha256');
|
|
471
|
+
|
|
378
472
|
try {
|
|
379
|
-
for await (const data of
|
|
473
|
+
for await (const data of finalStream) {
|
|
380
474
|
fileLength += data.length;
|
|
381
|
-
if (type === 'remote'
|
|
475
|
+
if (type === 'remote'
|
|
476
|
+
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
477
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
382
478
|
throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
|
|
383
479
|
data: { media, type }
|
|
384
480
|
});
|
|
385
481
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
482
|
+
|
|
483
|
+
sha256Plain = sha256Plain.update(data);
|
|
484
|
+
if (writeStream) {
|
|
485
|
+
if (!writeStream.write(data)) {
|
|
486
|
+
await (0, events_1.once)(writeStream, 'drain');
|
|
389
487
|
}
|
|
390
488
|
}
|
|
391
|
-
sha256Plain.update(data);
|
|
392
489
|
onChunk(aes.update(data));
|
|
393
490
|
}
|
|
491
|
+
|
|
394
492
|
onChunk(aes.final());
|
|
395
493
|
const mac = hmac.digest().slice(0, 10);
|
|
396
|
-
sha256Enc.update(mac);
|
|
494
|
+
sha256Enc = sha256Enc.update(mac);
|
|
397
495
|
const fileSha256 = sha256Plain.digest();
|
|
398
496
|
const fileEncSha256 = sha256Enc.digest();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
497
|
+
|
|
498
|
+
encWriteStream.push(mac);
|
|
499
|
+
encWriteStream.push(null);
|
|
500
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
501
|
+
finalStream.destroy();
|
|
502
|
+
|
|
404
503
|
return {
|
|
405
504
|
mediaKey,
|
|
406
|
-
|
|
407
|
-
|
|
505
|
+
encWriteStream,
|
|
506
|
+
bodyPath,
|
|
408
507
|
mac,
|
|
409
508
|
fileEncSha256,
|
|
410
509
|
fileSha256,
|
|
411
|
-
fileLength
|
|
510
|
+
fileLength,
|
|
511
|
+
didSaveToTmpPath
|
|
412
512
|
};
|
|
413
513
|
}
|
|
414
514
|
catch (error) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
originalFileStream?.destroy?.();
|
|
515
|
+
encWriteStream.destroy();
|
|
516
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
|
418
517
|
aes.destroy();
|
|
419
518
|
hmac.destroy();
|
|
420
519
|
sha256Plain.destroy();
|
|
421
520
|
sha256Enc.destroy();
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
await fs_1.promises.unlink(
|
|
521
|
+
finalStream.destroy();
|
|
522
|
+
|
|
523
|
+
if (didSaveToTmpPath) {
|
|
524
|
+
try {
|
|
525
|
+
await fs_1.promises.unlink(bodyPath);
|
|
526
|
+
}
|
|
527
|
+
catch (err) {
|
|
427
528
|
}
|
|
428
|
-
}
|
|
429
|
-
catch (err) {
|
|
430
|
-
logger?.error({ err }, 'failed deleting tmp files');
|
|
431
529
|
}
|
|
432
530
|
throw error;
|
|
433
531
|
}
|
|
532
|
+
|
|
533
|
+
function onChunk(buff) {
|
|
534
|
+
sha256Enc = sha256Enc.update(buff);
|
|
535
|
+
hmac = hmac.update(buff);
|
|
536
|
+
encWriteStream.push(buff);
|
|
537
|
+
}
|
|
434
538
|
};
|
|
435
539
|
exports.encryptedStream = encryptedStream;
|
|
436
540
|
const DEF_HOST = 'mmg.whatsapp.net';
|
|
@@ -440,13 +544,9 @@ const toSmallestChunkSize = (num) => {
|
|
|
440
544
|
};
|
|
441
545
|
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
442
546
|
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
443
|
-
const downloadContentFromMessage =
|
|
444
|
-
const
|
|
445
|
-
const
|
|
446
|
-
if (!downloadUrl) {
|
|
447
|
-
throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
448
|
-
}
|
|
449
|
-
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);
|
|
450
550
|
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
451
551
|
};
|
|
452
552
|
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
@@ -469,8 +569,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
469
569
|
}
|
|
470
570
|
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
|
|
471
571
|
const headers = {
|
|
472
|
-
...(options
|
|
473
|
-
Origin: Defaults_1.DEFAULT_ORIGIN
|
|
572
|
+
...(options === null || options === void 0 ? void 0 : options.headers) || {},
|
|
573
|
+
Origin: Defaults_1.DEFAULT_ORIGIN,
|
|
474
574
|
};
|
|
475
575
|
if (startChunk || endChunk) {
|
|
476
576
|
headers.Range = `bytes=${startChunk}-`;
|
|
@@ -480,10 +580,10 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
480
580
|
}
|
|
481
581
|
// download the message
|
|
482
582
|
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
483
|
-
...
|
|
583
|
+
...options || {},
|
|
484
584
|
headers,
|
|
485
585
|
maxBodyLength: Infinity,
|
|
486
|
-
maxContentLength: Infinity
|
|
586
|
+
maxContentLength: Infinity,
|
|
487
587
|
});
|
|
488
588
|
let remainingBytes = Buffer.from([]);
|
|
489
589
|
let aes;
|
|
@@ -533,16 +633,18 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
533
633
|
catch (error) {
|
|
534
634
|
callback(error);
|
|
535
635
|
}
|
|
536
|
-
}
|
|
636
|
+
},
|
|
537
637
|
});
|
|
538
638
|
return fetched.pipe(output, { end: true });
|
|
539
639
|
};
|
|
540
640
|
exports.downloadEncryptedContent = downloadEncryptedContent;
|
|
541
641
|
function extensionForMediaMessage(message) {
|
|
542
|
-
const getExtension = (mimetype) => mimetype.split(';')[0]
|
|
642
|
+
const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
|
|
543
643
|
const type = Object.keys(message)[0];
|
|
544
644
|
let extension;
|
|
545
|
-
if (type === 'locationMessage' ||
|
|
645
|
+
if (type === 'locationMessage' ||
|
|
646
|
+
type === 'liveLocationMessage' ||
|
|
647
|
+
type === 'productMessage') {
|
|
546
648
|
extension = '.jpeg';
|
|
547
649
|
}
|
|
548
650
|
else {
|
|
@@ -551,42 +653,55 @@ function extensionForMediaMessage(message) {
|
|
|
551
653
|
}
|
|
552
654
|
return extension;
|
|
553
655
|
}
|
|
656
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
554
657
|
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
555
|
-
return async (
|
|
658
|
+
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
659
|
+
var _a, _b;
|
|
660
|
+
const { default: axios } = await import('axios');
|
|
556
661
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
557
662
|
let uploadInfo = await refreshMediaConn(false);
|
|
558
663
|
let urls;
|
|
559
664
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
665
|
+
const chunks = [];
|
|
666
|
+
if (!Buffer.isBuffer(stream)) {
|
|
667
|
+
for await (const chunk of stream) {
|
|
668
|
+
chunks.push(chunk);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
|
|
560
672
|
fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
|
|
561
|
-
|
|
673
|
+
let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
|
|
674
|
+
if (newsletter) {
|
|
675
|
+
media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
|
|
676
|
+
}
|
|
677
|
+
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
562
678
|
logger.debug(`uploading to "${hostname}"`);
|
|
563
679
|
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
564
|
-
const url = `https://${hostname}${
|
|
565
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
680
|
+
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
566
681
|
let result;
|
|
567
682
|
try {
|
|
568
|
-
|
|
683
|
+
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
684
|
+
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
685
|
+
}
|
|
686
|
+
const body = await axios.post(url, reqBody, {
|
|
569
687
|
...options,
|
|
570
|
-
maxRedirects: 0,
|
|
571
688
|
headers: {
|
|
572
|
-
...
|
|
689
|
+
...options.headers || {},
|
|
573
690
|
'Content-Type': 'application/octet-stream',
|
|
574
|
-
Origin: Defaults_1.DEFAULT_ORIGIN
|
|
691
|
+
'Origin': Defaults_1.DEFAULT_ORIGIN
|
|
575
692
|
},
|
|
576
693
|
httpsAgent: fetchAgent,
|
|
577
694
|
timeout: timeoutMs,
|
|
578
695
|
responseType: 'json',
|
|
579
696
|
maxBodyLength: Infinity,
|
|
580
|
-
maxContentLength: Infinity
|
|
697
|
+
maxContentLength: Infinity,
|
|
581
698
|
});
|
|
582
699
|
result = body.data;
|
|
583
|
-
if (result
|
|
700
|
+
if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
|
|
584
701
|
urls = {
|
|
585
702
|
mediaUrl: result.url,
|
|
586
703
|
directPath: result.direct_path,
|
|
587
|
-
|
|
588
|
-
fbid: result.fbid,
|
|
589
|
-
ts: result.ts
|
|
704
|
+
handle: result.handle
|
|
590
705
|
};
|
|
591
706
|
break;
|
|
592
707
|
}
|
|
@@ -596,10 +711,10 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
596
711
|
}
|
|
597
712
|
}
|
|
598
713
|
catch (error) {
|
|
599
|
-
if (
|
|
600
|
-
result = error.response
|
|
714
|
+
if (axios.isAxiosError(error)) {
|
|
715
|
+
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
601
716
|
}
|
|
602
|
-
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]
|
|
717
|
+
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
603
718
|
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
|
|
604
719
|
}
|
|
605
720
|
}
|
|
@@ -616,11 +731,11 @@ const getMediaRetryKey = (mediaKey) => {
|
|
|
616
731
|
/**
|
|
617
732
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
618
733
|
*/
|
|
619
|
-
const encryptMediaRetryRequest =
|
|
734
|
+
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
620
735
|
const recp = { stanzaId: key.id };
|
|
621
|
-
const recpBuffer =
|
|
736
|
+
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
622
737
|
const iv = Crypto.randomBytes(12);
|
|
623
|
-
const retryKey =
|
|
738
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
624
739
|
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
625
740
|
const req = {
|
|
626
741
|
tag: 'receipt',
|
|
@@ -645,7 +760,7 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
645
760
|
tag: 'rmr',
|
|
646
761
|
attrs: {
|
|
647
762
|
jid: key.remoteJid,
|
|
648
|
-
from_me: (!!key.fromMe).toString(),
|
|
763
|
+
'from_me': (!!key.fromMe).toString(),
|
|
649
764
|
// @ts-ignore
|
|
650
765
|
participant: key.participant || undefined
|
|
651
766
|
}
|
|
@@ -668,10 +783,7 @@ const decodeMediaRetryNode = (node) => {
|
|
|
668
783
|
const errorNode = (0, WABinary_1.getBinaryNodeChild)(node, 'error');
|
|
669
784
|
if (errorNode) {
|
|
670
785
|
const errorCode = +errorNode.attrs.code;
|
|
671
|
-
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, {
|
|
672
|
-
data: errorNode.attrs,
|
|
673
|
-
statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode)
|
|
674
|
-
});
|
|
786
|
+
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode) });
|
|
675
787
|
}
|
|
676
788
|
else {
|
|
677
789
|
const encryptedInfoNode = (0, WABinary_1.getBinaryNodeChild)(node, 'encrypt');
|
|
@@ -687,17 +799,21 @@ const decodeMediaRetryNode = (node) => {
|
|
|
687
799
|
return event;
|
|
688
800
|
};
|
|
689
801
|
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
690
|
-
const decryptMediaRetryData =
|
|
691
|
-
const retryKey =
|
|
802
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
803
|
+
const retryKey = getMediaRetryKey(mediaKey);
|
|
692
804
|
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
693
|
-
return
|
|
805
|
+
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
694
806
|
};
|
|
695
807
|
exports.decryptMediaRetryData = decryptMediaRetryData;
|
|
696
808
|
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
|
|
697
809
|
exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
|
|
698
810
|
const MEDIA_RETRY_STATUS_MAP = {
|
|
699
|
-
[
|
|
700
|
-
[
|
|
701
|
-
[
|
|
702
|
-
[
|
|
811
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
812
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
813
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
814
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
703
815
|
};
|
|
816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
817
|
+
function __importStar(arg0) {
|
|
818
|
+
throw new Error('Function not implemented.');
|
|
819
|
+
}
|