ph-utils 0.20.0 → 0.20.1
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/lib/dom.js +28 -18
- package/lib/src/array.d.ts +79 -0
- package/lib/src/array.js +212 -0
- package/lib/src/color.d.ts +55 -0
- package/lib/src/color.js +294 -0
- package/lib/src/config.d.ts +33 -0
- package/lib/src/config.js +99 -0
- package/lib/src/copy.d.ts +11 -0
- package/lib/src/copy.js +101 -0
- package/lib/src/crypto.d.ts +74 -0
- package/lib/src/crypto.js +261 -0
- package/lib/src/crypto_node.d.ts +61 -0
- package/lib/src/crypto_node.js +133 -0
- package/lib/src/date.d.ts +66 -0
- package/lib/src/date.js +202 -0
- package/lib/src/dom.d.ts +265 -0
- package/lib/src/dom.js +635 -0
- package/lib/src/file.d.ts +29 -0
- package/lib/src/file.js +54 -0
- package/lib/src/id.d.ts +68 -0
- package/lib/src/id.js +170 -0
- package/lib/src/index.d.ts +154 -0
- package/lib/src/index.js +239 -0
- package/lib/src/logger.d.ts +62 -0
- package/lib/src/logger.js +122 -0
- package/lib/src/server.d.ts +33 -0
- package/lib/src/server.js +65 -0
- package/lib/src/storage.d.ts +51 -0
- package/lib/src/storage.js +73 -0
- package/lib/src/theme.d.ts +44 -0
- package/lib/src/theme.js +156 -0
- package/lib/src/validator.d.ts +71 -0
- package/lib/src/validator.js +238 -0
- package/lib/src/web.d.ts +30 -0
- package/lib/src/web.js +100 -0
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** 配置信息 */
|
|
2
|
+
export declare let config: Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* 解析环境变量;
|
|
5
|
+
* 同时读取多个环境变量文件: .env, .env.local, .env.[development|test|production];
|
|
6
|
+
* 根据运行环境变量 `NODE_ENV` 读取不同的环境变量文件;
|
|
7
|
+
* 同时支持手动通过运行命令指定 `NODE_ENV` 值, 不指定默认为: production
|
|
8
|
+
*
|
|
9
|
+
* ```bash
|
|
10
|
+
* node test.js --NODE_ENV development
|
|
11
|
+
* // or
|
|
12
|
+
* node test.js -n development
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* ```js
|
|
16
|
+
* // test.js
|
|
17
|
+
* parseEnvs();
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseEnv(envFiles?: string[]): Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* 解析配置文件并合并内容。
|
|
25
|
+
*
|
|
26
|
+
* @param files - 要解析的配置文件列表,默认为 ["config.json", "config.local.json"]。
|
|
27
|
+
* @param runParseEnv - 是否运行环境变量解析,默认为 true。
|
|
28
|
+
* @returns 合并后的配置对象。
|
|
29
|
+
*
|
|
30
|
+
* 该函数会根据当前环境加载相应的配置文件,并将其内容合并到最终的配置对象中。
|
|
31
|
+
* 如果指定的文件列表中不包含环境特定的配置文件,则会自动添加。
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseConfig(files?: string[], runParseEnv?: boolean): Record<string, any>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { parseEnv as readEnv, parseArgs } from "node:util";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/** 配置信息 */
|
|
5
|
+
export let config = {};
|
|
6
|
+
/**
|
|
7
|
+
* 解析环境变量;
|
|
8
|
+
* 同时读取多个环境变量文件: .env, .env.local, .env.[development|test|production];
|
|
9
|
+
* 根据运行环境变量 `NODE_ENV` 读取不同的环境变量文件;
|
|
10
|
+
* 同时支持手动通过运行命令指定 `NODE_ENV` 值, 不指定默认为: production
|
|
11
|
+
*
|
|
12
|
+
* ```bash
|
|
13
|
+
* node test.js --NODE_ENV development
|
|
14
|
+
* // or
|
|
15
|
+
* node test.js -n development
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* // test.js
|
|
20
|
+
* parseEnvs();
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
export function parseEnv(envFiles = [".env", ".env.local"]) {
|
|
26
|
+
// development, test, production
|
|
27
|
+
const files = [...envFiles];
|
|
28
|
+
let nodeEnv = process.env.NODE_ENV;
|
|
29
|
+
const { values } = parseArgs({
|
|
30
|
+
options: {
|
|
31
|
+
NODE_ENV: {
|
|
32
|
+
type: "string",
|
|
33
|
+
short: "n",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
strict: false,
|
|
37
|
+
});
|
|
38
|
+
if (values.NODE_ENV != null && typeof values.NODE_ENV === "string") {
|
|
39
|
+
nodeEnv = values.NODE_ENV;
|
|
40
|
+
}
|
|
41
|
+
if (nodeEnv == null) {
|
|
42
|
+
nodeEnv = "production";
|
|
43
|
+
}
|
|
44
|
+
process.env.NODE_ENV = nodeEnv;
|
|
45
|
+
const envFile = `.env.${nodeEnv}`;
|
|
46
|
+
if (!files.includes(envFile)) {
|
|
47
|
+
files.push(envFile);
|
|
48
|
+
}
|
|
49
|
+
let envParsed = {};
|
|
50
|
+
for (let i = 0, len = files.length; i < len; i++) {
|
|
51
|
+
const file = join(process.cwd(), files[i]);
|
|
52
|
+
try {
|
|
53
|
+
const envContent = readFileSync(file, {
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
});
|
|
56
|
+
const envValue = readEnv(envContent);
|
|
57
|
+
for (const key in envValue) {
|
|
58
|
+
process.env[key] = envValue[key];
|
|
59
|
+
envParsed[key] = envValue[key];
|
|
60
|
+
}
|
|
61
|
+
// eslint-disable-next-line
|
|
62
|
+
}
|
|
63
|
+
catch (err) { }
|
|
64
|
+
}
|
|
65
|
+
return envParsed;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 解析配置文件并合并内容。
|
|
69
|
+
*
|
|
70
|
+
* @param files - 要解析的配置文件列表,默认为 ["config.json", "config.local.json"]。
|
|
71
|
+
* @param runParseEnv - 是否运行环境变量解析,默认为 true。
|
|
72
|
+
* @returns 合并后的配置对象。
|
|
73
|
+
*
|
|
74
|
+
* 该函数会根据当前环境加载相应的配置文件,并将其内容合并到最终的配置对象中。
|
|
75
|
+
* 如果指定的文件列表中不包含环境特定的配置文件,则会自动添加。
|
|
76
|
+
*/
|
|
77
|
+
export function parseConfig(files, runParseEnv = true) {
|
|
78
|
+
let d = [...(files || ["config.json", "config.local.json"])];
|
|
79
|
+
if (runParseEnv) {
|
|
80
|
+
parseEnv();
|
|
81
|
+
}
|
|
82
|
+
const envConfigPath = `config.${process.env.NODE_ENV}.json`;
|
|
83
|
+
if (!d.includes(envConfigPath)) {
|
|
84
|
+
d.push(envConfigPath);
|
|
85
|
+
}
|
|
86
|
+
for (let i = 0, len = d.length; i < len; i++) {
|
|
87
|
+
const filePath = join(process.cwd(), d[i]);
|
|
88
|
+
try {
|
|
89
|
+
const content = readFileSync(filePath, {
|
|
90
|
+
encoding: "utf-8",
|
|
91
|
+
});
|
|
92
|
+
let contentJson = JSON.parse(content);
|
|
93
|
+
config = { ...config, ...contentJson };
|
|
94
|
+
// eslint-disable-next-line
|
|
95
|
+
}
|
|
96
|
+
catch (err) { }
|
|
97
|
+
}
|
|
98
|
+
return config;
|
|
99
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 复制数据, 可以从多种类型的数据
|
|
3
|
+
* 1. 直接复制文本: await copy("待复制的文本")
|
|
4
|
+
* 2. 复制节点上的 data-copy-text:
|
|
5
|
+
* <button data-copy-text="这是待复制的文本">复制</button>
|
|
6
|
+
* await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
|
|
7
|
+
* 3. 直接复制节点本身数据: await copy('#a')
|
|
8
|
+
* @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
|
|
9
|
+
* @returns {Promise<boolean>} 是否复制成功
|
|
10
|
+
*/
|
|
11
|
+
export declare function copy(source: string | HTMLElement): Promise<boolean>;
|
package/lib/src/copy.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 创建一个临时节点缓存待复制数据
|
|
3
|
+
* @param {String} value
|
|
4
|
+
* @return {HTMLElement}
|
|
5
|
+
*/
|
|
6
|
+
function createFakeElement(value) {
|
|
7
|
+
const fakeElement = document.createElement("textarea");
|
|
8
|
+
fakeElement.style.border = "0";
|
|
9
|
+
fakeElement.style.padding = "0";
|
|
10
|
+
fakeElement.style.margin = "0";
|
|
11
|
+
fakeElement.style.position = "absolute";
|
|
12
|
+
fakeElement.style.left = "-9999px";
|
|
13
|
+
fakeElement.style.top = "-9999";
|
|
14
|
+
fakeElement.setAttribute("readonly", "");
|
|
15
|
+
fakeElement.value = value;
|
|
16
|
+
return fakeElement;
|
|
17
|
+
}
|
|
18
|
+
/** 通过执行 execCommand 来执行复制 */
|
|
19
|
+
function copyFromCommand(text) {
|
|
20
|
+
// 添加节点
|
|
21
|
+
const fakeEl = createFakeElement(text);
|
|
22
|
+
document.body.append(fakeEl);
|
|
23
|
+
fakeEl.focus();
|
|
24
|
+
fakeEl.select();
|
|
25
|
+
// 执行复制
|
|
26
|
+
const res = document.execCommand("copy");
|
|
27
|
+
fakeEl.remove(); // 删除节点
|
|
28
|
+
return Promise.resolve(res);
|
|
29
|
+
}
|
|
30
|
+
/** 使用 navigator.clipboard 复制 */
|
|
31
|
+
function copyFromClipboard(text) {
|
|
32
|
+
const theClipboard = navigator.clipboard;
|
|
33
|
+
if (theClipboard != null) {
|
|
34
|
+
return theClipboard
|
|
35
|
+
.writeText(text)
|
|
36
|
+
.then(() => {
|
|
37
|
+
Promise.resolve(true);
|
|
38
|
+
})
|
|
39
|
+
.catch(() => Promise.resolve(false));
|
|
40
|
+
}
|
|
41
|
+
return Promise.resolve(false);
|
|
42
|
+
}
|
|
43
|
+
/** 解析待复制的文本 */
|
|
44
|
+
function parseCopyText(source) {
|
|
45
|
+
let copyText = null; // 待复制文本
|
|
46
|
+
let sourceEl = null;
|
|
47
|
+
// 获取待复制数据
|
|
48
|
+
if (typeof source === "string") {
|
|
49
|
+
// 从节点拿数据
|
|
50
|
+
if (source.startsWith("#") || source.startsWith(".")) {
|
|
51
|
+
sourceEl = document.querySelector(source);
|
|
52
|
+
if (sourceEl == null) {
|
|
53
|
+
copyText = source;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
copyText = source;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (source instanceof HTMLElement) {
|
|
61
|
+
sourceEl = source;
|
|
62
|
+
}
|
|
63
|
+
// 从节点获取待复制数据
|
|
64
|
+
if (sourceEl != null) {
|
|
65
|
+
if (sourceEl.hasAttribute("data-copy-text")) {
|
|
66
|
+
copyText = sourceEl.getAttribute("data-copy-text");
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const tagName = sourceEl.tagName;
|
|
70
|
+
if (tagName === "INPUT" || tagName === "TEXTAREA") {
|
|
71
|
+
copyText = sourceEl.value;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
copyText = sourceEl.textContent;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return copyText;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 复制数据, 可以从多种类型的数据
|
|
82
|
+
* 1. 直接复制文本: await copy("待复制的文本")
|
|
83
|
+
* 2. 复制节点上的 data-copy-text:
|
|
84
|
+
* <button data-copy-text="这是待复制的文本">复制</button>
|
|
85
|
+
* await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
|
|
86
|
+
* 3. 直接复制节点本身数据: await copy('#a')
|
|
87
|
+
* @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
|
|
88
|
+
* @returns {Promise<boolean>} 是否复制成功
|
|
89
|
+
*/
|
|
90
|
+
export async function copy(source) {
|
|
91
|
+
// 待复制文本
|
|
92
|
+
const copyText = parseCopyText(source);
|
|
93
|
+
if (copyText == null) {
|
|
94
|
+
return Promise.resolve(false);
|
|
95
|
+
}
|
|
96
|
+
const v = await copyFromClipboard(copyText);
|
|
97
|
+
if (v === false) {
|
|
98
|
+
return copyFromCommand(copyText);
|
|
99
|
+
}
|
|
100
|
+
return Promise.resolve(true);
|
|
101
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将原始的二进制数据转换为 Hex String
|
|
3
|
+
* @param bf 待转换的原始数据
|
|
4
|
+
* @param upper 是否需要转换为大写
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export declare function bufferToHex(bf: ArrayBuffer | Uint8Array, upper?: boolean): string;
|
|
8
|
+
/**
|
|
9
|
+
* SHA 哈希算法
|
|
10
|
+
* @param message 待进行 hash 的数据
|
|
11
|
+
* @param upper 是否转换为大写, 默认为: false
|
|
12
|
+
* @param algorithm hash算法, 支持: SHA-1、SHA-256、SHA-384、SHA-512; 默认为: SHA-256
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
export declare function sha(message: string | ArrayBuffer, upper?: boolean, algorithm?: string): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* 哈希算法
|
|
18
|
+
* @param message 待进行 hash 的数据
|
|
19
|
+
* @param upper 是否转换为大写, 默认为: false
|
|
20
|
+
* @param algorithm hash算法, 支持: SHA-1、SHA-256、SHA-384、SHA-512; 默认为: SHA-256
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
23
|
+
export declare function hash(message: string | ArrayBuffer, upper?: boolean, algorithm?: string): Promise<string>;
|
|
24
|
+
type HMACAlgorithm = "SHA-256" | "SHA-512";
|
|
25
|
+
/**
|
|
26
|
+
* 使用 HMAC 算法计算消息的哈希值
|
|
27
|
+
* @param message - 需要计算哈希的消息字符串
|
|
28
|
+
* @param secret - 用于生成 HMAC 的密钥
|
|
29
|
+
* @param algorithm - HMAC 使用的哈希算法,默认为 "SHA-256"
|
|
30
|
+
* @param upper - 是否将结果转换为大写,默认为 false
|
|
31
|
+
* @returns 返回十六进制格式的 HMAC 哈希值
|
|
32
|
+
*/
|
|
33
|
+
export declare function hmacHash(message: string, secret: string, algorithm?: HMACAlgorithm, upper?: boolean): Promise<string>;
|
|
34
|
+
/** 返回结果类似 */
|
|
35
|
+
type AlgorithmResType = "hex" | "hexUpper" | "base64" | "raw";
|
|
36
|
+
/**
|
|
37
|
+
* AES 加密
|
|
38
|
+
* @param message 待加密的数据
|
|
39
|
+
* @param key 加解密密钥
|
|
40
|
+
* @param encode 加密后的数据转换的形式, hex - 转换为16进制字符串, hexUpper - 转换为16进制且大写, base64 - 转换为 base64 形式
|
|
41
|
+
* @param iv 加解密向量
|
|
42
|
+
* @returns [加密数据,向量]
|
|
43
|
+
*/
|
|
44
|
+
export declare function aesEncrypt(message: string, key: string, encode?: AlgorithmResType, iv?: null | Uint8Array | string): Promise<{
|
|
45
|
+
ciphertext: string | ArrayBuffer;
|
|
46
|
+
iv: string;
|
|
47
|
+
key: string;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* AES 解密
|
|
51
|
+
* @param message 加密后的数据
|
|
52
|
+
* @param key 解密密钥
|
|
53
|
+
* @param iv 向量
|
|
54
|
+
* @param encode 加密后数据的形式: hex | base64
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
57
|
+
export declare function aesDecrypt(message: Uint8Array | string, key: string, iv: string, encode?: AlgorithmResType): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* RSA 加密
|
|
60
|
+
* @param key 公钥
|
|
61
|
+
* @param message 待加密数据
|
|
62
|
+
* @param encode 返回类型
|
|
63
|
+
* @returns
|
|
64
|
+
*/
|
|
65
|
+
export declare function rsaEncrypt(message: string, publicKey: string, encode?: AlgorithmResType): Promise<string | ArrayBuffer>;
|
|
66
|
+
/**
|
|
67
|
+
* RSA 解密
|
|
68
|
+
* @param key 私钥, 根据私钥解密
|
|
69
|
+
* @param message 加密后的数据
|
|
70
|
+
* @param encode 加密后的数据形式
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
export declare function rsaDecrypt(privateKey: string, message: Uint8Array | string, encode?: AlgorithmResType): Promise<string>;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/**
|
|
3
|
+
* 将原始的二进制数据转换为 Hex String
|
|
4
|
+
* @param bf 待转换的原始数据
|
|
5
|
+
* @param upper 是否需要转换为大写
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function bufferToHex(bf, upper = false) {
|
|
9
|
+
const u8Array = bf instanceof Uint8Array ? bf : new Uint8Array(bf);
|
|
10
|
+
const hashArray = Array.from(u8Array);
|
|
11
|
+
return hashArray
|
|
12
|
+
.map((b) => {
|
|
13
|
+
let hx = b.toString(16).padStart(2, "0");
|
|
14
|
+
return upper === true ? hx.toUpperCase() : hx;
|
|
15
|
+
})
|
|
16
|
+
.join("");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 将16进制的数据转换为 UInt8Array
|
|
20
|
+
* @param data 16进制的数据
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
23
|
+
function hexToBuffer(data) {
|
|
24
|
+
const len = data.length / 2;
|
|
25
|
+
const uint8Array = new Uint8Array(len);
|
|
26
|
+
for (let i = 0; i < len; i++) {
|
|
27
|
+
const byteHex = data.substring(i * 2, i * 2 + 2);
|
|
28
|
+
const byte = parseInt(byteHex.toLocaleLowerCase(), 16);
|
|
29
|
+
uint8Array[i] = byte;
|
|
30
|
+
}
|
|
31
|
+
return uint8Array;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 将原始数据转换为 Base64 编码
|
|
35
|
+
* @param bf 待转换的原始数据
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
function bufferToBase64(bf) {
|
|
39
|
+
const u8Array = bf instanceof Uint8Array ? bf : new Uint8Array(bf);
|
|
40
|
+
const hashArray = Array.from(u8Array);
|
|
41
|
+
return globalThis.btoa(String.fromCharCode.apply(null, hashArray));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 将 Base64 转换为 UInt8Array 数据
|
|
45
|
+
* @param data
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
function base64ToBuffer(data) {
|
|
49
|
+
return new Uint8Array(globalThis
|
|
50
|
+
.atob(data)
|
|
51
|
+
.split("")
|
|
52
|
+
.map((char) => char.charCodeAt(0)));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* SHA 哈希算法
|
|
56
|
+
* @param message 待进行 hash 的数据
|
|
57
|
+
* @param upper 是否转换为大写, 默认为: false
|
|
58
|
+
* @param algorithm hash算法, 支持: SHA-1、SHA-256、SHA-384、SHA-512; 默认为: SHA-256
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
export async function sha(message, upper = false, algorithm = "SHA-256") {
|
|
62
|
+
let msgBuffer = message;
|
|
63
|
+
if (typeof message === "string") {
|
|
64
|
+
msgBuffer = new TextEncoder().encode(message);
|
|
65
|
+
}
|
|
66
|
+
const hashBuffer = await globalThis.crypto.subtle.digest(algorithm || "SHA-256", msgBuffer);
|
|
67
|
+
return bufferToHex(hashBuffer, upper);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 哈希算法
|
|
71
|
+
* @param message 待进行 hash 的数据
|
|
72
|
+
* @param upper 是否转换为大写, 默认为: false
|
|
73
|
+
* @param algorithm hash算法, 支持: SHA-1、SHA-256、SHA-384、SHA-512; 默认为: SHA-256
|
|
74
|
+
* @returns
|
|
75
|
+
*/
|
|
76
|
+
export async function hash(message, upper = false, algorithm = "SHA-256") {
|
|
77
|
+
return sha(message, upper, algorithm);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 使用 HMAC 算法计算消息的哈希值
|
|
81
|
+
* @param message - 需要计算哈希的消息字符串
|
|
82
|
+
* @param secret - 用于生成 HMAC 的密钥
|
|
83
|
+
* @param algorithm - HMAC 使用的哈希算法,默认为 "SHA-256"
|
|
84
|
+
* @param upper - 是否将结果转换为大写,默认为 false
|
|
85
|
+
* @returns 返回十六进制格式的 HMAC 哈希值
|
|
86
|
+
*/
|
|
87
|
+
export async function hmacHash(message, secret, algorithm = "SHA-256", upper = false) {
|
|
88
|
+
const encoder = new TextEncoder();
|
|
89
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: { name: algorithm } }, false, ["sign"]);
|
|
90
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
|
|
91
|
+
return bufferToHex(signature, upper);
|
|
92
|
+
}
|
|
93
|
+
function parseRsaKey(pem) {
|
|
94
|
+
const pemHeader = "-----BEGIN PUBLIC KEY-----";
|
|
95
|
+
const pemFooter = "-----END PUBLIC KEY-----";
|
|
96
|
+
if (pem.indexOf(pemHeader) !== -1 && pem.indexOf(pemFooter) !== -1) {
|
|
97
|
+
pem = pem.substring(pemHeader.length, pem.indexOf(pemFooter)).trim();
|
|
98
|
+
}
|
|
99
|
+
return pem;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 导入上下文密钥
|
|
103
|
+
* @param key 导入的密钥
|
|
104
|
+
* @param algorithmName 算法名称
|
|
105
|
+
* @param usages 该密钥可以用于哪些函数使用
|
|
106
|
+
* @returns
|
|
107
|
+
*/
|
|
108
|
+
// eslint-disable-next-line no-undef
|
|
109
|
+
async function importKey(key, algorithmName, usages, encoding = "hex") {
|
|
110
|
+
let name = "AES-CBC";
|
|
111
|
+
if (algorithmName == null) {
|
|
112
|
+
name = "AES-CBC";
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (algorithmName.toUpperCase() === "AES") {
|
|
116
|
+
name = "AES-CBC";
|
|
117
|
+
}
|
|
118
|
+
else if (algorithmName.toUpperCase() === "RSA") {
|
|
119
|
+
name = "RSA-OAEP";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
name = name.toUpperCase();
|
|
123
|
+
if (usages == null || usages.length === 0) {
|
|
124
|
+
usages = ["encrypt"];
|
|
125
|
+
}
|
|
126
|
+
let format = "raw";
|
|
127
|
+
let algorithm = { name };
|
|
128
|
+
if (name.includes("RSA")) {
|
|
129
|
+
format = "spki";
|
|
130
|
+
algorithm.hash = { name: "SHA-256" };
|
|
131
|
+
key = parseRsaKey(key);
|
|
132
|
+
}
|
|
133
|
+
const keyBuf = encoding === "base64" ? base64ToBuffer(key) : hexToBuffer(key);
|
|
134
|
+
// importKey时传 false 表明该密钥不能被导出
|
|
135
|
+
return Promise.all([
|
|
136
|
+
globalThis.crypto.subtle.importKey(format, keyBuf, algorithm, false, usages),
|
|
137
|
+
Promise.resolve({ name }),
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 加密
|
|
142
|
+
* @param algorithm 算法参数, 算法名称、向量等
|
|
143
|
+
* @param key 算法密钥
|
|
144
|
+
* @param message 待加密的数据
|
|
145
|
+
* @param encode 解密后返回数据格式
|
|
146
|
+
* @returns
|
|
147
|
+
*/
|
|
148
|
+
async function encrypt(algorithm, key, message, encode = "hex") {
|
|
149
|
+
if (typeof message === "string") {
|
|
150
|
+
message = new TextEncoder().encode(message);
|
|
151
|
+
}
|
|
152
|
+
const encrypted = await globalThis.crypto.subtle.encrypt(algorithm, key, message);
|
|
153
|
+
if (encode === "hex") {
|
|
154
|
+
return bufferToHex(encrypted);
|
|
155
|
+
}
|
|
156
|
+
else if (encode === "hexUpper") {
|
|
157
|
+
return bufferToHex(encrypted, true);
|
|
158
|
+
}
|
|
159
|
+
else if (encode === "base64") {
|
|
160
|
+
return bufferToBase64(encrypted);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
return encrypted;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 数据解密
|
|
168
|
+
* @param algorithm 解密算法
|
|
169
|
+
* @param key 解密密钥
|
|
170
|
+
* @param message 加密后的数据
|
|
171
|
+
* @returns
|
|
172
|
+
*/
|
|
173
|
+
async function decrypt(algorithm, key, message) {
|
|
174
|
+
const decrypted = await globalThis.crypto.subtle.decrypt(algorithm, key, message);
|
|
175
|
+
return new TextDecoder("utf-8").decode(decrypted);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* AES 加密
|
|
179
|
+
* @param message 待加密的数据
|
|
180
|
+
* @param key 加解密密钥
|
|
181
|
+
* @param encode 加密后的数据转换的形式, hex - 转换为16进制字符串, hexUpper - 转换为16进制且大写, base64 - 转换为 base64 形式
|
|
182
|
+
* @param iv 加解密向量
|
|
183
|
+
* @returns [加密数据,向量]
|
|
184
|
+
*/
|
|
185
|
+
export async function aesEncrypt(message, key, encode = "hex", iv = null) {
|
|
186
|
+
let ciphertext = "";
|
|
187
|
+
let resIv = "";
|
|
188
|
+
// 导入密钥
|
|
189
|
+
const [cryptoKey, algorithm] = await importKey(key, "aes", ["encrypt"]);
|
|
190
|
+
if (iv == null) {
|
|
191
|
+
iv = globalThis.crypto.getRandomValues(new Uint8Array(16));
|
|
192
|
+
}
|
|
193
|
+
else if (typeof iv === "string") {
|
|
194
|
+
iv = hexToBuffer(iv);
|
|
195
|
+
}
|
|
196
|
+
const encodeData = await encrypt({ ...algorithm, iv: iv }, cryptoKey, message, encode);
|
|
197
|
+
ciphertext = encodeData;
|
|
198
|
+
resIv = bufferToHex(iv);
|
|
199
|
+
return { ciphertext, iv: resIv, key };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* 根据加密后的数据类型使用对应函数最终转换为 UInt8Array
|
|
203
|
+
* @param message 原始加密后的数据
|
|
204
|
+
* @param type 类型: hex | base64
|
|
205
|
+
* @returns
|
|
206
|
+
*/
|
|
207
|
+
function parseEncryptData(message, type) {
|
|
208
|
+
let input;
|
|
209
|
+
if (typeof message === "string") {
|
|
210
|
+
if (type === "hex" || type === "hexUpper") {
|
|
211
|
+
input = hexToBuffer(message);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
input = base64ToBuffer(message);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
input = message;
|
|
219
|
+
}
|
|
220
|
+
return input;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* AES 解密
|
|
224
|
+
* @param message 加密后的数据
|
|
225
|
+
* @param key 解密密钥
|
|
226
|
+
* @param iv 向量
|
|
227
|
+
* @param encode 加密后数据的形式: hex | base64
|
|
228
|
+
* @returns
|
|
229
|
+
*/
|
|
230
|
+
export async function aesDecrypt(message, key, iv, encode = "hex") {
|
|
231
|
+
// 导入密钥
|
|
232
|
+
const [cryptoKey, algorithm] = await importKey(key, "aes", ["decrypt"]);
|
|
233
|
+
const input = parseEncryptData(message, encode);
|
|
234
|
+
return await decrypt({ ...algorithm, iv: hexToBuffer(iv) }, cryptoKey, input);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* RSA 加密
|
|
238
|
+
* @param key 公钥
|
|
239
|
+
* @param message 待加密数据
|
|
240
|
+
* @param encode 返回类型
|
|
241
|
+
* @returns
|
|
242
|
+
*/
|
|
243
|
+
export async function rsaEncrypt(message, publicKey, encode = "hex") {
|
|
244
|
+
// 导入密钥
|
|
245
|
+
const [cryptoKey, algorithm] = await importKey(publicKey, "rsa", ["encrypt"], "base64");
|
|
246
|
+
return await encrypt(algorithm, cryptoKey, message, encode);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* RSA 解密
|
|
250
|
+
* @param key 私钥, 根据私钥解密
|
|
251
|
+
* @param message 加密后的数据
|
|
252
|
+
* @param encode 加密后的数据形式
|
|
253
|
+
* @returns
|
|
254
|
+
*/
|
|
255
|
+
export async function rsaDecrypt(privateKey, message, encode = "hex") {
|
|
256
|
+
// 导入密钥
|
|
257
|
+
const [cryptoKey, algorithm] = await importKey(privateKey, "rsa", [
|
|
258
|
+
"decrypt",
|
|
259
|
+
]);
|
|
260
|
+
return await decrypt({ ...algorithm }, cryptoKey, parseEncryptData(message, encode));
|
|
261
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
type HashAlgorithmName = "md5" | SHAHashAlgorithmName;
|
|
2
|
+
type SHAHashAlgorithmName = "sha1" | "sha256" | "sha512";
|
|
3
|
+
/**
|
|
4
|
+
* 进行 md5|sha1|sha256 数据摘要签名
|
|
5
|
+
* @param d 待加密的数据
|
|
6
|
+
* @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
|
|
7
|
+
* @param upper 返回的结果是否需要大写. Defaults to False.
|
|
8
|
+
*/
|
|
9
|
+
export declare function hashDigest(d: string, algorithm?: HashAlgorithmName, upper?: boolean): string;
|
|
10
|
+
/**
|
|
11
|
+
* 进行 md5|sha1|sha256 数据摘要签名
|
|
12
|
+
* @param d 待加密的数据
|
|
13
|
+
* @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
|
|
14
|
+
* @param upper 返回的结果是否需要大写. Defaults to False.
|
|
15
|
+
*/
|
|
16
|
+
export declare function hash(d: string, algorithm?: HashAlgorithmName, upper?: boolean): string;
|
|
17
|
+
/**
|
|
18
|
+
* 使用 HMAC 算法对消息进行哈希处理
|
|
19
|
+
* @param message 待处理的消息
|
|
20
|
+
* @param key 用于 HMAC 算法的密钥
|
|
21
|
+
* @param algorithm 哈希算法,可选值为 "sha1"、"sha256" 或 "sha512",默认为 "sha256"
|
|
22
|
+
* @param upper 返回的结果是否需要大写,默认为 false
|
|
23
|
+
* @returns 经过 HMAC 哈希处理后的字符串
|
|
24
|
+
*/
|
|
25
|
+
export declare function hmacHash(message: string, key: string, algorithm?: SHAHashAlgorithmName, upper?: boolean): string;
|
|
26
|
+
/**
|
|
27
|
+
* 生成 RSA 签名密钥对
|
|
28
|
+
* @returns: [公钥, 私钥]
|
|
29
|
+
*/
|
|
30
|
+
export declare function keyPair(): Promise<[string, string]>;
|
|
31
|
+
/**
|
|
32
|
+
* AES 加密
|
|
33
|
+
* @param key 加密密钥
|
|
34
|
+
* @param input 待加密的数据
|
|
35
|
+
* @param upper 是否转换为大写
|
|
36
|
+
* @returns [加密数据, 向量]
|
|
37
|
+
*/
|
|
38
|
+
export declare function aesEncrypt(key: string, input: string, upper?: boolean): [string, string];
|
|
39
|
+
/**
|
|
40
|
+
* AES 解密
|
|
41
|
+
* @param input 加密后的数据
|
|
42
|
+
* @param key 密钥
|
|
43
|
+
* @param iv 向量
|
|
44
|
+
* @returns
|
|
45
|
+
*/
|
|
46
|
+
export declare function aesDecrypt(input: string, key: string | Buffer, iv?: string | Buffer, algorithm?: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* RSA 公钥加密
|
|
49
|
+
* @param input 待加密字符串
|
|
50
|
+
* @param publicKey 公钥
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
export declare function rsaEncrypt(input: string, publicKey: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* RSA 解密
|
|
56
|
+
* @param encrtypData RSA加密后的数据
|
|
57
|
+
* @param privateKey 私钥
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
export declare function rsaDecrypt(encrtypData: string, privateKey: string): string;
|
|
61
|
+
export {};
|