remove origin validation
ALLOW_ANY_ORIGIN, ALLOW_ANY_ORIGIN_MUSIC, and everything they gated. The flag defaulted to ON, so none of it ran on a real install — what comes out is documented defence in depth that was already switched off. The file said so itself: "Both flags and their call sites come out once the tailnet is the perimeter." Origin was never authentication here in any case. An app's `officer://<hex>` origin is chosen by the client, forgeable outside a browser, and extractable from a shipped binary. Gone: the two flags, isOriginAllowed, isOriginCheckDisabled, isMusicOriginExempt, originValidationMiddleware, ORIGIN_RULES and the whole OFFICER_<APP>_ORIGIN scheme, PUBLIC_URL's origin/host derivation, and origin-validation.test.ts, which existed only to pin them. CORS now echoes whatever Origin it is given, which is what every install already did. What SURVIVES is the reason this needed care. origin-validation.ts held two unrelated things, and the second was the global authorization gate — a valid non-owner token reaches only what its role grants, deliberately NOT under the flag because it is account-based rather than origin-based. Its own comment called it "the airtight half". Deleting the file wholesale would have deleted authorization. So it moves to _middlewares/capability-gate.ts as capabilityGateMiddleware, with the name matching what it does: nothing in it reads an Origin header any more. hono.ts mounts it in the same position, ahead of every router. origin-middleware.ts stays and is untouched — it extracts the Origin for six auth handlers that log it, and for passkeys. Extraction, not validation. Also updates every claim that rested on the old model: CLAUDE.md's security section and repo map, docs/secret-store.md, docs/mobile-api-keys.md, and five messages in machine-setup's Tailscale section which told the owner to set ALLOW_ANY_ORIGIN=false when declining a tailnet. That advice is now impossible to follow, and the honest version is different: with no tailnet the token is the whole lock, so put a proxy in front and restrict who can reach it. Not typechecked (empty node_modules, frozen installs). Every changed file parses; the setup section was run and writes four variables now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,6 @@ import { createRouter } from '../../create-router';
|
||||
import {
|
||||
authAudit,
|
||||
originMiddleware,
|
||||
originValidationMiddleware,
|
||||
userMiddleware,
|
||||
bodyParser,
|
||||
signinRateLimiter,
|
||||
@@ -25,10 +24,11 @@ export const authRouter = createRouter();
|
||||
|
||||
authRouter.use(bodyParser());
|
||||
// After the body parser (it reads the claimed identity out of the body) and before everything else, so
|
||||
// that a probe rejected by origin validation or the rate limiter is recorded too. Observes only.
|
||||
// that a probe rejected by the rate limiter is recorded too. Observes only.
|
||||
authRouter.use(authAudit);
|
||||
// Extracts the Origin (or derives it from Referer) for the handlers that log it. Not a check — origin
|
||||
// validation was removed on 2026-08-13.
|
||||
authRouter.use(originMiddleware);
|
||||
authRouter.use(originValidationMiddleware);
|
||||
|
||||
authRouter.use('/', async (ctx) => ctx.json({ officerAuthServer: 'ok' }));
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ const TEST_USERS: number[] = [];
|
||||
export const signinHandler: Handler = async function (ctx) {
|
||||
const { email, password } = ctx.get('body');
|
||||
// A caller that sends neither Origin nor Referer — a server-to-server client, curl — leaves this
|
||||
// undefined. It used to be unreachable: originValidationMiddleware rejected those requests before this
|
||||
// handler ran, so the value was always a string by the time anything touched it. That is no longer
|
||||
// guaranteed (ALLOW_ANY_ORIGIN lets them through), and `undefined` reached both a SQL parameter and
|
||||
// `.startsWith`. Normalising to '' keeps every downstream use honest: no passkey is registered against
|
||||
// the empty origin, so an origin-less caller falls through to password auth, which is what it wants.
|
||||
// undefined. It was once unreachable: origin validation rejected those requests before this handler
|
||||
// ran, so the value was always a string by the time anything touched it. Then the flag that disabled
|
||||
// that check defaulted to on, and `undefined` reached both a SQL parameter and `.startsWith`. Origin
|
||||
// validation is gone entirely as of 2026-08-13, so undefined is now the ordinary case rather than the
|
||||
// edge one. Normalising to '' keeps every downstream use honest: no passkey is registered against the
|
||||
// empty origin, so an origin-less caller falls through to password auth, which is what it wants.
|
||||
const origin = (ctx.get('origin') as string | undefined) ?? '';
|
||||
|
||||
// Panic lockdown active → refuse all logins (looks like a normal failed login).
|
||||
|
||||
Reference in New Issue
Block a user