- Cambiada URL de API de HTTPS a HTTP por defecto - Implementada detección automática del protocolo correcto (HTTP/HTTPS) - Añadido soporte para certificados autofirmados con la opción -k - Mejor diagnóstico de conectividad con pruebas de puerto 80 y 443 - Información detallada sobre problemas de conexión y respuestas de API - Salida de depuración enriquecida para facilitar la resolución de problemas 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
471 lines
14 KiB
Bash
471 lines
14 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Library: developers.lib
|
|
# Description: Developers Tools Library
|
|
# Modified: 2024/12/09 08:20:00
|
|
# Derechos de Autor (C) [2024] [Mauro Rosero P. <mauro@roser.one>]
|
|
#
|
|
# 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 <https://www.gnu.org/licenses/>.
|
|
|
|
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
|
|
}
|
|
|
|
# Configuración global para servicios Git
|
|
FORGEJO_API_URL="http://git.rosero.one/api/v1" # Cambiado a HTTP en lugar de HTTPS
|
|
FORGEJO_CONFIG_FILE="$HOME/.developer/forgejo.cfg"
|
|
|
|
# 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
|
|
function forgejo_create_project() {
|
|
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
|
|
}
|