#!/usr/bin/env python3
"""
alfred-server-onboard — Sovereign Server AI IDE SSH Root Pairing Daemon
Runs temporarily on port 7722 on first boot of an Alfred Linux server.
Protects against bots/hackers with:
  1. Setup Password verification (checks any user created during install or /etc/alfred/setup_pass)
  2. 9-digit console PIN (printed strictly to /dev/tty1 & /dev/console)
  3. 1-strike instant iptables/nftables ban for unauthorized scan attempts
  4. Instant self-destruction and port closure upon successful key delivery
Universal support for macOS (.command), Linux (.sh), and Windows (.bat).
Auto-launches Cursor, Antigravity, Windsurf, or VS Code.
"""
import os, sys, subprocess, secrets, socket, threading, time, http.server, urllib.parse

PORT = 7722
CLAIM_MARKER = "/root/.ssh/user_claimed"
KEY_PATH = "/root/.ssh/user_root_ed25519"
AUTH_KEYS = "/root/.ssh/authorized_keys"
PIN_FILE = "/run/alfred_onboard_pin"

def get_server_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("1.1.1.1", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception:
        return "127.0.0.1"

def ensure_root_key():
    os.makedirs("/root/.ssh", mode=0o700, exist_ok=True)
    if not os.path.exists(KEY_PATH):
        subprocess.run([
            "ssh-keygen", "-t", "ed25519", "-f", KEY_PATH, "-N", "",
            "-C", "alfred-server-root-owner"
        ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        os.chmod(KEY_PATH, 0o600)
    
    pub_key_path = KEY_PATH + ".pub"
    if os.path.exists(pub_key_path):
        with open(pub_key_path) as f:
            pub_data = f.read().strip()
        
        existing_keys = ""
        if os.path.exists(AUTH_KEYS):
            with open(AUTH_KEYS) as f:
                existing_keys = f.read()
        
        if pub_data not in existing_keys:
            with open(AUTH_KEYS, "a") as f:
                f.write("\n" + pub_data + "\n")
            os.chmod(AUTH_KEYS, 0o600)

    sshd_dropin = "/etc/ssh/sshd_config.d/99-alfred-root-login.conf"
    try:
        os.makedirs("/etc/ssh/sshd_config.d", exist_ok=True)
        if not os.path.exists(sshd_dropin):
            with open(sshd_dropin, "w") as f:
                f.write("PermitRootLogin prohibit-password\nPubkeyAuthentication yes\n")
            subprocess.run(["systemctl", "reload", "ssh"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            subprocess.run(["systemctl", "reload", "sshd"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    except Exception:
        pass

def verify_system_password(password_attempt):
    if not password_attempt:
        return False

    if os.path.exists("/etc/alfred/setup_pass"):
        try:
            with open("/etc/alfred/setup_pass") as f:
                expected = f.read().strip()
            if password_attempt == expected:
                return True
        except Exception:
            pass
    
    try:
        import ctypes, ctypes.util
        libcrypt = ctypes.CDLL(ctypes.util.find_library("crypt") or "libcrypt.so.1")
        libcrypt.crypt.restype = ctypes.c_char_p
        libcrypt.crypt.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
        
        target_hashes = []
        if os.path.exists("/etc/shadow"):
            with open("/etc/shadow") as f:
                for line in f:
                    parts = line.strip().split(":")
                    if len(parts) > 1 and "$" in parts[1]:
                        target_hashes.append(parts[1])
        
        for h in target_hashes:
            res = libcrypt.crypt(password_attempt.encode("utf-8"), h.encode("utf-8"))
            if res and res.decode("utf-8") == h:
                return True
    except Exception:
        pass
    
    return False

def drop_attacker_ip(ip):
    if ip in ("127.0.0.1", "::1"):
        return
    try:
        subprocess.run(["iptables", "-I", "INPUT", "-s", ip, "-j", "DROP"], stderr=subprocess.DEVNULL)
    except Exception:
        pass

def generate_connect_script(os_type, server_ip, private_key):
    if os_type == "windows":
        key_lines = "\n".join([f"echo {line}>> \"%KEYFILE%\"" for line in private_key.splitlines()])
        return f"""@echo off
setlocal enabledelayedexpansion
title Alfred Linux Server - AI IDE Connect

echo ========================================================
echo   [ALFRED LINUX] SOVEREIGN SERVER AI IDE CONNECT
echo ========================================================
echo.

set SSHDIR=%USERPROFILE%\\.ssh
if not exist "%SSHDIR%" mkdir "%SSHDIR%"

set KEYFILE=%SSHDIR%\\alfred_server_root.key
if exist "%KEYFILE%" del "%KEYFILE%"

{key_lines}

icacls "%KEYFILE%" /inheritance:r >nul 2>&1
icacls "%KEYFILE%" /grant:r "%USERNAME%":F >nul 2>&1

set CONFIGFILE=%SSHDIR%\\config
findstr /i "Host alfred-server" "%CONFIGFILE%" >nul 2>&1
if %ERRORLEVEL% NEQ 0 (
    echo.>> "%CONFIGFILE%"
    echo Host alfred-server>> "%CONFIGFILE%"
    echo     HostName {server_ip}>> "%CONFIGFILE%"
    echo     User root>> "%CONFIGFILE%"
    echo     IdentityFile "%KEYFILE%">> "%CONFIGFILE%"
    echo     StrictHostKeyChecking accept-new>> "%CONFIGFILE%"
)

echo [OK] SSH Configuration installed to %CONFIGFILE%
echo [OK] Private Root key secured in %KEYFILE%
echo.
echo Launching your Sovereign AI IDE into root@{server_ip}...

where cursor >nul 2>&1
if %ERRORLEVEL% EQU 0 (
    echo Opening in Cursor...
    cursor --remote ssh-remote+alfred-server /root
    pause
    exit /b 0
)

where antigravity >nul 2>&1
if %ERRORLEVEL% EQU 0 (
    echo Opening in Google Antigravity...
    antigravity --remote ssh-remote+alfred-server /root
    pause
    exit /b 0
)

where windsurf >nul 2>&1
if %ERRORLEVEL% EQU 0 (
    echo Opening in Windsurf...
    windsurf --remote ssh-remote+alfred-server /root
    pause
    exit /b 0
)

where code >nul 2>&1
if %ERRORLEVEL% EQU 0 (
    echo Opening in VS Code...
    code --remote ssh-remote+alfred-server /root
    pause
    exit /b 0
)

echo.
echo [NOTE] No IDE CLI found in system PATH.
echo You can connect manually from any terminal or IDE:
echo    ssh alfred-server
echo.
pause
"""
    elif os_type == "mac":
        return f"""#!/bin/bash
clear
echo "========================================================"
echo "  [ALFRED LINUX] SOVEREIGN SERVER AI IDE CONNECT"
echo "========================================================"
echo ""

SSHDIR="$HOME/.ssh"
mkdir -p "$SSHDIR"
chmod 700 "$SSHDIR"

KEYFILE="$SSHDIR/alfred_server_root.key"
cat << 'EOF' > "$KEYFILE"
{private_key.strip()}
EOF
chmod 600 "$KEYFILE"

CONFIGFILE="$SSHDIR/config"
touch "$CONFIGFILE"
if ! grep -q "Host alfred-server" "$CONFIGFILE"; then
    cat << EOF >> "$CONFIGFILE"

Host alfred-server
    HostName {server_ip}
    User root
    IdentityFile "$KEYFILE"
    StrictHostKeyChecking accept-new
EOF
fi

echo "[OK] SSH Configuration installed to $CONFIGFILE"
echo "[OK] Private Root key secured in $KEYFILE"
echo ""
echo "Launching your Sovereign AI IDE into root@{server_ip}..."

if command -v cursor >/dev/null 2>&1; then
    echo "Opening in Cursor..."
    cursor --remote ssh-remote+alfred-server /root &
elif command -v antigravity >/dev/null 2>&1; then
    echo "Opening in Google Antigravity..."
    antigravity --remote ssh-remote+alfred-server /root &
elif command -v windsurf >/dev/null 2>&1; then
    echo "Opening in Windsurf..."
    windsurf --remote ssh-remote+alfred-server /root &
elif command -v code >/dev/null 2>&1; then
    echo "Opening in VS Code..."
    code --remote ssh-remote+alfred-server /root &
else
    echo ""
    echo "[NOTE] Connect manually from your terminal or AI IDE:"
    echo "   ssh alfred-server"
    echo ""
fi
exit 0
"""
    else:
        # Linux
        return f"""#!/bin/bash
clear
echo "========================================================"
echo "  [ALFRED LINUX] SOVEREIGN SERVER AI IDE CONNECT"
echo "========================================================"
echo ""

SSHDIR="$HOME/.ssh"
mkdir -p "$SSHDIR"
chmod 700 "$SSHDIR"

KEYFILE="$SSHDIR/alfred_server_root.key"
cat << 'EOF' > "$KEYFILE"
{private_key.strip()}
EOF
chmod 600 "$KEYFILE"

CONFIGFILE="$SSHDIR/config"
touch "$CONFIGFILE"
if ! grep -q "Host alfred-server" "$CONFIGFILE"; then
    cat << EOF >> "$CONFIGFILE"

Host alfred-server
    HostName {server_ip}
    User root
    IdentityFile "$KEYFILE"
    StrictHostKeyChecking accept-new
EOF
fi

echo "[OK] SSH Configuration installed to $CONFIGFILE"
echo "[OK] Private Root key secured in $KEYFILE"
echo ""
echo "Launching your Sovereign AI IDE into root@{server_ip}..."

if command -v cursor >/dev/null 2>&1; then
    echo "Opening in Cursor..."
    cursor --remote ssh-remote+alfred-server /root &
elif command -v antigravity >/dev/null 2>&1; then
    echo "Opening in Google Antigravity..."
    antigravity --remote ssh-remote+alfred-server /root &
elif command -v windsurf >/dev/null 2>&1; then
    echo "Opening in Windsurf..."
    windsurf --remote ssh-remote+alfred-server /root &
elif command -v code >/dev/null 2>&1; then
    echo "Opening in VS Code..."
    code --remote ssh-remote+alfred-server /root &
else
    echo ""
    echo "[NOTE] Connect manually from your terminal or AI IDE:"
    echo "   ssh alfred-server"
    echo ""
fi
exit 0
"""

class OnboardHandler(http.server.BaseHTTPRequestHandler):
    def log_message(self, format, *args):
        pass

    def do_GET(self):
        client_ip = self.client_address[0]
        if self.path not in ("/", "/index.html"):
            drop_attacker_ip(client_ip)
            self.send_response(404)
            self.end_headers()
            return

        html = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Alfred Linux Server — Root AI IDE Onboarding</title>
<style>
body {{
  background: #080b12;
  color: #e2e8f0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
}}
.card {{
  background: #111726;
  border: 1px solid #1e293b;
  border-radius: 12px;
  padding: 32px;
  max-width: 440px;
  width: 90%;
  box-shadow: 0 10px 25px rgba(0,0,0,0.5);
}}
.crest {{ text-align: center; font-size: 32px; margin-bottom: 8px; color: #d4af37; }}
h1 {{ font-size: 20px; margin: 0 0 8px 0; text-align: center; color: #f8fafc; }}
.sub {{ font-size: 13px; color: #94a3b8; text-align: center; margin-bottom: 24px; }}
.form-group {{ margin-bottom: 16px; }}
label {{ display: block; font-size: 12px; text-transform: uppercase; color: #00e5ff; margin-bottom: 6px; font-weight: bold; letter-spacing: 0.5px; }}
input {{
  width: 100%;
  padding: 10px 12px;
  background: #060910;
  border: 1px solid #26324b;
  border-radius: 6px;
  color: #fff;
  font-size: 14px;
  box-sizing: border-box;
}}
input:focus {{ border-color: #00e5ff; outline: none; }}
button {{
  width: 100%;
  padding: 12px;
  background: #d4af37;
  color: #080b12;
  font-size: 14px;
  font-weight: bold;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  margin-top: 10px;
}}
button:hover {{ background: #e6c55c; }}
.warn {{ font-size: 11px; color: #ef4444; margin-top: 16px; text-align: center; }}
</style>
</head>
<body>
<div class="card">
  <div class="crest">\\♛/</div>
  <h1>Alfred Linux Server</h1>
  <div class="sub">AI IDE Root SSH Pairing (Cursor, Antigravity, VS Code)</div>
  <form method="POST" action="/claim">
    <div class="form-group">
      <label>Server Setup Password:</label>
      <input type="password" name="password" required autofocus placeholder="Password set during install...">
    </div>
    <div class="form-group">
      <label>9-Digit Console PIN:</label>
      <input type="text" name="pin" required placeholder="Printed on server monitor...">
    </div>
    <button type="submit">🚀 Unlock & Download 1-Click Connect</button>
  </form>
  <div class="warn">DEFCON Armor: Unauthorized scan or wrong guess results in immediate IP ban.</div>
</div>
</body>
</html>
"""
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.end_headers()
        self.wfile.write(html.encode("utf-8"))

    def do_POST(self):
        client_ip = self.client_address[0]
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length).decode("utf-8")
        params = urllib.parse.parse_qs(body)
        
        pwd = params.get("password", [""])[0]
        pin = params.get("pin", [""])[0].replace("-", "").strip()

        with open(PIN_FILE) as f:
            expected_pin = f.read().strip().replace("-", "")

        pin_ok = (pin == expected_pin)
        pwd_ok = verify_system_password(pwd)

        if not (pin_ok and pwd_ok):
            print(f"[SECURITY] Attack detected from {client_ip} — Drop engaged.")
            drop_attacker_ip(client_ip)
            self.send_response(403)
            self.end_headers()
            self.wfile.write(b"Forbidden: Attack signature blocked.")
            return

        ua = self.headers.get("User-Agent", "").lower()
        if "mac" in ua or "darwin" in ua:
            os_type = "mac"
            filename = "connect-alfred.command"
            mime = "application/x-sh"
        elif "win" in ua:
            os_type = "windows"
            filename = "connect-alfred.bat"
            mime = "application/x-bat"
        else:
            os_type = "linux"
            filename = "connect-alfred.sh"
            mime = "application/x-sh"

        with open(KEY_PATH) as f:
            priv_key = f.read()

        server_ip = get_server_ip()
        script_body = generate_connect_script(os_type, server_ip, priv_key)

        self.send_response(200)
        self.send_header("Content-Type", mime)
        self.send_header("Content-Disposition", f'attachment; filename="{filename}"')
        self.end_headers()
        self.wfile.write(script_body.encode("utf-8"))

        print(f"[ONBOARD] Successfully delivered {filename} to {client_ip}. Self-destructing daemon...")
        
        with open(CLAIM_MARKER, "w") as f:
            f.write(f"Claimed by {client_ip} at {time.ctime()}\n")
        
        def kill_server():
            time.sleep(2)
            if os.path.exists(PIN_FILE):
                os.remove(PIN_FILE)
            sys.exit(0)
        
        threading.Thread(target=kill_server).start()

def main():
    if os.path.exists(CLAIM_MARKER):
        sys.exit(0)

    ensure_root_key()
    
    pin = f"{secrets.randbelow(900) + 100}-{secrets.randbelow(900) + 100}-{secrets.randbelow(900) + 100}"
    with open(PIN_FILE, "w") as f:
        f.write(pin)
    
    server_ip = get_server_ip()
    
    banner = f"""
========================================================================
\\♛/ ALFRED LINUX SOVEREIGN SERVER INITIALIZED
========================================================================
SSH Password Login is DISABLED for DEFCON Armor.

To connect your AI IDE (Cursor, Antigravity, VS Code, Windsurf) as root:
  1. Open in your computer browser:
     http://{server_ip}:{PORT}

  2. Enter your Server Setup Password + Console PIN:
     PIN: {pin}

  3. Double-click the downloaded 1-Click Connect file on your computer.
========================================================================
"""
    print(banner)
    for dev in ("/dev/tty1", "/dev/console"):
        try:
            with open(dev, "w") as f:
                f.write(banner)
        except Exception:
            pass

    server = http.server.HTTPServer(("0.0.0.0", PORT), OnboardHandler)
    server.serve_forever()

if __name__ == "__main__":
    main()
