@@ -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
0 commit comments