@solid/community-server
Version:
Community Solid Server: an open and modular implementation of the Solid specifications
114 lines • 4.63 kB
JavaScript
;
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