@lingxiteam/ebe-utils 0.0.33 → 0.0.35
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/es/index.d.ts +5 -1
- package/es/index.js +107 -62
- package/lib/h5public/src/components/factory/src/Icon/IconED/index.less +43 -0
- package/lib/h5public/src/components/factory/src/Icon/IconED/index.tsx +290 -0
- package/lib/public/src/services/api/engine.ts +0 -2
- package/lib/public/src/utils/Security/clientCapabilities.ts +8 -0
- package/lib/public/src/utils/Security/config.ts +56 -49
- package/lib/public/src/utils/Security/const.ts +38 -127
- package/lib/public/src/utils/Security/debug/data.ts +86 -0
- package/lib/public/src/utils/Security/debug/index.ts +21 -0
- package/lib/public/src/utils/Security/encipher/sign.ts +25 -56
- package/lib/public/src/utils/Security/html.ts +52 -0
- package/lib/public/src/utils/Security/httpEncryption.ts +42 -23
- package/lib/public/src/utils/Security/index.ts +15 -7
- package/lib/public/src/utils/Security/requester/fetch.ts +87 -52
- package/lib/public/src/utils/Security/requester/wx.ts +60 -11
- package/lib/public/src/utils/Security/requester/xhr.ts +194 -40
- package/lib/public/src/utils/Security/types.ts +8 -90
- package/lib/public/src/utils/Security/urlEncryption.ts +108 -0
- package/lib/public/src/utils/Security/utils/atob.ts +34 -0
- package/lib/public/src/utils/Security/utils/caseInsensitive.ts +25 -0
- package/lib/public/src/utils/Security/utils/check.ts +27 -3
- package/lib/public/src/utils/Security/utils/cookie.ts +101 -53
- package/lib/public/src/utils/Security/utils/encrypted.ts +190 -43
- package/lib/public/src/utils/Security/utils/random.ts +21 -0
- package/lib/public/src/utils/Security/utils/storge.ts +22 -0
- package/lib/public/src/utils/Security/utils/url.ts +30 -5
- package/lib/public/src/utils/getSceneCode.ts +51 -0
- package/lib/public/src/utils/useTool.ts +2 -172
- package/lib/public/yarn.lock +11441 -0
- package/package.json +3 -3
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/closeIcon.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/fileName.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/img.png +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import config from './config';
|
|
2
|
+
import { securityHeaderKey, signHeaderKey } from './const';
|
|
3
|
+
import { createHttpSignStr } from './encipher/sign';
|
|
4
|
+
import { MODE, modeType, securityType } from './types';
|
|
5
|
+
import { checkIsEncryption, checkIsSignMode } from './utils/check';
|
|
6
|
+
import {
|
|
7
|
+
decryptedStrForSearchParams,
|
|
8
|
+
encryptedStrForSearchParams,
|
|
9
|
+
} from './utils/encrypted';
|
|
10
|
+
import message from './utils/message';
|
|
11
|
+
import { getSearchObj, removeURLParameters } from './utils/url';
|
|
12
|
+
|
|
13
|
+
export const createHttpSignWithUrl: typeof securityType.createHttpSignWithUrl =
|
|
14
|
+
(url, options = {}, version) => {
|
|
15
|
+
if (!url) {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
if (version && !checkIsSignMode(version)) {
|
|
19
|
+
message.warn(`不支持[${version}]签名模式`);
|
|
20
|
+
return url;
|
|
21
|
+
}
|
|
22
|
+
let _url = url;
|
|
23
|
+
const signVersion =
|
|
24
|
+
version ||
|
|
25
|
+
(checkIsSignMode(config.mode as MODE)
|
|
26
|
+
? config.mode
|
|
27
|
+
: MODE.SIGN_WITH_TIME);
|
|
28
|
+
const signStr = createHttpSignStr(
|
|
29
|
+
url,
|
|
30
|
+
{ method: 'GET', ...options },
|
|
31
|
+
signVersion,
|
|
32
|
+
);
|
|
33
|
+
// 如果url上存在签名则移除原签名
|
|
34
|
+
if (
|
|
35
|
+
url.indexOf(signHeaderKey) !== -1 ||
|
|
36
|
+
url.indexOf(securityHeaderKey) !== -1
|
|
37
|
+
) {
|
|
38
|
+
_url = removeURLParameters(url, [signHeaderKey, securityHeaderKey]);
|
|
39
|
+
}
|
|
40
|
+
return `${_url}${
|
|
41
|
+
_url.includes('?') ? '&' : '?'
|
|
42
|
+
}${signHeaderKey}=${signStr}&${securityHeaderKey}=${signVersion}`;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 将url里的参数进行加密
|
|
47
|
+
* @param url url地址
|
|
48
|
+
* @param version 加密模式
|
|
49
|
+
* @returns 加密处理后的url地址(带加密模式标记)
|
|
50
|
+
*/
|
|
51
|
+
export const createEncryptedWithUrl: typeof securityType.createEncryptedWithUrl =
|
|
52
|
+
(url, version) => {
|
|
53
|
+
if (!url) {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
if (version && !checkIsEncryption(version)) {
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
if (url.indexOf('?') !== -1) {
|
|
60
|
+
const encryptedMode = version || '3.0';
|
|
61
|
+
return `${url.replace(/[^?]+$/g, (data) =>
|
|
62
|
+
encryptedStrForSearchParams(data, encryptedMode),
|
|
63
|
+
)}&${securityHeaderKey}=${encryptedMode}`;
|
|
64
|
+
}
|
|
65
|
+
return url;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const autoSecurityWithUrl: typeof securityType.autoSecurityWithUrl = (
|
|
69
|
+
url,
|
|
70
|
+
options,
|
|
71
|
+
) => {
|
|
72
|
+
let originUrl: string = url;
|
|
73
|
+
const securityHeaderKey = config.securityHeaderKey as string;
|
|
74
|
+
const confiMode = config.mode as modeType;
|
|
75
|
+
const modeInUrl = getSearchObj(url)[securityHeaderKey];
|
|
76
|
+
const finallyMode =
|
|
77
|
+
typeof options?.modeRule === 'function'
|
|
78
|
+
? options.modeRule(confiMode)
|
|
79
|
+
: confiMode;
|
|
80
|
+
// 处理旧模式url
|
|
81
|
+
if (modeInUrl) {
|
|
82
|
+
if (checkIsEncryption(modeInUrl)) {
|
|
83
|
+
if (finallyMode === modeInUrl) {
|
|
84
|
+
// 如果地址处理前后均为相同加密方式则不需处理
|
|
85
|
+
return url;
|
|
86
|
+
}
|
|
87
|
+
// 否则对url进行解密并移除旧模式参数标识
|
|
88
|
+
originUrl = removeURLParameters(url, [securityHeaderKey]).replace(
|
|
89
|
+
/[^?]+$/g,
|
|
90
|
+
(data) => decryptedStrForSearchParams(data, modeInUrl),
|
|
91
|
+
);
|
|
92
|
+
} else if (checkIsSignMode(modeInUrl)) {
|
|
93
|
+
// 移除旧模式参数标识
|
|
94
|
+
originUrl = removeURLParameters(url, [
|
|
95
|
+
config.sign?.valueKeyName as string,
|
|
96
|
+
securityHeaderKey,
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// 执行加签或加密处理
|
|
101
|
+
if (checkIsSignMode(finallyMode)) {
|
|
102
|
+
return createHttpSignWithUrl(originUrl, {}, finallyMode);
|
|
103
|
+
}
|
|
104
|
+
if (checkIsEncryption(finallyMode)) {
|
|
105
|
+
return createEncryptedWithUrl(originUrl, finallyMode as '2.0' | '3.0');
|
|
106
|
+
}
|
|
107
|
+
return originUrl;
|
|
108
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable no-bitwise */
|
|
2
|
+
/* eslint-disable no-plusplus */
|
|
3
|
+
|
|
4
|
+
const customAtob = (str: string) => {
|
|
5
|
+
if (typeof atob === 'function') {
|
|
6
|
+
return atob(str);
|
|
7
|
+
}
|
|
8
|
+
const base64 =
|
|
9
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
10
|
+
let result = '';
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < str.length; ) {
|
|
13
|
+
const char1 = base64.indexOf(str.charAt(i++));
|
|
14
|
+
const char2 = base64.indexOf(str.charAt(i++));
|
|
15
|
+
const char3 = base64.indexOf(str.charAt(i++));
|
|
16
|
+
const char4 = base64.indexOf(str.charAt(i++));
|
|
17
|
+
|
|
18
|
+
const byte1 = (char1 << 2) | (char2 >> 4);
|
|
19
|
+
const byte2 = ((char2 & 15) << 4) | (char3 >> 2);
|
|
20
|
+
const byte3 = ((char3 & 3) << 6) | char4;
|
|
21
|
+
|
|
22
|
+
result += String.fromCharCode(byte1);
|
|
23
|
+
|
|
24
|
+
if (char3 !== 64) {
|
|
25
|
+
result += String.fromCharCode(byte2);
|
|
26
|
+
}
|
|
27
|
+
if (char4 !== 64) {
|
|
28
|
+
result += String.fromCharCode(byte3);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default customAtob;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// 大小写不敏感函数
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取对象属性值,忽略大小写
|
|
5
|
+
* @param data 待获取数据的对象数据
|
|
6
|
+
* @param attr 属性名称
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export const getObjectValue = (data: Record<any, any>, attr: string): any => {
|
|
10
|
+
if (typeof attr === 'undefined' || typeof data === 'undefined')
|
|
11
|
+
return undefined;
|
|
12
|
+
// 优先通过attr直接获取数据,如果数据不存在,则进行小写转换再获取
|
|
13
|
+
let result = data[attr];
|
|
14
|
+
if (typeof result === 'undefined') {
|
|
15
|
+
const lowerAttr = attr.toLowerCase();
|
|
16
|
+
const objectKeys = Object.keys(data);
|
|
17
|
+
for (let i = 0; i < objectKeys.length; i += 1) {
|
|
18
|
+
if (objectKeys[i].toLowerCase() === lowerAttr) {
|
|
19
|
+
result = data[objectKeys[i]];
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
@@ -3,7 +3,6 @@ import { MODE } from '../types';
|
|
|
3
3
|
|
|
4
4
|
const signModes: string[] = [
|
|
5
5
|
MODE.SIGN,
|
|
6
|
-
MODE.SIGN_KEY,
|
|
7
6
|
MODE.SIGN_UUID,
|
|
8
7
|
MODE.SIGN_UUID_WITHOUT_SALT,
|
|
9
8
|
MODE.SIGN_WITHOUT_SALT,
|
|
@@ -11,28 +10,53 @@ const signModes: string[] = [
|
|
|
11
10
|
];
|
|
12
11
|
const signModesWithSalt: string[] = [
|
|
13
12
|
MODE.SIGN,
|
|
14
|
-
MODE.SIGN_KEY,
|
|
15
13
|
MODE.SIGN_UUID,
|
|
16
14
|
MODE.SIGN_WITH_TIME,
|
|
17
15
|
];
|
|
18
|
-
const encryptionModes: string[] = [MODE.AES, MODE.
|
|
16
|
+
const encryptionModes: string[] = [MODE.AES, MODE.RSA];
|
|
19
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 检查安全模式是否为加签
|
|
20
|
+
* @param mode 模式值
|
|
21
|
+
* @returns boolean
|
|
22
|
+
*/
|
|
20
23
|
export const checkIsSignMode = (mode: string): boolean => {
|
|
21
24
|
return signModes.includes(mode);
|
|
22
25
|
};
|
|
23
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 检查安全模式是否为加签(带盐值)
|
|
29
|
+
* @param mode 模式值
|
|
30
|
+
* @returns boolean
|
|
31
|
+
*/
|
|
24
32
|
export const checkIsSignWithSalt = (mode: string): boolean => {
|
|
25
33
|
return signModesWithSalt.includes(mode);
|
|
26
34
|
};
|
|
27
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 检查安全模式是否为加密
|
|
38
|
+
* @param mode 模式值
|
|
39
|
+
* @returns boolean
|
|
40
|
+
*/
|
|
28
41
|
export const checkIsEncryption = (mode: string): boolean => {
|
|
29
42
|
return encryptionModes.includes(mode);
|
|
30
43
|
};
|
|
31
44
|
|
|
45
|
+
/**
|
|
46
|
+
* 检查安全模式是否为合法值
|
|
47
|
+
* @param mode 模式值
|
|
48
|
+
* @returns boolean
|
|
49
|
+
*/
|
|
32
50
|
export const checkIsModeValue = (mode: string): boolean => {
|
|
33
51
|
return signModes.includes(mode) || encryptionModes.includes(mode);
|
|
34
52
|
};
|
|
35
53
|
|
|
54
|
+
/**
|
|
55
|
+
* 检查当前请求是否需要忽略
|
|
56
|
+
* @param url 请求地址
|
|
57
|
+
* @param options 请求参数
|
|
58
|
+
* @returns boolean
|
|
59
|
+
*/
|
|
36
60
|
export const checkIsUrlIgnore = (
|
|
37
61
|
url: string,
|
|
38
62
|
options?: { headers?: any; body?: any; method?: string },
|
|
@@ -1,70 +1,118 @@
|
|
|
1
|
-
import capabilities from '../clientCapabilities';
|
|
2
|
-
import message from './message';
|
|
3
|
-
|
|
4
|
-
const showError = () => message.warn('[lcdp-security]: 当前环境不支持cookie');
|
|
5
|
-
|
|
6
1
|
const CookieUtil = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return cookieValue;
|
|
2
|
+
/**
|
|
3
|
+
* 获取cookie值
|
|
4
|
+
* @param key cookie字段名称
|
|
5
|
+
* @returns cookie值
|
|
6
|
+
*/
|
|
7
|
+
getItem(key: string) {
|
|
8
|
+
return (
|
|
9
|
+
decodeURIComponent(
|
|
10
|
+
document.cookie.replace(
|
|
11
|
+
new RegExp(
|
|
12
|
+
`(?:(?:^|.*;)\\s*${encodeURIComponent(key).replace(
|
|
13
|
+
/[-.+*]/g,
|
|
14
|
+
'\\$&',
|
|
15
|
+
)}\\s*\\=\\s*([^;]*).*$)|^.*$`,
|
|
16
|
+
),
|
|
17
|
+
'$1',
|
|
18
|
+
),
|
|
19
|
+
) || null
|
|
20
|
+
);
|
|
28
21
|
},
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
/**
|
|
24
|
+
* 设置cookie值
|
|
25
|
+
* @param key cookie字段名称
|
|
26
|
+
* @param value 值
|
|
27
|
+
* @param end 有效结束事件
|
|
28
|
+
* @param path 作用域-路径
|
|
29
|
+
* @param domain 作用域-域名
|
|
30
|
+
* @param secure 是否只通过 https 协议传输
|
|
31
|
+
* @returns 设置成功返回true,设置失败返回false
|
|
32
|
+
*/
|
|
33
|
+
setItem(
|
|
34
|
+
key: string,
|
|
32
35
|
value: string,
|
|
33
|
-
|
|
34
|
-
path
|
|
35
|
-
domain
|
|
36
|
-
secure
|
|
36
|
+
end?: any,
|
|
37
|
+
path?: string,
|
|
38
|
+
domain?: string,
|
|
39
|
+
secure?: boolean,
|
|
37
40
|
) {
|
|
38
|
-
if (!
|
|
39
|
-
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
let cookieText = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
43
|
-
|
|
44
|
-
if (expires instanceof Date) {
|
|
45
|
-
cookieText += `; expires=${expires.toUTCString()}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (path) {
|
|
49
|
-
cookieText += `; path=${path}`;
|
|
41
|
+
if (!key || /^(?:expires|max\-age|path|domain|secure)$/i.test(key)) {
|
|
42
|
+
return false;
|
|
50
43
|
}
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
44
|
+
let expires = '';
|
|
45
|
+
if (end) {
|
|
46
|
+
switch (end.constructor) {
|
|
47
|
+
case Number:
|
|
48
|
+
expires =
|
|
49
|
+
end === Infinity
|
|
50
|
+
? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
|
|
51
|
+
: `; max-age=${end}`;
|
|
52
|
+
break;
|
|
53
|
+
case String:
|
|
54
|
+
expires = `; expires=${end}`;
|
|
55
|
+
break;
|
|
56
|
+
case Date:
|
|
57
|
+
expires = `; expires=${end.toUTCString()}`;
|
|
58
|
+
break;
|
|
59
|
+
default:
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
54
62
|
}
|
|
63
|
+
document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(
|
|
64
|
+
value,
|
|
65
|
+
)}${expires}${domain ? `; domain=${domain}` : ''}${
|
|
66
|
+
path ? `; path=${path}` : ''
|
|
67
|
+
}${secure ? '; secure' : ''}`;
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
55
70
|
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
/**
|
|
72
|
+
* 删除cookie指定项
|
|
73
|
+
* @param key cookie字段名称
|
|
74
|
+
* @param path cookie所在作用域-路径
|
|
75
|
+
* @param domain cookie所在作用域-域名
|
|
76
|
+
* @returns 删除成功返回true,删除失败返回false
|
|
77
|
+
*/
|
|
78
|
+
removeItem(key: string, path?: string, domain?: string) {
|
|
79
|
+
if (!key || !this.hasItem(key)) {
|
|
80
|
+
return false;
|
|
58
81
|
}
|
|
82
|
+
document.cookie = `${encodeURIComponent(
|
|
83
|
+
key,
|
|
84
|
+
)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT${
|
|
85
|
+
domain ? `; domain=${domain}` : ''
|
|
86
|
+
}${path ? `; path=${path}` : ''}`;
|
|
87
|
+
return true;
|
|
88
|
+
},
|
|
59
89
|
|
|
60
|
-
|
|
90
|
+
/**
|
|
91
|
+
* 是否包含cookie项
|
|
92
|
+
* @param key cookie字段名称
|
|
93
|
+
* @returns 存在返回true,不存在返回false
|
|
94
|
+
*/
|
|
95
|
+
hasItem(key: string) {
|
|
96
|
+
return new RegExp(
|
|
97
|
+
`(?:^|;\\s*)${encodeURIComponent(key).replace(/[-.+*]/g, '\\$&')}\\s*\\=`,
|
|
98
|
+
).test(document.cookie);
|
|
61
99
|
},
|
|
62
100
|
|
|
63
|
-
|
|
64
|
-
|
|
101
|
+
/**
|
|
102
|
+
* 获取cookie里所有字段名称
|
|
103
|
+
* @returns 字段名称列表
|
|
104
|
+
*/
|
|
105
|
+
keys() {
|
|
106
|
+
const aKeys = document.cookie
|
|
107
|
+
.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '')
|
|
108
|
+
.split(/\s*(?:\=[^;]*)?;\s*/);
|
|
109
|
+
for (let nIdx = 0; nIdx < aKeys.length; nIdx += 1) {
|
|
110
|
+
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
|
|
111
|
+
}
|
|
112
|
+
return aKeys;
|
|
65
113
|
},
|
|
66
114
|
};
|
|
67
115
|
|
|
68
|
-
export const getSaltValue = (saltKey: string) => CookieUtil.
|
|
116
|
+
export const getSaltValue = (saltKey: string) => CookieUtil.getItem(saltKey);
|
|
69
117
|
|
|
70
118
|
export default CookieUtil;
|
|
@@ -2,9 +2,14 @@ import config from '../config';
|
|
|
2
2
|
import { lxKey } from '../const';
|
|
3
3
|
import { AESDecrypt, AESEncrypt } from '../encipher/aes';
|
|
4
4
|
import { RSADecrypt, RSAEncrypt } from '../encipher/rsa';
|
|
5
|
-
import { MODE } from '../types';
|
|
6
|
-
import
|
|
5
|
+
import { MODE, requester } from '../types';
|
|
6
|
+
import { getObjectValue } from './caseInsensitive';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* 预置内部加密函数,将秘钥进行加密使用
|
|
10
|
+
* @param str 待加密内容
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
8
13
|
export function lxEncrypt(str: string) {
|
|
9
14
|
if (config.keyEncrypt) {
|
|
10
15
|
return AESEncrypt(str, lxKey) || str;
|
|
@@ -12,6 +17,11 @@ export function lxEncrypt(str: string) {
|
|
|
12
17
|
return str;
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
/**
|
|
21
|
+
* 预置内部解密函数
|
|
22
|
+
* @param str 待加密内容
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
15
25
|
function lxDecrypt(str: string) {
|
|
16
26
|
if (config.keyEncrypt) {
|
|
17
27
|
return AESDecrypt(str, lxKey) || str;
|
|
@@ -19,6 +29,12 @@ function lxDecrypt(str: string) {
|
|
|
19
29
|
return str;
|
|
20
30
|
}
|
|
21
31
|
|
|
32
|
+
/**
|
|
33
|
+
* 统一加密函数
|
|
34
|
+
* @param str 待加密内容
|
|
35
|
+
* @param type 加密类型
|
|
36
|
+
* @returns string 加密后内容
|
|
37
|
+
*/
|
|
22
38
|
export function encryptedStr(str: string, type: string): string {
|
|
23
39
|
if (type === MODE.AES) {
|
|
24
40
|
return AESEncrypt(
|
|
@@ -36,17 +52,17 @@ export function encryptedStr(str: string, type: string): string {
|
|
|
36
52
|
) || ''
|
|
37
53
|
);
|
|
38
54
|
}
|
|
39
|
-
if (type === MODE.DES) {
|
|
40
|
-
message.warn('DES encryption is no longer supported');
|
|
41
|
-
}
|
|
42
55
|
return str;
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
/**
|
|
59
|
+
* 统一解密函数
|
|
60
|
+
* @param str 待解密内容
|
|
61
|
+
* @param type 加密类型
|
|
62
|
+
* @param config 配置项(自定义秘钥和解密方法)
|
|
63
|
+
* @returns string 解密后的内容
|
|
64
|
+
*/
|
|
65
|
+
export function decryptedStr(str: string, type: string): string {
|
|
50
66
|
if (type === MODE.AES) {
|
|
51
67
|
return AESDecrypt(
|
|
52
68
|
str,
|
|
@@ -63,59 +79,190 @@ export function decryptedStr(
|
|
|
63
79
|
) || ''
|
|
64
80
|
);
|
|
65
81
|
}
|
|
66
|
-
if (type === MODE.DES) {
|
|
67
|
-
message.warn('DES encryption is no longer supported');
|
|
68
|
-
}
|
|
69
82
|
return str;
|
|
70
83
|
}
|
|
71
84
|
|
|
85
|
+
/**
|
|
86
|
+
* 将url参数加密,如: a=1&b=2 -> a=XAZYt1dl43v0gYUlNM6wEg%3D%3D&b=rbsCqzqEZvsUn41oxNsJ%2FQ%3D%3D
|
|
87
|
+
* @param search url参数, 如: a=1&b=2
|
|
88
|
+
* @param mode 加密模式
|
|
89
|
+
* @returns string 加密后数据
|
|
90
|
+
*/
|
|
91
|
+
export const encryptedStrForSearchParams = (
|
|
92
|
+
search: string,
|
|
93
|
+
mode: '2.0' | '3.0',
|
|
94
|
+
) => {
|
|
95
|
+
const params = search.split('&').map((param) => {
|
|
96
|
+
const [k, v] = param.split('=');
|
|
97
|
+
return `${encodeURIComponent(k)}=${encodeURIComponent(
|
|
98
|
+
encryptedStr(v, mode),
|
|
99
|
+
)}`;
|
|
100
|
+
});
|
|
101
|
+
return params.join('&');
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 将url参数解密
|
|
106
|
+
* @param search url参数, 如: a=XAZYt1dl43v0gYUlNM6wEg%3D%3D&b=rbsCqzqEZvsUn41oxNsJ%2FQ%3D%3D
|
|
107
|
+
* @param mode 加密模式
|
|
108
|
+
* @returns string 解密后数据
|
|
109
|
+
*/
|
|
110
|
+
export const decryptedStrForSearchParams = (
|
|
111
|
+
search: string,
|
|
112
|
+
mode: '2.0' | '3.0',
|
|
113
|
+
) => {
|
|
114
|
+
const params = search.split('&').map((param) => {
|
|
115
|
+
const [k, v] = param.split('=');
|
|
116
|
+
return `${decodeURIComponent(k)}=${decryptedStr(
|
|
117
|
+
decodeURIComponent(v),
|
|
118
|
+
mode,
|
|
119
|
+
)}`;
|
|
120
|
+
});
|
|
121
|
+
return params.join('&');
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 将对象数据value字段加密, 如: { a: 1, b: 2 } -> { a: 'XAZYt1dl43v0gYUlNM6wEg', b: 'XAZYt1dl43v0gYUlNM6wEg' }
|
|
126
|
+
* @param data 对象数据
|
|
127
|
+
* @param mode 加密模式
|
|
128
|
+
* @returns string 加密后数据
|
|
129
|
+
*/
|
|
130
|
+
const encryptedStrForObjectBody = (
|
|
131
|
+
data: Record<any, any>,
|
|
132
|
+
mode: '2.0' | '3.0',
|
|
133
|
+
) => {
|
|
134
|
+
return Object.keys(data).reduce(
|
|
135
|
+
(
|
|
136
|
+
previousValue: Record<string, string>,
|
|
137
|
+
key: string,
|
|
138
|
+
): Record<string, string> => {
|
|
139
|
+
if (typeof data[key] === 'object') {
|
|
140
|
+
previousValue[key] = encryptedStr(JSON.stringify(data[key]), mode);
|
|
141
|
+
} else {
|
|
142
|
+
previousValue[key] = encryptedStr(String(data[key]), mode);
|
|
143
|
+
}
|
|
144
|
+
return previousValue;
|
|
145
|
+
},
|
|
146
|
+
{},
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
72
150
|
interface optsType {
|
|
73
151
|
body?: any;
|
|
74
152
|
headers?: any;
|
|
75
153
|
}
|
|
76
154
|
type returnType = [string, { body?: any; headers?: any }];
|
|
77
155
|
|
|
78
|
-
|
|
156
|
+
/**
|
|
157
|
+
* 统一请求参数加密,对url参数、body参数进行加密
|
|
158
|
+
* @param url 请求url地址
|
|
159
|
+
* @param opts 请求配置,包含 headers、body
|
|
160
|
+
* @param mode 加密模式,2.0:rsa,3.0:aes
|
|
161
|
+
* @param requester 请求程序,"fetch" | "xhr" | "wxRequest"
|
|
162
|
+
* @returns [加密处理后的url, 加密处理后的数据(header、body)]
|
|
163
|
+
*/
|
|
79
164
|
export const encryptedRequestParams = (
|
|
80
165
|
url: string,
|
|
81
166
|
opts: optsType,
|
|
82
|
-
|
|
167
|
+
mode: '2.0' | '3.0',
|
|
168
|
+
requester: requester,
|
|
83
169
|
): returnType => {
|
|
84
|
-
const
|
|
170
|
+
const encryptedOpts = Object.assign({}, opts);
|
|
85
171
|
|
|
86
|
-
//
|
|
172
|
+
// 在请求头增加‘模式’字段,告知后端解密方式
|
|
173
|
+
encryptedOpts.headers = {
|
|
174
|
+
...(opts.headers || {}),
|
|
175
|
+
[config.securityHeaderKey as string]: mode,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// url search 部分参数加密
|
|
87
179
|
const encryptedUrl =
|
|
88
180
|
url.indexOf('?') !== -1
|
|
89
|
-
? url.replace(/[^?]+$/g, (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return `${encodeURIComponent(k)}=${encodeURIComponent(
|
|
93
|
-
encryptedStr(v, type),
|
|
94
|
-
)}`;
|
|
95
|
-
});
|
|
96
|
-
return params.join('&');
|
|
97
|
-
})
|
|
181
|
+
? url.replace(/[^?]+$/g, (data) =>
|
|
182
|
+
encryptedStrForSearchParams(data, mode),
|
|
183
|
+
)
|
|
98
184
|
: url;
|
|
99
185
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
186
|
+
/**
|
|
187
|
+
* body参数加密
|
|
188
|
+
* body 数据类型:
|
|
189
|
+
* - Fetch: a string | ArrayBuffer | Blob | DataView | File | FormData | TypedArray | URLSearchParams see: https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#body
|
|
190
|
+
* - XHR: a string | Blob | FormData | URLSearchParams | Document | null see: https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/send
|
|
191
|
+
* - wx.request: a string | object | ArrayBuffer see: https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
|
|
192
|
+
*
|
|
193
|
+
* 入参数据为: opts.body, 数据来源于
|
|
194
|
+
* fetch请求的 options.body
|
|
195
|
+
* xhr请求 send方法入参
|
|
196
|
+
* wx请求的 options.data
|
|
197
|
+
*
|
|
198
|
+
* 加密原则:
|
|
199
|
+
* 1. 对于表单数据只加密value部分
|
|
200
|
+
* 2. json或文本类型整个body加密
|
|
201
|
+
* 3. 其他类型(File、Blob...)不加密
|
|
202
|
+
*/
|
|
203
|
+
if (opts.body) {
|
|
204
|
+
const defaultContentType: Record<requester, string> = {
|
|
205
|
+
xhr: 'application/x-www-form-urlencoded',
|
|
206
|
+
fetch: 'text/plain',
|
|
207
|
+
wxRequest: 'application/json',
|
|
208
|
+
};
|
|
209
|
+
const contentType =
|
|
210
|
+
getObjectValue(opts.headers, 'Content-Type') ||
|
|
211
|
+
defaultContentType[requester];
|
|
212
|
+
const method = opts.headers?.method?.toUpperCase() || 'GET';
|
|
213
|
+
const isFormData =
|
|
214
|
+
typeof FormData !== 'undefined' && opts.body instanceof FormData;
|
|
215
|
+
const isURLSearchParams =
|
|
216
|
+
typeof URLSearchParams !== 'undefined' &&
|
|
217
|
+
opts.body instanceof URLSearchParams;
|
|
106
218
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
219
|
+
/* 1. 优先根据body数据类型来处理 */
|
|
220
|
+
if (isFormData || isURLSearchParams) {
|
|
221
|
+
const newObjData = isFormData ? new FormData() : new URLSearchParams();
|
|
222
|
+
const reqBody = opts.body;
|
|
223
|
+
for (const key of (reqBody as any).keys()) {
|
|
224
|
+
const value = reqBody.get(key);
|
|
225
|
+
// 只加密文本类型数据,文件数据不处理
|
|
226
|
+
if (typeof value === 'string') {
|
|
227
|
+
newObjData.append(key, encryptedStr(value, mode));
|
|
228
|
+
} else {
|
|
229
|
+
newObjData.append(key, value as any);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
encryptedOpts.body = newObjData;
|
|
233
|
+
} /* 2. 根据contentType类型来处理 */ else if (
|
|
234
|
+
contentType.indexOf('application/json') !== -1
|
|
235
|
+
) {
|
|
236
|
+
// wx.request 可以为对象类型
|
|
237
|
+
if (typeof opts.body === 'object') {
|
|
238
|
+
try {
|
|
239
|
+
if (method === 'GET') {
|
|
240
|
+
// get请求时,body数据将通过url参数传递
|
|
241
|
+
encryptedOpts.body = encryptedStrForObjectBody(opts.body, mode);
|
|
242
|
+
} else {
|
|
243
|
+
encryptedOpts.body = encryptedStr(JSON.stringify(opts.body), mode);
|
|
244
|
+
}
|
|
245
|
+
} catch {
|
|
246
|
+
encryptedOpts.body = opts.body;
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
encryptedOpts.body = encryptedStr(opts.body, mode);
|
|
250
|
+
}
|
|
251
|
+
} else if (
|
|
252
|
+
contentType.indexOf('application/x-www-form-urlencoded') !== -1
|
|
253
|
+
) {
|
|
254
|
+
if (typeof opts.body === 'object') {
|
|
255
|
+
encryptedOpts.body = encryptedStrForObjectBody(opts.body, mode);
|
|
256
|
+
} else {
|
|
257
|
+
encryptedOpts.body = encryptedStrForSearchParams(opts.body, mode);
|
|
258
|
+
}
|
|
259
|
+
} else if (typeof opts.body === 'string') {
|
|
260
|
+
// 文本数据 加密
|
|
261
|
+
encryptedOpts.body = encryptedStr(opts.body, mode);
|
|
262
|
+
} else {
|
|
263
|
+
// 其他类型数据不处理
|
|
264
|
+
encryptedOpts.body = opts.body;
|
|
114
265
|
}
|
|
115
|
-
encryptedOpts.body = formData;
|
|
116
|
-
} else if (opts.body) {
|
|
117
|
-
// 文本加密
|
|
118
|
-
encryptedOpts.body = encryptedStr(opts.body, type);
|
|
119
266
|
}
|
|
120
267
|
|
|
121
268
|
return [encryptedUrl, encryptedOpts];
|