fix(auth): bind current local registry and CORS

This commit is contained in:
2026-08-17 00:34:58 +02:00
parent c34e01e9b9
commit 94c2cd3709
15 changed files with 514 additions and 87 deletions
+24 -4
View File
@@ -81,13 +81,26 @@ export interface LocalSessionUser {
roles: readonly Role[];
}
export interface CurrentLocalSessionUser {
revision: string;
user: LocalSessionUser | undefined;
}
/** Operational validity-source failures must not masquerade as revoked credentials. */
export class AuthSessionOperationalError extends Error {
constructor() {
super("auth_session_operational_error");
}
}
/**
* The route layer supplies the current installation revision and local-registry lookup.
* Supplying this hook makes every resolve an authorization-generation check.
*/
export interface AuthSessionValidity {
currentAuthConfigRevision(): string | Promise<string>;
findLocalUser(subject: string): LocalSessionUser | undefined | Promise<LocalSessionUser | undefined>;
findLocalUser?(subject: string): LocalSessionUser | undefined | Promise<LocalSessionUser | undefined>;
currentLocalUser?(subject: string): CurrentLocalSessionUser | Promise<CurrentLocalSessionUser>;
}
export interface AuthSessionStore {
@@ -682,10 +695,15 @@ async function recordIsCurrent(record: AuthSessionRecord, validity: AuthSessionV
// A root-only store remains useful for creation/diagnostics, but is intentionally incapable
// of authenticating a principal. Task 8 must supply config and local-registry dependencies.
if (!validity) return false;
if (record.method === "local" && validity.currentLocalUser) {
const current = await validity.currentLocalUser(record.subject);
return typeof current.revision === "string" && current.revision === record.authConfigRevision
&& validLocalUser(current.user, record);
}
const revision = await validity.currentAuthConfigRevision();
if (typeof revision !== "string" || revision !== record.authConfigRevision) return false;
if (record.method !== "local") return true;
return validLocalUser(await validity.findLocalUser(record.subject), record);
return validity.findLocalUser === undefined ? false : validLocalUser(await validity.findLocalUser(record.subject), record);
}
const locks = new Map<string, Promise<void>>();
@@ -799,7 +817,8 @@ export function createFileAuthSessionStore(
}
try {
if (await recordIsCurrent(record, validity)) return record;
} catch {
} catch (error) {
if (error instanceof AuthSessionOperationalError) throw error;
await bridge.remove(root, "sessions", filename);
throw invalid();
}
@@ -815,7 +834,8 @@ export function createFileAuthSessionStore(
}
try {
if (await recordIsCurrent(trusted.value, validity)) return trusted.value;
} catch {
} catch (error) {
if (error instanceof AuthSessionOperationalError) throw error;
removeTrusted(directories.sessions, filename, trusted.identity);
throw invalid();
}