mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2026-06-23 04:10:17 +00:00
feat(csrf): add decorator to exclude routes from CSRF protection
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
@@ -4,16 +4,30 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { CanActivate, ExecutionContext, Injectable, ForbiddenException } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
|
||||
import { CSRF_EXEMPT_KEY } from '../../utils/decorators/csrf-exempt.decorator';
|
||||
|
||||
const UNPROTECTED_METHODS = ['GET', 'HEAD', 'OPTIONS'];
|
||||
|
||||
@Injectable()
|
||||
export class CsrfGuard implements CanActivate {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||
const reply = context.switchToHttp().getResponse<FastifyReply>();
|
||||
|
||||
// Ignore if the @CsrfExempt() decorator is set for the route
|
||||
const isCsrfExempt = this.reflector.getAllAndOverride<boolean>(CSRF_EXEMPT_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (isCsrfExempt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ignore unprotected methods (GET, HEAD, OPTIONS)
|
||||
const method = request.method.toUpperCase();
|
||||
if (UNPROTECTED_METHODS.includes(method)) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
|
||||
export const CSRF_EXEMPT_KEY = 'csrf_exempt';
|
||||
|
||||
/**
|
||||
* Decorator to mark a route as exempt from CSRF protection.
|
||||
* Routes with this decorator won't be protected by CSRF protection. This is required for non-public-API endpoints
|
||||
* called from non-browsers, e.g. OIDC backchannel-logout.
|
||||
*/
|
||||
export const CsrfExempt = () => SetMetadata(CSRF_EXEMPT_KEY, true);
|
||||
Reference in New Issue
Block a user