[studio] beta studio (#114)

* rrs stuff

* studio service yay

* rrs whitelist

* moree studiooooooo fellowwww

* rec room studio room loading yay

* fixes yay

* fix 2 because idk  yayuh

* Update cdn.app.ts

* ccontent length fix?

* Preserve content-length and upgrade metadata

Return a real zero-filled byte array for CDN HEAD responses so the runtime preserves Content-Length while still sending no payload. In notify, re-create the Request with its original headers, set OWNER_HEADER from the validated token, and forward that Request to hub.fetch to avoid losing WebSocket upgrade metadata (which could trigger 500s in Durable Objects). These changes ensure the editor's size checks and WebSocket upgrades remain reliable.

* fix x524234

* shirt thing?

* [auth] remove grant table as we already have audit_log for now

* rename table to generic device_grant

* cleanup/lint

---------

Co-authored-by: Devin Zuczek <devin.zuczek@gmail.com>
This commit is contained in:
Crasho
2026-10-05 19:39:22 +01:00
committed by GitHub
parent 0900bcac25
commit 26270e9c25
52 changed files with 18231 additions and 103 deletions
+23 -10
View File
@@ -5,16 +5,19 @@ authenticates players and issues the JWTs every other worker verifies.
## Routes
| Method | Path | Description |
| ------ | ------------------------------------------ | ------------------------------------------------------ |
| GET | `/eac/challenge` | EAC handshake; a constant, JSON-quoted, as text |
| GET | `/cachedlogin/forplatformid/:platform/:id` | Accounts linked to a platform id, for the login screen |
| POST | `/cachedlogin/forplatformids` | Bulk cached-login lookup (friends resolution) |
| POST | `/connect/token` | OAuth token endpoint; issues a JWT + refresh token |
| POST | `/account/me/changepassword` | Change the caller's password (auth-gated) |
| GET | `/role/developer/:id` | Developer role lookup; a bare JSON boolean |
| GET | `/role/moderator/:id` | Moderator role lookup; a bare JSON boolean |
| GET | `/openapi.json` | Generated OpenAPI 3.1 spec (see below) |
| Method | Path | Description |
| ------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| GET | `/eac/challenge` | EAC handshake; a constant, JSON-quoted, as text |
| GET | `/cachedlogin/forplatformid/:platform/:id` | Accounts linked to a platform id, for the login screen |
| POST | `/cachedlogin/forplatformids` | Bulk cached-login lookup (friends resolution) |
| POST | `/connect/deviceauthorization` | Studio device login: mint a user code and point the browser at WWW `/device` |
| POST | `/connect/device/approve` | Website approves that code for the signed-in account |
| POST | `/connect/device/deny` | Website refuses it |
| POST | `/connect/token` | OAuth token endpoint; issues a JWT + refresh token. Studio polls this with the device-code grant |
| POST | `/account/me/changepassword` | Change the caller's password (auth-gated) |
| GET | `/role/developer/:id` | Developer role lookup; a bare JSON boolean |
| GET | `/role/moderator/:id` | Moderator role lookup; a bare JSON boolean |
| GET | `/openapi.json` | Generated OpenAPI 3.1 spec (see below) |
## API documentation
@@ -45,6 +48,10 @@ route without documenting it fails rather than silently shipping an incomplete s
identity `platform_auth` proves.
- **`refresh_token`** — redeems a stored single-use refresh token, rotating it.
30-day TTL; platform and platform id come from what was stored at issue time.
- **`urn:ietf:params:oauth:grant-type:device_code`** — Rec Room Studio polling a
code from `POST /connect/deviceauthorization`. While the player has not approved
it on the website, the response is HTTP 400 `authorization_pending`. Studio
treats `expires_in` on the token as seconds.
- **`password`** — the fallback for any unrecognised or absent `grant_type`. Identifies
the account by `username` or numeric `account_id` and requires the matching password
(PBKDF2-SHA256, `salt:hash`). An account with no stored hash cannot be logged into at
@@ -55,6 +62,12 @@ Access tokens live for 1 hour (`TOKEN_TTL_SECONDS` in `@repo/jwt`) and carry a `
claim, so developer/moderator powers refresh on every login and every refresh grant.
Grant those flags with `runx admin grant-developer` / `grant-moderator`.
`betastudio` is a separate claim. RecFlare Studio treats it as permission to upload,
and developer does not include it. It is stamped from the account's `hasStudio` flag.
Staff add and remove people at `/settings/recroomstudio` on the website (or
`runx admin grant-studio`). A player already signed into Studio keeps the old token
until the next sign-in or refresh.
### Verifiable platforms: Steam and Meta
Only an identity we can _prove_ is ever bound to an account, so any grant that