From 9ec39b548f1086cf2902a7a74c85bd194fa73ce2 Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Tue, 18 Nov 2025 13:49:26 -0600 Subject: [PATCH] feat: Add SSH keyring synchronization module for GNOME Keyring integration --- Readme.md | 24 ++++++-- modules/apps.sh | 16 ++++- modules/ssh-keyring.sh | 129 +++++++++++++++++++++++++++++++++++++++++ omarchy-setup.sh | 64 +++++--------------- 4 files changed, 176 insertions(+), 57 deletions(-) create mode 100755 modules/ssh-keyring.sh diff --git a/Readme.md b/Readme.md index 74484d0..b60fbe4 100644 --- a/Readme.md +++ b/Readme.md @@ -6,7 +6,7 @@ Script de instalación y configuración **modular** para **Arch Linux / Omarchy* - **✅ Estructura Modular**: Scripts independientes para cada componente - **🎨 Menú Interactivo**: Selecciona qué instalar según tus necesidades -- **🌀 Spinner Inteligente**: Las tareas en background muestran progreso sin invadir los prompts interactivos +- **🌀 Progreso Limpio**: Las tareas en background muestran el estado sin invadir los prompts interactivos - **🔐 Sesión Sudo Persistente**: Reutiliza la contraseña durante toda la ejecución para evitar interrupciones - **🔧 Fácil de Extender**: Agrega nuevos módulos fácilmente @@ -35,6 +35,7 @@ omarchy_zsh_setup/ │ ├── printer.sh # Configuración de impresoras (CUPS) │ ├── mouse_cursor.sh # Tema de cursor Bibata │ ├── icon_manager.sh # Gestor de temas de iconos +│ ├── ssh-keyring.sh # Sincronización de claves SSH con GNOME Keyring │ ├── davinci-resolve.sh # DaVinci Resolve (Intel Edition) └── Readme.md ``` @@ -57,16 +58,17 @@ Selecciona las opciones que deseas instalar: 5) 🖨️ Configurar Impresoras (CUPS) 6) 🖱️ Instalar Tema de Cursor (Bibata) 7) 🎨 Gestionar Temas de Iconos (Papirus, Tela, etc.) + K) 🔐 Sincronizar claves SSH con GNOME Keyring F) 💾 Habilitar Formatos FAT/exFAT/NTFS/ext4 H) 🎨 Instalar Configuración de Hyprland R) 🎬 Instalar DaVinci Resolve (Intel Edition) - A) ✅ Instalar Todo (opciones 1, 2, 3, 4, 5, 6, 7, F, H) + A) ✅ Instalar Todo (opciones 1, 2, K, 3, 4, 5, 6, 7, F, H) 0) 🚪 Salir ``` -> ℹ️ **Nota:** La opción `A) Instalar Todo` ejecuta los módulos 1, 2, 3, 4, 5, 6, 7, F y H. DaVinci Resolve (`R`) no se incluye aquí; instálalo manualmente cuando ya tengas el ZIP en `~/Downloads/`. +> ℹ️ **Nota:** La opción `A) Instalar Todo` ejecuta los módulos 1, 2, K, 3, 4, 5, 6, 7, F y H. DaVinci Resolve (`R`) no se incluye aquí; instálalo manualmente cuando ya tengas el ZIP en `~/Downloads/`. -> 🌀 **Spinner inteligente:** Los módulos en background muestran una animación de progreso pero detienen la animación antes de cualquier interacción con el usuario; toda la salida detallada se imprime limpia y se escribe en `./logs/`. +> 🌀 **Progreso limpio:** Los módulos en background informan su avance sin animaciones invasivas; toda la salida detallada se imprime limpia y se escribe en `./logs/`. ## 📋 Módulos Disponibles @@ -103,6 +105,11 @@ Selecciona las opciones que deseas instalar: ### 7. 🎨 Gestor de Iconos (`icon_manager.sh`) - Menú interactivo para instalar y cambiar entre temas de iconos como Papirus, Tela y Candy. +### K. 🔐 Sincronizar Claves SSH (`ssh-keyring.sh`) +- Inicia/activa GNOME Keyring para componentes `ssh` y `secrets` +- Exporta `SSH_AUTH_SOCK` y registra claves desde `~/.ssh` usando `ssh-add` +- Evita duplicados mediante fingerprints y muestra un resumen al finalizar + ### F. 💾 Soporte de Formatos (`disk-format.sh`) - Instala utilidades para FAT32, exFAT, NTFS y ext4 - Añade herramientas gráficas (GParted, GNOME Disks) para formateo manual @@ -121,6 +128,9 @@ Cada módulo puede ejecutarse de forma independiente: # Configurar solo Zsh ./modules/zsh-config.sh +# Sincronizar claves SSH con GNOME Keyring +./modules/ssh-keyring.sh + # Instalar Docker ./modules/docker.sh ``` @@ -181,6 +191,12 @@ cd omarchy_setup - Genera el archivo de autocompletado `_oh-my-posh` en `~/.local/share/zsh/site-functions` - Modifica `.bashrc` para lanzar Zsh automáticamente +### 🔐 GNOME Keyring SSH +- Arranca el daemon de GNOME Keyring con componentes de `ssh` y `secrets` +- Garantiza que `SSH_AUTH_SOCK` apunte al socket del keyring (persistido en `~/.config/environment.d`) +- Busca claves privadas en `~/.ssh` (excluyendo `.pub` y certificados) y las registra con `ssh-add` +- Evita añadir claves duplicadas y muestra cómo verificar con `ssh-add -l` + ### 🐳 Docker - Portainer (interfaz web de gestión) - Usuario agregado al grupo docker diff --git a/modules/apps.sh b/modules/apps.sh index bb69d32..a9a6263 100755 --- a/modules/apps.sh +++ b/modules/apps.sh @@ -172,7 +172,19 @@ EOF if command_exists ssh-add; then local ssh_dir="${HOME}/.ssh" if [[ -d "$ssh_dir" ]]; then - mapfile -t ssh_private_keys < <(find "$ssh_dir" -maxdepth 1 -type f -name "id_*" ! -name "*.pub" ! -name "*-cert.pub" 2>/dev/null) + mapfile -t ssh_private_keys < <( + find "$ssh_dir" -maxdepth 1 -type f -perm -u=r \ + ! -name "*.pub" \ + ! -name "*-cert.pub" \ + ! -name "known_hosts" \ + ! -name "known_hosts.*" \ + ! -name "authorized_keys" \ + ! -name "config" \ + ! -name "*.old" \ + ! -name "agent" \ + ! -name "*.bak" \ + 2>/dev/null + ) if [[ ${#ssh_private_keys[@]} -gt 0 ]]; then log_info "Agregando claves SSH detectadas al keyring (se solicitará la passphrase si aplica)..." for key_path in "${ssh_private_keys[@]}"; do @@ -183,7 +195,7 @@ EOF if ssh-keygen -y -f "$key_path" >/dev/null 2>&1; then log_info "Registrando clave $(basename "$key_path")..." local spinner_was_active=0 - if [[ -n "${SPINNER_PID:-}" ]]; then + if [[ ${SPINNER_ACTIVE:-0} -eq 1 ]]; then spinner_was_active=1 fi if declare -F pause_spinner >/dev/null; then diff --git a/modules/ssh-keyring.sh b/modules/ssh-keyring.sh new file mode 100755 index 0000000..063c5c4 --- /dev/null +++ b/modules/ssh-keyring.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash +# =============================================================== +# ssh-keyring.sh - Sincronizar claves SSH con GNOME Keyring +# =============================================================== + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/common.sh" + +_derive_fingerprint() { + local key_path="$1" + local pub_path="${key_path}.pub" + local fingerprint="" + + if [[ -f "$pub_path" ]]; then + fingerprint="$(ssh-keygen -lf "$pub_path" 2>/dev/null | awk '{print $2}')" + else + fingerprint="$(ssh-keygen -lf <(ssh-keygen -y -f "$key_path" 2>/dev/null) 2>/dev/null | awk '{print $2}')" + fi + echo "$fingerprint" +} + +sync_ssh_keyring() { + log_step "Sincronizar claves SSH con GNOME Keyring" + + if ! command_exists gnome-keyring-daemon; then + log_error "gnome-keyring-daemon no está instalado. Ejecuta primero el módulo de aplicaciones." + return 1 + fi + + if ! command_exists ssh-add; then + log_error "ssh-add no está disponible (openssh). Instala el módulo de aplicaciones antes." + return 1 + fi + + mkdir -p "${HOME}/.config/environment.d" + cat <<'EOF' > "${HOME}/.config/environment.d/10-gnome-keyring.conf" +SSH_AUTH_SOCK=/run/user/$UID/keyring/ssh +EOF + + local keyring_eval="" + if keyring_eval="$(gnome-keyring-daemon --start --components=ssh,secrets 2>/dev/null)"; then + eval "$keyring_eval" + log_success "GNOME Keyring iniciado." + else + log_info "GNOME Keyring ya estaba en ejecución." + fi + + local keyring_socket="${SSH_AUTH_SOCK:-/run/user/$UID/keyring/ssh}" + if [[ ! -S "$keyring_socket" ]]; then + log_warning "No se encontró el socket de GNOME Keyring en ${keyring_socket}." + if [[ -S "/run/user/$UID/keyring/ssh" ]]; then + keyring_socket="/run/user/$UID/keyring/ssh" + else + log_error "GNOME Keyring no expone el componente SSH. Revisa tu sesión." + return 1 + fi + fi + export SSH_AUTH_SOCK="$keyring_socket" + + local ssh_dir="${HOME}/.ssh" + if [[ ! -d "$ssh_dir" ]]; then + log_warning "No existe el directorio ${ssh_dir}. No hay claves para agregar." + return 0 + fi + + mapfile -t ssh_private_keys < <( + find "$ssh_dir" -maxdepth 1 -type f -perm -u=r \ + ! -name "*.pub" \ + ! -name "*-cert.pub" \ + ! -name "known_hosts" \ + ! -name "known_hosts.*" \ + ! -name "authorized_keys" \ + ! -name "config" \ + ! -name "*.old" \ + ! -name "agent" \ + ! -name "*.bak" \ + 2>/dev/null | sort + ) + if [[ ${#ssh_private_keys[@]} -eq 0 ]]; then + log_warning "No se encontraron claves privadas SSH en ${ssh_dir}." + return 0 + fi + + local existing_fingerprints="" + if output=$(SSH_AUTH_SOCK="$SSH_AUTH_SOCK" ssh-add -l 2>/dev/null); then + existing_fingerprints="$(awk '{print $2}' <<<"$output")" + else + existing_fingerprints="" + fi + + local added=0 + for key_path in "${ssh_private_keys[@]}"; do + local fingerprint + fingerprint="$(_derive_fingerprint "$key_path")" + if [[ -z "$fingerprint" ]] && ! ssh-keygen -y -f "$key_path" >/dev/null 2>&1; then + log_warning "El archivo $(basename "$key_path") no parece una clave privada válida. Se omite." + continue + fi + + if [[ -n "$fingerprint" ]] && grep -Fq "$fingerprint" <<<"$existing_fingerprints"; then + log_info "Clave $(basename "$key_path") ya está registrada en el keyring." + continue + fi + + log_info "Añadiendo clave $(basename "$key_path") al keyring..." + if SSH_AUTH_SOCK="$SSH_AUTH_SOCK" ssh-add "$key_path"; then + log_success "Clave $(basename "$key_path") añadida correctamente." + added=$((added + 1)) + if [[ -n "$fingerprint" ]]; then + existing_fingerprints+=$'\n'"$fingerprint" + fi + else + log_warning "No se pudo añadir la clave $(basename "$key_path")." + fi + done + + if [[ $added -gt 0 ]]; then + log_success "Claves SSH sincronizadas con GNOME Keyring." + else + log_info "No se añadieron nuevas claves SSH." + fi + + log_info "Para verificar, ejecuta: ssh-add -l" + return 0 +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + sync_ssh_keyring "$@" +fi diff --git a/omarchy-setup.sh b/omarchy-setup.sh index a1407c9..762d26e 100755 --- a/omarchy-setup.sh +++ b/omarchy-setup.sh @@ -32,74 +32,36 @@ source "${MODULES_DIR}/common.sh" log_info "Verificando permisos de los módulos..." chmod +x "${MODULES_DIR}"/*.sh 2>/dev/null || true -# --- Funciones de UI Mejorada (Spinner y Barra de Progreso) --- +# --- Funciones de UI Mejorada (Indicador de Progreso) --- -SPINNER_PID= -SPINNER_DEVICE_ACTIVE= +SPINNER_ACTIVE=0 SPINNER_MESSAGE= spinner_clear_line() { - local device="${SPINNER_DEVICE_ACTIVE:-/dev/tty}" - if [[ ! -w "$device" ]]; then - device="/dev/null" - fi - printf '\r\033[K' >"$device" 2>/dev/null || true + : } pause_spinner() { - local device="${SPINNER_DEVICE_ACTIVE:-/dev/tty}" - if [[ ! -w "$device" ]]; then - device="/dev/null" + if (( SPINNER_ACTIVE )); then + SPINNER_ACTIVE=0 fi - if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then - kill "$SPINNER_PID" &>/dev/null || true - wait "$SPINNER_PID" &>/dev/null || true - fi - spinner_clear_line - printf '\033[?25h' >"$device" 2>/dev/null || true - SPINNER_PID= } resume_spinner() { if [[ -n "$SPINNER_MESSAGE" ]]; then - start_spinner "$SPINNER_MESSAGE" + log_info "$SPINNER_MESSAGE" + SPINNER_ACTIVE=1 fi } -# Inicia una animación de spinner en segundo plano -# Uso: start_spinner "Mensaje..." start_spinner() { local message="$1" - if [[ -n "$SPINNER_PID" ]]; then - pause_spinner - fi - - local device="/dev/tty" - if [[ ! -w "$device" ]]; then - device="/dev/null" - fi - - SPINNER_DEVICE_ACTIVE="$device" + pause_spinner SPINNER_MESSAGE="$message" - - ( - local chars="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" - local dev="$device" - local msg="$message" - while :; do - for (( i=0; i<${#chars}; i++ )); do - printf '\r\033[K%s %s' "${CYAN}${chars:$i:1}${NC}" "$msg" >"$dev" - sleep 0.1 - done - done - ) & - SPINNER_PID=$! - # Ocultar cursor en la terminal, si es posible - printf '\033[?25l' >"$device" 2>/dev/null || true + SPINNER_ACTIVE=1 + log_info "$message" } -# Detiene el spinner y muestra un mensaje de finalización -# Uso: stop_spinner $? "Mensaje de éxito" "Mensaje de error" stop_spinner() { local exit_code=$1 local success_msg=$2 @@ -113,7 +75,6 @@ stop_spinner() { log_error "$error_msg" fi - SPINNER_DEVICE_ACTIVE= SPINNER_MESSAGE= } @@ -174,13 +135,14 @@ MODULES=( ["5"]="printer;install_printer;🖨️ Configurar Impresoras (CUPS);bg" ["6"]="mouse_cursor;install_mouse_cursor;🖱️ Instalar Tema de Cursor (Bibata);bg" ["7"]="icon_manager;run_module_main;🎨 Gestionar Temas de Iconos (Papirus, Tela, etc.);fg" + ["K"]="ssh-keyring;sync_ssh_keyring;🔐 Sincronizar claves SSH con GNOME Keyring;fg" ["F"]="disk-format;run_module_main;💾 Habilitar Formatos FAT/exFAT/NTFS/ext4;bg" ["R"]="davinci-resolve;install_davinci_resolve;🎬 Instalar DaVinci Resolve (Intel Edition);fg" ["H"]="hyprland-config;run_module_main;🎨 Instalar Configuración de Hyprland;bg" ) # Módulos a incluir en la opción "Instalar Todo" -INSTALL_ALL_CHOICES=("1" "2" "3" "4" "5" "6" "7" "F" "H") +INSTALL_ALL_CHOICES=("1" "2" "K" "3" "4" "5" "6" "7" "F" "H") # Función para mostrar el menú show_menu() { @@ -423,7 +385,7 @@ main() { read -p "Presiona Enter para continuar..." elif [[ "$choice" == "A" ]]; then - log_warning "La opción 'Instalar Todo' ejecutará los módulos: 1, 2, 3, 4, 5, 6, 7, F y H." + log_warning "La opción 'Instalar Todo' ejecutará los módulos: 1, 2, K, 3, 4, 5, 6, 7, F y H." log_info "DaVinci Resolve (opción R) no se ejecutará en este lote; instálalo aparte cuando ya tengas el ZIP." echo -ne "${BOLD}¿Confirmas que deseas instalar todas las opciones ahora? [s/N]: ${NC}" read -r confirm