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

466 líneas
11 KiB
Markdown

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