Files
fn_registry/functions/browser/cdp_load_storage_state.go
T
egutierrez 5b10b419a2 feat(browser): auto-commit con 44 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 12:49:54 +02:00

99 lines
3.1 KiB
Go

package browser
import (
"encoding/json"
"fmt"
"os"
"strings"
)
// jsQuote serializa s como literal string JavaScript con comillas dobles y
// caracteres escapados correctamente. Usa json.Marshal internamente para
// reutilizar el mismo escapado que JSON (compatible con JS).
func jsQuote(s string) string {
b, err := json.Marshal(s)
if err != nil {
// Fallback seguro: comillas dobles escapando backslash y comilla doble
return fmt.Sprintf("%q", s)
}
return string(b)
}
// CdpLoadStorageState lee el JSON generado por CdpSaveStorageState y restaura
// cookies y localStorage en la pestaña activa. Permite retomar una sesion
// autenticada sin repetir el login.
//
// CRITICO: el localStorage es por-origen. Antes de llamar a esta funcion hay
// que haber navegado al origen correcto (CdpNavigate al dominio). Orden
// correcto: navegar -> CdpLoadStorageState -> recargar pagina.
func CdpLoadStorageState(c *CDPConn, inPath string) error {
if c == nil {
return fmt.Errorf("cdp load storage state: conexion nula")
}
if inPath == "" {
return fmt.Errorf("cdp load storage state: inPath vacio")
}
data, err := os.ReadFile(inPath)
if err != nil {
return fmt.Errorf("cdp load storage state: leer archivo: %w", err)
}
var state CdpStorageState
if err := json.Unmarshal(data, &state); err != nil {
return fmt.Errorf("cdp load storage state: unmarshal: %w", err)
}
// Habilitar dominio Network para manipular cookies
if _, err := c.sendCDP("Network.enable", nil); err != nil {
return fmt.Errorf("cdp load storage state: Network.enable: %w", err)
}
// Restaurar cookies. Network.setCookies aplica de forma fiable las cookies
// (sobre todo httpOnly y de sesión) cuando cada una lleva el campo `url`: de
// ahí deriva scheme y scope. getAllCookies no lo incluye, así que lo
// sintetizamos a partir de domain/secure/path cuando falta.
if len(state.Cookies) > 0 {
for _, ck := range state.Cookies {
if _, has := ck["url"]; has {
continue
}
dom, _ := ck["domain"].(string)
dom = strings.TrimPrefix(dom, ".")
if dom == "" {
continue
}
scheme := "http"
if sec, _ := ck["secure"].(bool); sec {
scheme = "https"
}
path, _ := ck["path"].(string)
if path == "" {
path = "/"
}
ck["url"] = scheme + "://" + dom + path
}
if _, err := c.sendCDP("Network.setCookies", map[string]any{
"cookies": state.Cookies,
}); err != nil {
return fmt.Errorf("cdp load storage state: setCookies: %w", err)
}
}
// Restaurar localStorage y sessionStorage — setItem por cada par clave/valor
for k, v := range state.LocalStorage {
expr := fmt.Sprintf("window.localStorage.setItem(%s, %s)", jsQuote(k), jsQuote(v))
if _, err := CdpEvaluate(c, expr); err != nil {
return fmt.Errorf("cdp load storage state: localStorage setItem %q: %w", k, err)
}
}
for k, v := range state.SessionStorage {
expr := fmt.Sprintf("window.sessionStorage.setItem(%s, %s)", jsQuote(k), jsQuote(v))
if _, err := CdpEvaluate(c, expr); err != nil {
return fmt.Errorf("cdp load storage state: sessionStorage setItem %q: %w", k, err)
}
}
return nil
}