ddinit
Version:
封装了一些常用的钉钉小程序服务端API,获取员工周期性打卡结果(每日,任意时间,上周,上月...),在/离职员工列表,获取用户/部门信息、发送工作消息、审批流等
137 lines (113 loc) • 3.81 kB
text/typescript
import * as crypto from 'crypto'
/**
* 提供基于PKCS7算法的加解密接口
*
*/
const PKCS7Encoder: any = {}
/**
* 删除解密后明文的补位字符
*
* @param {String} text 解密后的明文
*/
PKCS7Encoder.decode = (text) => {
let pad = text[text.length - 1]
if (pad < 1 || pad > 32) {
pad = 0
}
return text.slice(0, text.length - pad)
}
/**
* 对需要加密的明文进行填充补位
*
* @param {String} text 需要进行填充补位操作的明文
*/
PKCS7Encoder.encode = function(text) {
const blockSize = 32
const textLength = text.length
// 计算需要填充的位数
const amountToPad = blockSize - (textLength % blockSize)
const result = new Buffer(amountToPad)
result.fill(amountToPad)
return Buffer.concat([text, result])
}
/**
* 加解密信息构造函数
*
* @param {String} token 第三方企业E应用平台上,开发者设置的Token
* @param {String} encodingAESKey 第三方企业E应用平台上,开发者设置的EncodingAESKey
* @param {String} id 对于ISV来说,填写对应的suitekey; 对于普通企业开发,填写企业的Corpid
*/
function DDBizMsgCrypt(token, encodingAESKey, id) {
if (!token || !encodingAESKey || !id) {
throw new Error('please check arguments')
}
this.token = token
this.id = id
const AESKey = new Buffer(encodingAESKey + '=', 'base64')
if (AESKey.length !== 32) {
throw new Error('encodingAESKey invalid')
}
this.key = AESKey
this.iv = AESKey.slice(0, 16)
}
/**
* 获取签名
*
* @param {String} timestamp 时间戳
* @param {String} nonce 随机数
* @param {String} encrypt 加密后的文本
*/
DDBizMsgCrypt.prototype.getSignature = function(timestamp, nonce, encrypt) {
const shasum = crypto.createHash('sha1')
const arr = [this.token, timestamp, nonce, encrypt].sort()
shasum.update(arr.join(''))
return shasum.digest('hex')
}
/**
* 对密文进行解密
*
* @param {String} text 待解密的密文
*/
DDBizMsgCrypt.prototype.decrypt = function(text) {
// 创建解密对象,AES采用CBC模式,数据采用PKCS#7填充;IV初始向量大小为16字节,取AESKey前16字节
const decipher = crypto.createDecipheriv('aes-256-cbc', this.key, this.iv)
decipher.setAutoPadding(false)
let deciphered = Buffer.concat([
decipher.update(text, 'base64'),
decipher.final()
])
deciphered = PKCS7Encoder.decode(deciphered)
// 算法:AES_Encrypt[random(16B) + msg_len(4B) + msg + $CorpID]
// 去除16位随机数
const content = deciphered.slice(16)
const length = content.slice(0, 4).readUInt32BE(0)
return {
message: content.slice(4, length + 4).toString(),
id: content.slice(length + 4).toString()
}
}
/**
* 对明文进行加密
*
* @param {String} text 待加密的明文
*/
DDBizMsgCrypt.prototype.encrypt = function(text) {
// 算法:AES_Encrypt[random(16B) + msg_len(4B) + msg + $CorpID]
// 获取16B的随机字符串
const randomString = crypto.pseudoRandomBytes(16)
const msg = new Buffer(text)
// 获取4B的内容长度的网络字节序
const msgLength = new Buffer(4)
msgLength.writeUInt32BE(msg.length, 0)
const id = new Buffer(this.id)
const bufMsg = Buffer.concat([randomString, msgLength, msg, id])
// 对明文进行补位操作
const encoded = PKCS7Encoder.encode(bufMsg)
// 创建加密对象,AES采用CBC模式,数据采用PKCS#7填充;IV初始向量大小为16字节,取AESKey前16字节
const cipher = crypto.createCipheriv('aes-256-cbc', this.key, this.iv)
cipher.setAutoPadding(false)
const cipheredMsg = Buffer.concat([cipher.update(encoded), cipher.final()])
// 返回加密数据的base64编码
return cipheredMsg.toString('base64')
}
export default DDBizMsgCrypt