UNPKG

n8n-nodes-zalo-nnt

Version:

Unofficial Zalo integration for n8n - Send messages, manage groups, user operations with QR login. No API key required, works via browser simulation.

322 lines 18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZaloLoginByQr = void 0; const n8n_workflow_1 = require("n8n-workflow"); const zca_js_1 = require("zca-js"); const axios_1 = __importDefault(require("axios")); const branding_1 = require("../shared/branding"); class ZaloLoginByQr { constructor() { this.description = { displayName: 'Zalo Đăng nhập QR by diginno.net', name: 'zaloLoginByQr', group: ['Zalo'], version: 1, description: 'Đăng nhập Zalo bằng QR code và lưu thông tin vào Credential by diginno.net', defaults: { name: 'Zalo Đăng nhập QR by diginno.net', }, inputs: ['main'], outputs: ['main'], icon: 'file:../shared/image.svg', credentials: [ { name: 'n8nApiZaloApi', required: true, displayName: 'n8n API Account (Required - only API Key & URL)', }, ], properties: [ branding_1.BRANDING_CONFIG, { displayName: '📺 Xem video hướng dẫn chi tiết tại <a href="https://www.youtube.com/watch?v=iwziXxQoW_Q" target="_blank" style="color: #1890ff; text-decoration: underline;">YouTube</a>', name: 'videoTutorial', type: 'notice', default: '', }, { displayName: 'Proxy', name: 'proxy', type: 'string', default: '', placeholder: 'https://user:pass@host:port', description: 'HTTP proxy to use for Zalo API requests', }, ], }; } async execute() { const returnData = []; const proxy = this.getNodeParameter('proxy', 0, ''); const timeout = 30; const fileName = 'zalo-qr-code.png'; let n8nCredential; try { n8nCredential = await this.getCredentials('n8nApiZaloApi'); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'n8n API credentials are required for QR login'); } console.error('Using n8n account credential for QR login'); try { const zaloOptions = { selfListen: true, logging: true, }; if (proxy) { zaloOptions.proxy = proxy; } const zalo = new zca_js_1.Zalo(zaloOptions); console.error('Starting Zalo QR login process...'); const processContext = (context) => { if (!context) { console.error('Context is null or undefined'); return; } const cookie = context.cookie || ''; const imei = context.imei || ''; const userAgent = context.userAgent || ''; console.error('=== ZALO CREDENTIALS ==='); console.error('Cookie:', cookie ? `Received (length: ${typeof cookie === 'string' ? cookie.length : Array.isArray(cookie) ? cookie.length : 'unknown'})` : 'None'); console.error('IMEI:', imei ? imei : 'None'); console.error('User Agent:', userAgent ? userAgent : 'None'); console.error('=== END CREDENTIALS ==='); }; const setupEventListeners = (api) => { console.error('Setting up event listeners to get credentials'); try { if (typeof api.getContext === 'function') { const contextResult = api.getContext(); if (contextResult && typeof contextResult.then === 'function') { contextResult .then((context) => { processContext(context); }) .catch((error) => { console.error('Error getting context:', error); }); } else { processContext(contextResult); } } else { console.error('getContext is not a function'); if (api.context) { console.error('Found context in api object'); processContext(api.context); } else { console.error('No context found in api object'); } } } catch (error) { console.error('Error in setupEventListeners:', error); } }; const qrCodePromise = new Promise(async (resolve, reject) => { let isResolved = false; let userDisplayName = ''; let userPhone = ''; const timeoutId = setTimeout(() => { if (!isResolved) { isResolved = true; reject(new n8n_workflow_1.NodeOperationError(this.getNode(), 'Timeout generating QR code. Please try again or check your Zalo connection.')); } }, timeout * 1000); try { let api = await zalo.loginQR(null, (qrEvent) => { var _a, _b; console.error('Received QR event type:', qrEvent ? qrEvent.type : 'no event'); switch (qrEvent.type) { case 0: if ((_a = qrEvent === null || qrEvent === void 0 ? void 0 : qrEvent.data) === null || _a === void 0 ? void 0 : _a.image) { const qrCodeBase64 = qrEvent.data.image; console.error('QR code generated, length:', qrCodeBase64.length); if (isResolved) return; clearTimeout(timeoutId); if (qrCodeBase64) { isResolved = true; resolve(qrCodeBase64); } } else { console.error('Could not get QR code from Zalo SDK'); reject(new Error('Could not get QR code')); } break; case 1: console.error('QR code expired. Please try again.'); break; case 2: console.error('=== QR CODE SCANNED ==='); if (qrEvent === null || qrEvent === void 0 ? void 0 : qrEvent.data) { console.error('User:', qrEvent.data.display_name); console.error('Avatar:', qrEvent.data.avatar ? 'Yes' : 'No'); userDisplayName = qrEvent.data.display_name || ''; if (qrEvent.data.phone) { userPhone = qrEvent.data.phone; } } break; case 3: console.error('=== QR CODE DECLINED ==='); if ((_b = qrEvent === null || qrEvent === void 0 ? void 0 : qrEvent.data) === null || _b === void 0 ? void 0 : _b.code) { console.error('Decline code:', qrEvent.data.code); } break; case 4: console.error('=== GOT LOGIN INFO ==='); if (qrEvent === null || qrEvent === void 0 ? void 0 : qrEvent.data) { const cookie = qrEvent.data.cookie || []; const imei = qrEvent.data.imei || ''; const userAgent = qrEvent.data.userAgent || ''; console.error('Cookie received:', cookie.length > 0 ? 'Yes' : 'No'); console.error('IMEI received:', imei ? 'Yes' : 'No'); console.error('User Agent received:', userAgent ? 'Yes' : 'No'); try { if (cookie.length > 0 || imei || userAgent) { const now = new Date(); const vietnamTime = new Date(now.getTime()); const day = String(vietnamTime.getDate()).padStart(2, '0'); const month = String(vietnamTime.getMonth() + 1).padStart(2, '0'); const year = vietnamTime.getFullYear(); const hours = String(vietnamTime.getHours()).padStart(2, '0'); const minutes = String(vietnamTime.getMinutes()).padStart(2, '0'); const timeStr = `${day}-${month}-${year} ${hours}:${minutes}`; let credentialName = userDisplayName || 'Zalo'; if (userPhone && userPhone.length >= 3) { const last3Digits = userPhone.slice(-3); credentialName += ` ${last3Digits}`; } credentialName += ` ${timeStr}`; (async () => { try { console.error('=== CREATING ZALO CREDENTIAL ==='); const credentialApiData = { name: credentialName, type: 'zaloApi', nodesAccess: [], data: { cookie: JSON.stringify(cookie), imei: imei, userAgent: userAgent, proxy: proxy || '', supportCode: '', licenseKey: '', }, }; const n8nApi = await this.getCredentials('n8nApiZaloApi'); const n8nApiUrl = n8nApi.url.replace(/\/+$/, ''); const n8nApiKey = n8nApi.apiKey; const fullApiUrl = `${n8nApiUrl}/api/v1/credentials`; console.error(`Creating credential: ${credentialName}`); console.error(`API URL: ${fullApiUrl}`); const response = await axios_1.default.post(fullApiUrl, credentialApiData, { headers: { 'Content-Type': 'application/json', 'X-N8N-API-KEY': n8nApiKey, }, }); console.error('=== CREDENTIAL CREATED SUCCESSFULLY ==='); console.error('Response:', JSON.stringify(response.data).substring(0, 300)); } catch (error) { console.error('=== CREDENTIAL CREATION FAILED ==='); console.error('Error:', error.message); if (error.response) { console.error('Status:', error.response.status); console.error('Data:', JSON.stringify(error.response.data)); } else if (error.request) { console.error('No response - check n8n URL and if n8n is running'); } } })(); } else { console.error('=== NO CREDENTIALS TO SAVE ==='); console.error('No login information available to save'); } } catch (fileError) { console.error('Error saving credentials:', fileError.message); } } break; default: console.error('Unknown QR event type:', qrEvent.type); } }); console.error('Starting Zalo listener'); api.listener.start(); api.listener.onConnected(() => { console.error('=== ZALO SDK CONNECTED ==='); setupEventListeners(api); }); api.listener.onError((error) => { console.error('=== ZALO ERROR ===', error); }); api.listener.onMessage((message) => { console.error('=== ZALO MESSAGE RECEIVED ==='); console.error('Message type:', message.type); console.error('Message content:', JSON.stringify(message).substring(0, 200) + '...'); if (message.type === 'login_success' || message.type === 'qr_scanned') { console.error('=== QR CODE SCANNED OR LOGIN SUCCESSFUL ==='); setupEventListeners(api); } }); console.error('All event listeners set up'); } catch (error) { clearTimeout(timeoutId); if (!isResolved) { isResolved = true; reject(error); } } }); const qrCodeBase64 = await qrCodePromise; const binaryData = Buffer.from(qrCodeBase64, 'base64'); const newItem = { json: { success: true, message: 'QR code generated successfully. Scan with Zalo app to login. Credentials will be auto-created after successful login.', fileName, credentialType: 'n8nApiZaloApi', }, binary: { data: await this.helpers.prepareBinaryData(binaryData, fileName, 'image/png'), }, }; returnData.push(newItem); if (returnData[0] && returnData[0].json) { returnData[0].json.credentialInstructions = 'Using n8n API credential. New Zalo credentials will be created automatically after successful QR login.'; returnData[0].json.credentialName = n8nCredential.name || 'Unknown'; returnData[0].json.credentialId = n8nCredential.id || 'Unknown'; returnData[0].json.autoCreateApi = 'Credentials will be created automatically via n8n API after successful login.'; } return [returnData]; } catch (error) { if (this.continueOnFail()) { const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray({ error: error.message }), { itemData: { item: 0 } }); return [executionData]; } else { throw error; } } } } exports.ZaloLoginByQr = ZaloLoginByQr; //# sourceMappingURL=ZaloLoginByQr.node.js.map