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)); }