UNPKG

@warriorteam/zalo-personal

Version:

Unofficial Zalo Personal API for JavaScript - A powerful library for interacting with Zalo personal accounts with URL attachment support

467 lines (378 loc) 12.7 kB
# Xác Thực (Authentication) ## Tổng Quan Zalo Personal SDK hỗ trợ hai phương thức đăng nhập chính: - **Cookie Authentication**: Sử dụng cookie từ browser - **QR Code Authentication**: Quét mã QR để đăng nhập ## Đăng Nhập Bằng Cookie ### 1. Lấy Cookie Từ Browser Để sử dụng cookie authentication, bạn cần lấy cookie từ browser: 1. Mở Zalo Web (chat.zalo.me) 2. Đăng nhập vào tài khoản 3. Mở Developer Tools (F12) 4. Vào tab Application/Storage → Cookies 5. Copy tất cả cookies ### 2. Cấu Hình Credentials ```typescript import { Zalo, Credentials } from 'zalo-personal-sdk'; const credentials: Credentials = { imei: 'your-device-imei', // IMEI thiết bị (có thể generate) cookie: [ { domain: ".zalo.me", name: "_zlang", value: "vn", path: "/", // ... các thuộc tính cookie khác } // ... thêm các cookie khác ], userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', language: 'vi' // Optional, mặc định là 'vi' }; ``` ### 3. Đăng Nhập ```typescript const zalo = new Zalo({ selfListen: true, // Lắng nghe tin nhắn của chính mình logLevel: 'info', // Mức độ log (info, debug, error) apiVersion: 'v1' // Phiên bản API }); try { const api = await zalo.login(credentials); console.log('Đăng nhập thành công!'); // Sử dụng API const ownId = await api.getOwnId(); console.log('ID của bạn:', ownId); } catch (error) { console.error('Lỗi đăng nhập:', error.message); } ``` ### 4. Generate IMEI ```typescript import { generateZaloUUID } from 'zalo-personal-sdk/utils'; const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'; const imei = generateZaloUUID(userAgent); console.log('Generated IMEI:', imei); ``` ## Đăng Nhập Bằng QR Code ### 1. Cấu Hình QR Login ```typescript import { Zalo, LoginQRCallbackEventType } from 'zalo-personal-sdk'; const zalo = new Zalo(); const options = { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', language: 'vi', qrPath: './qr-code.png' // Optional: đường dẫn lưu QR code }; ``` ### 2. Callback Handler ```typescript const qrCallback = (event) => { switch (event.type) { case LoginQRCallbackEventType.QrCodeGenerated: console.log('QR Code đã được tạo tại:', event.data.qrCodePath); console.log('QR Code URL:', event.data.qrCodeUrl); // Hiển thị QR code cho người dùng quét break; case LoginQRCallbackEventType.WaitingForScan: console.log('Đang chờ quét QR code...'); break; case LoginQRCallbackEventType.Scanned: console.log('QR code đã được quét, đang chờ xác nhận...'); break; case LoginQRCallbackEventType.Confirmed: console.log('Đã xác nhận đăng nhập trên điện thoại'); break; case LoginQRCallbackEventType.LoggedIn: console.log('Đăng nhập thành công!'); break; case LoginQRCallbackEventType.GotLoginInfo: console.log('Thông tin đăng nhập:', { cookie: event.data.cookie, imei: event.data.imei, userAgent: event.data.userAgent }); // Lưu thông tin này để sử dụng cho lần đăng nhập sau saveCredentials(event.data); break; case LoginQRCallbackEventType.Error: console.error('Lỗi đăng nhập QR:', event.data.error); break; case LoginQRCallbackEventType.Timeout: console.log('QR code đã hết hạn, tạo QR mới...'); break; } }; ``` ### 3. Thực Hiện QR Login ```typescript try { const api = await zalo.loginQR(options, qrCallback); console.log('Đăng nhập QR thành công!'); // API đã sẵn sàng sử dụng const ownId = await api.getOwnId(); console.log('ID của bạn:', ownId); } catch (error) { console.error('Lỗi đăng nhập QR:', error.message); } ``` ### 4. Lưu Trữ Credentials ```typescript function saveCredentials(loginData) { const credentials = { imei: loginData.imei, cookie: loginData.cookie, userAgent: loginData.userAgent, language: 'vi' }; // Lưu vào file fs.writeFileSync('./credentials.json', JSON.stringify(credentials, null, 2)); // Hoặc lưu vào database // await db.saveCredentials(userId, credentials); } function loadCredentials() { try { const data = fs.readFileSync('./credentials.json', 'utf8'); return JSON.parse(data); } catch (error) { return null; } } ``` ## Xử Lý Session ### 1. Kiểm Tra Session ```typescript // Kiểm tra xem session có còn hợp lệ không try { const accountInfo = await api.fetchAccountInfo(); console.log('Session hợp lệ:', accountInfo); } catch (error) { console.log('Session hết hạn, cần đăng nhập lại'); // Thực hiện đăng nhập lại } ``` ### 2. Keep Alive ```typescript // Giữ session active setInterval(async () => { try { await api.keepAlive(); console.log('Keep alive thành công'); } catch (error) { console.error('Keep alive thất bại:', error.message); } }, 5 * 60 * 1000); // 5 phút ``` ### 3. Refresh Session ```typescript async function refreshSession() { try { // Thử các API đơn giản để kiểm tra session await api.getOwnId(); return true; } catch (error) { console.log('Session hết hạn, đăng nhập lại...'); // Đăng nhập lại bằng credentials đã lưu const savedCredentials = loadCredentials(); if (savedCredentials) { try { const newApi = await zalo.login(savedCredentials); return newApi; } catch (loginError) { console.error('Không thể đăng nhập lại:', loginError.message); return false; } } return false; } } ``` ## Xử Lý Lỗi ### 1. Các Lỗi Thường Gặp ```typescript import { ZaloApiError } from 'zalo-personal-sdk'; try { const api = await zalo.login(credentials); } catch (error) { if (error instanceof ZaloApiError) { switch (error.message) { case 'Missing required params': console.error('Thiếu thông tin đăng nhập bắt buộc'); break; case 'Đăng nhập thất bại': console.error('Cookie không hợp lệ hoặc hết hạn'); break; case 'Khởi tạo ngữ cảnh thất bại': console.error('Lỗi khởi tạo session'); break; default: console.error('Lỗi không xác định:', error.message); } } else { console.error('Lỗi hệ thống:', error); } } ``` ### 2. Retry Logic ```typescript async function loginWithRetry(credentials, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { console.log(`Thử đăng nhập lần ${attempt}...`); const api = await zalo.login(credentials); console.log('Đăng nhập thành công!'); return api; } catch (error) { console.error(`Lần thử ${attempt} thất bại:`, error.message); if (attempt === maxRetries) { throw new Error(`Đăng nhập thất bại sau ${maxRetries} lần thử`); } // Chờ trước khi thử lại await new Promise(resolve => setTimeout(resolve, 2000 * attempt)); } } } ``` ## Bảo Mật ### 1. Bảo Vệ Credentials ```typescript // KHÔNG hard-code credentials trong code // ✗ Sai const credentials = { cookie: [{ name: 'session', value: 'abc123...' }] }; // ✓ Đúng const credentials = { cookie: JSON.parse(process.env.ZALO_COOKIES), imei: process.env.ZALO_IMEI, userAgent: process.env.ZALO_USER_AGENT }; ``` ### 2. Mã Hóa Credentials ```typescript const crypto = require('crypto'); function encryptCredentials(credentials, secretKey) { const cipher = crypto.createCipher('aes-256-cbc', secretKey); let encrypted = cipher.update(JSON.stringify(credentials), 'utf8', 'hex'); encrypted += cipher.final('hex'); return encrypted; } function decryptCredentials(encryptedData, secretKey) { const decipher = crypto.createDecipher('aes-256-cbc', secretKey); let decrypted = decipher.update(encryptedData, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return JSON.parse(decrypted); } ``` ### 3. Validate Credentials ```typescript function validateCredentials(credentials) { if (!credentials.imei || typeof credentials.imei !== 'string') { throw new Error('IMEI không hợp lệ'); } if (!credentials.cookie || !Array.isArray(credentials.cookie)) { throw new Error('Cookie không hợp lệ'); } if (!credentials.userAgent || typeof credentials.userAgent !== 'string') { throw new Error('User Agent không hợp lệ'); } return true; } ``` ## Ví Dụ Hoàn Chỉnh ```typescript import { Zalo, ZaloApiError } from 'zalo-personal-sdk'; import fs from 'fs/promises'; class ZaloAuth { private zalo: Zalo; private api: any = null; constructor() { this.zalo = new Zalo({ selfListen: false, logLevel: 'info' }); } async loginWithCredentials(credentialsPath: string) { try { const credentialsData = await fs.readFile(credentialsPath, 'utf8'); const credentials = JSON.parse(credentialsData); validateCredentials(credentials); this.api = await this.zalo.login(credentials); console.log('✅ Đăng nhập thành công!'); return this.api; } catch (error) { console.error('❌ Lỗi đăng nhập:', error.message); throw error; } } async loginWithQR(qrPath?: string) { return new Promise((resolve, reject) => { const options = { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', language: 'vi', qrPath: qrPath || './qr-login.png' }; this.zalo.loginQR(options, (event) => { switch (event.type) { case 'qr_code_generated': console.log('📱 Vui lòng quét QR code tại:', event.data.qrCodePath); break; case 'logged_in': console.log('✅ Đăng nhập QR thành công!'); resolve(event.api); break; case 'got_login_info': // Lưu credentials để lần sau sử dụng this.saveCredentials(event.data); break; case 'error': reject(new Error(event.data.error)); break; } }).then(api => { this.api = api; }).catch(reject); }); } private async saveCredentials(loginData: any) { const credentials = { imei: loginData.imei, cookie: loginData.cookie, userAgent: loginData.userAgent, language: 'vi', savedAt: new Date().toISOString() }; await fs.writeFile('./credentials.json', JSON.stringify(credentials, null, 2)); console.log('💾 Đã lưu credentials'); } getApi() { if (!this.api) { throw new Error('Chưa đăng nhập. Vui lòng gọi login trước.'); } return this.api; } } // Sử dụng async function main() { const auth = new ZaloAuth(); try { // Thử đăng nhập bằng credentials đã lưu await auth.loginWithCredentials('./credentials.json'); } catch (error) { console.log('Không thể đăng nhập bằng credentials, sử dụng QR...'); await auth.loginWithQR(); } const api = auth.getApi(); // Test API const ownId = await api.getOwnId(); console.log('🆔 ID của bạn:', ownId); } main().catch(console.error); ``` ## Lưu Ý Quan Trọng 1. **Cookie Expiry**: Cookie có thể hết hạn, cần xử lý đăng nhập lại 2. **Rate Limiting**: Không đăng nhập quá nhiều lần trong thời gian ngắn 3. **User Agent**: Sử dụng User Agent thật, không fake 4. **Security**: Không chia sẻ credentials với người khác 5. **Backup**: Luôn backup credentials ở nơi an toàn 6. **Environment**: Sử dụng environment variables cho production