From 05add10ba8c69b1a9df565d84770f966691ebcfe Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 23 Jun 2025 15:45:24 +0800 Subject: [PATCH 1/3] add middleware for verifying team access --- server/middleware/verifyOwnership.js | 4 +++- server/middleware/verifyTeamAccess.js | 25 +++++++++++++++++++++++++ server/routes/maintenanceWindowRoute.js | 15 ++++++++++++--- server/routes/monitorRoute.js | 6 +++++- server/routes/notificationRoute.js | 16 +++++++++++++--- 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 server/middleware/verifyTeamAccess.js diff --git a/server/middleware/verifyOwnership.js b/server/middleware/verifyOwnership.js index ca2476f54..754d96204 100755 --- a/server/middleware/verifyOwnership.js +++ b/server/middleware/verifyOwnership.js @@ -6,8 +6,10 @@ const SERVICE_NAME = "verifyOwnership"; const verifyOwnership = (Model, paramName) => { const stringService = ServiceRegistry.get(StringService.SERVICE_NAME); return async (req, res, next) => { + console.log(req.params); const userId = req.user._id; const documentId = req.params[paramName]; + try { const doc = await Model.findById(documentId); //If the document is not found, return a 404 error @@ -35,7 +37,7 @@ const verifyOwnership = (Model, paramName) => { // If the userID does not match the document's userID, return a 403 error if (userId.toString() !== doc.userId.toString()) { - const error = new Error(stringService.verifyOwnerUnauthorized); + const error = new Error("Unauthorized"); error.status = 403; throw error; } diff --git a/server/middleware/verifyTeamAccess.js b/server/middleware/verifyTeamAccess.js new file mode 100644 index 000000000..463bd4c05 --- /dev/null +++ b/server/middleware/verifyTeamAccess.js @@ -0,0 +1,25 @@ +const SERVICE_NAME = "verifyTeamAccess"; + +const verifyTeamAccess = (Model, paramName) => { + return async (req, res, next) => { + try { + const documentId = req.params[paramName]; + const doc = await Model.findById(documentId); + if (req.user.teamId.toString() === doc.teamId.toString()) { + next(); + return; + } + + const error = new Error("Unauthorized"); + error.status = 403; + throw error; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "verifyTeamAccess"; + next(error); + return; + } + }; +}; + +export { verifyTeamAccess }; diff --git a/server/routes/maintenanceWindowRoute.js b/server/routes/maintenanceWindowRoute.js index 2665c2bb8..36f982e25 100755 --- a/server/routes/maintenanceWindowRoute.js +++ b/server/routes/maintenanceWindowRoute.js @@ -1,7 +1,8 @@ import { Router } from "express"; import { verifyOwnership } from "../middleware/verifyOwnership.js"; +import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js"; import Monitor from "../db/models/Monitor.js"; - +import MaintenanceWindow from "../db/models/MaintenanceWindow.js"; class MaintenanceWindowRoutes { constructor(maintenanceWindowController) { this.router = Router(); @@ -24,9 +25,17 @@ class MaintenanceWindowRoutes { this.router.get("/:id", this.maintenanceWindowController.getMaintenanceWindowById); - this.router.put("/:id", this.maintenanceWindowController.editMaintenanceWindow); + this.router.put( + "/:id", + verifyTeamAccess(MaintenanceWindow, "id"), + this.maintenanceWindowController.editMaintenanceWindow + ); - this.router.delete("/:id", this.maintenanceWindowController.deleteMaintenanceWindow); + this.router.delete( + "/:id", + verifyTeamAccess(MaintenanceWindow, "id"), + this.maintenanceWindowController.deleteMaintenanceWindow + ); } getRouter() { diff --git a/server/routes/monitorRoute.js b/server/routes/monitorRoute.js index 2c6ae870e..168f8b88d 100755 --- a/server/routes/monitorRoute.js +++ b/server/routes/monitorRoute.js @@ -2,7 +2,9 @@ import { Router } from "express"; import { isAllowed } from "../middleware/isAllowed.js"; import multer from "multer"; import { fetchMonitorCertificate } from "../controllers/controllerUtils.js"; - +import Monitor from "../db/models/Monitor.js"; +import { verifyOwnership } from "../middleware/verifyOwnership.js"; +import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js"; const upload = multer({ storage: multer.memoryStorage(), // Store file in memory as Buffer }); @@ -62,6 +64,7 @@ class MonitorRoutes { this.router.delete( "/:monitorId", + verifyOwnership(Monitor, "monitorId"), isAllowed(["admin", "superadmin"]), this.monitorController.deleteMonitor ); @@ -74,6 +77,7 @@ class MonitorRoutes { this.router.put( "/:monitorId", + verifyTeamAccess(Monitor, "monitorId"), isAllowed(["admin", "superadmin"]), this.monitorController.editMonitor ); diff --git a/server/routes/notificationRoute.js b/server/routes/notificationRoute.js index 164c0afcc..09becd16c 100755 --- a/server/routes/notificationRoute.js +++ b/server/routes/notificationRoute.js @@ -1,6 +1,8 @@ import { Router } from "express"; import { verifyJWT } from "../middleware/verifyJWT.js"; - +import { verifyOwnership } from "../middleware/verifyOwnership.js"; +import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js"; +import Notification from "../db/models/Notification.js"; class NotificationRoutes { constructor(notificationController) { this.router = Router(); @@ -18,10 +20,18 @@ class NotificationRoutes { this.router.get("/team", this.notificationController.getNotificationsByTeamId); - this.router.delete("/:id", this.notificationController.deleteNotification); + this.router.delete( + "/:id", + verifyOwnership(Notification, "id"), + this.notificationController.deleteNotification + ); this.router.get("/:id", this.notificationController.getNotificationById); - this.router.put("/:id", this.notificationController.editNotification); + this.router.put( + "/:id", + verifyTeamAccess(Notification, "id"), + this.notificationController.editNotification + ); } getRouter() { From c8685c427344fc59bdc86da68cb143f6adf27438 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 10:00:41 +0800 Subject: [PATCH 2/3] remove console --- server/middleware/verifyOwnership.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/middleware/verifyOwnership.js b/server/middleware/verifyOwnership.js index 754d96204..011b178a4 100755 --- a/server/middleware/verifyOwnership.js +++ b/server/middleware/verifyOwnership.js @@ -6,7 +6,6 @@ const SERVICE_NAME = "verifyOwnership"; const verifyOwnership = (Model, paramName) => { const stringService = ServiceRegistry.get(StringService.SERVICE_NAME); return async (req, res, next) => { - console.log(req.params); const userId = req.user._id; const documentId = req.params[paramName]; From 40f879f6714ef7486e423798494f6e5058b58a5f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 10:02:36 +0800 Subject: [PATCH 3/3] user and teamId check --- server/middleware/verifyTeamAccess.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/middleware/verifyTeamAccess.js b/server/middleware/verifyTeamAccess.js index 463bd4c05..60647bdc2 100644 --- a/server/middleware/verifyTeamAccess.js +++ b/server/middleware/verifyTeamAccess.js @@ -5,6 +5,19 @@ const verifyTeamAccess = (Model, paramName) => { try { const documentId = req.params[paramName]; const doc = await Model.findById(documentId); + + if (!doc) { + const error = new Error("Document not found"); + error.status = 404; + throw error; + } + + if (!req?.user?.teamId || !doc.teamId) { + const error = new Error("Missing team information"); + error.status = 400; + throw error; + } + if (req.user.teamId.toString() === doc.teamId.toString()) { next(); return;