#!/bin/sh # Self-contained, per-user bootstrap. No sudo, package managers, or system Python/Tor. set -eu umask 077 rdzv_main() { VERSION='0.2.1' RELEASE_ORIGIN='https://rendezvous.sh' RELEASE_SHA256='2f07da69062c00b830e34ca9752908e63e7f3e689341445c161099b40a8ae43f' RELEASE_PARTS='rendezvous-0.2.1-linux-x86_64.tar.gz.part00 rendezvous-0.2.1-linux-x86_64.tar.gz.part01 rendezvous-0.2.1-linux-x86_64.tar.gz.part02' MODE='host' case "${1-}" in host|join|install) MODE=$1; shift ;; esac case "$MODE" in host|join|install) ;; *) printf '%s\n' 'Invalid mode' >&2; return 1 ;; esac if [ "$(uname -s)" != Linux ] || [ "$(uname -m)" != x86_64 ]; then printf '%s\n' 'This portable release supports Linux x86_64. No system changes were made.' >&2 return 1 fi GLIBC=$(getconf GNU_LIBC_VERSION 2>/dev/null || true) case "$GLIBC" in 'glibc '*) GLIBC=${GLIBC#glibc } ;; *) printf '%s\n' 'This release needs glibc 2.34+ (not Alpine/musl).' >&2; return 1 ;; esac MAJOR=${GLIBC%%.*}; MINOR=${GLIBC#*.}; MINOR=${MINOR%%.*} case "$MAJOR:$MINOR" in *[!0-9:]*|:|*:) printf '%s\n' 'Could not determine glibc version.' >&2; return 1 ;; esac if [ "$MAJOR" -lt 2 ] || { [ "$MAJOR" -eq 2 ] && [ "$MINOR" -lt 34 ]; }; then printf '%s\n' 'This release requires glibc 2.34+ (Ubuntu 22.04+, Debian 12+, Amazon Linux 2023).' >&2 return 1 fi for tool in curl tar sha256sum mktemp; do command -v "$tool" >/dev/null 2>&1 || { printf 'Required base utility missing: %s\n' "$tool" >&2; return 1; } done : "${HOME:?HOME must be set}" ROOT="$HOME/.local/share/rendezvous" BIN="$HOME/.local/bin" if [ -L "$ROOT" ]; then printf '%s\n' 'Refusing symlinked installation root.' >&2; return 1; fi mkdir -p "$ROOT" "$BIN" chmod 700 "$ROOT" WORK=$(mktemp -d "$ROOT/.install.XXXXXXXX") PENDING_ENV='' trap 'rm -rf -- "$WORK"; if [ -n "$PENDING_ENV" ]; then rm -rf -- "$PENDING_ENV"; fi' EXIT trap 'exit 130' INT trap 'exit 143' TERM HUP TARGET="$ROOT/$VERSION" if [ ! -f "$TARGET/.complete" ] || [ "$(cat "$TARGET/.complete" 2>/dev/null)" != "$RELEASE_SHA256" ]; then if [ -t 2 ] && [ "${NO_COLOR+x}" != x ] && [ "${TERM-}" != dumb ]; then printf '\033[90mDownloading Rendezvous %s…\033[0m\n' "$VERSION" >&2 else printf 'Downloading Rendezvous %s…\n' "$VERSION" >&2 fi : > "$WORK/release.tar.gz" for part in $RELEASE_PARTS; do curl --proto '=https' --tlsv1.2 -fsSL --retry 3 --connect-timeout 20 --max-time 300 \ "$RELEASE_ORIGIN/releases/$VERSION/$part" -o "$WORK/part" cat "$WORK/part" >> "$WORK/release.tar.gz" done printf '%s %s\n' "$RELEASE_SHA256" "$WORK/release.tar.gz" > "$WORK/checksum" if ! sha256sum -c "$WORK/checksum" >/dev/null; then printf '%s\n' 'Release checksum mismatch; nothing installed.' >&2 return 1 fi tar -tzf "$WORK/release.tar.gz" > "$WORK/members" while IFS= read -r member; do case "/$member/" in *'/../'*|*'/./'*) printf '%s\n' 'Unsafe release path.' >&2; return 1 ;; esac case "$member" in app|app/*|bin|bin/*|python|python/*|tor|tor/*|licenses|licenses/*|BUILD.json) ;; *) printf '%s\n' 'Unexpected release contents.' >&2; return 1 ;; esac done < "$WORK/members" ENV_DIR=$(mktemp -d "$ROOT/runtime-$VERSION.XXXXXXXX") PENDING_ENV=$ENV_DIR # Only the exact hash-pinned publisher archive is extracted, never unverified input. tar -xzf "$WORK/release.tar.gz" --no-same-owner --no-same-permissions -C "$ENV_DIR" "$ENV_DIR/bin/rdzv" --version >/dev/null "$ENV_DIR/bin/tor" --version >/dev/null mkdir -p "$TARGET" printf '%s\n' "$ENV_DIR" > "$WORK/environment" mv "$WORK/environment" "$TARGET/environment" printf '%s\n' "$RELEASE_SHA256" > "$WORK/complete" mv "$WORK/complete" "$TARGET/.complete" PENDING_ENV='' fi ENV_DIR=$(cat "$TARGET/environment") case "$ENV_DIR" in "$ROOT"/runtime-*) ;; *) printf '%s\n' 'Invalid local runtime path.' >&2; return 1 ;; esac cat > "$WORK/rdzv" <<'SH' #!/bin/sh set -eu ROOT="$HOME/.local/share/rendezvous" ENV_DIR=$(cat "$ROOT/0.2.1/environment") case "$ENV_DIR" in "$ROOT"/runtime-*) ;; *) exit 1 ;; esac exec "$ENV_DIR/bin/rdzv" "$@" SH chmod 700 "$WORK/rdzv" mv "$WORK/rdzv" "$BIN/rdzv" cp "$BIN/rdzv" "$WORK/rendezvous" mv "$WORK/rendezvous" "$BIN/rendezvous" rm -rf -- "$WORK" trap - EXIT INT TERM HUP [ "$MODE" != install ] || return 0 if [ "$MODE" = join ]; then case " $* " in *' --invitation-file '*) exec "$BIN/rdzv" "$MODE" "$@" ;; *) if [ -r /dev/tty ]; then exec "$BIN/rdzv" "$MODE" "$@" &2; return 1; fi ;; esac fi exec "$BIN/rdzv" "$MODE" "$@" } rdzv_main "$@"