#!/bin/sh
set -eu

LIB_DIR=/usr/lib/proxyauth
SRC_TARBALL=/usr/share/proxyauth/proxyauth-src.tar.gz
STATE_DIR=/var/lib/proxyauth
BUILD_DIR=$STATE_DIR/build
RUST_DIR=$STATE_DIR/rust
LOG_DIR=/var/log/proxyauth
LOG_FILE=$LOG_DIR/build.log

if [ "$(id -u)" -ne 0 ]; then
    echo "proxyauth-build must be run as root" >&2
    exit 1
fi

group_exists() {
    getent group "$1" >/dev/null 2>&1 || grep -q "^$1:" /etc/group 2>/dev/null
}

setup_user() {
    nologin=$(command -v nologin 2>/dev/null || echo /sbin/nologin)

    if ! group_exists proxyauth; then
        if command -v groupadd >/dev/null 2>&1; then
            groupadd --system proxyauth
        else
            addgroup -S proxyauth
        fi
    fi

    if ! id proxyauth >/dev/null 2>&1; then
        if command -v useradd >/dev/null 2>&1; then
            useradd --system --gid proxyauth --no-create-home \
                --home-dir /opt/proxyauth --shell "$nologin" proxyauth
        else
            adduser -S -D -H -h /opt/proxyauth -s "$nologin" -G proxyauth proxyauth
        fi
    fi

    if group_exists www-data; then
        if command -v usermod >/dev/null 2>&1; then
            usermod -aG www-data proxyauth 2>/dev/null || true
        else
            addgroup proxyauth www-data 2>/dev/null || true
        fi
    fi
}

setup_dirs() {
    mkdir -p /etc/proxyauth/certs/routes /opt/proxyauth/db "$LOG_DIR"
    touch "$LOG_DIR/proxyauth.log" "$LOG_DIR/proxyauth.err"

    if [ ! -f /etc/proxyauth/certs/cert.pem ] || [ ! -f /etc/proxyauth/certs/key.pem ]; then
        echo "==> Generating a self-signed certificate"
        openssl req -x509 -newkey rsa:2048 -sha256 -days 7300 -nodes \
            -keyout /etc/proxyauth/certs/key.pem \
            -out /etc/proxyauth/certs/cert.pem \
            -subj "/CN=localhost" >/dev/null 2>&1
        chmod 644 /etc/proxyauth/certs/cert.pem
        chmod 640 /etc/proxyauth/certs/key.pem
    fi
}

run_build() {
    set -e

    TOOLCHAIN=$(cat "$LIB_DIR/toolchain")

    RUSTUP_HOME=$RUST_DIR/rustup
    CARGO_HOME=$RUST_DIR/cargo
    CARGO_TARGET_DIR=$BUILD_DIR/target
    HOME=$BUILD_DIR
    PATH=$CARGO_HOME/bin:$PATH
    export RUSTUP_HOME CARGO_HOME CARGO_TARGET_DIR HOME PATH

    mem_kb=$(awk '/^MemTotal:/ { print $2 }' /proc/meminfo 2>/dev/null || echo 0)
    if [ -z "${CARGO_BUILD_JOBS:-}" ] && [ "${mem_kb:-0}" -gt 0 ] && [ "$mem_kb" -lt 2000000 ]; then
        echo "==> Less than 2 GB of RAM: building with a single job"
        CARGO_BUILD_JOBS=1
        export CARGO_BUILD_JOBS
    fi

    if [ ! -x "$CARGO_HOME/bin/rustup" ]; then
        echo "==> Installing Rust $TOOLCHAIN into $RUST_DIR"
        curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o "$BUILD_DIR/rustup-init.sh"
        sh "$BUILD_DIR/rustup-init.sh" -y --profile minimal \
            --default-toolchain "$TOOLCHAIN" --no-modify-path
        rm -f "$BUILD_DIR/rustup-init.sh"
    else
        echo "==> Checking Rust $TOOLCHAIN"
        rustup toolchain install "$TOOLCHAIN" --profile minimal
    fi

    rustup toolchain list | awk '{ print $1 }' | while read -r installed; do
        case "$installed" in
            "$TOOLCHAIN"-*) ;;
            *) rustup toolchain uninstall "$installed" ;;
        esac
    done

    RUSTUP_TOOLCHAIN=$TOOLCHAIN
    export RUSTUP_TOOLCHAIN

    if rustc -vV | grep -q '^host:.*musl'; then
        RUSTFLAGS="${RUSTFLAGS:-} -C target-feature=-crt-static"
        export RUSTFLAGS
    fi

    echo "==> Extracting sources"
    rm -rf "$BUILD_DIR/src"
    mkdir -p "$BUILD_DIR/src"
    tar -xzf "$SRC_TARBALL" -C "$BUILD_DIR/src" --strip-components=1

    echo "==> Building ProxyAuth (this can take several minutes)"
    cd "$BUILD_DIR/src"
    cargo build --release --locked --offline

    install -m 0755 "$CARGO_TARGET_DIR/release/proxyauth" "$LIB_DIR/proxyauth.new"
    mv -f "$LIB_DIR/proxyauth.new" "$LIB_DIR/proxyauth"

    cd /
    rm -rf "$BUILD_DIR/src"
}

compile() {
    mkdir -p "$BUILD_DIR" "$RUST_DIR"
    chmod 0700 "$STATE_DIR"
    rm -f "$BUILD_DIR/.status"

    { ( run_build ); echo "$?" > "$BUILD_DIR/.status"; } 2>&1 | tee "$LOG_FILE"

    return "$(cat "$BUILD_DIR/.status" 2>/dev/null || echo 1)"
}

fix_permissions() {
    chown -R proxyauth:proxyauth /etc/proxyauth /opt/proxyauth "$LOG_DIR"
    chmod 750 /etc/proxyauth /etc/proxyauth/certs /etc/proxyauth/certs/routes \
        /opt/proxyauth /opt/proxyauth/db "$LOG_DIR"
    chmod 640 "$LOG_DIR/proxyauth.log" "$LOG_DIR/proxyauth.err"
}

setup_user
setup_dirs

status=0

if [ "${PROXYAUTH_SKIP_BUILD:-0}" != "1" ]; then
    set +e
    compile
    status=$?
    set -e

    if [ "$status" -eq 0 ]; then
        timeout 60 "$LIB_DIR/proxyauth" prepare >/dev/null 2>&1 || true
        echo "==> ProxyAuth built: $LIB_DIR/proxyauth"
    else
        echo "==> ERROR: ProxyAuth build failed (log: $LOG_FILE)" >&2
        echo "==> Fix the problem, then run 'proxyauth-build' again as root" >&2
    fi
fi

fix_permissions

exit "$status"
