128 lines
5.1 KiB
Bash
128 lines
5.1 KiB
Bash
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: CC0-1.0
|
|
# Dedicated to the public domain under CC0 1.0 Universal.
|
|
# See https://creativecommons.org/publicdomain/zero/1.0/
|
|
# This script is not affiliated with or endorsed by The Tor Project.
|
|
|
|
set -Eeuo pipefail
|
|
IFS=$'\n\t'
|
|
|
|
# ------------------------------- logging --------------------------------------
|
|
# Plain ASCII, no icons or emojis.
|
|
c_green() { printf '\033[0;32m%s\033[0m\n' "$*"; }
|
|
c_yellow() { printf '\033[1;33m%s\033[0m\n' "$*"; }
|
|
c_red() { printf '\033[0;31m%s\033[0m\n' "$*"; }
|
|
log() { c_green "INFO: $*"; }
|
|
warn() { c_yellow "WARN: $*"; }
|
|
die() { c_red "ERROR: $*"; exit 1; }
|
|
|
|
# Print a helpful line number on failure.
|
|
trap 'die "Error on or near line $LINENO. Exiting."' ERR
|
|
|
|
# ------------------------------- root check -----------------------------------
|
|
# We must be root to modify APT sources and install packages.
|
|
if [[ ${EUID:-0} -ne 0 ]]; then
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
exec sudo -E -- "$0" "$@"
|
|
else
|
|
die "Please run as root (or install sudo)."
|
|
fi
|
|
fi
|
|
|
|
# Make APT non-interactive and a bit more resilient.
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
APT_FLAGS=(-y -o Dpkg::Use-Pty=0 -o Acquire::Retries=3 -o Acquire::http::No-Cache=true)
|
|
|
|
# --------------------------- detect codename ----------------------------------
|
|
# We need the Debian/Ubuntu codename (e.g., bookworm, bullseye, noble, jammy).
|
|
OS_ID='' CODENAME=''
|
|
if [[ -r /etc/os-release ]]; then
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
OS_ID="${ID:-}"
|
|
CODENAME="${VERSION_CODENAME:-}"
|
|
fi
|
|
if [[ -z ${CODENAME} ]]; then
|
|
if command -v lsb_release >/dev/null 2>&1; then
|
|
CODENAME="$(lsb_release -cs 2>/dev/null || true)"
|
|
fi
|
|
fi
|
|
[[ -z ${CODENAME} ]] && die "Could not determine distro codename. Aborting."
|
|
|
|
log "Distro ID: ${OS_ID:-unknown}, Codename: ${CODENAME}"
|
|
|
|
# ------------------------------ prerequisites ---------------------------------
|
|
# Minimal tools to fetch keys and manage repos.
|
|
log "Ensuring prerequisites..."
|
|
apt-get update "${APT_FLAGS[@]}"
|
|
apt-get install "${APT_FLAGS[@]}" --no-install-recommends \
|
|
ca-certificates gnupg curl lsb-release
|
|
|
|
# ------------------------ configure Tor Project repo --------------------------
|
|
# This section is the whole point: always use the Tor Project APT repository.
|
|
|
|
log "Configuring Tor Project APT repository..."
|
|
|
|
# Create a dedicated system keyring directory if needed.
|
|
install -d -m 0755 /usr/share/keyrings
|
|
|
|
# Download the Tor Project archive signing key to a temporary file.
|
|
# Official key fingerprint:
|
|
# A3C4 F0F9 79CA A22C DBA8 F512 EE8C BC9E 886D DD89
|
|
KEY_URL="https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc"
|
|
TMP_KEY="$(mktemp)"
|
|
curl -fsSL "$KEY_URL" -o "$TMP_KEY"
|
|
|
|
# Verify the fingerprint before trusting the key.
|
|
FPR_EXPECTED="A3C4 F0F9 79CA A22C DBA8 F512 EE8C BC9E 886D DD89"
|
|
FPR_SEEN="$(gpg --show-keys --with-colons "$TMP_KEY" 2>/dev/null | awk -F: '/^fpr:/ {print $10; exit}' | sed 's/.\{4\}/& /g' | sed 's/ $//')"
|
|
if [[ "$FPR_SEEN" != "$FPR_EXPECTED" ]]; then
|
|
rm -f "$TMP_KEY"
|
|
die "Tor Project key fingerprint mismatch. Expected '$FPR_EXPECTED' but saw '$FPR_SEEN'."
|
|
fi
|
|
|
|
# Install the verified key into a dedicated keyring file.
|
|
gpg --dearmor < "$TMP_KEY" > /usr/share/keyrings/torproject-org-archive.gpg
|
|
rm -f "$TMP_KEY"
|
|
|
|
# Write the source list entry, pinned to the keyring.
|
|
# Note: if the Tor Project does not publish packages for your codename or arch,
|
|
# APT operations will fail, which is intentional for this script.
|
|
SRC_LINE="deb [signed-by=/usr/share/keyrings/torproject-org-archive.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main"
|
|
SRC_FILE="/etc/apt/sources.list.d/torproject-org.list"
|
|
printf '%s\n' "$SRC_LINE" > "$SRC_FILE"
|
|
|
|
# Refresh APT indices from the Tor Project repo.
|
|
apt-get update "${APT_FLAGS[@]}"
|
|
|
|
# ------------------------------- installation ---------------------------------
|
|
# Install Tor from the Tor Project repository, plus their keyring package
|
|
# to keep keys maintained via APT.
|
|
log "Installing tor and deb.torproject.org-keyring from the Tor Project repo..."
|
|
apt-get install "${APT_FLAGS[@]}" --no-install-recommends tor deb.torproject.org-keyring
|
|
|
|
# ------------------------------- post-install ---------------------------------
|
|
# Show version and attempt to enable and start the service on systemd systems.
|
|
if command -v tor >/dev/null 2>&1; then
|
|
log "Tor installed. Version:"
|
|
tor --version || true
|
|
|
|
if command -v systemctl >/dev/null 2>&1; then
|
|
# Try common service names. Ignore errors if a given unit does not exist.
|
|
systemctl enable --now tor.service >/dev/null 2>&1 || true
|
|
systemctl enable --now tor@default.service >/dev/null 2>&1 || true
|
|
|
|
# Print a simple status hint if neither service is active.
|
|
if ! systemctl is-active --quiet tor.service 2>/dev/null \
|
|
&& ! systemctl is-active --quiet tor@default.service 2>/dev/null; then
|
|
warn "Tor service is not active. You can start it with:"
|
|
warn " systemctl start tor.service"
|
|
warn " or"
|
|
warn " systemctl start tor@default.service"
|
|
fi
|
|
else
|
|
warn "Systemd not detected. Use your init system to manage the Tor daemon."
|
|
fi
|
|
else
|
|
die "Tor did not install correctly."
|
|
fi
|