From e907ab8cc09e5c98c1ed5f0a862fe08c8fd70327 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Minelli?= <michael@minelli.me>
Date: Mon, 31 Jul 2023 23:45:07 +0200
Subject: [PATCH] Add Exercice authentification by secret

---
 ExpressAPI/src/controllers/Session.ts         | 26 ++++++++++---------
 ExpressAPI/src/managers/ExerciceManager.ts    | 18 +++++++++++++
 .../src/middlewares/ParamsCallbackManager.ts  | 10 ++++++-
 .../src/middlewares/SecurityMiddleware.ts     | 10 ++++---
 ExpressAPI/src/types/ApiRequest.ts            |  8 +++---
 ExpressAPI/src/types/SecurityCheckType.ts     |  1 +
 6 files changed, 52 insertions(+), 21 deletions(-)
 create mode 100644 ExpressAPI/src/managers/ExerciceManager.ts

diff --git a/ExpressAPI/src/controllers/Session.ts b/ExpressAPI/src/controllers/Session.ts
index 3abcc18..b8f9f18 100644
--- a/ExpressAPI/src/controllers/Session.ts
+++ b/ExpressAPI/src/controllers/Session.ts
@@ -5,7 +5,7 @@ import Config              from '../config/Config';
 import express             from 'express';
 import ApiRequest          from '../types/ApiRequest';
 import UserManager         from '../managers/UserManager';
-import DojoResponse        from '../shared/types/DojoResponse';
+import DojoResponse        from '../shared/types/Dojo/DojoResponse';
 import { User }            from '../types/DatabaseTypes';
 
 
@@ -26,21 +26,23 @@ class Session {
     async initSession(req: ApiRequest) {
         const authorization = req.headers.authorization;
         if ( authorization ) {
-            const jwtToken = authorization.replace('Bearer ', '');
-
-            try {
-                const jwtData = jwt.verify(jwtToken, Config.jwtConfig.secret) as JwtPayload;
-
-                if ( jwtData.profile ) {
-                    this.profile = jwtData.profile;
-                    this.profile = await UserManager.getById(this.profile.id);
-                }
-            } catch ( err ) { }
+            if ( authorization.startsWith('Bearer ') ) {
+                const jwtToken = authorization.replace('Bearer ', '');
+
+                try {
+                    const jwtData = jwt.verify(jwtToken, Config.jwtConfig.secret) as JwtPayload;
+
+                    if ( jwtData.profile ) {
+                        this.profile = jwtData.profile;
+                        this.profile = await UserManager.getById(this.profile.id);
+                    }
+                } catch ( err ) { }
+            }
         }
     }
 
     private static getToken(profileJson: any): string {
-        return profileJson.id === null ? null : jwt.sign({ profile: profileJson }, Config.jwtConfig.secret, Config.jwtConfig.expiresIn > 0 ? { expiresIn: Config.jwtConfig.expiresIn } : {});
+        return profileJson === null ? null : jwt.sign({ profile: profileJson }, Config.jwtConfig.secret, Config.jwtConfig.expiresIn > 0 ? { expiresIn: Config.jwtConfig.expiresIn } : {});
     }
 
     private async getResponse<T>(code: number, data: T, descriptionOverride?: string): Promise<DojoResponse<T>> {
diff --git a/ExpressAPI/src/managers/ExerciceManager.ts b/ExpressAPI/src/managers/ExerciceManager.ts
new file mode 100644
index 0000000..489a6e6
--- /dev/null
+++ b/ExpressAPI/src/managers/ExerciceManager.ts
@@ -0,0 +1,18 @@
+import { Prisma } from '@prisma/client';
+import { Enonce } from '../types/DatabaseTypes';
+import db         from '../helpers/DatabaseHelper';
+
+
+class ExerciceManager {
+    get(id: string, include: Prisma.ExerciceInclude | undefined = undefined): Promise<Enonce | undefined> {
+        return db.exercice.findUnique({
+                                          where  : {
+                                              id: id
+                                          },
+                                          include: include
+                                      });
+    }
+}
+
+
+export default new ExerciceManager();
diff --git a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
index c0ccb39..358da8a 100644
--- a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
+++ b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
@@ -3,6 +3,7 @@ import ApiRequest      from '../types/ApiRequest';
 import express         from 'express';
 import { StatusCodes } from 'http-status-codes';
 import EnonceManager   from '../managers/EnonceManager';
+import ExerciceManager from '../managers/ExerciceManager';
 
 
 class ParamsCallbackManager {
@@ -24,7 +25,8 @@ class ParamsCallbackManager {
     initBoundParams(req: ApiRequest) {
         if ( !req.boundParams ) {
             req.boundParams = {
-                enonce: null
+                enonce  : null,
+                exercice: null
             };
         }
     }
@@ -34,6 +36,12 @@ class ParamsCallbackManager {
             exercices: true,
             staff    : true
         } ], 'enonce');
+
+        this.listenParam('exerciceId', backend, ExerciceManager.get.bind(ExerciceManager), [ {
+            enonce : true,
+            members: true,
+            results: true
+        } ], 'exercice');
     }
 }
 
diff --git a/ExpressAPI/src/middlewares/SecurityMiddleware.ts b/ExpressAPI/src/middlewares/SecurityMiddleware.ts
index 85a6056..97a2299 100644
--- a/ExpressAPI/src/middlewares/SecurityMiddleware.ts
+++ b/ExpressAPI/src/middlewares/SecurityMiddleware.ts
@@ -11,7 +11,7 @@ class SecurityMiddleware {
     check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: ApiRequest, res: express.Response, next: express.NextFunction) => void {
         return async (req: ApiRequest, res: express.Response, next: express.NextFunction) => {
             if ( checkIfConnected ) {
-                if ( req.session.profile.id === null ) {
+                if ( req.session.profile === null ) {
                     return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
                 }
             }
@@ -19,9 +19,9 @@ class SecurityMiddleware {
             let isAllowed = checkTypes.length === 0;
 
             if ( !isAllowed ) {
-                for ( let checkType of checkTypes ) {
+                for ( const checkType of checkTypes ) {
                     try {
-                        switch ( checkType ) {
+                        switch ( String(checkType) ) {
                             case SecurityCheckType.TEACHING_STAFF:
                                 isAllowed = isAllowed || req.session.profile.isTeachingStaff;
                                 break;
@@ -31,8 +31,10 @@ class SecurityMiddleware {
                             case SecurityCheckType.ENONCE_IS_PUBLISHED:
                                 isAllowed = isAllowed || req.boundParams.enonce.published;
                                 break;
+                            case SecurityCheckType.EXERCICE_SECRET:
+                                isAllowed = isAllowed || (req.headers.authorization && req.headers.authorization && req.headers.authorization.replace('ExerciceSecret ', '') === req.boundParams.exercice.secret);
+                                break;
                             default:
-                                isAllowed = isAllowed || false;
                                 break;
                         }
                     } catch ( e ) {
diff --git a/ExpressAPI/src/types/ApiRequest.ts b/ExpressAPI/src/types/ApiRequest.ts
index 6d1549c..9a6c06d 100644
--- a/ExpressAPI/src/types/ApiRequest.ts
+++ b/ExpressAPI/src/types/ApiRequest.ts
@@ -1,11 +1,11 @@
-import express    from 'express';
-import Session    from '../controllers/Session';
-import { Enonce } from './DatabaseTypes';
+import express              from 'express';
+import Session              from '../controllers/Session';
+import { Enonce, Exercice } from './DatabaseTypes';
 
 
 type ApiRequest = express.Request & {
     session: Session, boundParams: {
-        enonce: Enonce
+        enonce: Enonce, exercice: Exercice
     }
 }
 
diff --git a/ExpressAPI/src/types/SecurityCheckType.ts b/ExpressAPI/src/types/SecurityCheckType.ts
index fcb3a6d..b063ff9 100644
--- a/ExpressAPI/src/types/SecurityCheckType.ts
+++ b/ExpressAPI/src/types/SecurityCheckType.ts
@@ -2,6 +2,7 @@ enum SecurityCheckType {
     TEACHING_STAFF      = 'teachingStaff',
     ENONCE_STAFF        = 'enonceStaff',
     ENONCE_IS_PUBLISHED = 'enonceIsPublished',
+    EXERCICE_SECRET     = 'exerciceSecret',
 }
 
 
-- 
GitLab