From b96b23d92bdd69df06e1d244a6ed73afe7b6764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 23 Jul 2026 00:22:48 +0000 Subject: [PATCH] auth: add POST /auth/lockdown to trigger the distress lockdown exposes the duress lockdown as an endpoint (needs the distress password in the body, rate-limited) so it can be tripped from a shortcut/webhook, not only by typing the distress password at the login form. Co-Authored-By: Claude Opus 4.8 --- src/servers/api/auth/auth.ts | 3 +++ src/servers/api/auth/lockdown.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/servers/api/auth/lockdown.ts diff --git a/src/servers/api/auth/auth.ts b/src/servers/api/auth/auth.ts index a70cefd3..4e9c651b 100644 --- a/src/servers/api/auth/auth.ts +++ b/src/servers/api/auth/auth.ts @@ -19,6 +19,7 @@ import { forgotPasswordHandler } from './forgot-password'; import { resetPasswordHandler } from './reset-password'; import { bootstrapHandler } from './bootstrap'; import { usersMe } from './users-me'; +import { lockdownHandler } from './lockdown'; import { passkeyRouter } from './passkey-router'; export const authRouter = createRouter(); @@ -34,6 +35,8 @@ authRouter.post('/signin', signinRateLimiter, signinHandler); authRouter.post('/signout', userMiddleware, signoutHandler); // Explicit "revoke the current token" alias (same effect as signout: blacklists this JWT). authRouter.post('/blacklist-token', userMiddleware, signoutHandler); +// Trigger the duress lockdown programmatically (needs the distress password in the body). +authRouter.post('/lockdown', signinRateLimiter, lockdownHandler); authRouter.post('/signup', signupRateLimiter, signupHandler); authRouter.post('/bootstrap', signupRateLimiter, bootstrapHandler); authRouter.post('/verify', verifyHandler); diff --git a/src/servers/api/auth/lockdown.ts b/src/servers/api/auth/lockdown.ts new file mode 100644 index 00000000..475ef3db --- /dev/null +++ b/src/servers/api/auth/lockdown.ts @@ -0,0 +1,15 @@ +import type { Handler } from 'hono'; +import * as errors from '@@/custom-errors'; +import { triggerLockdown } from './distress'; + +const { DISTRESS_PASSWORD } = process.env; + +// Trigger the duress lockdown programmatically — same effect as entering the distress password at +// login. Requires the distress password in the body so only its holder can trip it (rate-limited at +// the route). Once tripped, all logins and existing sessions are refused until the server restarts. +export const lockdownHandler: Handler = async (ctx) => { + const { password } = ctx.get('body') as { password?: string }; + if (!DISTRESS_PASSWORD || password !== DISTRESS_PASSWORD) throw errors.UNAUTHORIZED(); + triggerLockdown(); + return ctx.json({ ok: true }); +};