feat(platform): add Discord onboarding and Velocity gate

This commit is contained in:
dmg
2026-08-01 13:45:18 -04:00
parent 9d305e5dc9
commit c5de0a1810
80 changed files with 4840 additions and 1572 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ The admin console will use Keycloak OIDC and JWT-backed Auth.js sessions, follow
## Application environment
- `AUTH_SECRET`
- `APP_URL`
- `NEXTAUTH_URL`
- `KEYCLOAK_ISSUER_URL`
- `KEYCLOAK_CLIENT_ID`
- `KEYCLOAK_CLIENT_SECRET`
+2 -2
View File
@@ -10,7 +10,7 @@ User authentication begins with an opaque, short-lived, single-use token created
### Discord bot
The bot creates private login links in response to `/register` and `/account`. Discord user IDs are the canonical Discord identity; mutable usernames are snapshots only. Nickname updates target the guild selected in admin settings.
The bot creates private login links in response to `/register` and `/account`. Discord user IDs are the canonical Discord identity; mutable usernames are snapshots only. Nickname updates target the deployment guild configured by `DISCORD_GUILD_ID`; the public join button uses `DISCORD_INVITE_URL`.
### Velocity plugin
@@ -23,7 +23,7 @@ The decision is fail closed. Unknown players, invalid responses, expired request
- Browser input is untrusted. Minecraft profile resolution occurs on the server.
- Forwarded IP headers are accepted only from configured reverse proxies.
- Discord IDs come from bot-authenticated requests or one-time-code records, not browser fields.
- Velocity requests will use per-server credentials, timestamps, and request IDs to support authentication and replay prevention.
- Velocity requests use hashed per-server bearer credentials, timestamps, and database-unique request IDs for authentication and replay prevention.
- Session and one-time-code values are random and stored only as hashes.
- Exact IP addresses are sensitive data and require an explicit retention policy before production deployment.
+39
View File
@@ -0,0 +1,39 @@
# Security review
Review date: 2026-08-01
## Scope
Next.js portal and APIs, Discord bot, PostgreSQL persistence, Keycloak admin authentication, and the Velocity admission plugin.
## Automated checks
- Semgrep `auto`: 0 findings
- `npm audit`: 0 known vulnerabilities after dependency overrides
- TypeScript, ESLint, unit tests, Next.js production build: passing
- Velocity Java tests and shaded plugin build: passing
## Implemented controls
- Discord login and session tokens use cryptographically secure randomness and are stored only as SHA-256 hashes.
- Login links expire after ten minutes, are single use, and are rate limited per Discord user with a PostgreSQL advisory lock.
- Session cookies are `httpOnly`, `sameSite=lax`, path-scoped, and secure in production.
- Admin access uses Keycloak OIDC and a required role.
- User mutations verify ownership server-side.
- Mojang lookup is server-side and targets a fixed host, avoiding client-forged validation and SSRF.
- Velocity credentials are high-entropy bearer tokens stored only as hashes.
- Velocity requests have a 45-second clock window and database-unique request IDs for cross-instance replay prevention.
- Velocity and its API fail closed.
- ORM-parameterized queries are used throughout.
- CSP, clickjacking, MIME-sniffing, referrer, and browser-permission headers are configured.
- Forwarded IP headers are ignored unless `TRUST_PROXY=true` is explicitly configured.
- Secrets are excluded from logs and repository configuration.
## Outstanding production requirements
- Select and implement a VPN/proxy intelligence provider before enabling VPN-based account-addition blocking. The current classification is explicitly `unknown`.
- Define and automate retention for exact IP addresses and audit events.
- Add monitoring and alerts for repeated login denials, plugin authentication failures, and Discord API failures.
- Use HTTPS for the public application and Velocity API URL. Protect the Velocity configuration file because it contains the one-time-displayed API token.
- Restrict database credentials so normal application roles cannot update or delete historical event rows outside approved application paths.
- Validate migrations in staging before production. Local migration application was unavailable during development because the Docker daemon was not running.