// src/security.ts import { Elysia, Context } from 'elysia'; // 脱敏规则配置 const MASK_RULES: Record 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 = {}; 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 }); } });