UNPKG

typed-wx-api

Version:
118 lines 4.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.APICrypto = void 0; const crypto_1 = __importDefault(require("crypto")); const api_base_1 = require("./api_base"); const errors_1 = require("../errors"); /** * @internal */ class APICrypto extends api_base_1.APIBase { /** * AES算法pkcs7 padding Decoder * @param buff 需要解码的Buffer * @returns {Blob|ArrayBuffer|Array.<T>|string|*} * @constructor */ pkcs7Decoder(buff) { let pad = buff[buff.length - 1]; if (pad < 1 || pad > 32) { pad = 0; } return buff.slice(0, buff.length - pad); } /** * AES算法pkcs7 padding Encoder * @param buff 需要编码码的Buffer * @returns {Blob|ArrayBuffer|Array.<T>|string|*} * @constructor */ pkcs7Encoder(buff) { const blockSize = 32; const strSize = buff.length; const amountToPad = blockSize - (strSize % blockSize); const pad = new Buffer(amountToPad - 1); pad.fill(String.fromCharCode(amountToPad)); return Buffer.concat([buff, pad]); } /** * 初始化AES解密的配置信息 * @param corpId 企业微信的corpId,当为第三方套件回调事件时,corpId的内容为suiteId * @param token 企业微信的token,当为第三方套件回调事件时,token的内容为套件的token * @param encodingAESKey 企业微信的encodingAESKey,当为第三方套件回调事件时,encodingAESKey的内容为套件的encodingAESKey */ initCrypto(corpId, token, encodingAESKey) { const aesKey = new Buffer(encodingAESKey + '=', 'base64'); this.cryptoConfig = { corpId, token, aesKey, iv: aesKey.slice(0, 16) }; } /** * 生成签名 * @param timestamp String|Number 时间戳 * @param nonce String 随机串 * @param encrypt String 加密的数据 * @returns {*} String 排好序的签名 */ rawSignature(timestamp, nonce, encrypt) { const { token } = this.cryptoConfig; const rawList = [token, timestamp, nonce]; if (encrypt) rawList.push(encrypt); const rawStr = rawList.sort().join(''); const sha1 = crypto_1.default.createHash('sha1'); sha1.update(rawStr); return sha1.digest('hex'); } /** * 对给定的消息进行AES加密 * @param msg String 需要加密的明文 * @param corpId 可选 需要对比的corpId,如果第三方回调时默认是suiteId,也可自行传入作为匹配处理 * @returns {string} 加密后的结果 */ encrypt(message, corpId) { const { aesKey, iv } = this.cryptoConfig; corpId = corpId || this.cryptoConfig.corpId; const msgBuffer = new Buffer(message); const random16 = crypto_1.default.pseudoRandomBytes(16); const msgLen = new Buffer(4); msgLen.writeUInt32BE(msgBuffer.length, 0); const rawMsg = Buffer.concat([ random16, msgLen, msgBuffer, new Buffer(corpId) ]); const cipher = crypto_1.default.createCipheriv('aes-256-cbc', aesKey, iv); const cipheredMsg = Buffer.concat([cipher.update(rawMsg), cipher.final()]); return cipheredMsg.toString('base64'); } /** * 对给定的密文进行AES解密 * @param str 需要解密的密文 * @param corpId 可选 需要对比的corpId,如果第三方回调时默认是suiteId,也可自行传入作为匹配处理 * @returns {string} 解密后的结果 */ decrypt(str, corpId) { const { aesKey, iv } = this.cryptoConfig; corpId = corpId || this.cryptoConfig.corpId; const aesCipher = crypto_1.default.createDecipheriv('aes-256-cbc', aesKey, iv); aesCipher.setAutoPadding(false); const decipheredBuff = this.pkcs7Decoder(Buffer.concat([aesCipher.update(str, 'base64'), aesCipher.final()])); const data = decipheredBuff.slice(16); const msgLen = data.slice(0, 4).readUInt32BE(0); const decryptCorpId = data.slice(msgLen + 4).toString(); if (corpId !== decryptCorpId) { throw new errors_1.WxAPIError('corpId is invalid', 400); } return data.slice(4, msgLen + 4).toString(); } } exports.APICrypto = APICrypto; //# sourceMappingURL=api_crypto.js.map