UNPKG

@solid/community-server

Version:

Community Solid Server: an open and modular implementation of the Solid specifications

114 lines 4.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OwnerPermissionReader = void 0; const policy_engine_1 = require("@solidlab/policy-engine"); const global_logger_factory_1 = require("global-logger-factory"); const IterableUtil_1 = require("../util/IterableUtil"); const IdentifierMap_1 = require("../util/map/IdentifierMap"); const MapUtil_1 = require("../util/map/MapUtil"); const PermissionReader_1 = require("./PermissionReader"); /** * Allows control access if the request is being made by an owner of the pod containing the resource. * This overrules any deductions made by the source reader: * if the target resource is owned by the client, they will always have control access. */ class OwnerPermissionReader extends PermissionReader_1.PermissionReader { logger = (0, global_logger_factory_1.getLoggerFor)(this); podStore; storageStrategy; reader; constructor(podStore, storageStrategy, reader) { super(); this.podStore = podStore; this.storageStrategy = storageStrategy; this.reader = reader; } async canHandle(input) { return this.reader.canHandle(input); } async handle(input) { const requestedResources = input.requestedModes.distinctKeys(); const auths = [...(0, IterableUtil_1.filter)(requestedResources, (id) => input.requestedModes.hasEntry(id, policy_engine_1.ACL.Control))]; const owned = await this.findOwnedResources(auths, input.credentials.agent?.webId); const updatedRequest = new IdentifierMap_1.IdentifierSetMultiMap(input.requestedModes); for (const identifier of owned) { updatedRequest.deleteEntry(identifier, policy_engine_1.ACL.Control); } let result; if (updatedRequest.size > 0) { result = await this.reader.handle({ requestedModes: updatedRequest, credentials: input.credentials }); } else { result = new IdentifierMap_1.IdentifierMap(); } for (const identifier of owned) { const permissions = (0, MapUtil_1.getDefault)(result, identifier, () => ({})); permissions[policy_engine_1.ACL.Control] = true; result.set(identifier, permissions); } return result; } async findOwnedResources(identifiers, webId) { if (identifiers.length === 0) { this.logger.debug(`No resources found that need an ownership check.`); return []; } if (!webId) { this.logger.debug(`No WebId found for an ownership check on the pod.`); return []; } const pods = await this.findPods(identifiers); const owners = await this.findOwners(Object.values(pods)); const result = []; for (const identifier of identifiers) { const webIds = owners[pods[identifier.path]]; if (webIds?.includes(webId)) { result.push(identifier); } } return result; } /** * Finds all pods that contain the given identifiers. * Return value is a record where the keys are the identifiers and the values the associated pod. */ async findPods(identifiers) { const pods = {}; for (const identifier of identifiers) { let pod; try { pod = await this.storageStrategy.getStorageIdentifier(identifier); } catch { this.logger.error(`Unable to find root storage for ${identifier.path}`); continue; } pods[identifier.path] = pod.path; } return pods; } /** * Finds the owners of the given pods. * Return value is a record where the keys are the pods and the values are all the WebIDs that own this pod. */ async findOwners(pods) { const owners = {}; // Set to only have the unique values for (const baseUrl of new Set(pods)) { const pod = await this.podStore.findByBaseUrl(baseUrl); if (!pod) { this.logger.error(`Unable to find pod ${baseUrl}`); continue; } const podOwners = await this.podStore.getOwners(pod.id); if (!podOwners) { this.logger.error(`Unable to find owners for ${baseUrl}`); continue; } owners[baseUrl] = podOwners.map((owner) => owner.webId); } return owners; } } exports.OwnerPermissionReader = OwnerPermissionReader; //# sourceMappingURL=OwnerPermissionReader.js.map