File size: 3,999 Bytes
7355804 1dd1e45 7355804 1dd1e45 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | #!/usr/bin/env bash
set -euo pipefail
log() {
printf '[asa-api] %s\n' "$*" >&2
}
run_api() {
log "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")))'
}
enable_tor="${ASA_ENABLE_TOR:-false}"
enable_tor="$(printf '%s' "${enable_tor}" | tr '[:upper:]' '[:lower:]')"
case "${enable_tor}" in
1|true|t|yes|y|on)
;;
0|false|f|no|n|off|'')
log "Tor integration disabled for this run; clearing proxy environment"
unset ASA_PROXY TOR_CONTROL_PORT ASA_TOR_CONTROL_COOKIE
run_api
;;
*)
log "ASA_ENABLE_TOR must be a boolean value. Got: ${ASA_ENABLE_TOR:-}"
exit 1
;;
esac
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; routing agent traffic through ${proxy_url}"
run_api
|