830f2d34de
Cierra el gap de reproducibilidad entre PCs del proyecto web_scraping: la organizacion de extensiones y el CDP global dejaban de ser pasos manuales con sudo documentados en prosa. - apply_chromium_extension_policy: escribe ExtensionInstallForcelist (whitelist via --keep) en /etc/chromium/policies/managed/extensions.json de forma idempotente, con backup automatico y validacion JSON. --dry-run previsualiza sin tocar el sistema. - apply_chromium_cdp_flag: gestiona /etc/chromium.d/cdp (CDP global). Loopback por defecto, --network para bind 0.0.0.0 (con aviso), --remove para desactivar, --dry-run para previsualizar. Idempotente con backup. Ambas: dominio browser, grupo navegator, impuras (escriben en /etc via sudo), guard de auto-ejecucion (ejecutables con fn run y sourceables). Docs del proyecto (CONVENTIONS.md reglas 8/9, CHROMIUM_SYSTEM.md inventario + tabla accionable) ahora apuntan a 'fn run apply_chromium_*' como metodo canonico en vez de editar los archivos de /etc a mano.
206 lines
7.5 KiB
Bash
206 lines
7.5 KiB
Bash
#!/usr/bin/env bash
|
|
# apply_chromium_extension_policy — Escribe de forma idempotente la política managed de Chromium
|
|
# que fuerza la instalación de un conjunto de extensiones en CUALQUIER perfil del navegador.
|
|
|
|
apply_chromium_extension_policy() {
|
|
local policy_path="/etc/chromium/policies/managed/extensions.json"
|
|
local update_url="https://clients2.google.com/service/update2/crx"
|
|
local dry_run=0
|
|
local -a ext_ids=()
|
|
|
|
# --- Parseo de argumentos ---
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--keep)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "apply_chromium_extension_policy: --keep requiere un ID de extensión" >&2
|
|
return 1
|
|
fi
|
|
ext_ids+=("$2")
|
|
shift 2
|
|
;;
|
|
--policy-path)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "apply_chromium_extension_policy: --policy-path requiere un valor" >&2
|
|
return 1
|
|
fi
|
|
policy_path="$2"
|
|
shift 2
|
|
;;
|
|
--update-url)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "apply_chromium_extension_policy: --update-url requiere un valor" >&2
|
|
return 1
|
|
fi
|
|
update_url="$2"
|
|
shift 2
|
|
;;
|
|
--dry-run)
|
|
dry_run=1
|
|
shift
|
|
;;
|
|
*)
|
|
echo "apply_chromium_extension_policy: argumento desconocido: $1" >&2
|
|
echo "Uso: apply_chromium_extension_policy --keep <ext_id> [--keep <ext_id>]... [--policy-path <path>] [--update-url <url>] [--dry-run]" >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# --- Validar que hay al menos una extensión ---
|
|
if [[ ${#ext_ids[@]} -eq 0 ]]; then
|
|
echo "apply_chromium_extension_policy: se requiere al menos un --keep <ext_id>" >&2
|
|
return 1
|
|
fi
|
|
|
|
# --- Construir el JSON ---
|
|
local forcelist_entries=""
|
|
local first=1
|
|
for id in "${ext_ids[@]}"; do
|
|
if [[ $first -eq 0 ]]; then
|
|
forcelist_entries+=","$'\n'
|
|
fi
|
|
forcelist_entries+=" \"${id};${update_url}\""
|
|
first=0
|
|
done
|
|
|
|
local new_json
|
|
new_json=$(printf '{\n "ExtensionInstallForcelist": [\n%s\n ]\n}\n' "$forcelist_entries")
|
|
|
|
# --- Modo dry-run ---
|
|
if [[ $dry_run -eq 1 ]]; then
|
|
echo "[dry-run] JSON que se escribiría en: ${policy_path}"
|
|
echo "---"
|
|
echo "$new_json"
|
|
echo "---"
|
|
echo "[dry-run] No se ha modificado el sistema."
|
|
return 0
|
|
fi
|
|
|
|
# --- Idempotencia: comparar con contenido actual ---
|
|
if [[ -f "$policy_path" ]]; then
|
|
local current_content
|
|
current_content=$(cat "$policy_path" 2>/dev/null || true)
|
|
if [[ "$current_content" == "$new_json" ]]; then
|
|
echo "apply_chromium_extension_policy: política ya aplicada (sin cambios). Nada que hacer."
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# --- Backup del archivo existente ---
|
|
local backup_path=""
|
|
if [[ -f "$policy_path" ]]; then
|
|
local date_suffix
|
|
date_suffix=$(date +%Y%m%d)
|
|
backup_path="${policy_path}.bak.${date_suffix}"
|
|
if [[ ! -f "$backup_path" ]]; then
|
|
echo "apply_chromium_extension_policy: creando backup → ${backup_path}"
|
|
if [[ $EUID -ne 0 ]]; then
|
|
sudo cp "$policy_path" "$backup_path" || {
|
|
echo "apply_chromium_extension_policy: no se pudo crear el backup en ${backup_path}" >&2
|
|
return 1
|
|
}
|
|
else
|
|
cp "$policy_path" "$backup_path" || {
|
|
echo "apply_chromium_extension_policy: no se pudo crear el backup en ${backup_path}" >&2
|
|
return 1
|
|
}
|
|
fi
|
|
else
|
|
echo "apply_chromium_extension_policy: backup del día ya existe (${backup_path}), se omite."
|
|
fi
|
|
fi
|
|
|
|
# --- Crear directorio padre si no existe ---
|
|
local policy_dir
|
|
policy_dir=$(dirname "$policy_path")
|
|
if [[ ! -d "$policy_dir" ]]; then
|
|
echo "apply_chromium_extension_policy: creando directorio ${policy_dir}"
|
|
if [[ $EUID -ne 0 ]]; then
|
|
sudo mkdir -p "$policy_dir" || {
|
|
echo "apply_chromium_extension_policy: no se pudo crear el directorio ${policy_dir}" >&2
|
|
return 1
|
|
}
|
|
else
|
|
mkdir -p "$policy_dir" || {
|
|
echo "apply_chromium_extension_policy: no se pudo crear el directorio ${policy_dir}" >&2
|
|
return 1
|
|
}
|
|
fi
|
|
fi
|
|
|
|
# --- Escribir el JSON vía tmpfile + sudo cp / tee ---
|
|
local tmpfile
|
|
tmpfile=$(mktemp /tmp/chromium_policy_XXXXXX.json)
|
|
echo "$new_json" > "$tmpfile"
|
|
|
|
if [[ $EUID -ne 0 ]]; then
|
|
sudo cp "$tmpfile" "$policy_path" || {
|
|
echo "apply_chromium_extension_policy: no se pudo escribir ${policy_path}" >&2
|
|
rm -f "$tmpfile"
|
|
# Restaurar backup si hubo
|
|
if [[ -n "$backup_path" && -f "$backup_path" ]]; then
|
|
echo "apply_chromium_extension_policy: restaurando backup tras error..."
|
|
sudo cp "$backup_path" "$policy_path" 2>/dev/null || true
|
|
fi
|
|
return 1
|
|
}
|
|
else
|
|
cp "$tmpfile" "$policy_path" || {
|
|
echo "apply_chromium_extension_policy: no se pudo escribir ${policy_path}" >&2
|
|
rm -f "$tmpfile"
|
|
if [[ -n "$backup_path" && -f "$backup_path" ]]; then
|
|
echo "apply_chromium_extension_policy: restaurando backup tras error..."
|
|
cp "$backup_path" "$policy_path" 2>/dev/null || true
|
|
fi
|
|
return 1
|
|
}
|
|
fi
|
|
rm -f "$tmpfile"
|
|
|
|
# --- Validar el JSON escrito ---
|
|
local validation_ok=0
|
|
if command -v python3 &>/dev/null; then
|
|
python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$policy_path" 2>/dev/null && validation_ok=1
|
|
elif command -v jq &>/dev/null; then
|
|
jq . "$policy_path" &>/dev/null && validation_ok=1
|
|
else
|
|
# Sin parser disponible, asumir OK (el JSON lo generamos nosotros)
|
|
validation_ok=1
|
|
fi
|
|
|
|
if [[ $validation_ok -eq 0 ]]; then
|
|
echo "apply_chromium_extension_policy: el JSON escrito no es válido — restaurando backup" >&2
|
|
if [[ -n "$backup_path" && -f "$backup_path" ]]; then
|
|
if [[ $EUID -ne 0 ]]; then
|
|
sudo cp "$backup_path" "$policy_path" 2>/dev/null || true
|
|
else
|
|
cp "$backup_path" "$policy_path" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
# --- Resumen final ---
|
|
echo "apply_chromium_extension_policy: política aplicada correctamente."
|
|
echo " Ruta : ${policy_path}"
|
|
echo " Extensiones forzadas (${#ext_ids[@]}):"
|
|
for id in "${ext_ids[@]}"; do
|
|
echo " - ${id}"
|
|
done
|
|
if [[ -n "$backup_path" && -f "$backup_path" ]]; then
|
|
echo " Backup : ${backup_path}"
|
|
fi
|
|
echo ""
|
|
echo " AVISO: Chromium cachea la politica en memoria. Para que surta efecto:"
|
|
echo " pkill -9 chromium (cierra TODOS los procesos)"
|
|
echo " # Luego relanza Chromium. O desde un Chromium abierto:"
|
|
echo " # chrome://policy → 'Reload policies'"
|
|
}
|
|
|
|
# Auto-ejecución al correr el archivo directo (bash file.sh / fn run). Si se hace `source`,
|
|
# solo se define la función y no se ejecuta nada.
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
apply_chromium_extension_policy "$@"
|
|
fi
|