@tmsfe/tms-core 0.0.151 → 0.0.153

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmsfe/tms-core",
3
- "version": "0.0.151",
3
+ "version": "0.0.153",
4
4
  "description": "tms运行时框架",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,446 @@
1
+ /**
2
+ * 加密相关的原子工具能力
3
+ * 暴露出来的工具函数封装原则:不可以向外throw错误,返回执行结果统一格式:{ success: boolean, msg: string, res: any }
4
+ * https://iwiki.woa.com/p/4013041987#1.-RSA+AES-%E5%88%87%E6%8D%A2-Curve25519+XSalsa20%EF%BC%9A
5
+ */
6
+ /* eslint-disable @typescript-eslint/no-require-imports */
7
+ const ecc = require('./nacl.min.js');
8
+ const base64Util = require('./nacl-util.min.js');
9
+ /* eslint-enable @typescript-eslint/no-require-imports */
10
+
11
+ interface BaseResp<T> {
12
+ success: boolean,
13
+ msg: string,
14
+ res: T,
15
+ }
16
+
17
+ interface CryptoKeyInfo {
18
+ sharedByte: Uint8Array,
19
+ clientPublicKey: string,
20
+ serverPubId: string,
21
+ }
22
+
23
+ // 出行接口域名
24
+ const SERVER_HOST_MAP = {
25
+ production: 'https://tim.map.qq.com', // 出行服务正式环境域名
26
+ test: 'https://tim.sparta.html5.qq.com', // 出行服务测试环境域名
27
+ development: 'https://tim.sparta.html5.qq.com/dev', // 出行服务开发环境域名
28
+ predist: 'https://tim.sparta.html5.qq.com/pre', // 出行服务灰度环境域名
29
+ mock: 'http://localhost:8003', // 本地mock环境
30
+ };
31
+
32
+ // 基础工具
33
+ const baseUtil = {
34
+ _isObject: (obj: any): boolean => Object.prototype.toString.call(obj) === '[object Object]',
35
+ // Uint8Array转为url安全的base64编码
36
+ encUrl: (input: Uint8Array): string => {
37
+ let base64 = base64Util.encode(input);
38
+ base64 = base64
39
+ .replace(/\+/g, '-')
40
+ .replace(/\//g, '_')
41
+ .replace(/=+$/, '');
42
+ return base64;
43
+ },
44
+ // url安全的base64解码
45
+ decUrl: (input: string): Uint8Array => {
46
+ let base64 = input.replace(/-/g, '+').replace(/_/g, '/');
47
+ while (base64.length % 4) {
48
+ base64 += '=';
49
+ }
50
+ return base64Util.decode(base64);
51
+ },
52
+ // header格式化,将header的key转换为小写
53
+ formatHeader: (header): any => {
54
+ if (!header || !baseUtil._isObject(header)) {
55
+ return {};
56
+ }
57
+ const formatHeader = {};
58
+ Object.keys(header).forEach((key) => {
59
+ formatHeader[key.toLocaleLowerCase()] = header[key];
60
+ });
61
+ return formatHeader;
62
+ },
63
+ formatGetData: (params: any): string => {
64
+ if (!params || !baseUtil._isObject(params)) {
65
+ return '';
66
+ }
67
+ return Object.keys(params)
68
+ .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
69
+ .join('&');
70
+ },
71
+ getSinanHost: (): string => {
72
+ if (wx.$_encryptEnvInfo) {
73
+ return SERVER_HOST_MAP[wx.$_encryptEnvInfo.envName];
74
+ }
75
+ return '';
76
+ },
77
+ getClientEncryptOpen: (): boolean => {
78
+ if (wx.$_encryptEnvInfo) {
79
+ return wx.$_encryptEnvInfo.requestEncryptOpen;
80
+ }
81
+ return false;
82
+ },
83
+ BaseRespFac: class BaseRespFac<T> implements BaseResp<T> {
84
+ success: boolean;
85
+ msg: string;
86
+ res: T;
87
+
88
+ constructor(res: T, success?: boolean, msg?: string) {
89
+ this.success = success === undefined ? true : success;
90
+ this.msg = msg === undefined ? '' : msg;
91
+ this.res = res;
92
+ }
93
+ },
94
+ };
95
+ let composeParamsFunc = null;
96
+ // 加密工具
97
+ const eccUtil = {
98
+ _refreshPromise: null,
99
+ _refreshPubKeyInfo: async (forceRefresh: boolean): Promise<boolean> => {
100
+ // 未完成初始化或者关闭秘钥刷新能力,则不支持秘钥刷新
101
+ if (!composeParamsFunc) {
102
+ return false;
103
+ }
104
+ if (!wx.$_publicKey || forceRefresh) {
105
+ // eslint-disable-next-line
106
+ eccUtil._refreshPromise = new Promise(async (resolve) => {
107
+ const url = `${baseUtil.getSinanHost()}/basic/crypto/lastkey`;
108
+ const data = await composeParamsFunc({});
109
+ wx.request({
110
+ url,
111
+ method: 'POST',
112
+ data,
113
+ enableHttp2: true,
114
+ success: (res) => {
115
+ const success = eccUtil._updateGlobalPublicKeyInfo(false, res.header);
116
+ resolve(success);
117
+ },
118
+ fail: () => {
119
+ eccUtil._updateGlobalPublicKeyInfo(true);
120
+ resolve(false);
121
+ },
122
+ });
123
+ });
124
+ }
125
+ return eccUtil._refreshPromise;
126
+ },
127
+ // 解析resHeader详情,更新全局公钥信息
128
+ _updateGlobalPublicKeyInfo: (clear: boolean, resHeader?: {[key: string]: any}): BaseResp<boolean> => {
129
+ if (clear) {
130
+ wx.$_publicKey = null;
131
+ return;
132
+ }
133
+ const header = baseUtil.formatHeader(resHeader);
134
+ const {
135
+ 'x-gateway-code': code,
136
+ 'x-crypto-pub-id': pubId, 'x-crypto-pub-key': pubKey, 'x-crypto-pub-exp': pubExp, 'x-crypto-path': pathRule,
137
+ } = header;
138
+ const success = !code && pubId; // login接口会出现接口成功,但是不返回publicKeyInfo的情况
139
+ wx.$_publicKey = success ? { pubId, pubKey, pubExp, pathRule } : null;
140
+ return new baseUtil.BaseRespFac(success);
141
+ },
142
+ _privateKeyInfo: null,
143
+ getPrivateKeyInfo: (): CryptoKeyInfo => {
144
+ if (!wx.$_publicKey) return null;
145
+ const serverPubInfo = wx.$_publicKey;
146
+ if (!eccUtil._privateKeyInfo || eccUtil._privateKeyInfo.serverPubId !== serverPubInfo.pubId) {
147
+ const keyPair = ecc.box.keyPair(); // 生成客户端公钥私钥
148
+ eccUtil._privateKeyInfo = {
149
+ serverPubId: serverPubInfo.pubId, // 服务端公钥id
150
+ sharedByte: ecc.box.before(baseUtil.decUrl(serverPubInfo.pubKey), keyPair.secretKey),
151
+ clientPublicKey: baseUtil.encUrl(keyPair.publicKey), // base64 url safe 编码后的客户端公钥
152
+ };
153
+ }
154
+ return eccUtil._privateKeyInfo;
155
+ },
156
+ resolveGwCode: async (codeStr: string): Promise<{ retry: boolean, success: boolean }> => {
157
+ if (!codeStr) return { retry: false, success: true };
158
+ const code = parseInt(codeStr, 10);
159
+ switch (code) {
160
+ case 0:
161
+ return { retry: false, success: true };
162
+ case 11300: // 解密失败
163
+ return { retry: false, success: false };
164
+ case 11305: // 公钥id无效
165
+ case 11306: { // 公钥过期
166
+ const genPubSuccess = await eccUtil._refreshPubKeyInfo(true); // 1. 获取公钥
167
+ if (!genPubSuccess) return { retry: false, success: false };
168
+ eccUtil.getPrivateKeyInfo(); // 2. 生成私钥
169
+ return { retry: true, success: false };
170
+ }
171
+ case 11307: // 加密未开启
172
+ return { retry: false, success: false };
173
+ default:
174
+ return { retry: false, success: false };
175
+ }
176
+ },
177
+ execEncrypt: (input: string, ignoreNull = false): BaseResp<{
178
+ cryptoKeyInfo: CryptoKeyInfo,
179
+ encryptedContent: any } | null> => {
180
+ try {
181
+ const eccKeyInfo = eccUtil.getPrivateKeyInfo();
182
+ if (!eccKeyInfo) {
183
+ return new baseUtil.BaseRespFac(null, false, '加密失败:无加密秘钥信息');
184
+ }
185
+ const cryptoKeyInfo = Object.assign({}, eccKeyInfo); // 因为这里的加密数据要在后续流程中复用,所以需要值拷贝
186
+ if (ignoreNull && (!input || input === '{}')) { // 如果需要忽略空值
187
+ return new baseUtil.BaseRespFac({ cryptoKeyInfo, encryptedContent: '' });
188
+ }
189
+ const { sharedByte } = cryptoKeyInfo;
190
+ const nonce = ecc.randomBytes(ecc.box.nonceLength);
191
+ const encrypted = ecc.box.after(base64Util.decodeUTF8(input), nonce, sharedByte);
192
+ const combined = new Uint8Array(nonce.length + encrypted.length);
193
+ combined.set(nonce);
194
+ combined.set(encrypted, nonce.length);
195
+ const encryptedStr = baseUtil.encUrl(combined);
196
+ return new baseUtil.BaseRespFac({
197
+ cryptoKeyInfo,
198
+ encryptedContent: encryptedStr,
199
+ });
200
+ } catch (e) {
201
+ return new baseUtil.BaseRespFac(null, false, `execEncrypt失败:${JSON.stringify(e)}`);
202
+ }
203
+ },
204
+ execDecrypt: (msg: Uint8Array, cryptoKeyInfo: CryptoKeyInfo): BaseResp<string> => {
205
+ try {
206
+ const { sharedByte } = cryptoKeyInfo;
207
+ const nonce = msg.slice(0, ecc.box.nonceLength);
208
+ const encrypted = msg.slice(ecc.box.nonceLength);
209
+ const decrypted = ecc.box.open.after(encrypted, nonce, sharedByte);
210
+ const decryptedStr = base64Util.encodeUTF8(decrypted);
211
+ return new baseUtil.BaseRespFac(decryptedStr);
212
+ } catch (err) {
213
+ return new baseUtil.BaseRespFac('', false, `execDecrypt失败:${JSON.stringify(err)}`);;
214
+ }
215
+ },
216
+ closeCrypto: () => {
217
+ eccUtil._privateKeyInfo = null;
218
+ eccUtil._updateGlobalPublicKeyInfo(true);
219
+ },
220
+ openCrypto: async (): Promise<boolean> => {
221
+ const genPubSuccess = await eccUtil._refreshPubKeyInfo(false); // 1. 获取公钥
222
+ if (!genPubSuccess) return false;
223
+ eccUtil.getPrivateKeyInfo(); // 2. 生成私钥
224
+ return true;
225
+ },
226
+ };
227
+ // 加密规则判断工具
228
+ const cryptRuleUtil = {
229
+ // 远程加密服务是否开启
230
+ _isServerOpen: (): boolean => !!wx.$_publicKey,
231
+ // 检查path是否符合下发的路由前缀
232
+ _pathInEnablePrefix: (path: string): boolean => {
233
+ if (!wx.$_publicKey) {
234
+ return false;
235
+ }
236
+ const { pathRule } = wx.$_publicKey;
237
+ if (pathRule === '*') {
238
+ return true;
239
+ }
240
+ const prefixArr = pathRule.split(',').map(item => item.trim());
241
+ for (let i = 0, len = prefixArr.length; i < len; i++) {
242
+ if (path.indexOf(prefixArr[i]) > -1) {
243
+ return true;
244
+ }
245
+ }
246
+ return false;
247
+ },
248
+ // 判断是否是性能埋点上报接口
249
+ _isPerformanceReport: (path: string, params: any): boolean => {
250
+ // 如果是日志上报接口,需要过滤性能日志,不需要加密
251
+ if (path.indexOf('basic/event/upload') > -1) {
252
+ if (params.batch?.length === 1 && params.batch[0]?.[31] === 'tms-performance-log') {
253
+ return true;
254
+ }
255
+ return false;
256
+ }
257
+ return false;
258
+ },
259
+ // 不参与加密的请求路径规则: { 允许的域名: 不需要加密的path }
260
+ _encryptPathRule: {
261
+ 'tim.map.qq.com': ['^/user/login', '^/api/getClientConfigs', '^/basic/crypto/lastkey'],
262
+ 'tim.sparta.html5.qq.com': [
263
+ '^/user/login',
264
+ '^/cnabroad', '^~/ReChargeCard/', '^/gasolinerecharge/v2/', '^/gasolinerecharge/rechargecard/',
265
+ '^/tde', '^/basic/crypto/lastkey',
266
+ ],
267
+ },
268
+ _isHostValid: (url) => {
269
+ // 使用正则表达式解析URL
270
+ const urlPattern = /^(https?:\/\/)?([^/?#]+)([/?#].*)?$/;
271
+ const matches = url.match(urlPattern);
272
+ if (!matches) {
273
+ console.error('Invalid URL:', url);
274
+ return false; // 如果URL无效,默认返回false
275
+ }
276
+ const domain = matches[2];
277
+ const path = matches[3] || '/';
278
+ if (cryptRuleUtil._encryptPathRule[domain]) {
279
+ const pathRules = cryptRuleUtil._encryptPathRule[domain];
280
+ for (const rule of pathRules) {
281
+ const regex = new RegExp(rule);
282
+ if (regex.test(path)) {
283
+ return false; // 匹配到规则,不需要加密
284
+ }
285
+ }
286
+ return true; // 此域名下,默认需要加密
287
+ }
288
+ return false; // 没有匹配到规则,不需要加密
289
+ },
290
+ };
291
+
292
+ // 初始化加密工具
293
+ const init = (composeFunc: Function): BaseResp<null> => {
294
+ composeParamsFunc = (...args) => composeFunc(...args); // 加密服务器公共参数
295
+ return new baseUtil.BaseRespFac(null);
296
+ };
297
+
298
+ // 判断是否满足加密规则
299
+ const isCryptoRuleMath = (path: string, reqData: any): BaseResp<boolean> => {
300
+ if (!wx.$_encryptEnvInfo.requestEncryptOpen) {
301
+ return new baseUtil.BaseRespFac(false, false, '本地加密未开启');
302
+ }
303
+ // 如果服务端下发的加密开关关闭,不走加密
304
+ if (!cryptRuleUtil._isServerOpen()) {
305
+ return new baseUtil.BaseRespFac(false, false, '服务端加密未开启');
306
+ }
307
+ // 请求路由不满足服务端下发的加密规则,不走加密
308
+ if (!cryptRuleUtil._pathInEnablePrefix(path)) {
309
+ return new baseUtil.BaseRespFac(false, false, '未命中服务端加密规则');
310
+ }
311
+ // 请求接口是加密性能埋点上报接口,不加密
312
+ if (cryptRuleUtil._isPerformanceReport(path, reqData)) {
313
+ return new baseUtil.BaseRespFac(false, false, '性能埋点');
314
+ }
315
+ // 请求路由不走sinan网关,不加密
316
+ if (!cryptRuleUtil._isHostValid(path)) {
317
+ return new baseUtil.BaseRespFac(false, false, '非sinan网关加密接口');
318
+ }
319
+ return new baseUtil.BaseRespFac(true);;
320
+ };
321
+ // 请求加密
322
+ const reqEncrypt = (method: string, data: any, header: {
323
+ [key: string]: any }, encryptedResponseHeaderName: string): BaseResp<{
324
+ cryptoKeyInfo: CryptoKeyInfo,
325
+ header: any,
326
+ data: any,
327
+ } | null> => {
328
+ const reqHeader = baseUtil.formatHeader(header);
329
+ if (reqHeader.contentType) {
330
+ return new baseUtil.BaseRespFac(null, false, '户自定义了请求contentType');
331
+ }
332
+ let finalData = {};
333
+ // 1. 处理请求参数
334
+ if (method.toUpperCase() === 'GET') {
335
+ const searchParams = baseUtil.formatGetData(data);
336
+ if (!searchParams) {
337
+ return new baseUtil.BaseRespFac(null, false, `GET请求参数不满足加密的规则: ${JSON.stringify(data)}`);
338
+ }
339
+ const { success, msg, res } = eccUtil.execEncrypt(searchParams);
340
+ if (!success) {
341
+ return new baseUtil.BaseRespFac(null, false, `GET请求参数加密失败: ${msg}`);
342
+ }
343
+ finalData = { tmsec: res.encryptedContent };
344
+ } else {
345
+ const { success, msg, res } = eccUtil.execEncrypt(JSON.stringify(data));
346
+ if (!success) {
347
+ return new baseUtil.BaseRespFac(null, false, `${method}请求参数加密失败: ${msg}`);
348
+ }
349
+ finalData = res.encryptedContent;
350
+ }
351
+ // 2. 处理Headers
352
+ const { success, msg, res } = eccUtil.execEncrypt(JSON.stringify(header), true);
353
+ if (!success) {
354
+ return new baseUtil.BaseRespFac(null, false, `请求Header加密失败: ${msg}`);
355
+ }
356
+ return new baseUtil.BaseRespFac({
357
+ cryptoKeyInfo: res.cryptoKeyInfo,
358
+ data: finalData,
359
+ header: {
360
+ 'Content-Type': 'text/plain',
361
+ 'X-Crypto-Mode': '2', // ecc加密模式
362
+ 'X-Encrypted-Headers': res.encryptedContent,
363
+ 'X-Encrypt-Pub': res.cryptoKeyInfo.serverPubId,
364
+ 'X-Encrypt-Key': res.cryptoKeyInfo.clientPublicKey,
365
+ 'X-Encrypt-Response': '3', // 加密,二进制
366
+ 'X-Response-Header-Name': encryptedResponseHeaderName,
367
+ },
368
+ });
369
+ };
370
+ // 解密请求结果
371
+ const resDecrypt = async (header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<BaseResp<{
372
+ retry: boolean,
373
+ header: any,
374
+ data: any,
375
+ }>> => {
376
+ try {
377
+ const formatHeader = baseUtil.formatHeader(header);
378
+ const {
379
+ // 'x-encrypt-key': clientPublicKey, // base64 url safe编码后的客户端公钥
380
+ 'x-encrypt-response': encryptResponseMode, // 期望的响应加密模式 2: 加密、不压缩 3: 加密、二进制
381
+ 'x-response-header-name': encryptedResponseHeaderName, // 需要加密的响应Header: X-Header1,X-Header2
382
+ 'x-encrypted-headers': encryptedHeaders, // 加密后的Header信息
383
+ 'x-gateway-code': gatewayCode, // 网关返回的错误码
384
+ 'content-type': contentType, // 响应内容类型
385
+ } = formatHeader;
386
+ if (!encryptResponseMode || encryptResponseMode === '0') { // 不需要解密,直接返回
387
+ return new baseUtil.BaseRespFac({ header, data, retry: false });
388
+ }
389
+ const { retry, success: gwSuccess } = await eccUtil.resolveGwCode(gatewayCode);
390
+ if (!gwSuccess) {
391
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry }, false, `网关返回错误码: ${gatewayCode}`);
392
+ }
393
+ let decryptedHeaders = {};
394
+ if (encryptedResponseHeaderName) { // 解密响应Header
395
+ const { success, msg, res } = eccUtil.execDecrypt(baseUtil.decUrl(encryptedHeaders), cryptoKeyInfo);
396
+ if (!success) {
397
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Header失败: ${msg}`);
398
+ }
399
+ decryptedHeaders = JSON.parse(res);
400
+ }
401
+ const needDecode = contentType === 'text/plain';
402
+ const cipher = needDecode ? baseUtil.decUrl(data) : new Uint8Array(data);
403
+ const { success, msg, res } = eccUtil.execDecrypt(cipher, cryptoKeyInfo);
404
+ if (!success) {
405
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Body失败: ${msg}`);
406
+ }
407
+ const decryptedBody = JSON.parse(res); // 解密响应Body
408
+ return new baseUtil.BaseRespFac({
409
+ retry: false,
410
+ header: {
411
+ ...header,
412
+ ...decryptedHeaders,
413
+ },
414
+ data: decryptedBody,
415
+ });
416
+ } catch (e) {
417
+ // 因为上面的逻辑有parse, 所以这里再加一个catch
418
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Body失败: ${JSON.stringify(e)}`);
419
+ }
420
+ };
421
+ // 处理接下来的请求开关
422
+ let dealEncryptionSwitching = false;
423
+ const dealEncryptionSwitch = async (path: string, resHeader): Promise<void> => {
424
+ if ((!resHeader || dealEncryptionSwitching)) {
425
+ return;
426
+ }
427
+ dealEncryptionSwitching = true;
428
+ const formatHeader = baseUtil.formatHeader(resHeader);
429
+ if (formatHeader['x-crypto-enable'] === '0') {
430
+ eccUtil.closeCrypto();
431
+ } else if (formatHeader['x-crypto-enable'] === '1') {
432
+ `${baseUtil.getSinanHost()}/user/login` === path && eccUtil._updateGlobalPublicKeyInfo(false, formatHeader);
433
+ await eccUtil.openCrypto();
434
+ } // 0是关闭,2是开启, 1是保持
435
+ dealEncryptionSwitching = false;
436
+ };
437
+
438
+ const encryptUtil = {
439
+ init, // 初始化加密工具
440
+ isCryptoRuleMath, // 请求是否符合加密规则
441
+ reqEncrypt, // 请求加密:header和data
442
+ resDecrypt, // 响应解密
443
+ dealEncryptionSwitch, // 处理加密开关
444
+ };
445
+
446
+ export default encryptUtil;
@@ -0,0 +1,175 @@
1
+ import encryptUtil from './encrypt-util';
2
+ import { genTraceparent } from './traceUtils';
3
+
4
+ interface Params {
5
+ filePath?: string,
6
+ name?: string,
7
+ data?: any,
8
+ }
9
+
10
+ const logger = wx.getLogManager({});
11
+ const util = {
12
+ // 统一格式化日志输出
13
+ formatLog(args: any[]): any[] {
14
+ // 小程序日志管理器都只是精确到秒,我们补上毫秒方便分析
15
+ const time = new Date()
16
+ .toISOString()
17
+ .replace('T', ' ')
18
+ .substring(0, 19)
19
+ .replace(/-/g, '-')
20
+ .replace(/:/g, ':');
21
+ args.unshift(time);
22
+ return args;
23
+ },
24
+ logInfo: (...args) => {
25
+ console.log(...args);
26
+ const items = util.formatLog(args);
27
+ logger.log(...items);
28
+ },
29
+ reportFunc: (...args) => {
30
+ util.logInfo('reportFunc init fail:', ...args);
31
+ },
32
+ // 判断是否需要加密
33
+ needsEncryption: (path: string, reqData: Params): Boolean => {
34
+ // 小程序构建环境的加密开关关闭,不走加密
35
+ if (!wx.$_encryptEnvInfo.requestEncryptOpen) return false;
36
+ const isCryptoRuleMathRes = encryptUtil.isCryptoRuleMath(path, reqData);
37
+ return isCryptoRuleMathRes.res;
38
+ },
39
+ reqEncrypt: (obj: { url: string, method: string, data: any, header: any }): {
40
+ data: any, header: any, msg: string, cryptoKeyInfo?: any } => {
41
+ const { url, method, data, header = {} } = obj;
42
+ // 判断请求是否满足加密要求,如果不满足则走默认请求
43
+ const { success, msg } = encryptUtil.isCryptoRuleMath(url, data);
44
+ if (!success) {
45
+ return { data, header, msg };
46
+ }
47
+ // 加密请求数据
48
+ const reqEncryptRes = encryptUtil.reqEncrypt(method, data, header, '');
49
+ if (!reqEncryptRes.success) {
50
+ return { data, header, msg };
51
+ }
52
+ return Object.assign({ msg }, reqEncryptRes.res);
53
+ },
54
+ };
55
+
56
+ // 劫持wx.request和wx.uploadFile函数
57
+ const requestInit = () => {
58
+ if (!wx.request.cryptoFlag) {
59
+ wx._request = wx.request;
60
+ proxyWxRequest();
61
+ wx.request.cryptoFlag = true;
62
+ }
63
+ if (!wx.uploadFile.cryptoFlag) {
64
+ wx._uploadFile = wx.uploadFile;
65
+ proxyWxUploadFile();
66
+ wx.uploadFile.cryptoFlag = true;
67
+ }
68
+ };
69
+
70
+ function proxyWxRequest(): void {
71
+ Object.defineProperty(wx, 'request', {
72
+ writable: true,
73
+ enumerable: true,
74
+ configurable: true,
75
+ value(options: any) {
76
+ const { url, method, data, header = {}, success, fail, complete, dataType, responseType } = options;
77
+ const traceparent = genTraceparent();
78
+ // 如果用户自定义了dataType或者responseType,则不做处理
79
+ if (dataType || responseType) {
80
+ util.reportFunc(url, traceparent, '用户自定义了dataType和responseType');
81
+ wx._request.call(this, Object.assign(options, {
82
+ success: (res) => {
83
+ encryptUtil.dealEncryptionSwitch(url, res.header);
84
+ success?.call(this, res);
85
+ },
86
+ header: { ...header, Traceparent: traceparent },
87
+ }));
88
+ return;
89
+ }
90
+ // 加密请求数据
91
+ const { data: formatData, header: formatHeader, msg, cryptoKeyInfo } = util
92
+ .reqEncrypt({ url, method, data, header });
93
+ if (!cryptoKeyInfo) {
94
+ // 如果没有加密信息,则不走加密
95
+ util.logInfo(url, traceparent, msg);
96
+ wx._request.call(this, Object.assign(options, {
97
+ success: (res) => {
98
+ encryptUtil.dealEncryptionSwitch(url, res.header);
99
+ success?.call(this, res);
100
+ },
101
+ header: { ...header, Traceparent: traceparent },
102
+ }));
103
+ return;
104
+ }
105
+ let completeResolver;
106
+ // eslint-disable-next-line
107
+ const completePromp = new Promise(resolve => { completeResolver = resolve; });
108
+ wx._request.call(this, Object.assign(options, {
109
+ data: formatData,
110
+ dataType: '其他',
111
+ responseType: 'arraybuffer',
112
+ success: async (result) => {
113
+ // 解密响应
114
+ const { header: resHeader, data: resData } = result;
115
+ const { success: resSuccess, msg, res } = await encryptUtil.resDecrypt(resHeader, resData, cryptoKeyInfo);
116
+ if (resSuccess) {
117
+ util.logInfo(url, traceparent, '解密成功');
118
+ success?.call(this, res);
119
+ const completeRes: any = await completePromp;
120
+ completeRes.header = resHeader;
121
+ completeRes.data = resData;
122
+ complete?.call(this, completeRes);
123
+ } else {
124
+ util.reportFunc(url, traceparent, `解密失败:${msg}`);
125
+ wx._request.call(this, Object.assign(options, {
126
+ success: (res) => {
127
+ encryptUtil.dealEncryptionSwitch(url, res.header);
128
+ success?.call(this, res);
129
+ },
130
+ header: { ...header, Traceparent: traceparent },
131
+ }));
132
+ }
133
+ },
134
+ fail: async (err) => {
135
+ fail?.call(this, err);
136
+ const completeRes: any = await completePromp;
137
+ complete?.call(this, completeRes);
138
+ },
139
+ complete: (res) => {
140
+ completeResolver(res);
141
+ },
142
+ header: { ...formatHeader, Traceparent: traceparent },
143
+ }));
144
+ },
145
+ });
146
+ }
147
+
148
+ function proxyWxUploadFile(): void {
149
+ Object.defineProperty(wx, 'uploadFile', {
150
+ writable: true,
151
+ enumerable: true,
152
+ configurable: true,
153
+ value(options: any) {
154
+ wx._uploadFile.call(this, Object.assign(options, {
155
+ header: { ...options.header, Traceparent: genTraceparent() },
156
+ }));
157
+ },
158
+ });
159
+ }
160
+
161
+ export const encryptObjInit = (utilFunc: {
162
+ composeParamsFunc: Function,
163
+ report: Function,
164
+ }) => {
165
+ // 初始化参数加签函数和性能上报函数
166
+ const { report, composeParamsFunc } = utilFunc;
167
+ encryptUtil.init(composeParamsFunc);
168
+ util.reportFunc = (...args) => {
169
+ util.logInfo('request_encrypt_log', ...args);
170
+ report('request_encrypt_log', ...args);
171
+ };
172
+ // 劫持wx.request和wx.uploadFile函数
173
+ requestInit();
174
+ };
175
+
@@ -0,0 +1,2 @@
1
+ /* eslint-disable */
2
+ const Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){for(var t,r,n,h,o,i,c,a="",s=0;s<e.length;)h=(t=e[s++])>>2,o=(3&t)<<4|(r=e[s++])>>4,i=(15&r)<<2|(n=e[s++])>>6,c=63&n,isNaN(r)?i=c=64:isNaN(n)&&(c=64),a=a+this._keyStr.charAt(h)+this._keyStr.charAt(o)+this._keyStr.charAt(i)+this._keyStr.charAt(c);return a},decode:function(e){var t,r,n,h,o,i,c=[],a=0;for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");a<e.length;)t=this._keyStr.indexOf(e.charAt(a++))<<2|(h=this._keyStr.indexOf(e.charAt(a++)))>>4,r=(15&h)<<4|(o=this._keyStr.indexOf(e.charAt(a++)))>>2,n=(3&o)<<6|(i=this._keyStr.indexOf(e.charAt(a++))),c.push(t),64!=o&&c.push(r),64!=i&&c.push(n);return new Uint8Array(c)},encodeUTF8:function(e){var t,r=[];for(t=0;t<e.length;t++)r.push(String.fromCharCode(e[t]));return decodeURIComponent(escape(r.join("")))},decodeUTF8:function(e){if("string"!=typeof e)throw new TypeError("expected string");var t,r=unescape(encodeURIComponent(e)),n=new Uint8Array(r.length);for(t=0;t<r.length;t++)n[t]=r.charCodeAt(t);return n}};module.exports = Base64;
@@ -0,0 +1,2 @@
1
+ /* eslint-disable */
2
+ !function(r){"use strict";var u64=function(r,e){this.hi=0|r,this.lo=0|e},gf=function(r){var e,n=new Float64Array(16);if(r)for(e=0;e<r.length;e++)n[e]=r[e];return n},randombytes=function(){throw new Error("no PRNG")},e=new Uint8Array(16),n=new Uint8Array(32);n[0]=9;var t=gf(),o=gf([1]),a=gf([56129,1]),c=gf([30883,4953,19914,30187,55467,16705,2637,112,59544,30585,16505,36039,65139,11119,27886,20995]),i=gf([61785,9906,39828,60374,45398,33411,5274,224,53552,61171,33010,6542,64743,22239,55772,9222]),y=gf([54554,36645,11616,51542,42930,38181,51040,26924,56412,64982,57905,49316,21502,52590,14035,8553]),s=gf([26200,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214]),f=gf([41136,18958,6951,50414,58488,44335,6150,12099,55207,15867,153,11085,57099,20417,9344,11139]);function L32(r,e){return r<<e|r>>>32-e}function ld32(r,e){var n=255&r[e+3];return(n=(n=n<<8|255&r[e+2])<<8|255&r[e+1])<<8|255&r[e+0]}function dl64(r,e){var n=r[e]<<24|r[e+1]<<16|r[e+2]<<8|r[e+3],t=r[e+4]<<24|r[e+5]<<16|r[e+6]<<8|r[e+7];return new u64(n,t)}function st32(r,e,n){var t;for(t=0;t<4;t++)r[e+t]=255&n,n>>>=8}function ts64(r,e,n){r[e]=n.hi>>24&255,r[e+1]=n.hi>>16&255,r[e+2]=n.hi>>8&255,r[e+3]=255&n.hi,r[e+4]=n.lo>>24&255,r[e+5]=n.lo>>16&255,r[e+6]=n.lo>>8&255,r[e+7]=255&n.lo}function vn(r,e,n,t,o){var a,c=0;for(a=0;a<o;a++)c|=r[e+a]^n[t+a];return(1&c-1>>>8)-1}function crypto_verify_16(r,e,n,t){return vn(r,e,n,t,16)}function crypto_verify_32(r,e,n,t){return vn(r,e,n,t,32)}function core(r,e,n,t,o){var a,c,i,y=new Uint32Array(16),s=new Uint32Array(16),f=new Uint32Array(16),u=new Uint32Array(4);for(a=0;a<4;a++)s[5*a]=ld32(t,4*a),s[1+a]=ld32(n,4*a),s[6+a]=ld32(e,4*a),s[11+a]=ld32(n,16+4*a);for(a=0;a<16;a++)f[a]=s[a];for(a=0;a<20;a++){for(c=0;c<4;c++){for(i=0;i<4;i++)u[i]=s[(5*c+4*i)%16];for(u[1]^=L32(u[0]+u[3]|0,7),u[2]^=L32(u[1]+u[0]|0,9),u[3]^=L32(u[2]+u[1]|0,13),u[0]^=L32(u[3]+u[2]|0,18),i=0;i<4;i++)y[4*c+(c+i)%4]=u[i]}for(i=0;i<16;i++)s[i]=y[i]}if(o){for(a=0;a<16;a++)s[a]=s[a]+f[a]|0;for(a=0;a<4;a++)s[5*a]=s[5*a]-ld32(t,4*a)|0,s[6+a]=s[6+a]-ld32(e,4*a)|0;for(a=0;a<4;a++)st32(r,4*a,s[5*a]),st32(r,16+4*a,s[6+a])}else for(a=0;a<16;a++)st32(r,4*a,s[a]+f[a]|0)}function crypto_core_salsa20(r,e,n,t){return core(r,e,n,t,!1),0}function crypto_core_hsalsa20(r,e,n,t){return core(r,e,n,t,!0),0}var u=new Uint8Array([101,120,112,97,110,100,32,51,50,45,98,121,116,101,32,107]);function crypto_stream_salsa20_xor(r,e,n,t,o,a,c){var i,y,s=new Uint8Array(16),f=new Uint8Array(64);if(!o)return 0;for(y=0;y<16;y++)s[y]=0;for(y=0;y<8;y++)s[y]=a[y];for(;o>=64;){for(crypto_core_salsa20(f,s,c,u),y=0;y<64;y++)r[e+y]=(n?n[t+y]:0)^f[y];for(i=1,y=8;y<16;y++)i=i+(255&s[y])|0,s[y]=255&i,i>>>=8;o-=64,e+=64,n&&(t+=64)}if(o>0)for(crypto_core_salsa20(f,s,c,u),y=0;y<o;y++)r[e+y]=(n?n[t+y]:0)^f[y];return 0}function crypto_stream_salsa20(r,e,n,t,o){return crypto_stream_salsa20_xor(r,e,null,0,n,t,o)}function crypto_stream(r,e,n,t,o){var a=new Uint8Array(32);return crypto_core_hsalsa20(a,t,o,u),crypto_stream_salsa20(r,e,n,t.subarray(16),a)}function crypto_stream_xor(r,e,n,t,o,a,c){var i=new Uint8Array(32);return crypto_core_hsalsa20(i,a,c,u),crypto_stream_salsa20_xor(r,e,n,t,o,a.subarray(16),i)}function add1305(r,e){var n,t=0;for(n=0;n<17;n++)t=t+(r[n]+e[n]|0)|0,r[n]=255&t,t>>>=8}var _=new Uint32Array([5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252]);function crypto_onetimeauth(r,e,n,t,o,a){var c,i,y,s,f=new Uint32Array(17),u=new Uint32Array(17),p=new Uint32Array(17),l=new Uint32Array(17),w=new Uint32Array(17);for(y=0;y<17;y++)u[y]=p[y]=0;for(y=0;y<16;y++)u[y]=a[y];for(u[3]&=15,u[4]&=252,u[7]&=15,u[8]&=252,u[11]&=15,u[12]&=252,u[15]&=15;o>0;){for(y=0;y<17;y++)l[y]=0;for(y=0;y<16&&y<o;++y)l[y]=n[t+y];for(l[y]=1,t+=y,o-=y,add1305(p,l),i=0;i<17;i++)for(f[i]=0,y=0;y<17;y++)f[i]=f[i]+p[y]*(y<=i?u[i-y]:320*u[i+17-y]|0)|0;for(i=0;i<17;i++)p[i]=f[i];for(s=0,y=0;y<16;y++)s=s+p[y]|0,p[y]=255&s,s>>>=8;for(s=s+p[16]|0,p[16]=3&s,s=5*(s>>>2)|0,y=0;y<16;y++)s=s+p[y]|0,p[y]=255&s,s>>>=8;s=s+p[16]|0,p[16]=s}for(y=0;y<17;y++)w[y]=p[y];for(add1305(p,_),c=0|-(p[16]>>>7),y=0;y<17;y++)p[y]^=c&(w[y]^p[y]);for(y=0;y<16;y++)l[y]=a[y+16];for(l[16]=0,add1305(p,l),y=0;y<16;y++)r[e+y]=p[y];return 0}function crypto_onetimeauth_verify(r,e,n,t,o,a){var c=new Uint8Array(16);return crypto_onetimeauth(c,0,n,t,o,a),crypto_verify_16(r,e,c,0)}function crypto_secretbox(r,e,n,t,o){var a;if(n<32)return-1;for(crypto_stream_xor(r,0,e,0,n,t,o),crypto_onetimeauth(r,16,r,32,n-32,r),a=0;a<16;a++)r[a]=0;return 0}function crypto_secretbox_open(r,e,n,t,o){var a,c=new Uint8Array(32);if(n<32)return-1;if(crypto_stream(c,0,32,t,o),0!==crypto_onetimeauth_verify(e,16,e,32,n-32,c))return-1;for(crypto_stream_xor(r,0,e,0,n,t,o),a=0;a<32;a++)r[a]=0;return 0}function set25519(r,e){var n;for(n=0;n<16;n++)r[n]=0|e[n]}function car25519(r){var e,n;for(n=0;n<16;n++)r[n]+=65536,e=Math.floor(r[n]/65536),r[(n+1)*(n<15?1:0)]+=e-1+37*(e-1)*(15===n?1:0),r[n]-=65536*e}function sel25519(r,e,n){for(var t,o=~(n-1),a=0;a<16;a++)t=o&(r[a]^e[a]),r[a]^=t,e[a]^=t}function pack25519(r,e){var n,t,o,a=gf(),c=gf();for(n=0;n<16;n++)c[n]=e[n];for(car25519(c),car25519(c),car25519(c),t=0;t<2;t++){for(a[0]=c[0]-65517,n=1;n<15;n++)a[n]=c[n]-65535-(a[n-1]>>16&1),a[n-1]&=65535;a[15]=c[15]-32767-(a[14]>>16&1),o=a[15]>>16&1,a[14]&=65535,sel25519(c,a,1-o)}for(n=0;n<16;n++)r[2*n]=255&c[n],r[2*n+1]=c[n]>>8}function neq25519(r,e){var n=new Uint8Array(32),t=new Uint8Array(32);return pack25519(n,r),pack25519(t,e),crypto_verify_32(n,0,t,0)}function par25519(r){var e=new Uint8Array(32);return pack25519(e,r),1&e[0]}function unpack25519(r,e){var n;for(n=0;n<16;n++)r[n]=e[2*n]+(e[2*n+1]<<8);r[15]&=32767}function A(r,e,n){var t;for(t=0;t<16;t++)r[t]=e[t]+n[t]|0}function Z(r,e,n){var t;for(t=0;t<16;t++)r[t]=e[t]-n[t]|0}function M(r,e,n){var t,o,a=new Float64Array(31);for(t=0;t<31;t++)a[t]=0;for(t=0;t<16;t++)for(o=0;o<16;o++)a[t+o]+=e[t]*n[o];for(t=0;t<15;t++)a[t]+=38*a[t+16];for(t=0;t<16;t++)r[t]=a[t];car25519(r),car25519(r)}function S(r,e){M(r,e,e)}function inv25519(r,e){var n,t=gf();for(n=0;n<16;n++)t[n]=e[n];for(n=253;n>=0;n--)S(t,t),2!==n&&4!==n&&M(t,t,e);for(n=0;n<16;n++)r[n]=t[n]}function pow2523(r,e){var n,t=gf();for(n=0;n<16;n++)t[n]=e[n];for(n=250;n>=0;n--)S(t,t),1!==n&&M(t,t,e);for(n=0;n<16;n++)r[n]=t[n]}function crypto_scalarmult(r,e,n){var t,o,c=new Uint8Array(32),i=new Float64Array(80),y=gf(),s=gf(),f=gf(),u=gf(),_=gf(),p=gf();for(o=0;o<31;o++)c[o]=e[o];for(c[31]=127&e[31]|64,c[0]&=248,unpack25519(i,n),o=0;o<16;o++)s[o]=i[o],u[o]=y[o]=f[o]=0;for(y[0]=u[0]=1,o=254;o>=0;--o)sel25519(y,s,t=c[o>>>3]>>>(7&o)&1),sel25519(f,u,t),A(_,y,f),Z(y,y,f),A(f,s,u),Z(s,s,u),S(u,_),S(p,y),M(y,f,y),M(f,s,_),A(_,y,f),Z(y,y,f),S(s,y),Z(f,u,p),M(y,f,a),A(y,y,u),M(f,f,y),M(y,u,p),M(u,s,i),S(s,_),sel25519(y,s,t),sel25519(f,u,t);for(o=0;o<16;o++)i[o+16]=y[o],i[o+32]=f[o],i[o+48]=s[o],i[o+64]=u[o];var l=i.subarray(32),w=i.subarray(16);return inv25519(l,l),M(w,w,l),pack25519(r,w),0}function crypto_scalarmult_base(r,e){return crypto_scalarmult(r,e,n)}function crypto_box_keypair(r,e){return randombytes(e,32),crypto_scalarmult_base(r,e)}function crypto_box_beforenm(r,n,t){var o=new Uint8Array(32);return crypto_scalarmult(o,t,n),crypto_core_hsalsa20(r,e,o,u)}var p=crypto_secretbox,l=crypto_secretbox_open;function add64(){var r,e,n,t=0,o=0,a=0,c=0,i=65535;for(n=0;n<arguments.length;n++)t+=(r=arguments[n].lo)&i,o+=r>>>16,a+=(e=arguments[n].hi)&i,c+=e>>>16;return new u64((a+=(o+=t>>>16)>>>16)&i|(c+=a>>>16)<<16,t&i|o<<16)}function shr64(r,e){return new u64(r.hi>>>e,r.lo>>>e|r.hi<<32-e)}function xor64(){var r,e=0,n=0;for(r=0;r<arguments.length;r++)e^=arguments[r].lo,n^=arguments[r].hi;return new u64(n,e)}function R(r,e){var n,t,o=32-e;return e<32?(n=r.hi>>>e|r.lo<<o,t=r.lo>>>e|r.hi<<o):e<64&&(n=r.lo>>>e|r.hi<<o,t=r.hi>>>e|r.lo<<o),new u64(n,t)}function Ch(r,e,n){var t=r.hi&e.hi^~r.hi&n.hi,o=r.lo&e.lo^~r.lo&n.lo;return new u64(t,o)}function Maj(r,e,n){var t=r.hi&e.hi^r.hi&n.hi^e.hi&n.hi,o=r.lo&e.lo^r.lo&n.lo^e.lo&n.lo;return new u64(t,o)}function Sigma0(r){return xor64(R(r,28),R(r,34),R(r,39))}function Sigma1(r){return xor64(R(r,14),R(r,18),R(r,41))}function sigma0(r){return xor64(R(r,1),R(r,8),shr64(r,7))}function sigma1(r){return xor64(R(r,19),R(r,61),shr64(r,6))}var w=[new u64(1116352408,3609767458),new u64(1899447441,602891725),new u64(3049323471,3964484399),new u64(3921009573,2173295548),new u64(961987163,4081628472),new u64(1508970993,3053834265),new u64(2453635748,2937671579),new u64(2870763221,3664609560),new u64(3624381080,2734883394),new u64(310598401,1164996542),new u64(607225278,1323610764),new u64(1426881987,3590304994),new u64(1925078388,4068182383),new u64(2162078206,991336113),new u64(2614888103,633803317),new u64(3248222580,3479774868),new u64(3835390401,2666613458),new u64(4022224774,944711139),new u64(264347078,2341262773),new u64(604807628,2007800933),new u64(770255983,1495990901),new u64(1249150122,1856431235),new u64(1555081692,3175218132),new u64(1996064986,2198950837),new u64(2554220882,3999719339),new u64(2821834349,766784016),new u64(2952996808,2566594879),new u64(3210313671,3203337956),new u64(3336571891,1034457026),new u64(3584528711,2466948901),new u64(113926993,3758326383),new u64(338241895,168717936),new u64(666307205,1188179964),new u64(773529912,1546045734),new u64(1294757372,1522805485),new u64(1396182291,2643833823),new u64(1695183700,2343527390),new u64(1986661051,1014477480),new u64(2177026350,1206759142),new u64(2456956037,344077627),new u64(2730485921,1290863460),new u64(2820302411,3158454273),new u64(3259730800,3505952657),new u64(3345764771,106217008),new u64(3516065817,3606008344),new u64(3600352804,1432725776),new u64(4094571909,1467031594),new u64(275423344,851169720),new u64(430227734,3100823752),new u64(506948616,1363258195),new u64(659060556,3750685593),new u64(883997877,3785050280),new u64(958139571,3318307427),new u64(1322822218,3812723403),new u64(1537002063,2003034995),new u64(1747873779,3602036899),new u64(1955562222,1575990012),new u64(2024104815,1125592928),new u64(2227730452,2716904306),new u64(2361852424,442776044),new u64(2428436474,593698344),new u64(2756734187,3733110249),new u64(3204031479,2999351573),new u64(3329325298,3815920427),new u64(3391569614,3928383900),new u64(3515267271,566280711),new u64(3940187606,3454069534),new u64(4118630271,4000239992),new u64(116418474,1914138554),new u64(174292421,2731055270),new u64(289380356,3203993006),new u64(460393269,320620315),new u64(685471733,587496836),new u64(852142971,1086792851),new u64(1017036298,365543100),new u64(1126000580,2618297676),new u64(1288033470,3409855158),new u64(1501505948,4234509866),new u64(1607167915,987167468),new u64(1816402316,1246189591)];function crypto_hashblocks(r,e,n){var t,o,a,c=[],i=[],y=[],s=[];for(o=0;o<8;o++)c[o]=y[o]=dl64(r,8*o);for(var f=0;n>=128;){for(o=0;o<16;o++)s[o]=dl64(e,8*o+f);for(o=0;o<80;o++){for(a=0;a<8;a++)i[a]=y[a];for(t=add64(y[7],Sigma1(y[4]),Ch(y[4],y[5],y[6]),w[o],s[o%16]),i[7]=add64(t,Sigma0(y[0]),Maj(y[0],y[1],y[2])),i[3]=add64(i[3],t),a=0;a<8;a++)y[(a+1)%8]=i[a];if(o%16==15)for(a=0;a<16;a++)s[a]=add64(s[a],s[(a+9)%16],sigma0(s[(a+1)%16]),sigma1(s[(a+14)%16]))}for(o=0;o<8;o++)y[o]=add64(y[o],c[o]),c[o]=y[o];f+=128,n-=128}for(o=0;o<8;o++)ts64(r,8*o,c[o]);return n}var h=new Uint8Array([106,9,230,103,243,188,201,8,187,103,174,133,132,202,167,59,60,110,243,114,254,148,248,43,165,79,245,58,95,29,54,241,81,14,82,127,173,230,130,209,155,5,104,140,43,62,108,31,31,131,217,171,251,65,189,107,91,224,205,25,19,126,33,121]);function crypto_hash(r,e,n){var t,o=new Uint8Array(64),a=new Uint8Array(256),c=n;for(t=0;t<64;t++)o[t]=h[t];for(crypto_hashblocks(o,e,n),n%=128,t=0;t<256;t++)a[t]=0;for(t=0;t<n;t++)a[t]=e[c-n+t];for(a[n]=128,a[(n=256-128*(n<112?1:0))-9]=0,ts64(a,n-8,new u64(c/536870912|0,c<<3)),crypto_hashblocks(o,a,n),t=0;t<64;t++)r[t]=o[t];return 0}function add(r,e){var n=gf(),t=gf(),o=gf(),a=gf(),c=gf(),y=gf(),s=gf(),f=gf(),u=gf();Z(n,r[1],r[0]),Z(u,e[1],e[0]),M(n,n,u),A(t,r[0],r[1]),A(u,e[0],e[1]),M(t,t,u),M(o,r[3],e[3]),M(o,o,i),M(a,r[2],e[2]),A(a,a,a),Z(c,t,n),Z(y,a,o),A(s,a,o),A(f,t,n),M(r[0],c,y),M(r[1],f,s),M(r[2],s,y),M(r[3],c,f)}function cswap(r,e,n){var t;for(t=0;t<4;t++)sel25519(r[t],e[t],n)}function pack(r,e){var n=gf(),t=gf(),o=gf();inv25519(o,e[2]),M(n,e[0],o),M(t,e[1],o),pack25519(r,t),r[31]^=par25519(n)<<7}function scalarmult(r,e,n){var a,c;for(set25519(r[0],t),set25519(r[1],o),set25519(r[2],o),set25519(r[3],t),c=255;c>=0;--c)cswap(r,e,a=n[c/8|0]>>(7&c)&1),add(e,r),add(r,r),cswap(r,e,a)}function scalarbase(r,e){var n=[gf(),gf(),gf(),gf()];set25519(n[0],y),set25519(n[1],s),set25519(n[2],o),M(n[3],y,s),scalarmult(r,n,e)}function crypto_sign_keypair(r,e,n){var t,o=new Uint8Array(64),a=[gf(),gf(),gf(),gf()];for(n||randombytes(e,32),crypto_hash(o,e,32),o[0]&=248,o[31]&=127,o[31]|=64,scalarbase(a,o),pack(r,a),t=0;t<32;t++)e[t+32]=r[t];return 0}var b=new Float64Array([237,211,245,92,26,99,18,88,214,156,247,162,222,249,222,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16]);function modL(r,e){var n,t,o,a;for(t=63;t>=32;--t){for(n=0,o=t-32,a=t-12;o<a;++o)e[o]+=n-16*e[t]*b[o-(t-32)],n=Math.floor((e[o]+128)/256),e[o]-=256*n;e[o]+=n,e[t]=0}for(n=0,o=0;o<32;o++)e[o]+=n-(e[31]>>4)*b[o],n=e[o]>>8,e[o]&=255;for(o=0;o<32;o++)e[o]-=n*b[o];for(t=0;t<32;t++)e[t+1]+=e[t]>>8,r[t]=255&e[t]}function reduce(r){var e,n=new Float64Array(64);for(e=0;e<64;e++)n[e]=r[e];for(e=0;e<64;e++)r[e]=0;modL(r,n)}function crypto_sign(r,e,n,t){var o,a,c=new Uint8Array(64),i=new Uint8Array(64),y=new Uint8Array(64),s=new Float64Array(64),f=[gf(),gf(),gf(),gf()];crypto_hash(c,t,32),c[0]&=248,c[31]&=127,c[31]|=64;var u=n+64;for(o=0;o<n;o++)r[64+o]=e[o];for(o=0;o<32;o++)r[32+o]=c[32+o];for(crypto_hash(y,r.subarray(32),n+32),reduce(y),scalarbase(f,y),pack(r,f),o=32;o<64;o++)r[o]=t[o];for(crypto_hash(i,r,n+64),reduce(i),o=0;o<64;o++)s[o]=0;for(o=0;o<32;o++)s[o]=y[o];for(o=0;o<32;o++)for(a=0;a<32;a++)s[o+a]+=i[o]*c[a];return modL(r.subarray(32),s),u}function crypto_sign_open(r,e,n,a){var i,y=new Uint8Array(32),s=new Uint8Array(64),u=[gf(),gf(),gf(),gf()],_=[gf(),gf(),gf(),gf()];if(n<64)return-1;if(function(r,e){var n=gf(),a=gf(),i=gf(),y=gf(),s=gf(),u=gf(),_=gf();return set25519(r[2],o),unpack25519(r[1],e),S(i,r[1]),M(y,i,c),Z(i,i,r[2]),A(y,r[2],y),S(s,y),S(u,s),M(_,u,s),M(n,_,i),M(n,n,y),pow2523(n,n),M(n,n,i),M(n,n,y),M(n,n,y),M(r[0],n,y),S(a,r[0]),M(a,a,y),neq25519(a,i)&&M(r[0],r[0],f),S(a,r[0]),M(a,a,y),neq25519(a,i)?-1:(par25519(r[0])===e[31]>>7&&Z(r[0],t,r[0]),M(r[3],r[0],r[1]),0)}(_,a))return-1;for(i=0;i<n;i++)r[i]=e[i];for(i=0;i<32;i++)r[i+32]=a[i];if(crypto_hash(s,r,n),reduce(s),scalarmult(u,_,s),scalarbase(_,e.subarray(32)),add(u,_),pack(y,u),n-=64,crypto_verify_32(e,0,y,0)){for(i=0;i<n;i++)r[i]=0;return-1}for(i=0;i<n;i++)r[i]=e[i+64];return n}var g=16,v=64,d=32,m=64;function checkLengths(r,e){if(32!==r.length)throw new Error("bad key size");if(24!==e.length)throw new Error("bad nonce size")}function checkArrayTypes(){for(var r=0;r<arguments.length;r++)if(!(arguments[r]instanceof Uint8Array))throw new TypeError("unexpected type, use Uint8Array")}r.lowlevel={crypto_core_hsalsa20:crypto_core_hsalsa20,crypto_stream_xor:crypto_stream_xor,crypto_stream:crypto_stream,crypto_stream_salsa20_xor:crypto_stream_salsa20_xor,crypto_stream_salsa20:crypto_stream_salsa20,crypto_onetimeauth:crypto_onetimeauth,crypto_onetimeauth_verify:crypto_onetimeauth_verify,crypto_verify_16:crypto_verify_16,crypto_verify_32:crypto_verify_32,crypto_secretbox:crypto_secretbox,crypto_secretbox_open:crypto_secretbox_open,crypto_scalarmult:crypto_scalarmult,crypto_scalarmult_base:crypto_scalarmult_base,crypto_box_beforenm:crypto_box_beforenm,crypto_box_afternm:p,crypto_box:function(r,e,n,t,o,a){var c=new Uint8Array(32);return crypto_box_beforenm(c,o,a),p(r,e,n,t,c)},crypto_box_open:function(r,e,n,t,o,a){var c=new Uint8Array(32);return crypto_box_beforenm(c,o,a),l(r,e,n,t,c)},crypto_box_keypair:crypto_box_keypair,crypto_hash:crypto_hash,crypto_sign:crypto_sign,crypto_sign_keypair:crypto_sign_keypair,crypto_sign_open:crypto_sign_open,crypto_secretbox_KEYBYTES:32,crypto_secretbox_NONCEBYTES:24,crypto_secretbox_ZEROBYTES:32,crypto_secretbox_BOXZEROBYTES:g,crypto_scalarmult_BYTES:32,crypto_scalarmult_SCALARBYTES:32,crypto_box_PUBLICKEYBYTES:32,crypto_box_SECRETKEYBYTES:32,crypto_box_BEFORENMBYTES:32,crypto_box_NONCEBYTES:24,crypto_box_ZEROBYTES:32,crypto_box_BOXZEROBYTES:16,crypto_sign_BYTES:v,crypto_sign_PUBLICKEYBYTES:d,crypto_sign_SECRETKEYBYTES:m,crypto_sign_SEEDBYTES:32,crypto_hash_BYTES:64,gf:gf,D:c,L:b,pack25519:pack25519,unpack25519:unpack25519,M:M,A:A,S:S,Z:Z,pow2523:pow2523,add:add,set25519:set25519,modL:modL,scalarmult:scalarmult,scalarbase:scalarbase},r.randomBytes=function(r){var e=new Uint8Array(r);return randombytes(e,r),e},r.secretbox=function(r,e,n){checkArrayTypes(r,e,n),checkLengths(n,e);for(var t=new Uint8Array(32+r.length),o=new Uint8Array(t.length),a=0;a<r.length;a++)t[a+32]=r[a];return crypto_secretbox(o,t,t.length,e,n),o.subarray(g)},r.secretbox.open=function(r,e,n){checkArrayTypes(r,e,n),checkLengths(n,e);for(var t=new Uint8Array(g+r.length),o=new Uint8Array(t.length),a=0;a<r.length;a++)t[a+g]=r[a];return t.length<32||0!==crypto_secretbox_open(o,t,t.length,e,n)?null:o.subarray(32)},r.secretbox.keyLength=32,r.secretbox.nonceLength=24,r.secretbox.overheadLength=g,r.scalarMult=function(r,e){if(checkArrayTypes(r,e),32!==r.length)throw new Error("bad n size");if(32!==e.length)throw new Error("bad p size");var n=new Uint8Array(32);return crypto_scalarmult(n,r,e),n},r.scalarMult.base=function(r){if(checkArrayTypes(r),32!==r.length)throw new Error("bad n size");var e=new Uint8Array(32);return crypto_scalarmult_base(e,r),e},r.scalarMult.scalarLength=32,r.scalarMult.groupElementLength=32,r.box=function(e,n,t,o){var a=r.box.before(t,o);return r.secretbox(e,n,a)},r.box.before=function(r,e){checkArrayTypes(r,e),function(r,e){if(32!==r.length)throw new Error("bad public key size");if(32!==e.length)throw new Error("bad secret key size")}(r,e);var n=new Uint8Array(32);return crypto_box_beforenm(n,r,e),n},r.box.after=r.secretbox,r.box.open=function(e,n,t,o){var a=r.box.before(t,o);return r.secretbox.open(e,n,a)},r.box.open.after=r.secretbox.open,r.box.keyPair=function(){var r=new Uint8Array(32),e=new Uint8Array(32);return crypto_box_keypair(r,e),{publicKey:r,secretKey:e}},r.box.keyPair.fromSecretKey=function(r){if(checkArrayTypes(r),32!==r.length)throw new Error("bad secret key size");var e=new Uint8Array(32);return crypto_scalarmult_base(e,r),{publicKey:e,secretKey:new Uint8Array(r)}},r.box.publicKeyLength=32,r.box.secretKeyLength=32,r.box.sharedKeyLength=32,r.box.nonceLength=24,r.box.overheadLength=r.secretbox.overheadLength,r.sign=function(r,e){if(checkArrayTypes(r,e),e.length!==m)throw new Error("bad secret key size");var n=new Uint8Array(v+r.length);return crypto_sign(n,r,r.length,e),n},r.sign.open=function(r,e){if(checkArrayTypes(r,e),e.length!==d)throw new Error("bad public key size");var n=new Uint8Array(r.length),t=crypto_sign_open(n,r,r.length,e);if(t<0)return null;for(var o=new Uint8Array(t),a=0;a<o.length;a++)o[a]=n[a];return o},r.sign.detached=function(e,n){for(var t=r.sign(e,n),o=new Uint8Array(v),a=0;a<o.length;a++)o[a]=t[a];return o},r.sign.detached.verify=function(r,e,n){if(checkArrayTypes(r,e,n),e.length!==v)throw new Error("bad signature size");if(n.length!==d)throw new Error("bad public key size");var t,o=new Uint8Array(v+r.length),a=new Uint8Array(v+r.length);for(t=0;t<v;t++)o[t]=e[t];for(t=0;t<r.length;t++)o[t+v]=r[t];return crypto_sign_open(a,o,o.length,n)>=0},r.sign.keyPair=function(){var r=new Uint8Array(d),e=new Uint8Array(m);return crypto_sign_keypair(r,e),{publicKey:r,secretKey:e}},r.sign.keyPair.fromSecretKey=function(r){if(checkArrayTypes(r),r.length!==m)throw new Error("bad secret key size");for(var e=new Uint8Array(d),n=0;n<e.length;n++)e[n]=r[32+n];return{publicKey:e,secretKey:new Uint8Array(r)}},r.sign.keyPair.fromSeed=function(r){if(checkArrayTypes(r),32!==r.length)throw new Error("bad seed size");for(var e=new Uint8Array(d),n=new Uint8Array(m),t=0;t<32;t++)n[t]=r[t];return crypto_sign_keypair(e,n,!0),{publicKey:e,secretKey:n}},r.sign.publicKeyLength=d,r.sign.secretKeyLength=m,r.sign.seedLength=32,r.sign.signatureLength=v,r.hash=function(r){checkArrayTypes(r);var e=new Uint8Array(64);return crypto_hash(e,r,r.length),e},r.hash.hashLength=64,r.verify=function(r,e){return checkArrayTypes(r,e),0!==r.length&&0!==e.length&&(r.length===e.length&&0===vn(r,0,e,0,r.length))},r.setPRNG=function(r){randombytes=r},function(){if("undefined"==typeof wx||"function"!=typeof wx.getRandomValues)throw new Error("No suitable random number generator available.");r.setPRNG((function(r,e){wx.getRandomValues({length:e,success:n=>{const t=new Uint8Array(n.randomValues);for(var o=0;o<e;o++)r[o]=t[o];!function(r){for(var e=0;e<r.length;e++)r[e]=0}(t)}})}))}()}("undefined"!=typeof module&&module.exports?module.exports:self.nacl=self.nacl||{});