mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-04-16 01:27:13 +00:00
fix: add CompleteRequest type to have better type checks for HTTP-Request attribute injection.
Signed-off-by: Yannick Bungers <git@innay.de> Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
0263c09ce1
commit
d369132519
10 changed files with 34 additions and 38 deletions
|
@ -9,12 +9,11 @@ import {
|
|||
Injectable,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Note } from '../../notes/note.entity';
|
||||
import { NotesService } from '../../notes/notes.service';
|
||||
import { User } from '../../users/user.entity';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
/**
|
||||
* Saves the note identified by the `noteIdOrAlias` URL parameter
|
||||
|
@ -28,9 +27,7 @@ export class GetNoteInterceptor implements NestInterceptor {
|
|||
context: ExecutionContext,
|
||||
next: CallHandler,
|
||||
): Promise<Observable<T>> {
|
||||
const request: Request & { user: User; note: Note } = context
|
||||
.switchToHttp()
|
||||
.getRequest();
|
||||
const request: CompleteRequest = context.switchToHttp().getRequest();
|
||||
const noteIdOrAlias = request.params['noteIdOrAlias'];
|
||||
request.note = await getNote(this.noteService, noteIdOrAlias);
|
||||
return next.handle();
|
||||
|
|
|
@ -9,11 +9,10 @@ import {
|
|||
Injectable,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Note } from '../../notes/note.entity';
|
||||
import { NotesService } from '../../notes/notes.service';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
/**
|
||||
* Saves the note identified by the `HedgeDoc-Note` header
|
||||
|
@ -27,9 +26,7 @@ export class NoteHeaderInterceptor implements NestInterceptor {
|
|||
context: ExecutionContext,
|
||||
next: CallHandler,
|
||||
): Promise<Observable<T>> {
|
||||
const request: Request & {
|
||||
note: Note;
|
||||
} = context.switchToHttp().getRequest();
|
||||
const request: CompleteRequest = context.switchToHttp().getRequest();
|
||||
const noteId: string = request.headers['hedgedoc-note'] as string;
|
||||
request.note = await this.noteService.getNoteByIdOrAlias(noteId);
|
||||
return next.handle();
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
*/
|
||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { NotesService } from '../../notes/notes.service';
|
||||
import { Permission } from '../../permissions/permissions.enum';
|
||||
import { PermissionsService } from '../../permissions/permissions.service';
|
||||
import { User } from '../../users/user.entity';
|
||||
import { getNote } from './get-note.interceptor';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
/**
|
||||
* This guards controller methods from access, if the user has not the appropriate permissions.
|
||||
|
@ -41,10 +40,8 @@ export class PermissionsGuard implements CanActivate {
|
|||
);
|
||||
return false;
|
||||
}
|
||||
const request: Request & { user: User } = context
|
||||
.switchToHttp()
|
||||
.getRequest();
|
||||
const user = request.user;
|
||||
const request: CompleteRequest = context.switchToHttp().getRequest();
|
||||
const user = request.user ?? null;
|
||||
// handle CREATE permissions, as this does not need any note
|
||||
if (permissions[0] === Permission.CREATE) {
|
||||
return this.permissionsService.mayCreate(user);
|
||||
|
|
|
@ -8,9 +8,8 @@ import {
|
|||
ExecutionContext,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { Note } from '../../notes/note.entity';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
/**
|
||||
* Extracts the {@link Note} object from a request
|
||||
|
@ -20,7 +19,7 @@ import { Note } from '../../notes/note.entity';
|
|||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const RequestNote = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
const request: Request & { note: Note } = ctx.switchToHttp().getRequest();
|
||||
const request: CompleteRequest = ctx.switchToHttp().getRequest();
|
||||
if (!request.note) {
|
||||
// We should have a note here, otherwise something is wrong
|
||||
throw new InternalServerErrorException(
|
||||
|
|
|
@ -8,9 +8,8 @@ import {
|
|||
ExecutionContext,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { User } from '../../users/user.entity';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
type RequestUserParameter = {
|
||||
guestsAllowed: boolean;
|
||||
|
@ -29,9 +28,7 @@ export const RequestUser = createParamDecorator(
|
|||
data: RequestUserParameter = { guestsAllowed: false },
|
||||
ctx: ExecutionContext,
|
||||
) => {
|
||||
const request: Request & { user: User | null } = ctx
|
||||
.switchToHttp()
|
||||
.getRequest();
|
||||
const request: CompleteRequest = ctx.switchToHttp().getRequest();
|
||||
if (!request.user) {
|
||||
if (data.guestsAllowed) {
|
||||
return null;
|
||||
|
|
16
backend/src/api/utils/request.type.ts
Normal file
16
backend/src/api/utils/request.type.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Request } from 'express';
|
||||
|
||||
import { Note } from '../../notes/note.entity';
|
||||
import { SessionState } from '../../session/session.service';
|
||||
import { User } from '../../users/user.entity';
|
||||
|
||||
export type CompleteRequest = Request & {
|
||||
user?: User;
|
||||
note?: Note;
|
||||
session?: SessionState;
|
||||
};
|
|
@ -8,9 +8,8 @@ import {
|
|||
ExecutionContext,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { SessionState } from '../../session/session.service';
|
||||
import { CompleteRequest } from './request.type';
|
||||
|
||||
/**
|
||||
* Extracts the auth provider identifier from a session inside a request
|
||||
|
@ -20,9 +19,7 @@ import { SessionState } from '../../session/session.service';
|
|||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const SessionAuthProvider = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
const request: Request & {
|
||||
session: SessionState;
|
||||
} = ctx.switchToHttp().getRequest();
|
||||
const request: CompleteRequest = ctx.switchToHttp().getRequest();
|
||||
if (!request.session?.authProvider) {
|
||||
// We should have an auth provider here, otherwise something is wrong
|
||||
throw new InternalServerErrorException(
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ExecutionContext, Injectable } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { CompleteRequest } from '../api/utils/request.type';
|
||||
import { User } from '../users/user.entity';
|
||||
import { UsersService } from '../users/users.service';
|
||||
|
||||
|
@ -16,7 +16,7 @@ export class MockAuthGuard {
|
|||
constructor(private usersService: UsersService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const req: Request = context.switchToHttp().getRequest();
|
||||
const req: CompleteRequest = context.switchToHttp().getRequest();
|
||||
if (!this.user) {
|
||||
// this assures that we can create the user 'hardcoded', if we need them before any calls are made or
|
||||
// create them on the fly when the first call to the api is made
|
||||
|
|
|
@ -11,12 +11,11 @@ import {
|
|||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { CompleteRequest } from '../api/utils/request.type';
|
||||
import { GuestAccess } from '../config/guest_access.enum';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import { NotInDBError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { SessionState } from '../session/session.service';
|
||||
import { User } from '../users/user.entity';
|
||||
import { UsersService } from '../users/users.service';
|
||||
|
||||
/**
|
||||
|
@ -39,10 +38,7 @@ export class SessionGuard implements CanActivate {
|
|||
}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request: Request & {
|
||||
session?: SessionState;
|
||||
user?: User;
|
||||
} = context.switchToHttp().getRequest();
|
||||
const request: CompleteRequest = context.switchToHttp().getRequest();
|
||||
const username = request.session?.username;
|
||||
if (!username) {
|
||||
if (this.noteConfig.guestAccess !== GuestAccess.DENY && request.session) {
|
||||
|
|
|
@ -79,7 +79,7 @@ export class PermissionsService {
|
|||
* @return if the user is allowed to create notes
|
||||
*/
|
||||
public mayCreate(user: User | null): boolean {
|
||||
return user !== null || this.noteConfig.guestAccess === GuestAccess.CREATE;
|
||||
return !!user || this.noteConfig.guestAccess === GuestAccess.CREATE;
|
||||
}
|
||||
|
||||
async isOwner(user: User | null, note: Note): Promise<boolean> {
|
||||
|
|
Loading…
Add table
Reference in a new issue