Files
wechat-access-unqclawed/http/crypto-utils.ts
HenryXiaoYang ba754ccc31 feat: add WeChat QR code login and AGP WebSocket channel plugin
- Auth module: WeChat OAuth2 scan-to-login flow with terminal QR code
- Token persistence to ~/.openclaw/wechat-access-auth.json (chmod 600)
- Token resolution: config > saved state > interactive login
- Invite code verification (configurable bypass)
- Production/test environment support
- AGP WebSocket client with heartbeat, reconnect, wake detection
- Message handler: Agent dispatch with streaming text and tool calls
- Random device GUID generation (persisted, no real machine ID)
2026-03-10 02:29:06 +08:00

97 lines
3.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================
// 加密解密工具
// ============================================
// 处理微信服务号的消息加密、解密和签名验证
// 微信使用 AES-256-CBC 加密算法和 SHA-1 签名算法
/**
* 验证签名参数接口
* @property token - 微信服务号配置的 Token
* @property timestamp - 时间戳
* @property nonce - 随机数
* @property encrypt - 加密的消息内容
* @property signature - 微信生成的签名,用于验证消息来源
*/
export interface VerifySignatureParams {
token: string;
timestamp: string;
nonce: string;
encrypt: string;
signature: string;
}
/**
* 解密消息参数接口
* @property encodingAESKey - 微信服务号配置的 EncodingAESKey43位字符
* @property receiveId - 接收方 ID通常是服务号的原始 ID
* @property encrypt - 加密的消息内容Base64 编码)
*/
export interface DecryptMessageParams {
encodingAESKey: string;
receiveId: string;
encrypt: string;
}
/**
* 验证微信消息签名
* @param params - 签名验证参数
* @returns 签名是否有效
* @description
* 验证流程:
* 1. 将 token、timestamp、nonce、encrypt 按字典序排序
* 2. 拼接成字符串
* 3. 进行 SHA-1 哈希
* 4. 与微信提供的 signature 比对
*
* **注意:当前为简化实现,生产环境需要实现真实的 SHA-1 签名验证**
*/
export const verifySignature = (params: VerifySignatureParams): boolean => {
// TODO: 实现真实的签名验证逻辑
// 参考算法:
// const arr = [params.token, params.timestamp, params.nonce, params.encrypt].sort();
// const str = arr.join('');
// const hash = crypto.createHash('sha1').update(str).digest('hex');
// return hash === params.signature;
console.log("[wechat-access] 验证签名参数:", params);
return true; // 简化实现,直接返回 true
};
/**
* 解密微信消息
* @param params - 解密参数
* @returns 解密后的明文消息JSON 字符串)
* @description
* 解密流程:
* 1. 将 Base64 编码的 encrypt 解码为二进制
* 2. 使用 AES-256-CBC 算法解密(密钥由 encodingAESKey 派生)
* 3. 去除填充PKCS7
* 4. 提取消息内容格式随机16字节 + 4字节消息长度 + 消息内容 + receiveId
* 5. 验证 receiveId 是否匹配
*
* **注意:当前为简化实现,返回模拟数据,生产环境需要实现真实的 AES 解密**
*/
export const decryptMessage = (params: DecryptMessageParams): string => {
// TODO: 实现真实的解密逻辑
// 参考算法:
// const key = Buffer.from(params.encodingAESKey + '=', 'base64');
// const iv = key.slice(0, 16);
// const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
// decipher.setAutoPadding(false);
// let decrypted = Buffer.concat([decipher.update(params.encrypt, 'base64'), decipher.final()]);
// // 去除 PKCS7 填充
// const pad = decrypted[decrypted.length - 1];
// decrypted = decrypted.slice(0, decrypted.length - pad);
// // 提取消息内容
// const content = decrypted.slice(16);
// const msgLen = content.readUInt32BE(0);
// const message = content.slice(4, 4 + msgLen).toString('utf8');
// const receiveId = content.slice(4 + msgLen).toString('utf8');
// if (receiveId !== params.receiveId) throw new Error('receiveId mismatch');
// return message;
console.log("[wechat-access] 解密参数:", params);
// 返回模拟的解密结果(标准微信消息格式)
return '{"msgtype":"text","Content":"Hello from 服务号","MsgId":"123456","FromUserName":"user001","ToUserName":"gh_test","CreateTime":1234567890}';
};