From d49f8ec01369a39ebf643bee1ed841dcfedbdeb0 Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <fabio@manganiello.tech>
Date: Sun, 23 Mar 2025 23:44:20 +0100
Subject: [PATCH] Fixed `preRequestHandler` route setup.

The map is a static object defined on the root `Route` class.

This means that any changes made by its derived classes (e.g. by
specifying the `@authenticate` annotation on some methods) will impact
the object for all the other derived classes too.

To prevent clashes, the structure of the map has been changed from:

```
method -> preRequestHandler
```

to:

```
RouteClass.name -> method -> preRequestHandler
```
---
 src/auth.ts         | 6 +++++-
 src/routes/Route.ts | 7 ++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/auth.ts b/src/auth.ts
index 307f279..f5b45d8 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -18,7 +18,11 @@ class AuthInfo {
 function authenticate(roles: RoleName[] = []) {
   return function (route: any, method: string) {
     const routeClass = (<typeof Route> route.constructor);
-    routeClass.preRequestHandlers[method] = async (req: Request): Promise<AuthInfo> => {
+    if (!routeClass.preRequestHandlers[routeClass.name]) {
+      routeClass.preRequestHandlers[routeClass.name] = {}
+    }
+
+    routeClass.preRequestHandlers[routeClass.name][method] = async (req: Request): Promise<AuthInfo> => {
       let user: Optional<User>;
       let session: Optional<UserSession>;
 
diff --git a/src/routes/Route.ts b/src/routes/Route.ts
index 81da82d..d109fb7 100644
--- a/src/routes/Route.ts
+++ b/src/routes/Route.ts
@@ -14,8 +14,8 @@ import { logRequest } from '../helpers/logging';
 
 abstract class Route {
   protected readonly path: string;
-  // Method -> Handler mapping
-  public static preRequestHandlers: Record<string, RequestHandler> = {};
+  // Route -> Method -> Handler mapping
+  public static preRequestHandlers: Record<string, Record<string, RequestHandler>> = {};
 
   constructor(path: string) {
     this.path = path;
@@ -76,9 +76,10 @@ abstract class Route {
     logRequest(req);
 
     try {
+      const routeClass = <typeof Route> this.constructor;
       // @ts-expect-error
       const handler = (this[handlerName]) as ((req: Request, res: Response, auth: AuthInfo) => Promise<void>);
-      const preRequestHandler = (<typeof Route> this.constructor).preRequestHandlers[handlerName];
+      const preRequestHandler = routeClass.preRequestHandlers[routeClass.name]?.[handlerName];
 
       let authInfo: Optional<AuthInfo>
       if (preRequestHandler) {