8733b7d175
- 0038: lanzar Chrome/Edge/Brave externo con --remote-debugging-port + --user-data-dir por profile, control via CDP desde cdp-cli Go. Decision Go vs C++ in-process documentada; deja la puerta abierta a un cliente C++ minimo solo para streaming en el futuro. Supersedes 0032. - 0039: gestor de cookies/sesiones por profile via CDP — list, export EditThisCookie, import, clear selectivo, health checks con selectores, locks cuando un enricher esta usando el profile. - 0040: profiles como concepto de primera clase — metadata (color, icon, browser_preference, UA, project, template), templates anon/auth/work/ investigation, ProfilePicker reusable, project default, tag en executions.metrics. Actualiza 0038 para apuntar a 0040 como duenio del UX de profiles.
186 lines
7.5 KiB
Markdown
186 lines
7.5 KiB
Markdown
---
|
|
id: 0039
|
|
title: Gestor de cookies y sesiones por profile
|
|
status: pending
|
|
priority: high
|
|
created: 2026-05-04
|
|
depends_on: [0038]
|
|
---
|
|
|
|
## Contexto y objetivo
|
|
|
|
Una vez que `0038` deja al app lanzar browsers externos con
|
|
`--user-data-dir` por profile, las cookies y el `localStorage` quedan
|
|
persistidas automaticamente por Chrome/Edge en disco. Este issue cubre
|
|
la **gestion explicita** de esas sesiones desde graph_explorer:
|
|
visualizarlas, exportarlas, importarlas, limpiarlas y monitorizar cuando
|
|
caducan.
|
|
|
|
Sin esto, los profiles son cajas negras que solo se manipulan abriendo
|
|
el browser. Un OSINT serio necesita ver "que sesiones tengo activas, en
|
|
que dominios, cuando expiran, que hacer si alguna se rompe".
|
|
|
|
## Alcance
|
|
|
|
### 1. Inventario de sesiones (CDP read-only)
|
|
|
|
Panel **Sessions** dentro o junto al panel **Browsers**:
|
|
|
|
```
|
|
┌─ Sessions in profile: linkedin ─────────────────────────┐
|
|
│ Domain Cookies Auth? Expires │
|
|
│ linkedin.com 42 Yes 2026-08-12 │
|
|
│ www.linkedin.com 18 Yes session │
|
|
│ static.licdn.com 6 No 2027-01-01 │
|
|
│ google-analytics.com 3 No 2026-11-01 │
|
|
│ │
|
|
│ [Export profile] [Import .json] [Clear domain] │
|
|
│ [Clear all cookies] [Open browser] │
|
|
└──────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Datos via `Network.getAllCookies` (CDP). Detectar "Auth?" heuristico:
|
|
cookie con flag `httpOnly=true` o nombre matching
|
|
`/sess|auth|token|sid|li_at|c_user/i`.
|
|
|
|
### 2. Export / import de profiles
|
|
|
|
- **Export profile** → `<app>/local_files/exports/<profile>-<date>.json`
|
|
con TODAS las cookies + un manifest (`browser`, `version`,
|
|
`created_at`, `domains`).
|
|
- **Import .json** → escribe via `Network.setCookie` sobre un profile
|
|
vivo. Si el profile no esta vivo, lanzarlo headless solo para inyectar
|
|
y cerrarlo.
|
|
- Formato JSON compatible con la extension EditThisCookie (estandar de
|
|
facto), para que el usuario pueda importar/exportar fuera del app.
|
|
|
|
### 3. Limpieza selectiva
|
|
|
|
| Accion | Implementacion CDP |
|
|
|---|---|
|
|
| Clear all cookies | `Network.clearBrowserCookies` |
|
|
| Clear domain | iterar `getAllCookies` + `deleteCookies` filtrado |
|
|
| Clear cookie | `Network.deleteCookies` con name+domain |
|
|
| Clear localStorage de un origin | `Storage.clearDataForOrigin` |
|
|
|
|
Antes de cualquier "clear all" → confirmacion modal con el numero de
|
|
cookies que se van a perder.
|
|
|
|
### 4. Health check de sesiones autenticadas
|
|
|
|
Por profile, opcional, definir en `<profile>/.fn_session.yaml`:
|
|
|
|
```yaml
|
|
auth_check:
|
|
- name: linkedin
|
|
url: https://www.linkedin.com/feed/
|
|
success_selector: "main[role='main']"
|
|
redirect_to_login_means_failed: true
|
|
- name: google
|
|
url: https://myaccount.google.com
|
|
success_selector: "[data-email]"
|
|
```
|
|
|
|
El app puede lanzar un check por sesion (CDP navigate + check selector)
|
|
y mostrar:
|
|
|
|
```
|
|
linkedin ✓ Authenticated (last check: 2 min ago)
|
|
google ✗ Login expired (redirected to /accounts/signin)
|
|
twitter ? Never checked [check now]
|
|
```
|
|
|
|
Health checks NO son automaticos por defecto — requieren click manual
|
|
para no quemar sesiones con polls innecesarios. Opcion de "check on
|
|
launch" por profile.
|
|
|
|
### 5. Lock / busy state
|
|
|
|
Cuando un enricher esta usando un profile (CDP busy), bloquear acciones
|
|
destructivas (clear, import) en el panel — solo lectura permitida.
|
|
Visual: candado al lado del profile + tooltip "in use by enricher
|
|
fetch_webpage_browser".
|
|
|
|
Lock implementado en `graph_explorer.db` tabla `browser_locks(profile,
|
|
holder, acquired_at)`. TTL 60s por si el holder muere sin liberar.
|
|
|
|
## Schema en `graph_explorer.db`
|
|
|
|
```sql
|
|
CREATE TABLE browser_profiles (
|
|
name TEXT PRIMARY KEY,
|
|
browser_path TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
notes TEXT
|
|
);
|
|
|
|
CREATE TABLE browser_locks (
|
|
profile TEXT PRIMARY KEY REFERENCES browser_profiles(name),
|
|
holder TEXT, -- enricher_id, panel, etc.
|
|
acquired_at TIMESTAMP,
|
|
expires_at TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE browser_session_checks (
|
|
id INTEGER PRIMARY KEY,
|
|
profile TEXT REFERENCES browser_profiles(name),
|
|
check_name TEXT, -- 'linkedin', 'google', ...
|
|
status TEXT, -- 'authenticated' | 'expired' | 'error'
|
|
detail TEXT,
|
|
checked_at TIMESTAMP
|
|
);
|
|
```
|
|
|
|
## Plan de implementacion
|
|
|
|
| Fase | Entregable |
|
|
|---|---|
|
|
| 0039a | `cdp-cli cookies list --profile X` — JSON con todas las cookies por dominio. Lectura via `Network.getAllCookies`. |
|
|
| 0039b | `cdp-cli cookies export --profile X --out file.json` — formato EditThisCookie. |
|
|
| 0039c | `cdp-cli cookies import --profile X --in file.json` — `Network.setCookie` masivo. |
|
|
| 0039d | `cdp-cli cookies clear --profile X [--domain Y]` — clear selectivo. |
|
|
| 0039e | Panel **Sessions** en C++: tabla agregada por dominio, botones de export/import/clear. |
|
|
| 0039f | `cdp-cli session-check --profile X --config <file>.yaml` — health check con selectores. |
|
|
| 0039g | UI de health check en panel Sessions: status por sesion, boton "check now". |
|
|
| 0039h | Locks: implementar `browser_locks` + UI para mostrar profile busy. |
|
|
| 0039i | Migrar profiles preexistentes (creados manualmente) — boton "Register existing folder". |
|
|
|
|
## Riesgos y mitigaciones
|
|
|
|
| Riesgo | Mitigacion |
|
|
|---|---|
|
|
| Importar cookies sobreescribe datos validos | Dialogo de import con preview + opcion "merge" vs "replace". |
|
|
| Export con cookies de auth = secret en disco | `local_files/exports/` con permisos 0600 en POSIX. Warning explicito al exportar. Documentar en panel. |
|
|
| Health check quema rate limit del sitio | Caching: si ultimo check < 5 min, no re-checkear sin force. |
|
|
| Cookies httpOnly no se ven via JS pero si via CDP | Documentar: el panel muestra MAS cookies que las visibles desde DevTools de la pagina. |
|
|
| Diferencias de schema entre Chrome / Edge / Brave | CDP es estandar — mismo subset funciona en todos. Tests por browser en CI manual. |
|
|
|
|
## Definicion de hecho
|
|
|
|
- En el panel **Sessions** del profile `linkedin`, veo 42 cookies
|
|
agrupadas por dominio, con flag de auth detectado y fecha de
|
|
expiracion.
|
|
- Click en **Export profile** genera un JSON valido que la extension
|
|
EditThisCookie puede importar en otro browser.
|
|
- Click en **Clear domain: google-analytics.com** elimina solo esas 3
|
|
cookies sin tocar las demas.
|
|
- Configurando un `auth_check` para LinkedIn y haciendo click en
|
|
**Check now**, el app lanza CDP, navega, evalua el selector y muestra
|
|
`✓ Authenticated` en menos de 4s.
|
|
- Un enricher corriendo sobre `linkedin` bloquea las acciones
|
|
destructivas del panel (boton "Clear all" deshabilitado con tooltip).
|
|
- Cerrar manualmente el browser y volver a lanzarlo desde el panel
|
|
conserva todas las cookies del profile (verificado por el inventario
|
|
pre/post).
|
|
|
|
## Fuera de alcance
|
|
|
|
- Cifrado at-rest del `user-data-dir` — Chrome ya cifra los secrets con
|
|
DPAPI (Windows) / Keychain (Mac). En Linux Chrome usa cifrado debil
|
|
por defecto, pero esta fuera de nuestro control.
|
|
- Sync de profiles entre PCs — los `local_files/browser_profiles/`
|
|
estan gitignorados a proposito (secrets). Si en el futuro hace falta,
|
|
un export manual + import en el otro PC es la via.
|
|
- Auto-renovacion de tokens (cuando un sitio refresca cookies via
|
|
refresh_token) — fuera de v1, demasiado especifico por sitio.
|