@ryuu-reinzz/baileys 3.0.0-beta.2 → 3.0.0-beta.21
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 +6 -0
- package/WAProto/fix-imports.js +70 -18
- package/WAProto/index.js +197 -160
- package/lib/Defaults/index.js +17 -4
- package/lib/Signal/libsignal.js +63 -2
- package/lib/Signal/lid-mapping.js +170 -70
- package/lib/Socket/Client/websocket.js +5 -1
- package/lib/Socket/business.js +11 -8
- package/lib/Socket/chats.js +55 -28
- package/lib/Socket/index.js +0 -6
- package/lib/Socket/messages-recv.js +152 -75
- package/lib/Socket/messages-send.js +230 -148
- package/lib/Socket/socket.js +69 -15
- package/lib/Utils/auth-utils.js +53 -20
- package/lib/Utils/chat-utils.js +100 -51
- package/lib/Utils/crypto.js +2 -26
- package/lib/Utils/event-buffer.js +33 -7
- package/lib/Utils/generics.js +4 -1
- package/lib/Utils/history.js +46 -5
- package/lib/Utils/identity-change-handler.js +49 -0
- package/lib/Utils/index.js +2 -0
- package/lib/Utils/lt-hash.js +2 -42
- package/lib/Utils/make-mutex.js +20 -27
- package/lib/Utils/message-retry-manager.js +58 -5
- package/lib/Utils/messages-media.js +151 -40
- package/lib/Utils/messages.js +43 -23
- package/lib/Utils/noise-handler.js +139 -85
- package/lib/Utils/process-message.js +57 -14
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/sync-action-utils.js +48 -0
- package/lib/Utils/tc-token-utils.js +18 -0
- package/lib/Utils/use-sqlite-auth-state.js +122 -0
- package/lib/WABinary/decode.js +24 -0
- package/lib/WABinary/encode.js +5 -1
- package/lib/WABinary/generic-utils.js +19 -8
- package/package.json +7 -2
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { proto } from '../../WAProto/index.js';
|
|
2
|
+
import { isLidUser, isPnUser } from '../WABinary/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Process contactAction and return events to emit.
|
|
5
|
+
* Pure function - no side effects.
|
|
6
|
+
*/
|
|
7
|
+
export const processContactAction = (action, id, logger) => {
|
|
8
|
+
const results = [];
|
|
9
|
+
if (!id) {
|
|
10
|
+
logger?.warn({ hasFullName: !!action.fullName, hasLidJid: !!action.lidJid, hasPnJid: !!action.pnJid }, 'contactAction sync: missing id in index');
|
|
11
|
+
return results;
|
|
12
|
+
}
|
|
13
|
+
const lidJid = action.lidJid;
|
|
14
|
+
const idIsPn = isPnUser(id);
|
|
15
|
+
// PN is in index[1], not in contactAction.pnJid which is usually null
|
|
16
|
+
const phoneNumber = idIsPn ? id : action.pnJid || undefined;
|
|
17
|
+
// Always emit contacts.upsert
|
|
18
|
+
results.push({
|
|
19
|
+
event: 'contacts.upsert',
|
|
20
|
+
data: [
|
|
21
|
+
{
|
|
22
|
+
id,
|
|
23
|
+
name: action.fullName || action.firstName || action.username || undefined,
|
|
24
|
+
lid: lidJid || undefined,
|
|
25
|
+
phoneNumber
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
// Emit lid-mapping.update if we have valid LID-PN pair
|
|
30
|
+
if (lidJid && isLidUser(lidJid) && idIsPn) {
|
|
31
|
+
results.push({
|
|
32
|
+
event: 'lid-mapping.update',
|
|
33
|
+
data: { lid: lidJid, pn: id }
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
};
|
|
38
|
+
export const emitSyncActionResults = (ev, results) => {
|
|
39
|
+
for (const result of results) {
|
|
40
|
+
if (result.event === 'contacts.upsert') {
|
|
41
|
+
ev.emit('contacts.upsert', result.data);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
ev.emit('lid-mapping.update', result.data);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=sync-action-utils.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export async function buildTcTokenFromJid({ authState, jid, baseContent = [] }) {
|
|
2
|
+
try {
|
|
3
|
+
const tcTokenData = await authState.keys.get('tctoken', [jid]);
|
|
4
|
+
const tcTokenBuffer = tcTokenData?.[jid]?.token;
|
|
5
|
+
if (!tcTokenBuffer)
|
|
6
|
+
return baseContent.length > 0 ? baseContent : undefined;
|
|
7
|
+
baseContent.push({
|
|
8
|
+
tag: 'tctoken',
|
|
9
|
+
attrs: {},
|
|
10
|
+
content: tcTokenBuffer
|
|
11
|
+
});
|
|
12
|
+
return baseContent;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return baseContent.length > 0 ? baseContent : undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=tc-token-utils.js.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom SQLite Auth Store untuk Baileys
|
|
3
|
+
* by Ryuu
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Database from "better-sqlite3";
|
|
7
|
+
import { proto } from '../../WAProto/index.js';
|
|
8
|
+
import { initAuthCreds } from './auth-utils.js';
|
|
9
|
+
import { BufferJSON } from './generics.js';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
/**
|
|
12
|
+
* Membuat atau mengambil auth state dari SQLite
|
|
13
|
+
* @param {string} folder - Lokasi file SQLite (contoh: "./auth.db")
|
|
14
|
+
*/
|
|
15
|
+
export const useSQLiteAuthState = async (folder) => {
|
|
16
|
+
if (!folder) {
|
|
17
|
+
throw new Error('Path required')
|
|
18
|
+
};
|
|
19
|
+
if (!fs.existsSync(folder)) {
|
|
20
|
+
fs.mkdirSync(folder, { recursive: true })
|
|
21
|
+
};
|
|
22
|
+
if (folder.endsWith("/")) {
|
|
23
|
+
folder += "auth.db"
|
|
24
|
+
} else {
|
|
25
|
+
folder += "/auth.db"
|
|
26
|
+
}
|
|
27
|
+
const db = new Database(folder);
|
|
28
|
+
db.pragma("journal_mode = WAL");
|
|
29
|
+
|
|
30
|
+
db.prepare(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS baileys_state (
|
|
32
|
+
key TEXT PRIMARY KEY,
|
|
33
|
+
value BLOB
|
|
34
|
+
)
|
|
35
|
+
`).run();
|
|
36
|
+
|
|
37
|
+
const load = (key) => {
|
|
38
|
+
const row = db.prepare("SELECT value FROM baileys_state WHERE key = ?").get(key);
|
|
39
|
+
if (!row) return null;
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(row.value.toString(), BufferJSON.reviver);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const save = (key, data) => {
|
|
48
|
+
const json = JSON.stringify(data, BufferJSON.replacer);
|
|
49
|
+
const buf = Buffer.from(json, "utf8");
|
|
50
|
+
db.prepare("REPLACE INTO baileys_state (key, value) VALUES (?, ?)").run(key, buf);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const creds = load("creds") || initAuthCreds();
|
|
54
|
+
|
|
55
|
+
const keys = {};
|
|
56
|
+
const categories = [
|
|
57
|
+
"pre-key",
|
|
58
|
+
"session",
|
|
59
|
+
"sender-key",
|
|
60
|
+
"app-state-sync-key",
|
|
61
|
+
"app-state-sync-version"
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
for (const category of categories) {
|
|
65
|
+
keys[category] = {};
|
|
66
|
+
const rows = db
|
|
67
|
+
.prepare("SELECT key, value FROM baileys_state WHERE key LIKE ?")
|
|
68
|
+
.all(`${category}:%`);
|
|
69
|
+
for (const row of rows) {
|
|
70
|
+
try {
|
|
71
|
+
keys[category][row.key.slice(category.length + 1)] = JSON.parse(row.value.toString());
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function saveCreds() {
|
|
77
|
+
save("creds", creds);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const set = (category, id, value) => {
|
|
81
|
+
const key = `${category}:${id}`;
|
|
82
|
+
save(key, value);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const get = (category, id) => {
|
|
86
|
+
const key = `${category}:${id}`;
|
|
87
|
+
return load(key);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const del = (category, id) => {
|
|
91
|
+
const key = `${category}:${id}`;
|
|
92
|
+
db.prepare("DELETE FROM baileys_state WHERE key = ?").run(key);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
state: {
|
|
97
|
+
creds,
|
|
98
|
+
keys: {
|
|
99
|
+
get: async (type, ids) => {
|
|
100
|
+
const data = {};
|
|
101
|
+
for (const id of ids) {
|
|
102
|
+
const value = load(`${type}:${id}`);
|
|
103
|
+
if (value) data[id] = value;
|
|
104
|
+
}
|
|
105
|
+
return data;
|
|
106
|
+
},
|
|
107
|
+
set: async (data) => {
|
|
108
|
+
for (const category in data) {
|
|
109
|
+
for (const id in data[category]) {
|
|
110
|
+
const value = data[category][id];
|
|
111
|
+
save(`${category}:${id}`, value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
saveCreds: async () => save("creds", creds)
|
|
118
|
+
};
|
|
119
|
+
setInterval(async () => {
|
|
120
|
+
await save("creds", creds);
|
|
121
|
+
}, 30_000);
|
|
122
|
+
}
|
package/lib/WABinary/decode.js
CHANGED
|
@@ -136,6 +136,26 @@ export const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0
|
|
|
136
136
|
}
|
|
137
137
|
return jidEncode(user, server, device);
|
|
138
138
|
};
|
|
139
|
+
const readFbJid = () => {
|
|
140
|
+
const user = readString(readByte());
|
|
141
|
+
const device = readInt(2);
|
|
142
|
+
const server = readString(readByte());
|
|
143
|
+
return `${user}:${device}@${server}`;
|
|
144
|
+
};
|
|
145
|
+
const readInteropJid = () => {
|
|
146
|
+
const user = readString(readByte());
|
|
147
|
+
const device = readInt(2);
|
|
148
|
+
const integrator = readInt(2);
|
|
149
|
+
let server = 'interop';
|
|
150
|
+
const beforeServer = indexRef.index;
|
|
151
|
+
try {
|
|
152
|
+
server = readString(readByte());
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
indexRef.index = beforeServer;
|
|
156
|
+
}
|
|
157
|
+
return `${integrator}-${user}:${device}@${server}`;
|
|
158
|
+
};
|
|
139
159
|
const readString = (tag) => {
|
|
140
160
|
if (tag >= 1 && tag < SINGLE_BYTE_TOKENS.length) {
|
|
141
161
|
return SINGLE_BYTE_TOKENS[tag] || '';
|
|
@@ -156,6 +176,10 @@ export const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0
|
|
|
156
176
|
return readStringFromChars(readInt(4));
|
|
157
177
|
case TAGS.JID_PAIR:
|
|
158
178
|
return readJidPair();
|
|
179
|
+
case TAGS.FB_JID:
|
|
180
|
+
return readFbJid();
|
|
181
|
+
case TAGS.INTEROP_JID:
|
|
182
|
+
return readInteropJid();
|
|
159
183
|
case TAGS.AD_JID:
|
|
160
184
|
return readAdJid();
|
|
161
185
|
case TAGS.HEX_8:
|
package/lib/WABinary/encode.js
CHANGED
|
@@ -144,6 +144,10 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
|
|
|
144
144
|
pushByte(TAGS.LIST_EMPTY);
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
+
if (str === '') {
|
|
148
|
+
writeStringRaw(str);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
147
151
|
const tokenIndex = TOKEN_MAP[str];
|
|
148
152
|
if (tokenIndex) {
|
|
149
153
|
if (typeof tokenIndex.dict === 'number') {
|
|
@@ -157,7 +161,7 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
|
|
|
157
161
|
else if (isHex(str)) {
|
|
158
162
|
writePackedBytes(str, 'hex');
|
|
159
163
|
}
|
|
160
|
-
else
|
|
164
|
+
else {
|
|
161
165
|
const decodedJid = jidDecode(str);
|
|
162
166
|
if (decodedJid) {
|
|
163
167
|
writeJid(decodedJid);
|
|
@@ -2,11 +2,27 @@ import { Boom } from '@hapi/boom';
|
|
|
2
2
|
import { proto } from '../../WAProto/index.js';
|
|
3
3
|
import {} from './types.js';
|
|
4
4
|
// some extra useful utilities
|
|
5
|
+
const indexCache = new WeakMap();
|
|
5
6
|
export const getBinaryNodeChildren = (node, childTag) => {
|
|
6
|
-
if (Array.isArray(node
|
|
7
|
-
return
|
|
7
|
+
if (!node || !Array.isArray(node.content))
|
|
8
|
+
return [];
|
|
9
|
+
let index = indexCache.get(node);
|
|
10
|
+
// Build the index once per node
|
|
11
|
+
if (!index) {
|
|
12
|
+
index = new Map();
|
|
13
|
+
for (const child of node.content) {
|
|
14
|
+
let arr = index.get(child.tag);
|
|
15
|
+
if (!arr)
|
|
16
|
+
index.set(child.tag, (arr = []));
|
|
17
|
+
arr.push(child);
|
|
18
|
+
}
|
|
19
|
+
indexCache.set(node, index);
|
|
8
20
|
}
|
|
9
|
-
|
|
21
|
+
// Return first matching child
|
|
22
|
+
return index.get(childTag) || [];
|
|
23
|
+
};
|
|
24
|
+
export const getBinaryNodeChild = (node, childTag) => {
|
|
25
|
+
return getBinaryNodeChildren(node, childTag)[0];
|
|
10
26
|
};
|
|
11
27
|
export const getAllBinaryNodeChildren = ({ content }) => {
|
|
12
28
|
if (Array.isArray(content)) {
|
|
@@ -14,11 +30,6 @@ export const getAllBinaryNodeChildren = ({ content }) => {
|
|
|
14
30
|
}
|
|
15
31
|
return [];
|
|
16
32
|
};
|
|
17
|
-
export const getBinaryNodeChild = (node, childTag) => {
|
|
18
|
-
if (Array.isArray(node?.content)) {
|
|
19
|
-
return node?.content.find(item => item.tag === childTag);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
33
|
export const getBinaryNodeChildBuffer = (node, childTag) => {
|
|
23
34
|
const child = getBinaryNodeChild(node, childTag)?.content;
|
|
24
35
|
if (Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuu-reinzz/baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
4
|
+
"version": "3.0.0-beta.21",
|
|
5
5
|
"description": "A WebSockets library for interacting with WhatsApp Web",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|
|
@@ -20,17 +20,22 @@
|
|
|
20
20
|
"WAProto/**/*",
|
|
21
21
|
"engine-requirements.js"
|
|
22
22
|
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"start": "node engine-requirements.js"
|
|
25
|
+
},
|
|
23
26
|
"dependencies": {
|
|
24
27
|
"@cacheable/node-cache": "^1.4.0",
|
|
25
|
-
"@ryuu-reinzz/haruka-lib": "^3.2.
|
|
28
|
+
"@ryuu-reinzz/haruka-lib": "^3.2.3",
|
|
26
29
|
"@hapi/boom": "^9.1.3",
|
|
27
30
|
"async-mutex": "^0.5.0",
|
|
31
|
+
"better-sqlite3": "^12.5.0",
|
|
28
32
|
"libsignal": "git+https://github.com/whiskeysockets/libsignal-node",
|
|
29
33
|
"lru-cache": "^11.1.0",
|
|
30
34
|
"music-metadata": "^11.7.0",
|
|
31
35
|
"p-queue": "^9.0.0",
|
|
32
36
|
"pino": "^9.6",
|
|
33
37
|
"protobufjs": "^7.2.4",
|
|
38
|
+
"whatsapp-rust-bridge": "0.5.2",
|
|
34
39
|
"ws": "^8.13.0"
|
|
35
40
|
},
|
|
36
41
|
"devDependencies": {
|