init
This commit is contained in:
83
src/security.ts
Normal file
83
src/security.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
// src/security.ts
|
||||
import { Elysia, Context } from 'elysia';
|
||||
|
||||
// 脱敏规则配置
|
||||
const MASK_RULES: Record<string, (value: string) => string> = {
|
||||
// 手机号:138****1234
|
||||
mobile: (v) => v.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'),
|
||||
phone: (v) => v.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'),
|
||||
|
||||
// 邮箱:ab***@example.com
|
||||
email: (v) => v.replace(/(.{2}).+(@.*)/, '$1***$2'),
|
||||
|
||||
// 身份证:110***********1234
|
||||
id_card: (v) => v.length > 8
|
||||
? v.substring(0, 3) + '*'.repeat(v.length - 7) + v.substring(v.length - 4)
|
||||
: v,
|
||||
|
||||
// 银行卡:6222 **** **** 1234
|
||||
bank_card: (v) => v.replace(/(\d{4})\d+(\d{4})/, '$1 **** **** $2'),
|
||||
|
||||
// 用户名:如果长度>4,则中间用*
|
||||
nickname: (v) => v.length > 4
|
||||
? v.substring(0, 2) + '*'.repeat(v.length - 4) + v.substring(v.length - 2)
|
||||
: v,
|
||||
|
||||
// 默认规则
|
||||
default: (v) => v.length > 6
|
||||
? v.substring(0, 2) + '*'.repeat(v.length - 4) + v.substring(v.length - 2)
|
||||
: v
|
||||
};
|
||||
|
||||
// 判断是否为敏感字段(支持模糊匹配)
|
||||
const isSensitiveField = (key: string): boolean => {
|
||||
const sensitiveKeys = ['mobile', 'phone', 'email', 'id_card', 'bank_card', 'nickname', 'realname', 'address'];
|
||||
return sensitiveKeys.some(term => key.toLowerCase().includes(term));
|
||||
};
|
||||
|
||||
// 获取脱敏函数
|
||||
const getMaskFn = (key: string): ((v: string) => string) => {
|
||||
for (const [term, fn] of Object.entries(MASK_RULES)) {
|
||||
if (key.toLowerCase().includes(term)) {
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
return MASK_RULES.default || ((v: string) => v);
|
||||
};
|
||||
|
||||
// 递归脱敏
|
||||
export const sanitizeResult = (data: any): any => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(sanitizeResult);
|
||||
}
|
||||
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
const result: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
if (value == null) {
|
||||
result[key] = value;
|
||||
} else if (isSensitiveField(key)) {
|
||||
result[key] = typeof value === 'string' ? getMaskFn(key)(value) : value;
|
||||
} else if (typeof value === 'object') {
|
||||
result[key] = sanitizeResult(value);
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
// API Key 验证(修复:使用 Elysia 插件类型)
|
||||
export const verifyApiKey = (app: Elysia) => app.onBeforeHandle((ctx) => {
|
||||
const authHeader = ctx.request.headers.get('authorization');
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
const token = authHeader.substring(7);
|
||||
if (token !== process.env.ADMIN_API_KEY) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user