#!/bin/bash # # Library: developers.lib # Description: Developers Tools Library # Modified: 2024/12/09 08:20:00 # Derechos de Autor (C) [2024] [Mauro Rosero P. ] # # Este programa es software libre: usted puede redistribuirlo y/o modificarlo # bajo los términos de la Licencia Pública Affero General de GNU tal como # lo publica la Free Software Foundation, ya sea la versión 3 de la licencia, # o (a su elección) cualquier versión posterior. # # Este programa se distribuye con la esperanza de que sea útil, # pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de # COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la # Licencia Pública Affero General de GNU para obtener más detalles. # # Debería haber recibido una copia de la Licencia Pública Affero General # junto con este programa. Si no la recibió, consulte . GPG_DEFAULT_PATH=$HOME/.gnupg GPG_CONFIG_PATH=bin/config GPG_TEMPLATE=gpg.config GPG_CONFIG=gpg.conf GPG_BACKUP_CFG=gpg.backup GPGP_BACKUP_SECRET=gpg.secret GPG_SUBKEY_ID="" GPG_REVOKE_FILES="*.rev" DB_GPG_PATH=$HOME/.gnupg DB_GPG_FILE=$USER.db DB_GPG_SUBKEYS_KEY="subkey_id" DB_GPG_SUBKEYS="GPG_SUBKEYS" SQL_GPG_SUBKEYS="${DB_GPG_SUBKEYS}.sql" # Test library function devslib_test() { echo "Developers Library loaded!" exit 1 } # Set gpg environment function gpg_setting() { local BIN_CONFIG=$1 local GPG_PATH=$2 local LOCAL_BACKUP=$3 local TIMESTAMP=$4 # Check if gpg directory path exists if [ ! -d "${GPG_PATH}" ] then # Create gpg directory path mkdir -p ${GPG_PATH} if [ $? -ne 0 ]; then return 2 fi fi # Check if gpg template file exists if [ ! -f "${BIN_CONFIG}/${GPG_CFG_PATH}/${GPG_TEMPLATE}" ] then return 1 fi if [ -d "${LOCAL_BACKUP}" ] then if [ -f "${GPG_PATH}/${GPG_CONFIG}" ] then # Destination file backup local BACKUP_FILE="${LOCAL_BACKUP}/gpg_${TIMESTAMP}.bak" cp -f "${GPG_PATH}/${GPG_CONFIG}" "${BACKUP_FILE}" if [ $? -ne 0 ]; then return 3 fi fi fi # Copia el archivo de plantilla al destino cp -f "${BIN_CONFIG}/${GPG_CFG_PATH}/${GPG_TEMPLATE}" "${GPG_PATH}/${GPG_CONFIG}" return $? } # Generate token for backup file function gpg_backup_token() { local SECRET_FILE=$1 if [[ ! -e $archivo_token ]] then local BACKUP_TOKEN=$(uuidgen | base64 ) echo "$BACKUP_TOKEN" > "$SECRET_FILE" chmod 600 "$SECRET_FILE" fi return 0 } # FULL EXTENDED GNUGP BACKUP function developer_backup() { local DB_BACKUP=$1 local BIN_CONFIG=$2 local TIMESTAMP=$3 local GNUGP_PATH=$4 local rc=0 # Check if backup configuration file exists if [ ! -f $BIN_CONFIG/$GPG_BACKUP_CFG ] then return 10 fi local LOCAL_BACKUP=$HOME/$(cat < $BIN_CONFIG/$GPG_BACKUP_CFG) # Check if backup path exist if [ -z "$LOCAL_BACKUP" ]; then return 11 fi if [ ! -d "${LOCAL_BACKUP}" ] then mkdir -p "${LOCAL_BACKUP}" rc=$? if [ $rc -ne 0 ]; then return $rc fi fi gpg_backup_token "${LOCAL_BACKUP}/$GPGP_BACKUP_SECRET" # Get secret backup ZPASSWORD=$(echo "$(cat < "${LOCAL_BACKUP}/$GPGP_BACKUP_SECRET")" | base64 -d) if [ -z "${ZPASSWORD}" ]; then return 13 fi # Export full backup keys to backup work path local TMP_PATH=$(mktemp -d) local TMP_FILE="gpg.bak" gpg --export-options backup -o "${TMP_PATH}/${TMP_FILE}" --export rc=$? if [ $rc -ne 0 ]; then rm -rf "${tmp_path}" return $rc fi # Dump GPG_SUBKEYS table to SQL local TMP_DB_DUMP="${SQL_GPG_SUBKEYS}" local DB_DUMP="${TMP_PATH}/${TMP_DB_DUMP}" sqlite_dump "${DB_BACKUP}" "${DB_DUMP}" "${DB_GPG_SUBKEYS}" rc=$? if [ ${rc} -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi # Copy full .gnupg for backup mkdir ${TMP_PATH}/.gnupg if [ $? -eq 0 ]; then cp -rf $GNUGP_PATH/* ${TMP_PATH}/.gnupg/ rc=$? if [ $rc -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi fi # Copy full .ssh for backup mkdir ${TMP_PATH}/.ssh if [ $? -eq 0 ]; then cp -rf $HOME/.ssh/* ${TMP_PATH}/.ssh/ rc=$? if [ $rc -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi fi # Copy .giconfig for user to backup if [ -f $HOME/.gitconfig ]; then cp -f $HOME/.gitconfig ${TMP_PATH}/ rc=$? if [ $rc -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi fi # Copy .developer folder for user to backup mkdir ${TMP_PATH}/.developer if [ $? -eq 0 ] && [ -d $HOME/.developer ]; then cp -rf $HOME/.developer/* ${TMP_PATH}/.developer/ rc=$? if [ $rc -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi fi # Change backup work path to make zip archive cd "${TMP_PATH}" # Comprimir el archivo de respaldo en un archivo ZIP protegido con contraseña BACKUP_FILE="${LOCAL_BACKUP}/gpg_${USER}_${TIMESTAMP}" zip -qqr -P "${ZPASSWORD}" $BACKUP_FILE * .gnupg .ssh .gitconfig .developer rc=$? if [ $rc -ne 0 ] then rm -rf "${TMP_PATH}" return $rc fi rm -rf "${TMP_PATH}" return 0 } # RESTORE PROFILE DEVELOPER LOCAL BACKUP function developer_restore() { local BIN_CONFIG=$1 local BACKUP_ZIP=$2 local rc=0 # Check provided backup zip filename if [ -z "$BACKUP_ZIP" ]; then return 10 fi # Check if backup zip file exists if [ ! -f "$BACKUP_ZIP" ] then return 11 fi # Check if backup configuration file exists local LOCAL_BACKUP=$(dirname $BACKUP_ZIP) if [ ! -f $LOCAL_BACKUP/$GPGP_BACKUP_SECRET ] then return 12 fi # Get secret backup ZPASSWORD=$(echo "$(cat < "${LOCAL_BACKUP}/$GPGP_BACKUP_SECRET")" | base64 -d) if [ -z "${ZPASSWORD}" ]; then return 14 fi clear # Restore zip full .gnupg path unzip -qqo -P "$ZPASSWORD" "$BACKUP_ZIP" ".gnupg"/* -d $HOME rc=$? if [ $rc -ne 0 ]; then return $rc fi # Restore zip full .ssh path unzip -qqo -P "$ZPASSWORD" "$BACKUP_ZIP" ".ssh"/* -d $HOME rc=$? if [ $rc -ne 0 ]; then return $rc fi # Restore zip full .gitconfig file unzip -qqo -P "$ZPASSWORD" "$BACKUP_ZIP" ".gitconfig" -d $HOME rc=$? if [ $rc -ne 0 ]; then return $rc fi # Restore zip full .developer directory unzip -qqo -P "$ZPASSWORD" "$BACKUP_ZIP" ".developer"/* -d $HOME rc=$? if [ $rc -ne 0 ]; then return $rc fi return 0 } # Función para crear un proyecto Git en Forgejo # $1: nombre del proyecto # $2: descripción del proyecto # $3: tipo de visibilidad (private/public) [por defecto: private] # $4: ruta local del proyecto (opcional) # Return: 0 si se crea correctamente, otro valor en caso de error local PROJECT_NAME=$1 local PROJECT_DESC=$2 local VISIBILITY=${3:-private} # Por defecto private si no se especifica local PROJECT_PATH=$4 # Verificar parámetros obligatorios if [ -z "$PROJECT_NAME" ] || [ -z "$PROJECT_DESC" ]; then return 10 # Error: faltan parámetros obligatorios fi # Verificar que el archivo de configuración de Forgejo existe if [ ! -f "$FORGEJO_CONFIG_FILE" ]; then mkdir -p "$(dirname "$FORGEJO_CONFIG_FILE")" # Si el archivo no existe, preguntar por token if [ -t 0 ]; then # Solo si es terminal interactiva echo "Archivo de configuración de Forgejo no encontrado." echo "" echo "Para generar un token en Forgejo:" local FORGEJO_BASE_URL=$(echo "$FORGEJO_API_URL" | sed -E 's|/api/v1||') echo "1. Inicie sesión en $FORGEJO_BASE_URL" echo "2. Vaya a Configuración → Aplicaciones" echo "3. Genere un nuevo token de acceso personal con permisos de 'repo'" echo "" read -p "Ingrese su token de acceso de Forgejo: " FORGEJO_TOKEN echo "FORGEJO_TOKEN=$FORGEJO_TOKEN" > "$FORGEJO_CONFIG_FILE" chmod 600 "$FORGEJO_CONFIG_FILE" # Restricción de permisos por seguridad else return 11 # Error: no existe configuración y no es interactivo fi fi # Cargar token de Forgejo source "$FORGEJO_CONFIG_FILE" if [ -z "$FORGEJO_TOKEN" ]; then return 12 # Error: token no disponible fi # Verificar visibilidad válida if [ "$VISIBILITY" != "private" ] && [ "$VISIBILITY" != "public" ]; then VISIBILITY="private" # Establecer valor por defecto si es inválido fi # Preparar datos para la API local API_DATA="{\"name\":\"$PROJECT_NAME\",\"description\":\"$PROJECT_DESC\",\"private\":$([ "$VISIBILITY" == "private" ] && echo "true" || echo "false")}" # Comprobar si podemos acceder a la API - Con timeout y manejo de errores de conexión echo "DEBUG: Verificando acceso a la API en: $FORGEJO_API_URL/version" >&2 # Verificar primero el host base local BASE_URL=$(echo "$FORGEJO_API_URL" | sed -E 's|https?://([^/]+)/.*|\1|') if ! ping -c 1 -W 2 "$BASE_URL" >/dev/null 2>&1; then echo "ERROR: No se puede alcanzar el servidor $BASE_URL" >&2 echo "{\"error\":\"No se puede conectar con el servidor $BASE_URL. Verifique su conexión y la URL.\"}" > "$HOME/.developer/${PROJECT_NAME}.error" return 13 fi echo "DEBUG: Verificando puertos alternativos..." >&2 # Prueba conexión HTTP puerto 80 primero if nc -z -w 2 "$BASE_URL" 80 2>/dev/null; then echo "DEBUG: Puerto 80 (HTTP) accesible" >&2 # Intenta versión HTTP explícitamente local HTTP_API_URL=$(echo "$FORGEJO_API_URL" | sed 's|^https://|http://|') local API_RESPONSE=$(curl -s -v --connect-timeout 5 --max-time 10 "$HTTP_API_URL/version" 2>/tmp/curl_verbose.log || echo "") if [ -n "$API_RESPONSE" ] && echo "$API_RESPONSE" | grep -q "version"; then echo "DEBUG: API accesible vía HTTP (puerto 80)" >&2 # Reemplazar URL por HTTP para el resto de la función FORGEJO_API_URL="$HTTP_API_URL" else echo "ERROR: Servidor accesible pero la API no responde correctamente por HTTP" >&2 echo "{\"error\":\"Servidor accesible en puerto 80, pero la API no responde correctamente. Verifique la configuración del servidor.\"}" > "$HOME/.developer/${PROJECT_NAME}.error" cat /tmp/curl_verbose.log >> "$HOME/.developer/${PROJECT_NAME}.error" 2>/dev/null return 13 fi elif nc -z -w 2 "$BASE_URL" 443 2>/dev/null; then echo "DEBUG: Puerto 443 (HTTPS) accesible, pero posibles problemas con certificado o API" >&2 # Intenta con HTTPS pero ignorando errores de certificado local API_RESPONSE=$(curl -s -v -k --connect-timeout 5 --max-time 10 "$FORGEJO_API_URL/version" 2>/tmp/curl_verbose.log || echo "") if [ -n "$API_RESPONSE" ] && echo "$API_RESPONSE" | grep -q "version"; then echo "DEBUG: API accesible vía HTTPS inseguro (ignorando certificado)" >&2 # Continuar pero usando -k para ignorar certificados export FORGEJO_CURL_OPTS="-k" else echo "ERROR: Servidor HTTPS accesible pero la API no responde correctamente" >&2 echo "{\"error\":\"Servidor accesible en puerto 443, pero la API no responde. Posibles problemas de certificado o configuración.\"}" > "$HOME/.developer/${PROJECT_NAME}.error" cat /tmp/curl_verbose.log >> "$HOME/.developer/${PROJECT_NAME}.error" 2>/dev/null return 13 fi else echo "ERROR: No se puede acceder a los puertos HTTP (80) ni HTTPS (443) en $BASE_URL" >&2 echo "{\"error\":\"Servidor accesible por ping pero no responde en los puertos web (80/443).\"}" > "$HOME/.developer/${PROJECT_NAME}.error" return 13 fi # Verificar token con timeout y manejo de errores echo "DEBUG: Verificando token con API en: $FORGEJO_API_URL/user" >&2 local TOKEN_CHECK=$(curl ${FORGEJO_CURL_OPTS:-} -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 -H "Authorization: token $FORGEJO_TOKEN" "$FORGEJO_API_URL/user" 2>/dev/null || echo "000") if [ "$TOKEN_CHECK" != "200" ]; then if [ "$TOKEN_CHECK" == "401" ]; then echo "ERROR: Token inválido o sin permisos suficientes. Código: 401" >&2 echo "{\"error\":\"Token inválido o sin permisos suficientes. Genere un nuevo token con permisos 'repo'\"}" > "$HOME/.developer/${PROJECT_NAME}.error" elif [ "$TOKEN_CHECK" == "000" ]; then echo "ERROR: No se pudo verificar el token. Error de conectividad" >&2 echo "{\"error\":\"No se pudo verificar el token. Error de conectividad con el servidor\"}" > "$HOME/.developer/${PROJECT_NAME}.error" else echo "ERROR: Token inválido o sin acceso. Código: $TOKEN_CHECK" >&2 echo "{\"error\":\"Token inválido o sin acceso. Código: $TOKEN_CHECK\"}" > "$HOME/.developer/${PROJECT_NAME}.error" fi return 12 fi # Llamar a la API de Forgejo para crear el repositorio echo "DEBUG: Enviando solicitud de creación de repositorio..." >&2 local API_RESPONSE=$(curl ${FORGEJO_CURL_OPTS:-} -s -X POST --connect-timeout 10 --max-time 30 "$FORGEJO_API_URL/user/repos" \ -H "Authorization: token $FORGEJO_TOKEN" \ -H "Content-Type: application/json" \ -d "$API_DATA" 2>/tmp/curl_error.log || echo '{"error":"Falló la comunicación con el servidor"}') echo "DEBUG: Respuesta API: $API_RESPONSE" >&2 # Verificar respuesta if echo "$API_RESPONSE" | grep -q "\"id\":[0-9]*"; then local REPO_URL=$(echo "$API_RESPONSE" | grep -o '"clone_url":"[^"]*"' | cut -d'"' -f4) if [ -n "$REPO_URL" ]; then echo "$REPO_URL" > "$HOME/.developer/${PROJECT_NAME}.repo" else # Extraer HTML URL como fallback REPO_URL=$(echo "$API_RESPONSE" | grep -o '"html_url":"[^"]*"' | head -1 | cut -d'"' -f4) if [ -n "$REPO_URL" ]; then echo "$REPO_URL" > "$HOME/.developer/${PROJECT_NAME}.repo" else echo "ERROR: No se pudo extraer la URL del repositorio." >&2 echo "$API_RESPONSE" > "$HOME/.developer/${PROJECT_NAME}.error" return 14 fi fi # Si se proporcionó una ruta local, configurar el repositorio if [ -n "$PROJECT_PATH" ] && [ -d "$PROJECT_PATH" ]; then cd "$PROJECT_PATH" # Verificar si ya es un repositorio git if [ -d ".git" ]; then # Añadir el remoto git remote add origin "$REPO_URL" git push -u origin main || git push -u origin master else # Inicializar el repositorio y hacer primer commit si no existe git init git add . git commit -m "[INIT] Proyecto $PROJECT_NAME" git remote add origin "$REPO_URL" git push -u origin main fi fi return 0 # Éxito else # Guardar mensaje de error echo "$API_RESPONSE" > "$HOME/.developer/${PROJECT_NAME}.error" return 13 # Error: falló la creación del repositorio fi }