feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""Lanza Chromium en un perfil del catalogo osint_db y expone sus cuentas/secret_refs.
|
||||
|
||||
Wrapper que compone `browser_profile_show` (para leer la metadata del perfil y sus
|
||||
cuentas desde el service osint_db) y luego lanza Chromium en ese perfil. Devuelve las
|
||||
cuentas con sus `secret_ref` (REFERENCIAS a secretos, nunca el password) para que el
|
||||
operador sepa que credenciales usar.
|
||||
|
||||
GOTCHAS de este entorno (Linux nativo de enmanuel):
|
||||
- El wrapper `/usr/bin/chromium` ya inyecta `--user-data-dir=$HOME/.config/chromium-cdp`
|
||||
y `--remote-debugging-port=9222` via `/etc/chromium.d/cdp`. Por eso, si el
|
||||
`user_data_dir` resuelto ES ese default, NO se pasa `--user-data-dir` (se hereda del
|
||||
wrapper); si es OTRO directorio, se pasa explicito.
|
||||
- Lanzar chromium directamente como hijo da exit-144 en este entorno. Se lanza SIEMPRE
|
||||
via `systemd-run --user --scope --` (proceso aislado), en background, sin esperar.
|
||||
|
||||
Funcion impura: hace red (HTTP al service) y lanza un proceso. No lanza excepciones;
|
||||
devuelve un dict de estado. Con `dry_run=True` no abre nada (devuelve el comando).
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from browser.browser_profile_show import browser_profile_show
|
||||
|
||||
# Default del wrapper /etc/chromium.d/cdp en esta maquina (se compara expandido).
|
||||
_DEFAULT_USER_DATA_DIR = os.path.expanduser("~/.config/chromium-cdp")
|
||||
|
||||
|
||||
def browser_profile_open(
|
||||
profile_dir: str,
|
||||
url: str | None = None,
|
||||
base_url: str = "http://127.0.0.1:8771",
|
||||
dry_run: bool = False,
|
||||
) -> dict:
|
||||
"""Lanza Chromium en el perfil indicado y devuelve sus cuentas/secret_refs.
|
||||
|
||||
Args:
|
||||
profile_dir: nombre del directorio real del perfil Chromium (ej. "Profile 1",
|
||||
"osint_01"). Debe existir en el catalogo osint_db.
|
||||
url: URL a abrir al arrancar (ej. "https://mail.google.com"). None -> sin URL.
|
||||
base_url: base del service osint_db. Default http://127.0.0.1:8771.
|
||||
dry_run: si True, NO lanza nada; devuelve el comando que lanzaria. Util para test
|
||||
y para revisar el comando antes de abrir el navegador.
|
||||
|
||||
Returns:
|
||||
Caso dry_run ok: {"status":"ok", "profile_dir": str, "cmd": list[str] (argv que
|
||||
se lanzaria), "accounts": list de dicts {service, identity, secret_ref, role}}.
|
||||
Caso real ok: {"status":"ok", "profile_dir": str, "launched": True,
|
||||
"cmd": list[str], "accounts": list de dicts {service, identity, secret_ref, role}}.
|
||||
Caso perfil no existe / service caido: {"status":"error", "error": str} (no lanza).
|
||||
"""
|
||||
try:
|
||||
meta = browser_profile_show(profile_dir, base_url=base_url)
|
||||
if meta.get("status") != "ok":
|
||||
# Perfil inexistente o service caido: propaga el error sin lanzar nada.
|
||||
return meta
|
||||
|
||||
profile = meta.get("profile", {})
|
||||
raw_accounts = meta.get("accounts", [])
|
||||
accounts = [
|
||||
{
|
||||
"service": a.get("service"),
|
||||
"identity": a.get("identity"),
|
||||
"secret_ref": a.get("secret_ref"),
|
||||
"role": a.get("role"),
|
||||
}
|
||||
for a in raw_accounts
|
||||
]
|
||||
|
||||
# Resolver user_data_dir: el de la fila si no esta vacio; si no, el default del wrapper.
|
||||
row_udd = (profile.get("user_data_dir") or "").strip()
|
||||
resolved_udd = os.path.expanduser(row_udd) if row_udd else _DEFAULT_USER_DATA_DIR
|
||||
|
||||
chromium_args = ["chromium", f'--profile-directory={profile_dir}']
|
||||
# Solo pasar --user-data-dir si NO es el default del wrapper (que ya lo inyecta).
|
||||
if os.path.normpath(resolved_udd) != os.path.normpath(_DEFAULT_USER_DATA_DIR):
|
||||
chromium_args.append(f"--user-data-dir={resolved_udd}")
|
||||
if url:
|
||||
chromium_args.append(url)
|
||||
|
||||
# Lanzamiento aislado para evitar exit-144 (ver gotcha del modulo).
|
||||
cmd = ["systemd-run", "--user", "--scope", "--", *chromium_args]
|
||||
|
||||
if dry_run:
|
||||
return {
|
||||
"status": "ok",
|
||||
"profile_dir": profile_dir,
|
||||
"cmd": cmd,
|
||||
"accounts": accounts,
|
||||
}
|
||||
|
||||
# Background, sin esperar: no bloquear al operador ni capturar el navegador.
|
||||
subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True,
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"profile_dir": profile_dir,
|
||||
"launched": True,
|
||||
"cmd": cmd,
|
||||
"accounts": accounts,
|
||||
}
|
||||
except Exception as e: # noqa: BLE001 - contrato: nunca lanzar
|
||||
return {"status": "error", "error": f"{type(e).__name__}: {e}"}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Smoke contra un puerto muerto: el service caido -> browser_profile_show falla,
|
||||
# browser_profile_open propaga el error sin abrir navegador.
|
||||
res = browser_profile_open("Profile 1", url="https://example.com",
|
||||
base_url="http://127.0.0.1:1", dry_run=True)
|
||||
assert res["status"] == "error", res
|
||||
print("browser_profile_open smoke OK (service caido -> status error, sin lanzar)")
|
||||
print(f" {res}")
|
||||
Reference in New Issue
Block a user