---
name: list_chrome_profile_extensions
kind: function
lang: go
domain: browser
version: "1.0.0"
purity: impure
signature: "func ListChromeProfileExtensions(userDataDir, profileDir string) ([]ProfileExtension, error)"
description: "Lee las extensiones instaladas en un perfil de Chrome/Chromium parseando extensions.settings del archivo Preferences. Devuelve ID, Name, Version, Location (string legible), Enabled y FromPolicy para cada extensión. Si userDataDir es vacío usa ~/.config/chromium. Cuando falta el campo manifest en Preferences intenta leer el manifest.json desde el disco (Extensions/<id>/<ver>/manifest.json)."
tags: [chrome, chromium, browser, profile, extensions, navegator]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["encoding/json", "fmt", "os", "path/filepath", "sort"]
params:
  - name: userDataDir
    desc: "Ruta al user-data-dir de Chrome/Chromium (ej. ~/.config/chromium, ~/.config/google-chrome). Vacío = ~/.config/chromium."
  - name: profileDir
    desc: "Nombre del subdirectorio del perfil dentro de userDataDir (ej. 'Default', 'Profile 1'). Debe coincidir con el valor de --profile-directory del proceso Chrome."
output: "Slice de ProfileExtension ordenado por ID (orden determinista). Error si Preferences no existe o contiene JSON inválido. Slice vacío sin error si el perfil no tiene ninguna extensión registrada."
tested: true
tests:
  - "dos extensiones con IDs ordenados y campos correctos"
  - "extension con state 0 tiene Enabled false"
  - "perfil sin Preferences devuelve error"
  - "Preferences sin extensions.settings devuelve slice vacío sin error"
  - "fallback a Extensions/<id>/<ver>/manifest.json cuando falta manifest en Preferences"
  - "location 5 y 10 también son FromPolicy true"
  - "Preferences con JSON inválido devuelve error"
test_file_path: "functions/browser/list_chrome_profile_extensions_test.go"
file_path: "functions/browser/list_chrome_profile_extensions.go"
---

## Ejemplo

```go
// Listar extensiones del perfil Default del Chromium del usuario
exts, err := browser.ListChromeProfileExtensions("", "Default")
if err != nil {
    log.Fatal(err)
}
for _, e := range exts {
    policy := ""
    if e.FromPolicy {
        policy = " [policy]"
    }
    enabled := "off"
    if e.Enabled {
        enabled = "on"
    }
    fmt.Printf("%s  %-40s  v%-12s  %-24s  %s%s\n",
        e.ID, e.Name, e.Version, e.Location, enabled, policy)
}
// Output (ejemplo):
// dddbmnkl  uBlock Origin Lite                        v1.0.2        external_policy_download  on [policy]
// hklob123  My Dev Extension                          v0.1.0        unpacked                  on

// Con ruta explícita (Google Chrome)
exts, err = browser.ListChromeProfileExtensions("/home/user/.config/google-chrome", "Default")
```

## Cuando usarla

Antes de automatizar un perfil de Chrome/Chromium con CDP para auditar qué extensiones están activas, detectar extensiones instaladas por política (FromPolicy) o verificar que una extensión concreta está habilitada. También útil para depurar comportamientos inesperados del navegador causados por extensiones desconocidas.

## Gotchas

- **Preferences puede estar bloqueado mientras Chrome está abierto.** En la práctica Chrome escribe atómicamente el archivo y el bloqueo es brevísimo, pero si el proceso está escribiendo en ese instante `os.ReadFile` puede devolver datos parciales. Usar cuando Chrome no esté activo o tolerar reintento.
- **manifest.name puede ser una clave i18n** (`__MSG_appName__`). En ese caso el `Name` devuelto será esa clave, no el string localizado. Las extensiones empaquetadas en el repositorio de Chrome suelen tener el nombre resuelto directamente en el JSON, pero las extensiones no publicadas pueden usar i18n.
- **Extensions del sistema (location 5 = component) siempre tienen FromPolicy = true** aunque no vengan de una política de empresa; son extensiones internas del propio Chromium (PDF viewer, etc.).
- **Extensiones desinstaladas con estado de caché** pueden aparecer en `extensions.settings` con `state: 0` pero sin directorio en `Extensions/`. Esto es normal; `ListChromeProfileExtensions` las devuelve con `Enabled: false`.
- **Profile Directory ≠ Profile Name.** El parámetro `profileDir` debe ser el nombre del directorio (ej. `"Profile 1"`), que corresponde al `Dir` de `ChromeProfile` devuelto por `list_chrome_profiles_go_browser`.
- En Chrome (Google) el user-data-dir por defecto suele ser `~/.config/google-chrome`; en Chromium `~/.config/chromium`. Pasar ruta explícita si no usas Chromium.
