#!/usr/bin/env bash # Smoke test for the file host. # # Usage: # ./scripts/smoke-test.sh # assumes http://127.0.0.1:3000 # BASE_URL=http://127.0.0.1:3000 ./scripts/smoke-test.sh # # Requires a running instance and `bun` on PATH. set -euo pipefail BASE="${BASE_URL:-http://127.0.0.1:3000}" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT pass=0 fail=0 check() { # check local name="$1" shift if "$@"; then pass=$((pass + 1)) echo "ok: $name" >&2 else fail=$((fail + 1)) echo "FAIL: $name" >&2 fi } get() { # get bun -e 'const d = JSON.parse(await Bun.file(process.argv[3]).text()); console.log(d[process.argv[2]])' _ "$2" "$1" } printf 'hello world\n' > "$TMP/plain.txt" dd if=/dev/urandom of="$TMP/random.bin" bs=1M count=16 2>/dev/null check "health endpoint" curl -sS -f "$BASE/api/health" >/dev/null check "upload plain file" curl -sS -f -F "file=@$TMP/plain.txt" "$BASE/api/upload" > "$TMP/up.json" KEY="$(get "$TMP/up.json" key)" ID="$(get "$TMP/up.json" id)" URL="$(get "$TMP/up.json" url)" [ -n "$KEY" ] && check "upload returns a key" true check "download with key" curl -sS -f -o "$TMP/down.txt" "$BASE$URL" check "downloaded content matches" cmp "$TMP/plain.txt" "$TMP/down.txt" check "invalid key returns 404" test \ "$(curl -sS -o /dev/null -w '%{http_code}' "$BASE/d/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")" = "404" check "id alone cannot download" test \ "$(curl -sS -o /dev/null -w '%{http_code}' "$BASE/d/$ID")" = "404" check "storage directory not served" test \ "$(curl -sS -o /dev/null -w '%{http_code}' "$BASE/storage/")" = "404" check "unicode filename upload" \ curl -sS -f -F "file=@$TMP/plain.txt;filename=caf%C3%A9-%E6%96%87%E4%BB%B6.txt" "$BASE/api/upload" > "$TMP/upU.json" KU="$(get "$TMP/upU.json" key)" check "unicode filename download" curl -sS -f -o /dev/null "$BASE/d/$KU" check "path traversal filename sanitized" \ curl -sS -f -F "file=@$TMP/plain.txt;filename=../../../../etc/passwd" "$BASE/api/upload" > "$TMP/upT.json" check "upload 16MB binary" curl -sS -f -F "file=@$TMP/random.bin" "$BASE/api/upload" > "$TMP/upL.json" KL="$(get "$TMP/upL.json" key)" check "download 16MB binary" curl -sS -f -o "$TMP/random.out" "$BASE/d/$KL" check "16MB round-trip identical" cmp "$TMP/random.bin" "$TMP/random.out" check "delete requires key" test \ "$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE "$BASE/api/files/$ID")" = "404" check "delete with key succeeds" \ curl -sS -f -X DELETE -H "X-Delete-Key: $KEY" "$BASE/api/files/$ID" >/dev/null check "file gone after delete" test \ "$(curl -sS -o /dev/null -w '%{http_code}' "$BASE$URL")" = "404" echo echo "-- password protection --" check "upload with password" curl -sS -f -F "password=hunter2" -F "file=@$TMP/plain.txt" "$BASE/api/upload" > "$TMP/upP.json" KP="$(get "$TMP/upP.json" key)" check "protected file serves a password form" test \ "$(curl -sS -o /dev/null -w '%{content_type}' "$BASE/d/$KP")" = "text/html; charset=utf-8" check "wrong password is rejected" test \ "$(curl -sS -o /dev/null -w '%{http_code}' -X POST -d 'password=nope' "$BASE/api/auth/$KP")" = "302" check "correct password returns redirect" curl -sS -c "$TMP/cj.txt" -X POST -d "password=hunter2" "$BASE/api/auth/$KP" >/dev/null curl -sS -b "$TMP/cj.txt" -o "$TMP/downP.txt" "$BASE/d/$KP" check "download with cookie matches" cmp "$TMP/plain.txt" "$TMP/downP.txt" echo echo "passed: $pass, failed: $fail" [ "$fail" -eq 0 ] || exit 1