temporarily allow any origin on /api/music

Off unless ALLOW_ANY_ORIGIN_MUSIC=true, so it is opt-in per host and reverting is an env
edit rather than a deploy. Set on this host now; the flag and the two call sites come out
when the tailnet becomes the perimeter and the music app stops needing to be public.

It drops one layer, not the lock: /api/music still requires a valid token through
userMiddleware, and the non-owner account backstop in originScopeMiddleware still confines
music accounts to /api/auth + /api/music whatever Origin they claim. Worth being plain
about what is lost — Origin was never authentication here. `officer://<hex>` is chosen by
the client, trivially forged outside a browser, and extractable from any shipped app
binary. It is defence in depth, and this removes it for one path prefix.

Two gates had to know: userMiddleware, which is what actually 403s, and the CORS origin
callback, which would otherwise echo an empty origin and block a browser client that
userMiddleware had already allowed through.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-30 10:49:14 +00:00
co-authored by Claude Opus 5
parent 1e6b01cd21
commit 418729a470
3 changed files with 23 additions and 3 deletions
+7 -3
View File
@@ -1,7 +1,7 @@
import type { MiddlewareHandler } from 'hono';
import { verify } from '@@/jwt';
import * as errors from '@@/custom-errors';
import { isOriginAllowed } from './origin-validation';
import { isOriginAllowed, isMusicOriginExempt } from './origin-validation';
import { isLockdown, noteBlocked } from '../api/auth/panic';
import { getUserById, isTokenBlacklisted } from 'officerdb';
@@ -24,10 +24,14 @@ export const userMiddleware: MiddlewareHandler = async function (ctx, next) {
}
if (!token) throw errors.UNAUTHORIZED();
// Validate origin for authenticated routes
// Validate origin for authenticated routes.
// TEMPORARY, opt-in: ALLOW_ANY_ORIGIN_MUSIC=true drops the Origin check for /api/music only, so a
// client that can't present the app's custom-scheme origin can still reach the music API. Auth is
// untouched — a valid token is still required, and the non-owner account backstop in
// originScopeMiddleware still applies. Delete this and the env var once the tailnet is the perimeter.
const origin = ctx.get('origin') as string | undefined;
const host = ctx.req.header('host');
if (!isOriginAllowed(origin, host)) {
if (!isMusicOriginExempt(ctx.req.path) && !isOriginAllowed(origin, host)) {
throw errors.FORBIDDEN('Invalid origin');
}