feat: add note length check on note creation

This check throws a MaximumDocumentLengthExceededError, if the configured maxDocumentLength is exceeded by the new note

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2022-10-02 23:26:50 +02:00
parent 35032eef09
commit 5275f6b876
7 changed files with 30 additions and 4 deletions

View file

@ -88,7 +88,7 @@ export class NotesController {
} }
@Post() @Post()
@OpenApi(201) @OpenApi(201, 413)
@Permissions(Permission.CREATE) @Permissions(Permission.CREATE)
async createNote( async createNote(
@RequestUser() user: User, @RequestUser() user: User,
@ -101,7 +101,7 @@ export class NotesController {
} }
@Post(':noteAlias') @Post(':noteAlias')
@OpenApi(201, 400, 404, 409) @OpenApi(201, 400, 404, 409, 413)
@Permissions(Permission.CREATE) @Permissions(Permission.CREATE)
async createNamedNote( async createNamedNote(
@RequestUser() user: User, @RequestUser() user: User,

View file

@ -69,7 +69,7 @@ export class NotesController {
@Permissions(Permission.CREATE) @Permissions(Permission.CREATE)
@Post() @Post()
@OpenApi(201, 403, 409) @OpenApi(201, 403, 409, 413)
async createNote( async createNote(
@RequestUser() user: User, @RequestUser() user: User,
@MarkdownBody() text: string, @MarkdownBody() text: string,
@ -112,6 +112,7 @@ export class NotesController {
400, 400,
403, 403,
409, 409,
413,
) )
async createNamedNote( async createNamedNote(
@RequestUser() user: User, @RequestUser() user: User,

View file

@ -22,5 +22,7 @@ export const unprocessableEntityDescription =
"The request change can't be processed"; "The request change can't be processed";
export const conflictDescription = export const conflictDescription =
'The request conflicts with the current state of the application'; 'The request conflicts with the current state of the application';
export const payloadTooLargeDescription =
'The note is longer than the maximal allowed length of a note';
export const internalServerErrorDescription = export const internalServerErrorDescription =
'The request triggered an internal server error.'; 'The request triggered an internal server error.';

View file

@ -25,6 +25,7 @@ import {
noContentDescription, noContentDescription,
notFoundDescription, notFoundDescription,
okDescription, okDescription,
payloadTooLargeDescription,
unauthorizedDescription, unauthorizedDescription,
} from './descriptions'; } from './descriptions';
@ -37,6 +38,7 @@ export type HttpStatusCodes =
| 403 | 403
| 404 | 404
| 409 | 409
| 413
| 500; | 500;
/** /**
@ -156,6 +158,13 @@ export const OpenApi = (
}), }),
); );
break; break;
case 413:
decoratorsToApply.push(
ApiConflictResponse({
description: description ?? payloadTooLargeDescription,
}),
);
break;
case 500: case 500:
decoratorsToApply.push( decoratorsToApply.push(
ApiInternalServerErrorResponse({ ApiInternalServerErrorResponse({

View file

@ -10,6 +10,7 @@ import {
ConflictException, ConflictException,
InternalServerErrorException, InternalServerErrorException,
NotFoundException, NotFoundException,
PayloadTooLargeException,
UnauthorizedException, UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common';
import { HttpException } from '@nestjs/common/exceptions/http.exception'; import { HttpException } from '@nestjs/common/exceptions/http.exception';
@ -70,6 +71,10 @@ const mapOfHedgeDocErrorsToHttpErrors: Map<string, HttpExceptionConstructor> =
'PasswordTooWeakError', 'PasswordTooWeakError',
(object): HttpException => new BadRequestException(object), (object): HttpException => new BadRequestException(object),
], ],
[
'MaximumDocumentLengthExceededError',
(object): HttpException => new PayloadTooLargeException(object),
],
]); ]);
@Catch() @Catch()

View file

@ -55,3 +55,7 @@ export class NoLocalIdentityError extends Error {
export class PasswordTooWeakError extends Error { export class PasswordTooWeakError extends Error {
name = 'PasswordTooWeakError'; name = 'PasswordTooWeakError';
} }
export class MaximumDocumentLengthExceededError extends Error {
name = 'MaximumDocumentLengthExceededError';
}

View file

@ -14,6 +14,7 @@ import noteConfiguration, { NoteConfig } from '../config/note.config';
import { import {
AlreadyInDBError, AlreadyInDBError,
ForbiddenIdError, ForbiddenIdError,
MaximumDocumentLengthExceededError,
NotInDBError, NotInDBError,
} from '../errors/errors'; } from '../errors/errors';
import { NoteEvent } from '../events'; import { NoteEvent } from '../events';
@ -79,11 +80,12 @@ export class NotesService {
* @async * @async
* Create a new note. * Create a new note.
* @param {string} noteContent - the content the new note should have * @param {string} noteContent - the content the new note should have
* @param {string=} alias - a optional alias the note should have * @param {string=} alias - an optional alias the note should have
* @param {User=} owner - the owner of the note * @param {User=} owner - the owner of the note
* @return {Note} the newly created note * @return {Note} the newly created note
* @throws {AlreadyInDBError} a note with the requested id or alias already exists * @throws {AlreadyInDBError} a note with the requested id or alias already exists
* @throws {ForbiddenIdError} the requested id or alias is forbidden * @throws {ForbiddenIdError} the requested id or alias is forbidden
* @throws {MaximumDocumentLengthExceededError} the noteContent is longer than the maxDocumentLength
*/ */
async createNote( async createNote(
noteContent: string, noteContent: string,
@ -94,6 +96,9 @@ export class NotesService {
this.checkNoteIdOrAlias(alias); this.checkNoteIdOrAlias(alias);
} }
const newNote = Note.create(owner, alias); const newNote = Note.create(owner, alias);
if (noteContent.length > this.noteConfig.maxDocumentLength) {
throw new MaximumDocumentLengthExceededError();
}
//TODO: Calculate patch //TODO: Calculate patch
newNote.revisions = Promise.resolve([ newNote.revisions = Promise.resolve([
Revision.create(noteContent, noteContent, newNote as Note) as Revision, Revision.create(noteContent, noteContent, newNote as Note) as Revision,