From d27c531d9ae20e0317a60623bd0ccd9a0e56d915 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Sun, 21 Nov 2021 17:19:57 +0100 Subject: [PATCH] refactor: move permissions service calls into permissions guard This commit removes all previous calls to the permissions service at the beginning of the controller methods to the permissions guard. This should make the code a bit cleaner and remove boilerplate code. Signed-off-by: Philip Molares --- src/api/private/notes/notes.controller.ts | 47 ++++++--------- src/api/public/notes/notes.controller.ts | 73 ++++++++--------------- 2 files changed, 44 insertions(+), 76 deletions(-) diff --git a/src/api/private/notes/notes.controller.ts b/src/api/private/notes/notes.controller.ts index c7007c878..4d38ff561 100644 --- a/src/api/private/notes/notes.controller.ts +++ b/src/api/private/notes/notes.controller.ts @@ -13,7 +13,6 @@ import { NotFoundException, Param, Post, - UnauthorizedException, UseGuards, } from '@nestjs/common'; @@ -31,7 +30,8 @@ import { NoteDto } from '../../../notes/note.dto'; import { Note } from '../../../notes/note.entity'; import { NoteMediaDeletionDto } from '../../../notes/note.media-deletion.dto'; import { NotesService } from '../../../notes/notes.service'; -import { PermissionsService } from '../../../permissions/permissions.service'; +import { Permissions } from '../../../permissions/permissions.decorator'; +import { Permission } from '../../../permissions/permissions.enum'; import { RevisionMetadataDto } from '../../../revisions/revision-metadata.dto'; import { RevisionDto } from '../../../revisions/revision.dto'; import { RevisionsService } from '../../../revisions/revisions.service'; @@ -39,6 +39,7 @@ import { User } from '../../../users/user.entity'; import { UsersService } from '../../../users/users.service'; import { GetNotePipe } from '../../utils/get-note.pipe'; import { MarkdownBody } from '../../utils/markdownbody-decorator'; +import { PermissionsGuard } from '../../utils/permissions.guard'; import { RequestUser } from '../../utils/request-user.decorator'; @UseGuards(SessionGuard) @@ -47,7 +48,6 @@ export class NotesController { constructor( private readonly logger: ConsoleLoggerService, private noteService: NotesService, - private permissionsService: PermissionsService, private historyService: HistoryService, private userService: UsersService, private mediaService: MediaService, @@ -57,38 +57,34 @@ export class NotesController { } @Get(':noteIdOrAlias') + @Permissions(Permission.READ) + @UseGuards(PermissionsGuard) async getNote( @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } await this.historyService.updateHistoryEntryTimestamp(note, user); return await this.noteService.toNoteDto(note); } @Get(':noteIdOrAlias/media') + @Permissions(Permission.READ) + @UseGuards(PermissionsGuard) async getNotesMedia( @Param('noteIdOrAlias', GetNotePipe) note: Note, - @RequestUser() user: User, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } const media = await this.mediaService.listUploadsByNote(note); return media.map((media) => this.mediaService.toMediaUploadDto(media)); } @Post() @HttpCode(201) + @Permissions(Permission.CREATE) + @UseGuards(PermissionsGuard) async createNote( @RequestUser() user: User, @MarkdownBody() text: string, ): Promise { - if (!this.permissionsService.mayCreate(user)) { - throw new UnauthorizedException('Creating note denied!'); - } this.logger.debug('Got raw markdown:\n' + text); return await this.noteService.toNoteDto( await this.noteService.createNote(text, user), @@ -97,14 +93,13 @@ export class NotesController { @Post(':noteAlias') @HttpCode(201) + @Permissions(Permission.CREATE) + @UseGuards(PermissionsGuard) async createNamedNote( @RequestUser() user: User, @Param('noteAlias') noteAlias: string, @MarkdownBody() text: string, ): Promise { - if (!this.permissionsService.mayCreate(user)) { - throw new UnauthorizedException('Creating note denied!'); - } this.logger.debug('Got raw markdown:\n' + text, 'createNamedNote'); try { return await this.noteService.toNoteDto( @@ -123,14 +118,13 @@ export class NotesController { @Delete(':noteIdOrAlias') @HttpCode(204) + @Permissions(Permission.OWNER) + @UseGuards(PermissionsGuard) async deleteNote( @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, @Body() noteMediaDeletionDto: NoteMediaDeletionDto, ): Promise { - if (!this.permissionsService.isOwner(user, note)) { - throw new UnauthorizedException('Deleting note denied!'); - } const mediaUploads = await this.mediaService.listUploadsByNote(note); for (const mediaUpload of mediaUploads) { if (!noteMediaDeletionDto.keepMedia) { @@ -146,13 +140,12 @@ export class NotesController { } @Get(':noteIdOrAlias/revisions') + @Permissions(Permission.READ) + @UseGuards(PermissionsGuard) async getNoteRevisions( @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } const revisions = await this.revisionsService.getAllRevisions(note); return await Promise.all( revisions.map((revision) => @@ -163,13 +156,12 @@ export class NotesController { @Delete(':noteIdOrAlias/revisions') @HttpCode(204) + @Permissions(Permission.READ) + @UseGuards(PermissionsGuard) async purgeNoteRevisions( @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } this.logger.debug( 'Purging history of note: ' + note.id, 'purgeNoteRevisions', @@ -183,15 +175,14 @@ export class NotesController { } @Get(':noteIdOrAlias/revisions/:revisionId') + @Permissions(Permission.READ) + @UseGuards(PermissionsGuard) async getNoteRevision( @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, @Param('revisionId') revisionId: number, ): Promise { try { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } return this.revisionsService.toRevisionDto( await this.revisionsService.getRevision(note, revisionId), ); diff --git a/src/api/public/notes/notes.controller.ts b/src/api/public/notes/notes.controller.ts index 49583e92c..fc4ccdf63 100644 --- a/src/api/public/notes/notes.controller.ts +++ b/src/api/public/notes/notes.controller.ts @@ -15,7 +15,6 @@ import { Param, Post, Put, - UnauthorizedException, UseGuards, } from '@nestjs/common'; import { @@ -48,7 +47,8 @@ import { NoteDto } from '../../../notes/note.dto'; import { Note } from '../../../notes/note.entity'; import { NoteMediaDeletionDto } from '../../../notes/note.media-deletion.dto'; import { NotesService } from '../../../notes/notes.service'; -import { PermissionsService } from '../../../permissions/permissions.service'; +import { Permissions } from '../../../permissions/permissions.decorator'; +import { Permission } from '../../../permissions/permissions.enum'; import { RevisionMetadataDto } from '../../../revisions/revision-metadata.dto'; import { RevisionDto } from '../../../revisions/revision.dto'; import { RevisionsService } from '../../../revisions/revisions.service'; @@ -61,6 +61,7 @@ import { import { FullApi } from '../../utils/fullapi-decorator'; import { GetNotePipe } from '../../utils/get-note.pipe'; import { MarkdownBody } from '../../utils/markdownbody-decorator'; +import { PermissionsGuard } from '../../utils/permissions.guard'; import { RequestUser } from '../../utils/request-user.decorator'; @ApiTags('notes') @@ -71,14 +72,14 @@ export class NotesController { private readonly logger: ConsoleLoggerService, private noteService: NotesService, private revisionsService: RevisionsService, - private permissionsService: PermissionsService, private historyService: HistoryService, private mediaService: MediaService, ) { this.logger.setContext(NotesController.name); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.CREATE) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Post() @HttpCode(201) @ApiUnauthorizedResponse({ description: unauthorizedDescription }) @@ -87,17 +88,14 @@ export class NotesController { @RequestUser() user: User, @MarkdownBody() text: string, ): Promise { - // ToDo: provide user for createNoteDto - if (!this.permissionsService.mayCreate(user)) { - throw new UnauthorizedException('Creating note denied!'); - } this.logger.debug('Got raw markdown:\n' + text); return await this.noteService.toNoteDto( await this.noteService.createNote(text, user), ); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias') @ApiOkResponse({ description: 'Get information about the newly created note', @@ -108,14 +106,12 @@ export class NotesController { @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } await this.historyService.updateHistoryEntryTimestamp(note, user); return await this.noteService.toNoteDto(note); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.CREATE) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Post(':noteAlias') @HttpCode(201) @ApiCreatedResponse({ @@ -129,9 +125,6 @@ export class NotesController { @Param('noteAlias') noteAlias: string, @MarkdownBody() text: string, ): Promise { - if (!this.permissionsService.mayCreate(user)) { - throw new UnauthorizedException('Creating note denied!'); - } this.logger.debug('Got raw markdown:\n' + text, 'createNamedNote'); try { return await this.noteService.toNoteDto( @@ -148,7 +141,8 @@ export class NotesController { } } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.OWNER) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Delete(':noteIdOrAlias') @HttpCode(204) @ApiNoContentResponse({ description: successfullyDeletedDescription }) @@ -158,9 +152,6 @@ export class NotesController { @Param('noteIdOrAlias', GetNotePipe) note: Note, @Body() noteMediaDeletionDto: NoteMediaDeletionDto, ): Promise { - if (!this.permissionsService.isOwner(user, note)) { - throw new UnauthorizedException('Deleting note denied!'); - } const mediaUploads = await this.mediaService.listUploadsByNote(note); for (const mediaUpload of mediaUploads) { if (!noteMediaDeletionDto.keepMedia) { @@ -175,7 +166,8 @@ export class NotesController { return; } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.WRITE) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Put(':noteIdOrAlias') @ApiOkResponse({ description: 'The new, changed note', @@ -187,16 +179,14 @@ export class NotesController { @Param('noteIdOrAlias', GetNotePipe) note: Note, @MarkdownBody() text: string, ): Promise { - if (!this.permissionsService.mayWrite(user, note)) { - throw new UnauthorizedException('Updating note denied!'); - } this.logger.debug('Got raw markdown:\n' + text, 'updateNote'); return await this.noteService.toNoteDto( await this.noteService.updateNote(note, text), ); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias/content') @ApiProduces('text/markdown') @ApiOkResponse({ @@ -208,13 +198,11 @@ export class NotesController { @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } return await this.noteService.getNoteContent(note); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias/metadata') @ApiOkResponse({ description: 'The metadata of the note', @@ -225,13 +213,11 @@ export class NotesController { @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } return await this.noteService.toNoteMetadataDto(note); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.OWNER) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Put(':noteIdOrAlias/metadata/permissions') @ApiOkResponse({ description: 'The updated permissions of the note', @@ -243,15 +229,13 @@ export class NotesController { @Param('noteIdOrAlias', GetNotePipe) note: Note, @Body() updateDto: NotePermissionsUpdateDto, ): Promise { - if (!this.permissionsService.isOwner(user, note)) { - throw new UnauthorizedException('Updating note denied!'); - } return this.noteService.toNotePermissionsDto( await this.noteService.updateNotePermissions(note, updateDto), ); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias/revisions') @ApiOkResponse({ description: 'Revisions of the note', @@ -263,9 +247,6 @@ export class NotesController { @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } const revisions = await this.revisionsService.getAllRevisions(note); return await Promise.all( revisions.map((revision) => @@ -274,7 +255,8 @@ export class NotesController { ); } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias/revisions/:revisionId') @ApiOkResponse({ description: 'Revision of the note for the given id or alias', @@ -286,9 +268,6 @@ export class NotesController { @Param('noteIdOrAlias', GetNotePipe) note: Note, @Param('revisionId') revisionId: number, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } try { return this.revisionsService.toRevisionDto( await this.revisionsService.getRevision(note, revisionId), @@ -301,7 +280,8 @@ export class NotesController { } } - @UseGuards(TokenAuthGuard) + @Permissions(Permission.READ) + @UseGuards(TokenAuthGuard, PermissionsGuard) @Get(':noteIdOrAlias/media') @ApiOkResponse({ description: 'All media uploads of the note', @@ -313,9 +293,6 @@ export class NotesController { @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - if (!this.permissionsService.mayRead(user, note)) { - throw new UnauthorizedException('Reading note denied!'); - } const media = await this.mediaService.listUploadsByNote(note); return media.map((media) => this.mediaService.toMediaUploadDto(media)); }