typed-wx-api
Version:
Typed Wechat API
118 lines • 4.6 kB
JavaScript
;
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