diff --git a/src/api/private/alias/alias.controller.ts b/src/api/private/alias/alias.controller.ts index a359728e0..d32cc21cf 100644 --- a/src/api/private/alias/alias.controller.ts +++ b/src/api/private/alias/alias.controller.ts @@ -13,10 +13,9 @@ import { Param, Post, Put, - Req, UnauthorizedException, + UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { AlreadyInDBError, @@ -24,6 +23,7 @@ import { NotInDBError, PrimaryAliasDeletionForbiddenError, } from '../../../errors/errors'; +import { SessionGuard } from '../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { AliasCreateDto } from '../../../notes/alias-create.dto'; import { AliasUpdateDto } from '../../../notes/alias-update.dto'; @@ -31,8 +31,11 @@ import { AliasDto } from '../../../notes/alias.dto'; import { AliasService } from '../../../notes/alias.service'; import { NotesService } from '../../../notes/notes.service'; import { PermissionsService } from '../../../permissions/permissions.service'; +import { User } from '../../../users/user.entity'; import { UsersService } from '../../../users/users.service'; +import { RequestUser } from '../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @Controller('alias') export class AliasController { constructor( @@ -44,15 +47,12 @@ export class AliasController { ) { this.logger.setContext(AliasController.name); } - @Post() async addAlias( - @Req() req: Request, + @RequestUser() user: User, @Body() newAliasDto: AliasCreateDto, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); const note = await this.noteService.getNoteByIdOrAlias( newAliasDto.noteIdOrAlias, ); @@ -77,7 +77,7 @@ export class AliasController { @Put(':alias') async makeAliasPrimary( - @Req() req: Request, + @RequestUser() user: User, @Param('alias') alias: string, @Body() changeAliasDto: AliasUpdateDto, ): Promise { @@ -87,8 +87,6 @@ export class AliasController { ); } try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); const note = await this.noteService.getNoteByIdOrAlias(alias); if (!this.permissionsService.isOwner(user, note)) { throw new UnauthorizedException('Reading note denied!'); @@ -112,12 +110,10 @@ export class AliasController { @Delete(':alias') @HttpCode(204) async removeAlias( - @Req() req: Request, + @RequestUser() user: User, @Param('alias') alias: string, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); const note = await this.noteService.getNoteByIdOrAlias(alias); if (!this.permissionsService.isOwner(user, note)) { throw new UnauthorizedException('Reading note denied!'); diff --git a/src/api/private/me/history/history.controller.ts b/src/api/private/me/history/history.controller.ts index fdb098b4c..2bdedab36 100644 --- a/src/api/private/me/history/history.controller.ts +++ b/src/api/private/me/history/history.controller.ts @@ -13,6 +13,7 @@ import { Param, Post, Put, + UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -21,27 +22,27 @@ import { HistoryEntryImportDto } from '../../../../history/history-entry-import. import { HistoryEntryUpdateDto } from '../../../../history/history-entry-update.dto'; import { HistoryEntryDto } from '../../../../history/history-entry.dto'; import { HistoryService } from '../../../../history/history.service'; +import { SessionGuard } from '../../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../../logger/console-logger.service'; import { GetNotePipe } from '../../../../notes/get-note.pipe'; import { Note } from '../../../../notes/note.entity'; -import { UsersService } from '../../../../users/users.service'; +import { User } from '../../../../users/user.entity'; +import { RequestUser } from '../../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @ApiTags('history') @Controller('/me/history') export class HistoryController { constructor( private readonly logger: ConsoleLoggerService, private historyService: HistoryService, - private userService: UsersService, ) { this.logger.setContext(HistoryController.name); } @Get() - async getHistory(): Promise { - // ToDo: use actual user here + async getHistory(@RequestUser() user: User): Promise { try { - const user = await this.userService.getUserByUsername('hardcoded'); const foundEntries = await this.historyService.getEntriesByUser(user); return foundEntries.map((entry) => this.historyService.toHistoryEntryDto(entry), @@ -56,11 +57,10 @@ export class HistoryController { @Post() async setHistory( + @RequestUser() user: User, @Body('history') history: HistoryEntryImportDto[], ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); await this.historyService.setHistory(user, history); } catch (e) { if (e instanceof NotInDBError || e instanceof ForbiddenIdError) { @@ -71,10 +71,8 @@ export class HistoryController { } @Delete() - async deleteHistory(): Promise { + async deleteHistory(@RequestUser() user: User): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); await this.historyService.deleteHistory(user); } catch (e) { if (e instanceof NotInDBError) { @@ -87,11 +85,10 @@ export class HistoryController { @Put(':note') async updateHistoryEntry( @Param('note', GetNotePipe) note: Note, + @RequestUser() user: User, @Body() entryUpdateDto: HistoryEntryUpdateDto, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); const newEntry = await this.historyService.updateHistoryEntry( note, user, @@ -109,10 +106,9 @@ export class HistoryController { @Delete(':note') async deleteHistoryEntry( @Param('note', GetNotePipe) note: Note, + @RequestUser() user: User, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); await this.historyService.deleteHistoryEntry(note, user); } catch (e) { if (e instanceof NotInDBError) { diff --git a/src/api/private/me/me.controller.ts b/src/api/private/me/me.controller.ts index 78f090cc7..240d5b72b 100644 --- a/src/api/private/me/me.controller.ts +++ b/src/api/private/me/me.controller.ts @@ -3,14 +3,26 @@ * * SPDX-License-Identifier: AGPL-3.0-only */ -import { Body, Controller, Delete, Get, HttpCode, Post } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + HttpCode, + Post, + UseGuards, +} from '@nestjs/common'; +import { SessionGuard } from '../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { MediaUploadDto } from '../../../media/media-upload.dto'; import { MediaService } from '../../../media/media.service'; import { UserInfoDto } from '../../../users/user-info.dto'; +import { User } from '../../../users/user.entity'; import { UsersService } from '../../../users/users.service'; +import { RequestUser } from '../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @Controller('me') export class MeController { constructor( @@ -20,27 +32,20 @@ export class MeController { ) { this.logger.setContext(MeController.name); } - @Get() - async getMe(): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); + getMe(@RequestUser() user: User): UserInfoDto { return this.userService.toUserDto(user); } @Get('media') - async getMyMedia(): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); + async getMyMedia(@RequestUser() user: User): Promise { const media = await this.mediaService.listUploadsByUser(user); return media.map((media) => this.mediaService.toMediaUploadDto(media)); } @Delete() @HttpCode(204) - async deleteUser(): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); + async deleteUser(@RequestUser() user: User): Promise { const mediaUploads = await this.mediaService.listUploadsByUser(user); for (const mediaUpload of mediaUploads) { await this.mediaService.deleteFile(mediaUpload); @@ -52,9 +57,10 @@ export class MeController { @Post('profile') @HttpCode(200) - async updateDisplayName(@Body('name') newDisplayName: string): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); + async updateDisplayName( + @RequestUser() user: User, + @Body('name') newDisplayName: string, + ): Promise { await this.userService.changeDisplayName(user, newDisplayName); } } diff --git a/src/api/private/media/media.controller.ts b/src/api/private/media/media.controller.ts index 8db4e26f4..9c89eac31 100644 --- a/src/api/private/media/media.controller.ts +++ b/src/api/private/media/media.controller.ts @@ -11,6 +11,7 @@ import { InternalServerErrorException, Post, UploadedFile, + UseGuards, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; @@ -20,6 +21,7 @@ import { MediaBackendError, NotInDBError, } from '../../../errors/errors'; +import { SessionGuard } from '../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { MediaUploadUrlDto } from '../../../media/media-upload-url.dto'; import { MediaService } from '../../../media/media.service'; @@ -28,7 +30,9 @@ import { Note } from '../../../notes/note.entity'; import { NotesService } from '../../../notes/notes.service'; import { User } from '../../../users/user.entity'; import { UsersService } from '../../../users/users.service'; +import { RequestUser } from '../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @Controller('media') export class MediaController { constructor( @@ -46,9 +50,8 @@ export class MediaController { async uploadMedia( @UploadedFile() file: MulterFile, @Headers('HedgeDoc-Note') noteId: string, + @RequestUser() user: User, ): Promise { - // ToDo: Get real userName - const user: User = await this.userService.getUserByUsername('hardcoded'); try { // TODO: Move getting the Note object into a decorator const note: Note = await this.noteService.getNoteByIdOrAlias(noteId); diff --git a/src/api/private/notes/notes.controller.ts b/src/api/private/notes/notes.controller.ts index 6ab130701..6d087895b 100644 --- a/src/api/private/notes/notes.controller.ts +++ b/src/api/private/notes/notes.controller.ts @@ -14,6 +14,7 @@ import { Param, Post, UnauthorizedException, + UseGuards, } from '@nestjs/common'; import { @@ -22,6 +23,7 @@ import { NotInDBError, } from '../../../errors/errors'; import { HistoryService } from '../../../history/history.service'; +import { SessionGuard } from '../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { MediaUploadDto } from '../../../media/media-upload.dto'; import { MediaService } from '../../../media/media.service'; @@ -34,9 +36,12 @@ import { PermissionsService } from '../../../permissions/permissions.service'; import { RevisionMetadataDto } from '../../../revisions/revision-metadata.dto'; import { RevisionDto } from '../../../revisions/revision.dto'; import { RevisionsService } from '../../../revisions/revisions.service'; +import { User } from '../../../users/user.entity'; import { UsersService } from '../../../users/users.service'; import { MarkdownBody } from '../../utils/markdownbody-decorator'; +import { RequestUser } from '../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @Controller('notes') export class NotesController { constructor( @@ -53,10 +58,9 @@ export class NotesController { @Get(':noteIdOrAlias') async getNote( + @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.mayRead(user, note)) { throw new UnauthorizedException('Reading note denied!'); } @@ -67,10 +71,9 @@ export class NotesController { @Get(':noteIdOrAlias/media') async getNotesMedia( @Param('noteIdOrAlias', GetNotePipe) note: Note, + @RequestUser() user: User, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.mayRead(user, note)) { throw new UnauthorizedException('Reading note denied!'); } @@ -86,10 +89,10 @@ export class NotesController { @Post() @HttpCode(201) - async createNote(@MarkdownBody() text: string): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); - // ToDo: provide user for createNoteDto + async createNote( + @RequestUser() user: User, + @MarkdownBody() text: string, + ): Promise { if (!this.permissionsService.mayCreate(user)) { throw new UnauthorizedException('Creating note denied!'); } @@ -102,11 +105,10 @@ export class NotesController { @Post(':noteAlias') @HttpCode(201) async createNamedNote( + @RequestUser() user: User, @Param('noteAlias') noteAlias: string, @MarkdownBody() text: string, ): Promise { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.mayCreate(user)) { throw new UnauthorizedException('Creating note denied!'); } @@ -129,12 +131,11 @@ export class NotesController { @Delete(':noteIdOrAlias') @HttpCode(204) async deleteNote( + @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, @Body() noteMediaDeletionDto: NoteMediaDeletionDto, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.isOwner(user, note)) { throw new UnauthorizedException('Deleting note denied!'); } @@ -160,11 +161,10 @@ export class NotesController { @Get(':noteIdOrAlias/revisions') async getNoteRevisions( + @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.mayRead(user, note)) { throw new UnauthorizedException('Reading note denied!'); } @@ -185,11 +185,10 @@ export class NotesController { @Delete(':noteIdOrAlias/revisions') @HttpCode(204) async purgeNoteRevisions( + @RequestUser() user: User, @Param('noteIdOrAlias') noteIdOrAlias: string, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); const note = await this.noteService.getNoteByIdOrAlias(noteIdOrAlias); if (!this.permissionsService.mayRead(user, note)) { throw new UnauthorizedException('Reading note denied!'); @@ -217,12 +216,11 @@ export class NotesController { @Get(':noteIdOrAlias/revisions/:revisionId') async getNoteRevision( + @RequestUser() user: User, @Param('noteIdOrAlias', GetNotePipe) note: Note, @Param('revisionId') revisionId: number, ): Promise { try { - // ToDo: use actual user here - const user = await this.userService.getUserByUsername('hardcoded'); if (!this.permissionsService.mayRead(user, note)) { throw new UnauthorizedException('Reading note denied!'); } diff --git a/src/api/private/tokens/tokens.controller.spec.ts b/src/api/private/tokens/tokens.controller.spec.ts index 56ecfd57e..3d2118860 100644 --- a/src/api/private/tokens/tokens.controller.spec.ts +++ b/src/api/private/tokens/tokens.controller.spec.ts @@ -14,6 +14,7 @@ import { Identity } from '../../../identity/identity.entity'; import { LoggerModule } from '../../../logger/logger.module'; import { Session } from '../../../users/session.entity'; import { User } from '../../../users/user.entity'; +import { UsersModule } from '../../../users/users.module'; import { TokensController } from './tokens.controller'; describe('TokensController', () => { @@ -29,6 +30,7 @@ describe('TokensController', () => { }), LoggerModule, AuthModule, + UsersModule, ], }) .overrideProvider(getRepositoryToken(User)) diff --git a/src/api/private/tokens/tokens.controller.ts b/src/api/private/tokens/tokens.controller.ts index 9271953bc..d634be650 100644 --- a/src/api/private/tokens/tokens.controller.ts +++ b/src/api/private/tokens/tokens.controller.ts @@ -9,17 +9,25 @@ import { Delete, Get, HttpCode, + NotFoundException, Param, Post, + UnauthorizedException, + UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { AuthTokenWithSecretDto } from '../../../auth/auth-token-with-secret.dto'; import { AuthTokenDto } from '../../../auth/auth-token.dto'; import { AuthService } from '../../../auth/auth.service'; +import { NotInDBError } from '../../../errors/errors'; +import { SessionGuard } from '../../../identity/session.guard'; import { ConsoleLoggerService } from '../../../logger/console-logger.service'; +import { User } from '../../../users/user.entity'; import { TimestampMillis } from '../../../utils/timestamp'; +import { RequestUser } from '../../utils/request-user.decorator'; +@UseGuards(SessionGuard) @ApiTags('tokens') @Controller('tokens') export class TokensController { @@ -31,9 +39,8 @@ export class TokensController { } @Get() - async getUserTokens(): Promise { - // ToDo: Get real userName - return (await this.authService.getTokensByUsername('hardcoded')).map( + async getUserTokens(@RequestUser() user: User): Promise { + return (await this.authService.getTokensByUsername(user.userName)).map( (token) => this.authService.toAuthTokenDto(token), ); } @@ -42,10 +49,10 @@ export class TokensController { async postTokenRequest( @Body('label') label: string, @Body('validUntil') validUntil: TimestampMillis, + @RequestUser() user: User, ): Promise { - // ToDo: Get real userName return await this.authService.createTokenForUser( - 'hardcoded', + user.userName, label, validUntil, ); @@ -53,7 +60,24 @@ export class TokensController { @Delete('/:keyId') @HttpCode(204) - async deleteToken(@Param('keyId') keyId: string): Promise { - return await this.authService.removeToken(keyId); + async deleteToken( + @RequestUser() user: User, + @Param('keyId') keyId: string, + ): Promise { + const tokens = await this.authService.getTokensByUsername(user.userName); + try { + for (const token of tokens) { + if (token.keyId == keyId) { + return await this.authService.removeToken(keyId); + } + } + } catch (e) { + if (e instanceof NotInDBError) { + throw new NotFoundException(e.message); + } + } + throw new UnauthorizedException( + 'User is not authorized to delete this token', + ); } }