package browser import ( "context" "fmt" "time" ) // Cookie representa una cookie. type Cookie struct { Name string `json:"name"` Value string `json:"value"` Domain string `json:"domain,omitempty"` Path string `json:"path,omitempty"` Expires float64 `json:"expires,omitempty"` // Unix timestamp HTTPOnly bool `json:"httpOnly,omitempty"` Secure bool `json:"secure,omitempty"` SameSite string `json:"sameSite,omitempty"` // "Strict", "Lax", "None" } // GetCookies obtiene todas las cookies o las de un dominio específico. func (b *Browser) GetCookies(ctx context.Context, urls ...string) ([]*Cookie, error) { params := make(map[string]interface{}) if len(urls) > 0 { params["urls"] = urls } var result struct { Cookies []*Cookie `json:"cookies"` } if err := b.cdpClient.Execute(ctx, "Network.getCookies", params, &result); err != nil { return nil, fmt.Errorf("failed to get cookies: %w", err) } return result.Cookies, nil } // SetCookie establece una cookie. func (b *Browser) SetCookie(ctx context.Context, cookie *Cookie) error { params := map[string]interface{}{ "name": cookie.Name, "value": cookie.Value, } if cookie.Domain != "" { params["domain"] = cookie.Domain } if cookie.Path != "" { params["path"] = cookie.Path } if cookie.Expires > 0 { params["expires"] = cookie.Expires } if cookie.HTTPOnly { params["httpOnly"] = true } if cookie.Secure { params["secure"] = true } if cookie.SameSite != "" { params["sameSite"] = cookie.SameSite } var result struct { Success bool `json:"success"` } if err := b.cdpClient.Execute(ctx, "Network.setCookie", params, &result); err != nil { return fmt.Errorf("failed to set cookie: %w", err) } if !result.Success { return fmt.Errorf("failed to set cookie: %s", cookie.Name) } return nil } // SetCookies establece múltiples cookies. func (b *Browser) SetCookies(ctx context.Context, cookies []*Cookie) error { for _, cookie := range cookies { if err := b.SetCookie(ctx, cookie); err != nil { return err } } return nil } // DeleteCookie elimina una cookie específica. func (b *Browser) DeleteCookie(ctx context.Context, name string, domain string) error { params := map[string]interface{}{ "name": name, } if domain != "" { params["domain"] = domain } return b.cdpClient.Execute(ctx, "Network.deleteCookies", params, nil) } // ClearCookies elimina todas las cookies. func (b *Browser) ClearCookies(ctx context.Context) error { return b.cdpClient.Execute(ctx, "Network.clearBrowserCookies", nil, nil) } // LocalStorageItem representa un item de localStorage. type LocalStorageItem struct { Key string `json:"key"` Value string `json:"value"` } // GetLocalStorage obtiene todos los items del localStorage. func (b *Browser) GetLocalStorage(ctx context.Context) ([]*LocalStorageItem, error) { script := ` (() => { const items = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); items.push({ key: key, value: localStorage.getItem(key) }); } return items; })() ` var result struct { Result struct { Value []map[string]interface{} `json:"value"` } `json:"result"` } params := map[string]interface{}{ "expression": script, "returnByValue": true, } if err := b.cdpClient.Execute(ctx, "Runtime.evaluate", params, &result); err != nil { return nil, fmt.Errorf("failed to get localStorage: %w", err) } items := make([]*LocalStorageItem, 0, len(result.Result.Value)) for _, item := range result.Result.Value { items = append(items, &LocalStorageItem{ Key: item["key"].(string), Value: item["value"].(string), }) } return items, nil } // SetLocalStorage establece un item en localStorage. func (b *Browser) SetLocalStorage(ctx context.Context, key, value string) error { script := fmt.Sprintf(`localStorage.setItem(%q, %q)`, key, value) params := map[string]interface{}{ "expression": script, } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // RemoveLocalStorage elimina un item de localStorage. func (b *Browser) RemoveLocalStorage(ctx context.Context, key string) error { script := fmt.Sprintf(`localStorage.removeItem(%q)`, key) params := map[string]interface{}{ "expression": script, } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // ClearLocalStorage limpia todo el localStorage. func (b *Browser) ClearLocalStorage(ctx context.Context) error { params := map[string]interface{}{ "expression": "localStorage.clear()", } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // GetSessionStorage obtiene todos los items del sessionStorage. func (b *Browser) GetSessionStorage(ctx context.Context) ([]*LocalStorageItem, error) { script := ` (() => { const items = []; for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i); items.push({ key: key, value: sessionStorage.getItem(key) }); } return items; })() ` var result struct { Result struct { Value []map[string]interface{} `json:"value"` } `json:"result"` } params := map[string]interface{}{ "expression": script, "returnByValue": true, } if err := b.cdpClient.Execute(ctx, "Runtime.evaluate", params, &result); err != nil { return nil, fmt.Errorf("failed to get sessionStorage: %w", err) } items := make([]*LocalStorageItem, 0, len(result.Result.Value)) for _, item := range result.Result.Value { items = append(items, &LocalStorageItem{ Key: item["key"].(string), Value: item["value"].(string), }) } return items, nil } // SetSessionStorage establece un item en sessionStorage. func (b *Browser) SetSessionStorage(ctx context.Context, key, value string) error { script := fmt.Sprintf(`sessionStorage.setItem(%q, %q)`, key, value) params := map[string]interface{}{ "expression": script, } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // RemoveSessionStorage elimina un item de sessionStorage. func (b *Browser) RemoveSessionStorage(ctx context.Context, key string) error { script := fmt.Sprintf(`sessionStorage.removeItem(%q)`, key) params := map[string]interface{}{ "expression": script, } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // ClearSessionStorage limpia todo el sessionStorage. func (b *Browser) ClearSessionStorage(ctx context.Context) error { params := map[string]interface{}{ "expression": "sessionStorage.clear()", } return b.cdpClient.Execute(ctx, "Runtime.evaluate", params, nil) } // StorageType tipo de storage. type StorageType string const ( StorageTypeCookies StorageType = "cookies" StorageTypeLocalStorage StorageType = "local_storage" StorageTypeSessionStorage StorageType = "session_storage" StorageTypeIndexedDB StorageType = "indexeddb" StorageTypeWebSQL StorageType = "websql" StorageTypeCacheStorage StorageType = "cache_storage" ) // ClearDataForOrigin limpia datos de un origen específico. func (b *Browser) ClearDataForOrigin(ctx context.Context, origin string, storageTypes ...StorageType) error { if len(storageTypes) == 0 { // Por defecto, limpiar todo storageTypes = []StorageType{ StorageTypeCookies, StorageTypeLocalStorage, StorageTypeSessionStorage, StorageTypeIndexedDB, StorageTypeWebSQL, StorageTypeCacheStorage, } } // Convertir a string separado por comas types := "" for i, st := range storageTypes { if i > 0 { types += "," } types += string(st) } params := map[string]interface{}{ "origin": origin, "storageTypes": types, } return b.cdpClient.Execute(ctx, "Storage.clearDataForOrigin", params, nil) } // ExportCookies exporta las cookies del perfil a un archivo JSON. func (b *Browser) ExportCookies(ctx context.Context) ([]*Cookie, error) { return b.GetCookies(ctx) } // ImportCookies importa cookies desde un slice. func (b *Browser) ImportCookies(ctx context.Context, cookies []*Cookie) error { return b.SetCookies(ctx, cookies) } // CreateCookie crea una cookie helper. func CreateCookie(name, value, domain string) *Cookie { return &Cookie{ Name: name, Value: value, Domain: domain, Path: "/", // Expira en 1 año Expires: float64(time.Now().Add(365 * 24 * time.Hour).Unix()), HTTPOnly: false, Secure: false, SameSite: "Lax", } } // CreateSessionCookie crea una cookie de sesión (sin expiración). func CreateSessionCookie(name, value, domain string) *Cookie { return &Cookie{ Name: name, Value: value, Domain: domain, Path: "/", HTTPOnly: false, Secure: false, SameSite: "Lax", } } // CreateSecureCookie crea una cookie segura (HTTPS only). func CreateSecureCookie(name, value, domain string) *Cookie { return &Cookie{ Name: name, Value: value, Domain: domain, Path: "/", Expires: float64(time.Now().Add(365 * 24 * time.Hour).Unix()), HTTPOnly: true, Secure: true, SameSite: "Strict", } }