feat(browser): auto-commit con 60 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,21 +15,45 @@ type CdpStorageState struct {
|
||||
SessionStorage map[string]string `json:"sessionStorage"`
|
||||
}
|
||||
|
||||
// readWebStorage lee window.<store> (localStorage|sessionStorage) como mapa. Si el
|
||||
// origen no permite acceso (about:blank, chrome://) devuelve un mapa vacío.
|
||||
func readWebStorage(c *CDPConn, store string) map[string]string {
|
||||
// isStorageAccessDenied reconoce el error de CdpEvaluate cuando el origen no
|
||||
// permite acceder a window.localStorage/sessionStorage (about:blank, chrome://,
|
||||
// data:, sandbox sin allow-same-origin): el navegador lanza SecurityError. Es
|
||||
// puro: decide a partir del texto del error. Distingue ese caso legítimo (no hay
|
||||
// storage que guardar -> {}) de un error real (conexión caída, JS roto) que SÍ
|
||||
// debe propagarse para no escribir una sesión incompleta en silencio.
|
||||
func isStorageAccessDenied(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
s := err.Error()
|
||||
return strings.Contains(s, "SecurityError") ||
|
||||
strings.Contains(s, "Access is denied") ||
|
||||
strings.Contains(s, "operation is insecure") ||
|
||||
strings.Contains(s, "denied for this document")
|
||||
}
|
||||
|
||||
// readWebStorage lee window.<store> (localStorage|sessionStorage) como mapa.
|
||||
// Distingue tres casos:
|
||||
// - storage accesible (con o sin datos) -> (mapa, nil)
|
||||
// - origen sin storage accesible (about:blank, chrome://) -> ({}, nil)
|
||||
// - error REAL de evaluación (conexión caída, JS roto, JSON inválido) -> (nil, error)
|
||||
func readWebStorage(c *CDPConn, store string) (map[string]string, error) {
|
||||
raw, err := CdpEvaluate(c, "JSON.stringify(Object.assign({}, window."+store+"))")
|
||||
if err != nil {
|
||||
return map[string]string{}
|
||||
if isStorageAccessDenied(err) {
|
||||
// Origen sin storage accesible: vacío legítimo, no error.
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("leer %s: %w", store, err)
|
||||
}
|
||||
if raw == "" || raw == "undefined" || raw == "null" {
|
||||
return map[string]string{}
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
var m map[string]string
|
||||
if err := json.Unmarshal([]byte(raw), &m); err != nil {
|
||||
return map[string]string{}
|
||||
return nil, fmt.Errorf("parsear %s: %w", store, err)
|
||||
}
|
||||
return m
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// cookieDomainMatchesHost indica si una cookie con `domain` aplica al `host` dado.
|
||||
@@ -100,11 +124,21 @@ func CdpSaveStorageState(c *CDPConn, outPath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Capturar localStorage y sessionStorage del origen actualmente cargado.
|
||||
// Capturar localStorage y sessionStorage del origen actualmente cargado. Un
|
||||
// error real (no un origen sin storage) aborta el guardado: mejor fallar que
|
||||
// escribir una sesión incompleta que el caller creería válida.
|
||||
localStorage, err := readWebStorage(c, "localStorage")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cdp save storage state: %w", err)
|
||||
}
|
||||
sessionStorage, err := readWebStorage(c, "sessionStorage")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cdp save storage state: %w", err)
|
||||
}
|
||||
state := CdpStorageState{
|
||||
Cookies: cookies,
|
||||
LocalStorage: readWebStorage(c, "localStorage"),
|
||||
SessionStorage: readWebStorage(c, "sessionStorage"),
|
||||
LocalStorage: localStorage,
|
||||
SessionStorage: sessionStorage,
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(state, "", " ")
|
||||
|
||||
Reference in New Issue
Block a user