"use client"; import { useState, useEffect, useCallback } from "react"; import { Card, Button, Badge, Input } from "@/shared/components"; const DEFAULT_MITM_ROUTER_BASE = "http://localhost:20128"; /** * Shared MITM infrastructure card — manages SSL cert + server start/stop. * DNS per-tool is handled separately in MitmToolCard. */ export default function MitmServerCard({ apiKeys, cloudEnabled, onStatusChange }) { const [status, setStatus] = useState(null); const [loading, setLoading] = useState(false); const [showPasswordModal, setShowPasswordModal] = useState(false); const [sudoPassword, setSudoPassword] = useState(""); const [selectedApiKey, setSelectedApiKey] = useState(() => apiKeys?.[0]?.key || ""); const [pendingAction, setPendingAction] = useState(null); const [modalError, setModalError] = useState(null); const [actionError, setActionError] = useState(null); const [mitmRouterBaseUrl, setMitmRouterBaseUrl] = useState(DEFAULT_MITM_ROUTER_BASE); const serverIsWindows = status?.isWin === true; const canRunWithoutPassword = serverIsWindows || status?.hasCachedPassword || status?.needsSudoPassword === false; const isAdmin = status?.isAdmin !== false; // No privilege: not admin/root AND (Win OR no cached sudo password) const noPrivilege = !isAdmin && (serverIsWindows || (!status?.hasCachedPassword && status?.needsSudoPassword !== false)); const fetchStatus = useCallback(async () => { try { const res = await fetch("/api/cli-tools/antigravity-mitm"); if (res.ok) { const data = await res.json(); setStatus(data); if (data.mitmRouterBaseUrl) { setMitmRouterBaseUrl(data.mitmRouterBaseUrl); } onStatusChange?.(data); } } catch { setStatus({ running: false, certExists: false, dnsStatus: {} }); } }, [onStatusChange]); useEffect(() => { queueMicrotask(() => { fetchStatus(); }); }, [fetchStatus]); const handleAction = (action) => { setActionError(null); if (canRunWithoutPassword) { doAction(action, ""); } else { setPendingAction(action); setShowPasswordModal(true); setModalError(null); } }; const doAction = async (action, password) => { setLoading(true); setActionError(null); try { let res; if (action === "trust-cert") { res = await fetch("/api/cli-tools/antigravity-mitm", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "trust-cert", sudoPassword: password }), }); } else if (action === "start") { const keyToUse = selectedApiKey?.trim() || (apiKeys?.length > 0 ? apiKeys[0].key : null) || (!cloudEnabled ? "sk_9router" : null); res = await fetch("/api/cli-tools/antigravity-mitm", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ apiKey: keyToUse, sudoPassword: password, mitmRouterBaseUrl: mitmRouterBaseUrl.trim() || DEFAULT_MITM_ROUTER_BASE, }), }); } else { res = await fetch("/api/cli-tools/antigravity-mitm", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sudoPassword: password }), }); } if (!res.ok) { const data = await res.json().catch(() => ({})); setActionError(data.error || `Failed to ${action} MITM server`); return; } setShowPasswordModal(false); setSudoPassword(""); await fetchStatus(); } catch (e) { setActionError(e.message || "Network error"); } finally { setLoading(false); setPendingAction(null); } }; const handleConfirmPassword = () => { if (!sudoPassword.trim()) { setModalError("Sudo password is required"); return; } doAction(pendingAction, sudoPassword); }; const isRunning = status?.running; return ( <>
{/* Header */}
security MITM Server {isRunning ? ( Running ) : ( Stopped )}
{[ { label: "Cert", ok: status?.certExists }, { label: "Trusted", ok: status?.certTrusted }, { label: "Server", ok: isRunning }, ].map(({ label, ok }) => ( {ok ? "check_circle" : "cancel"} {label} ))}
{/* Purpose & How it works */}

Purpose: Use Antigravity IDE & GitHub Copilot → with ANY provider/model from 9Router

How it works: Antigravity/Copilot IDE request → DNS redirect to localhost:443 → MITM proxy intercepts → 9Router → response to Antigravity/Copilot

{/* Base URL + API Key — same row pattern as Claude Code / cli-tools */}
9Router Base URL arrow_forward setMitmRouterBaseUrl(e.target.value)} placeholder={DEFAULT_MITM_ROUTER_BASE} disabled={isRunning} className="flex-1 min-w-0 px-2 py-1.5 bg-surface rounded border border-border text-xs text-text-main focus:outline-none focus:ring-1 focus:ring-primary/50 disabled:opacity-50" />
{!isRunning && (
API Key arrow_forward setSelectedApiKey(e.target.value)} placeholder={cloudEnabled ? "Enter or pick API key" : "sk_9router (default)"} className="flex-1 min-w-0 px-2 py-1.5 bg-surface rounded border border-border text-xs text-text-main focus:outline-none focus:ring-1 focus:ring-primary/50" /> {apiKeys?.length > 0 && ( {apiKeys.map((key) => ( ))} )}
)}
{/* Action buttons */}
{status?.certExists && !status?.certTrusted && ( )} {isRunning ? ( ) : ( )} {isRunning && (

Enable DNS per tool below to activate interception

)}
{/* Action error */} {actionError && (
error {actionError}
)} {/* Windows admin warning */} {serverIsWindows && !isAdmin && (
shield_lock Administrator required — restart 9Router as Administrator to use MITM
)}
{/* Password Modal */} {showPasswordModal && (

Sudo Password Required

warning

Required for SSL certificate and server startup

setSudoPassword(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !loading) handleConfirmPassword(); }} /> {modalError && (
error {modalError}
)}
)} ); }