Skip to content

Commit 117f559

Browse files
committed
Reapply "✨ feat: 增加脱敏函数(desensitize), 支持邮箱,银行卡号,姓名"
This reverts commit 737c0af.
1 parent c0b167a commit 117f559

File tree

5 files changed

+144
-32
lines changed

5 files changed

+144
-32
lines changed

.husky/pre-commit

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
export NVM_DIR="$HOME/.nvm"
3+
4+
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
5+
6+
# npx lint-staged

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,44 @@ if (err) {
245245
}
246246
```
247247
248-
### 2. desensitize(value: string, type: "mobile" | "idcard"): string
248+
### 2. desensitize(value: string, type: "mobile" | "idcard" | "email" | "bankcard" | "name"): string
249249
**功能描述**:对敏感信息(手机号或身份证号)进行脱敏处理,隐藏中间部分。
250250
251251
**参数**
252252
- `value: string` — 原始字符串,如手机号或身份证号。
253-
- `type: "mobile" | "idcard"` — 数据类型,"mobile" 脱敏手机号,"idcard" 脱敏身份证号。
253+
- `type: "mobile" | "idcard" | "email" | "bankcard" | "name"`
254+
- 默认保留首尾,中间脱敏部分
255+
- `"mobile"`:脱敏手机号
256+
- `"idcard"`:脱敏身份证号
257+
- `"email"`:脱敏电子邮箱
258+
- `"bankcard"`:脱敏银行卡号
259+
- `"name"`:脱敏姓名
254260
255261
**返回值**
256-
string — 脱敏后字符串,如果输入非字符串则返回空字符串。
262+
`string` — 脱敏后字符串,如果输入非字符串则返回空字符串。
257263
258264
- 示例
259265
```typescript
260266
import { desensitize } from 'ui-utils-kit';
261267
262-
console.log(desensitize('13812345678', 'mobile')); // 输出:138****5678
263-
console.log(desensitize('110105199001011234', 'idcard')); // 输出:110105********1234
268+
desensitize('13812345678', 'mobile'); // 输出:138****5678
269+
desensitize('110105199001011234', 'idcard'); // 输出:110105********1234
270+
271+
desensitize("ethan.yin@openai.com", "email"); // => "e*********@openai.com"
272+
desensitize("a@domain.cn", "email"); // => "a@domain.cn" // 本地部分仅一个字符,无需替换
273+
274+
desensitize("6227001234567890", "bankcard"); // => "**** **** **** 7890"
275+
desensitize("6227 0012 3456 7890", "bankcard"); // => "**** **** **** 7890"
276+
277+
desensitize("张三", "name"); // => "张*"
278+
desensitize("张三丰", "name"); // => "张*丰"
279+
280+
// 英文名(按单词脱敏)
281+
// - “John Doe” => “J**n D*e”
282+
// - “Al Li” => “A* L*”
283+
(desensitize("John Doe", "name"); // 输出: J**n D*e
284+
desensitize("Al Li", "name"); // 输出: A* L*
285+
264286
```
265287
266288
### 3. Mutex 类

packages/core/README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,44 @@ if (err) {
245245
}
246246
```
247247
248-
### 2. desensitize(value: string, type: "mobile" | "idcard"): string
248+
### 2. desensitize(value: string, type: "mobile" | "idcard" | "email" | "bankcard" | "name"): string
249249
**功能描述**:对敏感信息(手机号或身份证号)进行脱敏处理,隐藏中间部分。
250250
251251
**参数**
252252
- `value: string` — 原始字符串,如手机号或身份证号。
253-
- `type: "mobile" | "idcard"` — 数据类型,"mobile" 脱敏手机号,"idcard" 脱敏身份证号。
253+
- `type: "mobile" | "idcard" | "email" | "bankcard" | "name"`
254+
- 默认保留首尾,中间脱敏部分
255+
- `"mobile"`:脱敏手机号
256+
- `"idcard"`:脱敏身份证号
257+
- `"email"`:脱敏电子邮箱
258+
- `"bankcard"`:脱敏银行卡号
259+
- `"name"`:脱敏姓名
254260
255261
**返回值**
256-
string — 脱敏后字符串,如果输入非字符串则返回空字符串。
262+
`string` — 脱敏后字符串,如果输入非字符串则返回空字符串。
257263
258264
- 示例
259265
```typescript
260266
import { desensitize } from 'ui-utils-kit';
261267
262-
console.log(desensitize('13812345678', 'mobile')); // 输出:138****5678
263-
console.log(desensitize('110105199001011234', 'idcard')); // 输出:110105********1234
268+
desensitize('13812345678', 'mobile'); // 输出:138****5678
269+
desensitize('110105199001011234', 'idcard'); // 输出:110105********1234
270+
271+
desensitize("ethan.yin@openai.com", "email"); // => "e*********@openai.com"
272+
desensitize("a@domain.cn", "email"); // => "a@domain.cn" // 本地部分仅一个字符,无需替换
273+
274+
desensitize("6227001234567890", "bankcard"); // => "**** **** **** 7890"
275+
desensitize("6227 0012 3456 7890", "bankcard"); // => "**** **** **** 7890"
276+
277+
desensitize("张三", "name"); // => "张*"
278+
desensitize("张三丰", "name"); // => "张*丰"
279+
280+
// 英文名(按单词脱敏)
281+
// - “John Doe” => “J**n D*e”
282+
// - “Al Li” => “A* L*”
283+
(desensitize("John Doe", "name"); // 输出: J**n D*e
284+
desensitize("Al Li", "name"); // 输出: A* L*
285+
264286
```
265287
266288
### 3. Mutex 类

packages/core/src/common.ts

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,74 @@ export function safeJsonParse<T>(jsonString: string, defaultValue: T): [Error |
2626

2727

2828
/**
29-
* 对敏感信息进行脱敏处理
29+
* 数据脱敏函数
3030
*
31-
* @param value - 原始字符串(如手机号、身份证号)
32-
* @param type - 数据类型,可选值为 "mobile"(手机号)或 "idcard"(身份证号)
33-
* @returns 脱敏后的字符串
31+
* @param value - 原始数据
32+
* @param type - 脱敏类型
33+
* @returns 脱敏后的数据
3434
*/
35-
export function desensitize(value: string, type: "mobile" | "idcard"): string {
35+
export function desensitize(
36+
value: string,
37+
type: "mobile" | "idcard" | "email" | "bankcard" | "name"
38+
): string {
3639
if (typeof value !== "string") {
37-
return "";
40+
return value;
3841
}
3942

4043
switch (type) {
4144
case "mobile":
42-
// 手机号脱敏:保留前3位和后4位,中间4位替换为星号
43-
// 示例:13812345678 => 138****5678
44-
return value.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2");
45+
// 手机号:前三位、后四位保留
46+
return value.replace(/^(1[3-9]\d)(\d{4})(\d{4})$/, (_, p1, _p2, p3) => `${p1}****${p3}`);
4547

4648
case "idcard":
47-
// 身份证号脱敏:保留前6位和后4位,中间位数替换为星号
48-
// 示例:110105199001011234 => 110105********1234
49-
return value.replace(/^(\d{6})\d+(\d{4})$/, (_, p1, p2) => {
50-
const middleLength = value.length - p1.length - p2.length;
51-
const masked = "*".repeat(middleLength);
52-
return `${p1}${masked}${p2}`;
53-
});
49+
// 身份证号:前6位、后4位保留
50+
return value.replace(/^(.{6})\d+(.{4})$/, (_, p1, p2) => `${p1}******${p2}`);
51+
52+
case "email":
53+
// 邮箱:保留首字母与域名(避免 ReDoS,使用 [^@] 代替 .)
54+
return value.replace(/^(.)([^@]*)(@[^@]+)$/, (_, first: string, middle: string, domain: string) =>
55+
`${first}${middle.replace(/./g, "*")}${domain}`);
56+
57+
case "bankcard":
58+
// 银行卡:仅保留后4位
59+
return value
60+
.replace(/\s+/g, "")
61+
.replace(/.(?=.{4})/g, "*")
62+
.replace(/(.{4})/g, "$1 ")
63+
.trim();
64+
65+
case "name":
66+
if (/[\u4E00-\u9FA5]/.test(value)) {
67+
const len = value.length;
68+
if (len === 2) {
69+
return `${value[0]}*`;
70+
} else if (len >= 3) {
71+
return value[0] + "*".repeat(len - 2) + value[len - 1];
72+
} else {
73+
return "*";
74+
}
75+
} else {
76+
// 英文名脱敏:按单词拆分,每段:
77+
// - 长度 >=3:保留首尾,中间 *
78+
// - 长度 ==2:保留首位,末位 *
79+
// - 长度 ==1:替换为 *
80+
return value.split(" ").map((part) => {
81+
const len = part.length;
82+
if (len >= 3) {
83+
return part[0] + "*".repeat(len - 2) + part[len - 1];
84+
} else if (len === 2) {
85+
return `${part[0]}*`;
86+
} else if (len === 1) {
87+
return "*";
88+
}
89+
return part;
90+
}).join(" ");
91+
}
5492

5593
default:
56-
return value;
94+
// 默认:保留首尾字符
95+
return value.replace(/^(.)(.*)(.)$/, (_, first: string, middle: string, last: string) =>
96+
`${first}${middle.replace(/./g, "*")}${last}`);
5797
}
5898
}
5999

playground/README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,44 @@ if (err) {
245245
}
246246
```
247247
248-
### 2. desensitize(value: string, type: "mobile" | "idcard"): string
248+
### 2. desensitize(value: string, type: "mobile" | "idcard" | "email" | "bankcard" | "name"): string
249249
**功能描述**:对敏感信息(手机号或身份证号)进行脱敏处理,隐藏中间部分。
250250
251251
**参数**
252252
- `value: string` — 原始字符串,如手机号或身份证号。
253-
- `type: "mobile" | "idcard"` — 数据类型,"mobile" 脱敏手机号,"idcard" 脱敏身份证号。
253+
- `type: "mobile" | "idcard" | "email" | "bankcard" | "name"`
254+
- 默认保留首尾,中间脱敏部分
255+
- `"mobile"`:脱敏手机号
256+
- `"idcard"`:脱敏身份证号
257+
- `"email"`:脱敏电子邮箱
258+
- `"bankcard"`:脱敏银行卡号
259+
- `"name"`:脱敏姓名
254260
255261
**返回值**
256-
string — 脱敏后字符串,如果输入非字符串则返回空字符串。
262+
`string` — 脱敏后字符串,如果输入非字符串则返回空字符串。
257263
258264
- 示例
259265
```typescript
260266
import { desensitize } from 'ui-utils-kit';
261267
262-
console.log(desensitize('13812345678', 'mobile')); // 输出:138****5678
263-
console.log(desensitize('110105199001011234', 'idcard')); // 输出:110105********1234
268+
desensitize('13812345678', 'mobile'); // 输出:138****5678
269+
desensitize('110105199001011234', 'idcard'); // 输出:110105********1234
270+
271+
desensitize("ethan.yin@openai.com", "email"); // => "e*********@openai.com"
272+
desensitize("a@domain.cn", "email"); // => "a@domain.cn" // 本地部分仅一个字符,无需替换
273+
274+
desensitize("6227001234567890", "bankcard"); // => "**** **** **** 7890"
275+
desensitize("6227 0012 3456 7890", "bankcard"); // => "**** **** **** 7890"
276+
277+
desensitize("张三", "name"); // => "张*"
278+
desensitize("张三丰", "name"); // => "张*丰"
279+
280+
// 英文名(按单词脱敏)
281+
// - “John Doe” => “J**n D*e”
282+
// - “Al Li” => “A* L*”
283+
(desensitize("John Doe", "name"); // 输出: J**n D*e
284+
desensitize("Al Li", "name"); // 输出: A* L*
285+
264286
```
265287
266288
### 3. Mutex 类

0 commit comments

Comments
 (0)