#!/usr/bin/env bash set -euo pipefail ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" cd "$ROOT" umask 077 if [[ -f .env ]]; then # This is a local shell configuration file. Do not use untrusted .env files. set -a # shellcheck disable=SC1091 source .env set +a fi if ! command -v cargo >/dev/null 2>&1 && [[ -x "$HOME/.cargo/bin/cargo" ]]; then export PATH="$HOME/.cargo/bin:$PATH" fi mode="${1:-run}" if [[ $# -gt 0 ]]; then shift; fi case "$mode" in help|-h|--help) cat <<'HELP' RustProxy 0.25.7 ./dev.sh Build and start proxy + local panel ./dev.sh run [serve flags] Same, with extra server options ./dev.sh admin setup-token Generate/print a one-time setup capability before first login ./dev.sh admin init --username NAME Create the sole administrator (hidden password prompt) ./dev.sh admin reset-password Recover the password and revoke all existing sessions ./dev.sh admin logout-all Revoke sessions without changing the password ./dev.sh admin status Show administrator setup status ./dev.sh tls generate --name app --hosts app.localhost,alias.localhost Create a named self-signed certificate (no overwrite) ./dev.sh tls import --name app --cert fullchain.pem --key privkey.pem Validate and import a PEM pair (private key mode 600) ./dev.sh tls deploy --id app --cert /etc/letsencrypt/live/app/fullchain.pem --key /etc/letsencrypt/live/app/privkey.pem Deploy an externally issued pair to an existing manual certificate id ./dev.sh tls reload Re-read and hot-apply configured certificate files without changing config revision ./dev.sh config reload Revalidate the current runtime configuration ./dev.sh repair Preserve known legacy files; no compilation required ./dev.sh doctor Check source layout and show available build tools ./dev.sh token Compatibility alias for admin setup-token ./dev.sh config get Export the running desired config as JSON ./dev.sh config apply FILE Validate, persist and hot-apply a JSON document ./dev.sh config validate FILE Validate only; works without a running server ./dev.sh backup DIRECTORY Back up SQLite and configured certificates using Python 3 ./dev.sh mock [--port 9001] Start a random-data HTTP origin (Python only; Ctrl+C to stop) ./dev.sh mock-auth [--port 9300] Start a LOOPBACK-ONLY fake Tinyauth peer (never production) ./dev.sh acme --doctor Check local Certbot availability without network access ./dev.sh acme --cert-dir DIR Read provider request JSON from stdin; stage PEM files ./dev.sh test Run offline release checks and all Rust tests ./dev.sh build Build the development binary only ./dev.sh release Build an optimized binary (target/release/rust-proxy) ./dev.sh fmt Format Rust sources with rustfmt ./dev.sh check Cargo check for all targets Defaults: HTTP 127.0.0.1:8080, HTTPS 127.0.0.1:8443, panel 127.0.0.1:9090. The optional diagnostic origin uses 127.0.0.1:9000 and is OFF by default. Set RUST_PROXY_TLS=0 to disable the TLS listener. Default certificate is self-signed. Set RUST_PROXY_DEMO=1 to explicitly start a diagnostic origin and seed a NEW database. Configuration options: .env.example, README.md, docs/API.md, ./dev.sh run --help. HELP exit 0 ;; run|admin|token|config|tls|repair|doctor|backup|test|build|release|fmt|check|mock|mock-auth|acme) ;; *) printf 'Unknown command: %s. Use ./dev.sh help\n' "$mode" >&2; exit 2 ;; esac if [[ "$mode" == "backup" ]]; then exec python3 scripts/backup.py --data-dir "${RUST_PROXY_DATA_DIR:-$ROOT/data}" "$@" fi if ! command -v python3 >/dev/null 2>&1; then printf 'Python 3.10+ is required for source preflight and upgrade safety checks.\n' >&2 exit 127 fi python3 -c 'import sys; sys.exit(0 if sys.version_info >= (3, 10) else "Python 3.10+ is required.")' if [[ "$mode" == "doctor" ]]; then python3 scripts/preflight.py printf 'Source layout: OK\n' for tool in cargo rustc cc python3; do printf '%s: ' "$tool" command -v "$tool" || printf 'NOT FOUND\n' done exit 0 fi if [[ "$mode" == "acme" ]]; then exec python3 scripts/acme_provider.py "$@"; fi if [[ "$mode" == "mock-auth" ]]; then exec python3 scripts/mock_auth.py "$@"; fi if [[ "$mode" == "mock" ]]; then exec python3 scripts/mock_server.py "$@"; fi python3 scripts/preflight.py --repair-known if [[ "$mode" == "repair" ]]; then printf 'Source preflight: OK\n'; exit 0; fi if [[ "$mode" == "test" ]]; then python3 scripts/rust_module_contracts.py python3 scripts/source_module_contracts.py python3 scripts/check_source.py python3 scripts/release_smoke.py python3 scripts/memory_contracts.py python3 scripts/web_server_contracts.py python3 scripts/security_contracts.py python3 scripts/security_dependency_contracts.py if command -v node >/dev/null 2>&1; then node scripts/web_service_ui_test.mjs else printf 'Node.js not found; skipping Web Service UI behavior test.\n' >&2 fi python3 scripts/docs_check.py python3 scripts/langs_check.py fi if ! command -v cargo >/dev/null 2>&1; then cat >&2 <<'MISSING' Rust/Cargo is not installed or not in PATH. Install the stable Rust toolchain using https://rustup.rs, then open a new terminal. Linux also needs a C compiler/linker (for example: build-essential or gcc). macOS: install the Xcode command line tools. Windows: use WSL2 + Bash. This script does not install system software or run sudo automatically. MISSING exit 127 fi export RUST_PROXY_DATA_DIR="${RUST_PROXY_DATA_DIR:-$ROOT/data}" export RUST_PROXY_PROXY_LISTEN="${RUST_PROXY_PROXY_LISTEN:-127.0.0.1:8080}" export RUST_PROXY_ADMIN_LISTEN="${RUST_PROXY_ADMIN_LISTEN:-127.0.0.1:9090}" if [[ "${RUST_PROXY_TLS:-1}" == "1" ]]; then export RUST_PROXY_TLS_LISTEN="${RUST_PROXY_TLS_LISTEN:-127.0.0.1:8443}" else unset RUST_PROXY_TLS_LISTEN fi export RUST_PROXY_DEMO_LISTEN="${RUST_PROXY_DEMO_LISTEN:-127.0.0.1:9000}" export RUST_LOG="${RUST_LOG:-rust_proxy=info,warn}" export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target}" if [[ "$CARGO_TARGET_DIR" != /* ]]; then export CARGO_TARGET_DIR="$ROOT/$CARGO_TARGET_DIR"; fi if [[ "$mode" == "fmt" ]]; then exec cargo fmt --all "$@"; fi if [[ ! -f Cargo.lock ]]; then printf 'Resolving dependencies once; creating Cargo.lock (keep it for future builds).\n' >&2 cargo generate-lockfile fi case "$mode" in check) exec cargo check --locked --all-targets "$@" ;; release) exec cargo build --locked --release "$@" ;; esac if [[ "$mode" == "test" ]]; then printf 'Checking all Rust targets before tests...\n' >&2 cargo check --locked --all-targets fi printf 'Building RustProxy 0.25.7...\n' >&2 cargo build --locked BIN="$CARGO_TARGET_DIR/debug/rust-proxy" case "$mode" in build) printf 'Binary: %s\n' "$BIN" ;; token) exec "$BIN" token "$@" ;; admin) exec "$BIN" admin "$@" ;; config) exec "$BIN" config "$@" ;; tls) exec "$BIN" tls "$@" ;; test) cargo test --locked --all-targets ;; run) args=(serve) if [[ "${RUST_PROXY_DEMO:-0}" == "1" ]]; then args+=(--demo); fi exec "$BIN" "${args[@]}" "$@" ;; esac