The room client took its relay, room service, fixture, WebTransport URL, certificate hashes and issuer directory from its query string as given, and followed a relay's GOAWAY to any URI. A crafted link and a press of Join would send a joiner's camera and microphone to another origin. - web/room/endpoint.js: an endpoint is taken only on the page's own origin (`https://<host>`, or `wss://<host>` for a relay), never with user information; a page served from the loopback interface (a fixture page, the e2e harness) takes loopback addresses alone. - app.js: `service`, `ws`, `wt`, `fixture` and `issuer_directory` are held to it; `hashes` only on a loopback page. A refused endpoint is recorded (`snapshot().refused`) and shown, Join stays off, and the page connects to nothing: `enter()` checks the relay before it asks for the camera, a grant or a session. A GOAWAY naming another origin is refused: the page closes its session and says so. - web/room/endpoint.test.mjs (run by e2e/run.sh): own origin, another origin, scheme-relative, the page's host as user information, javascript:, a plain scheme on a secure page, an HTTP page, and loopback for the harness. - e2e scenario `origin`: a foreign `?ws=` is refused at Join and nothing connects (no WebSocket, request, grant or camera); a foreign `?service=`, scheme-relative, behind user information or as javascript:, is refused with Join off; a GOAWAY to another origin is refused and the session ends. The `service` scenario checks that every request and WebSocket of every page stays on the page's origin, as the production `connect-src` requires. Co-Authored-By: Claude Opus 5.5 <[email protected]>
86 lines
4.7 KiB
Shell
Executable file
86 lines
4.7 KiB
Shell
Executable file
#!/bin/bash
|
|
# Build what the browser MoQ client's tests need, and run them.
|
|
#
|
|
# e2e/run.sh [--only compose,webtransport,websocket,goaway,dvr,service,e2ee,age,co,ageco,binding,cowatch,origin] [--runs N]
|
|
#
|
|
# 1. joule-moq-relay, joule-moq-room (its own workspace) and wai_live_web (native,
|
|
# release: the test room and the host's composition);
|
|
# 2. joule-moq-web and wai-live-web for wasm32-unknown-unknown, through wasm-bindgen's web
|
|
# target into web/pkg/, each with its own --out-name; and joule-moq-web again with its
|
|
# feature e2ee (the member of an end-to-end encrypted room), under the workspace's `wasm`
|
|
# profile and with no name section, as joule_moq_web_e2ee, which a page loads for such a
|
|
# room alone; and wai-live-web again with its feature int_video, as wai_live_web_decode,
|
|
# the decoder on the browser sink's wasm route, which the binding page loads;
|
|
# 3. the browser-automation package from e2e/package-lock.json (`npm ci --ignore-scripts`:
|
|
# no install script runs), outside the tree unless PLAYWRIGHT_HOST names one installed;
|
|
# 4. the Node unit tests of the page's own modules;
|
|
# 5. e2e/room.e2e.mjs, in the installed browser whose executable BROWSER_BIN names (the
|
|
# CI job names the host's), otherwise the package's own, which PLAYWRIGHT_BROWSERS_PATH
|
|
# must then hold.
|
|
#
|
|
# Environment: CARGO_TARGET_DIR (one target directory for both workspaces), BROWSER_BIN,
|
|
# PLAYWRIGHT_HOST, MOQ_WEB_OUT (where artifacts go), CARGO_LOCKED (default --locked).
|
|
# Nothing listens beyond loopback: the relay and the page server bind 127.0.0.1.
|
|
set -euo pipefail
|
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
|
CRATE=$(cd "$HERE/.." && pwd)
|
|
JC=$(cd "$CRATE/../.." && pwd)
|
|
ROOT=$(cd "$JC/../.." && pwd)
|
|
WLW="$ROOT/wai/wai-live-web"
|
|
LOCKED=${CARGO_LOCKED---locked}
|
|
TARGET=${CARGO_TARGET_DIR:-$JC/target}
|
|
export CARGO_TARGET_DIR="$TARGET"
|
|
OUT=${MOQ_WEB_OUT:-${TMPDIR:-/tmp}/moq-web-e2e}
|
|
mkdir -p "$OUT"
|
|
# Each run starts from no results: a scenario writes keys and logs there, and the room
|
|
# service's keygen refuses a key file a previous run left.
|
|
rm -rf "$OUT/results"
|
|
PKG="$CRATE/web/pkg"
|
|
mkdir -p "$PKG"
|
|
|
|
step() { echo "== $*"; }
|
|
|
|
step "native: joule-moq-relay, joule-moq-room, wai_live_web"
|
|
(cd "$JC" && cargo build $LOCKED --release -p joule-moq-relay --bin joule-moq-relay)
|
|
(cd "$CRATE/../joule-moq-room" && cargo build $LOCKED --release --bin joule-moq-room)
|
|
(cd "$WLW" && cargo build $LOCKED --release --bin wai_live_web)
|
|
|
|
step "wasm: joule-moq-web, wai-live-web"
|
|
command -v wasm-bindgen >/dev/null || { echo "wasm-bindgen CLI 0.2.127 is needed (cargo install --locked wasm-bindgen-cli --version 0.2.127)"; exit 2; }
|
|
wasm-bindgen --version | grep -q ' 0\.2\.127$' || { echo "the wasm-bindgen CLI must be 0.2.127, the version both crates pin"; exit 2; }
|
|
(cd "$JC" && cargo build $LOCKED --release -p joule-moq-web --lib --target wasm32-unknown-unknown)
|
|
wasm-bindgen --target web --out-dir "$PKG" --out-name joule_moq_web "$TARGET/wasm32-unknown-unknown/release/joule_moq_web.wasm"
|
|
(cd "$JC" && cargo build $LOCKED --profile wasm -p joule-moq-web --lib --target wasm32-unknown-unknown --features e2ee)
|
|
wasm-bindgen --target web --remove-name-section --remove-producers-section --out-dir "$PKG" --out-name joule_moq_web_e2ee "$TARGET/wasm32-unknown-unknown/wasm/joule_moq_web.wasm"
|
|
(cd "$WLW" && cargo build $LOCKED --release --lib --target wasm32-unknown-unknown)
|
|
wasm-bindgen --target web --out-dir "$PKG" --out-name wai_live_web "$TARGET/wasm32-unknown-unknown/release/wai_live_web.wasm"
|
|
(cd "$WLW" && cargo build $LOCKED --release --lib --target wasm32-unknown-unknown --features int_video)
|
|
wasm-bindgen --target web --out-dir "$PKG" --out-name wai_live_web_decode "$TARGET/wasm32-unknown-unknown/release/wai_live_web.wasm"
|
|
ls -l "$PKG"/*.wasm
|
|
|
|
step "browser automation"
|
|
if [ -z "${PLAYWRIGHT_HOST:-}" ]; then
|
|
PW="$OUT/pw"
|
|
mkdir -p "$PW"
|
|
cp "$HERE/package.json" "$HERE/package-lock.json" "$PW/"
|
|
(cd "$PW" && npm ci --ignore-scripts --no-audit --no-fund)
|
|
export PLAYWRIGHT_HOST="$PW/node_modules"
|
|
fi
|
|
BROWSER_BIN=${BROWSER_BIN:-}
|
|
|
|
step "unit tests of the page's modules"
|
|
node --test "$CRATE/web/moq/capsule.test.mjs" "$CRATE/web/moq/media.test.mjs" "$CRATE/web/ads/presentation.test.mjs" "$CRATE/web/room/privacy-pass.test.mjs" "$CRATE/web/room/binding.test.mjs" "$CRATE/web/room/cowatch.test.mjs" "$CRATE/web/room/markup.test.mjs" "$CRATE/web/room/endpoint.test.mjs"
|
|
|
|
step "end-to-end"
|
|
browser=()
|
|
[ -n "$BROWSER_BIN" ] && browser=(--browser "$BROWSER_BIN")
|
|
node "$HERE/room.e2e.mjs" \
|
|
--relay "$TARGET/release/joule-moq-relay" \
|
|
--room "$TARGET/release/joule-moq-room" \
|
|
--wai "$TARGET/release/wai_live_web" \
|
|
--web "$CRATE/web" \
|
|
--corpus "$ROOT/wai/live-conformance/compose/vectors.json" \
|
|
--wai-dir "$ROOT/wai" \
|
|
--out "$OUT/results" \
|
|
${browser[@]+"${browser[@]}"} \
|
|
"$@"
|