mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
115 lines
6.2 KiB
TypeScript
115 lines
6.2 KiB
TypeScript
import type { CredentialSet } from '../../../src/authentication/Credentials';
|
|
import { ParentContainerReader } from '../../../src/authorization/ParentContainerReader';
|
|
import type { PermissionReader } from '../../../src/authorization/PermissionReader';
|
|
import type { AccessMap, PermissionMap } from '../../../src/authorization/permissions/Permissions';
|
|
import { AccessMode } from '../../../src/authorization/permissions/Permissions';
|
|
import { SingleRootIdentifierStrategy } from '../../../src/util/identifiers/SingleRootIdentifierStrategy';
|
|
import { IdentifierMap, IdentifierSetMultiMap } from '../../../src/util/map/IdentifierMap';
|
|
import { joinUrl } from '../../../src/util/PathUtil';
|
|
import { compareMaps } from '../../util/Util';
|
|
|
|
describe('A ParentContainerReader', (): void => {
|
|
const baseUrl = 'http://example.com/';
|
|
const parent1 = { path: joinUrl(baseUrl, 'foo/') };
|
|
const target1 = { path: joinUrl(parent1.path, 'foo') };
|
|
const parent2 = { path: joinUrl(baseUrl, 'bar/') };
|
|
const target2 = { path: joinUrl(parent2.path, 'bar') };
|
|
const parent3 = { path: joinUrl(baseUrl, 'baz/') };
|
|
const target3 = { path: joinUrl(parent3.path, 'baz') };
|
|
const credentials: CredentialSet = { public: {}};
|
|
let requestedModes: AccessMap;
|
|
let sourceResult: PermissionMap;
|
|
const identifierStrategy = new SingleRootIdentifierStrategy(baseUrl);
|
|
let source: jest.Mocked<PermissionReader>;
|
|
let reader: ParentContainerReader;
|
|
|
|
beforeEach(async(): Promise<void> => {
|
|
requestedModes = new IdentifierSetMultiMap();
|
|
|
|
sourceResult = new IdentifierMap([[{ path: joinUrl(baseUrl, 'test') }, { public: { read: true }}]]);
|
|
|
|
source = { handleSafe: jest.fn().mockResolvedValue(sourceResult) } as any;
|
|
reader = new ParentContainerReader(source, identifierStrategy);
|
|
});
|
|
|
|
it('requires parent append permissions to create resources.', async(): Promise<void> => {
|
|
requestedModes.set(target1, new Set([ AccessMode.create ]));
|
|
requestedModes.set(target2, new Set([ AccessMode.create ]));
|
|
sourceResult.set(parent1, { public: { append: true }});
|
|
|
|
const result = await reader.handle({ requestedModes, credentials });
|
|
expect(result.get(target1)).toEqual({ public: { create: true }});
|
|
expect(result.get(target2)).toEqual({ });
|
|
|
|
const updatedMap = new IdentifierSetMultiMap(requestedModes);
|
|
updatedMap.set(parent1, AccessMode.append);
|
|
updatedMap.set(parent2, AccessMode.append);
|
|
expect(source.handleSafe).toHaveBeenCalledTimes(1);
|
|
expect(source.handleSafe.mock.calls[0][0].credentials).toBe(credentials);
|
|
compareMaps(source.handleSafe.mock.calls[0][0].requestedModes, updatedMap);
|
|
expect(source.handleSafe.mock.calls[0][0].requestedModes).not.toEqual(requestedModes);
|
|
});
|
|
|
|
it('requires write and parent write permissions to delete resources.', async(): Promise<void> => {
|
|
requestedModes.set(target1, new Set([ AccessMode.delete ]));
|
|
requestedModes.set(target2, new Set([ AccessMode.delete ]));
|
|
requestedModes.set(target3, new Set([ AccessMode.delete ]));
|
|
sourceResult.set(parent1, { public: { write: true }});
|
|
sourceResult.set(parent2, { public: { write: true }});
|
|
sourceResult.set(target1, { public: { write: true }});
|
|
sourceResult.set(target3, { public: { write: true }});
|
|
|
|
const result = await reader.handle({ requestedModes, credentials });
|
|
expect(result.get(target1)).toEqual({ public: { delete: true, write: true }});
|
|
expect(result.get(target2)).toEqual({ public: {}});
|
|
expect(result.get(target3)).toEqual({ public: { write: true }});
|
|
|
|
const updatedMap = new IdentifierSetMultiMap(requestedModes);
|
|
updatedMap.set(parent1, AccessMode.write);
|
|
updatedMap.set(parent2, AccessMode.write);
|
|
updatedMap.set(parent3, AccessMode.write);
|
|
expect(source.handleSafe).toHaveBeenCalledTimes(1);
|
|
expect(source.handleSafe.mock.calls[0][0].credentials).toBe(credentials);
|
|
compareMaps(source.handleSafe.mock.calls[0][0].requestedModes, updatedMap);
|
|
});
|
|
|
|
it('does not allow create/delete if the source explicitly forbids it.', async(): Promise<void> => {
|
|
requestedModes.set(target1, new Set([ AccessMode.create, AccessMode.delete ]));
|
|
requestedModes.set(target2, new Set([ AccessMode.create, AccessMode.delete ]));
|
|
sourceResult.set(parent1, { public: { write: true, append: true }});
|
|
sourceResult.set(parent2, { public: { write: true, append: true }});
|
|
sourceResult.set(target1, { public: { write: true }});
|
|
sourceResult.set(target2, { public: { write: true, create: false, delete: false }});
|
|
|
|
const result = await reader.handle({ requestedModes, credentials });
|
|
expect(result.get(target1)).toEqual({ public: { write: true, create: true, delete: true }});
|
|
expect(result.get(target2)).toEqual({ public: { write: true, create: false, delete: false }});
|
|
|
|
const updatedMap = new IdentifierSetMultiMap(requestedModes);
|
|
updatedMap.set(parent1, new Set([ AccessMode.write, AccessMode.append ]));
|
|
updatedMap.set(parent2, new Set([ AccessMode.write, AccessMode.append ]));
|
|
expect(source.handleSafe).toHaveBeenCalledTimes(1);
|
|
expect(source.handleSafe.mock.calls[0][0].credentials).toBe(credentials);
|
|
compareMaps(source.handleSafe.mock.calls[0][0].requestedModes, updatedMap);
|
|
});
|
|
|
|
it('combines the modes with the parent resource if it is also being requested.', async(): Promise<void> => {
|
|
requestedModes.set(target1, AccessMode.create);
|
|
requestedModes.set(parent1, AccessMode.write);
|
|
sourceResult.set(parent1, { public: { write: true, append: true }});
|
|
sourceResult.set(target1, { public: { write: true }});
|
|
|
|
const result = await reader.handle({ requestedModes, credentials });
|
|
expect(result.get(target1)).toEqual({ public: { write: true, create: true, delete: true }});
|
|
expect(result.get(parent1)).toEqual({ public: { write: true, append: true }});
|
|
|
|
const updatedMap = new IdentifierSetMultiMap(requestedModes);
|
|
updatedMap.set(parent1, new Set([ AccessMode.write, AccessMode.append ]));
|
|
expect(source.handleSafe).toHaveBeenCalledTimes(1);
|
|
expect(source.handleSafe.mock.calls[0][0].credentials).toBe(credentials);
|
|
compareMaps(source.handleSafe.mock.calls[0][0].requestedModes, updatedMap);
|
|
expect(source.handleSafe.mock.calls[0][0].requestedModes.get(parent1))
|
|
.toEqual(new Set([ AccessMode.write, AccessMode.append ]));
|
|
});
|
|
});
|