@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 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
@@ -0,0 +1,4 @@
1
+ export * from './aes-decrypt-plugin';
2
+ export * from './types';
3
+ export * from './utils';
4
+ export * from './request-options';
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './aes-decrypt-plugin';
2
+ export * from './types';
3
+ export * from './utils';
4
+ export * from './request-options';
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
+ }