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
-
Inicia sesión en https://addons.mozilla.org
-
Ve a API Keys: https://addons.mozilla.org/developers/addon/api/key/
-
Genera credenciales:
- Click en "Generate new credentials"
- Copia el JWT issuer (API Key)
- Copia el JWT secret (API Secret)
-
Edita el archivo de credenciales:
nano private-keys/firefox-amo-credentials.json -
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 externalisted: 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:
- Construye paquetes ZIP sin firmar
- Firma el paquete de Firefox con AMO
- Firma el paquete de Chrome con tu clave privada
- 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 firmarca-archive-3.0.0-an+fx.xpi- Paquete firmado por AMOfirefox-sign.log- Log del proceso de firma
Chrome
ca-archive-3.0.0-chrome.zip- Paquete ZIP sin firmarca-archive-3.0.0-chrome.crx- Paquete firmadochrome-extension-id.txt- ID de la extensiónca-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)
- Ve a: https://addons.mozilla.org/developers/
- Click en "Submit a New Add-on"
- Sube el archivo
.xpifirmado - Completa información y submit para revisión
Opción 2: Self-hosted (para desarrollo)
- Sube el
.xpifirmado a tu servidor - Usuarios pueden instalarlo desde:
https://tu-servidor.com/ca-archive.xpi - Firefox verificará la firma automáticamente
Chrome
Opción 1: Chrome Web Store (Recomendado)
- Ve a: https://chrome.google.com/webstore/devconsole
- Click en "New Item"
- Sube el archivo
.zip(NO el .crx) - Completa información y publica
Nota: Chrome Web Store firma automáticamente, no subas el .crx.
Opción 2: Enterprise distribution (.crx)
- Distribuye el archivo
.crxfirmado - Los usuarios deben agregarlo manualmente
- 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:
-
Verificar que tienes credenciales reales de AMO:
cat private-keys/firefox-amo-credentials.jsonSi ves valores como:
"apiKey": "user:12345678:123"← ❌ Ejemplo, no funciona"apiSecret": "1234567890abcdef..."← ❌ Ejemplo, no funciona
Debes obtener credenciales reales:
-
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
-
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" } } } -
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:
- Verifica que copiaste correctamente API Key y Secret (sin espacios extra)
- Verifica formato JSON válido:
python3 -m json.tool private-keys/firefox-amo-credentials.json - Regenera credenciales en AMO si lleva mucho tiempo creadas
- 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?
- Revisa los logs en
dist/*-sign.log - Verifica permisos:
ls -la private-keys/ - Prueba con:
npm run lint - Abre un issue en GitHub
Recuerda: NUNCA compartas tus claves privadas ni las subas a repositorios públicos.