@baileys-md/baileys 11.0.3 → 11.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/README.md +1 -1
- package/WAProto/index.js +4182 -13516
- package/WASignalGroup/GroupProtocol.js +1697 -0
- package/WASignalGroup/ciphertext_message.js +16 -0
- package/WASignalGroup/group_cipher.js +120 -0
- package/WASignalGroup/group_session_builder.js +46 -0
- package/WASignalGroup/index.js +5 -0
- package/WASignalGroup/keyhelper.js +21 -0
- package/WASignalGroup/protobufs.js +3 -0
- package/WASignalGroup/queue_job.js +69 -0
- package/WASignalGroup/sender_chain_key.js +50 -0
- package/WASignalGroup/sender_key_distribution_message.js +78 -0
- package/WASignalGroup/sender_key_message.js +92 -0
- package/WASignalGroup/sender_key_name.js +70 -0
- package/WASignalGroup/sender_key_record.js +56 -0
- package/WASignalGroup/sender_key_state.js +129 -0
- package/{lib/Signal/Group/sender-message-key.js → WASignalGroup/sender_message_key.js} +16 -4
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.js +71 -52
- package/lib/Defaults/{phonenumber-mcc.js → phonenumber-mcc.json} +1 -1
- package/lib/Signal/libsignal.js +61 -41
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.js +19 -3
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/business.js +42 -37
- package/lib/Socket/chats.js +187 -194
- package/lib/Socket/groups.js +90 -87
- package/lib/Socket/index.js +8 -7
- package/lib/Socket/messages-recv.js +335 -360
- package/lib/Socket/messages-send.js +279 -156
- package/lib/Socket/newsletter.js +213 -144
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.js +161 -128
- package/lib/Socket/usync.js +26 -19
- package/lib/Store/index.js +8 -0
- package/lib/Store/make-cache-manager-store.js +83 -0
- package/lib/{Utils → Store}/make-in-memory-store.js +27 -19
- package/lib/Store/make-mongo-store.js +567 -0
- package/lib/{Utils → Store}/make-ordered-dictionary.js +5 -2
- package/lib/{Utils → Store}/object-repository.js +4 -1
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.js +4 -8
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.js +5 -3
- package/lib/Types/LabelAssociation.js +5 -3
- package/lib/Types/Message.js +7 -7
- package/lib/Types/Newsletter.js +17 -30
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.js +2 -3
- package/lib/Types/State.js +2 -2
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.js +31 -15
- package/lib/Utils/auth-utils.js +47 -31
- package/lib/Utils/baileys-event-stream.js +22 -15
- package/lib/Utils/business.js +69 -66
- package/lib/Utils/chat-utils.js +195 -200
- package/lib/Utils/crypto.js +85 -70
- package/lib/Utils/decode-wa-message.js +51 -46
- package/lib/Utils/event-buffer.js +46 -36
- package/lib/Utils/generics.js +188 -116
- package/lib/Utils/history.js +46 -37
- package/lib/Utils/index.js +33 -19
- package/lib/Utils/link-preview.js +55 -14
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.js +26 -23
- package/lib/Utils/make-mutex.js +10 -7
- package/lib/Utils/messages-media.js +368 -239
- package/lib/Utils/messages.js +510 -278
- package/lib/Utils/noise-handler.js +31 -22
- package/lib/Utils/process-message.js +148 -144
- package/lib/Utils/signal.js +64 -71
- package/lib/Utils/use-multi-file-auth-state.js +32 -14
- package/lib/Utils/validate-connection.js +115 -72
- package/lib/WABinary/constants.js +20 -1281
- package/lib/WABinary/decode.js +52 -15
- package/lib/WABinary/encode.js +48 -14
- package/lib/WABinary/generic-utils.js +39 -31
- package/lib/WABinary/index.js +21 -6
- package/lib/WABinary/jid-utils.js +40 -23
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.js +5 -2
- package/lib/WAM/constants.js +2366 -2257
- package/lib/WAM/encode.js +21 -17
- package/lib/WAM/index.js +19 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +11 -8
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +14 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -9
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +13 -9
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +22 -20
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +6 -3
- package/lib/WAUSync/Protocols/index.js +20 -5
- package/lib/WAUSync/USyncQuery.js +32 -34
- package/lib/WAUSync/USyncUser.js +5 -2
- package/lib/WAUSync/index.js +19 -4
- package/lib/index.js +33 -11
- package/package.json +61 -21
- package/WAProto/GenerateStatics.sh +0 -3
- package/WAProto/WAProto.proto +0 -4633
- package/WAProto/fix-imports.js +0 -29
- package/lib/Defaults/baileys-version.js +0 -1
- package/lib/Signal/Group/ciphertext-message.js +0 -12
- package/lib/Signal/Group/group-session-builder.js +0 -30
- package/lib/Signal/Group/group_cipher.js +0 -94
- package/lib/Signal/Group/index.js +0 -12
- package/lib/Signal/Group/keyhelper.js +0 -19
- package/lib/Signal/Group/queue-job.js +0 -54
- package/lib/Signal/Group/sender-chain-key.js +0 -32
- package/lib/Signal/Group/sender-key-distribution-message.js +0 -63
- package/lib/Signal/Group/sender-key-message.js +0 -67
- package/lib/Signal/Group/sender-key-name.js +0 -48
- package/lib/Signal/Group/sender-key-record.js +0 -50
- package/lib/Signal/Group/sender-key-state.js +0 -96
- package/lib/Socket/Client/types.js +0 -11
- package/lib/Socket/Client/websocket.js +0 -50
- package/lib/Socket/communities.js +0 -351
- package/lib/Socket/mex.js +0 -42
|
@@ -1,81 +1,108 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const hasher = Crypto.createHash('sha256');
|
|
25
|
-
const filePath = join(tmpdir(), mediaType + generateMessageIDV2());
|
|
26
|
-
const fileWriteStream = createWriteStream(filePath);
|
|
27
|
-
let fileLength = 0;
|
|
28
|
-
try {
|
|
29
|
-
for await (const data of stream) {
|
|
30
|
-
fileLength += data.length;
|
|
31
|
-
hasher.update(data);
|
|
32
|
-
if (!fileWriteStream.write(data)) {
|
|
33
|
-
await once(fileWriteStream, 'drain');
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
fileWriteStream.end();
|
|
37
|
-
await once(fileWriteStream, 'finish');
|
|
38
|
-
stream.destroy();
|
|
39
|
-
const fileSha256 = hasher.digest();
|
|
40
|
-
logger?.debug('hashed data for raw upload');
|
|
41
|
-
return {
|
|
42
|
-
filePath: filePath,
|
|
43
|
-
fileSha256,
|
|
44
|
-
fileLength
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
45
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 };
|
|
37
|
+
};
|
|
38
|
+
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.hkdfInfoKey = void 0;
|
|
40
|
+
exports.getMediaKeys = getMediaKeys;
|
|
41
|
+
exports.getAudioDuration = getAudioDuration;
|
|
42
|
+
exports.getAudioWaveform = getAudioWaveform;
|
|
43
|
+
exports.generateThumbnail = generateThumbnail;
|
|
44
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
45
|
+
const boom_1 = require("@hapi/boom");
|
|
46
|
+
const axios_1 = __importDefault(require("axios"));
|
|
47
|
+
const child_process_1 = require("child_process");
|
|
48
|
+
const Crypto = __importStar(require("crypto"));
|
|
49
|
+
const events_1 = require("events");
|
|
50
|
+
const fs_1 = require("fs");
|
|
51
|
+
const os_1 = require("os");
|
|
52
|
+
const path_1 = require("path");
|
|
53
|
+
const jimp_1 = __importDefault(require("jimp"));
|
|
54
|
+
const stream_1 = require("stream");
|
|
55
|
+
const WAProto_1 = require("../../WAProto");
|
|
56
|
+
const Defaults_1 = require("../Defaults");
|
|
57
|
+
const WABinary_1 = require("../WABinary");
|
|
58
|
+
const crypto_1 = require("./crypto");
|
|
59
|
+
const generics_1 = require("./generics");
|
|
60
|
+
const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
|
|
61
|
+
const getImageProcessingLibrary = async () => {
|
|
62
|
+
const [_jimp, sharp] = await Promise.all([
|
|
63
|
+
(async () => {
|
|
64
|
+
const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
|
|
65
|
+
return jimp;
|
|
66
|
+
})(),
|
|
67
|
+
(async () => {
|
|
68
|
+
const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
|
|
69
|
+
return sharp;
|
|
70
|
+
})()
|
|
71
|
+
]);
|
|
72
|
+
if (sharp) {
|
|
73
|
+
return { sharp };
|
|
46
74
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
await fs.unlink(filePath);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
//
|
|
55
|
-
}
|
|
56
|
-
throw error;
|
|
75
|
+
const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
|
|
76
|
+
if (jimp) {
|
|
77
|
+
return { jimp };
|
|
57
78
|
}
|
|
79
|
+
throw new boom_1.Boom('No image processing library available');
|
|
58
80
|
};
|
|
81
|
+
const hkdfInfoKey = (type) => {
|
|
82
|
+
const hkdfInfo = Defaults_1.MEDIA_HKDF_KEY_MAPPING[type];
|
|
83
|
+
return `WhatsApp ${hkdfInfo} Keys`;
|
|
84
|
+
};
|
|
85
|
+
exports.hkdfInfoKey = hkdfInfoKey;
|
|
59
86
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
60
|
-
|
|
87
|
+
async function getMediaKeys(buffer, mediaType) {
|
|
61
88
|
if (!buffer) {
|
|
62
|
-
throw new Boom('Cannot derive from empty media key');
|
|
89
|
+
throw new boom_1.Boom('Cannot derive from empty media key');
|
|
63
90
|
}
|
|
64
91
|
if (typeof buffer === 'string') {
|
|
65
92
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
66
93
|
}
|
|
67
94
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
68
|
-
const expandedMediaKey = await hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) });
|
|
95
|
+
const expandedMediaKey = await (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
|
|
69
96
|
return {
|
|
70
97
|
iv: expandedMediaKey.slice(0, 16),
|
|
71
98
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
72
|
-
macKey: expandedMediaKey.slice(48, 80)
|
|
99
|
+
macKey: expandedMediaKey.slice(48, 80),
|
|
73
100
|
};
|
|
74
101
|
}
|
|
75
102
|
/** Extracts video thumb using FFMPEG */
|
|
76
103
|
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
|
|
77
104
|
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
|
|
78
|
-
exec(cmd, err => {
|
|
105
|
+
(0, child_process_1.exec)(cmd, (err) => {
|
|
79
106
|
if (err) {
|
|
80
107
|
reject(err);
|
|
81
108
|
}
|
|
@@ -84,86 +111,117 @@ const extractVideoThumb = async (path, destPath, time, size) => new Promise((res
|
|
|
84
111
|
}
|
|
85
112
|
});
|
|
86
113
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
114
|
+
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
115
|
+
var _a, _b;
|
|
116
|
+
if (bufferOrFilePath instanceof stream_1.Readable) {
|
|
117
|
+
bufferOrFilePath = await (0, exports.toBuffer)(bufferOrFilePath);
|
|
118
|
+
}
|
|
119
|
+
const lib = await getImageProcessingLibrary();
|
|
120
|
+
if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
|
|
121
|
+
const img = lib.sharp.default(bufferOrFilePath);
|
|
122
|
+
const dimensions = await img.metadata();
|
|
123
|
+
const buffer = await img
|
|
124
|
+
.resize(width)
|
|
125
|
+
.jpeg({ quality: 50 })
|
|
126
|
+
.toBuffer();
|
|
127
|
+
return {
|
|
128
|
+
buffer,
|
|
129
|
+
original: {
|
|
130
|
+
width: dimensions.width,
|
|
131
|
+
height: dimensions.height,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
|
|
136
|
+
const { read, MIME_JPEG, RESIZE_BILINEAR, AUTO } = lib.jimp;
|
|
137
|
+
const jimp = await read(bufferOrFilePath);
|
|
138
|
+
const dimensions = {
|
|
139
|
+
width: jimp.getWidth(),
|
|
140
|
+
height: jimp.getHeight()
|
|
141
|
+
};
|
|
142
|
+
const buffer = await jimp
|
|
143
|
+
.quality(50)
|
|
144
|
+
.resize(width, AUTO, RESIZE_BILINEAR)
|
|
145
|
+
.getBufferAsync(MIME_JPEG);
|
|
146
|
+
return {
|
|
147
|
+
buffer,
|
|
148
|
+
original: dimensions
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
throw new boom_1.Boom('No image processing library available');
|
|
153
|
+
}
|
|
108
154
|
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
155
|
+
exports.extractImageThumb = extractImageThumb;
|
|
156
|
+
const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
|
|
157
|
+
.replace(/\+/g, '-')
|
|
158
|
+
.replace(/\//g, '_')
|
|
159
|
+
.replace(/\=+$/, '')));
|
|
160
|
+
exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
|
|
161
|
+
const generateProfilePicture = async (mediaUpload) => {
|
|
162
|
+
let bufferOrFilePath;
|
|
163
|
+
let img;
|
|
113
164
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
const cropped =
|
|
165
|
+
bufferOrFilePath = mediaUpload;
|
|
166
|
+
}
|
|
167
|
+
else if ('url' in mediaUpload) {
|
|
168
|
+
bufferOrFilePath = mediaUpload.url.toString();
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
|
|
172
|
+
}
|
|
173
|
+
const jimp = await jimp_1.default.read(bufferOrFilePath);
|
|
174
|
+
const cropped = jimp.getWidth() > jimp.getHeight() ? jimp.resize(550, -1) : jimp.resize(-1, 650);
|
|
175
|
+
img = cropped
|
|
176
|
+
.quality(100)
|
|
177
|
+
.getBufferAsync(jimp_1.default.MIME_JPEG);
|
|
124
178
|
return {
|
|
125
|
-
img: await
|
|
179
|
+
img: await img,
|
|
126
180
|
};
|
|
127
181
|
};
|
|
182
|
+
exports.generateProfilePicture = generateProfilePicture;
|
|
128
183
|
/** gets the SHA256 of the given media message */
|
|
129
|
-
|
|
184
|
+
const mediaMessageSHA256B64 = (message) => {
|
|
130
185
|
const media = Object.values(message)[0];
|
|
131
|
-
return media
|
|
186
|
+
return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
|
|
132
187
|
};
|
|
133
|
-
|
|
134
|
-
|
|
188
|
+
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
|
|
189
|
+
async function getAudioDuration(buffer) {
|
|
190
|
+
const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
|
|
135
191
|
let metadata;
|
|
136
|
-
const options = {
|
|
137
|
-
duration: true
|
|
138
|
-
};
|
|
139
192
|
if (Buffer.isBuffer(buffer)) {
|
|
140
|
-
metadata = await musicMetadata.parseBuffer(buffer, undefined,
|
|
193
|
+
metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
|
|
141
194
|
}
|
|
142
195
|
else if (typeof buffer === 'string') {
|
|
143
|
-
|
|
196
|
+
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
197
|
+
try {
|
|
198
|
+
metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
rStream.destroy();
|
|
202
|
+
}
|
|
144
203
|
}
|
|
145
204
|
else {
|
|
146
|
-
metadata = await musicMetadata.parseStream(buffer, undefined,
|
|
205
|
+
metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
|
|
147
206
|
}
|
|
148
207
|
return metadata.format.duration;
|
|
149
208
|
}
|
|
150
209
|
/**
|
|
151
210
|
referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
|
|
152
211
|
*/
|
|
153
|
-
|
|
212
|
+
async function getAudioWaveform(buffer, logger) {
|
|
154
213
|
try {
|
|
155
|
-
|
|
156
|
-
const { default: decoder } = await import('audio-decode');
|
|
214
|
+
const { default: decoder } = await eval('import(\'audio-decode\')');
|
|
157
215
|
let audioData;
|
|
158
216
|
if (Buffer.isBuffer(buffer)) {
|
|
159
217
|
audioData = buffer;
|
|
160
218
|
}
|
|
161
219
|
else if (typeof buffer === 'string') {
|
|
162
|
-
const rStream = createReadStream(buffer);
|
|
163
|
-
audioData = await toBuffer(rStream);
|
|
220
|
+
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
221
|
+
audioData = await (0, exports.toBuffer)(rStream);
|
|
164
222
|
}
|
|
165
223
|
else {
|
|
166
|
-
audioData = await toBuffer(buffer);
|
|
224
|
+
audioData = await (0, exports.toBuffer)(buffer);
|
|
167
225
|
}
|
|
168
226
|
const audioBuffer = await decoder(audioData);
|
|
169
227
|
const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
|
|
@@ -180,22 +238,23 @@ export async function getAudioWaveform(buffer, logger) {
|
|
|
180
238
|
}
|
|
181
239
|
// This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
|
|
182
240
|
const multiplier = Math.pow(Math.max(...filteredData), -1);
|
|
183
|
-
const normalizedData = filteredData.map(n => n * multiplier);
|
|
241
|
+
const normalizedData = filteredData.map((n) => n * multiplier);
|
|
184
242
|
// Generate waveform like WhatsApp
|
|
185
|
-
const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)));
|
|
243
|
+
const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
|
|
186
244
|
return waveform;
|
|
187
245
|
}
|
|
188
246
|
catch (e) {
|
|
189
|
-
logger
|
|
247
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
|
|
190
248
|
}
|
|
191
249
|
}
|
|
192
|
-
|
|
193
|
-
const readable = new Readable({ read: () => { } });
|
|
250
|
+
const toReadable = (buffer) => {
|
|
251
|
+
const readable = new stream_1.Readable({ read: () => { } });
|
|
194
252
|
readable.push(buffer);
|
|
195
253
|
readable.push(null);
|
|
196
254
|
return readable;
|
|
197
255
|
};
|
|
198
|
-
|
|
256
|
+
exports.toReadable = toReadable;
|
|
257
|
+
const toBuffer = async (stream) => {
|
|
199
258
|
const chunks = [];
|
|
200
259
|
for await (const chunk of stream) {
|
|
201
260
|
chunks.push(chunk);
|
|
@@ -203,47 +262,45 @@ export const toBuffer = async (stream) => {
|
|
|
203
262
|
stream.destroy();
|
|
204
263
|
return Buffer.concat(chunks);
|
|
205
264
|
};
|
|
206
|
-
|
|
265
|
+
exports.toBuffer = toBuffer;
|
|
266
|
+
const getStream = async (item, opts) => {
|
|
207
267
|
if (Buffer.isBuffer(item)) {
|
|
208
|
-
return { stream: toReadable(item), type: 'buffer' };
|
|
268
|
+
return { stream: (0, exports.toReadable)(item), type: 'buffer' };
|
|
209
269
|
}
|
|
210
270
|
if ('stream' in item) {
|
|
211
271
|
return { stream: item.stream, type: 'readable' };
|
|
212
272
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const buffer = Buffer.from(urlStr.split(',')[1], 'base64');
|
|
216
|
-
return { stream: toReadable(buffer), type: 'buffer' };
|
|
217
|
-
}
|
|
218
|
-
if (urlStr.startsWith('http://') || urlStr.startsWith('https://')) {
|
|
219
|
-
return { stream: await getHttpStream(item.url, opts), type: 'remote' };
|
|
273
|
+
if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
|
|
274
|
+
return { stream: await (0, exports.getHttpStream)(item.url, opts), type: 'remote' };
|
|
220
275
|
}
|
|
221
|
-
return { stream: createReadStream(item.url), type: 'file' };
|
|
276
|
+
return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
|
|
222
277
|
};
|
|
278
|
+
exports.getStream = getStream;
|
|
223
279
|
/** generates a thumbnail for a given media, if required */
|
|
224
|
-
|
|
280
|
+
async function generateThumbnail(file, mediaType, options) {
|
|
281
|
+
var _a;
|
|
225
282
|
let thumbnail;
|
|
226
283
|
let originalImageDimensions;
|
|
227
284
|
if (mediaType === 'image') {
|
|
228
|
-
const { buffer, original } = await extractImageThumb(file);
|
|
285
|
+
const { buffer, original } = await (0, exports.extractImageThumb)(file);
|
|
229
286
|
thumbnail = buffer.toString('base64');
|
|
230
287
|
if (original.width && original.height) {
|
|
231
288
|
originalImageDimensions = {
|
|
232
289
|
width: original.width,
|
|
233
|
-
height: original.height
|
|
290
|
+
height: original.height,
|
|
234
291
|
};
|
|
235
292
|
}
|
|
236
293
|
}
|
|
237
294
|
else if (mediaType === 'video') {
|
|
238
|
-
const imgFilename = join(getTmpFilesDirectory(), generateMessageIDV2() + '.jpg');
|
|
295
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
|
|
239
296
|
try {
|
|
240
297
|
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
241
|
-
const buff = await
|
|
298
|
+
const buff = await fs_1.promises.readFile(imgFilename);
|
|
242
299
|
thumbnail = buff.toString('base64');
|
|
243
|
-
await
|
|
300
|
+
await fs_1.promises.unlink(imgFilename);
|
|
244
301
|
}
|
|
245
302
|
catch (err) {
|
|
246
|
-
options.logger
|
|
303
|
+
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
247
304
|
}
|
|
248
305
|
}
|
|
249
306
|
return {
|
|
@@ -251,110 +308,160 @@ export async function generateThumbnail(file, mediaType, options) {
|
|
|
251
308
|
originalImageDimensions
|
|
252
309
|
};
|
|
253
310
|
}
|
|
254
|
-
|
|
255
|
-
const fetched = await
|
|
311
|
+
const getHttpStream = async (url, options = {}) => {
|
|
312
|
+
const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
|
|
256
313
|
return fetched.data;
|
|
257
314
|
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
315
|
+
exports.getHttpStream = getHttpStream;
|
|
316
|
+
const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
317
|
+
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
318
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
319
|
+
let bodyPath;
|
|
320
|
+
let didSaveToTmpPath = false;
|
|
321
|
+
try {
|
|
322
|
+
const buffer = await (0, exports.toBuffer)(stream);
|
|
323
|
+
if (type === 'file') {
|
|
324
|
+
bodyPath = media.url;
|
|
325
|
+
}
|
|
326
|
+
else if (saveOriginalFileIfRequired) {
|
|
327
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
|
|
328
|
+
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
329
|
+
didSaveToTmpPath = true;
|
|
330
|
+
}
|
|
331
|
+
const fileLength = buffer.length;
|
|
332
|
+
const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
|
|
333
|
+
stream === null || stream === void 0 ? void 0 : stream.destroy();
|
|
334
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
|
|
335
|
+
return {
|
|
336
|
+
mediaKey: undefined,
|
|
337
|
+
encWriteStream: buffer,
|
|
338
|
+
fileLength,
|
|
339
|
+
fileSha256,
|
|
340
|
+
fileEncSha256: undefined,
|
|
341
|
+
bodyPath,
|
|
342
|
+
didSaveToTmpPath
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
// destroy all streams with error
|
|
347
|
+
stream.destroy();
|
|
348
|
+
if (didSaveToTmpPath) {
|
|
349
|
+
try {
|
|
350
|
+
await fs_1.promises.unlink(bodyPath);
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
exports.prepareStream = prepareStream;
|
|
360
|
+
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
361
|
+
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
362
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
261
363
|
const mediaKey = Crypto.randomBytes(32);
|
|
262
364
|
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
let
|
|
266
|
-
let
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
365
|
+
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
366
|
+
let bodyPath;
|
|
367
|
+
let writeStream;
|
|
368
|
+
let didSaveToTmpPath = false;
|
|
369
|
+
if (type === 'file') {
|
|
370
|
+
bodyPath = media.url;
|
|
371
|
+
}
|
|
372
|
+
else if (saveOriginalFileIfRequired) {
|
|
373
|
+
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
|
|
374
|
+
writeStream = (0, fs_1.createWriteStream)(bodyPath);
|
|
375
|
+
didSaveToTmpPath = true;
|
|
270
376
|
}
|
|
271
377
|
let fileLength = 0;
|
|
272
378
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const onChunk = (buff) => {
|
|
277
|
-
sha256Enc.update(buff);
|
|
278
|
-
hmac.update(buff);
|
|
279
|
-
encFileWriteStream.write(buff);
|
|
280
|
-
};
|
|
379
|
+
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
380
|
+
let sha256Plain = Crypto.createHash('sha256');
|
|
381
|
+
let sha256Enc = Crypto.createHash('sha256');
|
|
281
382
|
try {
|
|
282
383
|
for await (const data of stream) {
|
|
283
384
|
fileLength += data.length;
|
|
284
|
-
if (type === 'remote'
|
|
285
|
-
|
|
385
|
+
if (type === 'remote'
|
|
386
|
+
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
387
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
388
|
+
throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
|
|
286
389
|
data: { media, type }
|
|
287
390
|
});
|
|
288
391
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
392
|
+
sha256Plain = sha256Plain.update(data);
|
|
393
|
+
if (writeStream) {
|
|
394
|
+
if (!writeStream.write(data)) {
|
|
395
|
+
await (0, events_1.once)(writeStream, 'drain');
|
|
292
396
|
}
|
|
293
397
|
}
|
|
294
|
-
sha256Plain.update(data);
|
|
295
398
|
onChunk(aes.update(data));
|
|
296
399
|
}
|
|
297
400
|
onChunk(aes.final());
|
|
298
401
|
const mac = hmac.digest().slice(0, 10);
|
|
299
|
-
sha256Enc.update(mac);
|
|
402
|
+
sha256Enc = sha256Enc.update(mac);
|
|
300
403
|
const fileSha256 = sha256Plain.digest();
|
|
301
404
|
const fileEncSha256 = sha256Enc.digest();
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
405
|
+
encWriteStream.push(mac);
|
|
406
|
+
encWriteStream.push(null);
|
|
407
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
305
408
|
stream.destroy();
|
|
306
|
-
logger
|
|
409
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
|
|
307
410
|
return {
|
|
308
411
|
mediaKey,
|
|
309
|
-
|
|
310
|
-
|
|
412
|
+
encWriteStream,
|
|
413
|
+
bodyPath,
|
|
311
414
|
mac,
|
|
312
415
|
fileEncSha256,
|
|
313
416
|
fileSha256,
|
|
314
|
-
fileLength
|
|
417
|
+
fileLength,
|
|
418
|
+
didSaveToTmpPath
|
|
315
419
|
};
|
|
316
420
|
}
|
|
317
421
|
catch (error) {
|
|
318
422
|
// destroy all streams with error
|
|
319
|
-
|
|
320
|
-
|
|
423
|
+
encWriteStream.destroy();
|
|
424
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
|
321
425
|
aes.destroy();
|
|
322
426
|
hmac.destroy();
|
|
323
427
|
sha256Plain.destroy();
|
|
324
428
|
sha256Enc.destroy();
|
|
325
429
|
stream.destroy();
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
430
|
+
if (didSaveToTmpPath) {
|
|
431
|
+
try {
|
|
432
|
+
await fs_1.promises.unlink(bodyPath);
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
330
436
|
}
|
|
331
|
-
}
|
|
332
|
-
catch (err) {
|
|
333
|
-
logger?.error({ err }, 'failed deleting tmp files');
|
|
334
437
|
}
|
|
335
438
|
throw error;
|
|
336
439
|
}
|
|
440
|
+
function onChunk(buff) {
|
|
441
|
+
sha256Enc = sha256Enc.update(buff);
|
|
442
|
+
hmac = hmac.update(buff);
|
|
443
|
+
encWriteStream.push(buff);
|
|
444
|
+
}
|
|
337
445
|
};
|
|
446
|
+
exports.encryptedStream = encryptedStream;
|
|
338
447
|
const DEF_HOST = 'mmg.whatsapp.net';
|
|
339
448
|
const AES_CHUNK_SIZE = 16;
|
|
340
449
|
const toSmallestChunkSize = (num) => {
|
|
341
450
|
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE;
|
|
342
451
|
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const downloadUrl =
|
|
347
|
-
if (!downloadUrl) {
|
|
348
|
-
throw new Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
349
|
-
}
|
|
452
|
+
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
453
|
+
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
454
|
+
const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
455
|
+
const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
|
|
350
456
|
const keys = await getMediaKeys(mediaKey, type);
|
|
351
|
-
return downloadEncryptedContent(downloadUrl, keys, opts);
|
|
457
|
+
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
352
458
|
};
|
|
459
|
+
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
353
460
|
/**
|
|
354
461
|
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
355
462
|
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
356
463
|
* */
|
|
357
|
-
|
|
464
|
+
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
358
465
|
let bytesFetched = 0;
|
|
359
466
|
let startChunk = 0;
|
|
360
467
|
let firstBlockIsIV = false;
|
|
@@ -369,8 +476,8 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
369
476
|
}
|
|
370
477
|
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
|
|
371
478
|
const headers = {
|
|
372
|
-
...(options
|
|
373
|
-
Origin: DEFAULT_ORIGIN
|
|
479
|
+
...(options === null || options === void 0 ? void 0 : options.headers) || {},
|
|
480
|
+
Origin: Defaults_1.DEFAULT_ORIGIN,
|
|
374
481
|
};
|
|
375
482
|
if (startChunk || endChunk) {
|
|
376
483
|
headers.Range = `bytes=${startChunk}-`;
|
|
@@ -379,11 +486,11 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
379
486
|
}
|
|
380
487
|
}
|
|
381
488
|
// download the message
|
|
382
|
-
const fetched = await getHttpStream(downloadUrl, {
|
|
383
|
-
...
|
|
489
|
+
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
490
|
+
...options || {},
|
|
384
491
|
headers,
|
|
385
492
|
maxBodyLength: Infinity,
|
|
386
|
-
maxContentLength: Infinity
|
|
493
|
+
maxContentLength: Infinity,
|
|
387
494
|
});
|
|
388
495
|
let remainingBytes = Buffer.from([]);
|
|
389
496
|
let aes;
|
|
@@ -398,7 +505,7 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
398
505
|
push(bytes);
|
|
399
506
|
}
|
|
400
507
|
};
|
|
401
|
-
const output = new Transform({
|
|
508
|
+
const output = new stream_1.Transform({
|
|
402
509
|
transform(chunk, _, callback) {
|
|
403
510
|
let data = Buffer.concat([remainingBytes, chunk]);
|
|
404
511
|
const decryptLength = toSmallestChunkSize(data.length);
|
|
@@ -433,15 +540,18 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
433
540
|
catch (error) {
|
|
434
541
|
callback(error);
|
|
435
542
|
}
|
|
436
|
-
}
|
|
543
|
+
},
|
|
437
544
|
});
|
|
438
545
|
return fetched.pipe(output, { end: true });
|
|
439
546
|
};
|
|
440
|
-
|
|
441
|
-
|
|
547
|
+
exports.downloadEncryptedContent = downloadEncryptedContent;
|
|
548
|
+
function extensionForMediaMessage(message) {
|
|
549
|
+
const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
|
|
442
550
|
const type = Object.keys(message)[0];
|
|
443
551
|
let extension;
|
|
444
|
-
if (type === 'locationMessage' ||
|
|
552
|
+
if (type === 'locationMessage' ||
|
|
553
|
+
type === 'liveLocationMessage' ||
|
|
554
|
+
type === 'productMessage') {
|
|
445
555
|
extension = '.jpeg';
|
|
446
556
|
}
|
|
447
557
|
else {
|
|
@@ -450,39 +560,53 @@ export function extensionForMediaMessage(message) {
|
|
|
450
560
|
}
|
|
451
561
|
return extension;
|
|
452
562
|
}
|
|
453
|
-
|
|
454
|
-
return async (
|
|
563
|
+
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
564
|
+
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
565
|
+
var _a, _b;
|
|
455
566
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
456
567
|
let uploadInfo = await refreshMediaConn(false);
|
|
457
568
|
let urls;
|
|
458
569
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
459
|
-
|
|
460
|
-
|
|
570
|
+
const chunks = [];
|
|
571
|
+
if (!Buffer.isBuffer(stream)) {
|
|
572
|
+
for await (const chunk of stream) {
|
|
573
|
+
chunks.push(chunk);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
|
|
577
|
+
fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
|
|
578
|
+
let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
|
|
579
|
+
if (newsletter) {
|
|
580
|
+
media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
|
|
581
|
+
}
|
|
582
|
+
for (const { hostname, maxContentLengthBytes } of hosts) {
|
|
461
583
|
logger.debug(`uploading to "${hostname}"`);
|
|
462
584
|
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
463
|
-
const url = `https://${hostname}${
|
|
464
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
585
|
+
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
465
586
|
let result;
|
|
466
587
|
try {
|
|
467
|
-
|
|
588
|
+
if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
|
|
589
|
+
throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
|
|
590
|
+
}
|
|
591
|
+
const body = await axios_1.default.post(url, reqBody, {
|
|
468
592
|
...options,
|
|
469
|
-
maxRedirects: 0,
|
|
470
593
|
headers: {
|
|
471
|
-
...
|
|
594
|
+
...options.headers || {},
|
|
472
595
|
'Content-Type': 'application/octet-stream',
|
|
473
|
-
Origin: DEFAULT_ORIGIN
|
|
596
|
+
'Origin': Defaults_1.DEFAULT_ORIGIN
|
|
474
597
|
},
|
|
475
598
|
httpsAgent: fetchAgent,
|
|
476
599
|
timeout: timeoutMs,
|
|
477
600
|
responseType: 'json',
|
|
478
601
|
maxBodyLength: Infinity,
|
|
479
|
-
maxContentLength: Infinity
|
|
602
|
+
maxContentLength: Infinity,
|
|
480
603
|
});
|
|
481
604
|
result = body.data;
|
|
482
|
-
if (result
|
|
605
|
+
if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
|
|
483
606
|
urls = {
|
|
484
607
|
mediaUrl: result.url,
|
|
485
|
-
directPath: result.direct_path
|
|
608
|
+
directPath: result.direct_path,
|
|
609
|
+
handle: result.handle
|
|
486
610
|
};
|
|
487
611
|
break;
|
|
488
612
|
}
|
|
@@ -492,36 +616,37 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, opt
|
|
|
492
616
|
}
|
|
493
617
|
}
|
|
494
618
|
catch (error) {
|
|
495
|
-
if (
|
|
496
|
-
result = error.response
|
|
619
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
620
|
+
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
497
621
|
}
|
|
498
|
-
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]
|
|
622
|
+
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
499
623
|
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
|
|
500
624
|
}
|
|
501
625
|
}
|
|
502
626
|
if (!urls) {
|
|
503
|
-
throw new Boom('Media upload failed on all hosts', { statusCode: 500 });
|
|
627
|
+
throw new boom_1.Boom('Media upload failed on all hosts', { statusCode: 500 });
|
|
504
628
|
}
|
|
505
629
|
return urls;
|
|
506
630
|
};
|
|
507
631
|
};
|
|
632
|
+
exports.getWAUploadToServer = getWAUploadToServer;
|
|
508
633
|
const getMediaRetryKey = (mediaKey) => {
|
|
509
|
-
return hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
634
|
+
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
510
635
|
};
|
|
511
636
|
/**
|
|
512
637
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
513
638
|
*/
|
|
514
|
-
|
|
639
|
+
const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
515
640
|
const recp = { stanzaId: key.id };
|
|
516
|
-
const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish();
|
|
641
|
+
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
517
642
|
const iv = Crypto.randomBytes(12);
|
|
518
643
|
const retryKey = await getMediaRetryKey(mediaKey);
|
|
519
|
-
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
644
|
+
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
520
645
|
const req = {
|
|
521
646
|
tag: 'receipt',
|
|
522
647
|
attrs: {
|
|
523
648
|
id: key.id,
|
|
524
|
-
to: jidNormalizedUser(meId),
|
|
649
|
+
to: (0, WABinary_1.jidNormalizedUser)(meId),
|
|
525
650
|
type: 'server-error'
|
|
526
651
|
},
|
|
527
652
|
content: [
|
|
@@ -540,7 +665,7 @@ export const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
540
665
|
tag: 'rmr',
|
|
541
666
|
attrs: {
|
|
542
667
|
jid: key.remoteJid,
|
|
543
|
-
from_me: (!!key.fromMe).toString(),
|
|
668
|
+
'from_me': (!!key.fromMe).toString(),
|
|
544
669
|
// @ts-ignore
|
|
545
670
|
participant: key.participant || undefined
|
|
546
671
|
}
|
|
@@ -549,8 +674,9 @@ export const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
549
674
|
};
|
|
550
675
|
return req;
|
|
551
676
|
};
|
|
552
|
-
|
|
553
|
-
|
|
677
|
+
exports.encryptMediaRetryRequest = encryptMediaRetryRequest;
|
|
678
|
+
const decodeMediaRetryNode = (node) => {
|
|
679
|
+
const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
|
|
554
680
|
const event = {
|
|
555
681
|
key: {
|
|
556
682
|
id: node.attrs.id,
|
|
@@ -559,37 +685,40 @@ export const decodeMediaRetryNode = (node) => {
|
|
|
559
685
|
participant: rmrNode.attrs.participant
|
|
560
686
|
}
|
|
561
687
|
};
|
|
562
|
-
const errorNode = getBinaryNodeChild(node, 'error');
|
|
688
|
+
const errorNode = (0, WABinary_1.getBinaryNodeChild)(node, 'error');
|
|
563
689
|
if (errorNode) {
|
|
564
690
|
const errorCode = +errorNode.attrs.code;
|
|
565
|
-
event.error = new Boom(`Failed to re-upload media (${errorCode})`, {
|
|
566
|
-
data: errorNode.attrs,
|
|
567
|
-
statusCode: getStatusCodeForMediaRetry(errorCode)
|
|
568
|
-
});
|
|
691
|
+
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode) });
|
|
569
692
|
}
|
|
570
693
|
else {
|
|
571
|
-
const encryptedInfoNode = getBinaryNodeChild(node, 'encrypt');
|
|
572
|
-
const ciphertext = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p');
|
|
573
|
-
const iv = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv');
|
|
694
|
+
const encryptedInfoNode = (0, WABinary_1.getBinaryNodeChild)(node, 'encrypt');
|
|
695
|
+
const ciphertext = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_p');
|
|
696
|
+
const iv = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_iv');
|
|
574
697
|
if (ciphertext && iv) {
|
|
575
698
|
event.media = { ciphertext, iv };
|
|
576
699
|
}
|
|
577
700
|
else {
|
|
578
|
-
event.error = new Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
|
|
701
|
+
event.error = new boom_1.Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
|
|
579
702
|
}
|
|
580
703
|
}
|
|
581
704
|
return event;
|
|
582
705
|
};
|
|
583
|
-
|
|
706
|
+
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
707
|
+
const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
584
708
|
const retryKey = await getMediaRetryKey(mediaKey);
|
|
585
|
-
const plaintext = aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
586
|
-
return proto.MediaRetryNotification.decode(plaintext);
|
|
709
|
+
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
710
|
+
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
587
711
|
};
|
|
588
|
-
|
|
712
|
+
exports.decryptMediaRetryData = decryptMediaRetryData;
|
|
713
|
+
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
|
|
714
|
+
exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
|
|
589
715
|
const MEDIA_RETRY_STATUS_MAP = {
|
|
590
|
-
[proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
591
|
-
[proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
592
|
-
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
593
|
-
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
|
|
716
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
717
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
718
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
719
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
594
720
|
};
|
|
595
|
-
|
|
721
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
722
|
+
function __importStar(arg0) {
|
|
723
|
+
throw new Error('Function not implemented.');
|
|
724
|
+
}
|