@blckrose/baileys 1.0.0 → 1.1.1
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/lib/Defaults/index.js +5 -0
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/libsignal.js +19 -7
- package/lib/Socket/community.js +361 -0
- package/lib/Socket/groups.js +76 -5
- package/lib/Socket/messages-recv.js +11 -0
- package/lib/Socket/messages-send.js +284 -16
- package/lib/Socket/newsletter.js +23 -0
- package/lib/Socket/socket.js +3 -1
- package/lib/Socket/usync.js +76 -0
- package/lib/Store/index.js +4 -0
- package/lib/Store/make-cache-manager-store.js +77 -0
- package/lib/Store/make-in-memory-store.js +400 -0
- package/lib/Store/make-ordered-dictionary.js +78 -0
- package/lib/Store/object-repository.js +23 -0
- package/lib/Types/MexUpdates.js +9 -0
- package/lib/Types/Newsletter.js +10 -0
- package/lib/Types/index.js +1 -0
- package/lib/Utils/audioToBuffer.js +31 -0
- package/lib/Utils/baileys-event-stream.js +54 -0
- package/lib/Utils/browser-utils.js +33 -20
- package/lib/Utils/generics.js +27 -0
- package/lib/Utils/index.js +5 -0
- package/lib/Utils/messages-media.js +103 -4
- package/lib/Utils/messages.js +470 -13
- package/lib/Utils/streamToBuffer.js +17 -0
- package/lib/Utils/use-mongo-file-auth-state.js +77 -0
- package/lib/Utils/use-single-file-auth-state.js +74 -0
- package/lib/WABinary/generic-utils.js +15 -0
- package/lib/WABinary/index.js +1 -0
- package/lib/WABinary/jid-utils.js +2 -0
- package/lib/WAUSync/Protocols/index.js +2 -1
- package/lib/index.js +20 -0
- package/package.json +3 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
import { createReadStream } from 'fs';
|
|
3
|
+
import { writeFile } from 'fs/promises';
|
|
4
|
+
import { createInterface } from 'readline';
|
|
5
|
+
import { delay } from './generics.js';
|
|
6
|
+
import { makeMutex } from './make-mutex.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Captures events from a baileys event emitter & stores them in a file
|
|
10
|
+
* @param ev The event emitter to read events from
|
|
11
|
+
* @param filename File to save to
|
|
12
|
+
*/
|
|
13
|
+
export const captureEventStream = (ev, filename) => {
|
|
14
|
+
const oldEmit = ev.emit;
|
|
15
|
+
// write mutex so data is appended in order
|
|
16
|
+
const writeMutex = makeMutex();
|
|
17
|
+
// monkey patch eventemitter to capture all events
|
|
18
|
+
ev.emit = function (...args) {
|
|
19
|
+
const content = JSON.stringify({ timestamp: Date.now(), event: args[0], data: args[1] }) + '\n';
|
|
20
|
+
const result = oldEmit.apply(ev, args);
|
|
21
|
+
writeMutex.mutex(async () => {
|
|
22
|
+
await writeFile(filename, content, { flag: 'a' });
|
|
23
|
+
});
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Read event file and emit events from there
|
|
30
|
+
* @param filename filename containing event data
|
|
31
|
+
* @param delayIntervalMs delay between each event emit
|
|
32
|
+
*/
|
|
33
|
+
export const readAndEmitEventStream = (filename, delayIntervalMs = 0) => {
|
|
34
|
+
const ev = new EventEmitter();
|
|
35
|
+
const fireEvents = async () => {
|
|
36
|
+
const fileStream = createReadStream(filename);
|
|
37
|
+
const rl = createInterface({
|
|
38
|
+
input: fileStream,
|
|
39
|
+
crlfDelay: Infinity
|
|
40
|
+
});
|
|
41
|
+
for await (const line of rl) {
|
|
42
|
+
if (line) {
|
|
43
|
+
const { event, data } = JSON.parse(line);
|
|
44
|
+
ev.emit(event, data);
|
|
45
|
+
delayIntervalMs && await delay(delayIntervalMs);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
fileStream.close();
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
ev,
|
|
52
|
+
task: fireEvents()
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -1,28 +1,41 @@
|
|
|
1
|
-
import { platform
|
|
1
|
+
import { platform } from 'os';
|
|
2
2
|
import { proto } from '../../WAProto/index.js';
|
|
3
|
-
const PLATFORM_MAP = {
|
|
4
|
-
aix:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
export const PLATFORM_MAP = {
|
|
4
|
+
'aix':'AIX','darwin':'Mac OS','win32':'Windows','android':'Android',
|
|
5
|
+
'freebsd':'FreeBSD','openbsd':'OpenBSD','sunos':'Solaris','linux':'Linux',
|
|
6
|
+
'ubuntu':'Ubuntu','ios':'iOS','baileys':'Baileys','chromeos':'Chrome OS',
|
|
7
|
+
'tizen':'Tizen','watchos':'watchOS','wearos':'Wear OS','harmonyos':'HarmonyOS',
|
|
8
|
+
'kaios':'KaiOS','smarttv':'Smart TV','raspberrypi':'Raspberry Pi OS',
|
|
9
|
+
'symbian':'Symbian','blackberry':'Blackberry OS','windowsphone':'Windows Phone'
|
|
10
|
+
};
|
|
11
|
+
export const PLATFORM_VERSIONS = {
|
|
12
|
+
'ubuntu':'22.04.4','darwin':'18.5','win32':'10.0.22631','android':'14.0.0',
|
|
13
|
+
'freebsd':'13.2','openbsd':'7.3','sunos':'11','linux':'6.5','ios':'18.2',
|
|
14
|
+
'baileys':'6.5.0','chromeos':'117.0.5938.132','tizen':'6.5','watchos':'10.1',
|
|
15
|
+
'wearos':'4.1','harmonyos':'4.0.0','kaios':'3.1','smarttv':'23.3.1',
|
|
16
|
+
'raspberrypi':'11 (Bullseye)','symbian':'3','blackberry':'10.3.3','windowsphone':'8.1'
|
|
15
17
|
};
|
|
16
18
|
export const Browsers = {
|
|
17
|
-
ubuntu: browser => ['
|
|
18
|
-
macOS: browser => ['
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
ubuntu: (browser) => [PLATFORM_MAP['ubuntu'], browser, PLATFORM_VERSIONS['ubuntu']],
|
|
20
|
+
macOS: (browser) => [PLATFORM_MAP['darwin'], browser, PLATFORM_VERSIONS['darwin']],
|
|
21
|
+
windows: (browser) => [PLATFORM_MAP['win32'], browser, PLATFORM_VERSIONS['win32']],
|
|
22
|
+
linux: (browser) => [PLATFORM_MAP['linux'], browser, PLATFORM_VERSIONS['linux']],
|
|
23
|
+
solaris: (browser) => [PLATFORM_MAP['sunos'], browser, PLATFORM_VERSIONS['sunos']],
|
|
24
|
+
baileys: (browser) => [PLATFORM_MAP['baileys'], browser, PLATFORM_VERSIONS['baileys']],
|
|
25
|
+
android: (browser) => [PLATFORM_MAP['android'], browser, PLATFORM_VERSIONS['android']],
|
|
26
|
+
iOS: (browser) => [PLATFORM_MAP['ios'], browser, PLATFORM_VERSIONS['ios']],
|
|
27
|
+
kaiOS: (browser) => [PLATFORM_MAP['kaios'], browser, PLATFORM_VERSIONS['kaios']],
|
|
28
|
+
chromeOS: (browser) => [PLATFORM_MAP['chromeos'], browser, PLATFORM_VERSIONS['chromeos']],
|
|
29
|
+
appropriate: (browser) => {
|
|
30
|
+
const p = platform();
|
|
31
|
+
return [PLATFORM_MAP[p] || 'Unknown OS', browser, PLATFORM_VERSIONS[p] || 'latest'];
|
|
32
|
+
},
|
|
33
|
+
custom: (p, browser, version) => {
|
|
34
|
+
return [PLATFORM_MAP[p.toLowerCase()] || p, browser, version || PLATFORM_VERSIONS[p] || 'latest'];
|
|
35
|
+
}
|
|
23
36
|
};
|
|
24
37
|
export const getPlatformId = (browser) => {
|
|
25
38
|
const platformType = proto.DeviceProps.PlatformType[browser.toUpperCase()];
|
|
26
|
-
return platformType ? platformType.toString() : '1';
|
|
39
|
+
return platformType ? platformType.toString() : '1';
|
|
27
40
|
};
|
|
28
41
|
//# sourceMappingURL=browser-utils.js.map
|
package/lib/Utils/generics.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Boom } from '@hapi/boom';
|
|
2
2
|
import { createHash, randomBytes } from 'crypto';
|
|
3
|
+
import axios from 'axios';
|
|
3
4
|
import { proto } from '../../WAProto/index.js';
|
|
4
5
|
const baileysVersion = [2, 3000, 1033105955];
|
|
5
6
|
import { DisconnectReason } from '../Types/index.js';
|
|
@@ -381,4 +382,30 @@ export function bytesToCrockford(buffer) {
|
|
|
381
382
|
export function encodeNewsletterMessage(message) {
|
|
382
383
|
return proto.Message.encode(message).finish();
|
|
383
384
|
}
|
|
385
|
+
|
|
386
|
+
export const COMPANION_PLATFORM_MAP = {
|
|
387
|
+
'Chrome': '49', 'Edge': '50', 'Firefox': '51', 'Opera': '53', 'Safari': '54',
|
|
388
|
+
'Brave': '1.79.112', 'Vivaldi': '6.2.3105.58', 'Tor': '12.5.3',
|
|
389
|
+
'Yandex': '23.7.1', 'Falkon': '22.08.3', 'Epiphany': '44.2'
|
|
390
|
+
};
|
|
391
|
+
// Browsers, PLATFORM_MAP, PLATFORM_VERSIONS, getPlatformId moved to browser-utils.js
|
|
392
|
+
export const printQRIfNecessaryListener = (ev, logger) => {
|
|
393
|
+
ev.on('connection.update', async ({ qr }) => {
|
|
394
|
+
if (qr) {
|
|
395
|
+
const QR = await import('qrcode-terminal').then(m => m.default || m).catch(() => {
|
|
396
|
+
logger.error('QR code terminal not added as dependency');
|
|
397
|
+
});
|
|
398
|
+
QR?.generate(qr, { small: true });
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
export const toUnicodeEscape = (text) =>
|
|
403
|
+
text.split('').map(c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0')).join('');
|
|
404
|
+
export const fromUnicodeEscape = (escapedText) =>
|
|
405
|
+
escapedText.replace(/\\u[\dA-Fa-f]{4}/g, m => String.fromCharCode(parseInt(m.slice(2), 16)));
|
|
406
|
+
export const asciiEncode = (text) => text.split('').map(c => c.charCodeAt(0));
|
|
407
|
+
export const asciiDecode = (...codes) => {
|
|
408
|
+
const arr = Array.isArray(codes[0]) ? codes[0] : codes;
|
|
409
|
+
return arr.map(c => String.fromCharCode(c)).join('');
|
|
410
|
+
};
|
|
384
411
|
//# sourceMappingURL=generics.js.map
|
package/lib/Utils/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from './generics.js';
|
|
2
|
+
export * from './audioToBuffer.js';
|
|
3
|
+
export * from './streamToBuffer.js';
|
|
2
4
|
export * from './decode-wa-message.js';
|
|
3
5
|
export * from './messages.js';
|
|
4
6
|
export * from './messages-media.js';
|
|
@@ -11,6 +13,9 @@ export * from './chat-utils.js';
|
|
|
11
13
|
export * from './lt-hash.js';
|
|
12
14
|
export * from './auth-utils.js';
|
|
13
15
|
export * from './use-multi-file-auth-state.js';
|
|
16
|
+
export * from './use-single-file-auth-state.js';
|
|
17
|
+
export * from './use-mongo-file-auth-state.js';
|
|
18
|
+
export * from './baileys-event-stream.js';
|
|
14
19
|
export * from './link-preview.js';
|
|
15
20
|
export * from './event-buffer.js';
|
|
16
21
|
export * from './process-message.js';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { once } from 'events';
|
|
3
|
+
import { unlink as unlinkFs } from 'fs/promises';
|
|
1
4
|
import { Boom } from '@hapi/boom';
|
|
2
5
|
import { exec } from 'child_process';
|
|
3
6
|
import * as Crypto from 'crypto';
|
|
4
|
-
import { once } from 'events';
|
|
5
7
|
import { createReadStream, createWriteStream, promises as fs, WriteStream } from 'fs';
|
|
6
8
|
import { tmpdir } from 'os';
|
|
7
9
|
import { join } from 'path';
|
|
@@ -36,7 +38,7 @@ export const getRawMediaUploadData = async (media, mediaType, logger) => {
|
|
|
36
38
|
const fileWriteStream = createWriteStream(filePath);
|
|
37
39
|
let fileLength = 0;
|
|
38
40
|
try {
|
|
39
|
-
for await (const data of
|
|
41
|
+
for await (const data of finalStream) {
|
|
40
42
|
fileLength += data.length;
|
|
41
43
|
hasher.update(data);
|
|
42
44
|
if (!fileWriteStream.write(data)) {
|
|
@@ -306,9 +308,53 @@ export const getHttpStream = async (url, options = {}) => {
|
|
|
306
308
|
// @ts-ignore Node18+ Readable.fromWeb exists
|
|
307
309
|
return response.body instanceof Readable ? response.body : Readable.fromWeb(response.body);
|
|
308
310
|
};
|
|
309
|
-
|
|
311
|
+
|
|
312
|
+
// ── convertToOpusBuffer (ported from elaina) ─────────────────────────────────
|
|
313
|
+
const convertToOpusBuffer = (buffer, logger) => new Promise((resolve, reject) => {
|
|
314
|
+
const args = [
|
|
315
|
+
'-i', 'pipe:0',
|
|
316
|
+
'-c:a', 'libopus',
|
|
317
|
+
'-b:a', '64k',
|
|
318
|
+
'-vbr', 'on',
|
|
319
|
+
'-compression_level', '10',
|
|
320
|
+
'-frame_duration', '20',
|
|
321
|
+
'-application', 'voip',
|
|
322
|
+
'-f', 'ogg',
|
|
323
|
+
'pipe:1'
|
|
324
|
+
];
|
|
325
|
+
const ffmpeg = spawn('ffmpeg', args);
|
|
326
|
+
const chunks = [];
|
|
327
|
+
ffmpeg.stdin.write(buffer);
|
|
328
|
+
ffmpeg.stdin.end();
|
|
329
|
+
ffmpeg.stdout.on('data', chunk => chunks.push(chunk));
|
|
330
|
+
ffmpeg.stderr.on('data', () => {});
|
|
331
|
+
ffmpeg.on('close', code => {
|
|
332
|
+
if (code === 0) resolve(Buffer.concat(chunks));
|
|
333
|
+
else reject(new Error(`FFmpeg Opus conversion exited with code ${code}`));
|
|
334
|
+
});
|
|
335
|
+
ffmpeg.on('error', err => reject(err));
|
|
336
|
+
});
|
|
337
|
+
// ── End convertToOpusBuffer ───────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
export const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
310
340
|
const { stream, type } = await getStream(media, opts);
|
|
311
341
|
logger?.debug('fetched media stream');
|
|
342
|
+
let finalStream = stream;
|
|
343
|
+
let opusConverted = false;
|
|
344
|
+
// Auto-convert to Opus if PTT or forceOpus
|
|
345
|
+
if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
|
|
346
|
+
try {
|
|
347
|
+
const buf = await toBuffer(finalStream);
|
|
348
|
+
const opusBuf = await convertToOpusBuffer(buf, logger);
|
|
349
|
+
finalStream = toReadable(opusBuf);
|
|
350
|
+
opusConverted = true;
|
|
351
|
+
logger?.debug('converted audio to Opus for PTT');
|
|
352
|
+
} catch (error) {
|
|
353
|
+
logger?.error('failed to convert audio to Opus, fallback to original');
|
|
354
|
+
const { stream: newStream } = await getStream(media, opts);
|
|
355
|
+
finalStream = newStream;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
312
358
|
const mediaKey = Crypto.randomBytes(32);
|
|
313
359
|
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
|
314
360
|
const encFilePath = join(getTmpFilesDirectory(), mediaType + generateMessageIDV2() + '-enc');
|
|
@@ -373,7 +419,8 @@ export const encryptedStream = async (media, mediaType, { logger, saveOriginalFi
|
|
|
373
419
|
mac,
|
|
374
420
|
fileEncSha256,
|
|
375
421
|
fileSha256,
|
|
376
|
-
fileLength
|
|
422
|
+
fileLength,
|
|
423
|
+
opusConverted
|
|
377
424
|
};
|
|
378
425
|
}
|
|
379
426
|
catch (error) {
|
|
@@ -771,4 +818,56 @@ const MEDIA_RETRY_STATUS_MAP = {
|
|
|
771
818
|
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
772
819
|
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
|
|
773
820
|
};
|
|
821
|
+
|
|
822
|
+
export const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
|
|
823
|
+
const { stream, type } = await getStream(media, opts);
|
|
824
|
+
logger?.debug('fetched media stream');
|
|
825
|
+
let opusConverted = false;
|
|
826
|
+
let buffer = await toBuffer(stream);
|
|
827
|
+
// Auto-convert to Opus if PTT or forceOpus
|
|
828
|
+
if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
|
|
829
|
+
try {
|
|
830
|
+
const opusBuf = await convertToOpusBuffer(buffer, logger);
|
|
831
|
+
buffer = opusBuf;
|
|
832
|
+
opusConverted = true;
|
|
833
|
+
logger?.debug('converted audio to Opus for newsletter PTT');
|
|
834
|
+
} catch (e) {
|
|
835
|
+
logger?.error('failed to convert audio for newsletter PTT');
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
const encFilePath = join(tmpdir(), mediaType + generateMessageID() + '-plain');
|
|
839
|
+
const encFileWriteStream = createWriteStream(encFilePath);
|
|
840
|
+
let originalFilePath;
|
|
841
|
+
let originalFileStream;
|
|
842
|
+
if (type === 'file') {
|
|
843
|
+
originalFilePath = media.url.toString();
|
|
844
|
+
} else if (saveOriginalFileIfRequired) {
|
|
845
|
+
originalFilePath = join(tmpdir(), mediaType + generateMessageID() + '-original');
|
|
846
|
+
originalFileStream = createWriteStream(originalFilePath);
|
|
847
|
+
}
|
|
848
|
+
let fileLength = 0;
|
|
849
|
+
const hashCtx = createHashCrypto('sha256');
|
|
850
|
+
try {
|
|
851
|
+
// Use buffer (possibly opus-converted) directly
|
|
852
|
+
fileLength = buffer.length;
|
|
853
|
+
hashCtx.update(buffer);
|
|
854
|
+
encFileWriteStream.write(buffer);
|
|
855
|
+
if (originalFileStream) {
|
|
856
|
+
originalFileStream.write(buffer);
|
|
857
|
+
}
|
|
858
|
+
const fileSha256 = hashCtx.digest();
|
|
859
|
+
encFileWriteStream.end();
|
|
860
|
+
originalFileStream?.end?.call(originalFileStream);
|
|
861
|
+
logger?.debug('prepared plain stream successfully');
|
|
862
|
+
return { mediaKey: undefined, originalFilePath, encFilePath, mac: undefined, fileEncSha256: undefined, fileSha256, fileLength, opusConverted };
|
|
863
|
+
} catch (error) {
|
|
864
|
+
encFileWriteStream.destroy();
|
|
865
|
+
originalFileStream?.destroy?.call(originalFileStream);
|
|
866
|
+
stream.destroy();
|
|
867
|
+
try {
|
|
868
|
+
await unlinkFs(encFilePath);
|
|
869
|
+
} catch (err) { logger?.error({ err }, 'failed deleting tmp files'); }
|
|
870
|
+
throw error;
|
|
871
|
+
}
|
|
872
|
+
};
|
|
774
873
|
//# sourceMappingURL=messages-media.js.map
|