#!/bin/sh
# sshyeet: make this machine reachable over ssh, through sshyeet.com.
#
#   curl -fsSL https://sshyeet.com | sh                  anyone holding the printed secret gets a shell
#   curl -fsSL https://sshyeet.com/gh/USER | sh          only github.com/USER's ssh keys get in
#   curl -fsSL https://sshyeet.com | sh -s -- --help     all agent flags (e.g. -d to detach, --ttl 1h)
#
# This script downloads the sshyeet agent (a static binary, ~10MB) for this
# OS/architecture into ${SSHYEET_HOME:-~/.cache/sshyeet} (a directory only you
# can write), checks it against https://sshyeet.com/dl/SHA256SUMS, and runs it. Nothing is installed system-wide and
# nothing listens on a local port; the agent dials out to sshyeet.com:443.
set -eu

base='https://sshyeet.com'
version='v5b21fb0'

say() { printf 'sshyeet: %s\n' "$*" >&2; }
die() { say "$*"; exit 1; }

fetch() { # url dest
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL --retry 3 -o "$2" "$1"
  elif command -v wget >/dev/null 2>&1; then
    wget -q -O "$2" "$1"
  else
    die "need curl or wget"
  fi
}

os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
  linux|darwin|freebsd) ;;
  *) die "unsupported OS: $os (linux, darwin and freebsd are; or build from source)" ;;
esac
arch=$(uname -m)
case "$arch" in
  x86_64|amd64) arch=amd64 ;;
  aarch64|arm64) arch=arm64 ;;
  armv6*|armv7*|armv8l|arm) arch=arm ;;
  i386|i486|i586|i686) arch=386 ;;
  riscv64) arch=riscv64 ;;
  mips) arch=mips ;;
  mipsel|mipsle) arch=mipsle ;;
  mips64) arch=mips64 ;;
  mips64el|mips64le) arch=mips64le ;;
  ppc64le) arch=ppc64le ;;
  s390x) arch=s390x ;;
  *) die "unsupported architecture: $arch" ;;
esac
name="sshyeet-$os-$arch"

# Where the binary lives: a directory owned by us and closed to others, so
# nobody else on this machine can plant or swap the thing we are about to run.
dir=""
if [ -n "${SSHYEET_HOME:-}" ]; then dir=$SSHYEET_HOME
elif [ -n "${XDG_CACHE_HOME:-}" ]; then dir=$XDG_CACHE_HOME/sshyeet
elif [ -n "${HOME:-}" ]; then dir=$HOME/.cache/sshyeet
fi
if [ -z "$dir" ] || ! { mkdir -p "$dir" 2>/dev/null && [ -w "$dir" ]; }; then
  dir=$(umask 077; mktemp -d "${TMPDIR:-/tmp}/sshyeet.XXXXXX") || die "cannot create a private directory; set SSHYEET_HOME"
fi
[ ! -L "$dir" ] || die "$dir is a symlink; refusing (set SSHYEET_HOME)"
chmod 700 "$dir" 2>/dev/null || true
owner=$(stat -c %u "$dir" 2>/dev/null || stat -f %u "$dir" 2>/dev/null || echo unknown)
[ "$owner" = "$(id -u)" ] || die "$dir is owned by uid $owner, not you; refusing (set SSHYEET_HOME)"
bin="$dir/sshyeet"

sha256() { # file -> hex digest, or nothing if no tool is available
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1
  elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1
  elif command -v openssl >/dev/null 2>&1; then openssl dgst -sha256 -r "$1" | cut -d' ' -f1
  fi
}

tmp="$dir/.download.$$"
trap 'rm -f "$tmp" "$tmp.gz" "$tmp.sums"' EXIT INT TERM
want=""
if fetch "$base/dl/SHA256SUMS" "$tmp.sums"; then
  want=$(grep " $name\$" "$tmp.sums" | cut -d' ' -f1)
  [ -n "$want" ] || die "$base/dl/SHA256SUMS has no entry for $name"
else
  say "warning: could not fetch $base/dl/SHA256SUMS; downloads cannot be verified"
fi

# Reuse a cached binary only if it is byte-for-byte the published one.
if [ -n "$want" ] && [ -f "$bin" ] && [ ! -L "$bin" ] && [ "$(sha256 "$bin")" = "$want" ]; then
  : # up to date and verified
else
  say "downloading $base/dl/$name ($version) to $bin"
  if command -v gzip >/dev/null 2>&1; then
    fetch "$base/dl/$name.gz" "$tmp.gz"
    gzip -dc "$tmp.gz" > "$tmp"
    rm -f "$tmp.gz"
  else
    fetch "$base/dl/$name" "$tmp"
  fi
  if [ -n "$want" ]; then
    got=$(sha256 "$tmp")
    if [ -z "$got" ]; then
      say "warning: no sha256sum, shasum or openssl here; cannot verify the download"
    elif [ "$got" != "$want" ]; then
      die "checksum mismatch for $name (got $got, want $want)"
    fi
  fi
  chmod 755 "$tmp"
  rm -f "$bin"
  mv -f "$tmp" "$bin"
fi
rm -f "$tmp.sums"
trap - EXIT INT TERM

# When piped from curl our stdin is the script itself; the agent does not read
# stdin, and Ctrl-C still reaches it because it stays in the foreground.
exec "$bin" --relay "$base" "$@"
