@polyv/request-plugin-aes-decrypt 2.0.0
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/README.md +113 -0
- package/aes-decrypt-plugin.d.ts +12 -0
- package/aes-decrypt-plugin.js +57 -0
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/package.json +12 -0
- package/request-options.d.ts +22 -0
- package/request-options.js +1 -0
- package/types.d.ts +55 -0
- package/types.js +22 -0
- package/utils.d.ts +25 -0
- package/utils.js +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# AESDecryptRequestPlugin
|
|
2
|
+
|
|
3
|
+
用途:AES 解密插件,用于对服务端返回的加密数据进行解密处理。
|
|
4
|
+
|
|
5
|
+
## 实例化参数
|
|
6
|
+
|
|
7
|
+
| 参数名 | 用途 | 类型 | 默认值 |
|
|
8
|
+
| - | - | - | - |
|
|
9
|
+
| `decryptKeys` | 解密密钥信息 | `AESKeyInfo` | - |
|
|
10
|
+
| `decryptPosition` | 解密位置 | `AESDecryptPosition` | `AESDecryptPosition.ResponseData` |
|
|
11
|
+
| `getDecryptInfo` | 获取解密信息的方法 | `function` | - |
|
|
12
|
+
|
|
13
|
+
## 请求选项
|
|
14
|
+
|
|
15
|
+
| 参数名 | 用途 | 类型 | 默认值 |
|
|
16
|
+
| - | - | - | - |
|
|
17
|
+
| `useAESDecrypt` | 是否使用 AES 解密 | `boolean` | `false` |
|
|
18
|
+
| `aesDecryptInfo` | AES 解密信息 | `AESDecryptInfo` | - |
|
|
19
|
+
|
|
20
|
+
## 解密密钥信息类型
|
|
21
|
+
|
|
22
|
+
`AESKeyInfo` 类型如下:
|
|
23
|
+
|
|
24
|
+
| 参数名 | 用途 | 类型 | 默认值 |
|
|
25
|
+
| - | - | - | - |
|
|
26
|
+
| `sign` | 解密签名(密钥) | `string` | - |
|
|
27
|
+
| `iv` | 解密偏移量 | `string` | - |
|
|
28
|
+
|
|
29
|
+
## 解密位置枚举
|
|
30
|
+
|
|
31
|
+
`AESDecryptPosition` 枚举如下:
|
|
32
|
+
|
|
33
|
+
| 枚举值 | 描述 |
|
|
34
|
+
| - | - |
|
|
35
|
+
| `AESDecryptPosition.WholeResponse` | 解密整个响应数据 |
|
|
36
|
+
| `AESDecryptPosition.ResponseData` | 仅解密响应中的 data 字段 |
|
|
37
|
+
|
|
38
|
+
## 使用方式
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import { PolyvRequest } from '@polyv/request-core';
|
|
42
|
+
import {
|
|
43
|
+
AESDecryptRequestPlugin,
|
|
44
|
+
AESDecryptPosition
|
|
45
|
+
} from '@polyv/request-plugin-aes-decrypt';
|
|
46
|
+
|
|
47
|
+
// 基础用法:使用固定的解密密钥
|
|
48
|
+
const requester = new PolyvRequest({
|
|
49
|
+
requestPlugins: [
|
|
50
|
+
new AESDecryptRequestPlugin({
|
|
51
|
+
decryptKeys: {
|
|
52
|
+
sign: 'yourDecryptKey',
|
|
53
|
+
iv: 'yourDecryptIV',
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 配置解密位置
|
|
60
|
+
const requester = new PolyvRequest({
|
|
61
|
+
requestPlugins: [
|
|
62
|
+
new AESDecryptRequestPlugin({
|
|
63
|
+
decryptKeys: {
|
|
64
|
+
sign: 'yourDecryptKey',
|
|
65
|
+
iv: 'yourDecryptIV',
|
|
66
|
+
},
|
|
67
|
+
decryptPosition: AESDecryptPosition.WholeResponse,
|
|
68
|
+
}),
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// 使用 getDecryptInfo 方法动态获取解密信息
|
|
73
|
+
const requester = new PolyvRequest({
|
|
74
|
+
requestPlugins: [
|
|
75
|
+
new AESDecryptRequestPlugin({
|
|
76
|
+
getDecryptInfo: async (options) => {
|
|
77
|
+
// 可以根据 options 中的信息动态获取解密密钥
|
|
78
|
+
return {
|
|
79
|
+
decryptKeys: {
|
|
80
|
+
sign: 'dynamicDecryptKey',
|
|
81
|
+
iv: 'dynamicDecryptIV',
|
|
82
|
+
},
|
|
83
|
+
decryptPosition: AESDecryptPosition.ResponseData,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 在某个请求中启用 AES 解密
|
|
91
|
+
requester.get('/api/data', {}, {
|
|
92
|
+
useAESDecrypt: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// 在某个请求中使用特定的解密信息
|
|
96
|
+
requester.get('/api/data', {}, {
|
|
97
|
+
useAESDecrypt: true,
|
|
98
|
+
aesDecryptInfo: {
|
|
99
|
+
decryptKeys: {
|
|
100
|
+
sign: 'specificKey',
|
|
101
|
+
iv: 'specificIV',
|
|
102
|
+
},
|
|
103
|
+
decryptPosition: AESDecryptPosition.WholeResponse,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 解密处理逻辑
|
|
109
|
+
|
|
110
|
+
1. 插件默认不启用,需要在请求选项中设置 `useAESDecrypt: true` 或全局配置启用
|
|
111
|
+
2. 解密信息的优先级为:请求选项中的 `aesDecryptInfo` > `getDecryptInfo` 方法返回的信息 > 初始化时提供的配置
|
|
112
|
+
3. 根据 `decryptPosition` 的设置,可以选择解密整个响应数据或只解密响应中的 data 字段
|
|
113
|
+
4. 解密后,如果解密结果是有效的 JSON 字符串,会自动解析为 JavaScript 对象
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RequestOptions, RequestPlugin, RequestResult } from '@polyv/request-core';
|
|
2
|
+
import { AESDecryptRequestPluginConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* aes 解密请求插件
|
|
5
|
+
*/
|
|
6
|
+
export declare class AESDecryptRequestPlugin implements RequestPlugin {
|
|
7
|
+
private __config;
|
|
8
|
+
constructor(config?: AESDecryptRequestPluginConfig);
|
|
9
|
+
usePlugin(options: RequestOptions): boolean;
|
|
10
|
+
interceptDecryptResponse(result: RequestResult, options: RequestOptions): Promise<RequestResult>;
|
|
11
|
+
private __getDecryptInfo;
|
|
12
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AESDecryptPosition, AESDecryptType } from './types';
|
|
2
|
+
import { decryptTextAES } from './utils';
|
|
3
|
+
/**
|
|
4
|
+
* aes 解密请求插件
|
|
5
|
+
*/
|
|
6
|
+
export class AESDecryptRequestPlugin {
|
|
7
|
+
__config;
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
this.__config = config;
|
|
10
|
+
}
|
|
11
|
+
usePlugin(options) {
|
|
12
|
+
const { useAESDecrypt = false } = options;
|
|
13
|
+
return useAESDecrypt;
|
|
14
|
+
}
|
|
15
|
+
async interceptDecryptResponse(result, options) {
|
|
16
|
+
const decryptInfo = await this.__getDecryptInfo(options);
|
|
17
|
+
if (!decryptInfo || !decryptInfo.decryptKeys) {
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
let newResultData = result.data;
|
|
21
|
+
const decryptPosition = decryptInfo.decryptPosition || AESDecryptPosition.ResponseData;
|
|
22
|
+
// 整个 response 解密
|
|
23
|
+
if (decryptPosition === AESDecryptPosition.WholeResponse && typeof result.data === 'string') {
|
|
24
|
+
newResultData = decryptTextAES(result.data, decryptInfo.decryptKeys, AESDecryptType.Hex);
|
|
25
|
+
}
|
|
26
|
+
// response.data 解密
|
|
27
|
+
if (decryptPosition === AESDecryptPosition.ResponseData && typeof result.data === 'object' && result.data) {
|
|
28
|
+
const res = result.data;
|
|
29
|
+
if (typeof res.data === 'string') {
|
|
30
|
+
const decryptedData = decryptTextAES(res.data, decryptInfo.decryptKeys, AESDecryptType.Hex);
|
|
31
|
+
newResultData = {
|
|
32
|
+
...newResultData,
|
|
33
|
+
data: decryptedData,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...result,
|
|
39
|
+
data: newResultData,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async __getDecryptInfo(options) {
|
|
43
|
+
let info = {
|
|
44
|
+
...this.__config,
|
|
45
|
+
};
|
|
46
|
+
if (typeof this.__config.getDecryptInfo === 'function') {
|
|
47
|
+
// 第二优先:实例化参数的 getDecryptInfo
|
|
48
|
+
const res = await this.__config.getDecryptInfo(options) || {};
|
|
49
|
+
info = { ...info, ...res };
|
|
50
|
+
}
|
|
51
|
+
if (options.aesDecryptInfo) {
|
|
52
|
+
// 第一优先:请求选项
|
|
53
|
+
info = { ...info, ...options.aesDecryptInfo };
|
|
54
|
+
}
|
|
55
|
+
return info;
|
|
56
|
+
}
|
|
57
|
+
}
|
package/index.d.ts
ADDED
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@polyv/request-plugin-aes-decrypt",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"main": "./index.js",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@polyv/request-core": "2.0.0",
|
|
7
|
+
"aes-js": "^3.1.2",
|
|
8
|
+
"crypto-js": "^4.1.1",
|
|
9
|
+
"js-base64": "^3.7.5"
|
|
10
|
+
},
|
|
11
|
+
"types": "./index.d.ts"
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AESDecryptInfo } from './types';
|
|
2
|
+
export interface AESDecryptRequestOptions {
|
|
3
|
+
/**
|
|
4
|
+
* 使用 aes 解密 data
|
|
5
|
+
* @default false
|
|
6
|
+
* @plugin `AESDecryptRequestPlugin`
|
|
7
|
+
*/
|
|
8
|
+
useAESDecrypt?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* aes 解密信息
|
|
11
|
+
* @plugin `AESDecryptRequestPlugin`
|
|
12
|
+
*/
|
|
13
|
+
aesDecryptInfo?: AESDecryptInfo;
|
|
14
|
+
}
|
|
15
|
+
declare module '@polyv/request-core' {
|
|
16
|
+
interface RequestCustomOptions extends AESDecryptRequestOptions {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
declare module 'axios' {
|
|
20
|
+
interface AxiosRequestConfig extends AESDecryptRequestOptions {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { RequestOptions } from '@polyv/request-core';
|
|
2
|
+
export interface AESDecryptRequestPluginConfig extends AESDecryptInfo {
|
|
3
|
+
/**
|
|
4
|
+
* 获取解密信息
|
|
5
|
+
*/
|
|
6
|
+
getDecryptInfo?: GetDecryptInfoFn;
|
|
7
|
+
}
|
|
8
|
+
export type GetDecryptInfoFn = (options: RequestOptions) => Promise<AESDecryptInfo | void> | AESDecryptInfo | void;
|
|
9
|
+
/**
|
|
10
|
+
* aes 解密位置
|
|
11
|
+
*/
|
|
12
|
+
export declare enum AESDecryptPosition {
|
|
13
|
+
/**
|
|
14
|
+
* 整个 response 数据解密
|
|
15
|
+
*/
|
|
16
|
+
WholeResponse = "wholeResponse",
|
|
17
|
+
/**
|
|
18
|
+
* 仅 response 中的 data 解密
|
|
19
|
+
*/
|
|
20
|
+
ResponseData = "responseData"
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* AES 解密编码方式
|
|
24
|
+
*/
|
|
25
|
+
export declare enum AESDecryptType {
|
|
26
|
+
Hex = "hex",
|
|
27
|
+
Base64 = "base64"
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* AES 解密/加密密钥信息
|
|
31
|
+
*/
|
|
32
|
+
export interface AESKeyInfo {
|
|
33
|
+
/**
|
|
34
|
+
* 签名
|
|
35
|
+
*/
|
|
36
|
+
sign: string;
|
|
37
|
+
/**
|
|
38
|
+
* 偏移量
|
|
39
|
+
*/
|
|
40
|
+
iv: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 解密信息
|
|
44
|
+
*/
|
|
45
|
+
export interface AESDecryptInfo {
|
|
46
|
+
/**
|
|
47
|
+
* 解密 key 信息
|
|
48
|
+
*/
|
|
49
|
+
decryptKeys?: AESKeyInfo;
|
|
50
|
+
/**
|
|
51
|
+
* 解密位置
|
|
52
|
+
* @default AESDecryptPosition.ResponseData
|
|
53
|
+
*/
|
|
54
|
+
decryptPosition?: AESDecryptPosition;
|
|
55
|
+
}
|
package/types.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aes 解密位置
|
|
3
|
+
*/
|
|
4
|
+
export var AESDecryptPosition;
|
|
5
|
+
(function (AESDecryptPosition) {
|
|
6
|
+
/**
|
|
7
|
+
* 整个 response 数据解密
|
|
8
|
+
*/
|
|
9
|
+
AESDecryptPosition["WholeResponse"] = "wholeResponse";
|
|
10
|
+
/**
|
|
11
|
+
* 仅 response 中的 data 解密
|
|
12
|
+
*/
|
|
13
|
+
AESDecryptPosition["ResponseData"] = "responseData";
|
|
14
|
+
})(AESDecryptPosition || (AESDecryptPosition = {}));
|
|
15
|
+
/**
|
|
16
|
+
* AES 解密编码方式
|
|
17
|
+
*/
|
|
18
|
+
export var AESDecryptType;
|
|
19
|
+
(function (AESDecryptType) {
|
|
20
|
+
AESDecryptType["Hex"] = "hex";
|
|
21
|
+
AESDecryptType["Base64"] = "base64";
|
|
22
|
+
})(AESDecryptType || (AESDecryptType = {}));
|
package/utils.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AESDecryptType, AESKeyInfo } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 解密数据(hex 方式)
|
|
4
|
+
* @param encryptedText 加密内容
|
|
5
|
+
* @param decryptKeys 解密 key 信息
|
|
6
|
+
* @param decryptType 解密类型
|
|
7
|
+
* @returns 返回解密后的明文数据
|
|
8
|
+
*/
|
|
9
|
+
export declare function decryptTextAES(encryptedText: string, decryptKeys: AESKeyInfo, decryptType: AESDecryptType): unknown;
|
|
10
|
+
/**
|
|
11
|
+
* 解密数据(hex 方式)
|
|
12
|
+
* @param encryptedText 加密内容
|
|
13
|
+
* @param sign 解密签名
|
|
14
|
+
* @param customIV 解密偏移量
|
|
15
|
+
* @returns 返回解密后的明文
|
|
16
|
+
*/
|
|
17
|
+
export declare function decryptTextBase64(encryptedText: string, sign: string, customIV: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* 解密数据(hex 方式)
|
|
20
|
+
* @param encryptedText 加密内容
|
|
21
|
+
* @param sign 解密签名
|
|
22
|
+
* @param customIV 解密偏移量
|
|
23
|
+
* @returns 返回解密后的明文
|
|
24
|
+
*/
|
|
25
|
+
export declare function decryptTextHex(encryptedText: string, sign: string, customIV: string): string;
|
package/utils.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import aesjs from 'aes-js';
|
|
2
|
+
import CryptoJS from 'crypto-js';
|
|
3
|
+
import { Base64 } from 'js-base64';
|
|
4
|
+
import { AESDecryptType } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* 获取解密所需要的密钥
|
|
7
|
+
* @param str 密钥所需数据
|
|
8
|
+
* @param len 字节数
|
|
9
|
+
* @returns 返回128位(16字节)密钥
|
|
10
|
+
*/
|
|
11
|
+
const str2ab = (str, len) => {
|
|
12
|
+
const bytes = aesjs.utils.utf8.toBytes(str);
|
|
13
|
+
const bytesLen = bytes.length;
|
|
14
|
+
if (bytesLen >= len) {
|
|
15
|
+
return bytes.slice(0, len);
|
|
16
|
+
}
|
|
17
|
+
return ([].concat(...(new Array(Math.ceil(len / bytesLen)).fill(bytes)))).slice(0, len);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* 解密数据(hex 方式)
|
|
21
|
+
* @param encryptedText 加密内容
|
|
22
|
+
* @param decryptKeys 解密 key 信息
|
|
23
|
+
* @param decryptType 解密类型
|
|
24
|
+
* @returns 返回解密后的明文数据
|
|
25
|
+
*/
|
|
26
|
+
export function decryptTextAES(encryptedText, decryptKeys, decryptType) {
|
|
27
|
+
const { sign, iv } = decryptKeys;
|
|
28
|
+
let decryptedText = '';
|
|
29
|
+
try {
|
|
30
|
+
if (decryptType === AESDecryptType.Hex) {
|
|
31
|
+
decryptedText = decryptTextHex(encryptedText, sign, iv);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
decryptedText = decryptTextBase64(encryptedText, sign, iv);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error('decryptTextAES decrypt error', e, { encryptedText, decryptKeys, decryptType });
|
|
39
|
+
}
|
|
40
|
+
let res = decryptedText;
|
|
41
|
+
try {
|
|
42
|
+
res = JSON.parse(res);
|
|
43
|
+
}
|
|
44
|
+
catch (e) { }
|
|
45
|
+
return res;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 解密数据(hex 方式)
|
|
49
|
+
* @param encryptedText 加密内容
|
|
50
|
+
* @param sign 解密签名
|
|
51
|
+
* @param customIV 解密偏移量
|
|
52
|
+
* @returns 返回解密后的明文
|
|
53
|
+
*/
|
|
54
|
+
export function decryptTextBase64(encryptedText, sign, customIV) {
|
|
55
|
+
const cryptoKey = CryptoJS.enc.Utf8.parse(sign);
|
|
56
|
+
const cfg = {};
|
|
57
|
+
cfg.iv = CryptoJS.enc.Utf8.parse(customIV);
|
|
58
|
+
cfg.mode = CryptoJS.mode.CBC;
|
|
59
|
+
cfg.pad = CryptoJS.pad.Pkcs7;
|
|
60
|
+
const crypto = CryptoJS.AES;
|
|
61
|
+
const cj = crypto.decrypt(encryptedText, cryptoKey, cfg);
|
|
62
|
+
return cj.toString(CryptoJS.enc.Utf8);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 解密数据(hex 方式)
|
|
66
|
+
* @param encryptedText 加密内容
|
|
67
|
+
* @param sign 解密签名
|
|
68
|
+
* @param customIV 解密偏移量
|
|
69
|
+
* @returns 返回解密后的明文
|
|
70
|
+
*/
|
|
71
|
+
export function decryptTextHex(encryptedText, sign, customIV) {
|
|
72
|
+
const encryptedBytes = aesjs.utils.hex.toBytes(encryptedText);
|
|
73
|
+
const key = str2ab(sign, 16);
|
|
74
|
+
let iv = key;
|
|
75
|
+
if (customIV) {
|
|
76
|
+
iv = str2ab(customIV, 16);
|
|
77
|
+
}
|
|
78
|
+
// eslint-disable-next-line
|
|
79
|
+
const aesCfb = new aesjs.ModeOfOperation.cbc(key, iv);
|
|
80
|
+
const decryptedBytes = aesCfb.decrypt(encryptedBytes);
|
|
81
|
+
const decryptedText = aesjs.utils.utf8.fromBytes(decryptedBytes);
|
|
82
|
+
return Base64.decode(decryptedText);
|
|
83
|
+
}
|