#!/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 [--keep ]... [--policy-path ] [--update-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 " >&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