#!/usr/bin/env bash # Launch VS Code with all traffic proxied through a local HTTP bridge that # itself forwards to your SOCKS5h tunnel (ssh -D). The bridge is auto-started # before Code launches and auto-stopped when Code exits -- but only if this # script started it (a bridge you started yourself is left running). # # tools/code --> http://127.0.0.1:18080 --> http2socks.py --> socks5h://127.0.0.1:12026 --> ssh -D # # Using the HTTP bridge (instead of pointing Chromium straight at SOCKS5) # means anything that only understands HTTP proxies -- extensions, # language servers, terminals, tasks -- also goes through the tunnel via # the HTTP_PROXY/HTTPS_PROXY/ALL_PROXY env vars below. # # Usage: # ./code-proxy.sh # open current dir in a new window # ./code-proxy.sh /path/to/proj # open a specific folder # ./code-proxy.sh --reuse-window # extra `code` flags pass through # # Env overrides: # CODE_PROXY_BIND bridge listen addr (default 127.0.0.1) # CODE_PROXY_PORT bridge listen port (default 18080) # KEEP_BRIDGE=1 don't auto-stop a bridge this script started # UPSTREAM socks5h://host:port (default socks5h://127.0.0.1:12026) set -uo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BRIDGE="$HERE/http2socks.sh" PIDFILE="$HERE/.http2socks.pid" BIND="${CODE_PROXY_BIND:-127.0.0.1}" PORT="${CODE_PROXY_PORT:-18080}" PROXY="http://${BIND}:${PORT}" BYPASS="localhost;127.0.0.1;[::1]" BYPASS_ENV="localhost,127.0.0.1,::1" # --- bridge lifecycle ------------------------------------------------------- bridge_running() { [[ -f "$PIDFILE" ]] && kill -0 "$(cat "$PIDFILE" 2>/dev/null)" 2>/dev/null } started_bridge=0 ensure_bridge() { if bridge_running; then echo "bridge: already running (pid $(cat "$PIDFILE")) on $PROXY" return 0 fi if [[ ! -x "$BRIDGE" ]]; then echo "bridge: $BRIDGE missing or not executable" >&2 exit 1 fi export BIND="$BIND" PORT="$PORT" if ! "$BRIDGE" start; then echo "bridge: failed to start" >&2 exit 1 fi started_bridge=1 } stop_bridge() { if [[ ${KEEP_BRIDGE:-0} -eq 1 ]]; then echo "bridge: KEEP_BRIDGE=1, leaving it running" return 0 fi if bridge_running; then "$BRIDGE" stop fi } cleanup() { if [[ $started_bridge -eq 1 ]]; then stop_bridge fi } trap cleanup EXIT INT TERM # --- launch code ------------------------------------------------------------ # If an existing `code` instance is running, VS Code reuses it and silently # ignores the proxy flags (and our exported env vars don't reach the already # running process). Warn so you don't get a false sense of being proxied. if pgrep -f '/lib/vscode/code' >/dev/null 2>&1; then echo "warning: a VS Code instance is already running." >&2 echo " Proxy flags are ignored by reused windows -- fully quit it" >&2 echo " first for real end-to-end proxying." >&2 fi ensure_bridge export HTTP_PROXY="$PROXY" export HTTPS_PROXY="$PROXY" export ALL_PROXY="$PROXY" export NO_PROXY="$BYPASS_ENV" echo "code-proxy: proxy=$PROXY -> socks5h://127.0.0.1:12026 (bridge auto-stops on exit)" # Run code as a foreground child (NOT exec) so our EXIT trap can fire and # stop the bridge once VS Code quits. #code --proxy-server="$PROXY" --proxy-bypass-list="$BYPASS" "$@" $@ code_rc=$? exit "$code_rc"