mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-06-04 08:49:59 -04:00
feat(auth): add guest login
Co-authored-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
04d19ebfbc
commit
167135a8d0
9 changed files with 87 additions and 19 deletions
|
@ -40,7 +40,9 @@ export class ApiTokensController {
|
|||
|
||||
@Get()
|
||||
@OpenApi(200)
|
||||
async getUserTokens(@RequestUserId() userId: number): Promise<ApiTokenDto[]> {
|
||||
async getUserTokens(
|
||||
@RequestUserId({ forbidGuests: true }) userId: number,
|
||||
): Promise<ApiTokenDto[]> {
|
||||
return (await this.apiTokenService.getTokensOfUserById(userId)).map(
|
||||
(token) => this.apiTokenService.toAuthTokenDto(token),
|
||||
);
|
||||
|
@ -50,7 +52,7 @@ export class ApiTokensController {
|
|||
@OpenApi(201)
|
||||
async postTokenRequest(
|
||||
@Body() createDto: ApiTokenCreateDto,
|
||||
@RequestUserId() userId: User[FieldNameUser.id],
|
||||
@RequestUserId({ forbidGuests: true }) userId: User[FieldNameUser.id],
|
||||
): Promise<ApiTokenWithSecretDto> {
|
||||
return await this.apiTokenService.createToken(
|
||||
userId,
|
||||
|
@ -62,7 +64,7 @@ export class ApiTokensController {
|
|||
@Delete('/:keyId')
|
||||
@OpenApi(204, 404)
|
||||
async deleteToken(
|
||||
@RequestUserId() userId: number,
|
||||
@RequestUserId({ forbidGuests: true }) userId: number,
|
||||
@Param('keyId') keyId: string,
|
||||
): Promise<void> {
|
||||
await this.apiTokenService.removeToken(keyId, userId);
|
||||
|
|
|
@ -66,7 +66,7 @@ export class MeController {
|
|||
@Put('profile')
|
||||
@OpenApi(200)
|
||||
async updateProfile(
|
||||
@RequestUserId() userId: number,
|
||||
@RequestUserId({ forbidGuests: true }) userId: number,
|
||||
@Body('displayName') newDisplayName: string,
|
||||
): Promise<void> {
|
||||
await this.userService.updateUser(
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { SessionGuard } from '../../../auth/session.guard';
|
||||
import { NotInDBError } from '../../../errors/errors';
|
||||
import { NotInDBError, PermissionError } from '../../../errors/errors';
|
||||
import { GroupsService } from '../../../groups/groups.service';
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { MediaService } from '../../../media/media.service';
|
||||
|
@ -70,10 +70,7 @@ export class NotesController {
|
|||
@OpenApi(200)
|
||||
@RequirePermission(RequiredPermission.READ)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
async getNote(
|
||||
@RequestUserId({ guestsAllowed: true }) userId: number,
|
||||
@RequestNoteId() noteId: number,
|
||||
): Promise<NoteDto> {
|
||||
async getNote(@RequestNoteId() noteId: number): Promise<NoteDto> {
|
||||
return await this.noteService.toNoteDto(noteId);
|
||||
}
|
||||
|
||||
|
@ -92,7 +89,7 @@ export class NotesController {
|
|||
@OpenApi(201, 413)
|
||||
@RequirePermission(RequiredPermission.CREATE)
|
||||
async createNote(
|
||||
@RequestUserId({ guestsAllowed: true }) userId: number,
|
||||
@RequestUserId() userId: number,
|
||||
@MarkdownBody() text: string,
|
||||
): Promise<NoteDto> {
|
||||
const createdNoteId = await this.noteService.createNote(text, userId);
|
||||
|
@ -103,7 +100,7 @@ export class NotesController {
|
|||
@OpenApi(201, 400, 404, 409, 413)
|
||||
@RequirePermission(RequiredPermission.CREATE)
|
||||
async createNamedNote(
|
||||
@RequestUserId({ guestsAllowed: true }) userId: number,
|
||||
@RequestUserId() userId: number,
|
||||
@Param('noteAlias') noteAlias: string,
|
||||
@MarkdownBody() text: string,
|
||||
): Promise<NoteDto> {
|
||||
|
@ -124,6 +121,12 @@ export class NotesController {
|
|||
@RequestNoteId() noteId: number,
|
||||
@Body() noteMediaDeletionDto: NoteMediaDeletionDto,
|
||||
): Promise<void> {
|
||||
const isOwner = await this.permissionService.isOwner(userId, noteId);
|
||||
if (!isOwner) {
|
||||
throw new PermissionError(
|
||||
'You do not have the permission to delete this note.',
|
||||
);
|
||||
}
|
||||
const mediaUploads =
|
||||
await this.mediaService.getMediaUploadUuidsByNoteId(noteId);
|
||||
for (const mediaUpload of mediaUploads) {
|
||||
|
@ -141,7 +144,6 @@ export class NotesController {
|
|||
@RequirePermission(RequiredPermission.READ)
|
||||
@Get(':noteAlias/metadata')
|
||||
async getNoteMetadata(
|
||||
@RequestUserId({ guestsAllowed: true }) userId: number,
|
||||
@RequestNoteId() noteId: number,
|
||||
): Promise<NoteMetadataDto> {
|
||||
return await this.noteService.toNoteMetadataDto(noteId);
|
||||
|
@ -152,7 +154,6 @@ export class NotesController {
|
|||
@RequirePermission(RequiredPermission.READ)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
async getNoteRevisions(
|
||||
@RequestUserId({ guestsAllowed: true }) userId: number,
|
||||
@RequestNoteId() noteId: number,
|
||||
): Promise<RevisionMetadataDto[]> {
|
||||
return await this.revisionsService.getAllRevisionMetadataDto(noteId);
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
import { CompleteRequest } from '../request.type';
|
||||
|
||||
type RequestUserIdParameter = {
|
||||
guestsAllowed: boolean;
|
||||
forbidGuests: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -26,14 +26,13 @@ type RequestUserIdParameter = {
|
|||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const RequestUserId = createParamDecorator(
|
||||
(
|
||||
data: RequestUserIdParameter = { guestsAllowed: false },
|
||||
data: RequestUserIdParameter = { forbidGuests: false },
|
||||
ctx: ExecutionContext,
|
||||
) => {
|
||||
const request: CompleteRequest = ctx.switchToHttp().getRequest();
|
||||
if (
|
||||
!request.authProviderType ||
|
||||
(request.authProviderType === AuthProviderType.GUEST &&
|
||||
!data.guestsAllowed)
|
||||
(request.authProviderType === AuthProviderType.GUEST && data.forbidGuests)
|
||||
) {
|
||||
throw new UnauthorizedException("You're not logged in");
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export const forbiddenDescription =
|
|||
'Access to the requested resource is not permitted';
|
||||
export const notFoundDescription = 'The requested resource was not found';
|
||||
export const successfullyDeletedDescription =
|
||||
'The requested resource was sucessfully deleted';
|
||||
'The requested resource was successfully deleted';
|
||||
export const unprocessableEntityDescription =
|
||||
"The request change can't be processed";
|
||||
export const conflictDescription =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue