diff --git a/bin/versadm_token.sh b/bin/versadm_token.sh new file mode 100755 index 0000000..b3c8135 --- /dev/null +++ b/bin/versadm_token.sh @@ -0,0 +1,419 @@ +#!/bin/bash +# ------------------------------------------------------------------ +# [Author] Cortana Rosero One +# [Title] versadm_token.sh - Administrador de Tokens para Control de Versiones +# [Generated] Created by Claude Code (claude-3-7-sonnet-20250219) +# +# AGPL License +# Modified date: 14/03/2025 +# ------------------------------------------------------------------ + +# Directorios base +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_DIR="$(dirname "$SCRIPT_DIR")" +CONFIG_DIR="$SCRIPT_DIR/config" +LIB_DIR="$SCRIPT_DIR/lib" +MSG_DIR="$SCRIPT_DIR/msg" +DEVELOPER_DIR="$HOME/.developer" + +# Cargar libraries +source "$LIB_DIR/base.lib" +source "$LIB_DIR/console.lib" +source "$MSG_DIR/head.es" + +# Variables globales +title="ADMINISTRADOR DE TOKENS PARA CONTROL DE VERSIONES" +apps_title="Gestión de Tokens Git" +SOPS_CONFIG_DIR="$DEVELOPER_DIR" + +# Opciones de sistemas de control de versiones +VCS_TYPES=("GitHub" "GitLab" "Forgejo/Codeberg") +VCS_COMMANDS=("gh" "glab" "berg") +VCS_TOKENS=("github.sops.yaml" "gitlab.sops.yaml" "forgejo.sops.yaml") +VCS_INSTALLERS=("ghcli_install.sh" "glcli_install.sh" "fjcli_install.sh") +VCS_TOKEN_URLS=("https://github.com/settings/tokens" "https://gitlab.com/-/profile/personal_access_tokens" "Sección Aplicaciones en su perfil de usuario") + +# Verificar que SOPS esté instalado +check_sops() { + if ! command -v sops &> /dev/null; then + dialog --backtitle "${title}" --title "${head_error}" --msgbox "El programa 'sops' no está instalado. Es necesario para encriptar tokens." 7 60 + exit 1 + fi +} + +# Verificar que dialog esté instalado +check_dialog() { + if ! command -v dialog &> /dev/null; then + echo -e "${head_001}" + exit 1 + fi +} + +# Crear directorio para tokens si no existe +check_token_directory() { + if [ ! -d "$SOPS_CONFIG_DIR" ]; then + mkdir -p "$SOPS_CONFIG_DIR" + fi + + # Asegurar que el directorio tenga permisos adecuados + chmod 700 "$SOPS_CONFIG_DIR" +} + +# Mostrar ayuda detallada sobre tokens +show_token_help() { + local vcs_index=$1 + local vcs_name=${VCS_TYPES[$vcs_index]} + local help_text="" + + case "$vcs_index" in + 0) # GitHub + help_text="AYUDA PARA TOKENS DE GITHUB\n\n" + help_text+="Para generar un token personal en GitHub:\n\n" + help_text+="1. Inicie sesión en GitHub y vaya a Configuración -> Configuración de desarrollador -> Tokens de acceso personal\n" + help_text+=" URL: ${VCS_TOKEN_URLS[$vcs_index]}\n\n" + help_text+="2. Haga clic en 'Generar nuevo token'\n\n" + help_text+="3. Proporcione una nota descriptiva para el token\n\n" + help_text+="4. Seleccione los permisos necesarios:\n" + help_text+=" - Para uso general: repo, workflow, read:org\n" + help_text+=" - Para acceso más limitado, solo seleccione lo que necesite\n\n" + help_text+="5. Haga clic en 'Generar token'\n\n" + help_text+="6. Copie el token inmediatamente (solo se muestra una vez)" + ;; + 1) # GitLab + help_text="AYUDA PARA TOKENS DE GITLAB\n\n" + help_text+="Para generar un token personal en GitLab:\n\n" + help_text+="1. Inicie sesión en GitLab y vaya a Preferencias -> Tokens de acceso\n" + help_text+=" URL: ${VCS_TOKEN_URLS[$vcs_index]}\n\n" + help_text+="2. Proporcione un nombre para el token\n\n" + help_text+="3. Opcionalmente, establezca una fecha de vencimiento\n\n" + help_text+="4. Seleccione los permisos necesarios:\n" + help_text+=" - Para uso general: api, read_repository, write_repository\n" + help_text+=" - Para acceso más limitado, solo seleccione lo que necesite\n\n" + help_text+="5. Haga clic en 'Crear token de acceso personal'\n\n" + help_text+="6. Copie el token inmediatamente (solo se muestra una vez)" + ;; + 2) # Forgejo/Codeberg + help_text="AYUDA PARA TOKENS DE FORGEJO/CODEBERG\n\n" + help_text+="Para generar un token personal en Forgejo o Codeberg:\n\n" + help_text+="1. Inicie sesión en su instancia de Forgejo o en Codeberg\n\n" + help_text+="2. Vaya a Configuración -> Aplicaciones\n\n" + help_text+="3. En la sección 'Generar nuevo token', proporcione un nombre\n\n" + help_text+="4. Seleccione los permisos necesarios (alcances):\n" + help_text+=" - Para uso general: repo, repo:status\n" + help_text+=" - Para acceso más limitado, solo seleccione lo que necesite\n\n" + help_text+="5. Haga clic en 'Generar token'\n\n" + help_text+="6. Copie el token inmediatamente (solo se muestra una vez)" + ;; + esac + + dialog --backtitle "${title}" --title "Ayuda sobre tokens de $vcs_name" --msgbox "$help_text" 22 75 +} + +# Diálogo personalizado para solicitar token con botón de ayuda +request_token_with_help() { + local vcs_index=$1 + local vcs_name=${VCS_TYPES[$vcs_index]} + local prompt="Ingrese su token personal de $vcs_name:" + local helper="Puede generar un nuevo token en: ${VCS_TOKEN_URLS[$vcs_index]}" + local button=0 + local token="" + + while [ $button -ne 1 ]; do + # Crear diálogo temporal + tempfile=$(mktemp) + + # Mostrar diálogo con 3 botones (Cancelar, OK, Ayuda) + dialog --backtitle "${title}" --title "${apps_title}" \ + --passwordbox "\n$prompt\n\n$helper" 12 70 \ + --extra-button --extra-label "Ayuda" 2>"$tempfile" + + button=$? + + # Procesar resultado según el botón presionado + case $button in + 0) # OK + token=$(cat "$tempfile") + rm -f "$tempfile" + + # Validar el token + if [ -z "$token" ]; then + dialog --backtitle "${title}" --title "${head_error}" --msgbox "El token no puede estar vacío. Por favor ingrese un token válido." 7 60 + button=3 # Mantener el bucle activo + continue + fi + + if [ ${#token} -lt 20 ]; then + dialog_yesno "El token parece ser demasiado corto. Verifique que haya copiado el token completo.\n\n¿Desea continuar de todas formas?" 10 70 + if [ $? -ne 0 ]; then + button=3 # Mantener el bucle activo + continue + fi + fi + + # Devolver el token si es válido + echo "$token" + return 0 + ;; + 1) # Cancelar + rm -f "$tempfile" + return 1 + ;; + 3) # Botón extra (Ayuda) + rm -f "$tempfile" + show_token_help "$vcs_index" + ;; + esac + done + + return 1 +} + +# Verificar e instalar CLI si es necesario +check_and_install_cli() { + local vcs_index=$1 + local command=${VCS_COMMANDS[$vcs_index]} + local vcs_name=${VCS_TYPES[$vcs_index]} + local installer="$SCRIPT_DIR/${VCS_INSTALLERS[$vcs_index]}" + + if ! command -v "$command" &> /dev/null; then + dialog_yesno "El CLI de $vcs_name ($command) no está instalado.\n¿Desea instalarlo ahora?" 8 60 + if [ $? -eq 0 ]; then + if [ -f "$installer" ]; then + clear + echo "Instalando CLI de $vcs_name..." + bash "$installer" + local result=$? + echo "Presione Enter para continuar..." + read + return $result + else + dialog --backtitle "${title}" --title "${head_error}" --msgbox "No se encontró el script de instalación para $vcs_name:\n$installer" 8 70 + return 1 + fi + else + dialog --backtitle "${title}" --title "${head_info}" \ + --msgbox "El CLI es necesario para interactuar completamente con $vcs_name.\nEl token se guardará de todas formas, pero no podrá verificar la conexión automáticamente." 9 70 + return 0 + fi + fi + + return 0 +} + +# Guardar token cifrado con SOPS +save_encrypted_token() { + local vcs_index=$1 + local token=$2 + local vcs_name=${VCS_TYPES[$vcs_index]} + local token_file="$SOPS_CONFIG_DIR/${VCS_TOKENS[$vcs_index]}" + + # Crear archivo YAML y encriptarlo con SOPS + echo "creating_token: \"$token\"" > "/tmp/token_temp.yaml" + sops --encrypt "/tmp/token_temp.yaml" > "$token_file" 2>/dev/null + + # Eliminar archivo temporal + rm -f "/tmp/token_temp.yaml" + + # Verificar resultado de la encriptación + if [ $? -eq 0 ]; then + # Establecer permisos adecuados + chmod 600 "$token_file" + + dialog --backtitle "${title}" --title "Encriptación Exitosa" \ + --msgbox "El token de $vcs_name ha sido encriptado exitosamente en:\n$token_file" 8 70 + return 0 + else + dialog --backtitle "${title}" --title "${head_error}" \ + --msgbox "Falló la encriptación del token de $vcs_name." 7 50 + return 1 + fi +} + +# Probar conexión con el servicio +test_connection() { + local vcs_index=$1 + local vcs_name=${VCS_TYPES[$vcs_index]} + local command=${VCS_COMMANDS[$vcs_index]} + local token_file="$SOPS_CONFIG_DIR/${VCS_TOKENS[$vcs_index]}" + local connection_status="" + local connection_message="" + + dialog --backtitle "${title}" --title "Prueba de conexión" --infobox "Probando conexión con $vcs_name..." 5 60 + + case "$vcs_index" in + 0) # GitHub + if command -v $command &> /dev/null; then + connection_status=$(gh api user 2>&1) + if [ $? -eq 0 ]; then + local username=$(echo "$connection_status" | grep '"login"' | cut -d'"' -f4) + connection_message="Conexión exitosa con GitHub.\nUsuario autenticado: $username" + else + connection_message="Error al conectar con GitHub:\n$connection_status" + fi + else + connection_message="CLI de GitHub no está instalado." + fi + ;; + 1) # GitLab + if command -v $command &> /dev/null; then + connection_status=$(glab api user 2>&1) + if [ $? -eq 0 ]; then + local username=$(echo "$connection_status" | grep '"username"' | cut -d'"' -f4) + connection_message="Conexión exitosa con GitLab.\nUsuario autenticado: $username" + else + connection_message="Error al conectar con GitLab:\n$connection_status" + fi + else + connection_message="CLI de GitLab no está instalado." + fi + ;; + 2) # Forgejo/Codeberg + if command -v $command &> /dev/null; then + # Intentar usar el token de SOPS para la autenticación + if [ -f "$token_file" ]; then + local token=$(sops --decrypt "$token_file" 2>/dev/null | grep 'creating_token' | cut -d'"' -f2) + if [ -n "$token" ]; then + connection_status=$(curl -s -H "Authorization: token $token" "https://codeberg.org/api/v1/user" 2>&1) + if echo "$connection_status" | grep -q '"username"'; then + local username=$(echo "$connection_status" | grep '"username"' | cut -d'"' -f4) + connection_message="Conexión exitosa con Forgejo/Codeberg.\nUsuario autenticado: $username" + else + connection_message="Error al conectar con Forgejo/Codeberg:\n$connection_status" + fi + else + connection_message="No se pudo extraer el token del archivo cifrado." + fi + else + connection_message="No se encontró un token configurado para Forgejo/Codeberg." + fi + else + connection_message="CLI de Forgejo/Codeberg no está instalado." + fi + ;; + esac + + dialog --backtitle "${title}" --title "Resultado de la prueba" --msgbox "$connection_message" 15 70 +} + +# Función principal para gestionar tokens +manage_vcs_token() { + # Construir opciones para el menú + local menu_options="" + for i in "${!VCS_TYPES[@]}"; do + local token_file="$SOPS_CONFIG_DIR/${VCS_TOKENS[$i]}" + local status="" + if [ -f "$token_file" ]; then + status="[✓]" + else + status="[ ]" + fi + menu_options+="$((i+1)) \"${VCS_TYPES[$i]} $status\" " + done + + # Mostrar menú de selección + dialog_input_menu "Seleccione la plataforma de control de versiones:" \ + "Seleccione la plataforma para la cual desea gestionar el token" \ + "$menu_options" \ + 15 70 + + if [ $codex -ne 0 ]; then + return 1 + fi + + # Calcular índice (0-based) a partir de la selección (1-based) + local selection=$((value-1)) + + # Verificar índice válido + if [ $selection -lt 0 ] || [ $selection -ge ${#VCS_TYPES[@]} ]; then + dialog --backtitle "${title}" --title "${head_error}" --msgbox "Selección inválida." 7 50 + return 1 + fi + + local vcs_name=${VCS_TYPES[$selection]} + local token_file="$SOPS_CONFIG_DIR/${VCS_TOKENS[$selection]}" + + # Mostrar menú de acciones + local action_menu="1 \"Configurar token\" " + + if [ -f "$token_file" ]; then + action_menu+="2 \"Probar conexión\" " + action_menu+="3 \"Eliminar token\" " + fi + + dialog_input_menu "Acciones para $vcs_name:" \ + "Seleccione la acción que desea realizar" \ + "$action_menu" \ + 12 70 + + if [ $codex -ne 0 ]; then + return 1 + fi + + case "$value" in + 1) # Configurar token + # Verificar si ya existe un token + if [ -f "$token_file" ]; then + dialog_yesno "Ya existe un token configurado para $vcs_name.\n¿Desea reemplazarlo?" 8 60 + if [ $? -ne 0 ]; then + return 0 + fi + fi + + # Verificar e instalar CLI si es necesario + check_and_install_cli "$selection" + + # Solicitar token + local token=$(request_token_with_help "$selection") + if [ $? -ne 0 ]; then + return 1 + fi + + # Guardar token + save_encrypted_token "$selection" "$token" + + # Preguntar si desea probar la conexión + if command -v "${VCS_COMMANDS[$selection]}" &> /dev/null; then + dialog_yesno "¿Desea probar la conexión con $vcs_name usando el token configurado?" 8 60 + if [ $? -eq 0 ]; then + test_connection "$selection" + fi + fi + ;; + 2) # Probar conexión + test_connection "$selection" + ;; + 3) # Eliminar token + dialog_yesno "¿Está seguro de que desea eliminar el token de $vcs_name?\nEsta acción no se puede deshacer." 8 60 + if [ $? -eq 0 ]; then + rm -f "$token_file" + dialog --backtitle "${title}" --title "Token eliminado" --msgbox "El token de $vcs_name ha sido eliminado." 7 50 + fi + ;; + esac + + return 0 +} + +# Función principal +main() { + # Verificar requisitos + check_dialog + check_sops + check_token_directory + + while true; do + # Ejecutar la función principal + manage_vcs_token + + # Preguntar si desea continuar o salir + dialog_yesno "¿Desea volver al menú principal?" 7 60 + if [ $? -ne 0 ]; then + break + fi + done +} + +# Ejecutar función principal +main + +exit 0 \ No newline at end of file