#!/usr/bin/env bash # Install a mkp224o-generated v3 key directory into the CyberLux HiddenServiceDir and restart Tor. # Run with sudo after vanity-onion-mine.sh has produced a folder named *.onion under the output path. # # sudo bash scripts/install-vanity-onion-key.sh /path/to/var/vanity-mine # sudo bash scripts/install-vanity-onion-key.sh /path/to/specificXXXX.onion # # If the path is a parent with several *.onion children, one is chosen automatically # (default: first in lexicographic order). Override with: # CYBERLUX_VANITY_PICK=latest — use the directory with the newest mtime # CYBERLUX_VANITY_PICK=first — same as default (first sorted A–Z) # Or pass a direct path to a single ... .onion folder. # 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" ARG="${1:-}" if [[ -z "${ARG}" ]]; then echo "Usage: sudo bash $0 " exit 1 fi # If ARG is relative, prefer REPO/ARG (so `var/vanity-mine` works from any cwd when using this repo). if [[ "${ARG}" != /* && -d "${REPO}/${ARG}" ]]; then ARG="${REPO}/${ARG}" fi if [[ ! -f "${TOR_DIRS_FILE}" ]]; then echo "Missing ${TOR_DIRS_FILE}. Run: cd ${REPO} && node scripts/generate-onion-config.cjs" exit 1 fi # Resolve single torDir (CyberLux uses "cyberlux" in onion-nodes.json) TOR_DIR_NAME="$(head -1 "${TOR_DIRS_FILE}" | tr -d '\r\n')" if [[ -z "${TOR_DIR_NAME}" ]]; then echo "Empty ${TOR_DIRS_FILE}" exit 1 fi HS_ROOT="/var/lib/tor/${TOR_DIR_NAME}" KEY_SRC="" if [[ -d "${ARG}" ]]; then if [[ -f "${ARG}/hs_ed25519_secret_key" ]]; then KEY_SRC="${ARG}" else # Pick a *.onion child (one or many) mapfile -t kids < <(find "${ARG}" -maxdepth 1 -type d -name '*.onion' 2>/dev/null | sort) if [[ "${#kids[@]}" -eq 1 ]]; then KEY_SRC="${kids[0]}" elif [[ "${#kids[@]}" -eq 0 ]]; then echo "No subdirectory matching *.onion under ${ARG} and no key at top level." exit 1 else pick="${CYBERLUX_VANITY_PICK:-first}" case "${pick}" in first) KEY_SRC="${kids[0]}" echo "[*] ${#kids[@]} *.onion key dirs; using first (lexicographic): ${KEY_SRC}" ;; latest|newest) latest="" latest_m=0 for d in "${kids[@]}"; do m="$(stat -c %Y "${d}" 2>/dev/null || echo 0)" if (( m >= latest_m )); then latest_m="${m}" latest="${d}" fi done KEY_SRC="${latest}" echo "[*] ${#kids[@]} *.onion key dirs; using latest mtime: ${KEY_SRC}" ;; *) echo "Unknown CYBERLUX_VANITY_PICK=${pick} (use first or latest)." exit 1 ;; esac fi fi else echo "Not a directory: ${ARG}" exit 1 fi if [[ ! -f "${KEY_SRC}/hs_ed25519_secret_key" ]]; then echo "No hs_ed25519_secret_key in ${KEY_SRC}" exit 1 fi TOR_USER="" for u in debian-tor tor _tor; do if id -u "${u}" &>/dev/null; then TOR_USER="${u}" break fi done if [[ -z "${TOR_USER}" ]]; then echo "No Tor system user (tried debian-tor, tor, _tor). Install Tor." exit 1 fi TS="$(date +%s)" if [[ -d "${HS_ROOT}" ]]; then echo "[*] Preserving current service dir as ${HS_ROOT}.stale.${TS}" mv "${HS_ROOT}" "${HS_ROOT}.stale.${TS}" fi mkdir -p "${HS_ROOT}" shopt -s dotglob nullglob for item in "${KEY_SRC}"/*; do base="$(basename "${item}")" [[ "${base}" == "." || "${base}" == ".." ]] && continue cp -a "${item}" "${HS_ROOT}/" done shopt -u dotglob nullglob chown -R "${TOR_USER}:${TOR_USER}" "${HS_ROOT}" chmod -R u+rwX,og-rwx "${HS_ROOT}" chmod 0700 "${HS_ROOT}" restart_tor() { systemctl restart tor@default.service 2>/dev/null || systemctl restart tor } echo "[*] Installed key material into ${HS_ROOT} (onion: $(tr -d '\n' < "${HS_ROOT}/hostname" 2>/dev/null || echo '?'))" restart_tor if [[ -f "${REPO}/scripts/export-onion-urls.sh" ]]; then bash "${REPO}/scripts/export-onion-urls.sh" || true fi if [[ -f "${REPO}/scripts/backup-onion-keys.sh" ]]; then bash "${REPO}/scripts/backup-onion-keys.sh" || true fi echo "[*] Done. Open: http://$(tr -d '\n' < "${HS_ROOT}/hostname") (in Tor Browser)" echo "[*] Old keys (if any): ${HS_ROOT}.stale.${TS}"