feat: Add SSH keyring synchronization module for GNOME Keyring integration

This commit is contained in:
Marco Gallegos
2025-11-18 13:49:26 -06:00
parent 8372aff1b8
commit 9ec39b548f
4 changed files with 176 additions and 57 deletions

View File

@@ -6,7 +6,7 @@ Script de instalación y configuración **modular** para **Arch Linux / Omarchy*
- **✅ Estructura Modular**: Scripts independientes para cada componente - **✅ Estructura Modular**: Scripts independientes para cada componente
- **🎨 Menú Interactivo**: Selecciona qué instalar según tus necesidades - **🎨 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 - **🔐 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 - **🔧 Fácil de Extender**: Agrega nuevos módulos fácilmente
@@ -35,6 +35,7 @@ omarchy_zsh_setup/
│ ├── printer.sh # Configuración de impresoras (CUPS) │ ├── printer.sh # Configuración de impresoras (CUPS)
│ ├── mouse_cursor.sh # Tema de cursor Bibata │ ├── mouse_cursor.sh # Tema de cursor Bibata
│ ├── icon_manager.sh # Gestor de temas de iconos │ ├── 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) │ ├── davinci-resolve.sh # DaVinci Resolve (Intel Edition)
└── Readme.md └── Readme.md
``` ```
@@ -57,16 +58,17 @@ Selecciona las opciones que deseas instalar:
5) 🖨️ Configurar Impresoras (CUPS) 5) 🖨️ Configurar Impresoras (CUPS)
6) 🖱️ Instalar Tema de Cursor (Bibata) 6) 🖱️ Instalar Tema de Cursor (Bibata)
7) 🎨 Gestionar Temas de Iconos (Papirus, Tela, etc.) 7) 🎨 Gestionar Temas de Iconos (Papirus, Tela, etc.)
K) 🔐 Sincronizar claves SSH con GNOME Keyring
F) 💾 Habilitar Formatos FAT/exFAT/NTFS/ext4 F) 💾 Habilitar Formatos FAT/exFAT/NTFS/ext4
H) 🎨 Instalar Configuración de Hyprland H) 🎨 Instalar Configuración de Hyprland
R) 🎬 Instalar DaVinci Resolve (Intel Edition) 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 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 ## 📋 Módulos Disponibles
@@ -103,6 +105,11 @@ Selecciona las opciones que deseas instalar:
### 7. 🎨 Gestor de Iconos (`icon_manager.sh`) ### 7. 🎨 Gestor de Iconos (`icon_manager.sh`)
- Menú interactivo para instalar y cambiar entre temas de iconos como Papirus, Tela y Candy. - 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`) ### F. 💾 Soporte de Formatos (`disk-format.sh`)
- Instala utilidades para FAT32, exFAT, NTFS y ext4 - Instala utilidades para FAT32, exFAT, NTFS y ext4
- Añade herramientas gráficas (GParted, GNOME Disks) para formateo manual - 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 # Configurar solo Zsh
./modules/zsh-config.sh ./modules/zsh-config.sh
# Sincronizar claves SSH con GNOME Keyring
./modules/ssh-keyring.sh
# Instalar Docker # Instalar Docker
./modules/docker.sh ./modules/docker.sh
``` ```
@@ -181,6 +191,12 @@ cd omarchy_setup
- Genera el archivo de autocompletado `_oh-my-posh` en `~/.local/share/zsh/site-functions` - Genera el archivo de autocompletado `_oh-my-posh` en `~/.local/share/zsh/site-functions`
- Modifica `.bashrc` para lanzar Zsh automáticamente - 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 ### 🐳 Docker
- Portainer (interfaz web de gestión) - Portainer (interfaz web de gestión)
- Usuario agregado al grupo docker - Usuario agregado al grupo docker

View File

@@ -172,7 +172,19 @@ EOF
if command_exists ssh-add; then if command_exists ssh-add; then
local ssh_dir="${HOME}/.ssh" local ssh_dir="${HOME}/.ssh"
if [[ -d "$ssh_dir" ]]; then 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 if [[ ${#ssh_private_keys[@]} -gt 0 ]]; then
log_info "Agregando claves SSH detectadas al keyring (se solicitará la passphrase si aplica)..." log_info "Agregando claves SSH detectadas al keyring (se solicitará la passphrase si aplica)..."
for key_path in "${ssh_private_keys[@]}"; do 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 if ssh-keygen -y -f "$key_path" >/dev/null 2>&1; then
log_info "Registrando clave $(basename "$key_path")..." log_info "Registrando clave $(basename "$key_path")..."
local spinner_was_active=0 local spinner_was_active=0
if [[ -n "${SPINNER_PID:-}" ]]; then if [[ ${SPINNER_ACTIVE:-0} -eq 1 ]]; then
spinner_was_active=1 spinner_was_active=1
fi fi
if declare -F pause_spinner >/dev/null; then if declare -F pause_spinner >/dev/null; then

129
modules/ssh-keyring.sh Executable file
View File

@@ -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

View File

@@ -32,74 +32,36 @@ source "${MODULES_DIR}/common.sh"
log_info "Verificando permisos de los módulos..." log_info "Verificando permisos de los módulos..."
chmod +x "${MODULES_DIR}"/*.sh 2>/dev/null || true 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_ACTIVE=0
SPINNER_DEVICE_ACTIVE=
SPINNER_MESSAGE= SPINNER_MESSAGE=
spinner_clear_line() { 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() { pause_spinner() {
local device="${SPINNER_DEVICE_ACTIVE:-/dev/tty}" if (( SPINNER_ACTIVE )); then
if [[ ! -w "$device" ]]; then SPINNER_ACTIVE=0
device="/dev/null"
fi 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() { resume_spinner() {
if [[ -n "$SPINNER_MESSAGE" ]]; then if [[ -n "$SPINNER_MESSAGE" ]]; then
start_spinner "$SPINNER_MESSAGE" log_info "$SPINNER_MESSAGE"
SPINNER_ACTIVE=1
fi fi
} }
# Inicia una animación de spinner en segundo plano
# Uso: start_spinner "Mensaje..."
start_spinner() { start_spinner() {
local message="$1" local message="$1"
if [[ -n "$SPINNER_PID" ]]; then pause_spinner
pause_spinner
fi
local device="/dev/tty"
if [[ ! -w "$device" ]]; then
device="/dev/null"
fi
SPINNER_DEVICE_ACTIVE="$device"
SPINNER_MESSAGE="$message" SPINNER_MESSAGE="$message"
SPINNER_ACTIVE=1
( log_info "$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
} }
# Detiene el spinner y muestra un mensaje de finalización
# Uso: stop_spinner $? "Mensaje de éxito" "Mensaje de error"
stop_spinner() { stop_spinner() {
local exit_code=$1 local exit_code=$1
local success_msg=$2 local success_msg=$2
@@ -113,7 +75,6 @@ stop_spinner() {
log_error "$error_msg" log_error "$error_msg"
fi fi
SPINNER_DEVICE_ACTIVE=
SPINNER_MESSAGE= SPINNER_MESSAGE=
} }
@@ -174,13 +135,14 @@ MODULES=(
["5"]="printer;install_printer;🖨️ Configurar Impresoras (CUPS);bg" ["5"]="printer;install_printer;🖨️ Configurar Impresoras (CUPS);bg"
["6"]="mouse_cursor;install_mouse_cursor;🖱️ Instalar Tema de Cursor (Bibata);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" ["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" ["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" ["R"]="davinci-resolve;install_davinci_resolve;🎬 Instalar DaVinci Resolve (Intel Edition);fg"
["H"]="hyprland-config;run_module_main;🎨 Instalar Configuración de Hyprland;bg" ["H"]="hyprland-config;run_module_main;🎨 Instalar Configuración de Hyprland;bg"
) )
# Módulos a incluir en la opción "Instalar Todo" # 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ú # Función para mostrar el menú
show_menu() { show_menu() {
@@ -423,7 +385,7 @@ main() {
read -p "Presiona Enter para continuar..." read -p "Presiona Enter para continuar..."
elif [[ "$choice" == "A" ]]; then 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." 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}" echo -ne "${BOLD}¿Confirmas que deseas instalar todas las opciones ahora? [s/N]: ${NC}"
read -r confirm read -r confirm