Files
2026-01-12 18:01:04 +08:00

95 lines
3.7 KiB
JavaScript

import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { getSignature, decrypt, encrypt } from '@wecom/crypto';
import { parseStringPromise } from 'xml2js';
function validateSignature(msgSignature, timestamp, nonce, encrypt) {
const { WEIXIN_EVENT_TOKEN, } = process.env;
if (!WEIXIN_EVENT_TOKEN)
throw new Error('static param error');
const devMsgSignature = getSignature(WEIXIN_EVENT_TOKEN, timestamp, nonce, encrypt);
return devMsgSignature === msgSignature;
}
export async function handleServer() {
const app = new Hono();
app.get('/we-comp/event', ({ req, ...args }) => {
try {
const { 'msg_signature': msgSignature, timestamp, nonce, echostr } = req.query();
const { WEIXIN_EVENT_TOKEN, WEIXIN_EVENT_ENCODING_AES_KEY, } = process.env;
if (!WEIXIN_EVENT_TOKEN
|| !WEIXIN_EVENT_ENCODING_AES_KEY
|| !msgSignature
|| !timestamp
|| !nonce
|| !echostr) {
throw new Error('static param error');
}
if (!validateSignature(msgSignature, timestamp, nonce, echostr)) {
throw new Error('validate error');
}
const { message, id } = decrypt(WEIXIN_EVENT_ENCODING_AES_KEY, echostr);
console.log('URL验证成功,解密后的消息:', message);
console.log('接收者ID:', id);
}
catch (e) {
console.error(e);
}
return args.text("");
});
app.post('/we-comp/event', async ({ req, ...args }) => {
const { 'msg_signature': msgSignature, timestamp, nonce } = req.query();
try {
const result = await parseStringPromise(await req.text());
const encrypt = result.xml.Encrypt.at(0);
const { WEIXIN_EVENT_TOKEN, WEIXIN_EVENT_ENCODING_AES_KEY, } = process.env;
if (!WEIXIN_EVENT_TOKEN
|| !WEIXIN_EVENT_ENCODING_AES_KEY
|| !msgSignature
|| !timestamp
|| !nonce) {
throw new Error('static param error');
}
// 2. 验证签名
if (!validateSignature(msgSignature, timestamp, nonce, encrypt)) {
throw new Error('签名验证失败');
}
const { message, id } = decrypt(WEIXIN_EVENT_ENCODING_AES_KEY, encrypt);
console.log('解密后的消息:', message);
console.log('接收者ID:', id);
// 5. 解析明文XML
const decryptedXml = await parseStringPromise(message);
const msgData = decryptedXml.xml;
const msgType = msgData.MsgType?.[0];
const fromUserName = msgData.FromUserName?.[0];
const toUserName = msgData.ToUserName?.[0];
const createTime = msgData.CreateTime?.[0];
console.log('========== 消息详情 ==========');
console.log('消息类型:', msgType);
console.log('发送者:', fromUserName);
console.log('接收者:', toUserName);
console.log('创建时间:', createTime);
console.log('============================');
}
catch (e) {
console.error(e);
}
return args.text('');
});
const server = serve({
fetch: app.fetch,
port: 3080,
});
process.on('SIGINT', () => {
server.close();
process.exit(0);
});
process.on('SIGTERM', () => {
server.close((err) => {
if (err) {
console.error(err);
process.exit(1);
}
process.exit(0);
});
});
}
//# sourceMappingURL=server.js.map