#!/usr/bin/env bash # ╔═══════════════════════════════════════════════════════════════════════════╗ # ║ Antigravity MITM LS Wrapper ║ # ║ ║ # ║ This script replaces the real Antigravity language server binary. ║ # ║ It injects HTTPS_PROXY and NODE_EXTRA_CA_CERTS environment variables ║ # ║ so the MITM proxy can intercept LS<->API traffic. ║ # ║ ║ # ║ Install: ./mitm-wrapper.sh install ║ # ║ Uninstall: ./mitm-wrapper.sh uninstall ║ # ║ (No args = act as wrapper, exec the real binary with injected env) ║ # ╚═══════════════════════════════════════════════════════════════════════════╝ set -euo pipefail # ── Config ──────────────────────────────────────────────────────────────────── # Resolve the real user's home (not /root when running under sudo) if [[ -n "${SUDO_USER:-}" ]]; then REAL_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6)" else REAL_HOME="$HOME" fi MITM_PORT_FILE="${REAL_HOME}/.config/antigravity-proxy/mitm-port" if [[ -n "${ANTIGRAVITY_MITM_PORT:-}" ]]; then MITM_PORT="$ANTIGRAVITY_MITM_PORT" elif [[ -f "$MITM_PORT_FILE" ]]; then MITM_PORT="$(cat "$MITM_PORT_FILE" 2>/dev/null || echo 8742)" else MITM_PORT="8742" fi CA_PATH="${REAL_HOME}/.config/antigravity-proxy/mitm-ca.pem" # Antigravity LS — discovered dynamically from running processes. # Hardcoded paths are only used as a fallback if no LS process is running. LS_FALLBACK_DIRS=( "/usr/share/antigravity/resources/app/extensions/antigravity/bin" "${REAL_HOME}/.antigravity/extensions/antigravity.antigravity-*/dist/bundled/language-server/bin" "${REAL_HOME}/.cursor/extensions/antigravity.antigravity-*/dist/bundled/language-server/bin" "${REAL_HOME}/.vscode/extensions/antigravity.antigravity-*/dist/bundled/language-server/bin" "/opt/antigravity/language-server/bin" ) BACKUP_SUFFIX=".real" # ── Colors ──────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # ── Find LS binary ─────────────────────────────────────────────────────────── find_ls_binary() { # Method 1: Find from running process via /proc if [[ -d /proc ]]; then for pid_dir in /proc/[0-9]*; do local exe_target exe_target="$(readlink "${pid_dir}/exe" 2>/dev/null)" || continue # Strip " (deleted)" suffix that appears when the binary was unlinked exe_target="${exe_target% (deleted)}" if [[ "$exe_target" == *language_server_linux* ]] || \ [[ "$exe_target" == *antigravity-language-server* ]]; then # FIX: If the running process is the backup (.real), strip the suffix # so we return the path to the base binary name. echo "${exe_target%$BACKUP_SUFFIX}" return 0 fi done fi # Method 2: Fallback — scan known directories for common binary names local bin_names=("language_server_linux_x64" "language_server_linux_arm64" "antigravity-language-server") for dir_pattern in "${LS_FALLBACK_DIRS[@]}"; do for dir in $dir_pattern; do [[ -d "$dir" ]] || continue for name in "${bin_names[@]}"; do local path="${dir}/${name}" if [[ -f "$path" || -f "${path}${BACKUP_SUFFIX}" ]]; then echo "$path" return 0 fi done done done return 1 } # ── Install ────────────────────────────────────────────────────────────────── cmd_install() { # Find the LS binary first (quiet, just to check permissions) local ls_path ls_path=$(find_ls_binary) || ls_path="${1:-}" # Allow override if [[ -n "${1:-}" ]]; then ls_path="$1" fi # Check permissions upfront — re-exec with sudo before doing anything if [[ -n "$ls_path" ]]; then local ls_dir ls_dir="$(dirname "$ls_path")" if [[ ! -w "$ls_dir" ]] && [[ "$EUID" -ne 0 ]]; then echo -e " ${RED}✗${NC} ${ls_dir} requires elevated permissions" echo -e " run: sudo $0 install ${1:-}" exit 1 fi fi echo -e "${BOLD}${CYAN}Antigravity MITM Wrapper Installer${NC}" echo -e "───────────────────────────────────" echo "" # Find the LS binary (for real this time, with output) if [[ -z "$ls_path" ]]; then echo -e " ${RED}✗${NC} Could not find Antigravity language server binary." echo -e " No LS process found in /proc, and fallback paths didn't match." echo "" echo -e " Set the path manually:" echo -e " $0 install /path/to/language_server_linux_x64" exit 1 fi echo -e " ${GREEN}✓${NC} Found LS: ${ls_path}" local real_path="${ls_path}${BACKUP_SUFFIX}" local wrapper_dir wrapper_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" local wrapper_src="${wrapper_dir}/mitm-wrapper.sh" # Verify the binary exists and is not already wrapped if [[ -f "$real_path" ]]; then echo -e " ${YELLOW}!${NC} Already installed (backup exists at ${real_path})" echo -e " Run '$0 uninstall' first to reinstall." exit 0 fi if [[ ! -f "$ls_path" ]]; then echo -e " ${RED}✗${NC} Binary not found: ${ls_path}" exit 1 fi # Verify it's a real binary, not already our wrapper if head -c 100 "$ls_path" | grep -q 'ANTIGRAVITY_MITM_PORT'; then echo -e " ${YELLOW}!${NC} Already wrapped (script detected). Run '$0 uninstall' first." exit 0 fi # Check CA cert if [[ ! -f "$CA_PATH" ]]; then echo -e " ${YELLOW}!${NC} CA cert not found at ${CA_PATH}" echo -e " Start the proxy first to generate it." echo -e " Continuing install anyway..." else echo -e " ${GREEN}✓${NC} CA cert: ${CA_PATH}" fi # Back up the real binary cp -p "$ls_path" "$real_path" echo -e " ${GREEN}✓${NC} Backed up real binary to ${real_path}" # Remove the original before writing (avoids "Text file busy" if LS is running) rm -f "$ls_path" # Create the wrapper script in-place tee "$ls_path" > /dev/null << 'WRAPPER_EOF' #!/usr/bin/env bash # Antigravity MITM LS Wrapper — auto-generated, do not edit. # The LS is a Go binary — it reads HTTPS_PROXY and SSL_CERT_FILE (not NODE_EXTRA_CA_CERTS). # Go's gRPC library also reads GRPC_DEFAULT_SSL_ROOTS_FILE_PATH for root certs. # We build a combined CA bundle (system CAs + MITM CA) and inject it. REAL_BINARY="${BASH_SOURCE[0]}.real" if [[ ! -f "$REAL_BINARY" ]]; then echo "ERROR: Real LS binary not found at $REAL_BINARY" >&2 echo "Run 'mitm-wrapper.sh uninstall' and reinstall." >&2 exit 1 fi # Inject MITM proxy (don't override if already set) export HTTPS_PROXY="${HTTPS_PROXY:-http://127.0.0.1:__MITM_PORT__}" # Build combined CA bundle: system CAs + MITM CA MITM_CA="__CA_PATH__" COMBINED_CA="/tmp/antigravity-mitm-combined-ca.pem" if [[ -f "$MITM_CA" ]]; then # Find system CA bundle SYS_CA="" for candidate in /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/cert.pem; do if [[ -f "$candidate" ]]; then SYS_CA="$candidate" break fi done if [[ -n "$SYS_CA" ]]; then cat "$SYS_CA" "$MITM_CA" > "$COMBINED_CA" 2>/dev/null export SSL_CERT_FILE="$COMBINED_CA" # Go's gRPC library may use this instead of SSL_CERT_FILE export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH="$COMBINED_CA" fi fi exec "$REAL_BINARY" "$@" WRAPPER_EOF # Substitute actual values sed -i "s|__MITM_PORT__|${MITM_PORT}|g" "$ls_path" sed -i "s|__CA_PATH__|${CA_PATH}|g" "$ls_path" # Make executable chmod +x "$ls_path" echo -e " ${GREEN}✓${NC} Wrapper installed at ${ls_path}" echo "" echo -e " ${BOLD}How it works:${NC}" echo -e " When Antigravity starts the LS, the wrapper will:" echo -e " 1. Set ${CYAN}HTTPS_PROXY${NC}=http://127.0.0.1:${MITM_PORT}" echo -e " 2. Build combined CA bundle (system + MITM) at /tmp/antigravity-mitm-combined-ca.pem" echo -e " 3. Set ${CYAN}SSL_CERT_FILE${NC} to the combined bundle" echo -e " 4. Exec the real LS binary with all original args" echo "" echo -e " ${YELLOW}Note:${NC} Restart Antigravity for the wrapper to take effect." echo "" } # ── Uninstall ──────────────────────────────────────────────────────────────── cmd_uninstall() { # Check permissions upfront local ls_path ls_path=$(find_ls_binary) || true if [[ -n "$ls_path" ]] && [[ ! -w "$(dirname "$ls_path")" ]] && [[ "$EUID" -ne 0 ]]; then echo -e " ${RED}✗${NC} $(dirname "$ls_path") requires elevated permissions" echo -e " run: sudo $0 uninstall" exit 1 fi echo -e "${BOLD}${CYAN}Antigravity MITM Wrapper Uninstaller${NC}" echo -e "─────────────────────────────────────" echo "" if [[ -n "$ls_path" ]]; then local real_path="${ls_path}${BACKUP_SUFFIX}" if [[ -f "$real_path" ]]; then mv -f "$real_path" "$ls_path" echo -e " ${GREEN}✓${NC} Restored real binary at ${ls_path}" else echo -e " ${YELLOW}!${NC} No backup found at ${real_path}" echo -e " The LS binary may not be wrapped." fi else echo -e " ${RED}✗${NC} Could not find Antigravity language server binary." fi echo "" echo -e " ${YELLOW}Note:${NC} Restart Antigravity for the change to take effect." echo "" } # ── Status ─────────────────────────────────────────────────────────────────── cmd_status() { echo -e "${BOLD}${CYAN}Antigravity MITM Wrapper Status${NC}" echo -e "────────────────────────────────" echo "" local ls_path if ls_path=$(find_ls_binary); then echo -e " ${GREEN}✓${NC} LS binary: ${ls_path}" local real_path="${ls_path}${BACKUP_SUFFIX}" if [[ -f "$real_path" ]]; then echo -e " ${GREEN}✓${NC} Wrapper: ${BOLD}installed${NC}" echo -e " ${GREEN}✓${NC} Real binary: ${real_path}" # Check if wrapper is valid if head -c 200 "$ls_path" | grep -q 'MITM LS Wrapper'; then echo -e " ${GREEN}✓${NC} Wrapper script: valid" else echo -e " ${RED}✗${NC} Wrapper script: ${BOLD}corrupted or replaced${NC}" fi else echo -e " ${YELLOW}○${NC} Wrapper: ${BOLD}not installed${NC}" fi else echo -e " ${RED}✗${NC} LS binary: not found" fi # Check CA cert if [[ -f "$CA_PATH" ]]; then echo -e " ${GREEN}✓${NC} CA cert: ${CA_PATH}" else echo -e " ${RED}✗${NC} CA cert: not found (start proxy first)" fi # Check MITM port if ss -tlnp 2>/dev/null | grep -q ":${MITM_PORT} "; then echo -e " ${GREEN}✓${NC} MITM proxy: listening on :${MITM_PORT}" else echo -e " ${YELLOW}○${NC} MITM proxy: not running on :${MITM_PORT}" fi echo "" } # ── Main ───────────────────────────────────────────────────────────────────── case "${1:-}" in install) shift cmd_install "${1:-}" ;; uninstall) cmd_uninstall ;; status) cmd_status ;; -h|--help) echo "Usage: $0 {install|uninstall|status}" echo "" echo "Commands:" echo " install [path] Install MITM wrapper (auto-detect or specify path)" echo " uninstall Restore original LS binary" echo " status Show wrapper installation status" echo "" echo "Environment:" echo " ANTIGRAVITY_MITM_PORT MITM proxy port (default: 8742)" ;; *) echo "Usage: $0 {install|uninstall|status}" exit 1 ;; esac