@alannxd/baileys 6.0.5 → 6.0.6
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/fix-import.js +29 -0
- package/WAProto/index.js +160 -201
- package/engine-requirements.js +1 -1
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +15 -37
- package/lib/Defaults/index.js +136 -119
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -1
- package/lib/Signal/Group/ciphertext-message.js +5 -2
- package/lib/Signal/Group/group-session-builder.d.ts +3 -4
- package/lib/Signal/Group/group-session-builder.js +41 -7
- package/lib/Signal/Group/group_cipher.d.ts +4 -4
- package/lib/Signal/Group/group_cipher.js +51 -37
- package/lib/Signal/Group/index.d.ts +11 -12
- package/lib/Signal/Group/index.js +57 -12
- package/lib/Signal/Group/keyhelper.d.ts +1 -2
- package/lib/Signal/Group/keyhelper.js +44 -7
- 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 +2 -3
- package/lib/Signal/Group/sender-chain-key.js +15 -7
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +1 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +11 -8
- package/lib/Signal/Group/sender-key-message.d.ts +1 -2
- package/lib/Signal/Group/sender-key-message.js +12 -9
- package/lib/Signal/Group/sender-key-name.d.ts +0 -1
- package/lib/Signal/Group/sender-key-name.js +5 -2
- package/lib/Signal/Group/sender-key-record.d.ts +2 -3
- package/lib/Signal/Group/sender-key-record.js +21 -9
- package/lib/Signal/Group/sender-key-state.d.ts +6 -7
- package/lib/Signal/Group/sender-key-state.js +42 -27
- package/lib/Signal/Group/sender-message-key.d.ts +0 -1
- package/lib/Signal/Group/sender-message-key.js +7 -4
- package/lib/Signal/libsignal.d.ts +3 -5
- package/lib/Signal/libsignal.js +90 -347
- package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +5 -4
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.d.ts +3 -3
- package/lib/Socket/Client/index.js +19 -3
- 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} +2 -3
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/business.d.ts +108 -154
- package/lib/Socket/business.js +43 -162
- package/lib/Socket/chats.d.ts +239 -96
- package/lib/Socket/chats.js +427 -627
- package/lib/Socket/communities.d.ts +146 -239
- package/lib/Socket/communities.js +80 -90
- package/lib/Socket/groups.d.ts +57 -104
- package/lib/Socket/groups.js +161 -154
- package/lib/Socket/index.d.ts +115 -202
- package/lib/Socket/index.js +10 -11
- package/lib/Socket/luxu.d.ts +266 -22
- package/lib/Socket/luxu.js +465 -422
- package/lib/Socket/messages-recv.d.ts +84 -136
- package/lib/Socket/messages-recv.js +615 -1421
- package/lib/Socket/messages-send.d.ts +126 -142
- package/lib/Socket/messages-send.js +671 -878
- package/lib/Socket/newsletter.d.ts +85 -121
- package/lib/Socket/newsletter.js +272 -147
- package/lib/Socket/registration.d.ts +267 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +19 -34
- package/lib/Socket/socket.js +313 -544
- package/lib/Socket/usync.d.ts +36 -0
- package/lib/Socket/usync.js +70 -0
- package/lib/Store/index.d.ts +3 -10
- package/lib/Store/index.js +10 -10
- package/lib/Store/make-cache-manager-store.d.ts +11 -17
- package/lib/Store/make-cache-manager-store.js +41 -43
- package/lib/Store/make-in-memory-store.d.ts +118 -39
- package/lib/Store/make-in-memory-store.js +341 -112
- package/lib/Store/make-ordered-dictionary.d.ts +10 -11
- package/lib/Store/make-ordered-dictionary.js +20 -14
- package/lib/Store/object-repository.d.ts +9 -10
- package/lib/Store/object-repository.js +6 -11
- package/lib/Types/Auth.d.ts +12 -19
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Call.d.ts +1 -3
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.d.ts +13 -35
- package/lib/Types/Chat.js +4 -8
- package/lib/Types/Contact.d.ts +1 -8
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.d.ts +17 -116
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.d.ts +5 -21
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.d.ts +0 -12
- package/lib/Types/Label.js +5 -3
- package/lib/Types/LabelAssociation.d.ts +0 -1
- package/lib/Types/LabelAssociation.js +5 -3
- package/lib/Types/Message.d.ts +58 -105
- package/lib/Types/Message.js +9 -11
- package/lib/Types/Newsletter.d.ts +103 -0
- package/lib/Types/Newsletter.js +38 -0
- package/lib/Types/Product.d.ts +1 -2
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.d.ts +2 -32
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.d.ts +25 -50
- package/lib/Types/Socket.js +2 -3
- package/lib/Types/State.d.ts +2 -72
- package/lib/Types/State.js +2 -56
- package/lib/Types/USync.d.ts +2 -3
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.d.ts +14 -22
- package/lib/Types/index.js +31 -15
- package/lib/Utils/auth-utils.d.ts +6 -12
- package/lib/Utils/auth-utils.js +143 -239
- package/lib/Utils/baileys-event-stream.d.ts +16 -0
- package/lib/Utils/baileys-event-stream.js +63 -0
- package/lib/Utils/business.d.ts +2 -3
- package/lib/Utils/business.js +69 -66
- package/lib/Utils/chat-utils.d.ts +23 -52
- package/lib/Utils/chat-utils.js +253 -396
- package/lib/Utils/crypto.d.ts +22 -18
- package/lib/Utils/crypto.js +90 -57
- package/lib/Utils/decode-wa-message.d.ts +8 -55
- package/lib/Utils/decode-wa-message.js +84 -203
- package/lib/Utils/event-buffer.d.ts +8 -9
- package/lib/Utils/event-buffer.js +77 -185
- package/lib/Utils/generics.d.ts +29 -28
- package/lib/Utils/generics.js +210 -180
- package/lib/Utils/history.d.ts +9 -18
- package/lib/Utils/history.js +55 -93
- package/lib/Utils/index.d.ts +17 -22
- package/lib/Utils/index.js +33 -22
- package/lib/Utils/link-preview.d.ts +5 -5
- package/lib/Utils/link-preview.js +24 -16
- package/lib/Utils/logger.d.ts +3 -11
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.d.ts +12 -8
- package/lib/Utils/lt-hash.js +46 -3
- package/lib/Utils/make-mutex.d.ts +2 -4
- package/lib/Utils/make-mutex.js +34 -24
- package/lib/Utils/messages-media.d.ts +44 -61
- package/lib/Utils/messages-media.js +482 -451
- package/lib/Utils/messages.d.ts +18 -32
- package/lib/Utils/messages.js +369 -458
- package/lib/Utils/noise-handler.d.ts +14 -13
- package/lib/Utils/noise-handler.js +99 -145
- package/lib/Utils/process-message.d.ts +12 -31
- package/lib/Utils/process-message.js +150 -459
- package/lib/Utils/signal.d.ts +5 -20
- package/lib/Utils/signal.js +72 -120
- package/lib/Utils/use-multi-file-auth-state.d.ts +2 -2
- package/lib/Utils/use-multi-file-auth-state.js +27 -29
- package/lib/Utils/validate-connection.d.ts +7 -7
- package/lib/Utils/validate-connection.js +99 -73
- package/lib/WABinary/constants.d.ts +27 -25
- package/lib/WABinary/constants.js +20 -1281
- package/lib/WABinary/decode.d.ts +5 -5
- package/lib/WABinary/decode.js +42 -52
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.js +155 -110
- package/lib/WABinary/generic-utils.d.ts +7 -8
- package/lib/WABinary/generic-utils.js +49 -48
- package/lib/WABinary/index.d.ts +5 -6
- package/lib/WABinary/index.js +21 -6
- package/lib/WABinary/jid-utils.d.ts +8 -25
- package/lib/WABinary/jid-utils.js +40 -74
- package/lib/WABinary/types.d.ts +1 -2
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.d.ts +11 -3
- package/lib/WAM/BinaryInfo.js +5 -2
- package/lib/WAM/constants.d.ts +3 -5
- package/lib/WAM/constants.js +11958 -19461
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.js +22 -17
- package/lib/WAM/index.d.ts +3 -4
- package/lib/WAM/index.js +19 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +3 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +13 -33
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +14 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -9
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +13 -9
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +3 -4
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +22 -20
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +3 -5
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +8 -13
- package/lib/WAUSync/Protocols/index.d.ts +4 -6
- package/lib/WAUSync/Protocols/index.js +20 -6
- package/lib/WAUSync/USyncQuery.d.ts +4 -6
- package/lib/WAUSync/USyncQuery.js +35 -44
- package/lib/WAUSync/USyncUser.d.ts +5 -10
- package/lib/WAUSync/USyncUser.js +5 -10
- package/lib/WAUSync/index.js +19 -4
- package/lib/index.d.ts +9 -10
- package/lib/index.js +34 -12
- package/package.json +50 -83
- package/WAProto/GenerateStatics.sh +0 -3
- package/WAProto/WAProto.proto +0 -5479
- package/WAProto/fix-imports.js +0 -85
- package/WAProto/index.d.ts +0 -14017
- package/lib/Signal/lid-mapping.d.ts +0 -23
- package/lib/Signal/lid-mapping.js +0 -277
- package/lib/Socket/Client/types.js +0 -11
- package/lib/Socket/Client/websocket.js +0 -54
- package/lib/Socket/mex.d.ts +0 -3
- package/lib/Socket/mex.js +0 -42
- package/lib/Store/keyed-db.d.ts +0 -22
- package/lib/Store/keyed-db.js +0 -108
- package/lib/Types/Bussines.d.ts +0 -25
- package/lib/Types/Bussines.js +0 -2
- package/lib/Types/Mex.d.ts +0 -141
- package/lib/Types/Mex.js +0 -37
- package/lib/Utils/browser-utils.d.ts +0 -4
- package/lib/Utils/browser-utils.js +0 -28
- package/lib/Utils/companion-reg-client-utils.d.ts +0 -17
- package/lib/Utils/companion-reg-client-utils.js +0 -35
- package/lib/Utils/identity-change-handler.d.ts +0 -44
- package/lib/Utils/identity-change-handler.js +0 -50
- package/lib/Utils/message-retry-manager.d.ts +0 -115
- package/lib/Utils/message-retry-manager.js +0 -265
- package/lib/Utils/offline-node-processor.d.ts +0 -17
- package/lib/Utils/offline-node-processor.js +0 -40
- package/lib/Utils/pre-key-manager.d.ts +0 -28
- package/lib/Utils/pre-key-manager.js +0 -106
- package/lib/Utils/reporting-utils.d.ts +0 -11
- package/lib/Utils/reporting-utils.js +0 -258
- package/lib/Utils/stanza-ack.d.ts +0 -11
- package/lib/Utils/stanza-ack.js +0 -38
- package/lib/Utils/sync-action-utils.d.ts +0 -19
- package/lib/Utils/sync-action-utils.js +0 -49
- package/lib/Utils/tc-token-utils.d.ts +0 -37
- package/lib/Utils/tc-token-utils.js +0 -163
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +0 -25
- package/lib/WAUSync/index.d.ts +0 -4
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 (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;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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;
|
|
27
|
+
const boom_1 = require("@hapi/boom");
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
29
|
+
const Crypto = __importStar(require("crypto"));
|
|
30
|
+
const events_1 = require("events");
|
|
31
|
+
const fs_1 = require("fs");
|
|
32
|
+
const os_1 = require("os");
|
|
33
|
+
const path_1 = require("path");
|
|
34
|
+
const stream_1 = require("stream");
|
|
35
|
+
const WAProto_1 = require("../../WAProto");
|
|
36
|
+
const Defaults_1 = require("../Defaults");
|
|
37
|
+
const WABinary_1 = require("../WABinary");
|
|
38
|
+
const crypto_1 = require("./crypto");
|
|
39
|
+
const generics_1 = require("./generics");
|
|
40
|
+
const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
|
|
16
41
|
const getImageProcessingLibrary = async () => {
|
|
17
|
-
|
|
18
|
-
|
|
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
|
+
]);
|
|
19
54
|
if (sharp) {
|
|
20
55
|
return { sharp };
|
|
21
56
|
}
|
|
57
|
+
const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
|
|
22
58
|
if (jimp) {
|
|
23
59
|
return { jimp };
|
|
24
60
|
}
|
|
25
|
-
throw new Boom('No image processing library available');
|
|
61
|
+
throw new boom_1.Boom('No image processing library available');
|
|
26
62
|
};
|
|
27
|
-
|
|
28
|
-
const hkdfInfo = MEDIA_HKDF_KEY_MAPPING[type];
|
|
63
|
+
const hkdfInfoKey = (type) => {
|
|
64
|
+
const hkdfInfo = Defaults_1.MEDIA_HKDF_KEY_MAPPING[type];
|
|
29
65
|
return `WhatsApp ${hkdfInfo} Keys`;
|
|
30
66
|
};
|
|
31
|
-
|
|
32
|
-
const { stream } = await getStream(media);
|
|
33
|
-
logger?.debug('got stream for raw upload');
|
|
34
|
-
const hasher = Crypto.createHash('sha256');
|
|
35
|
-
const filePath = join(tmpdir(), mediaType + generateMessageIDV2());
|
|
36
|
-
const fileWriteStream = createWriteStream(filePath);
|
|
37
|
-
let fileLength = 0;
|
|
38
|
-
try {
|
|
39
|
-
for await (const data of stream) {
|
|
40
|
-
fileLength += data.length;
|
|
41
|
-
hasher.update(data);
|
|
42
|
-
if (!fileWriteStream.write(data)) {
|
|
43
|
-
await once(fileWriteStream, 'drain');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
fileWriteStream.end();
|
|
47
|
-
await once(fileWriteStream, 'finish');
|
|
48
|
-
stream.destroy();
|
|
49
|
-
const fileSha256 = hasher.digest();
|
|
50
|
-
logger?.debug('hashed data for raw upload');
|
|
51
|
-
return {
|
|
52
|
-
filePath: filePath,
|
|
53
|
-
fileSha256,
|
|
54
|
-
fileLength
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
fileWriteStream.destroy();
|
|
59
|
-
stream.destroy();
|
|
60
|
-
try {
|
|
61
|
-
await fs.unlink(filePath);
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
//
|
|
65
|
-
}
|
|
66
|
-
throw error;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
67
|
+
exports.hkdfInfoKey = hkdfInfoKey;
|
|
69
68
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
70
|
-
|
|
69
|
+
function getMediaKeys(buffer, mediaType) {
|
|
71
70
|
if (!buffer) {
|
|
72
|
-
throw new Boom('Cannot derive from empty media key');
|
|
71
|
+
throw new boom_1.Boom('Cannot derive from empty media key');
|
|
73
72
|
}
|
|
74
73
|
if (typeof buffer === 'string') {
|
|
75
74
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
76
75
|
}
|
|
77
76
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
78
|
-
const expandedMediaKey = hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) });
|
|
77
|
+
const expandedMediaKey = (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
|
|
79
78
|
return {
|
|
80
79
|
iv: expandedMediaKey.slice(0, 16),
|
|
81
80
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
82
|
-
macKey: expandedMediaKey.slice(48, 80)
|
|
81
|
+
macKey: expandedMediaKey.slice(48, 80),
|
|
83
82
|
};
|
|
84
83
|
}
|
|
84
|
+
exports.getMediaKeys = getMediaKeys;
|
|
85
85
|
/** Extracts video thumb using FFMPEG */
|
|
86
86
|
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
|
|
87
87
|
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
|
|
88
|
-
exec(cmd, err => {
|
|
88
|
+
(0, child_process_1.exec)(cmd, (err) => {
|
|
89
89
|
if (err) {
|
|
90
90
|
reject(err);
|
|
91
91
|
}
|
|
@@ -94,151 +94,240 @@ const extractVideoThumb = async (path, destPath, time, size) => new Promise((res
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
bufferOrFilePath = await toBuffer(bufferOrFilePath);
|
|
97
|
+
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
98
|
+
var _a, _b;
|
|
99
|
+
if (bufferOrFilePath instanceof stream_1.Readable) {
|
|
100
|
+
bufferOrFilePath = await (0, exports.toBuffer)(bufferOrFilePath);
|
|
102
101
|
}
|
|
103
102
|
const lib = await getImageProcessingLibrary();
|
|
104
|
-
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') {
|
|
105
104
|
const img = lib.sharp.default(bufferOrFilePath);
|
|
106
105
|
const dimensions = await img.metadata();
|
|
107
|
-
const buffer = await img
|
|
106
|
+
const buffer = await img
|
|
107
|
+
.resize(width)
|
|
108
|
+
.jpeg({ quality: 50 })
|
|
109
|
+
.toBuffer();
|
|
108
110
|
return {
|
|
109
111
|
buffer,
|
|
110
112
|
original: {
|
|
111
113
|
width: dimensions.width,
|
|
112
|
-
height: dimensions.height
|
|
113
|
-
}
|
|
114
|
+
height: dimensions.height,
|
|
115
|
+
},
|
|
114
116
|
};
|
|
115
117
|
}
|
|
116
|
-
else if ('jimp' in lib && typeof lib.jimp
|
|
117
|
-
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);
|
|
118
121
|
const dimensions = {
|
|
119
|
-
width: jimp.
|
|
120
|
-
height: jimp.
|
|
122
|
+
width: jimp.getWidth(),
|
|
123
|
+
height: jimp.getHeight()
|
|
121
124
|
};
|
|
122
125
|
const buffer = await jimp
|
|
123
|
-
.
|
|
124
|
-
.
|
|
126
|
+
.quality(50)
|
|
127
|
+
.resize(width, AUTO, RESIZE_BILINEAR)
|
|
128
|
+
.getBufferAsync(MIME_JPEG);
|
|
125
129
|
return {
|
|
126
130
|
buffer,
|
|
127
131
|
original: dimensions
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
else {
|
|
131
|
-
throw new Boom('No image processing library available');
|
|
135
|
+
throw new boom_1.Boom('No image processing library available');
|
|
132
136
|
}
|
|
133
137
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
exports.extractImageThumb = extractImageThumb;
|
|
139
|
+
const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
|
|
140
|
+
.replace(/\+/g, '-')
|
|
141
|
+
.replace(/\//g, '_')
|
|
142
|
+
.replace(/\=+$/, '')));
|
|
143
|
+
exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
|
|
144
|
+
const generateProfilePicture = async (mediaUpload) => {
|
|
145
|
+
var _a, _b;
|
|
146
|
+
let bufferOrFilePath;
|
|
138
147
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
139
|
-
|
|
148
|
+
bufferOrFilePath = mediaUpload;
|
|
149
|
+
}
|
|
150
|
+
else if ('url' in mediaUpload) {
|
|
151
|
+
bufferOrFilePath = mediaUpload.url.toString();
|
|
140
152
|
}
|
|
141
153
|
else {
|
|
142
|
-
|
|
143
|
-
const { stream } = await getStream(mediaUpload);
|
|
144
|
-
// Convert the resulting stream to a buffer
|
|
145
|
-
buffer = await toBuffer(stream);
|
|
154
|
+
bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
|
|
146
155
|
}
|
|
147
156
|
const lib = await getImageProcessingLibrary();
|
|
148
157
|
let img;
|
|
149
|
-
if ('sharp' in lib && typeof lib.sharp
|
|
150
|
-
img = lib.sharp
|
|
151
|
-
.
|
|
152
|
-
.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)
|
|
153
161
|
.jpeg({
|
|
154
|
-
quality: 50
|
|
162
|
+
quality: 50,
|
|
155
163
|
})
|
|
156
164
|
.toBuffer();
|
|
157
165
|
}
|
|
158
|
-
else if ('jimp' in lib && typeof lib.jimp
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
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);
|
|
163
175
|
}
|
|
164
176
|
else {
|
|
165
|
-
throw new Boom('No image processing library available');
|
|
177
|
+
throw new boom_1.Boom('No image processing library available');
|
|
166
178
|
}
|
|
167
179
|
return {
|
|
168
|
-
img: await img
|
|
180
|
+
img: await img,
|
|
169
181
|
};
|
|
170
182
|
};
|
|
183
|
+
exports.generateProfilePicture = generateProfilePicture;
|
|
171
184
|
/** gets the SHA256 of the given media message */
|
|
172
|
-
|
|
185
|
+
const mediaMessageSHA256B64 = (message) => {
|
|
173
186
|
const media = Object.values(message)[0];
|
|
174
|
-
return media
|
|
187
|
+
return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
|
|
175
188
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
|
|
190
|
+
async function getAudioDuration(buffer) {
|
|
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;
|
|
190
227
|
}
|
|
191
|
-
return metadata.format.duration;
|
|
192
228
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
*/
|
|
196
|
-
export async function getAudioWaveform(buffer, logger) {
|
|
229
|
+
exports.getAudioDuration = getAudioDuration;
|
|
230
|
+
async function getAudioWaveform(buffer, logger) {
|
|
197
231
|
try {
|
|
198
|
-
|
|
199
|
-
const
|
|
232
|
+
const { PassThrough } = require('stream');
|
|
233
|
+
const ff = require('fluent-ffmpeg');
|
|
234
|
+
|
|
200
235
|
let audioData;
|
|
201
236
|
if (Buffer.isBuffer(buffer)) {
|
|
202
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);
|
|
203
243
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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);
|
|
230
281
|
}
|
|
231
|
-
|
|
232
|
-
|
|
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;
|
|
233
320
|
}
|
|
234
321
|
}
|
|
235
|
-
|
|
236
|
-
|
|
322
|
+
exports.convertToOpusBuffer = convertToOpusBuffer;
|
|
323
|
+
const toReadable = (buffer) => {
|
|
324
|
+
const readable = new stream_1.Readable({ read: () => { } });
|
|
237
325
|
readable.push(buffer);
|
|
238
326
|
readable.push(null);
|
|
239
327
|
return readable;
|
|
240
328
|
};
|
|
241
|
-
|
|
329
|
+
exports.toReadable = toReadable;
|
|
330
|
+
const toBuffer = async (stream) => {
|
|
242
331
|
const chunks = [];
|
|
243
332
|
for await (const chunk of stream) {
|
|
244
333
|
chunks.push(chunk);
|
|
@@ -246,47 +335,45 @@ export const toBuffer = async (stream) => {
|
|
|
246
335
|
stream.destroy();
|
|
247
336
|
return Buffer.concat(chunks);
|
|
248
337
|
};
|
|
249
|
-
|
|
338
|
+
exports.toBuffer = toBuffer;
|
|
339
|
+
const getStream = async (item, opts) => {
|
|
250
340
|
if (Buffer.isBuffer(item)) {
|
|
251
|
-
return { stream: toReadable(item), type: 'buffer' };
|
|
341
|
+
return { stream: (0, exports.toReadable)(item), type: 'buffer' };
|
|
252
342
|
}
|
|
253
343
|
if ('stream' in item) {
|
|
254
344
|
return { stream: item.stream, type: 'readable' };
|
|
255
345
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const buffer = Buffer.from(urlStr.split(',')[1], 'base64');
|
|
259
|
-
return { stream: toReadable(buffer), type: 'buffer' };
|
|
260
|
-
}
|
|
261
|
-
if (urlStr.startsWith('http://') || urlStr.startsWith('https://')) {
|
|
262
|
-
return { stream: await getHttpStream(item.url, opts), type: 'remote' };
|
|
346
|
+
if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
|
|
347
|
+
return { stream: await (0, exports.getHttpStream)(item.url, opts), type: 'remote' };
|
|
263
348
|
}
|
|
264
|
-
return { stream: createReadStream(item.url), type: 'file' };
|
|
349
|
+
return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
|
|
265
350
|
};
|
|
351
|
+
exports.getStream = getStream;
|
|
266
352
|
/** generates a thumbnail for a given media, if required */
|
|
267
|
-
|
|
353
|
+
async function generateThumbnail(file, mediaType, options) {
|
|
354
|
+
var _a;
|
|
268
355
|
let thumbnail;
|
|
269
356
|
let originalImageDimensions;
|
|
270
357
|
if (mediaType === 'image') {
|
|
271
|
-
const { buffer, original } = await extractImageThumb(file);
|
|
358
|
+
const { buffer, original } = await (0, exports.extractImageThumb)(file);
|
|
272
359
|
thumbnail = buffer.toString('base64');
|
|
273
360
|
if (original.width && original.height) {
|
|
274
361
|
originalImageDimensions = {
|
|
275
362
|
width: original.width,
|
|
276
|
-
height: original.height
|
|
363
|
+
height: original.height,
|
|
277
364
|
};
|
|
278
365
|
}
|
|
279
366
|
}
|
|
280
367
|
else if (mediaType === 'video') {
|
|
281
|
-
const imgFilename = join(getTmpFilesDirectory(),
|
|
368
|
+
const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
|
|
282
369
|
try {
|
|
283
370
|
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
284
|
-
const buff = await
|
|
371
|
+
const buff = await fs_1.promises.readFile(imgFilename);
|
|
285
372
|
thumbnail = buff.toString('base64');
|
|
286
|
-
await
|
|
373
|
+
await fs_1.promises.unlink(imgFilename);
|
|
287
374
|
}
|
|
288
375
|
catch (err) {
|
|
289
|
-
options.logger
|
|
376
|
+
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
|
|
290
377
|
}
|
|
291
378
|
}
|
|
292
379
|
return {
|
|
@@ -294,141 +381,180 @@ export async function generateThumbnail(file, mediaType, options) {
|
|
|
294
381
|
originalImageDimensions
|
|
295
382
|
};
|
|
296
383
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
384
|
+
exports.generateThumbnail = generateThumbnail;
|
|
385
|
+
const getHttpStream = async (url, options = {}) => {
|
|
386
|
+
const { default: axios } = await import('axios');
|
|
387
|
+
const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
|
|
388
|
+
return fetched.data;
|
|
389
|
+
};
|
|
390
|
+
exports.getHttpStream = getHttpStream;
|
|
391
|
+
const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
392
|
+
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
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
|
+
};
|
|
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;
|
|
305
432
|
}
|
|
306
|
-
// @ts-ignore Node18+ Readable.fromWeb exists
|
|
307
|
-
return response.body instanceof Readable ? response.body : Readable.fromWeb(response.body);
|
|
308
433
|
};
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
+
}
|
|
321
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
|
+
|
|
322
466
|
let fileLength = 0;
|
|
323
467
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
sha256Enc.update(buff);
|
|
329
|
-
hmac.update(buff);
|
|
330
|
-
// Handle backpressure: if write returns false, wait for drain
|
|
331
|
-
if (!encFileWriteStream.write(buff)) {
|
|
332
|
-
await once(encFileWriteStream, 'drain');
|
|
333
|
-
}
|
|
334
|
-
};
|
|
468
|
+
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
469
|
+
let sha256Plain = Crypto.createHash('sha256');
|
|
470
|
+
let sha256Enc = Crypto.createHash('sha256');
|
|
471
|
+
|
|
335
472
|
try {
|
|
336
|
-
for await (const data of
|
|
473
|
+
for await (const data of finalStream) {
|
|
337
474
|
fileLength += data.length;
|
|
338
|
-
if (type === 'remote'
|
|
339
|
-
opts
|
|
340
|
-
fileLength + data.length > opts.maxContentLength) {
|
|
341
|
-
throw new Boom(`content length exceeded when encrypting "${type}"`, {
|
|
475
|
+
if (type === 'remote'
|
|
476
|
+
&& (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
|
|
477
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
478
|
+
throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
|
|
342
479
|
data: { media, type }
|
|
343
480
|
});
|
|
344
481
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
482
|
+
|
|
483
|
+
sha256Plain = sha256Plain.update(data);
|
|
484
|
+
if (writeStream) {
|
|
485
|
+
if (!writeStream.write(data)) {
|
|
486
|
+
await (0, events_1.once)(writeStream, 'drain');
|
|
348
487
|
}
|
|
349
488
|
}
|
|
350
|
-
|
|
351
|
-
await onChunk(aes.update(data));
|
|
489
|
+
onChunk(aes.update(data));
|
|
352
490
|
}
|
|
353
|
-
|
|
491
|
+
|
|
492
|
+
onChunk(aes.final());
|
|
354
493
|
const mac = hmac.digest().slice(0, 10);
|
|
355
|
-
sha256Enc.update(mac);
|
|
494
|
+
sha256Enc = sha256Enc.update(mac);
|
|
356
495
|
const fileSha256 = sha256Plain.digest();
|
|
357
496
|
const fileEncSha256 = sha256Enc.digest();
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
// Wait for write streams to fully flush to disk
|
|
365
|
-
// This helps reduce memory pressure by allowing OS to release buffers
|
|
366
|
-
await encFinishPromise;
|
|
367
|
-
await originalFinishPromise;
|
|
368
|
-
logger?.debug('encrypted data successfully');
|
|
497
|
+
|
|
498
|
+
encWriteStream.push(mac);
|
|
499
|
+
encWriteStream.push(null);
|
|
500
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
|
|
501
|
+
finalStream.destroy();
|
|
502
|
+
|
|
369
503
|
return {
|
|
370
504
|
mediaKey,
|
|
371
|
-
|
|
372
|
-
|
|
505
|
+
encWriteStream,
|
|
506
|
+
bodyPath,
|
|
373
507
|
mac,
|
|
374
508
|
fileEncSha256,
|
|
375
509
|
fileSha256,
|
|
376
|
-
fileLength
|
|
510
|
+
fileLength,
|
|
511
|
+
didSaveToTmpPath
|
|
377
512
|
};
|
|
378
513
|
}
|
|
379
514
|
catch (error) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
originalFileStream?.destroy?.();
|
|
515
|
+
encWriteStream.destroy();
|
|
516
|
+
writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
|
|
383
517
|
aes.destroy();
|
|
384
518
|
hmac.destroy();
|
|
385
519
|
sha256Plain.destroy();
|
|
386
520
|
sha256Enc.destroy();
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
await
|
|
521
|
+
finalStream.destroy();
|
|
522
|
+
|
|
523
|
+
if (didSaveToTmpPath) {
|
|
524
|
+
try {
|
|
525
|
+
await fs_1.promises.unlink(bodyPath);
|
|
526
|
+
}
|
|
527
|
+
catch (err) {
|
|
392
528
|
}
|
|
393
|
-
}
|
|
394
|
-
catch (err) {
|
|
395
|
-
logger?.error({ err }, 'failed deleting tmp files');
|
|
396
529
|
}
|
|
397
530
|
throw error;
|
|
398
531
|
}
|
|
532
|
+
|
|
533
|
+
function onChunk(buff) {
|
|
534
|
+
sha256Enc = sha256Enc.update(buff);
|
|
535
|
+
hmac = hmac.update(buff);
|
|
536
|
+
encWriteStream.push(buff);
|
|
537
|
+
}
|
|
399
538
|
};
|
|
400
|
-
|
|
539
|
+
exports.encryptedStream = encryptedStream;
|
|
540
|
+
const DEF_HOST = 'mmg.whatsapp.net';
|
|
401
541
|
const AES_CHUNK_SIZE = 16;
|
|
402
542
|
const toSmallestChunkSize = (num) => {
|
|
403
543
|
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE;
|
|
404
544
|
};
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
catch {
|
|
413
|
-
return undefined;
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
export const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
417
|
-
// Fallback host: explicit opt > host parsed from `url` > DEF_MEDIA_HOST.
|
|
418
|
-
// Lets us honor a non-default host carried by the proto without forcing callers to thread it through.
|
|
419
|
-
const fallbackHost = opts.host ?? extractHost(url);
|
|
420
|
-
const downloadUrl = directPath ? getUrlFromDirectPath(directPath, fallbackHost) : url;
|
|
421
|
-
if (!downloadUrl) {
|
|
422
|
-
throw new Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
423
|
-
}
|
|
424
|
-
const keys = await getMediaKeys(mediaKey, type);
|
|
425
|
-
return downloadEncryptedContent(downloadUrl, keys, opts);
|
|
545
|
+
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
546
|
+
exports.getUrlFromDirectPath = getUrlFromDirectPath;
|
|
547
|
+
const downloadContentFromMessage = ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
548
|
+
const downloadUrl = url || (0, exports.getUrlFromDirectPath)(directPath);
|
|
549
|
+
const keys = getMediaKeys(mediaKey, type);
|
|
550
|
+
return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
|
|
426
551
|
};
|
|
552
|
+
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
427
553
|
/**
|
|
428
554
|
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
429
555
|
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
430
556
|
* */
|
|
431
|
-
|
|
557
|
+
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
432
558
|
let bytesFetched = 0;
|
|
433
559
|
let startChunk = 0;
|
|
434
560
|
let firstBlockIsIV = false;
|
|
@@ -442,14 +568,9 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
442
568
|
}
|
|
443
569
|
}
|
|
444
570
|
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
|
|
445
|
-
const headersInit = options?.headers ? options.headers : undefined;
|
|
446
571
|
const headers = {
|
|
447
|
-
...(
|
|
448
|
-
|
|
449
|
-
? Object.fromEntries(headersInit)
|
|
450
|
-
: headersInit
|
|
451
|
-
: {}),
|
|
452
|
-
Origin: DEFAULT_ORIGIN
|
|
572
|
+
...(options === null || options === void 0 ? void 0 : options.headers) || {},
|
|
573
|
+
Origin: Defaults_1.DEFAULT_ORIGIN,
|
|
453
574
|
};
|
|
454
575
|
if (startChunk || endChunk) {
|
|
455
576
|
headers.Range = `bytes=${startChunk}-`;
|
|
@@ -458,9 +579,11 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
458
579
|
}
|
|
459
580
|
}
|
|
460
581
|
// download the message
|
|
461
|
-
const fetched = await getHttpStream(downloadUrl, {
|
|
462
|
-
...
|
|
463
|
-
headers
|
|
582
|
+
const fetched = await (0, exports.getHttpStream)(downloadUrl, {
|
|
583
|
+
...options || {},
|
|
584
|
+
headers,
|
|
585
|
+
maxBodyLength: Infinity,
|
|
586
|
+
maxContentLength: Infinity,
|
|
464
587
|
});
|
|
465
588
|
let remainingBytes = Buffer.from([]);
|
|
466
589
|
let aes;
|
|
@@ -475,9 +598,9 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
475
598
|
push(bytes);
|
|
476
599
|
}
|
|
477
600
|
};
|
|
478
|
-
const output = new Transform({
|
|
601
|
+
const output = new stream_1.Transform({
|
|
479
602
|
transform(chunk, _, callback) {
|
|
480
|
-
let data =
|
|
603
|
+
let data = Buffer.concat([remainingBytes, chunk]);
|
|
481
604
|
const decryptLength = toSmallestChunkSize(data.length);
|
|
482
605
|
remainingBytes = data.slice(decryptLength);
|
|
483
606
|
data = data.slice(0, decryptLength);
|
|
@@ -510,15 +633,18 @@ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, {
|
|
|
510
633
|
catch (error) {
|
|
511
634
|
callback(error);
|
|
512
635
|
}
|
|
513
|
-
}
|
|
636
|
+
},
|
|
514
637
|
});
|
|
515
638
|
return fetched.pipe(output, { end: true });
|
|
516
639
|
};
|
|
517
|
-
|
|
518
|
-
|
|
640
|
+
exports.downloadEncryptedContent = downloadEncryptedContent;
|
|
641
|
+
function extensionForMediaMessage(message) {
|
|
642
|
+
const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
|
|
519
643
|
const type = Object.keys(message)[0];
|
|
520
644
|
let extension;
|
|
521
|
-
if (type === 'locationMessage' ||
|
|
645
|
+
if (type === 'locationMessage' ||
|
|
646
|
+
type === 'liveLocationMessage' ||
|
|
647
|
+
type === 'productMessage') {
|
|
522
648
|
extension = '.jpeg';
|
|
523
649
|
}
|
|
524
650
|
else {
|
|
@@ -527,158 +653,55 @@ export function extensionForMediaMessage(message) {
|
|
|
527
653
|
}
|
|
528
654
|
return extension;
|
|
529
655
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
};
|
|
536
|
-
export const uploadWithNodeHttp = async ({ url, filePath, headers, timeoutMs, agent }, redirectCount = 0) => {
|
|
537
|
-
if (redirectCount > 5) {
|
|
538
|
-
throw new Error('Too many redirects');
|
|
539
|
-
}
|
|
540
|
-
const parsedUrl = new URL(url);
|
|
541
|
-
const httpModule = parsedUrl.protocol === 'https:' ? await import('https') : await import('http');
|
|
542
|
-
// Get file size for Content-Length header (required for Node.js streaming)
|
|
543
|
-
const fileStats = await fs.stat(filePath);
|
|
544
|
-
const fileSize = fileStats.size;
|
|
545
|
-
return new Promise((resolve, reject) => {
|
|
546
|
-
const req = httpModule.request({
|
|
547
|
-
hostname: parsedUrl.hostname,
|
|
548
|
-
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
|
|
549
|
-
path: parsedUrl.pathname + parsedUrl.search,
|
|
550
|
-
method: 'POST',
|
|
551
|
-
headers: {
|
|
552
|
-
...headers,
|
|
553
|
-
'Content-Length': fileSize
|
|
554
|
-
},
|
|
555
|
-
agent,
|
|
556
|
-
timeout: timeoutMs
|
|
557
|
-
}, res => {
|
|
558
|
-
// Handle redirects (3xx)
|
|
559
|
-
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
560
|
-
res.resume(); // Consume response to free resources
|
|
561
|
-
const newUrl = new URL(res.headers.location, url).toString();
|
|
562
|
-
resolve(uploadWithNodeHttp({
|
|
563
|
-
url: newUrl,
|
|
564
|
-
filePath,
|
|
565
|
-
headers,
|
|
566
|
-
timeoutMs,
|
|
567
|
-
agent
|
|
568
|
-
}, redirectCount + 1));
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
let body = '';
|
|
572
|
-
res.on('data', chunk => (body += chunk));
|
|
573
|
-
res.on('end', () => {
|
|
574
|
-
try {
|
|
575
|
-
resolve(JSON.parse(body));
|
|
576
|
-
}
|
|
577
|
-
catch {
|
|
578
|
-
resolve(undefined);
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
});
|
|
582
|
-
req.on('error', reject);
|
|
583
|
-
req.on('timeout', () => {
|
|
584
|
-
req.destroy();
|
|
585
|
-
reject(new Error('Upload timeout'));
|
|
586
|
-
});
|
|
587
|
-
const stream = createReadStream(filePath);
|
|
588
|
-
stream.pipe(req);
|
|
589
|
-
stream.on('error', err => {
|
|
590
|
-
req.destroy();
|
|
591
|
-
reject(err);
|
|
592
|
-
});
|
|
593
|
-
});
|
|
594
|
-
};
|
|
595
|
-
const uploadWithFetch = async ({ url, filePath, headers, timeoutMs, agent }) => {
|
|
596
|
-
// Convert Node.js Readable to Web ReadableStream
|
|
597
|
-
const nodeStream = createReadStream(filePath);
|
|
598
|
-
const webStream = Readable.toWeb(nodeStream);
|
|
599
|
-
// Native fetch only accepts Undici-style dispatchers, not generic https Agents.
|
|
600
|
-
const dispatcher = typeof agent?.dispatch === 'function' ? agent : undefined;
|
|
601
|
-
const response = await fetch(url, {
|
|
602
|
-
...(dispatcher ? { dispatcher } : {}),
|
|
603
|
-
method: 'POST',
|
|
604
|
-
body: webStream,
|
|
605
|
-
headers,
|
|
606
|
-
duplex: 'half',
|
|
607
|
-
signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
|
|
608
|
-
});
|
|
609
|
-
try {
|
|
610
|
-
return (await response.json());
|
|
611
|
-
}
|
|
612
|
-
catch {
|
|
613
|
-
return undefined;
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
/**
|
|
617
|
-
* Uploads media to WhatsApp servers.
|
|
618
|
-
*
|
|
619
|
-
* ## Why we have two upload implementations:
|
|
620
|
-
*
|
|
621
|
-
* Node.js's native `fetch` (powered by undici) has a known bug where it buffers
|
|
622
|
-
* the entire request body in memory before sending, even when using streams.
|
|
623
|
-
* This causes memory issues with large files (e.g., 1GB file = 1GB+ memory usage).
|
|
624
|
-
* See: https://github.com/nodejs/undici/issues/4058
|
|
625
|
-
*
|
|
626
|
-
* Other runtimes (Bun, Deno, browsers) correctly stream the request body without
|
|
627
|
-
* buffering, so we can use the web-standard Fetch API there.
|
|
628
|
-
*
|
|
629
|
-
* ## Future considerations:
|
|
630
|
-
* Once the undici bug is fixed, we can simplify this to use only the Fetch API
|
|
631
|
-
* across all runtimes. Monitor the GitHub issue for updates.
|
|
632
|
-
*/
|
|
633
|
-
const uploadMedia = async (params, logger) => {
|
|
634
|
-
if (isNodeRuntime()) {
|
|
635
|
-
logger?.debug('Using Node.js https module for upload (avoids undici buffering bug)');
|
|
636
|
-
return uploadWithNodeHttp(params);
|
|
637
|
-
}
|
|
638
|
-
else {
|
|
639
|
-
logger?.debug('Using web-standard Fetch API for upload');
|
|
640
|
-
return uploadWithFetch(params);
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
644
|
-
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
|
656
|
+
exports.extensionForMediaMessage = extensionForMediaMessage;
|
|
657
|
+
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
658
|
+
return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
659
|
+
var _a, _b;
|
|
660
|
+
const { default: axios } = await import('axios');
|
|
645
661
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
646
662
|
let uploadInfo = await refreshMediaConn(false);
|
|
647
663
|
let urls;
|
|
648
664
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
'
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
for (const { hostname } of 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);
|
|
672
|
+
fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
|
|
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) {
|
|
663
678
|
logger.debug(`uploading to "${hostname}"`);
|
|
664
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
665
|
-
const url = `https://${hostname}${
|
|
679
|
+
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
680
|
+
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
666
681
|
let result;
|
|
667
682
|
try {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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, {
|
|
687
|
+
...options,
|
|
688
|
+
headers: {
|
|
689
|
+
...options.headers || {},
|
|
690
|
+
'Content-Type': 'application/octet-stream',
|
|
691
|
+
'Origin': Defaults_1.DEFAULT_ORIGIN
|
|
692
|
+
},
|
|
693
|
+
httpsAgent: fetchAgent,
|
|
694
|
+
timeout: timeoutMs,
|
|
695
|
+
responseType: 'json',
|
|
696
|
+
maxBodyLength: Infinity,
|
|
697
|
+
maxContentLength: Infinity,
|
|
698
|
+
});
|
|
699
|
+
result = body.data;
|
|
700
|
+
if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
|
|
676
701
|
urls = {
|
|
677
702
|
mediaUrl: result.url,
|
|
678
703
|
directPath: result.direct_path,
|
|
679
|
-
|
|
680
|
-
fbid: result.fbid,
|
|
681
|
-
ts: result.ts
|
|
704
|
+
handle: result.handle
|
|
682
705
|
};
|
|
683
706
|
break;
|
|
684
707
|
}
|
|
@@ -688,33 +711,37 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, opt
|
|
|
688
711
|
}
|
|
689
712
|
}
|
|
690
713
|
catch (error) {
|
|
691
|
-
|
|
692
|
-
|
|
714
|
+
if (axios.isAxiosError(error)) {
|
|
715
|
+
result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
716
|
+
}
|
|
717
|
+
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
718
|
+
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
|
|
693
719
|
}
|
|
694
720
|
}
|
|
695
721
|
if (!urls) {
|
|
696
|
-
throw new Boom('Media upload failed on all hosts', { statusCode: 500 });
|
|
722
|
+
throw new boom_1.Boom('Media upload failed on all hosts', { statusCode: 500 });
|
|
697
723
|
}
|
|
698
724
|
return urls;
|
|
699
725
|
};
|
|
700
726
|
};
|
|
727
|
+
exports.getWAUploadToServer = getWAUploadToServer;
|
|
701
728
|
const getMediaRetryKey = (mediaKey) => {
|
|
702
|
-
return hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
729
|
+
return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
703
730
|
};
|
|
704
731
|
/**
|
|
705
732
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
706
733
|
*/
|
|
707
|
-
|
|
734
|
+
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
708
735
|
const recp = { stanzaId: key.id };
|
|
709
|
-
const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish();
|
|
736
|
+
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
|
|
710
737
|
const iv = Crypto.randomBytes(12);
|
|
711
738
|
const retryKey = getMediaRetryKey(mediaKey);
|
|
712
|
-
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
739
|
+
const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
713
740
|
const req = {
|
|
714
741
|
tag: 'receipt',
|
|
715
742
|
attrs: {
|
|
716
743
|
id: key.id,
|
|
717
|
-
to: jidNormalizedUser(meId),
|
|
744
|
+
to: (0, WABinary_1.jidNormalizedUser)(meId),
|
|
718
745
|
type: 'server-error'
|
|
719
746
|
},
|
|
720
747
|
content: [
|
|
@@ -733,7 +760,7 @@ export const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
|
733
760
|
tag: 'rmr',
|
|
734
761
|
attrs: {
|
|
735
762
|
jid: key.remoteJid,
|
|
736
|
-
from_me: (!!key.fromMe).toString(),
|
|
763
|
+
'from_me': (!!key.fromMe).toString(),
|
|
737
764
|
// @ts-ignore
|
|
738
765
|
participant: key.participant || undefined
|
|
739
766
|
}
|
|
@@ -742,8 +769,9 @@ export const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
|
742
769
|
};
|
|
743
770
|
return req;
|
|
744
771
|
};
|
|
745
|
-
|
|
746
|
-
|
|
772
|
+
exports.encryptMediaRetryRequest = encryptMediaRetryRequest;
|
|
773
|
+
const decodeMediaRetryNode = (node) => {
|
|
774
|
+
const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
|
|
747
775
|
const event = {
|
|
748
776
|
key: {
|
|
749
777
|
id: node.attrs.id,
|
|
@@ -752,37 +780,40 @@ export const decodeMediaRetryNode = (node) => {
|
|
|
752
780
|
participant: rmrNode.attrs.participant
|
|
753
781
|
}
|
|
754
782
|
};
|
|
755
|
-
const errorNode = getBinaryNodeChild(node, 'error');
|
|
783
|
+
const errorNode = (0, WABinary_1.getBinaryNodeChild)(node, 'error');
|
|
756
784
|
if (errorNode) {
|
|
757
785
|
const errorCode = +errorNode.attrs.code;
|
|
758
|
-
event.error = new Boom(`Failed to re-upload media (${errorCode})`, {
|
|
759
|
-
data: errorNode.attrs,
|
|
760
|
-
statusCode: getStatusCodeForMediaRetry(errorCode)
|
|
761
|
-
});
|
|
786
|
+
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode) });
|
|
762
787
|
}
|
|
763
788
|
else {
|
|
764
|
-
const encryptedInfoNode = getBinaryNodeChild(node, 'encrypt');
|
|
765
|
-
const ciphertext = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p');
|
|
766
|
-
const iv = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv');
|
|
789
|
+
const encryptedInfoNode = (0, WABinary_1.getBinaryNodeChild)(node, 'encrypt');
|
|
790
|
+
const ciphertext = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_p');
|
|
791
|
+
const iv = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_iv');
|
|
767
792
|
if (ciphertext && iv) {
|
|
768
793
|
event.media = { ciphertext, iv };
|
|
769
794
|
}
|
|
770
795
|
else {
|
|
771
|
-
event.error = new Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
|
|
796
|
+
event.error = new boom_1.Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
|
|
772
797
|
}
|
|
773
798
|
}
|
|
774
799
|
return event;
|
|
775
800
|
};
|
|
776
|
-
|
|
801
|
+
exports.decodeMediaRetryNode = decodeMediaRetryNode;
|
|
802
|
+
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
777
803
|
const retryKey = getMediaRetryKey(mediaKey);
|
|
778
|
-
const plaintext = aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
779
|
-
return proto.MediaRetryNotification.decode(plaintext);
|
|
804
|
+
const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
805
|
+
return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
|
|
780
806
|
};
|
|
781
|
-
|
|
807
|
+
exports.decryptMediaRetryData = decryptMediaRetryData;
|
|
808
|
+
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
|
|
809
|
+
exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
|
|
782
810
|
const MEDIA_RETRY_STATUS_MAP = {
|
|
783
|
-
[proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
784
|
-
[proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
785
|
-
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
786
|
-
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
|
|
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,
|
|
787
815
|
};
|
|
788
|
-
|
|
816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
817
|
+
function __importStar(arg0) {
|
|
818
|
+
throw new Error('Function not implemented.');
|
|
819
|
+
}
|