CommunitySolidServer/src/ldp/permissions/SparqlPatchModesExtractor.ts
Joachim Van Herwegen 7f8b923399 feat: Replace acl specific permissions with generic permissions
This required AuxiliaryStrategy to have a new function
indicating if the auxiliary resource just used its associated resource authorization
or its own.
2021-09-28 13:06:38 +02:00

86 lines
3.0 KiB
TypeScript

import { Algebra } from 'sparqlalgebrajs';
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
import type { SparqlUpdatePatch } from '../http/SparqlUpdatePatch';
import type { Operation } from '../operations/Operation';
import type { Representation } from '../representation/Representation';
import { ModesExtractor } from './ModesExtractor';
import { AccessMode } from './Permissions';
export class SparqlPatchModesExtractor extends ModesExtractor {
public async canHandle({ method, body }: Operation): Promise<void> {
if (method !== 'PATCH') {
throw new NotImplementedHttpError(`Cannot determine permissions of ${method}, only PATCH.`);
}
if (!body) {
throw new NotImplementedHttpError('Cannot determine permissions of PATCH operations without a body.');
}
if (!this.isSparql(body)) {
throw new NotImplementedHttpError('Cannot determine permissions of non-SPARQL patches.');
}
if (!this.isSupported(body.algebra)) {
throw new NotImplementedHttpError('Can only determine permissions of a PATCH with DELETE/INSERT operations.');
}
}
public async handle({ body }: Operation): Promise<Set<AccessMode>> {
// Verified in `canHandle` call
const update = (body as SparqlUpdatePatch).algebra as Algebra.DeleteInsert;
const result = new Set<AccessMode>();
// Since `append` is a specific type of write, it is true if `write` is true.
if (this.needsWrite(update)) {
result.add(AccessMode.write);
result.add(AccessMode.append);
result.add(AccessMode.create);
result.add(AccessMode.delete);
} else if (this.needsAppend(update)) {
result.add(AccessMode.append);
}
return result;
}
private isSparql(data: Representation): data is SparqlUpdatePatch {
return Boolean((data as SparqlUpdatePatch).algebra);
}
private isSupported(op: Algebra.Operation): boolean {
if (this.isDeleteInsert(op) || this.isNop(op)) {
return true;
}
if (op.type === Algebra.types.COMPOSITE_UPDATE) {
return (op as Algebra.CompositeUpdate).updates.every((update): boolean => this.isSupported(update));
}
return false;
}
private isDeleteInsert(op: Algebra.Operation): op is Algebra.DeleteInsert {
return op.type === Algebra.types.DELETE_INSERT;
}
private isNop(op: Algebra.Operation): op is Algebra.Nop {
return op.type === Algebra.types.NOP;
}
private needsAppend(update: Algebra.Operation): boolean {
if (this.isNop(update)) {
return false;
}
if (this.isDeleteInsert(update)) {
return Boolean(update.insert && update.insert.length > 0);
}
return (update as Algebra.CompositeUpdate).updates.some((op): boolean => this.needsAppend(op));
}
private needsWrite(update: Algebra.Operation): boolean {
if (this.isNop(update)) {
return false;
}
if (this.isDeleteInsert(update)) {
return Boolean(update.delete && update.delete.length > 0);
}
return (update as Algebra.CompositeUpdate).updates.some((op): boolean => this.needsWrite(op));
}
}