#!/usr/bin/env bash set -euo pipefail [[ "${EUID}" -eq 0 ]] || { echo "Run as root (sudo)." exit 1 } REPO="$(cd "$(dirname "$0")/.." && pwd)" TOR_DIRS_FILE="${REPO}/scripts/generated/tor-dirs.txt" BACKUP_ROOT="${CYBERLUX_ONION_BACKUP_ROOT:-/var/backups/cyberlux-onion-keys}" CURRENT_DIR="${BACKUP_ROOT}/current" SNAPSHOT_ROOT="${BACKUP_ROOT}/snapshots" KEEP_COUNT="${CYBERLUX_ONION_BACKUP_KEEP:-10}" if [[ ! -f "${TOR_DIRS_FILE}" ]]; then echo "Missing ${TOR_DIRS_FILE}. Run the generator first." exit 1 fi mkdir -p "${BACKUP_ROOT}" "${SNAPSHOT_ROOT}" chmod 0700 "${BACKUP_ROOT}" "${SNAPSHOT_ROOT}" tmp_current="$(mktemp -d "${BACKUP_ROOT}/current.tmp.XXXXXX")" tmp_snapshot="$(mktemp -d "${BACKUP_ROOT}/snapshot.tmp.XXXXXX")" cleanup() { rm -rf "${tmp_current}" "${tmp_snapshot}" } trap cleanup EXIT saved=0 while IFS= read -r dir || [[ -n "${dir}" ]]; do [[ -z "${dir}" ]] && continue src="/var/lib/tor/${dir}" [[ -d "${src}" ]] || continue if [[ ! -s "${src}/hostname" ]] && [[ ! -f "${src}/hs_ed25519_secret_key" ]] && [[ ! -f "${src}/private_key" ]]; then continue fi cp -a "${src}" "${tmp_current}/${dir}" cp -a "${src}" "${tmp_snapshot}/${dir}" ((saved++)) || true done < "${TOR_DIRS_FILE}" if (( saved == 0 )); then echo "[*] No onion key directories are ready to back up yet." exit 0 fi snapshot_dir="${SNAPSHOT_ROOT}/$(date +%Y%m%d-%H%M%S)" mv "${tmp_snapshot}" "${snapshot_dir}" rm -rf "${CURRENT_DIR}" mv "${tmp_current}" "${CURRENT_DIR}" trap - EXIT chmod -R go-rwx "${BACKUP_ROOT}" || true chown -R root:root "${BACKUP_ROOT}" || true mapfile -t snapshots < <(ls -1dt "${SNAPSHOT_ROOT}"/* 2>/dev/null || true) if (( ${#snapshots[@]} > KEEP_COUNT )); then for old in "${snapshots[@]:KEEP_COUNT}"; do rm -rf "${old}" done fi echo "[*] Backed up ${saved} onion service directories." echo " Current restore set: ${CURRENT_DIR}"