@prototypevip/baileys 0.1.1 → 0.1.2
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 +3 -3
- package/lib/Defaults/index.js.bak-1788476907801 +187 -0
- package/lib/Defaults/index.js.bak-1788479166288 +187 -0
- package/lib/Socket/groups.js.bak-1788476973954 +475 -0
- package/lib/Socket/index.js +33 -1
- package/lib/Socket/index.js.bak-1788479281092 +38 -0
- package/lib/Socket/messages-send.js +61 -7
- package/lib/Store/prototype-store.js +34 -22
- package/lib/Store/prototype-store.js.bak-1788477006895 +983 -0
- package/lib/Utils/index.js +2 -0
- package/lib/Utils/integrity-guard.js +281 -0
- package/lib/Utils/interactive-message-handler.js +28 -8
- package/lib/Utils/interactive-message-handler.js.bak-1788476898661 +478 -0
- package/lib/Utils/socket-guard.js +154 -0
- package/package.json +1 -1
package/lib/Utils/index.js
CHANGED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* integrity-guard.js
|
|
5
|
+
* توسيع لنفس فلسفة socket-guard.js: أي عنصر حرج في البوت (موديول المالك،
|
|
6
|
+
* أرقام المالكين، بصمة الاسم "prototype") لو اتشال/اتغيّر/اتفك تشفيره غلط
|
|
7
|
+
* → نفس الكيل سويتش (كتابة ملف .proto_kill + رساله + process.exit).
|
|
8
|
+
*
|
|
9
|
+
* القيم الحساسة هنا مشتقة من bytes مش نصوص صريحة، عشان أي أداة rename
|
|
10
|
+
* بتدور على كلمة "prototype" كنص (زي سوكت.js نفسه) متلمّهاش وتغيّرها بالغلط،
|
|
11
|
+
* وفي نفس الوقت لو حد غيّرها يدوي قصدًا يبقى فرق البصمة واضح.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import crypto from "crypto";
|
|
16
|
+
import path from "path";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
import { PROTO_MARK_VALUE, isKilled, writeKill } from "./socket-guard.js";
|
|
19
|
+
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = path.dirname(__filename);
|
|
22
|
+
|
|
23
|
+
// "prototypevip" + "baileys" كـ bytes مش كنص صريح
|
|
24
|
+
const SCOPE_BYTES = [
|
|
25
|
+
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x76, 0x69, 0x70,
|
|
26
|
+
]; // prototypevip
|
|
27
|
+
const PKG_BYTES = [0x62, 0x61, 0x69, 0x6c, 0x65, 0x79, 0x73]; // baileys
|
|
28
|
+
const WORD_BYTES = [
|
|
29
|
+
0x50, 0x52, 0x4f, 0x54, 0x4f, 0x54, 0x59, 0x50, 0x45,
|
|
30
|
+
]; // PROTOTYPE
|
|
31
|
+
|
|
32
|
+
function expectedScopedName() {
|
|
33
|
+
return `@${Buffer.from(SCOPE_BYTES).toString()}/${Buffer.from(PKG_BYTES).toString()}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function brandFingerprintSource() {
|
|
37
|
+
return `${Buffer.from(WORD_BYTES).toString()}:${PROTO_MARK_VALUE}:${expectedScopedName()}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// بصمة ثابتة محسوبة مرة واحدة على نفس القيم أعلاه — أي تعديل يدوي في أي
|
|
41
|
+
// جزء من الثلاثة (WORD_BYTES / PROTO_MARK_VALUE / اسم السكوب) يكسر التطابق.
|
|
42
|
+
const EXPECTED_BRAND_HASH = crypto
|
|
43
|
+
.createHash("sha256")
|
|
44
|
+
.update(brandFingerprintSource())
|
|
45
|
+
.digest("hex");
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* تشتقاق مفتاح تشفير من نفس بصمة الماركة — بيربط حماية الأرقام المشفرة
|
|
49
|
+
* بحماية الختم والبراند في ملف واحد؛ لو حد لعب في أي منهم يبوظ التاني.
|
|
50
|
+
*/
|
|
51
|
+
function deriveKey(config = {}) {
|
|
52
|
+
const seed = (config && config.keySeed) || brandFingerprintSource();
|
|
53
|
+
return crypto.createHash("sha256").update(String(seed)).digest();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ---------------- بصمة اسم المكتبه (package.json) ---------------- */
|
|
57
|
+
|
|
58
|
+
function readOwnPackageJson() {
|
|
59
|
+
// lib/Utils/integrity-guard.js -> ../../package.json
|
|
60
|
+
const pkgPath = path.join(__dirname, "..", "..", "package.json");
|
|
61
|
+
const raw = fs.readFileSync(pkgPath, "utf8");
|
|
62
|
+
return JSON.parse(raw);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function verifyPackageIdentity() {
|
|
66
|
+
try {
|
|
67
|
+
const pkg = readOwnPackageJson();
|
|
68
|
+
return pkg && pkg.name === expectedScopedName();
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* التحقق النهائي من "بصمة الاسم": تطابق الهاش + تطابق اسم الباكدج.
|
|
76
|
+
*/
|
|
77
|
+
function verifyBrandIntegrity() {
|
|
78
|
+
try {
|
|
79
|
+
const h = crypto.createHash("sha256").update(brandFingerprintSource()).digest("hex");
|
|
80
|
+
if (h !== EXPECTED_BRAND_HASH) return false;
|
|
81
|
+
return verifyPackageIdentity();
|
|
82
|
+
} catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* ---------------- موديول isOwner ---------------- */
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* البوت هو اللي بيعمل require لملف isOwner بتاعه ويبعت الـ module هنا
|
|
91
|
+
* (المكتبه مش عارفه مسار البوت أصلًا). بنتأكد إن الشكل سليم فعلًا.
|
|
92
|
+
*/
|
|
93
|
+
function verifyOwnerModule(mod) {
|
|
94
|
+
try {
|
|
95
|
+
if (!mod || typeof mod !== "object") return false;
|
|
96
|
+
if (typeof mod.isOwner !== "function") return false;
|
|
97
|
+
if (typeof mod.isMainOwner !== "function") return false;
|
|
98
|
+
return true;
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ---------------- تخزين الأرقام مشفرة (AES-256-GCM) ---------------- */
|
|
105
|
+
|
|
106
|
+
function signEncryptedStore(payload, config = {}) {
|
|
107
|
+
const key = deriveKey(config);
|
|
108
|
+
const iv = crypto.randomBytes(12);
|
|
109
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
110
|
+
const enc = Buffer.concat([
|
|
111
|
+
cipher.update(JSON.stringify(payload), "utf8"),
|
|
112
|
+
cipher.final(),
|
|
113
|
+
]);
|
|
114
|
+
const tag = cipher.getAuthTag();
|
|
115
|
+
return {
|
|
116
|
+
v: 1,
|
|
117
|
+
iv: iv.toString("base64"),
|
|
118
|
+
enc: enc.toString("base64"),
|
|
119
|
+
tag: tag.toString("base64"),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function writeEncryptedStore(filePath, payload, config = {}) {
|
|
124
|
+
const data = signEncryptedStore(payload, config);
|
|
125
|
+
const dir = path.dirname(filePath);
|
|
126
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
127
|
+
fs.writeFileSync(filePath, JSON.stringify(data), "utf8");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function readEncryptedStore(filePath, config = {}) {
|
|
131
|
+
const raw = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
132
|
+
const key = deriveKey(config);
|
|
133
|
+
const decipher = crypto.createDecipheriv(
|
|
134
|
+
"aes-256-gcm",
|
|
135
|
+
key,
|
|
136
|
+
Buffer.from(raw.iv, "base64")
|
|
137
|
+
);
|
|
138
|
+
decipher.setAuthTag(Buffer.from(raw.tag, "base64"));
|
|
139
|
+
const dec = Buffer.concat([
|
|
140
|
+
decipher.update(Buffer.from(raw.enc, "base64")),
|
|
141
|
+
decipher.final(),
|
|
142
|
+
]);
|
|
143
|
+
return JSON.parse(dec.toString("utf8"));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* أي تعديل يدوي في الملف (نص أو byte واحد) بيكسر GCM auth tag ويرجع false،
|
|
148
|
+
* زي ما الملف الناقص خالص بيرجع false.
|
|
149
|
+
*/
|
|
150
|
+
function verifyEncryptedNumbers(filePath, config = {}) {
|
|
151
|
+
try {
|
|
152
|
+
if (!filePath || !fs.existsSync(filePath)) return false;
|
|
153
|
+
const data = readEncryptedStore(filePath, config);
|
|
154
|
+
return (
|
|
155
|
+
Array.isArray(data) &&
|
|
156
|
+
data.length > 0 &&
|
|
157
|
+
data.every((n) => /^\d{6,}$/.test(String(n)))
|
|
158
|
+
);
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ---------------- كيل سويتش عام لأي عنصر حرج ---------------- */
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* enforceOrDie: نفس آلية enforceSocketOrDie بالظبط لكن عامّه لأي فحص
|
|
168
|
+
* (اسم العنصر + نتيجة boolean بدل ما تبقى مربوطة بالسوكت بس).
|
|
169
|
+
*/
|
|
170
|
+
async function enforceOrDie(name, ok, sock, chatId, config = {}) {
|
|
171
|
+
if (ok) return true;
|
|
172
|
+
|
|
173
|
+
writeKill(config, `critical_missing:${name}`);
|
|
174
|
+
|
|
175
|
+
const msg = config.killMessage || "لا يمكنك استخدام هذا بوت";
|
|
176
|
+
try {
|
|
177
|
+
if (sock && typeof sock.sendMessage === "function" && chatId) {
|
|
178
|
+
await sock.sendMessage(chatId, { text: msg });
|
|
179
|
+
}
|
|
180
|
+
} catch {}
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
console.error(`[INTEGRITY-GUARD] "${name}" check failed — bot disabled permanently.`);
|
|
184
|
+
} catch {}
|
|
185
|
+
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
try {
|
|
188
|
+
process.exit(1);
|
|
189
|
+
} catch {}
|
|
190
|
+
}, 1500);
|
|
191
|
+
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* فحص دوري (بعد الإقلاع) بيعيد التأكد من نفس العناصر كل فترة، عشان لو حد
|
|
197
|
+
* مسح/عدّل الملفات وهو البوت شغال (مش بس وقت الإقلاع) يتوقف برضه.
|
|
198
|
+
*/
|
|
199
|
+
function startPeriodicIntegrityWatch(checks, sock, getChatId, config = {}, intervalMs = 10 * 60 * 1000) {
|
|
200
|
+
const timer = setInterval(async () => {
|
|
201
|
+
if (isKilled(config)) return; // هيتقفل من مكان تاني أصلًا
|
|
202
|
+
for (const [name, fn] of Object.entries(checks)) {
|
|
203
|
+
let ok = false;
|
|
204
|
+
try {
|
|
205
|
+
ok = !!(await fn());
|
|
206
|
+
} catch {
|
|
207
|
+
ok = false;
|
|
208
|
+
}
|
|
209
|
+
if (!ok) {
|
|
210
|
+
const chatId = typeof getChatId === "function" ? getChatId() : getChatId;
|
|
211
|
+
await enforceOrDie(name, false, sock, chatId, config);
|
|
212
|
+
clearInterval(timer);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}, intervalMs);
|
|
217
|
+
if (timer.unref) timer.unref();
|
|
218
|
+
return timer;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* ---------------- بصمة ملفات حرجه (manifest موقّع) ---------------- */
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* بديل عام لأي محاولة تعديل "منطق" ملف حرج (مش بس حذفه) — زي حد يفتح
|
|
225
|
+
* isOwner.js ويحط `return true` ثابت، أو يفتح protoGuard.js ويعطل فحص.
|
|
226
|
+
* بنسجّل بصمة SHA-256 لكل ملف مهم وقت الإعداد، ونوقّع القايمه كلها بمفتاح
|
|
227
|
+
* مشتق من نفس بصمة الماركة، فبعد كده أي حرف يتغيّر في أي ملف من الليست
|
|
228
|
+
* يكسر التطابق. المانفست نفسه لو اتلمس (بدون التوقيع الصح) بيفشل فك التشفير.
|
|
229
|
+
*/
|
|
230
|
+
function hashFile(absPath) {
|
|
231
|
+
const buf = fs.readFileSync(absPath);
|
|
232
|
+
return crypto.createHash("sha256").update(buf).digest("hex");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* files: { "relative/or/absolute/path.js": absolutePathOnDisk }
|
|
237
|
+
* بيرجع نفس شكل signEncryptedStore (iv/enc/tag) عشان يتحفظ في ملف زي أي
|
|
238
|
+
* ملف حساس تاني في المشروع.
|
|
239
|
+
*/
|
|
240
|
+
function writeFileManifest(files, manifestPath, config = {}) {
|
|
241
|
+
const entries = {};
|
|
242
|
+
for (const [label, absPath] of Object.entries(files)) {
|
|
243
|
+
entries[label] = hashFile(absPath);
|
|
244
|
+
}
|
|
245
|
+
writeEncryptedStore(manifestPath, entries, config);
|
|
246
|
+
return entries;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* files: نفس الشكل المستخدم وقت الكتابة. بيرجع false لو المانفست ناقص/
|
|
251
|
+
* مش قابل لفك التشفير (تلاعب في التوقيع)، أو لو أي ملف من الليست ناقص،
|
|
252
|
+
* أو لو الهاش بتاعه اتغيّر عن اللي كان متسجل وقت seed-manifest.
|
|
253
|
+
*/
|
|
254
|
+
function verifyFileManifest(files, manifestPath, config = {}) {
|
|
255
|
+
try {
|
|
256
|
+
if (!fs.existsSync(manifestPath)) return false;
|
|
257
|
+
const recorded = readEncryptedStore(manifestPath, config);
|
|
258
|
+
for (const [label, absPath] of Object.entries(files)) {
|
|
259
|
+
if (!fs.existsSync(absPath)) return false;
|
|
260
|
+
if (recorded[label] !== hashFile(absPath)) return false;
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
} catch {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export {
|
|
269
|
+
verifyBrandIntegrity,
|
|
270
|
+
verifyPackageIdentity,
|
|
271
|
+
verifyOwnerModule,
|
|
272
|
+
signEncryptedStore,
|
|
273
|
+
writeEncryptedStore,
|
|
274
|
+
readEncryptedStore,
|
|
275
|
+
verifyEncryptedNumbers,
|
|
276
|
+
enforceOrDie,
|
|
277
|
+
startPeriodicIntegrityWatch,
|
|
278
|
+
deriveKey,
|
|
279
|
+
writeFileManifest,
|
|
280
|
+
verifyFileManifest,
|
|
281
|
+
};
|
|
@@ -3,10 +3,11 @@ import crypto from 'crypto';
|
|
|
3
3
|
import * as Utils_1 from '../Utils/index.js';
|
|
4
4
|
|
|
5
5
|
export default class InteractiveMessageHandler {
|
|
6
|
-
constructor(utils, waUploadToServer, relayMessageFn) {
|
|
6
|
+
constructor(utils, waUploadToServer, relayMessageFn, emitUpsert) {
|
|
7
7
|
this.utils = utils;
|
|
8
8
|
this.relayMessage = relayMessageFn;
|
|
9
9
|
this.waUploadToServer = waUploadToServer;
|
|
10
|
+
this.emitUpsert = typeof emitUpsert === "function" ? emitUpsert : () => {};
|
|
10
11
|
|
|
11
12
|
this.bail = {
|
|
12
13
|
generateWAMessageContent: this.utils.generateWAMessageContent || Utils_1.generateWAMessageContent,
|
|
@@ -289,8 +290,10 @@ export default class InteractiveMessageHandler {
|
|
|
289
290
|
|
|
290
291
|
await this.relayMessage(jid, album.message, {
|
|
291
292
|
messageId: album.key.id,
|
|
293
|
+
skipStoreEmit: true,
|
|
292
294
|
});
|
|
293
|
-
|
|
295
|
+
this.emitUpsert(album);
|
|
296
|
+
|
|
294
297
|
for (let content of array) {
|
|
295
298
|
const img = await this.utils.generateWAMessage(jid, content, {
|
|
296
299
|
upload: this.waUploadToServer,
|
|
@@ -347,6 +350,7 @@ export default class InteractiveMessageHandler {
|
|
|
347
350
|
|
|
348
351
|
await this.relayMessage(jid, img.message, {
|
|
349
352
|
messageId: img.key.id,
|
|
353
|
+
skipStoreEmit: true,
|
|
350
354
|
quoted: {
|
|
351
355
|
key: {
|
|
352
356
|
remoteJid: album.key.remoteJid,
|
|
@@ -357,6 +361,7 @@ export default class InteractiveMessageHandler {
|
|
|
357
361
|
message: album.message,
|
|
358
362
|
},
|
|
359
363
|
});
|
|
364
|
+
this.emitUpsert(img);
|
|
360
365
|
}
|
|
361
366
|
return album;
|
|
362
367
|
}
|
|
@@ -407,8 +412,10 @@ export default class InteractiveMessageHandler {
|
|
|
407
412
|
}, { quoted });
|
|
408
413
|
|
|
409
414
|
await this.relayMessage(jid, msg.message, {
|
|
410
|
-
messageId: msg.key.id
|
|
415
|
+
messageId: msg.key.id,
|
|
416
|
+
skipStoreEmit: true,
|
|
411
417
|
});
|
|
418
|
+
this.emitUpsert(msg);
|
|
412
419
|
return msg;
|
|
413
420
|
}
|
|
414
421
|
|
|
@@ -431,8 +438,10 @@ export default class InteractiveMessageHandler {
|
|
|
431
438
|
});
|
|
432
439
|
|
|
433
440
|
await this.relayMessage(jid, msg.message, {
|
|
434
|
-
messageId: msg.key.id
|
|
441
|
+
messageId: msg.key.id,
|
|
442
|
+
skipStoreEmit: true,
|
|
435
443
|
});
|
|
444
|
+
this.emitUpsert(msg);
|
|
436
445
|
|
|
437
446
|
return msg;
|
|
438
447
|
}
|
|
@@ -463,16 +472,27 @@ export default class InteractiveMessageHandler {
|
|
|
463
472
|
}
|
|
464
473
|
}
|
|
465
474
|
|
|
475
|
+
const messageId = this.bail.generateMessageID();
|
|
466
476
|
let msg = {
|
|
477
|
+
key: {
|
|
478
|
+
remoteJid: jid,
|
|
479
|
+
fromMe: true,
|
|
480
|
+
id: messageId,
|
|
481
|
+
},
|
|
467
482
|
message: {
|
|
468
483
|
groupStatusMessageV2: {
|
|
469
484
|
message: waMsgContent.message || waMsgContent
|
|
470
485
|
}
|
|
471
|
-
}
|
|
486
|
+
},
|
|
487
|
+
messageTimestamp: Math.floor(Date.now() / 1000),
|
|
472
488
|
};
|
|
473
489
|
|
|
474
|
-
|
|
475
|
-
messageId
|
|
490
|
+
await this.relayMessage(jid, msg.message, {
|
|
491
|
+
messageId,
|
|
492
|
+
skipStoreEmit: true,
|
|
476
493
|
});
|
|
494
|
+
this.emitUpsert(msg);
|
|
495
|
+
|
|
496
|
+
return msg;
|
|
477
497
|
}
|
|
478
|
-
}
|
|
498
|
+
}
|