Files
ca-archive/SIGNING.md
2026-02-08 23:35:53 +01:00

11 KiB

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

# 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

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

🔑 Paso 1: Generar Claves

Generación automática

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:

mkdir -p private-keys
openssl genrsa -out private-keys/chrome-extension.pem 2048

Para Firefox: Crea private-keys/firefox-amo-credentials.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:

    nano private-keys/firefox-amo-credentials.json
    
  5. Agrega tus credenciales:

    {
      "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

./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

./build.sh --sign-firefox

Firmar solo Chrome

./build.sh --sign-chrome

Usando npm scripts

# 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

# 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

# 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

# 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

# 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

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":

{
  "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:

    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:

    {
      "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:

    ./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:

./scripts/generate-keys.sh

Error: "web-ext: command not found"

Solución:

# Instalar dependencias locales
npm install

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

Alternativa (instalación global):

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:

# Validar primero sin firmar
npm run lint

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

📊 Automatización (CI/CD)

GitHub Actions (ejemplo)

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

🆘 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.