/**
 * 安全中间件
 * 包含：XSS 防护、SQL 注入防护、敏感数据脱敏
 */

// XSS 防护
export function xssProtection() {
  return async (ctx: any, next: any) => {
    // 过滤请求体中的 XSS
    if (ctx.request.body && typeof ctx.request.body === 'object') {
      sanitizeObject(ctx.request.body);
    }

    // 过滤查询参数中的 XSS
    if (ctx.request.query && typeof ctx.request.query === 'object') {
      sanitizeObject(ctx.request.query);
    }

    // 设置安全响应头
    ctx.set('X-XSS-Protection', '1; mode=block');
    ctx.set('X-Content-Type-Options', 'nosniff');
    ctx.set('X-Frame-Options', 'DENY');
    ctx.set('Content-Security-Policy', "default-src 'self'");

    await next();
  };
}

/**
 * 递归清理对象中的 XSS
 */
function sanitizeObject(obj: any): void {
  for (const key in obj) {
    if (typeof obj[key] === 'string') {
      obj[key] = sanitizeString(obj[key]);
    } else if (typeof obj[key] === 'object' && obj[key] !== null) {
      sanitizeObject(obj[key]);
    }
  }
}

/**
 * 清理字符串中的 XSS 攻击代码
 */
function sanitizeString(str: string): string {
  return str
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#x27;')
    .replace(/\//g, '&#x2F;')
    .replace(/javascript:/gi, '')
    .replace(/on\w+=/gi, '')
    .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
    .replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi, '')
    .replace(/<object[^>]*>[\s\S]*?<\/object>/gi, '')
    .replace(/<embed[^>]*>[\s\S]*?<\/embed>/gi, '');
}

// SQL 注入防护
export function sqlInjectionProtection() {
  return async (ctx: any, next: any) => {
    // 检查请求参数
    const params = {
      ...ctx.request.query,
      ...(ctx.request.body || {}),
    };

    for (const key in params) {
      if (typeof params[key] === 'string') {
        if (detectSQLInjection(params[key])) {
          ctx.status = 400;
          ctx.body = {
            code: 400,
            message: '请求包含非法字符',
          };
          return;
        }
      }
    }

    await next();
  };
}

/**
 * 检测 SQL 注入
 */
function detectSQLInjection(str: string): boolean {
  const sqlPatterns = [
    /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE)\b)/i,
    /(--|;|\/\*|\*\/|@@|@)/,
    /(\b(OR|AND)\b\s+\d+=\d+)/i,
    /(\bUNION\b\s+\bSELECT\b)/i,
    /(\bWAITFOR\b\s+\bDELAY\b)/i,
    /(\bBENCHMARK\b)/i,
    /(SLEEP\()/i,
    /('|\")\s*(OR|AND)\s*('|\")/,
  ];

  return sqlPatterns.some(pattern => pattern.test(str));
}

// 敏感数据脱敏
export function sensitiveDataMasking() {
  return async (ctx: any, next: any) => {
    await next();

    // 脱敏响应中的敏感数据
    if (ctx.body && typeof ctx.body === 'object') {
      maskSensitiveData(ctx.body);
    }
  };
}

/**
 * 脱敏敏感数据
 */
function maskSensitiveData(obj: any): void {
  const sensitiveKeys = ['password', 'token', 'secret', 'key', 'cookie', 'authorization'];

  for (const key in obj) {
    if (sensitiveKeys.includes(key.toLowerCase())) {
      if (typeof obj[key] === 'string' && obj[key].length > 8) {
        obj[key] = obj[key].substring(0, 4) + '****' + obj[key].substring(obj[key].length - 4);
      } else {
        obj[key] = '****';
      }
    } else if (typeof obj[key] === 'object' && obj[key] !== null) {
      maskSensitiveData(obj[key]);
    }
  }
}

// 密码加密工具
export function maskPassword(password: string): string {
  if (!password || password.length < 8) return '****';
  return password.substring(0, 2) + '****' + password.substring(password.length - 2);
}

// 手机号脱敏
export function maskPhone(phone: string): string {
  if (!phone || phone.length !== 11) return phone;
  return phone.substring(0, 3) + '****' + phone.substring(7);
}

// 邮箱脱敏
export function maskEmail(email: string): string {
  if (!email || !email.includes('@')) return email;
  const [name, domain] = email.split('@');
  if (name.length <= 2) return `**@${domain}`;
  return name.substring(0, 2) + '****' + '@' + domain;
}
