/**
 * Mac 登录失败监控 & 自动封禁脚本
 * 检测 SSH/登录失败，同一 IP 失败 5 次自动封禁
 */

const { spawn } = require('child_process');
const https = require('https');
const fs = require('fs');

// ========== 配置 ==========
const CONFIG = {
  maxFailures: 5,
  banDurationMin: 60,
  tgBotToken: '8300905342:AAH3Q78FuR5Exrw2zWYJHFRyVeLlws3xnww',
  tgChatId: '165067365',
  dataFile: '/Users/jianzhang/.openclaw/workspace/scripts/ban-data.json',
  whitelistIPs: ['127.0.0.1', '192.168.1.1']
};

let failedAttempts = {};
let bannedIPs = {};

// ========== Telegram 通知 ==========
function sendTG(message) {
  const data = JSON.stringify({ chat_id: CONFIG.tgChatId, text: message, parse_mode: 'HTML' });
  const req = https.request({
    hostname: 'api.telegram.org',
    path: `/bot${CONFIG.tgBotToken}/sendMessage`,
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  });
  req.write(data);
  req.end();
}

// ========== 数据持久化 ==========
function saveData() {
  fs.writeFileSync(CONFIG.dataFile, JSON.stringify({ failedAttempts, bannedIPs }, null, 2));
}

function loadData() {
  try {
    if (fs.existsSync(CONFIG.dataFile)) {
      const d = JSON.parse(fs.readFileSync(CONFIG.dataFile, 'utf8'));
      failedAttempts = d.failedAttempts || {};
      bannedIPs = d.bannedIPs || {};
    }
  } catch (e) {}
}

// ========== 封禁/解封 IP ==========
function banIP(ip) {
  if (CONFIG.whitelistIPs.includes(ip) || bannedIPs[ip]) return;
  console.log(`[BAN] ${ip}`);
  bannedIPs[ip] = Date.now();
  
  spawn('sudo', ['pfctl', '-t', 'bruteforce', '-T', 'add', ip]).on('close', (code) => {
    if (code === 0) {
      sendTG(`🚫 <b>IP 已封禁</b>\n\nIP: <code>${ip}</code>\n原因: 登录失败 ${CONFIG.maxFailures} 次\n时长: ${CONFIG.banDurationMin} 分钟`);
    }
  });
  
  setTimeout(() => unbanIP(ip), CONFIG.banDurationMin * 60 * 1000);
  saveData();
}

function unbanIP(ip) {
  if (!bannedIPs[ip]) return;
  console.log(`[UNBAN] ${ip}`);
  delete bannedIPs[ip];
  delete failedAttempts[ip];
  spawn('sudo', ['pfctl', '-t', 'bruteforce', '-T', 'delete', ip]);
  saveData();
}

// ========== 记录失败 ==========
function recordFailure(ip) {
  if (CONFIG.whitelistIPs.includes(ip) || bannedIPs[ip]) return;
  if (!failedAttempts[ip]) failedAttempts[ip] = { count: 0, firstTime: Date.now() };
  failedAttempts[ip].count++;
  console.log(`[FAIL] ${ip} x${failedAttempts[ip].count}`);
  if (failedAttempts[ip].count >= CONFIG.maxFailures) banIP(ip);
  saveData();
}

// ========== 解析日志 ==========
function parseLine(line) {
  let m = line.match(/Failed password for .* from ([\d.]+)/);
  if (m) return m[1];
  m = line.match(/Invalid user .* from ([\d.]+)/);
  if (m) return m[1];
  m = line.match(/authentication failure.*rhost=([\d.]+)/);
  if (m) return m[1];
  return null;
}

// ========== 启动监控 ==========
function start() {
  console.log('[START] Mac Guard 启动');
  loadData();
  
  const log = spawn('log', ['stream', '--predicate', 'process == "sshd"', '--style', 'syslog']);
  log.stdout.on('data', (d) => {
    d.toString().split('\n').forEach(line => {
      const ip = parseLine(line);
      if (ip) recordFailure(ip);
    });
  });
  log.on('close', () => { console.log('[RESTART]'); setTimeout(start, 5000); });
}

start();
