From fdff3be316d8ce3b2e3fb951c7ba54d54499afa9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 21 Jul 2025 13:58:01 -0700 Subject: [PATCH] fix team auth --- server/controllers/monitorController.js | 94 +++++++++++++++++------- server/db/mongo/modules/monitorModule.js | 48 ------------ server/routes/monitorRoute.js | 12 +-- 3 files changed, 71 insertions(+), 83 deletions(-) diff --git a/server/controllers/monitorController.js b/server/controllers/monitorController.js index 79579e521..9943a765a 100755 --- a/server/controllers/monitorController.js +++ b/server/controllers/monitorController.js @@ -20,6 +20,7 @@ import axios from "axios"; import seedDb from "../db/mongo/utils/seedDb.js"; import pkg from "papaparse"; import { asyncHandler, createServerError } from "../utils/errorUtils.js"; +import { fetchMonitorCertificate } from "./controllerUtils.js"; const SERVICE_NAME = "monitorController"; class MonitorController { @@ -31,6 +32,15 @@ class MonitorController { this.emailService = emailService; } + async verifyTeamAccess(teamId, monitorId) { + const monitor = await this.db.getMonitorById(monitorId); + if (!monitor.teamId.equals(teamId)) { + const error = new Error("Unauthorized"); + error.status = 403; + throw error; + } + } + /** * Returns all monitors * @async @@ -52,32 +62,18 @@ class MonitorController { "getAllMonitors" ); - /** - * Returns all monitors with uptime stats for 1,7,30, and 90 days - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @param {function} next - * @returns {Promise} - * @throws {Error} - */ - getAllMonitorsWithUptimeStats = asyncHandler( - async (req, res, next) => { - const monitors = await this.db.getAllMonitorsWithUptimeStats(); - return res.success({ - msg: this.stringService.monitorGetAll, - data: monitors, - }); - }, - SERVICE_NAME, - "getAllMonitorsWithUptimeStats" - ); - getUptimeDetailsById = asyncHandler( async (req, res, next) => { const { monitorId } = req.params; const { dateRange, normalize } = req.query; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); + const data = await this.db.getUptimeDetailsById({ monitorId, dateRange, @@ -109,6 +105,13 @@ class MonitorController { let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query; const { monitorId } = req.params; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); + const monitorStats = await this.db.getMonitorStatsById({ monitorId, limit, @@ -140,8 +143,14 @@ class MonitorController { await getHardwareDetailsByIdParamValidation.validateAsync(req.params); await getHardwareDetailsByIdQueryValidation.validateAsync(req.query); - const { monitorId } = req.params; - const { dateRange } = req.query; + const monitorId = req?.params?.monitorId; + const dateRange = req?.query?.dateRange; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); const monitor = await this.db.getHardwareDetailsById({ monitorId, dateRange }); return res.success({ msg: this.stringService.monitorGetByIdSuccess, @@ -153,7 +162,7 @@ class MonitorController { ); getMonitorCertificate = asyncHandler( - async (req, res, next, fetchMonitorCertificate) => { + async (req, res, next) => { await getCertificateParamValidation.validateAsync(req.params); const { monitorId } = req.params; @@ -188,6 +197,18 @@ class MonitorController { await getMonitorByIdQueryValidation.validateAsync(req.query); const monitor = await this.db.getMonitorById(req.params.monitorId); + + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + if (!monitor.teamId.equals(teamId)) { + const error = new Error("Unauthorized"); + error.status = 403; + throw error; + } + return res.success({ msg: this.stringService.monitorGetByIdSuccess, data: monitor, @@ -367,6 +388,13 @@ class MonitorController { async (req, res, next) => { await getMonitorByIdParamValidation.validateAsync(req.params); const monitorId = req.params.monitorId; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); + const monitor = await this.db.deleteMonitor({ monitorId }); await this.jobQueue.deleteJob(monitor); await this.db.deleteStatusPagesByMonitorId(monitor._id); @@ -389,7 +417,7 @@ class MonitorController { */ deleteAllMonitors = asyncHandler( async (req, res, next) => { - const { teamId } = req.user; + const teamId = req?.user?.teamId; const { monitors, deletedCount } = await this.db.deleteAllMonitors(teamId); await Promise.all( monitors.map(async (monitor) => { @@ -431,7 +459,14 @@ class MonitorController { async (req, res, next) => { await getMonitorByIdParamValidation.validateAsync(req.params); await editMonitorBodyValidation.validateAsync(req.body); - const { monitorId } = req.params; + const monitorId = req?.params?.monitorId; + + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); const editedMonitor = await this.db.editMonitor(monitorId, req.body); @@ -462,6 +497,13 @@ class MonitorController { await pauseMonitorParamValidation.validateAsync(req.params); const monitorId = req.params.monitorId; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.verifyTeamAccess(teamId, monitorId); + const monitor = await this.db.pauseMonitor({ monitorId }); monitor.isActive === true ? await this.jobQueue.resumeJob(monitor._id, monitor) : await this.jobQueue.pauseJob(monitor); diff --git a/server/db/mongo/modules/monitorModule.js b/server/db/mongo/modules/monitorModule.js index b331bc337..3192b711c 100755 --- a/server/db/mongo/modules/monitorModule.js +++ b/server/db/mongo/modules/monitorModule.js @@ -56,53 +56,6 @@ const getAllMonitors = async (req, res) => { } }; -/** - * Get all monitors with uptime stats for 1,7,30, and 90 days - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise>} - * @throws {Error} - */ -const getAllMonitorsWithUptimeStats = async () => { - const timeRanges = { - 1: new Date(Date.now() - 24 * 60 * 60 * 1000), - 7: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), - 30: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), - 90: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), - }; - - try { - const monitors = await Monitor.find(); - const monitorsWithStats = await Promise.all( - monitors.map(async (monitor) => { - const model = CHECK_MODEL_LOOKUP[monitor.type]; - - const uptimeStats = await Promise.all( - Object.entries(timeRanges).map(async ([days, startDate]) => { - const checks = await model.find({ - monitorId: monitor._id, - createdAt: { $gte: startDate }, - }); - return [days, getUptimePercentage(checks)]; - }) - ); - - return { - ...monitor.toObject(), - ...Object.fromEntries(uptimeStats), - }; - }) - ); - - return monitorsWithStats; - } catch (error) { - error.service = SERVICE_NAME; - error.method = "getAllMonitorsWithUptimeStats"; - throw error; - } -}; - /** * Function to calculate uptime duration based on the most recent check. * @param {Array} checks Array of check objects. @@ -761,7 +714,6 @@ const pauseMonitor = async ({ monitorId }) => { export { getAllMonitors, - getAllMonitorsWithUptimeStats, getMonitorStatsById, getMonitorById, getMonitorsByIds, diff --git a/server/routes/monitorRoute.js b/server/routes/monitorRoute.js index 3f4a40c1a..15553fc1c 100755 --- a/server/routes/monitorRoute.js +++ b/server/routes/monitorRoute.js @@ -20,10 +20,9 @@ class MonitorRoutes { // Team routes this.router.get("/team", this.monitorController.getMonitorsByTeamId); this.router.get("/team/with-checks", this.monitorController.getMonitorsWithChecksByTeamId); - this.router.get("/team/summary", this.monitorController.getMonitorsAndSummaryByTeamId); // TODO should be /team/summary + this.router.get("/team/summary", this.monitorController.getMonitorsAndSummaryByTeamId); // Uptime routes - this.router.get("/uptime", this.monitorController.getAllMonitorsWithUptimeStats); this.router.get("/uptime/details/:monitorId", this.monitorController.getUptimeDetailsById); // Hardware routes @@ -53,13 +52,8 @@ class MonitorRoutes { // Individual monitor CRUD routes this.router.get("/:monitorId", this.monitorController.getMonitorById); - this.router.put("/:monitorId", verifyTeamAccess(Monitor, "monitorId"), isAllowed(["admin", "superadmin"]), this.monitorController.editMonitor); - this.router.delete( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - isAllowed(["admin", "superadmin"]), - this.monitorController.deleteMonitor - ); + this.router.put("/:monitorId", isAllowed(["admin", "superadmin"]), this.monitorController.editMonitor); + this.router.delete("/:monitorId", isAllowed(["admin", "superadmin"]), this.monitorController.deleteMonitor); } getRouter() {