n8n-nodes-zalo-oa-integration
Version:
Tích hợp Zalo Official Account API v3.0 vào n8n
289 lines • 11.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZaloOAWebhook = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const crypto = __importStar(require("crypto"));
class ZaloOAWebhook {
constructor() {
this.description = {
displayName: 'Zalo OA Webhook',
name: 'zaloOAWebhook',
icon: 'file:zalooa.svg',
group: ['trigger'],
version: 1,
description: 'Xử lý các sự kiện webhook từ Zalo OA',
defaults: {
name: 'Zalo OA Webhook',
},
inputs: [],
outputs: ["main"],
credentials: [
{
name: 'zaloOAApi',
required: true,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'OA Secret Key',
name: 'oaSecretKey',
type: 'string',
default: '',
required: true,
description: 'OA Secret Key từ trang quản lý Zalo OA',
typeOptions: {
password: true,
},
},
{
displayName: 'Các Loại Sự Kiện',
name: 'events',
type: 'multiOptions',
options: [
{
name: 'Người Dùng Follow OA',
value: 'follow',
description: 'Khi người dùng bắt đầu theo dõi OA',
},
{
name: 'Người Dùng Unfollow OA',
value: 'unfollow',
description: 'Khi người dùng hủy theo dõi OA',
},
{
name: 'Người Dùng Gửi Tin Nhắn Văn Bản',
value: 'user_send_text',
description: 'Khi người dùng gửi tin nhắn văn bản',
},
{
name: 'Người Dùng Gửi Hình Ảnh',
value: 'user_send_image',
description: 'Khi người dùng gửi hình ảnh',
},
{
name: 'Người Dùng Gửi File',
value: 'user_send_file',
description: 'Khi người dùng gửi file',
},
{
name: 'Người Dùng Gửi Vị Trí',
value: 'user_send_location',
description: 'Khi người dùng gửi vị trí',
},
{
name: 'Người Dùng Gửi Sticker',
value: 'user_send_sticker',
description: 'Khi người dùng gửi sticker',
},
{
name: 'Người Dùng Gửi GIF',
value: 'user_send_gif',
description: 'Khi người dùng gửi GIF',
},
{
name: 'Người Dùng Nhấp Vào Nút',
value: 'user_click_button',
description: 'Khi người dùng nhấp vào nút trong tin nhắn',
},
{
name: 'Người Dùng Nhấp Vào Liên Kết',
value: 'user_click_link',
description: 'Khi người dùng nhấp vào liên kết trong tin nhắn',
},
{
name: 'Tất Cả Sự Kiện',
value: 'all',
description: 'Nhận tất cả các loại sự kiện',
},
],
default: ['all'],
required: true,
description: 'Các loại sự kiện muốn nhận từ Zalo OA',
},
{
displayName: 'Xác Thực Mac',
name: 'validateMac',
type: 'boolean',
default: true,
description: 'Xác thực chữ ký MAC từ Zalo OA để đảm bảo an toàn',
},
],
};
}
async webhook() {
const req = this.getRequestObject();
const headerData = this.getHeaderData();
const oaSecretKey = this.getNodeParameter('oaSecretKey');
const validateMac = this.getNodeParameter('validateMac');
const events = this.getNodeParameter('events');
if (req.method === 'GET') {
const query = this.getQueryData();
if (Object.prototype.hasOwnProperty.call(query, 'hub.challenge')) {
return {
workflowData: [[
{
json: {
event_type: 'webhook_verification',
challenge: query['hub.challenge'],
timestamp: new Date().toISOString(),
},
},
]],
webhookResponse: query['hub.challenge'],
};
}
}
if (req.method === 'POST') {
try {
const body = req.body;
if (validateMac) {
const mac = headerData.mac;
if (!mac) {
return {
workflowData: [[
{
json: {
event_type: 'error',
error: 'Missing MAC header',
timestamp: new Date().toISOString(),
},
},
]],
webhookResponse: {
statusCode: 401,
body: {
error: 'Missing MAC header',
},
},
};
}
const data = JSON.stringify(body);
const calculatedMac = crypto.createHmac('sha256', oaSecretKey)
.update(data)
.digest('hex');
if (mac !== calculatedMac) {
return {
workflowData: [[
{
json: {
event_type: 'error',
error: 'Invalid MAC',
timestamp: new Date().toISOString(),
},
},
]],
webhookResponse: {
statusCode: 401,
body: {
error: 'Invalid MAC',
},
},
};
}
}
const eventType = body.event_name;
if (!events.includes('all') && !events.includes(eventType)) {
return {
workflowData: [[
{
json: {
event_type: 'ignored',
original_event: eventType,
message: 'Event ignored - not in selected events',
timestamp: new Date().toISOString(),
},
},
]],
webhookResponse: {
statusCode: 200,
body: {
message: 'Event ignored',
},
},
};
}
const returnData = [];
returnData.push({
json: {
...body,
event_type: eventType,
timestamp: new Date().toISOString(),
},
});
return {
workflowData: [returnData],
webhookResponse: {
statusCode: 200,
body: {
message: 'Webhook received',
},
},
};
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error);
}
}
return {
workflowData: [[
{
json: {
event_type: 'error',
error: 'Method not allowed',
method: req.method,
timestamp: new Date().toISOString(),
},
},
]],
webhookResponse: {
statusCode: 405,
body: {
error: 'Method not allowed',
},
},
};
}
}
exports.ZaloOAWebhook = ZaloOAWebhook;
//# sourceMappingURL=ZaloOAWebhook.node.js.map