Harden gameplay timing and map loading
This commit is contained in:
@@ -36,6 +36,9 @@ MINEGEO_ALLOW_ANY_ORIGIN=true
|
||||
|
||||
This bypasses MineGeo's browser origin checks, including their CSRF protection.
|
||||
The default is `false`; only the exact value `true` enables the bypass.
|
||||
Use `npm run dev` for this testing mode. Production ignores the bypass, and
|
||||
`npm start` refuses to launch when it is enabled. Public production URLs must use
|
||||
HTTPS; loopback HTTP remains available for testing a production build locally.
|
||||
Authentication, permissions, and JSON request requirements still apply. This
|
||||
setting controls MineGeo's API checks; Supabase email sign-in still needs allowed
|
||||
redirect URLs, and `MINEGEO_URL` still controls capture-tool pairing links.
|
||||
|
||||
57
docs/production-audit.md
Normal file
57
docs/production-audit.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Map and production audit — October 5, 2026
|
||||
|
||||
Tracked in [Linear DUN-30](https://linear.app/dungeons-and-projects/issue/DUN-30/fix-map-and-gameplay-bugs-and-prepare-minegeo-for-production).
|
||||
|
||||
## Fixes
|
||||
|
||||
- Panorama viewers own and release their textures on unmount. Failed and stalled
|
||||
loads release completed and late-arriving faces. There is no unbounded global
|
||||
cache of every panorama and rotating signed URL.
|
||||
- Map-image failures and stalled loads show a retry control, including results.
|
||||
Map cleanup is installed before image initialization. Resizing keeps the map
|
||||
fitted or preserves the player's view. Keyboard users can pan with arrow keys
|
||||
and press Enter to place a pin at the center.
|
||||
- Countdown synchronization accounts for request latency and uses a monotonic
|
||||
clock. Submission has an immediate lock, failed timeout requests stop retrying
|
||||
behind an error dialog, current-round points update immediately, and timeout
|
||||
results do not retain an unsubmitted pin.
|
||||
- Session media signing uses a single batch for the map and 30 faces. Catalog
|
||||
signing deduplicates images. Existing revision/media authorization is retained.
|
||||
- Missing/invalid map IDs get a 404; backend failures reach the retryable error
|
||||
boundary. The error page now uses Next.js 16.3's `retry()` to fetch fresh data.
|
||||
Database transport/schema errors return 503 without exposing their internals.
|
||||
- All API responses prevent caching, guest HTTPS cookies respect the configured
|
||||
proxy origin, production disables the origin bypass, and baseline browser
|
||||
security headers are configured. Startup validates environment, heap and
|
||||
panorama size before launching either process.
|
||||
- Client requests explain offline, timeout and non-JSON gateway errors. Catalog
|
||||
searches trim whitespace, source/result selection exposes pressed state,
|
||||
successful dashboard refreshes clear stale errors, and sign-out failures stay
|
||||
visible. Results now label the dashboard link accurately as My maps.
|
||||
|
||||
## Validation
|
||||
|
||||
- 63 Node regression tests passed, including new client-error, texture-disposal,
|
||||
clock, startup-config, backend-error and production-origin tests.
|
||||
- TypeScript checking and the optimized Next.js 16.3.8 production build passed.
|
||||
- The HTTP/API/Storage smoke passed against both development and compiled
|
||||
production servers with the configured backend. It exercised pages/JARs,
|
||||
headers, privacy, signed map/cubemap downloads, five rounds, duplicate requests,
|
||||
out-of-bounds rejection and foreign-origin denial, then deleted its test games.
|
||||
- Codex's built-in browser verified the live homepage/catalog, trimmed search,
|
||||
hard-mode panorama and timeout, game reload/results and result-round selection.
|
||||
A separate local fixture verified failed map images, successful retry, keyboard
|
||||
guessing and rectangular-map resizing. Browser checks found no uncaught errors.
|
||||
- The production npm dependency audit reported zero known vulnerabilities.
|
||||
- The Supabase security advisor and a permissions query confirmed public workflow
|
||||
RPCs use invoker security and deny anon/authenticated execution. Informational
|
||||
no-policy notices concern deliberately server-only RLS tables.
|
||||
|
||||
## Launch requirements and limits
|
||||
|
||||
Leaked-password protection remains disabled in the configured Supabase project;
|
||||
it must be enabled in provider settings where the plan supports it. Production
|
||||
SMTP, emailed login/recovery delivery, public HTTPS/proxy configuration and
|
||||
restoration from backups were not exercised in this local audit. No deployment,
|
||||
new Minecraft client capture, or cross-platform worker benchmark was performed.
|
||||
Follow [the production guide](production.md) before public launch.
|
||||
55
docs/production.md
Normal file
55
docs/production.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Production launch
|
||||
|
||||
The website requires a Node.js host and a persistent rendering worker. Deploy
|
||||
this checkout with Node.js 22 or later, run `npm ci`, `npm run setup`, and
|
||||
`npm run check`, then start it with `npm start` under your host's process manager.
|
||||
The supervisor runs the website and worker together and stops the companion if
|
||||
either exits. A host that runs only Next.js must run `npm run worker` separately.
|
||||
|
||||
Configure these before starting:
|
||||
|
||||
- `MINEGEO_URL`: the public HTTPS origin, without a path, query or credentials.
|
||||
Loopback HTTP is supported for local production checks.
|
||||
- `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`, and the
|
||||
server-only `SUPABASE_SECRET_KEY`. The supervisor validates missing keys and
|
||||
rejects a server secret in the publishable-key field before starting children.
|
||||
- Keep `MINEGEO_ALLOW_ANY_ORIGIN=false`. Production ignores the bypass; the
|
||||
supervisor also rejects it at startup. Use `MINEGEO_ALLOWED_ORIGINS` for exact
|
||||
aliases and configure your reverse proxy to retain the public Host header.
|
||||
- Keep the default loopback binding behind a local HTTPS reverse proxy. Set
|
||||
`MINEGEO_HOST=0.0.0.0` only when your hosting/container network requires it.
|
||||
- Apply the existing `supabase/migrations` in filename order. This audit adds no
|
||||
database migration. Keep the media and raw buckets private.
|
||||
|
||||
Configure Supabase Auth's Site URL and allowed `/auth/callback` redirects for the
|
||||
public origin, email confirmation, working production SMTP, and a minimum
|
||||
password length of 12. Enable leaked-password protection when the plan supports
|
||||
it; the October 5 audit found it disabled. See the [account guide](account-settings.md)
|
||||
and [Supabase password security](https://supabase.com/docs/guides/auth/password-security).
|
||||
|
||||
The site sends no-store headers for all application API responses, including
|
||||
drafts, pairing credentials, tokens and errors. Guest cookies are HttpOnly,
|
||||
SameSite=Lax, and Secure for the configured HTTPS public host behind a proxy.
|
||||
The response headers prevent framing and MIME sniffing, limit referrers, and
|
||||
disable unused camera, microphone and location permissions. Configure HTTPS
|
||||
certificates and HSTS at the public reverse proxy.
|
||||
|
||||
Monitor `/api/v1/health`: HTTP 200 means its database query succeeded; 503 means
|
||||
configuration or the data service is unavailable. Also retain worker logs and
|
||||
monitor failed/queued jobs; website health does not assert worker liveness.
|
||||
Keep Supabase backups enabled and test restoration before storing irreplaceable
|
||||
community uploads.
|
||||
|
||||
After deployment, run:
|
||||
|
||||
```sh
|
||||
npm run test:production -- https://your-public-origin.example
|
||||
```
|
||||
|
||||
Run this from the configured checkout for the same Supabase project. The test
|
||||
checks pages/downloads, security headers, invalid map IDs, guest access denial,
|
||||
CSRF denial, malformed JSON, session isolation, real signed WebP downloads, and
|
||||
all five rounds with idempotent activation/submission and out-of-bounds rejection.
|
||||
It removes only its generated guest session. A published map is required.
|
||||
|
||||
See [the audit record](production-audit.md) for evidence and remaining limits.
|
||||
Reference in New Issue
Block a user