Skip to content

Commit 0c44ae9

Browse files
committed
The right Core key always signs in; the audit actor is caller-declared
1 parent 76ba4bc commit 0c44ae9

4 files changed

Lines changed: 9 additions & 5 deletions

File tree

‎apps/web/e2e/access.spec.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ test("signs in with the Core key, keeps it out of the browser, and signs out and
3232
await page.getByRole("button", { name: "Sign out" }).click();
3333
for (let attempt = 0; attempt < 3; attempt++) await signIn(page, "not-the-core-key");
3434
await expect(page.getByRole("alert")).toHaveText("Too many attempts. Try again in 30 seconds.");
35+
// Failed attempts never lock out the right key.
36+
await signIn(page, FIXTURE_CORE_KEY);
37+
await expect(page.getByRole("heading", { name: "Overview", level: 1 })).toBeVisible();
3538
expect(await browserStorage(page)).not.toContain(FIXTURE_CORE_KEY);
3639
});
3740

‎apps/web/e2e/fixture-console.mjs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,17 @@ function authError(response, status, message, headers = {}) {
8484
send(response, status, { error: message }, headers);
8585
}
8686

87-
/** Sign-in with the Core key: a wrong key is refused, and repeated wrong keys lock sign-in for a while. */
87+
/** Sign-in with the Core key, as the console server does it: the key is compared first, so the right key
88+
* always signs in; only wrong keys count, and repeated wrong keys are refused for a while. */
8889
async function login(request, response) {
8990
const auth = state.auth;
9091
if (!request.headers["content-type"]?.startsWith("application/json")) return authError(response, 415, "Use application/json");
9192
let input;
9293
try { input = await body(request); } catch { return authError(response, 400, "Invalid authentication request"); }
9394
if (typeof input?.core_key !== "string" || !input.core_key) return authError(response, 400, "Invalid authentication request");
94-
const wait = Math.ceil((auth.lockedUntil - Date.now()) / 1000);
95-
if (wait > 0) return authError(response, 429, "Too many authentication attempts", { "retry-after": String(wait) });
9695
if (input.core_key !== CORE_KEY) {
96+
const wait = Math.ceil((auth.lockedUntil - Date.now()) / 1000);
97+
if (wait > 0) return authError(response, 429, "Too many authentication attempts", { "retry-after": String(wait) });
9798
auth.failures += 1;
9899
if (auth.failures < LOCKOUT_AFTER) return authError(response, 401, "Invalid Core key");
99100
auth.lockedUntil = Date.now() + LOCKOUT_SECONDS * 1000;

‎docs/web/architecture.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The console authenticates the browser, checks the request origin and forwards on
3535
allowed management routes. It replaces browser authorization and actor headers,
3636
strips browser cookies, and supplies its server-side deployment credential. Core
3737
rejects application keys on management routes and deployment credentials on `/v1`.
38-
The forwarded audit actor label is always `console` for console operations (operator scripts calling Core with the Core key directly leave it empty); it is display only, not Core authorization.
38+
The audit actor label is declared by the caller and is display only, never Core authorization: the console server declares `console`, and operator scripts calling Core with the Core key directly leave it empty.
3939

4040
Node and daemon connections use `/api/v1` with their own credentials. The reverse
4141
proxy sends them directly to Core; the console never forwards them, and they do not

‎docs/web/core-connection.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ configuration to an authenticated browser.
4949
Use TLS for remote browser access and loopback listeners for local development.
5050
Preserve host/origin checks and the management route allowlist. Browser authorization,
5151
cookies and actor headers are replaced or removed before forwarding to Core.
52-
A browser cannot choose the audit actor label the service reports: console operations always show as `console`. Keep deployment, application, node and provider credentials
52+
A browser cannot choose the audit actor label the service reports: the console server declares `console`. The label is caller-declared and display only. Keep deployment, application, node and provider credentials
5353
out of `VITE_*`, browser storage, source files, URLs and logs.
5454

5555
## Projects and application keys

0 commit comments

Comments
 (0)