tests/integration/login-races.test.ts
Rama main · réplica de lectura del repositorio original.
import { test } from "bun:test";
import assert from "node:assert/strict";
import { newOperatorAccount } from "../../src/core/accounts";
import { createApp } from "../../src/core/app";
import { organizationStatement } from "../../src/core/auth";
import type { Db, Param } from "../../src/core/db";
import { migrate } from "../../src/core/migrations";
import { recoverHostAccount } from "../../src/runtime/bun/accounts";
import { createSqliteDb, openDatabase } from "../../src/runtime/bun/sqlite";
async function setup(db: Db, now: Date) {
await migrate(db);
const account = await newOperatorAccount({
orgId: "org_login_race",
username: "login-race-owner",
createdBy: "race-test-owner",
role: "owner",
scopes: ["*"],
maxTrust: "asserted",
now,
});
await db.batch([
organizationStatement("org_login_race", "Login race test", now),
...account.statements,
{ sql: "UPDATE operator_accounts SET must_change_password = 0 WHERE id = ?", params: [account.accountId] },
]);
return account;
}
function loginRequest(password: string) {
return new Request("http://titen.test/v1/dashboard-sessions", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ username: "login-race-owner", password }),
});
}
test("a host reset rejects a password check that read the previous verifier", async () => {
const handle = openDatabase(":memory:");
const db = createSqliteDb(handle);
try {
const now = new Date("2026-10-05T00:00:00.000Z");
const account = await setup(db, now);
let resetOccurred = false;
const racedDb: Db = {
...db,
async all<Row>(sql: string, params?: Param[]) {
const rows = await db.all<Row>(sql, params);
if (!resetOccurred && sql.includes("AS webauthn_credentials")) {
resetOccurred = true;
await recoverHostAccount(db, account.username, true);
}
return rows;
},
};
const app = createApp({ db: racedDb, runtime: "test", now: () => now });
const response = await app(loginRequest(account.temporaryPassword));
assert.equal(resetOccurred, true);
assert.equal(response.status, 401, "the previous password must not issue a session after reset");
const active = await db.all<{ count: number }>(
"SELECT COUNT(*) AS count FROM api_keys WHERE label = 'Dashboard session' AND revoked_at IS NULL",
);
assert.equal(active[0]!.count, 0);
const current = await db.all<{ must_change_password: number }>(
"SELECT must_change_password FROM operator_accounts WHERE id = ?", [account.accountId],
);
assert.equal(current[0]!.must_change_password, 1);
} finally { handle.close(); }
});
test("concurrent failures write one audit for the active client block", async () => {
const handle = openDatabase(":memory:");
const db = createSqliteDb(handle);
try {
const now = new Date("2026-10-05T00:00:00.000Z");
await setup(db, now);
const app = createApp({ db, runtime: "test", now: () => now });
const attempt = () => app(loginRequest("incorrect horse battery staple"));
for (let i = 0; i < 4; i++) assert.equal((await attempt()).status, 401);
const responses = await Promise.all(Array.from({ length: 4 }, attempt));
assert.deepEqual(responses.map((response) => response.status), [401, 401, 401, 401]);
const audits = await db.all<{ detail: string }>(
"SELECT detail FROM audit_log WHERE org_id = ? AND action = 'operator_account.login_block'",
["org_login_race"],
);
assert.equal(audits.length, 1, "an active client block has only one transition audit");
assert.equal(JSON.parse(audits[0]!.detail).failed_attempts, 5);
const blocked = await db.all<{ blocked_until_ms: number }>(
"SELECT blocked_until_ms FROM login_throttles WHERE identity_hash LIKE '%.%'",
);
assert.equal(blocked[0]!.blocked_until_ms, now.getTime() + 30_000);
} finally { handle.close(); }
});
test("a host reset prevents a revoked session from completing password replacement", async () => {
const handle = openDatabase(":memory:");
const db = createSqliteDb(handle);
try {
const now = new Date("2026-10-05T00:00:00Z");
const account = await setup(db, now);
const app = createApp({ db, runtime: "test", now: () => now });
const login = await app(loginRequest(account.temporaryPassword));
const key = (await login.json() as any).data.api_key;
let resetOccurred = false;
const racedDb: Db = { ...db, async all<Row>(sql: string, params?: Param[]) {
const rows = await db.all<Row>(sql, params);
if (!resetOccurred && sql.includes("SELECT id, username, password_verifier")) {
resetOccurred = true;
await recoverHostAccount(db, account.username, true);
}
return rows;
} };
const racedApp = createApp({ db: racedDb, runtime: "test", now: () => now });
const result = await racedApp(new Request("http://titen.test/v1/operator-accounts/current/password", {
method: "PATCH", headers: { authorization: `Bearer ${key}` },
body: JSON.stringify({ password: "a revoked session replacement passphrase" }),
}));
assert.equal(resetOccurred, true);
assert.equal(result.status, 401);
const accountState = await db.all<{ must_change_password: number }>("SELECT must_change_password FROM operator_accounts WHERE id = ?", [account.accountId]);
assert.equal(accountState[0]!.must_change_password, 1);
} finally { handle.close(); }
});