Files
fn_registry/bash/functions/browser/restore_chrome_bookmarks.sh
T
Egutierrez ae841ceedb feat(browser): CRUD de perfiles Chromium + pipeline reset_chrome_profiles
Cinco funciones nuevas (dominio browser, grupo navegator) que cierran los gaps
de gestión de perfiles, más un pipeline que las orquesta:

- backup_chrome_bookmarks / restore_chrome_bookmarks: backup y restore de los
  archivos Bookmarks (copia byte a byte verbatim para preservar el checksum
  interno; en Chromium 148 los bookmarks no están bajo el super_mac de Secure
  Preferences). Guard por user-data-dir (no global).
- delete_chrome_profile: borra la carpeta del perfil + limpia su entrada en
  Local State (info_cache, profiles_order, last_active_profiles, last_used).
- create_chrome_profile: lanza chromium headless (vía systemd-run) para que la
  managed policy instale la whitelist de extensiones, y asigna el nombre legible
  en Local State. Mata todo el árbol de chromium del udd antes de editar Local
  State (los hijos zygote/gpu no repiten --user-data-dir pero referencian la ruta).
- list_chrome_profile_extensions (Go): lista extensiones de un perfil con
  ID/name/version/location/enabled/fromPolicy. 7 unit tests.
- reset_chrome_profiles (pipeline): backup -> cerrar chromium -> delete -> create
  -> restore -> verify. Destructivo (--yes), --dry-run seguro.

Validado: unit tests Go verdes, backup/restore byte-idéntico, delete limpia Local
State, create instala la forcelist global (uBlock + web_proxy) en perfiles nuevos.
2026-06-06 01:24:21 +02:00

166 lines
6.9 KiB
Bash

#!/usr/bin/env bash
# restore_chrome_bookmarks — restaura archivos Bookmarks de un backup generado por
# backup_chrome_bookmarks hacia los perfiles destino en user-data-dir.
# Copia byte a byte con cp -p (nunca parsea ni reserializa el JSON).
set -euo pipefail
restore_chrome_bookmarks() {
# ── defaults ──────────────────────────────────────────────────────────────
local _user_data_dir="${HOME}/.config/chromium"
local _backup_dir=""
local _profiles=()
local _dry_run=0
# ── parse args ────────────────────────────────────────────────────────────
_usage() {
cat >&2 <<'EOF'
Usage: restore_chrome_bookmarks --backup-dir <ts-dir>
[--user-data-dir <dir>] [--profile <name>]... [--dry-run]
--user-data-dir Raíz de perfiles destino. Default: ~/.config/chromium
--backup-dir Directorio de backup con timestamp generado por
backup_chrome_bookmarks. Debe contener subdirectorios
<profile>/Bookmarks. OBLIGATORIO.
--profile <name> Perfil a restaurar (repetible). Si no se pasa ninguno
se restauran TODOS los perfiles presentes en backup-dir.
--dry-run Muestra qué se copiaría sin tocar nada.
Exit codes:
0 éxito (o dry-run completado)
1 error de argumento o validación
2 chromium está corriendo (solo en modo real)
EOF
return 1
}
while [[ $# -gt 0 ]]; do
case "$1" in
--user-data-dir) _user_data_dir="$2"; shift 2 ;;
--backup-dir) _backup_dir="$2"; shift 2 ;;
--profile) _profiles+=("$2"); shift 2 ;;
--dry-run) _dry_run=1; shift ;;
-h|--help) _usage; return 0 ;;
*) echo "restore_chrome_bookmarks: argumento desconocido: $1" >&2; return 1 ;;
esac
done
# ── validaciones ──────────────────────────────────────────────────────────
if [[ -z "$_backup_dir" ]]; then
echo "restore_chrome_bookmarks: --backup-dir es obligatorio" >&2
return 1
fi
if [[ ! -d "$_backup_dir" ]]; then
echo "restore_chrome_bookmarks: backup-dir no encontrado: ${_backup_dir}" >&2
return 1
fi
if [[ ! -d "$_user_data_dir" ]]; then
echo "restore_chrome_bookmarks: user-data-dir no encontrado: ${_user_data_dir}" >&2
return 1
fi
# ── guard: ningún chromium debe tener ESTE user-data-dir abierto (excepto en dry-run) ──
# Por-udd, no global: permite operar sobre un user-data-dir de pruebas mientras el chromium
# diario (con otro --user-data-dir) sigue abierto.
if [[ $_dry_run -eq 0 ]]; then
if pgrep -af '[c]hromium' 2>/dev/null | grep -qF -- "--user-data-dir=${_user_data_dir}"; then
echo "restore_chrome_bookmarks: hay un chromium con este user-data-dir abierto — ciérralo antes de restaurar:" >&2
echo " pkill -TERM chromium" >&2
echo "(Chromium reescribe Bookmarks desde memoria al cerrar y desharía la restauración)" >&2
return 2
fi
fi
# ── determinar perfiles a restaurar ───────────────────────────────────────
local _target_profiles=()
if [[ ${#_profiles[@]} -gt 0 ]]; then
# Perfiles explícitos: verificar que existen en el backup
local _p
for _p in "${_profiles[@]}"; do
if [[ ! -f "${_backup_dir}/${_p}/Bookmarks" ]]; then
echo "restore_chrome_bookmarks: backup no contiene perfil '${_p}': ${_backup_dir}/${_p}/Bookmarks" >&2
return 1
fi
_target_profiles+=("$_p")
done
else
# Autodescubrir todos los perfiles en el backup
local _profile_path
while IFS= read -r -d '' _profile_path; do
local _pname
_pname="$(basename "$(dirname "$_profile_path")")"
_target_profiles+=("$_pname")
done < <(find "$_backup_dir" -mindepth 2 -maxdepth 2 -name "Bookmarks" -print0 | sort -z)
if [[ ${#_target_profiles[@]} -eq 0 ]]; then
echo "restore_chrome_bookmarks: no se encontraron archivos Bookmarks en: ${_backup_dir}" >&2
return 1
fi
fi
# ── restaurar cada perfil ─────────────────────────────────────────────────
local _restored_json=""
local _first=1
local _prof
for _prof in "${_target_profiles[@]}"; do
local _src="${_backup_dir}/${_prof}/Bookmarks"
local _dst_dir="${_user_data_dir}/${_prof}"
local _dst="${_dst_dir}/Bookmarks"
local _dst_bak="${_dst_dir}/Bookmarks.bak"
# Tamaño del archivo fuente para el JSON de salida
local _bytes=0
if [[ -f "$_src" ]]; then
_bytes="$(wc -c < "$_src")"
# Eliminar espacios que wc puede añadir en algunas plataformas
_bytes="${_bytes// /}"
fi
if [[ $_dry_run -eq 1 ]]; then
echo "=== restore_chrome_bookmarks DRY-RUN ===" >&2
echo " Perfil : ${_prof}" >&2
echo " src : ${_src}" >&2
echo " dst : ${_dst}" >&2
echo " bytes : ${_bytes}" >&2
if [[ -f "$_dst_bak" ]]; then
echo " .bak : borraría ${_dst_bak}" >&2
fi
else
# Crear directorio destino si no existe
mkdir -p "$_dst_dir"
# Copiar byte a byte preservando timestamps (NUNCA reserializar)
cp -p "$_src" "$_dst"
# Borrar Bookmarks.bak residual si existe
if [[ -f "$_dst_bak" ]]; then
rm -f "$_dst_bak"
fi
fi
# Construir fragmento JSON para este perfil
local _entry
_entry="$(printf '{"profile":"%s","dst":"%s","bytes":%s}' \
"$_prof" "$_dst" "$_bytes")"
if [[ $_first -eq 1 ]]; then
_restored_json="${_entry}"
_first=0
else
_restored_json+=",$_entry"
fi
done
# ── emitir resultado JSON ─────────────────────────────────────────────────
printf '{"restored":[%s]}\n' "$_restored_json"
}
# ── auto-ejecución ────────────────────────────────────────────────────────────
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
restore_chrome_bookmarks "$@"
fi