mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
import type { AuxiliaryStrategy } from '../http/auxiliary/AuxiliaryStrategy';
|
|
import type { ResourceIdentifier } from '../http/representation/ResourceIdentifier';
|
|
import { getLoggerFor } from '../logging/LogUtil';
|
|
import { IdentifierMap, IdentifierSetMultiMap } from '../util/map/IdentifierMap';
|
|
import type { MapEntry } from '../util/map/MapUtil';
|
|
import { modify } from '../util/map/MapUtil';
|
|
import type { PermissionReaderInput } from './PermissionReader';
|
|
import { PermissionReader } from './PermissionReader';
|
|
import type { AccessMap, AccessMode, PermissionMap } from './permissions/Permissions';
|
|
|
|
/**
|
|
* Determines the permissions of auxiliary resources by finding those of the corresponding subject resources.
|
|
*/
|
|
export class AuxiliaryReader extends PermissionReader {
|
|
protected readonly logger = getLoggerFor(this);
|
|
|
|
private readonly reader: PermissionReader;
|
|
private readonly auxiliaryStrategy: AuxiliaryStrategy;
|
|
|
|
public constructor(reader: PermissionReader, auxiliaryStrategy: AuxiliaryStrategy) {
|
|
super();
|
|
this.reader = reader;
|
|
this.auxiliaryStrategy = auxiliaryStrategy;
|
|
}
|
|
|
|
public async handle({ requestedModes, credentials }: PermissionReaderInput): Promise<PermissionMap> {
|
|
// Finds all the dependent auxiliary identifiers
|
|
const auxiliaries = this.findAuxiliaries(requestedModes);
|
|
|
|
// Replaces the dependent auxiliary identifies with the corresponding subject identifiers
|
|
const updatedMap = modify(new IdentifierSetMultiMap(requestedModes),
|
|
{ add: auxiliaries.values(), remove: auxiliaries.keys() });
|
|
const result = await this.reader.handleSafe({ requestedModes: updatedMap, credentials });
|
|
|
|
// Extracts the auxiliary permissions based on the subject permissions
|
|
for (const [ identifier, [ subject ]] of auxiliaries) {
|
|
this.logger.debug(`Mapping ${subject.path} permissions to ${identifier.path}`);
|
|
result.set(identifier, result.get(subject) ?? {});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Maps auxiliary resources that do not have their own authorization checks to their subject resource.
|
|
*/
|
|
private findAuxiliaries(requestedModes: AccessMap): IdentifierMap<MapEntry<AccessMap>> {
|
|
const auxiliaries = new IdentifierMap<[ResourceIdentifier, ReadonlySet<AccessMode>]>();
|
|
for (const [ identifier, modes ] of requestedModes.entrySets()) {
|
|
if (this.isDependentAuxiliary(identifier)) {
|
|
auxiliaries.set(identifier, [ this.auxiliaryStrategy.getSubjectIdentifier(identifier), modes ]);
|
|
}
|
|
}
|
|
return auxiliaries;
|
|
}
|
|
|
|
/**
|
|
* Checks if the identifier is an auxiliary resource that uses subject permissions.
|
|
*/
|
|
private isDependentAuxiliary(identifier: ResourceIdentifier): boolean {
|
|
return this.auxiliaryStrategy.isAuxiliaryIdentifier(identifier) &&
|
|
!this.auxiliaryStrategy.usesOwnAuthorization(identifier);
|
|
}
|
|
}
|