mirror of
https://git.victorphan.net/basketballcantho/zalo-monitor.git
synced 2026-08-07 15:03:11 +07:00
init
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Xem hướng dẫn sử dụng tại:
|
||||
* @tutorial https://drive.google.com/file/d/1xuGHYCu-5H28er4bXZEFjTCSGKcOekhi/view?usp=sharing
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import { createInterface } from "node:readline";
|
||||
import { Zalo, type Credentials } from "../src/index.js";
|
||||
import { decodeAES, decodeEventData } from "../src/utils.js";
|
||||
|
||||
const CREDENTIALS_PATH = "./test/credentials.json";
|
||||
const SECRET_PATH = "./test/secret.test.txt";
|
||||
|
||||
let gotFresh = false;
|
||||
|
||||
const credentials: Credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, "utf-8"));
|
||||
let secretKey = await getSecretKey(),
|
||||
cipher_key = "";
|
||||
|
||||
const rl = createInterface(process.stdin, process.stdout);
|
||||
const cannotDecodeAlert = () =>
|
||||
console.log(
|
||||
"\n\x1b[31mKhông thể giải mã, đảm bảo bạn lấy dữ liệu từ đúng tài khoản và trình duyệt của tài khoản đã đăng nhập\x1b[0m\n",
|
||||
);
|
||||
const exit = () => {
|
||||
console.log();
|
||||
process.exit();
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
async function main() {
|
||||
console.log();
|
||||
if (secretKey && !gotFresh) {
|
||||
const shouldGetFreshKey = await promptForFreshKey();
|
||||
if (shouldGetFreshKey) {
|
||||
secretKey = await getFreshKey();
|
||||
}
|
||||
}
|
||||
|
||||
prompt();
|
||||
}
|
||||
|
||||
function prompt() {
|
||||
console.log();
|
||||
rl.question(
|
||||
"Bạn muốn giải mã hóa loại nào? \x1b[32m[1] HTTP(s)\x1b[0m, \x1b[38;5;165m[2] Websocket\x1b[0m, \x1b[38;5;15m[3] thoát?\x1b[0m: ",
|
||||
(answer) => {
|
||||
if (answer == "1") {
|
||||
console.clear();
|
||||
console.log("\x1b[32m[ HTTP(s) ] Bắt đầu khởi động!\x1b[0m");
|
||||
decodeHTTP();
|
||||
} else if (answer == "2") {
|
||||
console.clear();
|
||||
console.log("\x1b[38;5;165m[ WEBSOCKET ] Bắt đầu khởi động!\x1b[0m");
|
||||
decodeWebsocket();
|
||||
} else if (answer == "3") exit();
|
||||
else {
|
||||
prompt();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function decodeHTTP() {
|
||||
rl.question("\n\x1b[32m[ HTTP(s) ] Dán đoạn dữ liệu bị mã hóa hoặc gõ \x1b[37mexit\x1b[0m \x1b[32mđể thoát:\x1b[0m\n\n", (encoded) => {
|
||||
if (encoded.length == 0) return decodeHTTP();
|
||||
if (encoded == "exit") return prompt();
|
||||
|
||||
if (encoded.startsWith('"') && encoded.endsWith('"')) encoded = JSON.parse(encoded);
|
||||
|
||||
try {
|
||||
const decoded = decodeAES(secretKey, encoded);
|
||||
if (decoded == null) {
|
||||
cannotDecodeAlert();
|
||||
return decodeHTTP();
|
||||
}
|
||||
|
||||
const parsed = JSON.stringify(JSON.parse(decoded), null, 2);
|
||||
|
||||
console.log();
|
||||
console.log("\x1b[32m=========== HTTP(s) ===========\x1b[0m");
|
||||
console.log(parsed);
|
||||
console.log("\x1b[32m===============================\x1b[0m");
|
||||
console.log();
|
||||
|
||||
return decodeHTTP();
|
||||
} catch {
|
||||
cannotDecodeAlert();
|
||||
return decodeHTTP();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function decodeWebsocket() {
|
||||
if (!cipher_key) {
|
||||
console.log(
|
||||
"Mở devtools trên trình duyệt tại https://chat.zalo.me/, vào tab Network -> (WS/Socket)\nMở tin nhắn đầu tiên, đổi sang định dạng UTF-8",
|
||||
);
|
||||
cipher_key = await promptForCipherKey();
|
||||
}
|
||||
|
||||
rl.question(
|
||||
"\n\x1b[38;5;165m[ WEBSOCKET ] Dán đoạn dữ liệu bị mã hóa hoặc gõ \x1b[37mexit\x1b[0m \x1b[38;5;165mđể thoát:\x1b[0m\n\n",
|
||||
async (encoded) => {
|
||||
if (encoded.length == 0) return decodeWebsocket();
|
||||
if (encoded == "exit") return prompt();
|
||||
|
||||
try {
|
||||
const decoded = await decodeEventData(JSON.parse(encoded), cipher_key);
|
||||
if (decoded == null) {
|
||||
cannotDecodeAlert();
|
||||
return decodeWebsocket();
|
||||
}
|
||||
|
||||
const parsed = JSON.stringify(decoded, null, 2);
|
||||
|
||||
console.log();
|
||||
console.log("\x1b[38;5;165m=========== WEBSOCKET ===========\x1b[0m");
|
||||
console.log(parsed);
|
||||
console.log("\x1b[38;5;165m=================================\x1b[0m");
|
||||
console.log();
|
||||
|
||||
return decodeWebsocket();
|
||||
} catch {
|
||||
cannotDecodeAlert();
|
||||
return decodeWebsocket();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function promptForFreshKey() {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
rl.question("\x1b[38;5;204m[ !? ] Tìm thấy khóa bí mật, bạn có muốn tái sử dụng? (y/n):\x1b[0m ", (answer) => {
|
||||
if (answer.toLowerCase() == "y") resolve(false);
|
||||
else if (answer.toLowerCase() == "n") resolve(true);
|
||||
else resolve(promptForFreshKey());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function getSecretKey(): Promise<string> {
|
||||
if (!fs.existsSync(SECRET_PATH)) {
|
||||
return await getFreshKey();
|
||||
} else {
|
||||
const localKey = fs.readFileSync(SECRET_PATH, "utf-8").trim();
|
||||
|
||||
if (!localKey) return await getFreshKey();
|
||||
return localKey;
|
||||
}
|
||||
}
|
||||
|
||||
async function getFreshKey() {
|
||||
gotFresh = true;
|
||||
const zalo = new Zalo({
|
||||
selfListen: true,
|
||||
logging: true,
|
||||
});
|
||||
|
||||
console.log();
|
||||
const api = await zalo.login(credentials);
|
||||
fs.writeFileSync(SECRET_PATH, api.getContext().secretKey, "utf-8");
|
||||
|
||||
return api.getContext().secretKey;
|
||||
}
|
||||
|
||||
async function promptForCipherKey() {
|
||||
return new Promise<string>((resolve) => {
|
||||
rl.question("\n\x1b[38;5;81mSao chép khóa và dán vào đây:\x1b[0m ", (answer) => {
|
||||
if (answer.length == 0) resolve(promptForCipherKey());
|
||||
|
||||
resolve(answer);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user