From 263547a497be4f08336b3aa9899c5a203986c612 Mon Sep 17 00:00:00 2001 From: fn-registry agent Date: Fri, 5 Jun 2026 17:27:18 +0200 Subject: [PATCH] chore: sync from fn-registry agent --- .gitignore | 17 ++++ CHROMIUM_SYSTEM.md | 208 +++++++++++++++++++++++++++++++++++++++++++++ CONVENTIONS.md | 170 ++++++++++++++++++++++++++++++++++++ analysis/.gitkeep | 0 project.md | 49 +++++++++++ vaults/.gitkeep | 0 6 files changed, 444 insertions(+) create mode 100644 .gitignore create mode 100644 CHROMIUM_SYSTEM.md create mode 100644 CONVENTIONS.md create mode 100644 analysis/.gitkeep create mode 100644 project.md create mode 100644 vaults/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef1f190 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Sub-repos Gitea independientes: cada app y cada analysis tiene su propio .git +# y se versiona en su propio repo dataforge/. El repo del project solo versiona +# las docs de nivel-project (project.md, CONVENTIONS.md, etc.), no el contenido de los hijos. +apps/*/ +analysis/*/ + +# Vaults: datos fuera del repo (symlinks a rutas absolutas), nunca se versionan. +vaults/* +!vaults/.gitkeep + +# Entornos, temporales y estado local +.venv/ +__pycache__/ +*.pyc +node_modules/ +*.log +.DS_Store diff --git a/CHROMIUM_SYSTEM.md b/CHROMIUM_SYSTEM.md new file mode 100644 index 0000000..a8dd766 --- /dev/null +++ b/CHROMIUM_SYSTEM.md @@ -0,0 +1,208 @@ +# Chromium en este equipo: dónde se toca y cómo + +Mapa de referencia de TODOS los puntos donde la configuración de Chromium se manipula en esta +máquina (Linux nativo, Ubuntu 24.04, Chromium 148 del paquete `.deb` de xtradeb — **no snap**). +Objetivo: no volver a redescubrir a ciegas de dónde sale cada comportamiento (extensiones, CDP, +proxy). Reconstruido el 2026-06-05 desde el sistema en vivo + transcripts de sesiones anteriores. + +## El wrapper que une todo + +`/usr/bin/chromium` es un **shell script** (no el binario). En cada arranque hace, en orden: + +1. Sourcea **todos** los archivos de `/etc/chromium.d/*` (cada uno exporta/añade a `CHROMIUM_FLAGS`). +2. Lee las **managed policies** de `/etc/chromium/policies/managed/*.json`. +3. Aplica `master_preferences` (`/etc/chromium/master_preferences`) al crear un perfil nuevo. +4. Lanza el binario real `/usr/lib/chromium/chromium $CHROMIUM_FLAGS "$@"`. + +Por eso cualquier cosa en `/etc/chromium.d/` o en el policy aplica a **TODO** chromium que se +lance, con cualquier perfil. Editar requiere `sudo` (`pass show claude/sudo | sudo -S ...`). + +## Inventario de puntos de configuración + +| Path | Qué controla | Quién/cuándo lo creó | Cómo editar | +|---|---|---|---| +| `/etc/chromium/policies/managed/extensions.json` | **Extensiones force-instaladas en cualquier perfil** (`ExtensionInstallForcelist`). Hoy: solo uBlock Origin Lite. | Proyecto "Code", migración de PC (2026-05-31), 4 extensiones. Reducido a uBlock 2026-06-04. | `fn run apply_chromium_extension_policy --keep ...` (idempotente, backup auto) o `sudo` editar el JSON. Backup: `extensions.json.bak.20260605` (las 4 originales). | +| `/etc/chromium.d/cdp` | **CDP global**: `--remote-debugging-port=9222 --remote-allow-origins=*` (bind loopback). | Proyecto web_scraping (2026-06-05), regla 8. | `fn run apply_chromium_cdp_flag [--remove]` o `sudo` editar/borrar el fragmento. | +| `/etc/chromium.d/web_proxy_ext` | Carga la **extensión de captura del proxy** (`--load-extension=~/.web_proxy/extension`). | Proyecto web_proxy (2026-06-02). | Función `install_chromium_proxy_extension_bash_browser` lo reescribe; `--uninstall` lo borra. | +| `/etc/chromium.d/extensions` | Pre-existente del `.deb`: `--enable-remote-extensions` + carga unpacked de `/usr/share/chromium/extensions/*` (vacío). | Paquete Debian (Jan 2025). | No tocar salvo necesidad. | +| `/etc/chromium.d/default-flags` | Flags base del `.deb`: `--show-component-extension-options`, `--enable-gpu-rasterization`, `--no-default-browser-check`, `--disable-pings`, `--media-router=0`. | Paquete Debian. | No tocar. | +| `/etc/chromium.d/dev-shm` | Añade `--disable-dev-shm-usage` si `/dev/shm` < 3.8 GB. | Paquete Debian. | No tocar. | +| `/etc/chromium.d/apikeys` | `GOOGLE_API_KEY` de Debian (pública, para sync/gmail). | Paquete Debian. | No tocar (no es secreto). | +| `/etc/chromium/master_preferences` | Estado inicial de perfiles nuevos (homepage, DuckDuckGo, signin off). **Sin extensiones.** | Distro. | No tocar para extensiones (no es el sitio). | +| `~/.web_proxy/extension/` | Código de la extensión toggle del proxy (MV3, `chrome.proxy`). | App web_proxy. | Vía `install_chromium_proxy_extension`. | +| `~/.mitmproxy/mitmproxy-ca-cert.pem` | CA de mitmproxy para HTTPS sin warnings. | mitmproxy. | `./web_proxy ca` para instrucciones. | + +**No existe** (verificado): external-extensions dir (`/usr/share/chromium/extensions` está vacío; +`/opt/chromium.org/...` no existe), cron ni systemd-timer que regenere config de chromium, ni +política `recommended/`. La forcelist es un archivo **estático sin regenerador automático del +sistema**; se aplica de forma reproducible con `fn run apply_chromium_extension_policy` (idempotente, +backup automático) o editándola a mano con sudo (también persistente). + +## Extensiones: el mecanismo (LO QUE MÁS CONFUNDE) + +Las extensiones de la Chrome Web Store (uBlock, Dark Reader, NoScript, OneTab) se instalan en +**cualquier perfil** vía `ExtensionInstallForcelist` en el policy managed. Chrome las descarga de +`clients2.google.com/service/update2/crx` al arrancar cualquier perfil (incluido temporal/nuevo) y +quedan "managed" (no removibles por la UI). Para cambiarlas se edita el JSON (sudo). + +- uBlock se usa en la variante **Lite** (`ddkjiahejlhfcafbddmgiahcphecmpfh`, MV3) porque el uBO + clásico (MV2) no carga en Chromium 148. +- IDs: uBlock Lite `ddkjiahejlhfcafbddmgiahcphecmpfh` · Dark Reader `eimadpbcbfnmbkopoojfekhnkhdbieeh` + · NoScript `doojmbjmlfjjnbmnoijecmcbfeoakpjm` · OneTab `chphlpgkkbolifaimnlloiipkdnihall`. + +### Anomalía resuelta (2026-06-05): backups dentro de `managed/` reinyectan extensiones + +Tras reducir la forcelist a solo uBlock **en disco**, los perfiles nuevos seguían instalando las 4 +(incluso un `--user-data-dir` recién creado las recibía como `location=7` external_policy_download, +activas). Causa raíz: **Chromium lee TODOS los archivos del directorio `policies/managed/` sin filtrar +por extensión de nombre.** El backup `extensions.json.bak.20260605` (con las 4 originales) vivía dentro +de `managed/` y Chromium lo mergeaba con `extensions.json`, así que el forcelist efectivo seguía +teniendo las 4 — ganando incluso sobre un `ExtensionInstallBlocklist`. Mover el `.bak` fuera de +`managed/` (a `policies/policy-backups/`) dejó el forcelist efectivo en solo uBlock y los perfiles +nuevos pasaron a instalar únicamente uBlock. + +> Regla dura: en `policies/managed/` (y `recommended/`) **solo** archivos `.json` de política activa. +> Cualquier `.bak`, `.old`, `.orig` ahí se carga como política. La función del registry +> `apply_chromium_extension_policy_bash_browser` ya guarda sus backups fuera de `managed/`. + +El secundario (caché en memoria) también existe: aun con el disco correcto, hay que cerrar TODOS los +Chromium (`pkill -9 chromium`) o pulsar `chrome://policy → Reload policies` para que el cambio surta +efecto en runtime. + +**Para diagnosticar la forcelist EFECTIVA (no la del archivo):** abrir `chrome://policy` en el +navegador y mirar `ExtensionInstallForcelist` (su columna *Source* y *Value*). No es scriptable por +CDP (`chrome.send` no accesible vía `Runtime.evaluate`); hay que verlo en la UI y pulsar +**"Reload policies"**. + +**Para que un cambio en la forcelist surta efecto de verdad:** cerrar **todos** los procesos +chromium a la vez (`pkill -9 chromium`) y relanzar uno; o usar `chrome://policy → Reload policies`. +Mientras quede un chromium vivo con la política vieja, los perfiles nuevos pueden heredarla. + +### Perfil limpio para scraping + +Dos caminos (regla 9 de `CONVENTIONS.md`): + +1. **Perfil nuevo desde cero** + forcelist=solo uBlock → nace solo con uBlock (una vez refrescada + la política). Es lo más limpio; no arrastra nada. +2. **`prepare_chrome_profile`** (clona el perfil real conservando solo uBlock): útil cuando se + necesitan las cookies/sesión del usuario. Borra carpetas de extensiones no-whitelist y purga sus + refs de `Preferences`/`Secure Preferences` (si no, Chrome las re-descarga del Web Store). + +## CDP: mapa de puertos + +| Puerto | Quién | Cómo se activa | +|---|---|---| +| 9222 | Chromium **diario** del usuario | Fragmento `/etc/chromium.d/cdp` (global, loopback). Todo chromium nuevo nace con él. | +| 9333 (o el que se pida) | Navegador de **automatización** dedicado | `script-navegador launch --port 9333` o `systemd-run ... chromium --remote-debugging-port=9333`. Se pasa `--port` para no chocar con el 9222 global. | + +Dos procesos chromium **no** pueden compartir el mismo `--remote-debugging-port`. El `--port` en +cmdline sobreescribe al del fragmento global. + +## Proxy / captura mitm (web_proxy) + +- App: `projects/web_scraping/apps/web_proxy` (sub-repo Gitea `dataforge/web_proxy`). Compone + funciones del registry: `start_mitm_capture`, `query_mitm_flows`, `rotate_capture_flows`, + `launch_chromium_proxy`, `install_chromium_proxy_extension`. +- Servicio `web_proxy.service` (systemd --user, `Restart=always`): mitmdump/mitmweb. +- Puertos: **proxy de captura `127.0.0.1:8889`**, UI mitmweb `http://127.0.0.1:8081`. +- Capturas: `~/captures/traffic-*.mitm`, rotación configurable (`--rotate-min`), retención 2048 MB + / 7 días. El addon hace `flush()` por flujo (sobrevive a kill -9). +- **Enrutar el navegador al proxy — dos vías:** + 1. Extensión toggle `~/.web_proxy/extension`: popup ON → `chrome.proxy` a `127.0.0.1:8889`; OFF → + directo. **Desde 2026-06-05 se instala vía managed policy, no con `--load-extension`** (Chromium + 137+ desactiva `--load-extension` en cuanto hay una managed policy activa: "Loading of unpacked + extensions is disabled by the administrator"). La extensión se empaquetó como `.crx` + (`chromium --pack-extension`, clave en `~/.web_proxy/extension.pem` — NO perder, fija el id + `nanldmckabfghgdebblpfbdbhphhbnde`), con un `~/.web_proxy/update.xml` (`file://`), y se fuerza con + `apply_chromium_extension_policy --keep "=file://$HOME/.web_proxy/update.xml"`. Si se edita la + extensión: re-empaquetar con la MISMA `.pem`, subir `version` en `manifest.json` y `update.xml`. + `/etc/chromium.d/web_proxy_ext` ya NO usa `--load-extension`. + 2. Perfil dedicado: `chromium --proxy-server=127.0.0.1:8889` (+ CA mitmproxy o + `--ignore-certificate-errors` para HTTPS). +- Consultar: `./web_proxy query "~d dominio.com" --last`, `./web_proxy har salida.har`, + `./web_proxy inspect`. + +## "Si quiero X, toco Y" (resumen accionable) + +| Quiero… | Toco… | +|---|---| +| Cambiar qué extensiones tiene cualquier perfil | `fn run apply_chromium_extension_policy --keep ...` (o editar el JSON con sudo) + cerrar TODO chromium + relanzar | +| Activar/quitar CDP global | `fn run apply_chromium_cdp_flag [--remove]` (o editar `/etc/chromium.d/cdp` con sudo) | +| Controlar un chromium con CDP | puerto 9222 (diario) o `script-navegador launch --port N` (dedicado) | +| Capturar tráfico HTTP/HTTPS | `web_proxy` (proxy 8889, UI 8081); navegador con `--proxy-server=127.0.0.1:8889` o extensión toggle ON | +| Perfil de scraping limpio | perfil nuevo desde cero (política da solo uBlock) o `prepare_chrome_profile --src ~/.config/chromium --dst ` | +| Ver la política EFECTIVA | `chrome://policy` en la UI (no por CDP) → "Reload policies" | + +## Selector de perfil — SIEMPRE pasar `--profile-directory` + +Este equipo tiene **varios perfiles** de chromium en `~/.config/chromium`: `Default`, `Personal`, +`Profile 1`, `Automation` (+ `System Profile`). Si se lanza chromium **sin** +`--profile-directory=`, Chrome se queda en el **selector de perfil** y NO carga ninguno. +Consecuencias observadas: + +- CDP responde (`/json/version` OK) pero **no hay perfil activo** → los comandos operan sobre una + ventana vacía. +- Las extensiones **no se procesan**: las force-removed de la política no se desinstalan (fue la + causa real de que las 3 extensiones "no se quitaran" — el diario estaba atascado en el picker). +- La sesión (`--restore-last-session`) no se restaura. + +**Regla: SIEMPRE lanzar con `--profile-directory=""`.** + +- Navegador diario del usuario: `--profile-directory="Default"` (o el que use a diario). +- Navegador de automatización/scraping: `--profile-directory="Automation"` (perfil dedicado), o un + `--user-data-dir` nuevo (que tiene un solo perfil y por tanto no muestra picker). + +```bash +# Diario (visible, con su perfil y CDP global) +systemd-run --user --unit=chromium-daily --collect --setenv=DISPLAY=:0.0 \ + chromium --profile-directory="Default" --restore-last-session + +# Automatización (perfil dedicado, proxy mitm, CDP en puerto propio) +systemd-run --user --unit=ws-explore --collect --setenv=DISPLAY=:0.0 \ + chromium --profile-directory="Automation" --remote-debugging-port=9333 \ + '--remote-allow-origins=*' --proxy-server=127.0.0.1:8889 --ignore-certificate-errors \ + --window-size=1366,768 about:blank +``` + +> Nota: `script-navegador launch` con `--user-data-dir` propio evita el picker (perfil único). Para +> apuntar al perfil real multi-perfil del usuario, añadir `--profile-directory`. + +## Gotchas aprendidos (para no repetir) + +- **`.bak`/`.old`/`.orig` en directorios "source-todo" se activan**: tanto + `/etc/chromium/policies/managed/` como `/etc/chromium.d/` se cargan ENTEROS (todos los archivos, sin + filtrar por extensión de nombre). Un `extensions.json.bak` en `managed/` se mergea como política (y + reinyecta sus extensiones); un `cdp.bak` en `chromium.d/` se sourcea como shell. Guardar SIEMPRE los + backups FUERA de esos directorios (este equipo usa `policies/policy-backups/` y + `chromium/chromiumd-backups/`). +- **Perfil diario real = `~/.config/chromium-cdp`** (lo fuerza `/etc/chromium.d/cdp`), NO + `~/.config/chromium`. Limpiar/inspeccionar el perfil del usuario = operar sobre `chromium-cdp`. +- **Selector de perfil**: con varios perfiles, sin `--profile-directory` Chrome se atasca en el + picker y no carga nada (ver sección arriba). SIEMPRE especificarlo. +- **El archivo de policy en disco ≠ política efectiva**: Chrome cachea; verifica siempre en + `chrome://policy`, no solo con `cat`. Para aplicar cambios, cierra todos los chromium. +- **Lanzar chromium desde el Bash tool de Claude da exit-144** (el harness mata el cgroup). Usa + `systemd-run --user --unit= --collect chromium ...` aislado. Ver memoria + `harness-exit-144-chromium`. (No afecta a binarios Go ni al uso real del usuario.) +- **`--remote-allow-origins=*` debe ir entre comillas en zsh** (el `*` se expande como glob). +- **Dark Reader no toca páginas `chrome://`**: una captura de `chrome://version` sale clara aunque + Dark Reader esté activo; usa una web normal para verificar si está oscureciendo. +- **`prepare_chrome_profile` clonando**: borra carpetas Y purga `Preferences`, pero pueden quedar + refs benignas en `commands`/pins; lo que causa re-descarga es `extensions.settings` (ya se purga). +- **Lock por user-data-dir**: dos procesos chromium NO pueden compartir el mismo `--user-data-dir` + (aunque sea con `--profile-directory` distinto). Si el diario tiene `~/.config/chromium` abierto, + un segundo chromium sobre ese mismo user-data-dir muere/delegará al existente y su + `--remote-debugging-port` no escucha. Para automatización en paralelo: usar un `--user-data-dir` + dedicado (p.ej. `~/.local/share/web_scraping/scrape-fresh`). +- **Ventana visible (headless=false) desde systemd-run**: hay que pasar el entorno gráfico: + `--setenv=DISPLAY=:0 --setenv=XAUTHORITY=$HOME/.Xauthority`. Sin ellos chromium no conecta al X + server y muere. (`DISPLAY` es `:0`, no `:0.0`.) +- **Mover la ventana sin xdotool/wmctrl** (no instalados): usar CDP nativo — + `Browser.getWindowForTarget` (sobre el ws browser-level de `/json/version`) → `windowId`, luego + `Browser.setWindowBounds {left,top,width,height}`. Funciona en modo visible; `windowState:normal` + confirma ventana real. +- **Proxy mitm (8889) ralentiza/cuelga sitios externos**: con `--proxy-server=127.0.0.1:8889`, la + navegación a sitios externos (p.ej. TED) puede tardar mucho o dejar el renderer atascado, y eso + bloquea `open`/`eval`/`shot` sobre esa tab. Para scraping con captura: subir timeouts, o revisar + la salud del upstream del proxy. Sin proxy, en este equipo la salida directa a internet puede dar + `ERR_CONNECTION_RESET` (la red parece pasar por la infra de captura). A revisar. diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 0000000..440d81c --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,170 @@ +# Convenciones del proyecto web_scraping + +Reglas operativas para todo control de navegador y extracción web del proyecto. Aplican a la app +`script_navegador`, a los scripts YAML y a cualquier función del dominio `browser` que se use desde +aquí. Construido 100% sobre Linux nativo (sin WSL/Windows). + +> Nota: estas son **convenciones** (cómo se trabaja), no datos. Los datos extraídos (pliegos, +> RFPs, listados) van en `vaults/` cuando empecemos a capturar. + +## 1. Tamaño de ventana fijo + +Todo navegador se lanza con un tamaño de ventana explícito y estable. Por defecto `1366x768` +(resolución de portátil muy común → menos sospechosa que un viewport raro). + +- Motivo: reproducibilidad de selectores/screenshots y menor superficie de fingerprinting (un + viewport común y consistente es menos señalable que uno aleatorio por sesión). +- Implementación: `script-navegador launch --width 1366 --height 768` (flags `--window-size` a + Chrome). Nunca lanzar sin tamaño definido. + +## 2. Carpeta de usuario dedicada del proyecto + +Siempre se define un `user-data-dir` propio del proyecto, nunca el perfil real del usuario por +defecto (evita locks y contaminación de la sesión personal). + +- Ruta por defecto: `~/.local/share/web_scraping/chrome-profile`. +- Implementación: `script-navegador launch --profile ` (default ya apunta ahí). +- El perfil es persistente entre ejecuciones (cookies, login, estado de extensiones). + +## 3. Flujo headless: primero visible, luego headless + +Se empieza desarrollando **con ventana visible** (`headless=false`) para ver lo que pasa y depurar +selectores junto al humano. Solo cuando un flujo está estandarizado y probado se pasa a +`headless=true` para correrlo desatendido/en lote. + +- Default de `launch`: `headless=false`. +- Promoción a headless: pasar `--headless` una vez el script YAML del flujo es estable. + +## 4. Esperas inteligentes + pequeños sleeps aleatorios + +Nunca `sleep` ciegos fijos como mecanismo de sincronización. Se espera a **condiciones reales**: + +- `readyState=complete` (`cdp_wait_load`). +- **Red en reposo** (`cdp_wait_idle`): nº de peticiones HTTP/WS en vuelo == 0 durante N ms + (señal "network idle"). Es inmune a extensiones que mutan el DOM y a animaciones JS. Timeout + corto (8s) porque páginas con polling/websockets persistentes pueden no llegar nunca a 0. +- Selector presente (`cdp_wait_element`). + +Sobre esas esperas se añaden **micro-pausas aleatorias < 500 ms** (`jitter`) entre acciones, para +imitar el ritmo humano (anti-detección). El random es complemento, no sustituto, de la espera real. + +> Histórico: `cdp_wait_idle` usó al principio la longitud de `innerHTML` como señal de quietud, +> pero con extensiones como Dark Reader (que reinyecta estilos sin parar) el DOM nunca se +> estabilizaba y la espera agotaba siempre el timeout. Por eso se migró a network-idle. + +## 5. Captura de datos vía extensión mitm (web_proxy) + +El tráfico se puede capturar con la infraestructura `web_proxy` (mitmproxy + extensión de toggle +ya presente en `/etc/chromium.d/`). Por eso los navegadores se lanzan con `--keep-extensions` +(no `--disable-extensions`): la extensión de captura debe seguir cargada. + +- mitmweb corre en `127.0.0.1:8081`; el proxy de captura en `:8889`. +- Las capturas rotan a `~/captures` (ver `rotate_capture_flows.py`). +- El toggle del proxy es per-perfil; activarlo en el perfil del proyecto cuando se quiera capturar. + +## 6. Movimientos de ratón + clics realistas + +Las interacciones (click, drag) deben simular trayectorias humanas (curvas, aceleración, micro- +desvíos), no saltos instantáneos a coordenadas. **Stack decidido: Go puro** — curvas Bézier sobre +`Input.dispatchMouseEvent` como funciones del registry (`cdp_move_mouse_human`, `cdp_click_human`), +sin dependencias externas. **Integrado y por defecto** (script_navegador v0.2.0): el comando `click` y +la acción `click` del runner YAML usan Bézier sin pedir nada. Opt-out con `--instant` (CLI) o +`instant: true` (paso YAML) cuando el elemento no tiene bounding box visible y conviene el click directo. + +## 7. Proxys rotativos (Decodo) — futuro + +Más adelante se integrarán proxys residenciales rotativos con **Decodo** (antes Smartproxy) para +distribuir las peticiones y evitar bloqueos por IP. Pendiente de implementar (ver +`## Pendientes`). + +## 8. CDP siempre activo en el navegador del usuario — futuro / decisión de seguridad + +Objetivo: poder usar las capacidades de automatización sobre el **chromium que el usuario usa a +diario** mientras navega, modificando el launcher (`/etc/chromium.d/`) para que todo chromium +nazca con CDP activado. + +**APLICADO** (2026-06-05): fragmento `/etc/chromium.d/cdp` con +`--remote-debugging-port=9222 --remote-allow-origins=*`, **sin** `--remote-debugging-address=0.0.0.0` +→ el puerto bindea solo en loopback (127.0.0.1), no accesible desde la red. Todo chromium que el +usuario abra a partir de ahora nace con CDP. (El chromium ya abierto antes del cambio no tiene CDP +hasta reiniciarlo.) + +Reproducible entre PCs con la función del registry `apply_chromium_cdp_flag_bash_browser` (no +editar el fragmento a mano): + +```bash +fn run apply_chromium_cdp_flag # escribe /etc/chromium.d/cdp (loopback 9222, idempotente) +fn run apply_chromium_cdp_flag --dry-run # previsualiza sin tocar nada +fn run apply_chromium_cdp_flag --remove # desactiva CDP global +# --network añade --remote-debugging-address=0.0.0.0 (expone a la red: riesgo, ver Gotchas) +``` + +> Coordinación de puertos: el chromium diario ocupa el 9222 global. Para sesiones de automatización +> con perfil dedicado, lanzar en OTRO puerto: `script-navegador launch --port 9333`. Dos procesos +> chromium no pueden compartir el mismo `--remote-debugging-port`. + +> ⚠️ Implicación de seguridad: con CDP abierto, **cualquier proceso local del usuario** puede +> controlar el navegador y leer cookies/sesiones autenticadas. El bind solo-local evita acceso +> desde la red, pero NO protege de procesos locales. Aceptado conscientemente para este equipo +> de un solo usuario. No replicar en máquinas compartidas/multiusuario. + +## 9. Perfiles nuevos: solo uBlock Origin Lite + +Al **preparar un perfil de usuario nuevo** para automatización (clonando del perfil real del +usuario), se conserva **únicamente uBlock Origin Lite** (`ddkjiahejlhfcafbddmgiahcphecmpfh`) y se +eliminan el resto de extensiones del usuario. + +- Motivo: uBlock reduce ruido (anuncios, trackers) → páginas más limpias y rápidas de scrapear. + Las demás estorban la automatización: + - **Dark Reader**: reinyecta estilos sin parar → rompe esperas por DOM y oscurece screenshots. + - **NoScript**: bloquea JavaScript → rompe SPAs y scraping de contenido dinámico. + - **OneTab**: interfiere con la gestión de pestañas. +- La extensión de captura `web_proxy` es **aparte**: se carga globalmente vía `/etc/chromium.d/` + (no es una extensión del perfil), por lo que esta regla no la toca. uBlock + web_proxy conviven. + +### Dos mecanismos (sistema + clonado) + +1. **Política de sistema (primario)** — `/etc/chromium/policies/managed/extensions.json` con + `ExtensionInstallForcelist` fuerza la instalación de extensiones en **cualquier perfil** de + chromium del equipo. Reducido el 2026-06-05 a **solo uBlock Origin Lite** + (`ddkjiahejlhfcafbddmgiahcphecmpfh`). Antes forzaba 4 (uBlock + Dark Reader + NoScript + + OneTab). Esto garantiza que todo perfil nuevo —lo cree quien lo cree— nazca solo con uBlock, + sin pasos extra. Backup del original en `extensions.json.bak.20260605`. + - ⚠️ Afecta también el perfil diario del usuario: al reiniciar chromium, las extensiones que + ya no están en la forcelist se desinstalan. + - Editar requiere `sudo` (`pass claude/sudo`). + - Reproducible entre PCs con la función del registry `apply_chromium_extension_policy_bash_browser` + (no editar el JSON a mano): escribe la forcelist de forma idempotente con backup automático. + + ```bash + # Forzar solo uBlock Origin Lite en todos los perfiles + fn run apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh + fn run apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh --dry-run + ``` + +2. **Clonado con filtro (secundario)** — `prepare_chrome_profile --src ~/.config/chromium + --dst ` clona un perfil existente (cookies, sesiones) conservando solo la + whitelist de extensiones (`--keep `, default uBlock). Útil cuando se quiere arrancar de + una copia del perfil real; la base de extensiones ya la garantiza la política de sistema. + +--- + +## Pendientes (decisiones abiertas) + +| # | Tema | Estado | +|---|---|---| +| 7 | Proxys rotativos con Decodo | Futuro, sin empezar | + +## Estado de implementación + +| Regla | Estado | Dónde | +|---|---|---| +| 1. Tamaño de ventana fijo | ✅ | `script-navegador launch --width/--height` (default 1366x768) | +| 2. Carpeta de usuario del proyecto | ✅ | `--profile` (default `~/.local/share/web_scraping/chrome-profile`) | +| 3. Flujo headless visible→true | ✅ convención | `launch` default `headless=false` | +| 4. Esperas inteligentes + jitter | ✅ | `cdp_wait_load`+`cdp_wait_idle` (network-idle)+`jitter()` | +| 5. Captura mitm | ✅ infra | `--keep-extensions` + `web_proxy` | +| 6. Ratón/clics realistas | ✅ | `cdp_move_mouse_human` + `cdp_click_human`; default en `script-navegador click` y runner YAML (opt-out `--instant` / `instant: true`) | +| 7. Proxys rotativos Decodo | ⏳ | futuro | +| 8. CDP global en chromium usuario | ✅ | `/etc/chromium.d/cdp` aplicado (loopback 9222) | +| 9. Perfiles nuevos solo uBlock | ✅ | `prepare_chrome_profile --src ~/.config/chromium --dst ` | diff --git a/analysis/.gitkeep b/analysis/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/project.md b/project.md new file mode 100644 index 0000000..5d059fc --- /dev/null +++ b/project.md @@ -0,0 +1,49 @@ +--- +name: web_scraping +description: "Plataforma de control de navegador y automatización web sobre Chrome via CDP en Linux nativo. Base reutilizable para scraping, automatización de tareas web, descubrimiento de endpoints/APIs para pentesting y captura de tráfico." +tags: [scraping, browser, cdp, automation, pentesting, linux] +repo_url: "" +--- + +## Notas + +Proyecto paraguas, de uso continuo, para todo lo relacionado con control de navegador y trabajo +sobre la web. No está atado a ningún dominio concreto: cualquier tarea de scraping, automatización +o reconocimiento web se hace y se capitaliza aquí. Construido 100% sobre Linux nativo (sin +dependencia de WSL/Windows). El control del navegador se hace con Chrome DevTools Protocol (CDP) +crudo a través de las funciones del dominio `browser` del registry, no con Playwright/Selenium. + +### Para qué sirve + +- **Web scraping**: extracción de datos de páginas y APIs, con o sin login, incluyendo SPAs. +- **Automatización web**: rellenar formularios, flujos multi-paso, tareas repetitivas en webapps. +- **Descubrimiento de endpoints (pentesting / recon)**: capturar el tráfico HTTP/WS que genera una + página (`cdp_har_record` + extensión mitm de `web_proxy`) para mapear las APIs reales que usa, + detectar endpoints ocultos y analizar peticiones. +- **Captura de tráfico**: interceptación y registro de flujos vía mitmproxy para análisis posterior. +- **Monitoreo / testing**: vigilar cambios en páginas, validar comportamiento, smoke de webs. + +### Componentes + +| Componente | Tipo | Estado | Qué hace | +|---|---|---|---| +| `script_navegador` | app (Go) | activo | Controlador de navegador: modo CLI rápido (comandos sueltos: open/click/type/eval/shot/tabs) + runner de scripts YAML. Compone funciones `cdp_*` del registry. | +| `web_proxy` | app (bash) | externo | Proxy de interceptación HTTP/HTTPS (mitmproxy). Vive en `apps/web_proxy`; provee la captura de tráfico que consume este proyecto. | +| vaults | datos | reservado | Datos extraídos por cada campaña (scrapes, HARs, listados, capturas). | +| analysis | exploración | reservado | Notebooks sobre los datos extraídos / capturados. | + +### Filosofía + +- **Registry-first**: toda capacidad reutilizable de navegador (lanzar Chrome, navegar, click, + type, screenshot, esperas inteligentes, captura HAR) vive en `functions/browser/` del registry. + La app solo orquesta: parsea comandos y compone funciones. Lo que sirva para una campaña sirve + para todas. +- **Esperas inteligentes siempre**: los scripts y comandos esperan condiciones reales del DOM + (readyState, selector presente, DOM estabilizado) en lugar de `sleep` ciegos. Ver + `CONVENTIONS.md`. +- **Linux nativo**: lanzamiento directo de `chromium`/`google-chrome` con `os/exec`, sin + `wslpath`, sin `chrome.exe`, sin proxies WSL↔Windows. + +Las reglas operativas (tamaño de ventana, perfil del proyecto, headless, jitter, captura, +movimientos realistas, proxys rotativos, CDP en el navegador del usuario) están en +`CONVENTIONS.md`. diff --git a/vaults/.gitkeep b/vaults/.gitkeep new file mode 100644 index 0000000..e69de29