提交 d5990b9c12700aad3dcff325eeba272f2ef9d1d1

作者 fanwh
0 个父辈

no message

  1 +logs/
  2 +npm-debug.log
  3 +yarn-error.log
  4 +node_modules/
  5 +package-lock.json
  6 +yarn.lock
  7 +coverage/
  8 +.idea/
  9 +run/
  10 +.DS_Store
  11 +*.sw*
  12 +*.un~
  13 +typings/
  14 +.nyc_output/
  1 +'use strict';
  2 +
  3 +class DingTalkEncryptException {
  4 + constructor(code) {
  5 + // super();
  6 + this.msgMap = new Map([
  7 + [ 0, '成功' ],
  8 + [ 900001, '加密明文文本非法' ],
  9 + [ 900002, '加密时间戳参数非法' ],
  10 + [ 900003, '加密随机字符串参数非法' ],
  11 + [ 900005, '签名不匹配' ],
  12 + [ 900006, '签名计算失败' ],
  13 + [ 900004, '不合法的 encodingAesKey' ],
  14 + [ 900007, '计算加密文字错误' ],
  15 + [ 900008, '计算解密文字错误' ],
  16 + [ 900009, '计算解密文字长度不匹配' ],
  17 + [ 900010, '计算解密文字corpid不匹配' ],
  18 + ]);
  19 + this.code = code;
  20 + this.message = this.msgMap.get(code);
  21 + }
  22 +
  23 + toString(){
  24 + return `DingTalkEncryptException: [${this.code}], ${this.message}\n`;
  25 + }
  26 +}
  27 +
  28 +module.exports = DingTalkEncryptException;
  1 +/* eslint-disable no-bitwise */
  2 +'use strict';
  3 +
  4 +const CryptoJS = require("crypto-js");
  5 +const Crypto = require('crypto');
  6 +const DingTalkEncryptException = require('./DingTalkEncryptException');
  7 +
  8 +class DingTalkEncryptor {
  9 + constructor(token, encodingAesKey, corpIdOrSuiteKey) {
  10 + this.utf8 = 'utf-8';
  11 + this.base64 = 'base64';
  12 + this.AES_ENCODE_KEY_LENGTH = 43;
  13 + this.RANDOM_LENGTH = 16;
  14 +
  15 + this.token = token;
  16 + this.encodingAesKey = encodingAesKey;
  17 + this.aesKey = CryptoJS.enc.Base64.parse(encodingAesKey+'=');
  18 + this.corpId = corpIdOrSuiteKey;
  19 + this.keySpec = this.aesKey;
  20 + this.iv = CryptoJS.enc.Base64.parse((encodingAesKey+'=').substring(0,22));
  21 + }
  22 +
  23 + // verify encodingAesKey
  24 + set encodingAesKey(val) {
  25 + if (!val || val.length !== this.AES_ENCODE_KEY_LENGTH) {
  26 + throw new DingTalkEncryptException(900004);
  27 + }
  28 + }
  29 +
  30 + encrypt(random, plainText) {
  31 + try {
  32 + const randomBuf = Buffer.from(random);
  33 + const plainTextBuf = Buffer.from(plainText);
  34 + const textLen = plainTextBuf.length;
  35 + const textLenBuf = Buffer.from([(textLen >> 24 & 255), (textLen >> 16 & 255), (textLen >> 8 & 255), (textLen & 255)]);
  36 + const cropIdBuf = Buffer.from(this.corpId);
  37 + const padCount = 32 - (randomBuf.length + textLenBuf.length + plainTextBuf.length + cropIdBuf.length) % 32;
  38 + const padBuf = Buffer.from(new Array(padCount).fill(padCount));
  39 + const finalBuf = Buffer.concat([randomBuf, textLenBuf, plainTextBuf, cropIdBuf, padBuf]);
  40 + console.log("randomBuf@@@",randomBuf.toString('utf-8'))
  41 + console.log("plainTextBuf@@@",plainTextBuf.toString('utf-8'))
  42 + console.log("textLenBuf@@@",textLen,textLenBuf.toString('hex'))
  43 + console.log("cropIdBuf@@@",cropIdBuf.toString('utf-8'))
  44 + console.log("padCount@@@",padCount )
  45 + console.log("padBuf@@@",padBuf)
  46 + console.log("finalBuf@@@",finalBuf.toString('hex'))
  47 +
  48 + const encrypted = CryptoJS.AES.encrypt(finalBuf.toString('hex'), this.keySpec, {
  49 + iv: this.iv,
  50 + mode: CryptoJS.mode.CBC,
  51 + padding:CryptoJS.pad.Pkcs7
  52 + });
  53 + return encrypted.toString(CryptoJS.enc.Base64);
  54 + } catch (e) {
  55 + console.log(e)
  56 + throw new DingTalkEncryptException(900007);
  57 + }
  58 + }
  59 +
  60 + decrypt(encrypted) {
  61 + let decrypt;
  62 + try {
  63 + // decrypt
  64 + const ciphertext = CryptoJS.enc.Base64.parse(encrypted);
  65 + decrypt = CryptoJS.AES.decrypt( {ciphertext}, this.keySpec, {
  66 + iv: this.iv,
  67 + mode: CryptoJS.mode.CBC,
  68 + padding:CryptoJS.pad.Pkcs7
  69 + });
  70 + } catch (e) {
  71 + throw new DingTalkEncryptException(900008);
  72 + }
  73 + //encrypt = Base64_Encode(AES_Encrypt[random(16B) + msg_len(4B) + msg + $key]) 钉钉加密消息格式
  74 + let cropId;
  75 + let plainText;
  76 + try {
  77 +
  78 + const finalDecrypt = decrypt.toString(CryptoJS.enc.Hex);
  79 + const textLen = parseInt(finalDecrypt.substring(32,8+32), 16) ;
  80 + plainText = CryptoJS.enc.Hex.parse(finalDecrypt.substring(40, 40 + textLen*2)).toString( CryptoJS.enc.Utf8);
  81 + cropId = CryptoJS.enc.Hex.parse(finalDecrypt.substring(40 + textLen*2)).toString(CryptoJS.enc.Utf8);
  82 +
  83 + } catch (e) {
  84 + throw new DingTalkEncryptException(900009);
  85 + }
  86 +
  87 + if (cropId != this.corpId) {
  88 + console.log(cropId, this.corpId)
  89 + throw new DingTalkEncryptException(900010);
  90 + } else {
  91 + return plainText;
  92 + }
  93 + }
  94 +
  95 + getSignature(token, timestamp, nonce, encrypt) {
  96 + timestamp = timestamp + '';
  97 + const strArr = [token, timestamp, nonce, encrypt];
  98 + strArr.sort();
  99 + const sha1 = CryptoJS.SHA1(strArr.join(''));
  100 + return sha1.toString(CryptoJS.enc.Hex);
  101 + }
  102 +
  103 + getEncryptedMap(plaintext, timeStamp, nonce) {
  104 + timeStamp = timeStamp + '';
  105 + if (plaintext == null) {
  106 + throw new DingTalkEncryptException(900001);
  107 + } else if (timeStamp == null) {
  108 + throw new DingTalkEncryptException(900002);
  109 + } else if (nonce == null) {
  110 + throw new DingTalkEncryptException(900003);
  111 + } else {
  112 + const encrypt = this.encrypt(this.getRandomStr(this.RANDOM_LENGTH), plaintext);
  113 + const signature = this.getSignature(this.token, timeStamp, nonce, encrypt);
  114 + return {
  115 + msg_signature: signature,
  116 + encrypt: encrypt,
  117 + timeStamp: timeStamp,
  118 + nonce: nonce
  119 + };
  120 + }
  121 + }
  122 +
  123 + getDecryptMsg(msgSignature, timeStamp, nonce, encryptMsg) {
  124 + const signature = this.getSignature(this.token, timeStamp, nonce, encryptMsg);
  125 + if (signature !== msgSignature) {
  126 + throw new DingTalkEncryptException(900006);
  127 + } else {
  128 + return this.decrypt(encryptMsg);
  129 + }
  130 + }
  131 +
  132 + getRandomStr(size) {
  133 + const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  134 + let randomStr = '';
  135 + for (let i = size; i > 0; --i) {
  136 + randomStr += base[Math.floor(Math.random() * base.length)];
  137 + }
  138 + return randomStr;
  139 + };
  140 +}
  141 +
  142 +module.exports = DingTalkEncryptor;
  1 +'use strict';
  2 +
  3 +const DingTalkEncryptor = require('./DingTalkEncryptor');
  4 +const utils = require('./Utils');
  5 +
  6 +
  7 +// const DingTalkEncryptException = require('./DingTalkEncryptException');
  8 +
  9 +/** 加解密需要,可以随机填写。如 "12345" */
  10 +const TOKEN = 'OUOdEgcMFxNDqoiADrf';
  11 +/** 加密密钥,用于回调数据的加密,固定为43个字符,从[a-z, A-Z, 0-9]共62个字符中随机生成*/
  12 +// const ENCODING_AES_KEY = 'TXpRMU5qYzRPVEF4TWpNME5UWTNPRGt3TVRJek5EVTI';
  13 +// const ENCODING_AES_KEY = utils.getRandomStr(43);
  14 +const ENCODING_AES_KEY = 'FRArTXHBSiMuyPjOjk4RqhOLuQ54d75A6PyYbFrShJy';
  15 +// console.log('ENCODING_AES_KEY:\n' + ENCODING_AES_KEY);
  16 +// let buffer = Buffer.from(ENCODING_AES_KEY + '=', 'base64');
  17 +// const base64Str = buffer.toString('base64');
  18 +// console.log(":::::ZZ",buffer.length,base64Str.length,base64Str,(Buffer.from(ENCODING_AES_KEY + '=', 'base64')));
  19 +/** 企业corpid, 可以在钉钉企业管理后台查看(https://oa.dingtalk.com/) */
  20 +// const CORP_ID = 'ding12345678901234567890123456789012';
  21 +const CORP_ID ='dingkuvhxslusd5hkjem';
  22 +/** 实例化加密类 */
  23 +// console.log('\nEncryptor Test:');
  24 +const encryptor = new DingTalkEncryptor(TOKEN, ENCODING_AES_KEY, CORP_ID);
  25 +
  26 +// const plainText = 'success';
  27 +const ENCRYPT_RANDOM_16 = 'aaaabbbbccccdddd';
  28 +// const timeStamp = (new Date().getTime()).toString();
  29 +// const nonce = utils.getRandomStr(8);
  30 +const timeStamp = '1648014018742';
  31 +const nonce = 'AU1FFNAK';
  32 +
  33 +/** 测试加解密响应报文或者字符串 */
  34 +// const testJson = {
  35 +// EventType: 'bpms_instance_change',
  36 +// processInstanceId: 'ad253df6-e175caf-68085c60ba8a',
  37 +// corpId: 'ding2c4d8175651',
  38 +// createTime: 1495592259000,
  39 +// title: '自测-1016',
  40 +// type: 'start',
  41 +// staffId: 'er5875',
  42 +// url: 'https://aflow.dingtalk.com/dingtalk/mobile/homepage.htm',
  43 +// processCode: 'xxx',
  44 +// };
  45 +// const testJson = '中文乱码测试/abc/123dddd';
  46 +
  47 +// // console.log(JSON.parse(JSON.stringify(testJson)));
  48 +const unencryptedJson = 'success';
  49 +// const unencryptedJson = JSON.stringify(testJson);
  50 +// console.log(` node unencryptedJson:\n ${unencryptedJson}`);
  51 +// const encryptedJson = encryptor.encrypt(ENCRYPT_RANDOM_16, unencryptedJson);
  52 +// console.log(` \nnode encryptedJson:\n ${encryptedJson}`);
  53 +// const decryptedJson = encryptor.decrypt(encryptedJson);
  54 +// console.log(` \nnode decryptedJson:\n ${decryptedJson}, (${decryptedJson.length})`);
  55 +// console.log(' \nnode sign:\n ' + encryptor.getSignature(TOKEN, timeStamp, nonce, encryptedJson));
  56 +const signature = '99011aff26fe6eea2aea3b9f1c17620483e8495d';
  57 +const encryptMsg = 'kKCIt2zJ1xPfCex1h3d4ZULhLvXi3RBbht1GxAsYK/Y9iZcw06P20xGTq8Lb9bskrd7fypdzcqo0GHvk+9zLonIXPFNKRTRkswZaH+t1A5683FoDYlXOsBRgpCsjSljo';
  58 +
  59 +const plainText = encryptor.getDecryptMsg(signature, timeStamp, nonce, encryptMsg)
  60 +
  61 +
  62 +console.log("plainText::",plainText)
  63 +
  64 +const result = encryptor.getEncryptedMap(unencryptedJson, timeStamp, utils.getRandomStr(8));
  65 +
  66 +
  67 +console.log("result::",result)
  1 + Apache License
  2 + Version 2.0, January 2004
  3 + http://www.apache.org/licenses/
  4 +
  5 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  6 +
  7 + 1. Definitions.
  8 +
  9 + "License" shall mean the terms and conditions for use, reproduction,
  10 + and distribution as defined by Sections 1 through 9 of this document.
  11 +
  12 + "Licensor" shall mean the copyright owner or entity authorized by
  13 + the copyright owner that is granting the License.
  14 +
  15 + "Legal Entity" shall mean the union of the acting entity and all
  16 + other entities that control, are controlled by, or are under common
  17 + control with that entity. For the purposes of this definition,
  18 + "control" means (i) the power, direct or indirect, to cause the
  19 + direction or management of such entity, whether by contract or
  20 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
  21 + outstanding shares, or (iii) beneficial ownership of such entity.
  22 +
  23 + "You" (or "Your") shall mean an individual or Legal Entity
  24 + exercising permissions granted by this License.
  25 +
  26 + "Source" form shall mean the preferred form for making modifications,
  27 + including but not limited to software source code, documentation
  28 + source, and configuration files.
  29 +
  30 + "Object" form shall mean any form resulting from mechanical
  31 + transformation or translation of a Source form, including but
  32 + not limited to compiled object code, generated documentation,
  33 + and conversions to other media types.
  34 +
  35 + "Work" shall mean the work of authorship, whether in Source or
  36 + Object form, made available under the License, as indicated by a
  37 + copyright notice that is included in or attached to the work
  38 + (an example is provided in the Appendix below).
  39 +
  40 + "Derivative Works" shall mean any work, whether in Source or Object
  41 + form, that is based on (or derived from) the Work and for which the
  42 + editorial revisions, annotations, elaborations, or other modifications
  43 + represent, as a whole, an original work of authorship. For the purposes
  44 + of this License, Derivative Works shall not include works that remain
  45 + separable from, or merely link (or bind by name) to the interfaces of,
  46 + the Work and Derivative Works thereof.
  47 +
  48 + "Contribution" shall mean any work of authorship, including
  49 + the original version of the Work and any modifications or additions
  50 + to that Work or Derivative Works thereof, that is intentionally
  51 + submitted to Licensor for inclusion in the Work by the copyright owner
  52 + or by an individual or Legal Entity authorized to submit on behalf of
  53 + the copyright owner. For the purposes of this definition, "submitted"
  54 + means any form of electronic, verbal, or written communication sent
  55 + to the Licensor or its representatives, including but not limited to
  56 + communication on electronic mailing lists, source code control systems,
  57 + and issue tracking systems that are managed by, or on behalf of, the
  58 + Licensor for the purpose of discussing and improving the Work, but
  59 + excluding communication that is conspicuously marked or otherwise
  60 + designated in writing by the copyright owner as "Not a Contribution."
  61 +
  62 + "Contributor" shall mean Licensor and any individual or Legal Entity
  63 + on behalf of whom a Contribution has been received by Licensor and
  64 + subsequently incorporated within the Work.
  65 +
  66 + 2. Grant of Copyright License. Subject to the terms and conditions of
  67 + this License, each Contributor hereby grants to You a perpetual,
  68 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  69 + copyright license to reproduce, prepare Derivative Works of,
  70 + publicly display, publicly perform, sublicense, and distribute the
  71 + Work and such Derivative Works in Source or Object form.
  72 +
  73 + 3. Grant of Patent License. Subject to the terms and conditions of
  74 + this License, each Contributor hereby grants to You a perpetual,
  75 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  76 + (except as stated in this section) patent license to make, have made,
  77 + use, offer to sell, sell, import, and otherwise transfer the Work,
  78 + where such license applies only to those patent claims licensable
  79 + by such Contributor that are necessarily infringed by their
  80 + Contribution(s) alone or by combination of their Contribution(s)
  81 + with the Work to which such Contribution(s) was submitted. If You
  82 + institute patent litigation against any entity (including a
  83 + cross-claim or counterclaim in a lawsuit) alleging that the Work
  84 + or a Contribution incorporated within the Work constitutes direct
  85 + or contributory patent infringement, then any patent licenses
  86 + granted to You under this License for that Work shall terminate
  87 + as of the date such litigation is filed.
  88 +
  89 + 4. Redistribution. You may reproduce and distribute copies of the
  90 + Work or Derivative Works thereof in any medium, with or without
  91 + modifications, and in Source or Object form, provided that You
  92 + meet the following conditions:
  93 +
  94 + (a) You must give any other recipients of the Work or
  95 + Derivative Works a copy of this License; and
  96 +
  97 + (b) You must cause any modified files to carry prominent notices
  98 + stating that You changed the files; and
  99 +
  100 + (c) You must retain, in the Source form of any Derivative Works
  101 + that You distribute, all copyright, patent, trademark, and
  102 + attribution notices from the Source form of the Work,
  103 + excluding those notices that do not pertain to any part of
  104 + the Derivative Works; and
  105 +
  106 + (d) If the Work includes a "NOTICE" text file as part of its
  107 + distribution, then any Derivative Works that You distribute must
  108 + include a readable copy of the attribution notices contained
  109 + within such NOTICE file, excluding those notices that do not
  110 + pertain to any part of the Derivative Works, in at least one
  111 + of the following places: within a NOTICE text file distributed
  112 + as part of the Derivative Works; within the Source form or
  113 + documentation, if provided along with the Derivative Works; or,
  114 + within a display generated by the Derivative Works, if and
  115 + wherever such third-party notices normally appear. The contents
  116 + of the NOTICE file are for informational purposes only and
  117 + do not modify the License. You may add Your own attribution
  118 + notices within Derivative Works that You distribute, alongside
  119 + or as an addendum to the NOTICE text from the Work, provided
  120 + that such additional attribution notices cannot be construed
  121 + as modifying the License.
  122 +
  123 + You may add Your own copyright statement to Your modifications and
  124 + may provide additional or different license terms and conditions
  125 + for use, reproduction, or distribution of Your modifications, or
  126 + for any such Derivative Works as a whole, provided Your use,
  127 + reproduction, and distribution of the Work otherwise complies with
  128 + the conditions stated in this License.
  129 +
  130 + 5. Submission of Contributions. Unless You explicitly state otherwise,
  131 + any Contribution intentionally submitted for inclusion in the Work
  132 + by You to the Licensor shall be under the terms and conditions of
  133 + this License, without any additional terms or conditions.
  134 + Notwithstanding the above, nothing herein shall supersede or modify
  135 + the terms of any separate license agreement you may have executed
  136 + with Licensor regarding such Contributions.
  137 +
  138 + 6. Trademarks. This License does not grant permission to use the trade
  139 + names, trademarks, service marks, or product names of the Licensor,
  140 + except as required for reasonable and customary use in describing the
  141 + origin of the Work and reproducing the content of the NOTICE file.
  142 +
  143 + 7. Disclaimer of Warranty. Unless required by applicable law or
  144 + agreed to in writing, Licensor provides the Work (and each
  145 + Contributor provides its Contributions) on an "AS IS" BASIS,
  146 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  147 + implied, including, without limitation, any warranties or conditions
  148 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
  149 + PARTICULAR PURPOSE. You are solely responsible for determining the
  150 + appropriateness of using or redistributing the Work and assume any
  151 + risks associated with Your exercise of permissions under this License.
  152 +
  153 + 8. Limitation of Liability. In no event and under no legal theory,
  154 + whether in tort (including negligence), contract, or otherwise,
  155 + unless required by applicable law (such as deliberate and grossly
  156 + negligent acts) or agreed to in writing, shall any Contributor be
  157 + liable to You for damages, including any direct, indirect, special,
  158 + incidental, or consequential damages of any character arising as a
  159 + result of this License or out of the use or inability to use the
  160 + Work (including but not limited to damages for loss of goodwill,
  161 + work stoppage, computer failure or malfunction, or any and all
  162 + other commercial damages or losses), even if such Contributor
  163 + has been advised of the possibility of such damages.
  164 +
  165 + 9. Accepting Warranty or Additional Liability. While redistributing
  166 + the Work or Derivative Works thereof, You may choose to offer,
  167 + and charge a fee for, acceptance of support, warranty, indemnity,
  168 + or other liability obligations and/or rights consistent with this
  169 + License. However, in accepting such obligations, You may act only
  170 + on Your own behalf and on Your sole responsibility, not on behalf
  171 + of any other Contributor, and only if You agree to indemnify,
  172 + defend, and hold each Contributor harmless for any liability
  173 + incurred by, or claims asserted against, such Contributor by reason
  174 + of your accepting any such warranty or additional liability.
  175 +
  176 + END OF TERMS AND CONDITIONS
  177 +
  178 + APPENDIX: How to apply the Apache License to your work.
  179 +
  180 + To apply the Apache License to your work, attach the following
  181 + boilerplate notice, with the fields enclosed by brackets "[]"
  182 + replaced with your own identifying information. (Don't include
  183 + the brackets!) The text should be enclosed in the appropriate
  184 + comment syntax for the file format. We also recommend that a
  185 + file or class name and description of purpose be included on the
  186 + same "printed page" as the copyright notice for easier
  187 + identification within third-party archives.
  188 +
  189 + Copyright [yyyy] [name of copyright owner]
  190 +
  191 + Licensed under the Apache License, Version 2.0 (the "License");
  192 + you may not use this file except in compliance with the License.
  193 + You may obtain a copy of the License at
  194 +
  195 + http://www.apache.org/licenses/LICENSE-2.0
  196 +
  197 + Unless required by applicable law or agreed to in writing, software
  198 + distributed under the License is distributed on an "AS IS" BASIS,
  199 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  200 + See the License for the specific language governing permissions and
  201 + limitations under the License.
  1 +# dingtalk-encrypt
  2 +DingTalk Encrypt Node Version.
  3 +Refer to [Java version](https://github.com/opendingtalk/eapp-corp-project.git):
  4 +
  5 +**Issues:** It's your turn!
  6 +
  7 +# Usage
  8 +## this repository
  9 +- git clone
  10 +- npm install
  11 +- run 'EncryptTest.js' for main APIs.
  12 +
  13 +## npm module
  14 +- npm install --save dingtalk-encrypt
  15 +- use APIs as follows API Doc.
  16 +
  17 +# API Doc
  18 +- Need constants:
  19 +> TOKEN - Random string for signature, unrestricted, such as "123456".
  20 + ENCODING_AES_KEY - Secret key for callback data, random 43 characters of [a-z, A-Z, 0-9].
  21 + CORP_ID - DingTalk corpId from the [Official OA](https://oa.dingtalk.com).
  22 +
  23 +- Main APIs([Usage Example](https://open-doc.dingtalk.com/microapp/serverapi2/lo5n6i)):
  24 + - getEncryptedMap
  25 + - getDecryptMsg
  26 + - getSignature
  27 + - encrypt
  28 + - decrypt
  29 +
  30 +- Example
  31 + - 处理钉钉回调
  32 + ```
  33 + // 参考:钉钉开发文档-业务事件回调
  34 + const DingTalkEncryptor = require('dingtalk-encrypt');
  35 + const utils = require('dingtalk-encrypt/Utils');
  36 + /** 加解密需要,可以随机填写。如 "12345" */
  37 + const TOKEN = '666666';
  38 + /** 加密密钥,用于回调数据的加密,固定为43个字符,从[a-z, A-Z, 0-9]共62个字符中随机生成*/
  39 + const ENCODING_AES_KEY = 'TXpRMU5qYzRPVEF4TWpNME5UWTNPRGt3TVRJek5EVTI';
  40 + // const ENCODING_AES_KEY = utils.getRandomStr(43);
  41 + /** 企业corpid, 可以在钉钉企业管理后台查看(https://oa.dingtalk.com/) */
  42 + const CORP_ID = 'ding12345678901234567890123456789012';
  43 + /** 实例化加密类 */
  44 + console.log('\nEncryptor Test:');
  45 + const encryptor = new DingTalkEncryptor(TOKEN, ENCODING_AES_KEY, CORP_ID);
  46 +
  47 + // 解密钉钉回调数据
  48 + const plainText = encryptor.getDecryptMsg(signature, timestamp, nonce, encryptMsg);
  49 + console.log('DEBUG plainText: ' + plainText);
  50 + const obj = JSON.parse(plainText);
  51 + // 回调事件类型,根据事件类型和业务数据处理相应业务
  52 + const eventType = obj.EventType;
  53 + // 响应数据:加密'success',签名等等
  54 + encryptor.getEncryptedMap('success', timestamp, utils.getRandomStr(8));
  55 + ```
  56 + - 单独使用加/解密
  57 + ```
  58 + /** 测试加解密响应报文或者字符串 */
  59 + const testJson = {
  60 + EventType: 'bpms_instance_change',
  61 + processInstanceId: 'ad253df6-e175caf-68085c60ba8a',
  62 + corpId: 'ding2c4d8175651',
  63 + createTime: 1495592259000,
  64 + title: '自测-1016',
  65 + type: 'start',
  66 + staffId: 'er5875',
  67 + url: 'https://aflow.dingtalk.com/dingtalk/mobile/homepage.htm',
  68 + processCode: 'xxx',
  69 + };
  70 + // console.log(JSON.parse(JSON.stringify(testJson)));
  71 + // const unencryptedJson = 'success';
  72 + const unencryptedJson = JSON.stringify(testJson);
  73 + console.log(` node unencryptedJson:\n ${unencryptedJson}`);
  74 + const encryptedJson = encryptor.encrypt(ENCRYPT_RANDOM_16, unencryptedJson);
  75 + console.log(` \nnode encryptedJson:\n ${encryptedJson}`);
  76 + const decryptedJson = encryptor.decrypt(encryptedJson);
  77 + console.log(` \nnode decryptedJson:\n ${decryptedJson}, (${decryptedJson.length})`);
  78 + console.log(' \nnode sign:\n ' + encryptor.getSignature(TOKEN, timeStamp, nonce, encryptedJson));
  79 +
  80 + ```
  81 +
  82 +# Thanks To
  83 +- [Authors of crypto-js](https://github.com/brix/crypto-js)
  84 +- [Authors of eapp-corp-project](https://github.com/opendingtalk/eapp-corp-project)
  1 +'use strict';
  2 +
  3 +const int2Bytes = function(count) {
  4 + const byteArr = [ (count >> 24 & 255), (count >> 16 & 255), (count >> 8 & 255), (count & 255) ];
  5 + // console.log(`debug int2Bytes: ${count} -> ${byteArr}`);
  6 + return byteArr;
  7 +};
  8 +const bytes2int = function(byteArr) {
  9 + let count = 0;
  10 + for (let i = 0; i < 4; ++i) {
  11 + count <<= 8;
  12 + count |= byteArr[i] & 255;
  13 + }
  14 + // console.log(`debug bytes2int: ${byteArr} -> ${count}`);
  15 + return count;
  16 +};
  17 +
  18 +// https://stackoverflow.com/questions/3195865/converting-byte-array-to-string-in-javascript
  19 +const string2Bin = function(str) {
  20 + const binaryArr = [];
  21 + for (let i = 0; i < str.length; i++) {
  22 + binaryArr.push(str.charCodeAt(i));
  23 + }
  24 + // console.log(`debug string2Bin: ${str} -> ${binaryArr}`);
  25 + return binaryArr;
  26 +};
  27 +const bin2String = function(array) {
  28 + const str = String.fromCharCode.apply(String, array);
  29 + // console.log(`debug bin2String: ${array} -> ${str}`);
  30 + return str;
  31 +};
  32 +
  33 +const getRandomStr = function(size) {
  34 + const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  35 + let randomStr = '';
  36 + for (let i = size; i > 0; --i) {
  37 + randomStr += base[Math.floor(Math.random() * base.length)];
  38 + }
  39 + return randomStr;
  40 +};
  41 +
  42 +module.exports = {
  43 + int2Bytes,
  44 + bytes2int,
  45 + string2Bin,
  46 + bin2String,
  47 + getRandomStr,
  48 +};
  1 +'use strict';
  2 +
  3 +(function(root, factory, undef) {
  4 + if (typeof exports === 'object') {
  5 + // CommonJS
  6 + module.exports = exports = factory(require('./DingTalkEncryptor'));
  7 + }
  8 +}(this, function(DingTalkEncryptor) {
  9 + return DingTalkEncryptor;
  10 +}));
  1 +{
  2 + "name": "dingtalk-encrypt",
  3 + "version": "2.0.0",
  4 + "description": "dingTalk Encrypt Nodejs Version.",
  5 + "main": "index.js",
  6 + "scripts": {
  7 + "test": "echo \"Error: no test specified\" && exit 1"
  8 + },
  9 + "keywords": [
  10 + "nodejs",
  11 + "dingtalk",
  12 + "crypto",
  13 + "encrypt",
  14 + "decrypt"
  15 + ],
  16 + "author": "senique,zhubg520",
  17 + "license": "Apache-2.0",
  18 + "homepage": "http://gitlab.workai.com.cn/fanwh/dingtalk-encrypt",
  19 + "dependencies": {
  20 + "crypto-js": "^4.1.1"
  21 + }
  22 +}
  1 +/*
  2 +* 可以
  3 +*/
  4 +http://www.mytju.com/classcode/tools/encode_utf8.asp
  5 +https://www.qqxiuzi.cn/bianma/Unicode-UTF.php
  6 +https://www.qqxiuzi.cn/bianma/base64.htm
  7 +
  8 +'TXpRMU5qYzRPVEF4TWpNME5UWTNPRGt3TVRJek5EVTI'
  9 +
  10 +Buffer.from(ENCODING_AES_KEY + '=', 'base64')
  11 +
  12 +4d 7a 51 31 4e 6a 63 34 4f 54 41 78 4d 6a 4d 30 4e 54 59 33 4f 44 6b 77 4d 54 49 7a 4e 44 55 32 Unicode编码16进制
  13 +
  14 +4d7a51314e6a63344f5441784d6a4d304e5459334f446b774d54497a4e445532
  15 +
  16 +MzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2 UTF8编码
  17 +
  18 +
  19 +/*
  20 +* 随机
  21 +*/
  22 +
  23 +'Q2fHd7jP6f9P20HWFsGmTm8V56srrPVTpvw3q1ESSfv'
  24 +
  25 +43 67 c7 77 b8 cf e9 ff 4f db 41 d6 16 c1 a6 4e 6f 15 e7 ab 2b ac f5 53 a6 fc 37 ab 51 12 49 fb
  26 +
  27 +4367c777b8cfe9ff4fdb41d616c1a64e6f15e7ab2bacf553a6fc37ab511249fb
注册登录 后发表评论