mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
Renumber the elevation migration from 0260 to 0267 — main claimed 0260 for an unrelated table while this branch sat unmerged, and 0266 is now the highest committed number. Two loose ends the merge itself did not touch: the schema comment on StepUpElevation.method still called it "audit/telemetry only, never an authorisation input" — the exact claim the fresh-factor fix (a prior commit on this branch) made false, since the method is now precisely what decides whether an elevation reaches the destructive MFA routes. Reworded to match. And pruneExpiredStepUpElevations in step-up.ts was dead code: the actual sweep runs in cleanup-handlers.ts against the worker Prisma client for reasons that function could never satisfy against the request-scoped one. Removed rather than left to drift.
41 lines
2.0 KiB
SQL
41 lines
2.0 KiB
SQL
-- v1.30.34 — token-bound step-up elevations.
|
|
--
|
|
-- The Bearer-transport equivalent of `sessions.mfa_verified_at`. A row is
|
|
-- minted only after a password or primary-passkey re-proof, is bound to the
|
|
-- exact API token that re-proved, is single-use (`consumed_at`), and expires
|
|
-- within minutes. Only the HMAC of the opaque secret is stored.
|
|
|
|
CREATE TABLE "step_up_elevations" (
|
|
"id" TEXT NOT NULL,
|
|
"user_id" TEXT NOT NULL,
|
|
"api_token_id" TEXT NOT NULL,
|
|
"token_hash" TEXT NOT NULL,
|
|
"method" TEXT NOT NULL,
|
|
"expires_at" TIMESTAMP(3) NOT NULL,
|
|
"consumed_at" TIMESTAMP(3),
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "step_up_elevations_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE UNIQUE INDEX "step_up_elevations_token_hash_key" ON "step_up_elevations"("token_hash");
|
|
|
|
-- At most ONE redeemable elevation per token, enforced by the database rather
|
|
-- than by the mint's delete-then-create ordering. Without it two concurrent
|
|
-- mints can interleave so that both rows survive, or the second mint's delete
|
|
-- strands the value the first mint already handed to the client.
|
|
CREATE UNIQUE INDEX "step_up_elevations_live_per_token_key"
|
|
ON "step_up_elevations"("api_token_id") WHERE "consumed_at" IS NULL;
|
|
|
|
CREATE INDEX "step_up_elevations_user_id_idx" ON "step_up_elevations"("user_id");
|
|
CREATE INDEX "step_up_elevations_api_token_id_idx" ON "step_up_elevations"("api_token_id");
|
|
CREATE INDEX "step_up_elevations_expires_at_idx" ON "step_up_elevations"("expires_at");
|
|
|
|
ALTER TABLE "step_up_elevations" ADD CONSTRAINT "step_up_elevations_user_id_fkey"
|
|
FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- Cascade on the token binding: revoking or deleting a token must never leave a
|
|
-- redeemable elevation behind.
|
|
ALTER TABLE "step_up_elevations" ADD CONSTRAINT "step_up_elevations_api_token_id_fkey"
|
|
FOREIGN KEY ("api_token_id") REFERENCES "api_tokens"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|