1# Signed in with a passkey, a reader sees a private repo's pages, reads its2# code.db in ranges with the cookie as code search's worker does, and finds3# the private repos they can read at /private/. Signed in as someone who4# may not read it, the repo is the missing page's 404. The sign-in pages5# work before a build has put their assets in www.6. "$(dirname "$0")/../lib.sh"7user dami8user ana9user cat10repo --private dami/secret "hidden thing"11repo --private dami/unbuilt "not yet"12repo --private cat/own13repo dami/open14for r in secret open; do15 clone dami "dami/$r" "$T/w/$r"16 at "$T/w/$r" commit "first"17 ok push_as dami "$T/w/$r" origin main18done19ok ssh_as dami readers dami/secret add ana20ok ssh_as dami readers dami/unbuilt add ana21build22# As if its first build hadn't finished.23rm -rf "$FORGE_ROOT/.forge/private/www/dami/unbuilt"24export FORGE_BASE_URL=https://forge.test25private_server26signin() {27 code=$(ssh_as "$1" passkey | sed -n 's/^ .*#enroll=//p')28 node "$T_HOME/test/authenticator.ts" enroll "$PRIV" "$code" "$T/$1.key"29}30ana=$(signin ana) || fail "ana"31cat=$(signin cat) || fail "cat"32as() { u=$1; shift; http -s -H "Cookie: __Host-forge=$u" "$@"; }3334eq "$(as "$ana" -o /dev/null -w '%{http_code}' "$PRIV/dami/secret/")" 20035as "$ana" "$PRIV/dami/secret/" | grep -q 'hidden thing' || fail "ana doesn't see dami/secret"36as "$ana" -D "$T/h" -o "$T/part" -H 'Range: bytes=0-99' "$PRIV/dami/secret/code.db"37has "$T/h" '^HTTP/1.1 206'38has "$T/h" '^Content-Range: bytes 0-99/'39has "$T/h" '^Cache-Control: private, no-cache'40eq "$(wc -c <"$T/part" | tr -d ' ')" 10041eq "$(head -c 15 "$T/part")" "SQLite format 3"4243response "$PRIV/dami/nope/" >"$T/missing"44response "$PRIV/dami/secret/" -H "Cookie: __Host-forge=$cat" >"$T/got"45cmp -s "$T/missing" "$T/got" || fail "cat, signed in, doesn't get the missing page's 404 for dami/secret"4647# /private/: what you may read and nothing else.48as "$ana" "$PRIV/private/" >"$T/list"49has "$T/list" 'Signed in as <b>ana</b>'50has "$T/list" '<a href="/dami/secret/"><span class="desc">dami /</span> <b>secret</b></a>'51has "$T/list" 'not yet <span class="desc">\(no pages yet\)</span>'52lacks "$T/list" '<b>(own|open)</b>'53as "$cat" "$PRIV/private/" >"$T/list"54has "$T/list" '<b>own</b>'55lacks "$T/list" '<b>(secret|unbuilt|open)</b>'56eq "$(http -s -o /dev/null -w '%{http_code} %{redirect_url}' "$PRIV/private/")" "303 $PRIV/login/?next=/private/"57http -s "$PRIV/login/?next=/dami/secret/" >"$T/page"58has "$T/page" 'data-next="/dami/secret/"'59http -s "$PRIV/login/?next=//evil.test/" >"$T/page"60has "$T/page" 'data-next=""'6162# Its scripts and styles, from the private server itself when www lacks them.63for a in $(grep -oE '(href|src)="/assets/[^"]+"' "$T/page" | sed -E 's/^[a-z]+="//; s/"$//' | sort -u); do64 eq "$(http -s -o /dev/null -w '%{http_code}' "$PRIV$a")" 20065done66grep -q '/assets/webauthn\.[A-Za-z0-9_-]*\.js' "$T/page" || fail "no webauthn script on the sign-in page"67grep -q '/assets/login\.[A-Za-z0-9_-]*\.js' "$T/page" || fail "no login script on the sign-in page"