#!/bin/bash
# tor-beacon - Tor hidden service for remote SSH access (Linux/Debian)
#
# Creates a persistent .onion address for SSH access from anywhere.
# Run as root: sudo tor-beacon setup --name mydevice
#
# Usage:
#   tor-beacon setup   --name <name> [--port <ssh-port>]
#   tor-beacon start   [--name <name>]
#   tor-beacon stop    [--name <name>]
#   tor-beacon status  [--name <name>]
#   tor-beacon address --name <name>
#
# Connect from anywhere:
#   torify ssh user@<onion-address>
#
# Docs: https://marcp.xyz/tor-onion-setup.html

set -e

# --- defaults ---
NAME=""
SSH_PORT=""
COMMAND=""
TOR_BASE="/var/lib/tor"
TORRC="/etc/tor/torrc"
DEFAULT_SSH_PORT=2222

# --- parse args ---
die() { echo "ERROR: $1" >&2; exit 1; }

while [ $# -gt 0 ]; do
    case "$1" in
        setup|start|stop|status|address)
            COMMAND="$1"; shift ;;
        --name|-n)
            NAME="$2"; shift 2 ;;
        --port|-p)
            SSH_PORT="$2"; shift 2 ;;
        -h|--help)
            COMMAND="help"; shift ;;
        *)
            die "unknown argument: $1" ;;
    esac
done

[ -z "$COMMAND" ] && COMMAND="help"
[ -z "$SSH_PORT" ] && SSH_PORT="$DEFAULT_SSH_PORT"

# derived paths
if [ -n "$NAME" ]; then
    SERVICE_DIR="$TOR_BASE/${NAME}_onion"
    HOSTNAME_FILE="$SERVICE_DIR/hostname"
fi

# --- helpers ---
require_name() {
    [ -n "$NAME" ] || die "missing --name (e.g. tor-beacon $COMMAND --name mydevice)"
}

wait_for_address() {
    local tries=3
    while [ $tries -gt 0 ]; do
        if [ -f "$HOSTNAME_FILE" ]; then
            echo "Onion address: $(cat "$HOSTNAME_FILE")"
            return 0
        fi
        echo "Waiting for tor to generate address..."
        sleep 5
        tries=$((tries - 1))
    done
    echo "WARNING: address not yet available"
    echo "Check: journalctl -u tor"
    return 1
}

# --- commands ---
cmd_setup() {
    require_name
    echo "=== tor-beacon setup: $NAME ==="

    # install tor
    if command -v tor &>/dev/null; then
        echo "tor already installed"
    else
        echo "Installing tor..."
        apt-get update && apt-get install -y tor
    fi

    # change SSH port if not 22
    if [ "$SSH_PORT" != "22" ]; then
        if ! grep -q "^Port $SSH_PORT" /etc/ssh/sshd_config 2>/dev/null; then
            echo "Setting SSH port to $SSH_PORT..."
            sed -i "s/^#\?Port .*/Port $SSH_PORT/" /etc/ssh/sshd_config
            systemctl restart ssh 2>/dev/null || systemctl restart sshd 2>/dev/null
        fi
    fi

    # create hidden service dir
    mkdir -p "$SERVICE_DIR"
    chown debian-tor:debian-tor "$SERVICE_DIR"
    chmod 700 "$SERVICE_DIR"

    # configure torrc
    if grep -q "${NAME}_onion" "$TORRC" 2>/dev/null; then
        echo "torrc already configured for $NAME"
    else
        [ -f "$TORRC" ] && cp "$TORRC" "$TORRC.backup.$(date +%Y%m%d)"
        cat >> "$TORRC" << EOF

# ${NAME} onion service (tor-beacon)
HiddenServiceDir $SERVICE_DIR/
HiddenServicePort 22 127.0.0.1:$SSH_PORT
EOF
        echo "torrc updated"
    fi

    # start or restart tor to pick up new config
    echo "Starting tor..."
    systemctl enable tor 2>/dev/null
    if systemctl is-active --quiet tor; then
        echo "Tor already running, restarting to load new config..."
        systemctl restart tor
    else
        systemctl start tor
    fi
    sleep 5
    wait_for_address || true

    echo ""
    echo "=== setup complete ==="
    echo ""
    echo "Usage:"
    echo "  tor-beacon start   --name $NAME"
    echo "  tor-beacon stop    --name $NAME"
    echo "  tor-beacon status  --name $NAME"
    echo "  tor-beacon address --name $NAME"
    if [ -f "$HOSTNAME_FILE" ]; then
        echo ""
        echo "Connect from anywhere:"
        echo "  torify ssh $(whoami)@$(cat "$HOSTNAME_FILE")"
    fi
}

cmd_start() {
    systemctl enable --now tor
    echo "Tor beacon started"
    sleep 2
    cmd_status
}

cmd_stop() {
    systemctl stop tor
    echo "Tor beacon stopped"
}

cmd_status() {
    if systemctl is-active --quiet tor; then
        echo "Tor: RUNNING"
    else
        echo "Tor: STOPPED"
    fi

    # show all configured beacons
    if [ -n "$NAME" ]; then
        if [ -f "$HOSTNAME_FILE" ]; then
            echo "$NAME: $(cat "$HOSTNAME_FILE")"
        else
            echo "$NAME: no address (not set up?)"
        fi
    else
        for dir in "$TOR_BASE"/*_onion; do
            [ -d "$dir" ] || continue
            n="$(basename "$dir" _onion)"
            if [ -f "$dir/hostname" ]; then
                echo "$n: $(cat "$dir/hostname")"
            else
                echo "$n: no address"
            fi
        done
    fi
}

cmd_address() {
    require_name
    [ -f "$HOSTNAME_FILE" ] || die "no address for $NAME. Run: tor-beacon setup --name $NAME"
    cat "$HOSTNAME_FILE"
}

cmd_help() {
    cat << 'EOF'
tor-beacon - Tor hidden service for remote SSH access (Linux/Debian)

Usage:
  tor-beacon setup   --name <name> [--port <ssh-port>]
  tor-beacon start   [--name <name>]
  tor-beacon stop    [--name <name>]
  tor-beacon status  [--name <name>]
  tor-beacon address --name <name>

Options:
  --name, -n    Service name (e.g. poetomat, photobooth)
  --port, -p    Local SSH port (default: 2222)

Examples:
  sudo tor-beacon setup --name poetomat
  sudo tor-beacon setup --name photobooth --port 1234
  tor-beacon start
  tor-beacon status
  torify ssh user@<onion-address>

Docs: https://marcp.xyz/tor-onion-setup.html
EOF
}

# --- main ---
case "$COMMAND" in
    setup)   cmd_setup ;;
    start)   cmd_start ;;
    stop)    cmd_stop ;;
    status)  cmd_status ;;
    address) cmd_address ;;
    help)    cmd_help ;;
esac
