6e094dce97
- web_proxy Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
584 lines
22 KiB
Bash
Executable File
584 lines
22 KiB
Bash
Executable File
#!/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"
|
|
EXT_DIR="$SCRIPT_DIR/extension"
|
|
|
|
# --- 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
|
|
DEFAULT_WEB_PORT=8081
|
|
DEFAULT_MAX_MB=2048 # tope de tamaño del directorio de capturas (MB); 0 = sin limite
|
|
DEFAULT_MAX_DAYS=7 # antiguedad maxima de una captura (dias); 0 = sin limite
|
|
|
|
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" web_port="${4:-}" web_pass="${5:-}" max_mb="${6:-}" max_days="${7:-}"
|
|
cat > "$CONFFILE" <<EOF
|
|
PORT=$port
|
|
OUT=$out
|
|
ROTATE=$rotate
|
|
WEB_PORT=$web_port
|
|
WEB_PASS=$web_pass
|
|
MAX_MB=$max_mb
|
|
MAX_DAYS=$max_days
|
|
EOF
|
|
}
|
|
|
|
# URL base de la UI de registros en vivo (sin token; la auth es por password).
|
|
web_ui_url() {
|
|
local web_port
|
|
web_port="$(conf_get WEB_PORT "")"
|
|
[[ -z "$web_port" ]] && return 1
|
|
printf 'http://127.0.0.1:%s/' "$web_port"
|
|
}
|
|
|
|
# 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")"
|
|
|
|
local max_mb max_days
|
|
max_mb="$(conf_get MAX_MB "$DEFAULT_MAX_MB")"
|
|
max_days="$(conf_get MAX_DAYS "$DEFAULT_MAX_DAYS")"
|
|
info "web_proxy — estado"
|
|
info " home: $WEB_PROXY_HOME"
|
|
info " capturas: $out"
|
|
info " rotacion: cada ${rotate} min"
|
|
info " retencion: max ${max_mb} MB, max ${max_days} dias"
|
|
|
|
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
|
|
|
|
local web_port web_pass
|
|
web_port="$(conf_get WEB_PORT "")"
|
|
web_pass="$(conf_get WEB_PASS "")"
|
|
if [[ -n "$web_port" ]]; then
|
|
ok " UI viva: http://127.0.0.1:$web_port (registros en tiempo real)"
|
|
[[ -n "$web_pass" ]] && info " UI login: password $web_pass (deja el usuario vacio)"
|
|
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 show_ui="yes" web_port mode="ext"
|
|
proxy_port="$(conf_get PORT "$DEFAULT_PORT")"
|
|
web_port="$(conf_get WEB_PORT "")"
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--url) url="$2"; shift 2 ;;
|
|
--port) proxy_port="$2"; shift 2 ;;
|
|
--no-ui) show_ui="no"; shift ;;
|
|
--fixed) mode="fixed"; shift ;; # proxy siempre activo, sin extension
|
|
--ext) mode="ext"; shift ;; # extension con toggle (default)
|
|
*) 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=(--profile "$WEB_PROXY_HOME/chromium-profile")
|
|
if [[ "$mode" == "fixed" ]]; then
|
|
# Proxy fijo: captura desde el primer request, sin toggle.
|
|
args+=(--proxy "http://127.0.0.1:${proxy_port}")
|
|
else
|
|
# Modo extension: la extension web_proxy toggle controla el proxy. Se
|
|
# carga desempaquetada y el navegador arranca SIN proxy fijo (toggle
|
|
# OFF por defecto). Un clic en su icono activa la captura.
|
|
args+=(--proxy none --ext "$EXT_DIR")
|
|
info "Extension de captura cargada. Clic en su icono (barra de extensiones) para ACTIVAR el proxy."
|
|
info "El proxy activo por defecto es 127.0.0.1:${proxy_port} (Captura web_proxy)."
|
|
fi
|
|
|
|
# Primera pestaña: la UI de registros en vivo (si el servicio corre en modo
|
|
# web). La UI es loopback y no se proxea, asi que carga directa. Las pestañas
|
|
# a sitios reales pasan por el proxy y aparecen en la UI en tiempo real.
|
|
local ui_url=""
|
|
[[ "$show_ui" == "yes" && -n "$web_port" ]] && ui_url="http://127.0.0.1:${web_port}"
|
|
if [[ -n "$ui_url" ]]; then
|
|
args+=(--url "$ui_url")
|
|
[[ -n "$url" ]] && args+=(--extra "$url")
|
|
local web_pass
|
|
web_pass="$(conf_get WEB_PASS "")"
|
|
[[ -n "$web_pass" ]] && info "UI de registros: login con password '$web_pass' (usuario vacio). Se recuerda en este perfil."
|
|
elif [[ -n "$url" ]]; then
|
|
args+=(--url "$url")
|
|
fi
|
|
bash "$BROWSER_FN" "${args[@]}"
|
|
}
|
|
|
|
# Abre solo la UI de registros en vivo en el navegador por defecto del sistema.
|
|
cmd_ui() {
|
|
local web_port
|
|
web_port="$(conf_get WEB_PORT "")"
|
|
if [[ -z "$web_port" ]]; then
|
|
err "El servicio no corre en modo web. Reinstala con: web_proxy install-service --web"
|
|
return 1
|
|
fi
|
|
local ui_url="http://127.0.0.1:${web_port}"
|
|
local web_pass
|
|
web_pass="$(conf_get WEB_PASS "")"
|
|
info "UI de registros en vivo: $ui_url"
|
|
[[ -n "$web_pass" ]] && info "login con password '$web_pass' (usuario vacio)"
|
|
if command -v xdg-open &>/dev/null; then
|
|
xdg-open "$ui_url" >/dev/null 2>&1 &
|
|
fi
|
|
}
|
|
|
|
# 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 en foreground
|
|
# (systemd gestiona el proceso) con Restart=always. Con --web usa mitmweb, que
|
|
# expone una UI web en vivo (estilo Burp/ZAP) ademas de capturar a disco; sin
|
|
# --web usa mitmdump headless.
|
|
cmd_install_service() {
|
|
local port out rotate enable_linger="no" web="no" web_port web_pass max_mb max_days
|
|
port="$(conf_get PORT "$DEFAULT_PORT")"
|
|
out="$(conf_get OUT "$DEFAULT_OUT")"
|
|
rotate="$(conf_get ROTATE "$DEFAULT_ROTATE")"
|
|
web_port="$(conf_get WEB_PORT "$DEFAULT_WEB_PORT")"
|
|
web_pass="$(conf_get WEB_PASS "")"
|
|
max_mb="$(conf_get MAX_MB "$DEFAULT_MAX_MB")"
|
|
max_days="$(conf_get MAX_DAYS "$DEFAULT_MAX_DAYS")"
|
|
[[ -n "$(conf_get WEB_PORT "")" ]] && web="yes"
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--port) port="$2"; shift 2 ;;
|
|
--out) out="$2"; shift 2 ;;
|
|
--rotate-min) rotate="$2"; shift 2 ;;
|
|
--max-mb) max_mb="$2"; shift 2 ;;
|
|
--max-days) max_days="$2"; shift 2 ;;
|
|
--web) web="yes"; shift ;;
|
|
--web-port) web="yes"; web_port="$2"; shift 2 ;;
|
|
--web-password) web="yes"; web_pass="$2"; shift 2 ;;
|
|
--headless) web="no"; shift ;;
|
|
--linger) enable_linger="yes"; shift ;;
|
|
*) err "install-service: flag desconocido: $1"; return 2 ;;
|
|
esac
|
|
done
|
|
[[ "$web" == "yes" && -z "$web_port" ]] && web_port="$DEFAULT_WEB_PORT"
|
|
# Password estable para la UI (la auth por token de mitmweb cambia en cada
|
|
# arranque; un password fijo da URL estable y cookie persistente en el perfil
|
|
# del navegador). Se genera uno aleatorio la primera vez.
|
|
if [[ "$web" == "yes" && -z "$web_pass" ]]; then
|
|
web_pass="$(tr -dc 'a-z0-9' </dev/urandom 2>/dev/null | head -c 10)"
|
|
[[ -z "$web_pass" ]] && web_pass="webproxy"
|
|
fi
|
|
|
|
local retention="--set max_total_mb=$max_mb --set max_age_days=$max_days"
|
|
local bin="$MITMDUMP_BIN" exec_line
|
|
if [[ "$web" == "yes" ]]; then
|
|
bin="$MITMWEB_BIN"
|
|
exec_line="$MITMWEB_BIN --no-web-open-browser --web-host 127.0.0.1 --web-port $web_port --set web_password=$web_pass -s $ADDON_PATH --set rotate_min=$rotate --set capture_dir=$out --set exclude_hosts=127.0.0.1:$web_port,localhost:$web_port $retention --listen-port $port"
|
|
else
|
|
exec_line="$MITMDUMP_BIN -s $ADDON_PATH --set rotate_min=$rotate --set capture_dir=$out $retention --listen-port $port"
|
|
fi
|
|
if [[ ! -x "$bin" ]]; then
|
|
err "$(basename "$bin") 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" \
|
|
"$([[ "$web" == "yes" ]] && echo "$web_port")" \
|
|
"$([[ "$web" == "yes" ]] && echo "$web_pass")" \
|
|
"$max_mb" "$max_days"
|
|
|
|
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=$exec_line
|
|
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 "$SERVICE_NAME"
|
|
# restart (no enable --now): si el servicio ya estaba activo, --now NO lo
|
|
# reinicia y seguiria corriendo con el unit viejo (password/puerto previos).
|
|
# restart fuerza recarga del unit actual, arrancando si estaba parado.
|
|
systemctl --user restart "$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 " retencion -> max ${max_mb} MB, max ${max_days} dias (borra las mas viejas al rotar)"
|
|
if [[ "$web" == "yes" ]]; then
|
|
ok " UI viva -> http://127.0.0.1:$web_port (registros en tiempo real)"
|
|
info " UI login -> deja el usuario vacio, password: $web_pass"
|
|
fi
|
|
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] [--web] [--web-port N] [--linger]
|
|
Instala + arranca como servicio
|
|
--web: UI de registros en vivo (mitmweb, estilo Burp)
|
|
stop-service / uninstall-service Para / desinstala el servicio
|
|
logs [N] Ultimas N lineas de log
|
|
|
|
Navegacion:
|
|
browser [--url URL] [--port N] [--no-ui] Lanza Chromium proxeado (perfil aislado).
|
|
Abre la UI de registros en vivo como primera pestaña.
|
|
ui Abre solo la UI de registros en el navegador del sistema
|
|
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 "$@" ;;
|
|
ui) cmd_ui "$@" ;;
|
|
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 "$@"
|