ph-utils 0.18.0 → 0.19.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.
@@ -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 {};
@@ -0,0 +1,133 @@
1
+ import { createHash, createCipheriv, randomBytes, generateKeyPair, createDecipheriv, privateDecrypt, publicEncrypt, createHmac, } from "node:crypto";
2
+ /**
3
+ * 进行 md5|sha1|sha256 数据摘要签名
4
+ * @param d 待加密的数据
5
+ * @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
6
+ * @param upper 返回的结果是否需要大写. Defaults to False.
7
+ */
8
+ export function hashDigest(d, algorithm = "sha256", upper = false) {
9
+ const hashed = createHash(algorithm).update(d).digest("hex");
10
+ return upper ? hashed.toUpperCase() : hashed;
11
+ }
12
+ /**
13
+ * 进行 md5|sha1|sha256 数据摘要签名
14
+ * @param d 待加密的数据
15
+ * @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
16
+ * @param upper 返回的结果是否需要大写. Defaults to False.
17
+ */
18
+ export function hash(d, algorithm = "sha256", upper = false) {
19
+ return hashDigest(d, algorithm, upper);
20
+ }
21
+ /**
22
+ * 使用 HMAC 算法对消息进行哈希处理
23
+ * @param message 待处理的消息
24
+ * @param key 用于 HMAC 算法的密钥
25
+ * @param algorithm 哈希算法,可选值为 "sha1"、"sha256" 或 "sha512",默认为 "sha256"
26
+ * @param upper 返回的结果是否需要大写,默认为 false
27
+ * @returns 经过 HMAC 哈希处理后的字符串
28
+ */
29
+ export function hmacHash(message, key, algorithm = "sha256", upper = false) {
30
+ const hashed = createHmac(algorithm, key).update(message).digest("hex");
31
+ return upper ? hashed.toUpperCase() : hashed;
32
+ }
33
+ /**
34
+ * 生成 RSA 签名密钥对
35
+ * @returns: [公钥, 私钥]
36
+ */
37
+ export async function keyPair() {
38
+ return new Promise((resolve, reject) => {
39
+ generateKeyPair("rsa", {
40
+ modulusLength: 2048,
41
+ publicKeyEncoding: {
42
+ type: "spki",
43
+ format: "pem",
44
+ },
45
+ privateKeyEncoding: {
46
+ type: "pkcs8",
47
+ format: "pem",
48
+ },
49
+ }, (err, publicKey, privateKey) => {
50
+ if (err == null) {
51
+ resolve([publicKey, privateKey]);
52
+ }
53
+ else {
54
+ reject(err);
55
+ }
56
+ });
57
+ });
58
+ }
59
+ /**
60
+ * AES 加密
61
+ * @param key 加密密钥
62
+ * @param input 待加密的数据
63
+ * @param upper 是否转换为大写
64
+ * @returns [加密数据, 向量]
65
+ */
66
+ export function aesEncrypt(key, input, upper = false) {
67
+ const iv = randomBytes(16);
68
+ const cipher = createCipheriv("aes-256-cbc", Buffer.from(key, "hex"), iv);
69
+ let encryptedData = cipher.update(input, "utf-8", "hex");
70
+ encryptedData += cipher.final("hex");
71
+ return [
72
+ upper === true ? encryptedData.toUpperCase() : encryptedData,
73
+ iv.toString("hex"),
74
+ ];
75
+ }
76
+ function aesAlgorithm(key) {
77
+ if (key.startsWith("aes-"))
78
+ return key;
79
+ let prefix = "aes-";
80
+ // 如果 key 不是以数字开头,则加上数字,例如:128,256 等
81
+ if (!/^\d/.test(key)) {
82
+ prefix += "256-";
83
+ }
84
+ return `${prefix}${key}`;
85
+ }
86
+ /**
87
+ * AES 解密
88
+ * @param input 加密后的数据
89
+ * @param key 密钥
90
+ * @param iv 向量
91
+ * @returns
92
+ */
93
+ export function aesDecrypt(input, key, iv, algorithm = "aes-256-cbc") {
94
+ let ivBuffer = null;
95
+ if (iv && !Buffer.isBuffer(iv)) {
96
+ ivBuffer = Buffer.from(iv, "hex");
97
+ }
98
+ let keyBuffer;
99
+ if (Buffer.isBuffer(key)) {
100
+ keyBuffer = key;
101
+ }
102
+ else {
103
+ keyBuffer = Buffer.from(key, "hex");
104
+ }
105
+ const cipher = createDecipheriv(aesAlgorithm(algorithm), keyBuffer, ivBuffer);
106
+ let decryptedData = cipher.update(input, "hex", "utf-8");
107
+ decryptedData += cipher.final("utf-8");
108
+ return decryptedData;
109
+ }
110
+ /**
111
+ * RSA 公钥加密
112
+ * @param input 待加密字符串
113
+ * @param publicKey 公钥
114
+ * @returns
115
+ */
116
+ export function rsaEncrypt(input, publicKey) {
117
+ return publicEncrypt({
118
+ key: publicKey,
119
+ oaepHash: "sha256",
120
+ }, Buffer.from(input)).toString("base64");
121
+ }
122
+ /**
123
+ * RSA 解密
124
+ * @param encrtypData RSA加密后的数据
125
+ * @param privateKey 私钥
126
+ * @returns
127
+ */
128
+ export function rsaDecrypt(encrtypData, privateKey) {
129
+ return privateDecrypt({
130
+ key: privateKey,
131
+ oaepHash: "sha256",
132
+ }, Buffer.from(encrtypData, "base64")).toString("utf-8");
133
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 将日期格式化为指定形式的字符串
3
+ * @param date 日期
4
+ * @param pattern 格式化字符串 yyyy - 年, mm - 月, dd - 日, HH - 小时(24时制), MM - 分钟, ss - 秒, S - 毫秒, 默认: yyyy-mm-dd HH:MM:ss
5
+ */
6
+ export declare function format(date?: Date | string | number | null, pattern?: string): string;
7
+ /**
8
+ * 将指定的参数解析为日期对象(Date)
9
+ * 参考 dayjs 实现, 也可以参考 https://github.com/nomiddlename/date-format
10
+ * @param date 待解析的日期参数
11
+ */
12
+ export declare function parse(date?: Date | string | number | null): Date;
13
+ /**
14
+ * 设置日期的开始或者结束的点
15
+ * @param date 日期,能够被 parse 解析的日期
16
+ * @param unit 单位,Date[D]、Minute[M], 默认为 Date
17
+ * @param isEnd true则为 endOf
18
+ */
19
+ export declare function dateOf(date?: Date | string | number | null, unit?: string, isEnd?: boolean): Date;
20
+ /**
21
+ * 设置日期的开始的点
22
+ * @param date 日期,能够被 parse 解析的日期
23
+ * @param unit 单位,Date[D]、Minute[M], 默认为 Date
24
+ * @returns
25
+ */
26
+ export declare function startOf(date?: Date | string | number | null, unit?: string): Date;
27
+ /**
28
+ * 设置日期的结束点
29
+ * @param date 日期,能够被 parse 解析的日期
30
+ * @param unit 单位,Date[D]、Minute[M], 默认为 Date
31
+ * @returns
32
+ */
33
+ export declare function endOf(date?: Date | string | number | null, unit?: string): Date;
34
+ /**
35
+ * 获取时间戳
36
+ * @param ctime 时间
37
+ * @param pre 精度, s - 精确到秒, ms - 精确到毫秒, 默认: s
38
+ * @returns
39
+ */
40
+ export declare function timestamp(ctime?: Date | string | number, pre?: "s" | "ms"): number;
41
+ /**
42
+ * 日期加上指定时间后的日期
43
+ * @param date 指定的日期
44
+ * @param num 需要添加的数字, 如果这个参数传递一个小于0的数字,则就是日期减去相应的数字
45
+ * @param unit 需要添加的单位,date、month、year、hours、minute、second
46
+ *
47
+ * 查阅文档: {@link https://gitee.com/towardly/ph/wikis/utils/date ph-utils}
48
+ *
49
+ * @example <caption>1. 分钟加1并格式化显示时间</caption>
50
+ *
51
+ * add(new Date(), 1, 'minute', 'HHMMss')
52
+ */
53
+ export declare function add(date: Date | string | number | null, num: number, unit: string): Date;
54
+ /**
55
+ * 日期加上指定时间后的日期
56
+ * @param date 指定的日期, 传递为 null ,则表示为当前日期
57
+ * @param num 需要添加的数字, 如果这个参数传递一个小于0的数字,则就是日期减去相应的数字
58
+ * @param unit 需要添加的单位,date - 加减天数
59
+ * @param fmt 如果传递了格式化的单位,则返回格式化后的日期, 格式化字符串 yyyy - 年, mm - 月, dd - 日, HH - 小时, MM - 分钟, ss - 秒
60
+ *
61
+ * #### 1. 前一天的日期字符串形式
62
+ * ```javascript
63
+ * add(new Date(), -1, 'Date', 'yyyy-mm-dd')
64
+ * ```
65
+ */
66
+ export declare function add(date: Date | string | number | null, num: number, unit: string, fmt: string): string;