From e1c1d182e44abf4952e9a6c57628a8d116e7baef Mon Sep 17 00:00:00 2001 From: Babayaga Date: Sat, 21 Feb 2026 00:11:17 +0100 Subject: [PATCH] acl ole :) --- packages/acl/dist-in/index.d.ts | 2 +- packages/acl/dist-in/index.js | 4 +- packages/acl/dist-in/vfs/AclVfsClient.d.ts | 2 +- packages/acl/dist-in/vfs/AclVfsClient.js | 21 ++++- packages/acl/dist-in/vfs/sanitizers.d.ts | 11 ++- packages/acl/dist-in/vfs/sanitizers.js | 21 ++++- packages/acl/dist-in/vfs/vfs-acl.js | 2 +- packages/acl/src/index.ts | 2 + packages/acl/src/vfs/AclVfsClient.ts | 19 ++++- packages/acl/src/vfs/sanitizers.ts | 20 ++++- packages/acl/src/vfs/vfs-acl.ts | 2 +- .../acl/tests/vfs-acl-anonymous.e2e.test.ts | 78 +++++++++++++++++++ .../vfs/root/anon-test/vfs-settings.json | 21 +++++ 13 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 packages/acl/tests/vfs-acl-anonymous.e2e.test.ts create mode 100644 packages/acl/tests/vfs/root/anon-test/vfs-settings.json diff --git a/packages/acl/dist-in/index.d.ts b/packages/acl/dist-in/index.d.ts index 6cb72396..e53ced43 100644 --- a/packages/acl/dist-in/index.d.ts +++ b/packages/acl/dist-in/index.d.ts @@ -11,4 +11,4 @@ export { DecoratedVfsClient } from './vfs/DecoratedVfsClient.js'; export { loadVfsSettings, vfsResource, resourceChain } from './vfs/vfs-acl.js'; export type { VfsSettings, VfsAclEntry, VfsGroup } from './vfs/vfs-acl.js'; export { DefaultSanitizers } from './vfs/sanitizers.js'; -export { assertNonEmpty, cleanPath, pathSegments, normalisePath, cleanPermission, cleanPermissions, isUuid, cleanUuid, cleanId, cleanGroupName, sanitizeSubpath, sanitizeWritePath, sanitizeFilename, } from './vfs/sanitizers.js'; +export { assertNonEmpty, cleanPath, pathSegments, normalisePath, cleanPermission, cleanPermissions, isUuid, cleanUuid, cleanId, cleanGroupName, sanitizeSubpath, sanitizeWritePath, sanitizeFilename, ANONYMOUS_USER_ID, AUTHENTICATED_USER_ID, } from './vfs/sanitizers.js'; diff --git a/packages/acl/dist-in/index.js b/packages/acl/dist-in/index.js index 06a0d8da..cc113248 100644 --- a/packages/acl/dist-in/index.js +++ b/packages/acl/dist-in/index.js @@ -10,5 +10,5 @@ export { AclVfsClient } from './vfs/AclVfsClient.js'; export { DecoratedVfsClient } from './vfs/DecoratedVfsClient.js'; export { loadVfsSettings, vfsResource, resourceChain } from './vfs/vfs-acl.js'; export { DefaultSanitizers } from './vfs/sanitizers.js'; -export { assertNonEmpty, cleanPath, pathSegments, normalisePath, cleanPermission, cleanPermissions, isUuid, cleanUuid, cleanId, cleanGroupName, sanitizeSubpath, sanitizeWritePath, sanitizeFilename, } from './vfs/sanitizers.js'; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFDSCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFnQnBELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWxELE1BQU07QUFDTixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFL0UsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUNILGNBQWMsRUFDZCxTQUFTLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFDdEMsZUFBZSxFQUFFLGdCQUFnQixFQUNqQyxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQzFDLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsR0FDdkQsTUFBTSxxQkFBcUIsQ0FBQyJ9 \ No newline at end of file +export { assertNonEmpty, cleanPath, pathSegments, normalisePath, cleanPermission, cleanPermissions, isUuid, cleanUuid, cleanId, cleanGroupName, sanitizeSubpath, sanitizeWritePath, sanitizeFilename, ANONYMOUS_USER_ID, AUTHENTICATED_USER_ID, } from './vfs/sanitizers.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFDSCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFnQnBELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWxELE1BQU07QUFDTixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFL0UsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUNILGNBQWMsRUFDZCxTQUFTLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFDdEMsZUFBZSxFQUFFLGdCQUFnQixFQUNqQyxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQzFDLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFDcEQsaUJBQWlCLEVBQ2pCLHFCQUFxQixHQUN4QixNQUFNLHFCQUFxQixDQUFDIn0= \ No newline at end of file diff --git a/packages/acl/dist-in/vfs/AclVfsClient.d.ts b/packages/acl/dist-in/vfs/AclVfsClient.d.ts index 575aee3d..66a49eca 100644 --- a/packages/acl/dist-in/vfs/AclVfsClient.d.ts +++ b/packages/acl/dist-in/vfs/AclVfsClient.d.ts @@ -25,7 +25,7 @@ export declare class AclVfsClient { /** * @param acl Populated Acl instance (call `loadVfsSettings` first) * @param ownerId UUID of the folder owner - * @param callerId UUID of the user performing the operation + * @param callerId UUID of the user performing the operation, or 'anonymous' * @param fsOpts LocalVFS options (must include `root`) */ constructor(acl: Acl, ownerId: string, callerId: string, fsOpts: IDefaultParameters); diff --git a/packages/acl/dist-in/vfs/AclVfsClient.js b/packages/acl/dist-in/vfs/AclVfsClient.js index be6aeac1..173b2ab8 100644 --- a/packages/acl/dist-in/vfs/AclVfsClient.js +++ b/packages/acl/dist-in/vfs/AclVfsClient.js @@ -12,12 +12,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function ( var _AclVfsClient_instances, _AclVfsClient_acl, _AclVfsClient_local, _AclVfsClient_ownerId, _AclVfsClient_callerId, _AclVfsClient_guard; import { LocalVFS } from './fs/Local.js'; import { resourceChain } from './vfs-acl.js'; -import { cleanUuid, sanitizeSubpath } from './sanitizers.js'; +import { cleanUuid, cleanId, sanitizeSubpath, ANONYMOUS_USER_ID, AUTHENTICATED_USER_ID } from './sanitizers.js'; export class AclVfsClient { /** * @param acl Populated Acl instance (call `loadVfsSettings` first) * @param ownerId UUID of the folder owner - * @param callerId UUID of the user performing the operation + * @param callerId UUID of the user performing the operation, or 'anonymous' * @param fsOpts LocalVFS options (must include `root`) */ constructor(acl, ownerId, callerId, fsOpts) { @@ -29,7 +29,7 @@ export class AclVfsClient { __classPrivateFieldSet(this, _AclVfsClient_acl, acl, "f"); __classPrivateFieldSet(this, _AclVfsClient_local, new LocalVFS(fsOpts), "f"); __classPrivateFieldSet(this, _AclVfsClient_ownerId, cleanUuid(ownerId), "f"); - __classPrivateFieldSet(this, _AclVfsClient_callerId, cleanUuid(callerId), "f"); + __classPrivateFieldSet(this, _AclVfsClient_callerId, cleanId(callerId), "f"); } // ── Read operations ───────────────────────────────────────────── async stat(path) { @@ -86,17 +86,30 @@ _AclVfsClient_acl = new WeakMap(), _AclVfsClient_local = new WeakMap(), _AclVfsC * Walk the resource chain from most-specific path to root. * If ANY level grants the permission, access is allowed. * This means a grant on `/` covers the entire tree. + * + * For non-anonymous callers, also checks grants given to the + * `'authenticated'` sentinel, so a single grant can cover all + * logged-in users. */ async function _AclVfsClient_guard(permission, path) { const safePath = sanitizeSubpath(path); const chain = resourceChain(__classPrivateFieldGet(this, _AclVfsClient_ownerId, "f"), safePath); + // 1. Check caller-specific grants for (const resource of chain) { const result = await __classPrivateFieldGet(this, _AclVfsClient_acl, "f").isAllowed(__classPrivateFieldGet(this, _AclVfsClient_callerId, "f"), resource, permission); if (result.ok && result.data) return; } + // 2. For non-anonymous callers, check 'authenticated' group grants + if (__classPrivateFieldGet(this, _AclVfsClient_callerId, "f") !== ANONYMOUS_USER_ID) { + for (const resource of chain) { + const result = await __classPrivateFieldGet(this, _AclVfsClient_acl, "f").isAllowed(AUTHENTICATED_USER_ID, resource, permission); + if (result.ok && result.data) + return; + } + } const err = new Error(`EACCES: user '${__classPrivateFieldGet(this, _AclVfsClient_callerId, "f")}' lacks '${permission}' on path '${path}'`); err.code = 'EACCES'; throw err; }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWNsVmZzQ2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Zmcy9BY2xWZnNDbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBcUJBLE9BQU8sRUFBRSxRQUFRLEVBQTJCLE1BQU0sZUFBZSxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU3RCxNQUFNLE9BQU8sWUFBWTtJQU1yQjs7Ozs7T0FLRztJQUNILFlBQVksR0FBUSxFQUFFLE9BQWUsRUFBRSxRQUFnQixFQUFFLE1BQTBCOztRQVgxRSxvQ0FBVTtRQUNWLHNDQUFpQjtRQUNqQix3Q0FBaUI7UUFDakIseUNBQWtCO1FBU3ZCLHVCQUFBLElBQUkscUJBQVEsR0FBRyxNQUFBLENBQUM7UUFDaEIsdUJBQUEsSUFBSSx1QkFBVSxJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBQSxDQUFDO1FBQ25DLHVCQUFBLElBQUkseUJBQVksU0FBUyxDQUFDLE9BQU8sQ0FBQyxNQUFBLENBQUM7UUFDbkMsdUJBQUEsSUFBSSwwQkFBYSxTQUFTLENBQUMsUUFBUSxDQUFDLE1BQUEsQ0FBQztJQUN6QyxDQUFDO0lBeUJELG1FQUFtRTtJQUVuRSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQVk7UUFDbkIsTUFBTSx1QkFBQSxJQUFJLG9EQUFPLE1BQVgsSUFBSSxFQUFRLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNoQyxPQUFPLHVCQUFBLElBQUksMkJBQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBWTtRQUN0QixNQUFNLHVCQUFBLElBQUksb0RBQU8sTUFBWCxJQUFJLEVBQVEsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ2hD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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWNsVmZzQ2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Zmcy9BY2xWZnNDbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBcUJBLE9BQU8sRUFBRSxRQUFRLEVBQTJCLE1BQU0sZUFBZSxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDN0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFFLGlCQUFpQixFQUFFLHFCQUFxQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFaEgsTUFBTSxPQUFPLFlBQVk7SUFNckI7Ozs7O09BS0c7SUFDSCxZQUFZLEdBQVEsRUFBRSxPQUFlLEVBQUUsUUFBZ0IsRUFBRSxNQUEwQjs7UUFYMUUsb0NBQVU7UUFDVixzQ0FBaUI7UUFDakIsd0NBQWlCO1FBQ2pCLHlDQUFrQjtRQVN2Qix1QkFBQSxJQUFJLHFCQUFRLEdBQUcsTUFBQSxDQUFDO1FBQ2hCLHVCQUFBLElBQUksdUJBQVUsSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQUEsQ0FBQztRQUNuQyx1QkFBQSxJQUFJLHlCQUFZLFNBQVMsQ0FBQyxPQUFPLENBQUMsTUFBQSxDQUFDO1FBQ25DLHVCQUFBLElBQUksMEJBQWEsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFBLENBQUM7SUFDdkMsQ0FBQztJQXNDRCxtRUFBbUU7SUFFbkUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFZO1FBQ25CLE1BQU0sdUJBQUEsSUFBSSxvREFBTyxNQUFYLElBQUksRUFBUSxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEMsT0FBTyx1QkFBQSxJQUFJLDJCQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBTyxDQUFDLElBQVk7UUFDdEIsTUFBTSx1QkFBQSxJQUFJLG9EQUFPLE1BQVgsSUFBSSxF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 \ No newline at end of file diff --git a/packages/acl/dist-in/vfs/sanitizers.d.ts b/packages/acl/dist-in/vfs/sanitizers.d.ts index 460ec296..7bce822e 100644 --- a/packages/acl/dist-in/vfs/sanitizers.d.ts +++ b/packages/acl/dist-in/vfs/sanitizers.d.ts @@ -50,6 +50,10 @@ export declare function cleanPermission(raw: string): string; * Validate and normalise permission arrays. */ export declare function cleanPermissions(raw: string[]): string[]; +/** Sentinel userId for unauthenticated/anonymous access. */ +export declare const ANONYMOUS_USER_ID = "anonymous"; +/** Sentinel userId for any authenticated user. */ +export declare const AUTHENTICATED_USER_ID = "authenticated"; /** * Test whether a string is a valid UUID. * @@ -64,9 +68,10 @@ export declare function isUuid(value: string): boolean; */ export declare function cleanUuid(raw: string): string; /** - * Validate a user/owner identifier — must be a valid UUID. + * Validate a user/owner identifier — must be a valid UUID or the + * well-known `'anonymous'` sentinel. * - * @throws Error if the identifier is not a valid UUID. + * @throws Error if the identifier is not a valid UUID or 'anonymous'. */ export declare function cleanId(raw: string): string; /** @@ -102,4 +107,6 @@ export declare const DefaultSanitizers: { readonly sanitizeSubpath: typeof sanitizeSubpath; readonly sanitizeWritePath: typeof sanitizeWritePath; readonly sanitizeFilename: typeof sanitizeFilename; + readonly ANONYMOUS_USER_ID: "anonymous"; + readonly AUTHENTICATED_USER_ID: "authenticated"; }; diff --git a/packages/acl/dist-in/vfs/sanitizers.js b/packages/acl/dist-in/vfs/sanitizers.js index e890c755..650dfa62 100644 --- a/packages/acl/dist-in/vfs/sanitizers.js +++ b/packages/acl/dist-in/vfs/sanitizers.js @@ -70,6 +70,13 @@ export function cleanPermissions(raw) { return raw.map(cleanPermission); } // --------------------------------------------------------------------------- +// Well-known sentinel IDs +// --------------------------------------------------------------------------- +/** Sentinel userId for unauthenticated/anonymous access. */ +export const ANONYMOUS_USER_ID = 'anonymous'; +/** Sentinel userId for any authenticated user. */ +export const AUTHENTICATED_USER_ID = 'authenticated'; +// --------------------------------------------------------------------------- // UUID validation // --------------------------------------------------------------------------- /** Standard UUID v1–v5 pattern (case-insensitive, lowercased on output). */ @@ -96,11 +103,17 @@ export function cleanUuid(raw) { return id; } /** - * Validate a user/owner identifier — must be a valid UUID. + * Validate a user/owner identifier — must be a valid UUID or the + * well-known `'anonymous'` sentinel. * - * @throws Error if the identifier is not a valid UUID. + * @throws Error if the identifier is not a valid UUID or 'anonymous'. */ export function cleanId(raw) { + const trimmed = raw.trim().toLowerCase(); + if (trimmed === ANONYMOUS_USER_ID) + return ANONYMOUS_USER_ID; + if (trimmed === AUTHENTICATED_USER_ID) + return AUTHENTICATED_USER_ID; return cleanUuid(raw); } /** @@ -159,5 +172,7 @@ export const DefaultSanitizers = { sanitizeSubpath, sanitizeWritePath, sanitizeFilename, + ANONYMOUS_USER_ID, + AUTHENTICATED_USER_ID, }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FuaXRpemVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92ZnMvc2FuaXRpemVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUMsR0FBVztJQUNqQyxPQUFPLEdBQUc7U0FDTCxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztTQUNuQixPQUFPLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQztTQUNwQixPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztTQUNuQixPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsR0FBVztJQUNwQyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0IsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUN6QyxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFXO0lBQ3JDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0FBQ3JDLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsR0FBVztJQUN2QyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkMsSUFBSSxDQUFDLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7SUFDM0QsT0FB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FuaXRpemVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92ZnMvc2FuaXRpemVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUMsR0FBVztJQUNqQyxPQUFPLEdBQUc7U0FDTCxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztTQUNuQixPQUFPLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQztTQUNwQixPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztTQUNuQixPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsR0FBVztJQUNwQyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0IsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUN6QyxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFXO0lBQ3JDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0FBQ3JDLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsR0FBVztJQUN2QyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkMsSUFBSSxDQUFDLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7SUFDM0QsT0FB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 \ No newline at end of file diff --git a/packages/acl/dist-in/vfs/vfs-acl.js b/packages/acl/dist-in/vfs/vfs-acl.js index f5d6258c..d56f2d5d 100644 --- a/packages/acl/dist-in/vfs/vfs-acl.js +++ b/packages/acl/dist-in/vfs/vfs-acl.js @@ -106,4 +106,4 @@ export async function loadVfsSettings(acl, userDir) { } return settings; } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmZzLWFjbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92ZnMvdmZzLWFjbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVqQyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUEyQnpHLDhFQUE4RTtBQUM5RSxVQUFVO0FBQ1YsOEVBQThFO0FBRTlFOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FBQyxPQUFlLEVBQUUsWUFBWSxHQUFHLEdBQUc7SUFDM0QsT0FBTyxPQUFPLE9BQU8sSUFBSSxhQUFhLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztBQUMzRCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxhQUFhLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFDMUQsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBRXZDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztJQUUzQiw2Q0FBNkM7SUFDN0MsS0FBSyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUN2QyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUVELHNCQUFzQjtJQUN0QixLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUV0QyxPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBRUQsOEVBQThFO0FBQzlFLFNBQVM7QUFDVCw4RUFBOEU7QUFFOUU7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlLENBQUMsR0FBUSxFQUFFLE9BQWU7O0lBQzNELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztJQUN4RCxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRTNDLE1BQU0sR0FBRyxHQUFHLFlBQVksQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0MsTUFBTSxRQUFRLEdBQWdCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFOUMsaUJBQWlCO0lBQ2pCLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFMUMsaUNBQWlDO0lBQ2pDLE1BQU0sTUFBTSxHQUFHLENBQUMsTUFBeUMsRUFBUSxFQUFFO1FBQy9ELElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUUsTUFBOEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3RSxDQUFDLENBQUM7SUFFRiwwQ0FBMEM7SUFDMUMsTUFBTSxTQUFTLEdBQUcsU0FBUyxTQUFTLEVBQUUsQ0FBQztJQUN2QyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDckUsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLFlBQVksQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUVyRCxxQ0FBcUM7SUFDckMsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7SUFDakQsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFBLFFBQVEsQ0FBQyxNQUFNLG1DQUFJLEVBQUUsRUFBRSxDQUFDO1FBQ3hDLE1BQU0sUUFBUSxHQUFHLGNBQWMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN2RCxZQUFZLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQsc0JBQXNCO0lBQ3RCLEtBQUssTUFBTSxLQUFLLElBQUksUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQy9CLE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxNQUFBLEtBQUssQ0FBQyxJQUFJLG1DQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDdEQsTUFBTSxTQUFTLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRXRELElBQUksS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2QsY0FBYztZQUNkLE1BQU0sU0FBUyxHQUFHLGNBQWMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDOUMsTUFBTSxTQUFTLEdBQUcsU0FBUyxTQUFTLElBQUksU0FBUyxFQUFFLENBQUM7WUFDcEQsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFFeEQsTUFBTSxPQUFPLEdBQUcsTUFBQSxZQUFZLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxtQ0FBSSxFQUFFLENBQUM7WUFDbEQsS0FBSyxNQUFNLFFBQVEsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUN4RCxDQUFDO1FBQ0wsQ0FBQzthQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3RCLG9CQUFvQjtZQUNwQixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3JDLE1BQU0sU0FBUyxHQUFHLGFBQWEsU0FBUyxJQUFJLE1BQU0sSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUNyRSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUN4RCxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQ3RELENBQUM7SUFDTCxDQUFDO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDcEIsQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmZzLWFjbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92ZnMvdmZzLWFjbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVqQyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFxQixNQUFNLGlCQUFpQixDQUFDO0FBMkI1SCw4RUFBOEU7QUFDOUUsVUFBVTtBQUNWLDhFQUE4RTtBQUU5RTs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsT0FBZSxFQUFFLFlBQVksR0FBRyxHQUFHO0lBQzNELE9BQU8sT0FBTyxPQUFPLElBQUksYUFBYSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7QUFDM0QsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLE9BQWUsRUFBRSxPQUFlO0lBQzFELE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUV2QyxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUM7SUFFM0IsNkNBQTZDO0lBQzdDLEtBQUssSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDdkMsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEdBQUcsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRCxzQkFBc0I7SUFDdEIsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFX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 \ No newline at end of file diff --git a/packages/acl/src/index.ts b/packages/acl/src/index.ts index e15dd6d6..44094da0 100644 --- a/packages/acl/src/index.ts +++ b/packages/acl/src/index.ts @@ -33,4 +33,6 @@ export { cleanPermission, cleanPermissions, isUuid, cleanUuid, cleanId, cleanGroupName, sanitizeSubpath, sanitizeWritePath, sanitizeFilename, + ANONYMOUS_USER_ID, + AUTHENTICATED_USER_ID, } from './vfs/sanitizers.js'; diff --git a/packages/acl/src/vfs/AclVfsClient.ts b/packages/acl/src/vfs/AclVfsClient.ts index e8f7cb31..bf4b82e4 100644 --- a/packages/acl/src/vfs/AclVfsClient.ts +++ b/packages/acl/src/vfs/AclVfsClient.ts @@ -21,7 +21,7 @@ import type { Acl } from '../Acl.js'; import type { INode } from './fs/VFS.js'; import { LocalVFS, type IDefaultParameters } from './fs/Local.js'; import { resourceChain } from './vfs-acl.js'; -import { cleanUuid, sanitizeSubpath } from './sanitizers.js'; +import { cleanUuid, cleanId, sanitizeSubpath, ANONYMOUS_USER_ID, AUTHENTICATED_USER_ID } from './sanitizers.js'; export class AclVfsClient { readonly #acl: Acl; @@ -32,14 +32,14 @@ export class AclVfsClient { /** * @param acl Populated Acl instance (call `loadVfsSettings` first) * @param ownerId UUID of the folder owner - * @param callerId UUID of the user performing the operation + * @param callerId UUID of the user performing the operation, or 'anonymous' * @param fsOpts LocalVFS options (must include `root`) */ constructor(acl: Acl, ownerId: string, callerId: string, fsOpts: IDefaultParameters) { this.#acl = acl; this.#local = new LocalVFS(fsOpts); this.#ownerId = cleanUuid(ownerId); - this.#callerId = cleanUuid(callerId); + this.#callerId = cleanId(callerId); } // ── Guards ────────────────────────────────────────────────────── @@ -48,16 +48,29 @@ export class AclVfsClient { * Walk the resource chain from most-specific path to root. * If ANY level grants the permission, access is allowed. * This means a grant on `/` covers the entire tree. + * + * For non-anonymous callers, also checks grants given to the + * `'authenticated'` sentinel, so a single grant can cover all + * logged-in users. */ async #guard(permission: string, path: string): Promise { const safePath = sanitizeSubpath(path); const chain = resourceChain(this.#ownerId, safePath); + // 1. Check caller-specific grants for (const resource of chain) { const result = await this.#acl.isAllowed(this.#callerId, resource, permission); if (result.ok && result.data) return; } + // 2. For non-anonymous callers, check 'authenticated' group grants + if (this.#callerId !== ANONYMOUS_USER_ID) { + for (const resource of chain) { + const result = await this.#acl.isAllowed(AUTHENTICATED_USER_ID, resource, permission); + if (result.ok && result.data) return; + } + } + const err = new Error( `EACCES: user '${this.#callerId}' lacks '${permission}' on path '${path}'`, ); diff --git a/packages/acl/src/vfs/sanitizers.ts b/packages/acl/src/vfs/sanitizers.ts index 512390e9..972a9284 100644 --- a/packages/acl/src/vfs/sanitizers.ts +++ b/packages/acl/src/vfs/sanitizers.ts @@ -74,6 +74,16 @@ export function cleanPermissions(raw: string[]): string[] { return raw.map(cleanPermission); } +// --------------------------------------------------------------------------- +// Well-known sentinel IDs +// --------------------------------------------------------------------------- + +/** Sentinel userId for unauthenticated/anonymous access. */ +export const ANONYMOUS_USER_ID = 'anonymous'; + +/** Sentinel userId for any authenticated user. */ +export const AUTHENTICATED_USER_ID = 'authenticated'; + // --------------------------------------------------------------------------- // UUID validation // --------------------------------------------------------------------------- @@ -105,11 +115,15 @@ export function cleanUuid(raw: string): string { } /** - * Validate a user/owner identifier — must be a valid UUID. + * Validate a user/owner identifier — must be a valid UUID or the + * well-known `'anonymous'` sentinel. * - * @throws Error if the identifier is not a valid UUID. + * @throws Error if the identifier is not a valid UUID or 'anonymous'. */ export function cleanId(raw: string): string { + const trimmed = raw.trim().toLowerCase(); + if (trimmed === ANONYMOUS_USER_ID) return ANONYMOUS_USER_ID; + if (trimmed === AUTHENTICATED_USER_ID) return AUTHENTICATED_USER_ID; return cleanUuid(raw); } @@ -173,4 +187,6 @@ export const DefaultSanitizers = { sanitizeSubpath, sanitizeWritePath, sanitizeFilename, + ANONYMOUS_USER_ID, + AUTHENTICATED_USER_ID, } as const; diff --git a/packages/acl/src/vfs/vfs-acl.ts b/packages/acl/src/vfs/vfs-acl.ts index ba024271..70e24d36 100644 --- a/packages/acl/src/vfs/vfs-acl.ts +++ b/packages/acl/src/vfs/vfs-acl.ts @@ -15,7 +15,7 @@ import { readFileSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import type { Acl } from '../Acl.js'; -import { pathSegments, normalisePath, cleanGroupName, cleanId, cleanPermissions } from './sanitizers.js'; +import { pathSegments, normalisePath, cleanGroupName, cleanId, cleanPermissions, ANONYMOUS_USER_ID } from './sanitizers.js'; // --------------------------------------------------------------------------- // Types diff --git a/packages/acl/tests/vfs-acl-anonymous.e2e.test.ts b/packages/acl/tests/vfs-acl-anonymous.e2e.test.ts new file mode 100644 index 00000000..5e4df69e --- /dev/null +++ b/packages/acl/tests/vfs-acl-anonymous.e2e.test.ts @@ -0,0 +1,78 @@ +/** + * VFS ACL — Anonymous user e2e test + * + * Verifies that the well-known 'anonymous' userId works through the + * ACL pipeline: loadVfsSettings populates grants, and isAllowed checks + * pass/fail correctly for anonymous callers. + */ +import { describe, it, expect, beforeAll } from 'vitest'; +import { resolve } from 'node:path'; +import { Acl } from '../src/Acl.js'; +import { MemoryBackend } from '../src/data/MemoryBackend.js'; +import { loadVfsSettings, vfsResource } from '../src/vfs/vfs-acl.js'; +import { ANONYMOUS_USER_ID } from '../src/vfs/sanitizers.js'; +import type { AclResult } from '../src/interfaces.js'; + +/** Unwrap AclResult — asserts ok and returns data. */ +function d(result: AclResult): T { + if (!result.ok) throw new Error(`Expected ok, got ${result.code}: ${result.message}`); + return result.data; +} + +const OWNER_ID = '3bb4cfbf-318b-44d3-a9d3-35680e738421'; +const READ_ONLY_USER = 'aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb'; +const STRANGER_USER = '99999999-0000-0000-0000-ffffffffffff'; + +const ROOT = vfsResource(OWNER_ID, '/'); +const SHARED = vfsResource(OWNER_ID, '/shared'); + +const USER_DIR = resolve(import.meta.dirname!, 'vfs/root/anon-test'); + +describe('VFS ACL — anonymous user', () => { + let acl: Acl; + + beforeAll(async () => { + acl = new Acl(new MemoryBackend()); + const settings = await loadVfsSettings(acl, USER_DIR); + expect(settings).not.toBeNull(); + expect(settings!.owner).toBe(OWNER_ID); + }); + + // Anonymous gets read+list on / + it('anonymous can read on /', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, ROOT, 'read'))).toBe(true); + }); + + it('anonymous can list on /', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, ROOT, 'list'))).toBe(true); + }); + + // Direct isAllowed on /shared returns false — the grant is on "/" only. + // AclVfsClient.#guard walks the resource chain, but raw acl.isAllowed does not. + it('anonymous direct check on /shared returns false (grant is on /)', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, SHARED, 'read'))).toBe(false); + }); + + // Anonymous CANNOT write + it('anonymous CANNOT write on /', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, ROOT, 'write'))).toBe(false); + }); + + it('anonymous CANNOT delete on /', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, ROOT, 'delete'))).toBe(false); + }); + + it('anonymous CANNOT mkdir on /', async () => { + expect(d(await acl.isAllowed(ANONYMOUS_USER_ID, ROOT, 'mkdir'))).toBe(false); + }); + + // Other users still work alongside anonymous + it('read-only user can still read on /', async () => { + expect(d(await acl.isAllowed(READ_ONLY_USER, ROOT, 'read'))).toBe(true); + }); + + // Stranger (no grant) is still denied + it('stranger CANNOT read on /', async () => { + expect(d(await acl.isAllowed(STRANGER_USER, ROOT, 'read'))).toBe(false); + }); +}); diff --git a/packages/acl/tests/vfs/root/anon-test/vfs-settings.json b/packages/acl/tests/vfs/root/anon-test/vfs-settings.json new file mode 100644 index 00000000..d6b03011 --- /dev/null +++ b/packages/acl/tests/vfs/root/anon-test/vfs-settings.json @@ -0,0 +1,21 @@ +{ + "owner": "3bb4cfbf-318b-44d3-a9d3-35680e738421", + "acl": [ + { + "userId": "anonymous", + "path": "/", + "permissions": [ + "read", + "list" + ] + }, + { + "userId": "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", + "path": "/", + "permissions": [ + "read", + "list" + ] + } + ] +} \ No newline at end of file