#!/usr/bin/bash set -euo pipefail IFS=$'\n\t' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -d "${SCRIPT_DIR}/../../.git" ]] || [[ -f "${SCRIPT_DIR}/../../nodo/config/etc/mirrors.env" ]]; then REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" else REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" fi if [[ -f "${REPO_ROOT}/nodo/config/etc/mirrors.env" ]]; then # shellcheck source=/dev/null source "${REPO_ROOT}/nodo/config/etc/mirrors.env" elif [[ -f "${REPO_ROOT}/config/etc/mirrors.env" ]]; then # shellcheck source=/dev/null source "${REPO_ROOT}/config/etc/mirrors.env" elif [[ -f "${REPO_ROOT}/etc/mirrors.env" ]]; then # shellcheck source=/dev/null source "${REPO_ROOT}/etc/mirrors.env" fi KEY_NAME="${MIRRORS_IPNS_KEY:-mxos-mirrors}" usage() { cat << USAGE Uso: $0 [OPCIONES] Administración, exportación y respaldo seguro de la llave Ed25519 de la red de espejos. Acciones: status Muestra el identificador y presencia de la llave en Kubo export-pem Exporta la llave privada en formato estándar PEM PKCS#8 export-libp2p Exporta la llave en formato nativo Protobuf de libp2p backup-age Exporta y cifra interactivamente con age (AES-256) backup-gpg Exporta y cifra simétricamente con GPG (AES-256) import Importa una llave exportada previamente hacia Kubo help Muestra este mensaje Ejemplos: $0 status $0 backup-age mxos-mirrors-backup.key.age $0 export-pem mxos-mirrors.pem $0 import mxos-mirrors.key USAGE exit 1 } cmd_status() { echo "==========================================================" echo " Estado de la Llave Ed25519: ${KEY_NAME}" echo "==========================================================" if ! ipfs key list | grep -Fxq "${KEY_NAME}"; then echo "Estado: NO PRESENTE en el almacén de Kubo." echo "Genérela con: ipfs key gen --type=ed25519 ${KEY_NAME}" return 1 fi local key_id key_id="$(ipfs key list -l | awk -v k="${KEY_NAME}" '$2 == k {print $1}')" echo "Presencia: Presente y activa" echo "Nombre: ${KEY_NAME}" echo "Key ID: ${key_id}" echo "Ruta IPNS: /ipns/${key_id}" echo -n "Resolución actual: " local current_target current_target="$(ipfs resolve "/ipns/${key_id}" 2>/dev/null || echo "Sin publicar o en propagación")" echo "${current_target}" echo "==========================================================" } cmd_export_pem() { local target_file="${1:-}" if [[ -z "${target_file}" ]]; then echo "Error: Debe especificar la ruta del archivo de destino (.pem)." >&2 exit 1 fi echo "==> Exportando llave '${KEY_NAME}' en formato PEM PKCS#8..." ipfs key export "${KEY_NAME}" --format=pem-pkcs8-cleartext -o "${target_file}" chmod 0600 "${target_file}" echo "==> Llave exportada en ${target_file} con permisos 0600." } cmd_export_libp2p() { local target_file="${1:-}" if [[ -z "${target_file}" ]]; then echo "Error: Debe especificar la ruta del archivo de destino (.key)." >&2 exit 1 fi echo "==> Exportando llave '${KEY_NAME}' en formato binario libp2p..." ipfs key export "${KEY_NAME}" -o "${target_file}" chmod 0600 "${target_file}" echo "==> Llave exportada en ${target_file} con permisos 0600." } cmd_backup_age() { local target_file="${1:-}" if [[ -z "${target_file}" ]]; then echo "Error: Debe especificar la ruta del archivo cifrado de salida (.age)." >&2 exit 1 fi if ! command -v age >/dev/null 2>&1; then echo "Error: 'age' no está instalado en el sistema." >&2 exit 1 fi local temp_key temp_key="$(mktemp -p /dev/shm "mxos-key-XXXXXX.key")" chmod 0600 "${temp_key}" trap 'rm -f "${temp_key}"' EXIT echo "==> Extrayendo llave temporal a memoria compartida (/dev/shm)..." ipfs key export "${KEY_NAME}" -o "${temp_key}" echo "==> Cifrando con age (ingrese frase de paso segura cuando se solicite)..." age -p -o "${target_file}" "${temp_key}" # Borrado seguro inmediato del archivo intermedio shred -u "${temp_key}" 2>/dev/null || rm -f "${temp_key}" trap - EXIT echo "==> Respaldo cifrado exitosamente en: ${target_file}" echo " Para restaurar: age -d ${target_file} > mxos-mirrors.key && ipfs key import ${KEY_NAME} mxos-mirrors.key" } cmd_backup_gpg() { local target_file="${1:-}" if [[ -z "${target_file}" ]]; then echo "Error: Debe especificar la ruta del archivo cifrado de salida (.gpg)." >&2 exit 1 fi if ! command -v gpg >/dev/null 2>&1; then echo "Error: 'gpg' no está instalado en el sistema." >&2 exit 1 fi local temp_key temp_key="$(mktemp -p /dev/shm "mxos-key-XXXXXX.key")" chmod 0600 "${temp_key}" trap 'rm -f "${temp_key}"' EXIT echo "==> Extrayendo llave temporal a memoria compartida (/dev/shm)..." ipfs key export "${KEY_NAME}" -o "${temp_key}" echo "==> Cifrando simétricamente con GPG (AES-256)..." gpg --symmetric --cipher-algo AES256 -o "${target_file}" "${temp_key}" shred -u "${temp_key}" 2>/dev/null || rm -f "${temp_key}" trap - EXIT echo "==> Respaldo cifrado exitosamente en: ${target_file}" echo " Para restaurar: gpg -d ${target_file} > mxos-mirrors.key && ipfs key import ${KEY_NAME} mxos-mirrors.key" } cmd_import() { local source_file="${1:-}" if [[ -z "${source_file}" || ! -f "${source_file}" ]]; then echo "Error: Debe especificar un archivo de llave existente para importar." >&2 exit 1 fi if ipfs key list | grep -Fxq "${KEY_NAME}"; then echo "Aviso: La llave '${KEY_NAME}' ya existe en el almacén de Kubo." read -r -p "¿Desea reemplazarla eliminando la existente? [s/N]: " confirm if [[ "${confirm}" =~ ^[sS]$ ]]; then ipfs key rm "${KEY_NAME}" else echo "Operación cancelada." return 0 fi fi echo "==> Importando llave hacia el almacén de Kubo..." # Si termina en .pem, intentar formato pem-pkcs8-cleartext if [[ "${source_file}" == *.pem ]]; then ipfs key import "${KEY_NAME}" -f pem-pkcs8-cleartext "${source_file}" else ipfs key import "${KEY_NAME}" "${source_file}" fi echo "==> Llave importada exitosamente." cmd_status } main() { local action="${1:-status}" shift || true case "${action}" in status) cmd_status ;; export-pem) cmd_export_pem "$@" ;; export-libp2p|export) cmd_export_libp2p "$@" ;; backup-age) cmd_backup_age "$@" ;; backup-gpg) cmd_backup_gpg "$@" ;; import) cmd_import "$@" ;; help|--help|-h) usage ;; *) echo "Acción desconocida: ${action}" >&2 usage ;; esac } main "$@"