403 líneas
12 KiB
Bash
Archivo Ejecutable
403 líneas
12 KiB
Bash
Archivo Ejecutable
#!/bin/bash
|
||
|
||
# Script de construcción para Classic Add-ons Archive v3.0
|
||
# Genera paquetes .xpi (Firefox) y .zip (Chrome)
|
||
|
||
set -e # Salir si hay errores
|
||
|
||
echo "=================================================="
|
||
echo " Classic Add-ons Archive - Build Script v3.0"
|
||
echo "=================================================="
|
||
echo ""
|
||
|
||
# Colores para output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Configuración
|
||
VERSION="3.0.0"
|
||
DIST_DIR="dist"
|
||
KEYS_DIR="private-keys"
|
||
FIREFOX_PACKAGE="ca-archive-${VERSION}.xpi"
|
||
CHROME_PACKAGE="ca-archive-${VERSION}-chrome.zip"
|
||
CHROME_CRX="ca-archive-${VERSION}-chrome.crx"
|
||
CHROME_KEY="$KEYS_DIR/chrome-extension.pem"
|
||
FIREFOX_JWT="$KEYS_DIR/firefox-amo-credentials.json"
|
||
|
||
# Opciones de línea de comandos
|
||
SIGN_MODE=""
|
||
for arg in "$@"; do
|
||
case $arg in
|
||
--sign)
|
||
SIGN_MODE="all"
|
||
shift
|
||
;;
|
||
--sign-chrome)
|
||
SIGN_MODE="chrome"
|
||
shift
|
||
;;
|
||
--sign-firefox)
|
||
SIGN_MODE="firefox"
|
||
shift
|
||
;;
|
||
--list|-l)
|
||
LIST_CONTENTS=true
|
||
shift
|
||
;;
|
||
*)
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Archivos a incluir (relativos al directorio raíz)
|
||
INCLUDE_FILES=(
|
||
"manifest.json"
|
||
"background.js"
|
||
"content/"
|
||
"skin/"
|
||
)
|
||
|
||
# Archivos a excluir (patrones de exclusión)
|
||
EXCLUDE_PATTERNS=(
|
||
"*.git*"
|
||
"*~"
|
||
"*.swp"
|
||
".DS_Store"
|
||
"Thumbs.db"
|
||
"*.tmp"
|
||
"*.log"
|
||
"*.md" # Excluir documentación (opcional: comentar para incluir)
|
||
"install.rdf" # Legacy
|
||
"chrome.manifest" # Legacy
|
||
"bootstrap.js" # Legacy
|
||
"update.xml" # Legacy
|
||
"content/db.js" # Legacy (usamos db-webext.js)
|
||
"package.json"
|
||
"package-lock.json"
|
||
"node_modules/"
|
||
"dist/"
|
||
)
|
||
|
||
# Función para imprimir con color
|
||
print_status() {
|
||
echo -e "${GREEN}[✓]${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}[!]${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}[✗]${NC} $1"
|
||
}
|
||
|
||
# Verificar que estamos en el directorio correcto
|
||
if [ ! -f "manifest.json" ]; then
|
||
print_error "No se encuentra manifest.json"
|
||
print_error "Ejecuta este script desde el directorio raíz del proyecto"
|
||
exit 1
|
||
fi
|
||
|
||
print_status "Directorio de proyecto detectado"
|
||
|
||
# Crear directorio de distribución
|
||
if [ -d "$DIST_DIR" ]; then
|
||
print_warning "Limpiando directorio de distribución existente..."
|
||
rm -rf "$DIST_DIR"
|
||
fi
|
||
|
||
mkdir -p "$DIST_DIR"
|
||
print_status "Directorio de distribución creado: $DIST_DIR/"
|
||
|
||
# Función para construir el comando de exclusión para zip
|
||
build_exclude_args() {
|
||
local args=""
|
||
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
|
||
args="$args -x '$pattern'"
|
||
done
|
||
echo "$args"
|
||
}
|
||
|
||
# Construir paquete para Firefox (.xpi)
|
||
echo ""
|
||
echo "Construyendo paquete para Firefox..."
|
||
print_status "Empaquetando archivos..."
|
||
|
||
# Crear archivo zip temporal
|
||
TMP_ZIP="$DIST_DIR/temp.zip"
|
||
|
||
# Comando de zip con exclusiones
|
||
zip -r "$TMP_ZIP" "${INCLUDE_FILES[@]}" \
|
||
-x "${EXCLUDE_PATTERNS[@]}" \
|
||
> /dev/null 2>&1
|
||
|
||
# Renombrar a .xpi
|
||
mv "$TMP_ZIP" "$DIST_DIR/$FIREFOX_PACKAGE"
|
||
|
||
if [ -f "$DIST_DIR/$FIREFOX_PACKAGE" ]; then
|
||
FIREFOX_SIZE=$(du -h "$DIST_DIR/$FIREFOX_PACKAGE" | cut -f1)
|
||
print_status "Paquete Firefox creado: $FIREFOX_PACKAGE ($FIREFOX_SIZE)"
|
||
else
|
||
print_error "Error al crear paquete Firefox"
|
||
exit 1
|
||
fi
|
||
|
||
# Construir paquete para Chrome (.zip)
|
||
echo ""
|
||
echo "Construyendo paquete para Chrome..."
|
||
print_status "Empaquetando archivos..."
|
||
|
||
zip -r "$DIST_DIR/$CHROME_PACKAGE" "${INCLUDE_FILES[@]}" \
|
||
-x "${EXCLUDE_PATTERNS[@]}" \
|
||
> /dev/null 2>&1
|
||
|
||
if [ -f "$DIST_DIR/$CHROME_PACKAGE" ]; then
|
||
CHROME_SIZE=$(du -h "$DIST_DIR/$CHROME_PACKAGE" | cut -f1)
|
||
print_status "Paquete Chrome creado: $CHROME_PACKAGE ($CHROME_SIZE)"
|
||
else
|
||
print_error "Error al crear paquete Chrome"
|
||
exit 1
|
||
fi
|
||
|
||
# Verificar integridad de los paquetes
|
||
echo ""
|
||
print_status "Verificando paquetes..."
|
||
|
||
# Verificar Firefox
|
||
if unzip -t "$DIST_DIR/$FIREFOX_PACKAGE" > /dev/null 2>&1; then
|
||
print_status "Paquete Firefox verificado (integridad OK)"
|
||
else
|
||
print_error "Paquete Firefox corrupto"
|
||
exit 1
|
||
fi
|
||
|
||
# Verificar Chrome
|
||
if unzip -t "$DIST_DIR/$CHROME_PACKAGE" > /dev/null 2>&1; then
|
||
print_status "Paquete Chrome verificado (integridad OK)"
|
||
else
|
||
print_error "Paquete Chrome corrupto"
|
||
exit 1
|
||
fi
|
||
|
||
# Firma de paquetes si se solicitó
|
||
if [ "$SIGN_MODE" = "firefox" ] || [ "$SIGN_MODE" = "all" ]; then
|
||
echo ""
|
||
echo "=================================================="
|
||
echo " Firmando paquete Firefox"
|
||
echo "=================================================="
|
||
|
||
if [ ! -f "$FIREFOX_JWT" ]; then
|
||
print_error "No se encontraron credenciales de Firefox: $FIREFOX_JWT"
|
||
print_warning "Ejecuta: ./scripts/generate-keys.sh"
|
||
exit 1
|
||
fi
|
||
|
||
# Buscar web-ext: primero en node_modules, luego global
|
||
WEB_EXT=""
|
||
if [ -f "node_modules/.bin/web-ext" ]; then
|
||
WEB_EXT="./node_modules/.bin/web-ext"
|
||
print_status "Usando web-ext local: $WEB_EXT"
|
||
elif command -v npx &> /dev/null; then
|
||
WEB_EXT="npx web-ext"
|
||
print_status "Usando web-ext via npx"
|
||
elif command -v web-ext &> /dev/null; then
|
||
WEB_EXT="web-ext"
|
||
print_status "Usando web-ext global"
|
||
else
|
||
print_error "web-ext no está instalado"
|
||
print_warning "Instalar con: npm install"
|
||
print_warning "O globalmente: npm install -g web-ext"
|
||
exit 1
|
||
fi
|
||
|
||
print_status "Firmando con AMO..."
|
||
|
||
# Leer credenciales del JSON
|
||
API_KEY=$(grep -o '"apiKey"[[:space:]]*:[[:space:]]*"[^"]*"' "$FIREFOX_JWT" | cut -d'"' -f4)
|
||
API_SECRET=$(grep -o '"apiSecret"[[:space:]]*:[[:space:]]*"[^"]*"' "$FIREFOX_JWT" | cut -d'"' -f4)
|
||
|
||
if [ -z "$API_KEY" ] || [ -z "$API_SECRET" ]; then
|
||
print_error "Credenciales de AMO inválidas en $FIREFOX_JWT"
|
||
exit 1
|
||
fi
|
||
|
||
# Firmar con web-ext
|
||
# Nota: El ID se lee automáticamente de manifest.json, no se pasa como parámetro
|
||
$WEB_EXT sign \
|
||
--source-dir=. \
|
||
--artifacts-dir="$DIST_DIR" \
|
||
--api-key="$API_KEY" \
|
||
--api-secret="$API_SECRET" \
|
||
--channel=unlisted \
|
||
2>&1 | tee "$DIST_DIR/firefox-sign.log"
|
||
|
||
# Verificar el código de salida
|
||
SIGN_EXIT_CODE=${PIPESTATUS[0]}
|
||
|
||
if [ $SIGN_EXIT_CODE -eq 0 ]; then
|
||
print_status "Paquete Firefox firmado exitosamente"
|
||
# Buscar el archivo firmado
|
||
SIGNED_XPI=$(ls -t "$DIST_DIR"/*.xpi 2>/dev/null | head -1)
|
||
if [ -f "$SIGNED_XPI" ]; then
|
||
print_status "Archivo firmado: $(basename "$SIGNED_XPI")"
|
||
fi
|
||
else
|
||
print_error "Error al firmar paquete Firefox (código: $SIGN_EXIT_CODE)"
|
||
print_warning "Revisa: $DIST_DIR/firefox-sign.log"
|
||
exit $SIGN_EXIT_CODE
|
||
fi
|
||
fi
|
||
|
||
if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
|
||
echo ""
|
||
echo "=================================================="
|
||
echo " Firmando paquete Chrome"
|
||
echo "=================================================="
|
||
|
||
if [ ! -f "$CHROME_KEY" ]; then
|
||
print_error "No se encontró clave de Chrome: $CHROME_KEY"
|
||
print_warning "Ejecuta: ./scripts/generate-keys.sh"
|
||
exit 1
|
||
fi
|
||
|
||
if ! command -v google-chrome &> /dev/null && ! command -v chromium &> /dev/null; then
|
||
print_warning "Chrome/Chromium no encontrado, usando método alternativo..."
|
||
|
||
# Método alternativo: crear .crx manualmente
|
||
print_status "Generando .crx con openssl..."
|
||
|
||
# Extraer clave pública
|
||
openssl rsa -in "$CHROME_KEY" -pubout -outform DER > "$DIST_DIR/public.der" 2>/dev/null
|
||
|
||
# Crear firma
|
||
openssl dgst -sha256 -sign "$CHROME_KEY" -out "$DIST_DIR/signature.bin" "$DIST_DIR/$CHROME_PACKAGE"
|
||
|
||
# Leer tamaños
|
||
pub_size=$(wc -c < "$DIST_DIR/public.der")
|
||
sig_size=$(wc -c < "$DIST_DIR/signature.bin")
|
||
|
||
# Crear header CRX3
|
||
(
|
||
printf "Cr24" # Magic number
|
||
printf '\x03\x00\x00\x00' # Version 3
|
||
printf "$(printf '%08x' $pub_size | sed 's/\(..\)/\\x\1/g' | tac -s'\\')" # Public key length (little endian)
|
||
printf "$(printf '%08x' $sig_size | sed 's/\(..\)/\\x\1/g' | tac -s'\\')" # Signature length (little endian)
|
||
cat "$DIST_DIR/public.der"
|
||
cat "$DIST_DIR/signature.bin"
|
||
cat "$DIST_DIR/$CHROME_PACKAGE"
|
||
) > "$DIST_DIR/$CHROME_CRX"
|
||
|
||
# Limpiar archivos temporales
|
||
rm -f "$DIST_DIR/public.der" "$DIST_DIR/signature.bin"
|
||
|
||
if [ -f "$DIST_DIR/$CHROME_CRX" ]; then
|
||
CRX_SIZE=$(du -h "$DIST_DIR/$CHROME_CRX" | cut -f1)
|
||
print_status "Paquete Chrome firmado: $CHROME_CRX ($CRX_SIZE)"
|
||
|
||
# Calcular hash
|
||
CRX_HASH=$(sha256sum "$DIST_DIR/$CHROME_CRX" | cut -d' ' -f1)
|
||
echo "$CRX_HASH" > "$DIST_DIR/${CHROME_CRX}.sha256"
|
||
print_status "Hash SHA256 guardado"
|
||
else
|
||
print_error "Error al crear .crx"
|
||
fi
|
||
else
|
||
print_status "Empaquetando con Chrome..."
|
||
|
||
# Usar Chrome para empaquetar
|
||
CHROME_BIN=$(command -v google-chrome || command -v chromium)
|
||
|
||
"$CHROME_BIN" --pack-extension=. --pack-extension-key="$CHROME_KEY" --no-message-box 2>/dev/null
|
||
|
||
if [ -f "$(basename $(pwd)).crx" ]; then
|
||
mv "$(basename $(pwd)).crx" "$DIST_DIR/$CHROME_CRX"
|
||
print_status "Paquete Chrome firmado: $CHROME_CRX"
|
||
else
|
||
print_error "Error al firmar con Chrome"
|
||
fi
|
||
fi
|
||
|
||
# Calcular Extension ID
|
||
if [ -f "$CHROME_KEY" ]; then
|
||
CHROME_ID=$(openssl rsa -in "$CHROME_KEY" -pubout -outform DER 2>/dev/null | \
|
||
openssl dgst -sha256 -binary | \
|
||
head -c 16 | \
|
||
od -An -tx1 | \
|
||
tr -d ' \n' | \
|
||
tr '0-9a-f' 'a-p')
|
||
echo "$CHROME_ID" > "$DIST_DIR/chrome-extension-id.txt"
|
||
print_status "Extension ID: $CHROME_ID"
|
||
fi
|
||
fi
|
||
|
||
# Listar contenido (opcional)
|
||
if [ "$LIST_CONTENTS" = true ]; then
|
||
echo ""
|
||
echo "Contenido del paquete Firefox:"
|
||
unzip -l "$DIST_DIR/$FIREFOX_PACKAGE"
|
||
fi
|
||
|
||
# Resumen final
|
||
echo ""
|
||
echo "=================================================="
|
||
echo " ✨ Build completado exitosamente"
|
||
echo "=================================================="
|
||
echo ""
|
||
echo "Paquetes generados en: $DIST_DIR/"
|
||
echo ""
|
||
echo " Firefox: $FIREFOX_PACKAGE ($FIREFOX_SIZE)"
|
||
echo " Chrome: $CHROME_PACKAGE ($CHROME_SIZE)"
|
||
|
||
if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
|
||
if [ -f "$DIST_DIR/$CHROME_CRX" ]; then
|
||
CRX_SIZE=$(du -h "$DIST_DIR/$CHROME_CRX" | cut -f1)
|
||
echo " Chrome (firmado): $CHROME_CRX ($CRX_SIZE)"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
|
||
if [ -z "$SIGN_MODE" ]; then
|
||
echo " ℹ️ Paquetes sin firmar. Para firmar usa:"
|
||
echo " ./build.sh --sign # Firmar ambos"
|
||
echo " ./build.sh --sign-firefox # Solo Firefox"
|
||
echo " ./build.sh --sign-chrome # Solo Chrome"
|
||
echo ""
|
||
fi
|
||
|
||
echo "Próximos pasos:"
|
||
echo ""
|
||
|
||
if [ -n "$SIGN_MODE" ]; then
|
||
echo " Paquetes firmados ✓"
|
||
echo ""
|
||
echo " Para publicar:"
|
||
if [ "$SIGN_MODE" = "firefox" ] || [ "$SIGN_MODE" = "all" ]; then
|
||
echo " Firefox AMO: El archivo firmado está listo para subir"
|
||
echo " https://addons.mozilla.org/developers/"
|
||
fi
|
||
if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
|
||
echo " Chrome Web Store: Sube el archivo .zip (no .crx)"
|
||
echo " https://chrome.google.com/webstore/devconsole"
|
||
fi
|
||
else
|
||
echo " Firefox:"
|
||
echo " 1. Ir a about:debugging#/runtime/this-firefox"
|
||
echo " 2. Click en 'Cargar complemento temporal'"
|
||
echo " 3. Seleccionar: $DIST_DIR/$FIREFOX_PACKAGE"
|
||
echo ""
|
||
echo " Chrome:"
|
||
echo " 1. Ir a chrome://extensions/"
|
||
echo " 2. Activar 'Modo de desarrollador'"
|
||
echo " 3. Click en 'Cargar extensión sin empaquetar'"
|
||
echo " 4. Extraer y seleccionar la carpeta de $CHROME_PACKAGE"
|
||
fi
|
||
|
||
echo ""
|
||
echo "=================================================="
|
||
|
||
exit 0
|