fix(auth): isolate bounded OIDC cleanup

This commit is contained in:
2026-08-17 07:46:43 +02:00
parent bdabecbb63
commit 3e7bb11313
8 changed files with 456 additions and 177 deletions
+21 -4
View File
@@ -8,7 +8,8 @@ const MAX_PROTOCOL_BYTES = 64 * 1024;
const MAX_RESPONSE_BYTES = 64 * 1024;
const MAX_SESSION_BYTES = 16 * 1024;
const MAX_OIDC_BYTES = 8 * 1024;
const MAX_ENTRIES = 256;
const DEFAULT_MAX_ENTRIES = 256;
const MAX_ENTRIES = 512;
const TIMEOUT_MS = 5_000;
const DIGEST_FILENAME = /^[a-f0-9]{64}\.json$/;
const CLAIM_FILENAME = /^[a-f0-9]{64}\.claim$/;
@@ -29,7 +30,11 @@ export interface WindowsAuthStorageBridge {
read(root: string, directory: WindowsAuthStorageDirectory, filename: string): Promise<Buffer | undefined>;
replace(root: string, directory: WindowsAuthStorageDirectory, filename: string, contents: Buffer): Promise<void>;
remove(root: string, directory: WindowsAuthStorageDirectory, filename: string): Promise<boolean>;
list(root: string, directory: WindowsAuthStorageDirectory): Promise<WindowsAuthStorageEntry[]>;
list(
root: string,
directory: WindowsAuthStorageDirectory,
maximumEntries?: number,
): Promise<WindowsAuthStorageEntry[]>;
claimConsume(root: string, filename: string): Promise<Buffer | undefined>;
readClaim(root: string, filename: string): Promise<Buffer | undefined>;
removeClaim(root: string, filename: string): Promise<boolean>;
@@ -98,6 +103,7 @@ interface BridgeRequest {
directory: WindowsAuthStorageDirectory;
filename?: string;
contentBase64?: string;
maximumEntries?: number;
}
function directoryMaximum(directory: WindowsAuthStorageDirectory): number {
@@ -151,7 +157,10 @@ function encodedRequest(request: BridgeRequest): Buffer {
validateRoot(request.root);
if (request.operation === "list") {
if (request.filename !== undefined || request.contentBase64 !== undefined) throw invalid();
if (request.maximumEntries !== undefined && (!Number.isInteger(request.maximumEntries)
|| request.maximumEntries < 1 || request.maximumEntries > MAX_ENTRIES)) throw invalid();
} else {
if (request.maximumEntries !== undefined) throw invalid();
if (request.filename === undefined) throw invalid();
const allowClaim = request.operation === "remove" && request.directory === "oidc";
const allowOidcSlot = request.directory === "oidc"
@@ -350,9 +359,17 @@ export function createWindowsAuthStorageBridge(options: WindowsAuthStorageBridge
const response = await request(recordRequest("remove", root, directory, filename));
return response.removed === true;
},
async list(root, directory) {
const response = await request({ version: PROTOCOL_VERSION, operation: "list", root, directory });
async list(root, directory, maximumEntries = DEFAULT_MAX_ENTRIES) {
if (!Number.isInteger(maximumEntries) || maximumEntries < 1 || maximumEntries > MAX_ENTRIES) throw invalid();
const response = await request({
version: PROTOCOL_VERSION,
operation: "list",
root,
directory,
maximumEntries,
});
if (response.entries === undefined) throw invalid();
if (response.entries.length > maximumEntries) throw invalid();
for (const entry of response.entries) {
if (!DIGEST_FILENAME.test(entry.name) && !(directory === "oidc"
&& (CLAIM_FILENAME.test(entry.name) || OIDC_SLOT_FILENAME.test(entry.name)))) throw invalid();