feat: scaffold inicial de web_proxy (proxy de interceptacion liviano)

This commit is contained in:
agent
2026-06-02 21:08:30 +02:00
commit 97dc5a35cf
4 changed files with 711 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# Estado local y capturas — no se versionan
local_files/
captures/
*.mitm
*.har
*.pid
*.log
chromium-profile/
+161
View File
@@ -0,0 +1,161 @@
---
name: web_proxy
lang: bash
domain: cybersecurity
version: 0.1.0
description: "Proxy de interceptacion HTTP/HTTPS liviano y siempre activo (mitmproxy) para capturar todo el trafico de un navegador con rotacion temporal de capturas, alternativa ligera a ZAP/Burp."
tags: [service, web-proxy, mitmproxy, proxy, capture, cybersecurity, chromium]
icon:
phosphor: "shield-check"
accent: "#7c3aed"
uses_functions:
- start_mitm_capture_bash_cybersecurity
- query_mitm_flows_bash_cybersecurity
- rotate_capture_flows_py_cybersecurity
- launch_chromium_proxy_bash_browser
- port_kill_bash_infra
uses_types: []
framework: ""
entry_point: "web_proxy"
dir_path: "apps/web_proxy"
repo_url: ""
service:
port: 8080
health_endpoint: null
health_timeout_s: 3
systemd_unit: web_proxy.service
systemd_scope: user
restart_policy: always
runtime: systemd-user
pc_targets:
- home-wsl
is_local_only: true
e2e_checks:
- id: syntax
cmd: "bash -n web_proxy"
timeout_s: 10
- id: help
cmd: "./web_proxy help"
expect_stdout_contains: "proxy de interceptacion"
timeout_s: 10
- id: capture_roundtrip
cmd: "bash tests/e2e_capture.sh"
expect_stdout_contains: "CAPTURE_OK"
timeout_s: 40
---
# web_proxy
Proxy de interceptacion HTTP/HTTPS liviano y siempre activo, pensado como
alternativa ligera a OWASP ZAP y Burp Suite. Construido sobre `mitmproxy`
(footprint de decenas de MB frente a la JVM de ZAP/Burp) y compuesto a partir
de funciones del registry `fn_registry`.
## Que hace
- Levanta un proxy local (`mitmdump` headless) que registra **todo** el trafico
HTTP/HTTPS que pasa por el.
- **Rota las capturas** en archivos `.mitm` por ventanas de tiempo configurables
(default 20 minutos), de modo que puedas consultar el trafico de cada tramo
por separado.
- Corre **siempre activo** como servicio `systemd --user` con `Restart=always`,
o de forma manual con `start`/`stop`.
- Lanza un **Chromium proxeado** en un perfil aislado para no contaminar tu
navegacion normal.
- Permite **consultar** las capturas guardadas: volcado filtrado, exportacion a
HAR, o inspeccion visual en `mitmweb`.
## Ejemplo
```bash
cd apps/web_proxy
# Servicio siempre activo en el puerto 8080, capturas en ~/captures, rotando cada 20 min
./web_proxy install-service --port 8080 --out ~/captures --rotate-min 20
# Confiar en el CA de mitmproxy para que HTTPS no rompa
./web_proxy ca
# Navegar con todo el trafico capturado (Chromium en perfil aislado)
./web_proxy browser --url https://example.com
# Consultar la ultima ventana de captura
./web_proxy query "~m POST" # solo peticiones POST
./web_proxy query "~c 500" --all # respuestas 5xx en todas las capturas
./web_proxy har ~/captures/sesion.har
# Inspeccion visual en el navegador
./web_proxy inspect
# Estado y logs
./web_proxy status
./web_proxy logs
```
Modo manual (sin servicio):
```bash
./web_proxy start --port 8080 --out ~/captures --rotate-min 20
./web_proxy browser
./web_proxy query "~d api.github.com"
./web_proxy stop
```
## Cuando usarla
Cuando quieras registrar de forma continua y liviana todo lo que hace un
navegador (debug de APIs, auditoria de trafico, inspeccion de requests de una
SPA) sin arrancar la maquinaria pesada de ZAP o Burp, y poder volver a consultar
sesiones pasadas troceadas por ventanas de tiempo.
## Como consultar las capturas
Las capturas son archivos `.mitm` en el directorio de salida (`~/captures` por
defecto), con nombre `traffic-YYYYmmdd-HHMMSS.mitm`, uno por ventana de rotacion.
| Forma | Comando |
|---|---|
| Volcado filtrado (CLI) | `./web_proxy query "~m POST"` |
| Volcado de todas las ventanas | `./web_proxy query "~u /api" --all` |
| Exportar a HAR | `./web_proxy har salida.har` |
| Inspeccion visual (UI web) | `./web_proxy inspect [archivo.mitm]` |
| Directo con mitmproxy | `mitmproxy -r ~/captures/traffic-*.mitm` |
Sintaxis de filtros de mitmproxy: `~u` URL, `~d` dominio, `~m` metodo, `~c`
codigo de estado, `~bq`/`~bs` cuerpo de peticion/respuesta. Combinables con
`&` (y), `|` (o), `!` (no).
## Gotchas
- **HTTPS**: requiere confiar en el CA de mitmproxy. Ejecuta `./web_proxy ca`
para las instrucciones. El navegador que lanza `./web_proxy browser` usa
`--ignore-certificate-errors` si no instalas el CA, lo cual es comodo pero
menos seguro (vale para uso local de captura, no para navegacion sensible).
- **Durabilidad**: el addon de rotacion hace `flush()` tras cada flujo, asi que
las capturas sobreviven a un `kill -9` o un corte abrupto del proceso.
- **Rotacion por trafico**: la rotacion ocurre al recibir un flujo; si no hay
trafico durante la ventana, el archivo no rota hasta el siguiente request.
- **Persistencia tras logout**: el servicio `systemd --user` para al cerrar
sesion salvo que actives linger con `./web_proxy install-service --linger`.
- **Conflicto de puerto**: `start` y el servicio no pueden coexistir en el mismo
puerto. `install-service` para el proxy manual automaticamente antes de
arrancar el servicio.
- **Stop fiable**: el `stop` mata por PID guardado en el pidfile (no depende de
`lsof`/`port_kill`, que en este entorno no siempre detecta el listener a
tiempo).
## Arquitectura
Orquesta funciones del registry (no reimplementa logica reutilizable):
| Funcion del registry | Rol |
|---|---|
| `start_mitm_capture_bash_cybersecurity` | Arranca `mitmdump` headless con rotacion |
| `rotate_capture_flows_py_cybersecurity` | Addon de mitmproxy que trocea las capturas |
| `query_mitm_flows_bash_cybersecurity` | Consulta capturas guardadas (volcado / HAR) |
| `launch_chromium_proxy_bash_browser` | Lanza Chromium proxeado en perfil aislado |
| `port_kill_bash_infra` | Limpieza de puertos ocupados |
El CLI `web_proxy` aporta solo la logica especifica de la app: gestion del
pidfile, configuracion persistente, generacion del unit `systemd --user` y la
interfaz de subcomandos.
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env bash
#
# e2e_capture.sh — prueba de roundtrip completa del stack de captura.
#
# Levanta un servidor HTTP local, arranca el proxy mitmproxy a traves de las
# funciones del registry, hace pasar trafico por el, y verifica que:
# - se crea un archivo .mitm con contenido,
# - la captura sobrevive a un SIGKILL (flush por flujo),
# - la consulta a HAR devuelve las entradas esperadas con sus codigos.
#
# Emite "CAPTURE_OK" en stdout si todo pasa; cualquier otro caso es fallo.
# Diseñado para ser idempotente y autolimpiante (puertos altos, dir temporal).
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REGISTRY_ROOT="${FN_REGISTRY_ROOT:-$(cd "$SCRIPT_DIR/../../.." && pwd)}"
export FN_REGISTRY_ROOT="$REGISTRY_ROOT"
START_FN="$REGISTRY_ROOT/bash/functions/cybersecurity/start_mitm_capture.sh"
QUERY_FN="$REGISTRY_ROOT/bash/functions/cybersecurity/query_mitm_flows.sh"
PROXY_PORT=18906
UPSTREAM_PORT=18913
WORK="$(mktemp -d /tmp/web_proxy_e2e.XXXXXX)"
cleanup() {
[[ -n "${PROXY_PID:-}" ]] && kill -9 "$PROXY_PID" 2>/dev/null
[[ -n "${SRV_PID:-}" ]] && kill -9 "$SRV_PID" 2>/dev/null
rm -rf "$WORK"
}
trap cleanup EXIT
fail() { echo "CAPTURE_FAIL: $*" >&2; exit 1; }
mkdir -p "$WORK/www" "$WORK/cap"
echo "<html><body>web_proxy e2e</body></html>" > "$WORK/www/index.html"
# --- 1. Upstream HTTP local (respuesta valida garantizada) -------------------
setsid bash -c "cd '$WORK/www' && exec python3 -m http.server $UPSTREAM_PORT" </dev/null >/dev/null 2>&1 &
SRV_PID=$!
disown "$SRV_PID" 2>/dev/null || true
sleep 1
# --- 2. Arrancar el proxy via funcion del registry ---------------------------
JSON="$(bash "$START_FN" --port "$PROXY_PORT" --out "$WORK/cap" --rotate-min 20)" \
|| fail "start_mitm_capture fallo"
PROXY_PID="$(printf '%s' "$JSON" | python3 -c 'import sys,json;print(json.load(sys.stdin)["pid"])' 2>/dev/null)"
[[ -n "$PROXY_PID" ]] || fail "no se obtuvo PID del proxy ($JSON)"
sleep 2
# --- 3. Trafico via proxy ----------------------------------------------------
for path in / /index.html /alpha /beta; do
curl -s -x "http://127.0.0.1:$PROXY_PORT" "http://127.0.0.1:$UPSTREAM_PORT${path}" -o /dev/null \
|| fail "curl fallo en $path"
done
sleep 1
# --- 4. Verificar captura ----------------------------------------------------
MITM="$(find "$WORK/cap" -name 'traffic-*.mitm' | head -1)"
[[ -n "$MITM" ]] || fail "no se creo archivo .mitm"
BYTES_BEFORE="$(stat -c%s "$MITM")"
[[ "$BYTES_BEFORE" -gt 0 ]] || fail "el .mitm quedo vacio antes de matar"
# --- 5. Durabilidad: SIGKILL no debe perder datos ----------------------------
kill -9 "$PROXY_PID" 2>/dev/null
PROXY_PID=""
sleep 1
BYTES_AFTER="$(stat -c%s "$MITM")"
[[ "$BYTES_AFTER" -eq "$BYTES_BEFORE" && "$BYTES_AFTER" -gt 0 ]] \
|| fail "la captura no sobrevivio al SIGKILL ($BYTES_BEFORE -> $BYTES_AFTER)"
# --- 6. Consulta a HAR -------------------------------------------------------
bash "$QUERY_FN" "$MITM" --har "$WORK/out.har" >/dev/null 2>&1 || fail "export HAR fallo"
ENTRIES="$(python3 -c "import json;print(len(json.load(open('$WORK/out.har'))['log']['entries']))" 2>/dev/null)"
[[ "$ENTRIES" == "4" ]] || fail "HAR esperaba 4 entradas, obtuvo ${ENTRIES:-0}"
echo "CAPTURE_OK ($ENTRIES flujos, ${BYTES_AFTER}B, sobrevivio SIGKILL)"
Executable
+464
View File
@@ -0,0 +1,464 @@
#!/usr/bin/env bash
#
# web_proxy — proxy de interceptacion HTTP/HTTPS liviano, siempre activo.
#
# Orquesta funciones del registry fn_registry para capturar todo el trafico de
# un navegador (estilo ZAP/Burp) con un footprint minimo basado en mitmproxy:
#
# start_mitm_capture_bash_cybersecurity arranca mitmdump con rotacion
# rotate_capture_flows_py_cybersecurity addon que trocea las capturas
# query_mitm_flows_bash_cybersecurity consulta capturas guardadas
# launch_chromium_proxy_bash_browser navegador proxeado en perfil aislado
#
# El proxy puede correr en dos modos:
# - manual: `web_proxy start` / `web_proxy stop` (background + pidfile)
# - servicio: `web_proxy install-service` (systemd --user, Restart=always,
# siempre activo, sobrevive a logout/reboot con linger)
#
# Estado y configuracion viven en $WEB_PROXY_HOME (default ~/.web_proxy).
# Las capturas .mitm viven en el directorio de salida (default ~/captures).
set -uo pipefail
# --- Resolucion de rutas -----------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# apps/web_proxy/ -> raiz del registry son dos niveles arriba.
REGISTRY_ROOT="${FN_REGISTRY_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
export FN_REGISTRY_ROOT="$REGISTRY_ROOT"
FN_BIN="$REGISTRY_ROOT/fn"
ADDON_PATH="$REGISTRY_ROOT/python/functions/cybersecurity/rotate_capture_flows.py"
START_FN="$REGISTRY_ROOT/bash/functions/cybersecurity/start_mitm_capture.sh"
QUERY_FN="$REGISTRY_ROOT/bash/functions/cybersecurity/query_mitm_flows.sh"
BROWSER_FN="$REGISTRY_ROOT/bash/functions/browser/launch_chromium_proxy.sh"
# --- Configuracion -----------------------------------------------------------
WEB_PROXY_HOME="${WEB_PROXY_HOME:-$HOME/.web_proxy}"
PIDFILE="$WEB_PROXY_HOME/web_proxy.pid"
CONFFILE="$WEB_PROXY_HOME/web_proxy.conf"
SERVICE_NAME="web_proxy.service"
SYSTEMD_USER_DIR="$HOME/.config/systemd/user"
DEFAULT_PORT=8080
DEFAULT_OUT="$HOME/captures"
DEFAULT_ROTATE=20
MITMDUMP_BIN="$(command -v mitmdump 2>/dev/null || echo "$HOME/.local/bin/mitmdump")"
MITMWEB_BIN="$(command -v mitmweb 2>/dev/null || echo "$HOME/.local/bin/mitmweb")"
CA_CERT="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
mkdir -p "$WEB_PROXY_HOME"
# --- Helpers -----------------------------------------------------------------
err() { printf '\033[31m%s\033[0m\n' "$*" >&2; }
ok() { printf '\033[32m%s\033[0m\n' "$*"; }
info() { printf '%s\n' "$*"; }
# Lee KEY del conffile (formato KEY=VAL), o imprime el default pasado.
conf_get() {
local key="$1" def="${2:-}"
if [[ -f "$CONFFILE" ]]; then
local val
val="$(grep -E "^${key}=" "$CONFFILE" 2>/dev/null | tail -1 | cut -d= -f2-)"
[[ -n "$val" ]] && { printf '%s' "$val"; return; }
fi
printf '%s' "$def"
}
conf_write() {
local port="$1" out="$2" rotate="$3"
cat > "$CONFFILE" <<EOF
PORT=$port
OUT=$out
ROTATE=$rotate
EOF
}
# PID del proxy manual, si vive. Imprime el PID o nada.
running_pid() {
[[ -f "$PIDFILE" ]] || return 1
local pid
pid="$(cat "$PIDFILE" 2>/dev/null)"
[[ -n "$pid" ]] || return 1
if kill -0 "$pid" 2>/dev/null; then
printf '%s' "$pid"
return 0
fi
return 1
}
service_active() {
systemctl --user is-active --quiet "$SERVICE_NAME" 2>/dev/null
}
# --- Subcomandos -------------------------------------------------------------
cmd_start() {
local port out rotate
port="$DEFAULT_PORT"; out="$DEFAULT_OUT"; rotate="$DEFAULT_ROTATE"
while [[ $# -gt 0 ]]; do
case "$1" in
--port) port="$2"; shift 2 ;;
--out) out="$2"; shift 2 ;;
--rotate-min) rotate="$2"; shift 2 ;;
*) err "start: flag desconocido: $1"; return 2 ;;
esac
done
if service_active; then
err "El servicio systemd ($SERVICE_NAME) ya esta activo. Usa 'web_proxy stop-service' o gestiona el servicio en su lugar."
return 1
fi
if running_pid >/dev/null; then
err "Ya hay un proxy manual corriendo (PID $(running_pid)). Para con 'web_proxy stop'."
return 1
fi
local json
json="$(bash "$START_FN" --port "$port" --out "$out" --rotate-min "$rotate")" || {
err "Fallo al arrancar mitmdump."
return 1
}
local pid
pid="$(printf '%s' "$json" | python3 -c 'import sys,json;print(json.load(sys.stdin)["pid"])' 2>/dev/null)"
if [[ -z "$pid" ]]; then
err "No se pudo extraer el PID del arranque. Salida: $json"
return 1
fi
printf '%s' "$pid" > "$PIDFILE"
conf_write "$port" "$out" "$rotate"
ok "Proxy activo en 127.0.0.1:$port (PID $pid)"
info " capturas -> $out (rotacion cada ${rotate} min)"
info " navegador -> web_proxy browser"
info " consultar -> web_proxy query \"~m POST\""
}
cmd_stop() {
local pid
if pid="$(running_pid)"; then
kill -TERM "$pid" 2>/dev/null
# Esperar cierre limpio; SIGKILL si se resiste.
for _ in 1 2 3 4 5; do
kill -0 "$pid" 2>/dev/null || break
sleep 0.3
done
kill -9 "$pid" 2>/dev/null
rm -f "$PIDFILE"
ok "Proxy manual detenido (PID $pid)."
else
rm -f "$PIDFILE"
info "No habia proxy manual corriendo."
fi
}
cmd_restart() {
cmd_stop
sleep 1
cmd_start "$@"
}
cmd_status() {
local port out rotate
port="$(conf_get PORT "$DEFAULT_PORT")"
out="$(conf_get OUT "$DEFAULT_OUT")"
rotate="$(conf_get ROTATE "$DEFAULT_ROTATE")"
info "web_proxy — estado"
info " home: $WEB_PROXY_HOME"
info " capturas: $out"
info " rotacion: cada ${rotate} min"
local pid
if pid="$(running_pid)"; then
ok " manual: ACTIVO (PID $pid, puerto $port)"
else
info " manual: parado"
fi
if service_active; then
ok " servicio: ACTIVO ($SERVICE_NAME)"
elif systemctl --user list-unit-files "$SERVICE_NAME" &>/dev/null && \
systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
info " servicio: instalado, parado"
else
info " servicio: no instalado"
fi
if [[ -d "$out" ]]; then
local n size
n="$(find "$out" -maxdepth 1 -name 'traffic-*.mitm' 2>/dev/null | wc -l)"
size="$(du -sh "$out" 2>/dev/null | cut -f1)"
info " archivos: ${n} capturas (${size:-0})"
local last
last="$(find "$out" -maxdepth 1 -name 'traffic-*.mitm' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -1 | cut -d' ' -f2-)"
[[ -n "$last" ]] && info " ultima: $(basename "$last")"
fi
if [[ -f "$CA_CERT" ]]; then
info " CA HTTPS: $CA_CERT"
else
info " CA HTTPS: no generado todavia (arranca el proxy una vez)"
fi
}
cmd_browser() {
local url="" proxy_port
proxy_port="$(conf_get PORT "$DEFAULT_PORT")"
while [[ $# -gt 0 ]]; do
case "$1" in
--url) url="$2"; shift 2 ;;
--port) proxy_port="$2"; shift 2 ;;
*) err "browser: flag desconocido: $1"; return 2 ;;
esac
done
if ! running_pid >/dev/null && ! service_active; then
err "No hay proxy activo. Arranca primero con 'web_proxy start' o instala el servicio."
return 1
fi
local args=(--proxy "http://127.0.0.1:${proxy_port}" --profile "$WEB_PROXY_HOME/chromium-profile")
# Si el CA esta instalado en el perfil, no forzamos --ignore-certificate-errors.
[[ -n "$url" ]] && args+=(--url "$url")
bash "$BROWSER_FN" "${args[@]}"
}
# Resuelve la lista de archivos a consultar: por defecto la ultima captura.
resolve_capture_files() {
local out scope="$1"
out="$(conf_get OUT "$DEFAULT_OUT")"
if [[ "$scope" == "all" ]]; then
find "$out" -maxdepth 1 -name 'traffic-*.mitm' 2>/dev/null | sort
else
find "$out" -maxdepth 1 -name 'traffic-*.mitm' -printf '%T@ %p\n' 2>/dev/null \
| sort -nr | head -1 | cut -d' ' -f2-
fi
}
cmd_query() {
local filter="" scope="last"
while [[ $# -gt 0 ]]; do
case "$1" in
--all) scope="all"; shift ;;
--last) scope="last"; shift ;;
*) filter="$1"; shift ;;
esac
done
local files
mapfile -t files < <(resolve_capture_files "$scope")
if [[ ${#files[@]} -eq 0 || -z "${files[0]}" ]]; then
err "No hay capturas en $(conf_get OUT "$DEFAULT_OUT")."
return 1
fi
if [[ -n "$filter" ]]; then
bash "$QUERY_FN" "${files[@]}" --filter "$filter"
else
bash "$QUERY_FN" "${files[@]}"
fi
}
cmd_har() {
local outhar="${1:-$HOME/captures/export.har}" scope="last"
[[ "${2:-}" == "--all" ]] && scope="all"
local files
mapfile -t files < <(resolve_capture_files "$scope")
if [[ ${#files[@]} -eq 0 || -z "${files[0]}" ]]; then
err "No hay capturas para exportar."
return 1
fi
bash "$QUERY_FN" "${files[@]}" --har "$outhar"
ok "HAR exportado a $outhar"
}
cmd_inspect() {
local file="${1:-}"
if [[ -z "$file" ]]; then
file="$(resolve_capture_files last)"
fi
if [[ -z "$file" || ! -f "$file" ]]; then
err "No hay captura para inspeccionar. Pasa una ruta o arranca el proxy."
return 1
fi
info "Abriendo mitmweb sobre $(basename "$file") -> http://127.0.0.1:8081"
info "(Ctrl-C para cerrar la UI; no afecta al proxy activo)"
"$MITMWEB_BIN" -r "$file" --no-web-open-browser
}
cmd_ca() {
info "HTTPS via proxy de interceptacion requiere confiar en el CA de mitmproxy."
info ""
if [[ ! -f "$CA_CERT" ]]; then
err "El CA aun no existe ($CA_CERT)."
info "Arranca el proxy una vez ('web_proxy start') para que mitmproxy lo genere."
return 1
fi
info "CA generado en: $CA_CERT"
info ""
info "Opciones:"
info " 1. Confianza a nivel sistema (recomendado):"
info " sudo cp $CA_CERT /usr/local/share/ca-certificates/mitmproxy.crt"
info " sudo update-ca-certificates"
info " 2. Solo para el navegador proxeado: importa el .pem en"
info " chrome://settings/certificates (pestaña Autoridades)."
info " 3. Rapido y sucio (menos seguro): el navegador de 'web_proxy browser'"
info " ya usa --ignore-certificate-errors si no instalas el CA."
}
# Genera e instala el unit systemd --user. El servicio corre mitmdump en
# foreground (systemd gestiona el proceso) con Restart=always.
cmd_install_service() {
local port out rotate enable_linger="no"
port="$(conf_get PORT "$DEFAULT_PORT")"
out="$(conf_get OUT "$DEFAULT_OUT")"
rotate="$(conf_get ROTATE "$DEFAULT_ROTATE")"
while [[ $# -gt 0 ]]; do
case "$1" in
--port) port="$2"; shift 2 ;;
--out) out="$2"; shift 2 ;;
--rotate-min) rotate="$2"; shift 2 ;;
--linger) enable_linger="yes"; shift ;;
*) err "install-service: flag desconocido: $1"; return 2 ;;
esac
done
if [[ ! -x "$MITMDUMP_BIN" ]]; then
err "mitmdump no encontrado. Instala con: uv tool install mitmproxy"
return 1
fi
# Si hay un proxy manual corriendo, pararlo para no chocar de puerto.
if running_pid >/dev/null; then
info "Parando el proxy manual antes de instalar el servicio..."
cmd_stop
fi
mkdir -p "$SYSTEMD_USER_DIR" "$out"
conf_write "$port" "$out" "$rotate"
cat > "$SYSTEMD_USER_DIR/$SERVICE_NAME" <<EOF
[Unit]
Description=web_proxy — proxy de interceptacion HTTP/HTTPS liviano (mitmproxy)
After=network.target
[Service]
Type=simple
ExecStart=$MITMDUMP_BIN -s $ADDON_PATH --set rotate_min=$rotate --set capture_dir=$out --listen-port $port
Restart=always
RestartSec=2
# Restart=always (no on-failure): un SIGTERM limpio es exit success y
# on-failure NO reiniciaria, dejando el proxy muerto en silencio.
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now "$SERVICE_NAME"
if [[ "$enable_linger" == "yes" ]]; then
loginctl enable-linger "$USER" 2>/dev/null \
&& ok "Linger activado: el servicio sigue vivo aunque cierres sesion." \
|| err "No se pudo activar linger (requiere permisos). El servicio para al cerrar sesion."
fi
sleep 1
if service_active; then
ok "Servicio instalado y ACTIVO en 127.0.0.1:$port."
info " capturas -> $out (rotacion cada ${rotate} min)"
info " logs -> web_proxy logs"
info " navegador -> web_proxy browser"
[[ "$enable_linger" == "no" ]] && info " persistir tras logout -> web_proxy install-service --linger"
else
err "El servicio no arranco. Revisa: web_proxy logs"
return 1
fi
}
cmd_uninstall_service() {
systemctl --user disable --now "$SERVICE_NAME" 2>/dev/null
rm -f "$SYSTEMD_USER_DIR/$SERVICE_NAME"
systemctl --user daemon-reload
ok "Servicio $SERVICE_NAME desinstalado."
}
cmd_logs() {
if service_active || systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
journalctl --user -u "$SERVICE_NAME" -n "${1:-40}" --no-pager
else
local out
out="$(conf_get OUT "$DEFAULT_OUT")"
[[ -f "$out/mitmdump.log" ]] && tail -n "${1:-40}" "$out/mitmdump.log" \
|| info "No hay logs (servicio no instalado, sin log manual)."
fi
}
usage() {
cat <<'EOF'
web_proxy — proxy de interceptacion HTTP/HTTPS liviano, siempre activo (mitmproxy)
USO: web_proxy <comando> [opciones]
Proxy:
start [--port N] [--out DIR] [--rotate-min N] Arranca el proxy (background, manual)
stop Para el proxy manual
restart [opciones de start] Reinicia el proxy manual
status Estado: proxy, servicio, capturas, CA
Servicio (siempre activo, systemd --user):
install-service [--port N] [--out DIR] [--rotate-min N] [--linger]
Instala + arranca como servicio
stop-service / uninstall-service Para / desinstala el servicio
logs [N] Ultimas N lineas de log
Navegacion:
browser [--url URL] [--port N] Lanza Chromium proxeado (perfil aislado)
ca Instrucciones para confiar en el CA (HTTPS)
Consultar capturas:
query [FILTRO] [--all|--last] Vuelca flujos (default: ultima captura)
Filtros mitmproxy: "~m POST", "~c 500", "~d host"
har [SALIDA.har] [--all] Exporta a HAR
inspect [ARCHIVO.mitm] Abre UI web (mitmweb) sobre una captura
Config:
WEB_PROXY_HOME directorio de estado (default ~/.web_proxy)
Defaults: puerto 8080, capturas ~/captures, rotacion 20 min
Ejemplo completo:
web_proxy install-service --port 8080 --out ~/captures --rotate-min 20
web_proxy ca # confiar en el CA para HTTPS
web_proxy browser # navega; todo queda capturado
web_proxy query "~m POST" # revisa los POST de la ultima ventana
web_proxy inspect # UI visual de la ultima captura
EOF
}
# --- Dispatch ----------------------------------------------------------------
main() {
local cmd="${1:-help}"
shift || true
case "$cmd" in
start) cmd_start "$@" ;;
stop) cmd_stop "$@" ;;
restart) cmd_restart "$@" ;;
status) cmd_status "$@" ;;
browser) cmd_browser "$@" ;;
query) cmd_query "$@" ;;
har) cmd_har "$@" ;;
inspect) cmd_inspect "$@" ;;
ca) cmd_ca "$@" ;;
install-service) cmd_install_service "$@" ;;
stop-service) systemctl --user stop "$SERVICE_NAME" && ok "Servicio parado." ;;
uninstall-service) cmd_uninstall_service "$@" ;;
logs) cmd_logs "$@" ;;
help|-h|--help) usage ;;
*) err "Comando desconocido: $cmd"; echo; usage; return 2 ;;
esac
}
main "$@"