@tmsfe/tms-core 0.0.158 → 0.0.160

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.158",
3
+ "version": "0.0.160",
4
4
  "description": "tms运行时框架",
5
5
  "repository": {
6
6
  "type": "git",
@@ -3,6 +3,7 @@
3
3
  * 暴露出来的工具函数封装原则:不可以向外throw错误,返回执行结果统一格式:{ success: boolean, msg: string, res: any }
4
4
  * https://iwiki.woa.com/p/4013041987#1.-RSA+AES-%E5%88%87%E6%8D%A2-Curve25519+XSalsa20%EF%BC%9A
5
5
  */
6
+ import md5 from './md5';
6
7
  /* eslint-disable @typescript-eslint/no-require-imports */
7
8
  const ecc = require('./nacl.min.js');
8
9
  const base64Util = require('./nacl-util.min.js');
@@ -106,12 +107,10 @@ const eccUtil = {
106
107
  method: 'POST',
107
108
  data,
108
109
  enableHttp2: true,
109
- success: (res) => {
110
- const success = eccUtil._updateGlobalPublicKeyInfo(false, res.header);
111
- resolve(success);
110
+ success: () => {
111
+ resolve(true);
112
112
  },
113
113
  fail: () => {
114
- eccUtil._updateGlobalPublicKeyInfo(true);
115
114
  resolve(false);
116
115
  },
117
116
  });
@@ -135,10 +134,10 @@ const eccUtil = {
135
134
  return new baseUtil.BaseRespFac(success);
136
135
  },
137
136
  _privateKeyInfo: null,
138
- getPrivateKeyInfo: (): CryptoKeyInfo => {
137
+ getPrivateKeyInfo: (forceUpdate = false): CryptoKeyInfo => {
139
138
  if (!wx.$_publicKey) return null;
140
139
  const serverPubInfo = wx.$_publicKey;
141
- if (!eccUtil._privateKeyInfo || eccUtil._privateKeyInfo.serverPubId !== serverPubInfo.pubId) {
140
+ if (forceUpdate || !eccUtil._privateKeyInfo || eccUtil._privateKeyInfo.serverPubId !== serverPubInfo.pubId) {
142
141
  const keyPair = ecc.box.keyPair(); // 生成客户端公钥私钥
143
142
  eccUtil._privateKeyInfo = {
144
143
  serverPubId: serverPubInfo.pubId, // 服务端公钥id
@@ -156,27 +155,83 @@ const eccUtil = {
156
155
  switch (code) {
157
156
  case 0:
158
157
  return { retry: false, success: true };
159
- case 11300: // 解密失败
160
- return { retry: false, success: false };
161
- case 11305: // 公钥id无效
158
+ case 11305: // 公钥id无效
162
159
  case 11306: { // 公钥过期
163
- const genPubSuccess = await eccUtil._refreshPubKeyInfo(true); // 1. 获取公钥
164
- if (!genPubSuccess) return { retry: false, success: false };
165
- eccUtil.getPrivateKeyInfo(); // 2. 生成私钥
160
+ // 1. 获取公钥
161
+ eccUtil._refreshPubKeyInfo(true).then((genPubSuccess) => {
162
+ genPubSuccess && eccUtil.getPrivateKeyInfo(); // 2. 生成私钥
163
+ });
166
164
  return { retry: true, success: false };
167
165
  }
168
- case 11307: // 加密未开启
169
- return { retry: false, success: false };
166
+ case 11308: { // 密钥对有问题
167
+ eccUtil.getPrivateKeyInfo(true); // 重新生成私钥
168
+ return { retry: true, success: false };
169
+ }
170
+ case 11300: // 解密失败
170
171
  case 11301:
171
172
  case 11302:
172
173
  case 11303:
173
174
  case 11304:
174
- case 11308:
175
+ case 11307: // 加密未开启
176
+ return { retry: true, success: false };
177
+ case 11309:
175
178
  return { retry: false, success: false };
176
179
  default: // 其他网关错误码
177
180
  return { retry: false, success: true };
178
181
  }
179
182
  },
183
+ _getSignSharedByte: () => baseUtil.decUrl('mEufQpM1n5J8-OZZoJE7ucYMC2suTjfsHUq_6z5cyh8'),
184
+ // 计算客户端加密签名
185
+ getClientCryptoSign: (data = {}, header = {}, sharedByte): string => {
186
+ const obj = baseUtil.formatHeader(Object.assign({}, data, header));
187
+ // 1. 生成签名前的字符串
188
+ const str = Object.keys(obj).filter(item => obj[item])
189
+ .sort()
190
+ .reduce((pre, cur) => {
191
+ pre.push(`${cur}=${obj[cur]}`);
192
+ return pre;
193
+ }, [])
194
+ .join('&');
195
+ // 2. md5
196
+ const md5Str = md5(str);
197
+ const nonce = ecc.randomBytes(ecc.box.nonceLength);
198
+ const encrypted = ecc.box.after(md5Str, nonce, sharedByte);
199
+ const combined = new Uint8Array(nonce.length + encrypted.length);
200
+ combined.set(nonce);
201
+ combined.set(encrypted, nonce.length);
202
+ return baseUtil.encUrl(combined);
203
+ },
204
+ // 验证服务端加密签名
205
+ verifyServerCryptoSign: (traceId: string, resHeader = {}): boolean => {
206
+ const formatHeader = baseUtil.formatHeader(resHeader);
207
+ const signStr = formatHeader['x-crypto-sign'];
208
+ const obj = {
209
+ 'x-encrypt-key': formatHeader['x-encrypt-key'],
210
+ 'x-encrypt-response': formatHeader['x-encrypt-response'],
211
+ 'x-response-header-name': formatHeader['x-response-header-name'],
212
+ 'x-encrypted-headers': formatHeader['x-encrypted-headers'],
213
+ 'x-crypto-enable': formatHeader['x-crypto-enable'],
214
+ 'content-type': formatHeader['content-type'],
215
+ 'x-gateway-code': formatHeader['x-gateway-code'],
216
+ 'x-crypto-pub-id': formatHeader['x-crypto-pub-id'],
217
+ 'x-crypto-pub-key': formatHeader['x-crypto-pub-key'],
218
+ 'x-crypto-pub-exp': formatHeader['x-crypto-pub-exp'],
219
+ 'x-crypto-path': formatHeader['x-crypto-path'],
220
+ 'x-trace-id': traceId,
221
+ };
222
+ const msg = baseUtil.decUrl(signStr);
223
+ const decrypted = ecc.sign.open(msg, eccUtil._getSignSharedByte());
224
+ const str = Object.keys(obj).filter(item => obj[item])
225
+ .sort()
226
+ .reduce((pre, cur) => {
227
+ pre.push(`${cur}=${obj[cur]}`);
228
+ return pre;
229
+ }, [])
230
+ .join('&');
231
+ const preHashArr = md5(str);
232
+ const verified = preHashArr.length === decrypted.length && preHashArr.every((v, i) => v === decrypted[i]);
233
+ return verified;
234
+ },
180
235
  /* eslint-enable complexity */
181
236
  execEncrypt: (input: string, ignoreNull = false): BaseResp<{
182
237
  cryptoKeyInfo: CryptoKeyInfo,
@@ -357,23 +412,30 @@ const reqEncrypt = (method: string, data: any, header: {
357
412
  if (!success) {
358
413
  return new baseUtil.BaseRespFac(null, false, `请求Header加密失败: ${msg}`);
359
414
  }
415
+ const cryptoHeader = {
416
+ 'X-Crypto-Mode': '2', // ecc加密模式
417
+ 'X-Encrypted-Headers': res.encryptedContent,
418
+ 'X-Encrypt-Pub': res.cryptoKeyInfo.serverPubId,
419
+ 'X-Encrypt-Key': res.cryptoKeyInfo.clientPublicKey,
420
+ 'X-Encrypt-Response': '3', // 加密,二进制
421
+ 'X-Response-Header-Name': encryptedResponseHeaderName,
422
+ 'Content-Type': 'text/plain',
423
+ };
424
+ const cryptoSign = eccUtil.getClientCryptoSign(baseUtil._isObject(finalData) ? finalData : {
425
+ body: finalData,
426
+ }, cryptoHeader, res.cryptoKeyInfo.sharedByte);
360
427
  return new baseUtil.BaseRespFac({
361
428
  cryptoKeyInfo: res.cryptoKeyInfo,
362
429
  data: finalData,
363
430
  header: {
364
- 'Content-Type': 'text/plain',
365
- 'X-Crypto-Mode': '2', // ecc加密模式
366
- 'X-Encrypted-Headers': res.encryptedContent,
367
- 'X-Encrypt-Pub': res.cryptoKeyInfo.serverPubId,
368
- 'X-Encrypt-Key': res.cryptoKeyInfo.clientPublicKey,
369
- 'X-Encrypt-Response': '3', // 加密,二进制
370
- 'X-Response-Header-Name': encryptedResponseHeaderName,
431
+ ...cryptoHeader,
432
+ 'X-Crypto-Sign': cryptoSign,
371
433
  },
372
434
  });
373
435
  };
374
436
  // 解密请求结果
375
- const resDecrypt = async (header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<BaseResp<{
376
- retry: boolean,
437
+ const resDecrypt = async (requestTraceId: string, header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<BaseResp<{
438
+ retry: boolean, // 是否需要明文重试
377
439
  header: any,
378
440
  data: any,
379
441
  }>> => {
@@ -397,13 +459,19 @@ const resDecrypt = async (header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<B
397
459
  }
398
460
  const { retry, success: gwSuccess } = await eccUtil.resolveGwCode(gatewayCode);
399
461
  if (!gwSuccess) {
462
+ // 网关加密流程出现问题,需要验证网关签名
463
+ const verified = eccUtil.verifyServerCryptoSign(requestTraceId, header);
464
+ if (!verified) {
465
+ // 验证失败,表示请求被篡改
466
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, '响应被篡改');
467
+ }
400
468
  return new baseUtil.BaseRespFac({ header: null, data: null, retry }, false, `网关返回错误码: ${gatewayCode}`);
401
469
  }
402
470
  let decryptedHeaders = {};
403
471
  if (encryptedResponseHeaderName) { // 解密响应Header
404
472
  const { success, msg, res } = eccUtil.execDecrypt(baseUtil.decUrl(encryptedHeaders), cryptoKeyInfo);
405
473
  if (!success) {
406
- return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Header失败: ${msg}`);
474
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: true }, false, `解密响应Header失败: ${msg}`);
407
475
  }
408
476
  decryptedHeaders = JSON.parse(res);
409
477
  }
@@ -411,7 +479,7 @@ const resDecrypt = async (header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<B
411
479
  const cipher = needDecode ? baseUtil.decUrl(data) : new Uint8Array(data);
412
480
  const { success, msg, res } = eccUtil.execDecrypt(cipher, cryptoKeyInfo);
413
481
  if (!success) {
414
- return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Body失败: ${msg}`);
482
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: true }, false, `解密响应Body失败: ${msg}`);
415
483
  }
416
484
  const decryptedBody = JSON.parse(res); // 解密响应Body
417
485
  return new baseUtil.BaseRespFac({
@@ -424,24 +492,40 @@ const resDecrypt = async (header, data, cryptoKeyInfo: CryptoKeyInfo): Promise<B
424
492
  });
425
493
  } catch (e) {
426
494
  // 因为上面的逻辑有parse, 所以这里再加一个catch
427
- return new baseUtil.BaseRespFac({ header: null, data: null, retry: false }, false, `解密响应Body失败: ${JSON.stringify(e)}`);
495
+ return new baseUtil.BaseRespFac({ header: null, data: null, retry: true }, false, `解密响应Body失败: ${JSON.stringify(e)}`);
428
496
  }
429
497
  };
430
498
  // 处理接下来的请求开关
431
499
  let dealEncryptionSwitching = false;
432
- const dealEncryptionSwitch = async (path: string, resHeader): Promise<void> => {
500
+ const dealEncryptionSwitch = async (path: string, traceId: string, resHeader): Promise<boolean> => {
433
501
  if ((!resHeader || dealEncryptionSwitching)) {
434
502
  return;
435
503
  }
436
504
  dealEncryptionSwitching = true;
437
505
  const formatHeader = baseUtil.formatHeader(resHeader);
438
506
  if (formatHeader['x-crypto-enable'] === '0') {
439
- eccUtil.closeCrypto();
507
+ // 网关加密验签,验签通过才能执行关闭
508
+ const verified = eccUtil.verifyServerCryptoSign(traceId, formatHeader);
509
+ if (verified) {
510
+ eccUtil.closeCrypto();
511
+ }
440
512
  } else if (formatHeader['x-crypto-enable'] === '1') {
441
- `${baseUtil.getSinanHost()}/user/login` === path && eccUtil._updateGlobalPublicKeyInfo(false, formatHeader);
513
+ if ([
514
+ `${baseUtil.getSinanHost()}/user/login`,
515
+ `${baseUtil.getSinanHost()}/basic/crypto/lastkey`,
516
+ ].indexOf(path) > -1) {
517
+ const verified = eccUtil.verifyServerCryptoSign(traceId, formatHeader);
518
+ if (!verified) {
519
+ // 验签失败,表示请求被篡改
520
+ dealEncryptionSwitching = false;
521
+ return false;
522
+ }
523
+ eccUtil._updateGlobalPublicKeyInfo(false, formatHeader);
524
+ }
442
525
  await eccUtil.openCrypto();
443
526
  } // 0是关闭,1是开启, 2是保持
444
527
  dealEncryptionSwitching = false;
528
+ return true;
445
529
  };
446
530
 
447
531
  const encryptUtil = {
@@ -71,6 +71,7 @@ function proxyWxRequest(): void {
71
71
  value(options: any) {
72
72
  const { url, method, data, header = {}, success, fail, complete, dataType, responseType } = options;
73
73
  const traceparent = genTraceparent();
74
+ const traceId = traceparent.split('-')[1];
74
75
  const originalOptions = { ...options };
75
76
 
76
77
  // 如果用户自定义了dataType或者responseType,则不做处理
@@ -79,7 +80,7 @@ function proxyWxRequest(): void {
79
80
  originalRequestApi.call(this, {
80
81
  ...originalOptions,
81
82
  success: (res) => {
82
- encryptUtil.dealEncryptionSwitch(url, res.header);
83
+ encryptUtil.dealEncryptionSwitch(url, traceId, res.header);
83
84
  success?.call(this, res);
84
85
  },
85
86
  header: { ...header, Traceparent: traceparent },
@@ -94,9 +95,14 @@ function proxyWxRequest(): void {
94
95
  util.logInfo(url, traceparent, msg);
95
96
  originalRequestApi.call(this, {
96
97
  ...originalOptions,
97
- success: (res) => {
98
- encryptUtil.dealEncryptionSwitch(url, res.header);
99
- success?.call(this, res);
98
+ success: async (res) => {
99
+ const dealSuccess = await encryptUtil.dealEncryptionSwitch(url, traceId, res.header);
100
+ if (dealSuccess) {
101
+ success?.call(this, res);
102
+ } else {
103
+ util.reportFunc(url, traceparent, `加密验签不通过: ${JSON.stringify(res)}`);
104
+ fail?.call(this, new Error('加密验签不通过'));
105
+ }
100
106
  },
101
107
  header: { ...header, Traceparent: traceparent },
102
108
  });
@@ -115,26 +121,34 @@ function proxyWxRequest(): void {
115
121
  responseType: 'arraybuffer',
116
122
  success: async (result) => {
117
123
  const { header: resHeader, data: resData } = result;
118
- const { success: resSuccess, msg, res } = await encryptUtil.resDecrypt(resHeader, resData, cryptoKeyInfo);
119
- if (resSuccess) {
120
- util.logInfo(url, traceparent, '解密成功');
121
- encryptUtil.dealEncryptionSwitch(url, resHeader);
122
- success?.call(this, res);
123
- const completeRes: any = await completePromp;
124
- completeRes.header = resHeader;
125
- completeRes.data = resData;
126
- complete?.call(this, completeRes);
127
- } else {
124
+ const { success: decSuccess, msg, res } = await encryptUtil
125
+ .resDecrypt(traceId, resHeader, resData, cryptoKeyInfo);
126
+ if (res.retry) { // 解密出现问题,需要明文重试
128
127
  util.reportFunc(url, traceparent, `解密失败:${msg}`);
128
+ const newTraceparent = genTraceparent();
129
+ const traceId = newTraceparent.split('-')[1];
129
130
  originalRequestApi.call(this, {
130
131
  ...originalOptions,
131
132
  success: (res) => {
132
- encryptUtil.dealEncryptionSwitch(url, res.header);
133
+ encryptUtil.dealEncryptionSwitch(url, traceId, res.header);
133
134
  success?.call(this, res);
134
135
  },
135
- header: { ...header, Traceparent: genTraceparent() },
136
+ header: { ...header, Traceparent: newTraceparent },
136
137
  });
138
+ return;
139
+ }
140
+ if (decSuccess) {
141
+ util.logInfo(url, traceparent, '解密成功');
142
+ encryptUtil.dealEncryptionSwitch(url, traceId, resHeader);
143
+ success?.call(this, res);
144
+ } else { // 不支持明文重试,且解密失败
145
+ util.reportFunc(url, traceparent, `解密失败:${msg}`);
146
+ fail?.call(this, new Error(msg));
137
147
  }
148
+ const completeRes: any = await completePromp;
149
+ completeRes.header = resHeader;
150
+ completeRes.data = resData;
151
+ complete?.call(this, completeRes);
138
152
  },
139
153
  fail: async (err) => {
140
154
  fail?.call(this, err);
@@ -0,0 +1 @@
1
+ function safeAdd(x,y){const lsw=(x&0xffff)+(y&0xffff);const msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xffff)}function bitRotateLeft(num,cnt){return(num<<cnt)|(num>>>(32-cnt))}function md5cmn(q,a,b,x,s,t){return safeAdd(bitRotateLeft(safeAdd(safeAdd(a,q),safeAdd(x,t)),s),b)}function md5ff(a,b,c,d,x,s,t){return md5cmn((b&c)|(~b&d),a,b,x,s,t)}function md5gg(a,b,c,d,x,s,t){return md5cmn((b&d)|(c&~d),a,b,x,s,t)}function md5hh(a,b,c,d,x,s,t){return md5cmn(b^c^d,a,b,x,s,t)}function md5ii(a,b,c,d,x,s,t){return md5cmn(c^(b|~d),a,b,x,s,t)}function binlMD5(x,len){x[len>>5]|=0x80<<len%32;x[(((len+64)>>>9)<<4)+14]=len;let a=1732584193;let b=-271733879;let c=-1732584194;let d=271733878;for(let i=0;i<x.length;i+=16){const olda=a;const oldb=b;const oldc=c;const oldd=d;a=md5ff(a,b,c,d,x[i],7,-680876936);d=md5ff(d,a,b,c,x[i+1],12,-389564586);c=md5ff(c,d,a,b,x[i+2],17,606105819);b=md5ff(b,c,d,a,x[i+3],22,-1044525330);a=md5ff(a,b,c,d,x[i+4],7,-176418897);d=md5ff(d,a,b,c,x[i+5],12,1200080426);c=md5ff(c,d,a,b,x[i+6],17,-1473231341);b=md5ff(b,c,d,a,x[i+7],22,-45705983);a=md5ff(a,b,c,d,x[i+8],7,1770035416);d=md5ff(d,a,b,c,x[i+9],12,-1958414417);c=md5ff(c,d,a,b,x[i+10],17,-42063);b=md5ff(b,c,d,a,x[i+11],22,-1990404162);a=md5ff(a,b,c,d,x[i+12],7,1804603682);d=md5ff(d,a,b,c,x[i+13],12,-40341101);c=md5ff(c,d,a,b,x[i+14],17,-1502002290);b=md5ff(b,c,d,a,x[i+15],22,1236535329);a=md5gg(a,b,c,d,x[i+1],5,-165796510);d=md5gg(d,a,b,c,x[i+6],9,-1069501632);c=md5gg(c,d,a,b,x[i+11],14,643717713);b=md5gg(b,c,d,a,x[i],20,-373897302);a=md5gg(a,b,c,d,x[i+5],5,-701558691);d=md5gg(d,a,b,c,x[i+10],9,38016083);c=md5gg(c,d,a,b,x[i+15],14,-660478335);b=md5gg(b,c,d,a,x[i+4],20,-405537848);a=md5gg(a,b,c,d,x[i+9],5,568446438);d=md5gg(d,a,b,c,x[i+14],9,-1019803690);c=md5gg(c,d,a,b,x[i+3],14,-187363961);b=md5gg(b,c,d,a,x[i+8],20,1163531501);a=md5gg(a,b,c,d,x[i+13],5,-1444681467);d=md5gg(d,a,b,c,x[i+2],9,-51403784);c=md5gg(c,d,a,b,x[i+7],14,1735328473);b=md5gg(b,c,d,a,x[i+12],20,-1926607734);a=md5hh(a,b,c,d,x[i+5],4,-378558);d=md5hh(d,a,b,c,x[i+8],11,-2022574463);c=md5hh(c,d,a,b,x[i+11],16,1839030562);b=md5hh(b,c,d,a,x[i+14],23,-35309556);a=md5hh(a,b,c,d,x[i+1],4,-1530992060);d=md5hh(d,a,b,c,x[i+4],11,1272893353);c=md5hh(c,d,a,b,x[i+7],16,-155497632);b=md5hh(b,c,d,a,x[i+10],23,-1094730640);a=md5hh(a,b,c,d,x[i+13],4,681279174);d=md5hh(d,a,b,c,x[i],11,-358537222);c=md5hh(c,d,a,b,x[i+3],16,-722521979);b=md5hh(b,c,d,a,x[i+6],23,76029189);a=md5hh(a,b,c,d,x[i+9],4,-640364487);d=md5hh(d,a,b,c,x[i+12],11,-421815835);c=md5hh(c,d,a,b,x[i+15],16,530742520);b=md5hh(b,c,d,a,x[i+2],23,-995338651);a=md5ii(a,b,c,d,x[i],6,-198630844);d=md5ii(d,a,b,c,x[i+7],10,1126891415);c=md5ii(c,d,a,b,x[i+14],15,-1416354905);b=md5ii(b,c,d,a,x[i+5],21,-57434055);a=md5ii(a,b,c,d,x[i+12],6,1700485571);d=md5ii(d,a,b,c,x[i+3],10,-1894986606);c=md5ii(c,d,a,b,x[i+10],15,-1051523);b=md5ii(b,c,d,a,x[i+1],21,-2054922799);a=md5ii(a,b,c,d,x[i+8],6,1873313359);d=md5ii(d,a,b,c,x[i+15],10,-30611744);c=md5ii(c,d,a,b,x[i+6],15,-1560198380);b=md5ii(b,c,d,a,x[i+13],21,1309151649);a=md5ii(a,b,c,d,x[i+4],6,-145523070);d=md5ii(d,a,b,c,x[i+11],10,-1120210379);c=md5ii(c,d,a,b,x[i+2],15,718787259);b=md5ii(b,c,d,a,x[i+9],21,-343485551);a=safeAdd(a,olda);b=safeAdd(b,oldb);c=safeAdd(c,oldc);d=safeAdd(d,oldd)}return[a,b,c,d]}function binl2rstr(input){let output='';const length32=input.length*32;for(let i=0;i<length32;i+=8){output+=String.fromCharCode((input[i>>5]>>>i%32)&0xff)}return output}function rstr2binl(input){const output=[];output[(input.length>>2)-1]=undefined;for(let i=0;i<output.length;i+=1){output[i]=0}const length8=input.length*8;for(let i=0;i<length8;i+=8){output[i>>5]|=(input.charCodeAt(i/8)&0xff)<<i%32}return output}function rstrMD5(s){return binl2rstr(binlMD5(rstr2binl(s),s.length*8))}function str2rstrUTF8(input){return unescape(encodeURIComponent(input))}function rawMD5(s){return rstrMD5(str2rstrUTF8(s))}function rstr2uint8array(input){const output=new Uint8Array(input.length);for(let i=0;i<input.length;i++){output[i]=input.charCodeAt(i)}return output}function md5(string){return rstr2uint8array(rawMD5(string))}export default md5;
package/src/md5.js CHANGED
@@ -356,7 +356,7 @@ function hexHMACMD5(k, d) {
356
356
  *
357
357
  * @param {string} string Input string
358
358
  * @param {string} [key] HMAC key
359
- * @param {boolean} [raw] Raw output switch
359
+ * @param {string} [raw] Raw output switch
360
360
  * @returns {string} MD5 output
361
361
  */
362
362
  function md5(string, key, raw) {
@@ -151,7 +151,7 @@ const getNavBarConfigData = () => { // eslint-disable-line require-jsdoc
151
151
  statusBarHeight = isIOS ? StatusBarHeightOnIOS : StatusBarHeightOnAndroid;
152
152
  }
153
153
 
154
- const enable = compareVersion(version, '7.0.0') >= 0 || brand === 'devtools'; // 微信版本是否支持自定义顶栏,不支持时自动隐藏
154
+ const enable = compareVersion(version, '7.0.0') >= 0 || brand === 'devtools' || platform === 'ohos'; // 微信版本是否支持自定义顶栏,不支持时自动隐藏
155
155
  const enterOptions = getEnterOptions();
156
156
  if (enable) {
157
157
  return { enable, ...calculateNavBarLayout(isIOS, statusBarHeight, enterOptions.apiCategory) };