feat: Return correct status codes for invalid requests

This commit is contained in:
Joachim Van Herwegen
2022-01-14 14:54:28 +01:00
parent bc6203f3e8
commit 1afed65368
12 changed files with 179 additions and 17 deletions

View File

@@ -2,4 +2,7 @@ import type { Operation } from '../../http/Operation';
import { AsyncHandler } from '../../util/handlers/AsyncHandler';
import type { AccessMode } from './Permissions';
/**
* Extracts all {@link AccessMode}s that are necessary to execute the given {@link Operation}.
*/
export abstract class ModesExtractor extends AsyncHandler<Operation, Set<AccessMode>> {}

View File

@@ -6,11 +6,13 @@ import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpErr
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.`);
}
/**
* Generates permissions for a SPARQL DELETE/INSERT body.
* Updates with only an INSERT can be done with just append permissions,
* while DELETEs require write permissions as well.
*/
export class SparqlUpdateModesExtractor extends ModesExtractor {
public async canHandle({ body }: Operation): Promise<void> {
if (!this.isSparql(body)) {
throw new NotImplementedHttpError('Cannot determine permissions of non-SPARQL patches.');
}

View File

@@ -18,7 +18,7 @@ export * from './authorization/access/AgentGroupAccessChecker';
export * from './authorization/permissions/Permissions';
export * from './authorization/permissions/ModesExtractor';
export * from './authorization/permissions/MethodModesExtractor';
export * from './authorization/permissions/SparqlPatchModesExtractor';
export * from './authorization/permissions/SparqlUpdateModesExtractor';
// Authorization
export * from './authorization/AllStaticReader';
@@ -359,9 +359,12 @@ export * from './util/errors/UnsupportedMediaTypeHttpError';
export * from './util/handlers/AsyncHandler';
export * from './util/handlers/BooleanHandler';
export * from './util/handlers/ConditionalHandler';
export * from './util/handlers/HandlerUtil';
export * from './util/handlers/MethodFilterHandler';
export * from './util/handlers/ParallelHandler';
export * from './util/handlers/SequenceHandler';
export * from './util/handlers/StaticHandler';
export * from './util/handlers/StaticThrowHandler';
export * from './util/handlers/UnionHandler';
export * from './util/handlers/UnsupportedAsyncHandler';
export * from './util/handlers/WaterfallHandler';

View File

@@ -0,0 +1,30 @@
import { NotImplementedHttpError } from '../errors/NotImplementedHttpError';
import { AsyncHandler } from './AsyncHandler';
/**
* Only accepts requests where the input has a `method` field that matches any one of the given methods.
* In case of a match, the input will be sent to the source handler.
*/
export class MethodFilterHandler<TIn extends { method: string }, TOut> extends AsyncHandler<TIn, TOut> {
private readonly methods: string[];
private readonly source: AsyncHandler<TIn, TOut>;
public constructor(methods: string[], source: AsyncHandler<TIn, TOut>) {
super();
this.methods = methods;
this.source = source;
}
public async canHandle(input: TIn): Promise<void> {
if (!this.methods.includes(input.method)) {
throw new NotImplementedHttpError(
`Cannot determine permissions of ${input.method}, only ${this.methods.join(',')}.`,
);
}
await this.source.canHandle(input);
}
public async handle(input: TIn): Promise<TOut> {
return this.source.handle(input);
}
}

View File

@@ -0,0 +1,18 @@
import type { HttpError } from '../errors/HttpError';
import { AsyncHandler } from './AsyncHandler';
/**
* Utility handler that can handle all input and always throws the given error.
*/
export class StaticThrowHandler extends AsyncHandler<any, never> {
private readonly error: HttpError;
public constructor(error: HttpError) {
super();
this.error = error;
}
public async handle(): Promise<never> {
throw this.error;
}
}