# Guía de Firma de Extensiones

Esta guía explica cómo firmar las extensiones de Classic Add-ons Archive para Firefox y Chrome.

## 🔐 ¿Por qué firmar?

- **Firefox**: Las extensiones firmadas pueden distribuirse fuera de AMO
- **Chrome**: La firma genera un ID consistente y permite actualizaciones
- **Seguridad**: Los usuarios pueden verificar la autenticidad
- **Profesional**: Distribución en stores oficiales

## 📋 Requisitos Previos

### Software necesario

```bash
# Instalar Node.js y npm (si no lo tienes)
sudo apt install nodejs npm   # Debian/Ubuntu
# o
brew install node             # macOS

# Instalar dependencias del proyecto (incluye web-ext)
npm install

# Para Chrome: openssl (generalmente ya instalado)
openssl version
```

**Nota**: web-ext se instala automáticamente como dependencia local, no necesitas instalarlo globalmente.

### Permisos de ejecución

```bash
chmod +x scripts/generate-keys.sh
chmod +x build.sh
```

## 🔑 Paso 1: Generar Claves

### Generación automática

```bash
cd /home/ale/projects/firefox/ca-archive
./scripts/generate-keys.sh
```

Este script genera:
- **Chrome**: Clave privada RSA 2048-bit (`private-keys/chrome-extension.pem`)
- **Chrome**: Extension ID calculado
- **Firefox**: Plantilla de credenciales AMO

### Generación manual (alternativa)

**Para Chrome:**
```bash
mkdir -p private-keys
openssl genrsa -out private-keys/chrome-extension.pem 2048
```

**Para Firefox:**
Crea `private-keys/firefox-amo-credentials.json`:
```json
{
  "web-ext": {
    "sign": {
      "apiKey": "user:12345678:123",
      "apiSecret": "tu-secret-aqui",
      "id": "ca-archive@Off.JustOff",
      "channel": "unlisted"
    }
  }
}
```

## 🦊 Paso 2: Configurar Credenciales de Firefox (AMO)

### Obtener credenciales AMO

1. **Inicia sesión** en https://addons.mozilla.org

2. **Ve a API Keys**: https://addons.mozilla.org/developers/addon/api/key/

3. **Genera credenciales**:
   - Click en "Generate new credentials"
   - Copia el **JWT issuer** (API Key)
   - Copia el **JWT secret** (API Secret)

4. **Edita el archivo de credenciales**:
   ```bash
   nano private-keys/firefox-amo-credentials.json
   ```

5. **Agrega tus credenciales**:
   ```json
   {
     "web-ext": {
       "sign": {
         "apiKey": "user:12345678:456",
         "apiSecret": "1a2b3c4d5e6f7g8h9i0j...",
         "channel": "unlisted"
       }
     }
   }
   ```

**Nota importante**: El ID de la extensión (`ca-archive@Off.JustOff`) se lee automáticamente de `manifest.json`, no es necesario incluirlo en las credenciales.

### Tipos de canal (channel)

- **`unlisted`**: No aparece en búsquedas de AMO, distribución externa
- **`listed`**: Aparece en AMO, revisión más estricta

**Recomendado**: Usar `unlisted` para desarrollo y `listed` para producción.

## 🏗️ Paso 3: Construir y Firmar

### Firmar ambas versiones

```bash
./build.sh --sign
```

Esto:
1. Construye paquetes ZIP sin firmar
2. Firma el paquete de Firefox con AMO
3. Firma el paquete de Chrome con tu clave privada
4. Genera archivos `.xpi` (Firefox) y `.crx` (Chrome)

### Firmar solo Firefox

```bash
./build.sh --sign-firefox
```

### Firmar solo Chrome

```bash
./build.sh --sign-chrome
```

### Usando npm scripts

```bash
# Generar claves
npm run keys:generate

# Construir sin firmar
npm run build

# Construir y firmar todo
npm run build:sign

# Firmar solo Firefox
npm run build:sign-firefox

# Firmar solo Chrome
npm run build:sign-chrome
```

## 📦 Archivos Generados

Después de la firma encontrarás en `dist/`:

### Firefox
- `ca-archive-3.0.0.xpi` - Paquete sin firmar
- `ca-archive-3.0.0-an+fx.xpi` - Paquete firmado por AMO
- `firefox-sign.log` - Log del proceso de firma

### Chrome
- `ca-archive-3.0.0-chrome.zip` - Paquete ZIP sin firmar
- `ca-archive-3.0.0-chrome.crx` - Paquete firmado
- `chrome-extension-id.txt` - ID de la extensión
- `ca-archive-3.0.0-chrome.crx.sha256` - Hash de verificación

## 🔍 Verificar Firma

### Firefox

```bash
# Verificar que es un ZIP válido
unzip -t dist/ca-archive-*.xpi

# Ver metadatos (requiere web-ext)
web-ext lint --source-dir=. --self-hosted
```

### Chrome

```bash
# Verificar hash SHA256
sha256sum -c dist/ca-archive-*-chrome.crx.sha256

# Ver Extension ID
cat dist/chrome-extension-id.txt
```

## 🚀 Distribución

### Firefox

**Opción 1: AMO (Recomendado para usuarios finales)**

1. Ve a: https://addons.mozilla.org/developers/
2. Click en "Submit a New Add-on"
3. Sube el archivo `.xpi` firmado
4. Completa información y submit para revisión

**Opción 2: Self-hosted (para desarrollo)**

1. Sube el `.xpi` firmado a tu servidor
2. Usuarios pueden instalarlo desde: `https://tu-servidor.com/ca-archive.xpi`
3. Firefox verificará la firma automáticamente

### Chrome

**Opción 1: Chrome Web Store (Recomendado)**

1. Ve a: https://chrome.google.com/webstore/devconsole
2. Click en "New Item"
3. Sube el archivo **`.zip`** (NO el .crx)
4. Completa información y publica

**Nota**: Chrome Web Store firma automáticamente, no subas el .crx.

**Opción 2: Enterprise distribution (.crx)**

1. Distribuye el archivo `.crx` firmado
2. Los usuarios deben agregarlo manualmente
3. Requiere políticas empresariales habilitadas

## 🔐 Seguridad de las Claves

### ⚠️ IMPORTANTE: Protege tus claves

```bash
# Permisos seguros
chmod 600 private-keys/chrome-extension.pem
chmod 600 private-keys/firefox-amo-credentials.json
chmod 700 private-keys/

# Verificar que están en .gitignore
git status private-keys/  # Debe decir "ignored"
```

### Backup de claves

```bash
# Hacer backup cifrado
tar czf ca-archive-keys-backup.tar.gz private-keys/
gpg -c ca-archive-keys-backup.tar.gz
rm ca-archive-keys-backup.tar.gz

# Guarda ca-archive-keys-backup.tar.gz.gpg en lugar seguro
```

### Restaurar backup

```bash
gpg -d ca-archive-keys-backup.tar.gz.gpg > ca-archive-keys-backup.tar.gz
tar xzf ca-archive-keys-backup.tar.gz
```

### ¿Qué hacer si pierdes las claves?

**Chrome:**
- El Extension ID cambiará
- Los usuarios verán una extensión "nueva"
- Perderás valoraciones/estadísticas

**Firefox:**
- Puedes generar nuevas credenciales AMO
- El ID de la extensión se mantiene (está en manifest.json)

## 🐛 Troubleshooting

### Error: "Cannot set custom ID ... because manifest.json declares ID"

**Causa**: El archivo de credenciales incluye un campo `"id"` que ya está en manifest.json

**Solución**:
Edita `private-keys/firefox-amo-credentials.json` y elimina la línea con `"id"`:
```json
{
  "web-ext": {
    "sign": {
      "apiKey": "user:12345678:123",
      "apiSecret": "tu-secret-aqui",
      "channel": "unlisted"
    }
  }
}
```

El ID se lee automáticamente de `manifest.json`.

### Error: "Unknown JWT iss (issuer)" - Status 401

**Error completo:**
```
WebExtError: Received bad response from the server while requesting 
https://addons.mozilla.org/api/v4/addons/...
status: 401
response: {"detail":"Unknown JWT iss (issuer)."}
```

**Causa**: Las credenciales AMO son inválidas o son credenciales de ejemplo/prueba.

**Soluciones**:

1. **Verificar que tienes credenciales reales de AMO:**
   ```bash
   cat private-keys/firefox-amo-credentials.json
   ```
   
   Si ves valores como:
   - `"apiKey": "user:12345678:123"` ← ❌ Ejemplo, no funciona
   - `"apiSecret": "1234567890abcdef..."` ← ❌ Ejemplo, no funciona
   
   **Debes obtener credenciales reales:**

2. **Obtener credenciales reales de AMO:**
   - Ve a: https://addons.mozilla.org/developers/addon/api/key/
   - Inicia sesión con tu cuenta de Firefox
   - Click en "Generate new credentials"
   - Dale un nombre descriptivo (ej: "ca-archive signing")
   - **Copia el JWT issuer** → Este es tu `apiKey`
   - **Copia el JWT secret** → Este es tu `apiSecret`

3. **Actualizar archivo de credenciales:**
   ```json
   {
     "web-ext": {
       "sign": {
         "apiKey": "user:TU_USER_ID_REAL:TU_KEY_ID_REAL",
         "apiSecret": "tu_secret_real_de_64_caracteres_hexadecimales_aqui",
         "channel": "unlisted"
       }
     }
   }
   ```

4. **Volver a intentar:**
   ```bash
   ./build.sh --sign
   ```

**⚠️ Nota importante:**
- El archivo de ejemplo tiene credenciales de prueba que NO funcionan
- DEBES generar tus propias credenciales en AMO
- Las credenciales son secretas, no las compartas ni las subas a Git
- El archivo `private-keys/` está excluido de Git por seguridad

### Error: "API Key invalid"

**Causa**: Credenciales de AMO incorrectas o mal formateadas

**Solución**:
1. Verifica que copiaste correctamente API Key y Secret (sin espacios extra)
2. Verifica formato JSON válido: `python3 -m json.tool private-keys/firefox-amo-credentials.json`
3. Regenera credenciales en AMO si lleva mucho tiempo creadas
4. Verifica que tu cuenta AMO tenga permisos de API habilitados

### Error: "Private key not found"

**Causa**: No se generaron las claves

**Solución**:
```bash
./scripts/generate-keys.sh
```

### Error: "web-ext: command not found"

**Solución**:
```bash
# Instalar dependencias locales
npm install

# El script usará automáticamente web-ext desde node_modules
./build.sh --sign
```

**Alternativa (instalación global)**:
```bash
npm install -g web-ext
```

### Chrome: "Package is invalid: CRX_HEADER_INVALID"

**Causa**: Archivo .crx mal formado

**Solución**:
- Usa la versión .zip para Chrome Web Store
- Regenera el .crx con: `./build.sh --sign-chrome`

### Firefox: Validación falla

**Solución**:
```bash
# Validar primero sin firmar
npm run lint

# Corregir errores y luego firmar
./build.sh --sign-firefox
```

## 📊 Automatización (CI/CD)

### GitHub Actions (ejemplo)

```yaml
name: Build and Sign
on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '16'
      
      - name: Install dependencies
        run: npm install -g web-ext
      
      - name: Setup keys
        run: |
          mkdir -p private-keys
          echo "${{ secrets.CHROME_KEY }}" > private-keys/chrome-extension.pem
          echo "${{ secrets.FIREFOX_CREDS }}" > private-keys/firefox-amo-credentials.json
      
      - name: Build and sign
        run: ./build.sh --sign
      
      - name: Upload artifacts
        uses: actions/upload-artifact@v2
        with:
          name: signed-packages
          path: dist/
```

**Configura secrets en**: Repository Settings > Secrets and variables > Actions

## 📚 Recursos Adicionales

- [Firefox Extension Workshop](https://extensionworkshop.com/)
- [Chrome Extension Publishing](https://developer.chrome.com/docs/webstore/publish/)
- [web-ext Documentation](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/)
- [AMO Signing API](https://addons-server.readthedocs.io/en/latest/topics/api/signing.html)

## 🆘 Soporte

¿Problemas con la firma?

1. Revisa los logs en `dist/*-sign.log`
2. Verifica permisos: `ls -la private-keys/`
3. Prueba con: `npm run lint`
4. Abre un issue en GitHub

---

**Recuerda**: NUNCA compartas tus claves privadas ni las subas a repositorios públicos.
