asa-api / scripts /start-with-tor.sh
cjerzak's picture
add files
7355804
#!/usr/bin/env bash
set -euo pipefail
log() {
printf '[asa-api] %s\n' "$*" >&2
}
proxy_url="${ASA_PROXY:-socks5h://127.0.0.1:9050}"
proxy_without_scheme="${proxy_url#*://}"
proxy_host_port="${proxy_without_scheme%%/*}"
proxy_host="${proxy_host_port%:*}"
proxy_port="${proxy_host_port##*:}"
if [[ -z "${proxy_host}" || "${proxy_host}" == "${proxy_host_port}" ]]; then
proxy_host="127.0.0.1"
fi
if [[ "${proxy_host}" != "127.0.0.1" && "${proxy_host}" != "localhost" ]]; then
log "ASA_PROXY must target a local Tor SOCKS listener. Got: ${proxy_url}"
exit 1
fi
if ! [[ "${proxy_port}" =~ ^[0-9]+$ ]]; then
log "ASA_PROXY must include a numeric port. Got: ${proxy_url}"
exit 1
fi
control_port="${TOR_CONTROL_PORT:-9051}"
if ! [[ "${control_port}" =~ ^[0-9]+$ ]]; then
log "TOR_CONTROL_PORT must be numeric. Got: ${control_port}"
exit 1
fi
tor_root="/tmp/tor"
tor_data_dir="${tor_root}/data"
tor_cookie_path="${ASA_TOR_CONTROL_COOKIE:-${tor_root}/control.authcookie}"
tor_pid_path="${tor_root}/tor.pid"
torrc_path="${tor_root}/torrc"
tor_probe_url="${ASA_TOR_PROBE_URL:-https://check.torproject.org/api/ip}"
tor_startup_timeout="${ASA_TOR_STARTUP_TIMEOUT_SEC:-90}"
if ! [[ "${tor_startup_timeout}" =~ ^[0-9]+$ ]]; then
log "ASA_TOR_STARTUP_TIMEOUT_SEC must be numeric. Got: ${tor_startup_timeout}"
exit 1
fi
install -d -m 700 "${tor_root}" "${tor_data_dir}" "$(dirname "${tor_cookie_path}")"
rm -f "${tor_pid_path}" "${tor_cookie_path}"
cat > "${torrc_path}" <<EOF
ClientOnly 1
DataDirectory ${tor_data_dir}
PidFile ${tor_pid_path}
SocksPort 127.0.0.1:${proxy_port}
ControlPort 127.0.0.1:${control_port}
CookieAuthentication 1
CookieAuthFile ${tor_cookie_path}
AvoidDiskWrites 1
Log notice stderr
EOF
log "Starting Tor on ${proxy_url} with control port ${control_port}"
tor -f "${torrc_path}" &
tor_pid=$!
tor_probe_file="$(mktemp)"
tor_probe_error_file="$(mktemp)"
cleanup_probe_files() {
rm -f "${tor_probe_file}" "${tor_probe_error_file}"
}
trap cleanup_probe_files EXIT
port_open() {
local host="$1"
local port="$2"
(exec 3<>"/dev/tcp/${host}/${port}") >/dev/null 2>&1
}
wait_for_tor() {
local started_at now
started_at="$(date +%s)"
while true; do
if ! kill -0 "${tor_pid}" 2>/dev/null; then
wait "${tor_pid}" || true
log "Tor exited before startup completed"
exit 1
fi
if curl --silent --show-error --fail --max-time 15 \
--proxy "${proxy_url}" \
"${tor_probe_url}" > "${tor_probe_file}" 2> "${tor_probe_error_file}"; then
if grep -Eq '"IsTor"[[:space:]]*:[[:space:]]*true' "${tor_probe_file}"; then
if [[ -r "${tor_cookie_path}" ]] && port_open "127.0.0.1" "${control_port}"; then
return 0
fi
fi
fi
now="$(date +%s)"
if (( now - started_at >= tor_startup_timeout )); then
log "Timed out waiting for Tor readiness"
if [[ -s "${tor_probe_error_file}" ]]; then
log "Last probe error: $(tail -n 1 "${tor_probe_error_file}")"
fi
if [[ -s "${tor_probe_file}" ]]; then
log "Last probe body: $(tr -d '\n' < "${tor_probe_file}")"
fi
exit 1
fi
sleep 1
done
}
wait_for_tor
export ASA_PROXY="${proxy_url}"
export TOR_CONTROL_PORT="${control_port}"
export ASA_TOR_CONTROL_COOKIE="${tor_cookie_path}"
log "Tor ready; starting API on port ${PORT:-7860}"
exec Rscript -e 'pr <- plumber::plumb("R/plumber.R"); pr$run(host = "0.0.0.0", port = as.integer(Sys.getenv("PORT", "7860")))'