diff --git a/server/controllers/maintenanceWindowController.js b/server/controllers/maintenanceWindowController.js index 322ba8a90..9807392cc 100755 --- a/server/controllers/maintenanceWindowController.js +++ b/server/controllers/maintenanceWindowController.js @@ -22,8 +22,25 @@ class MaintenanceWindowController { async (req, res, next) => { await createMaintenanceWindowBodyValidation.validateAsync(req.body); - const { teamId } = req.user; + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + const monitorIds = req.body.monitors; + + const monitors = await this.db.getMonitorsByIds(monitorIds); + + const unauthorizedMonitors = monitors.filter((monitor) => !monitor.teamId.equals(teamId)); + + if (unauthorizedMonitors.length > 0) { + const error = new Error("Unauthorized access to one or more monitors"); + error.status = 403; + error.service = SERVICE_NAME; + error.method = "createMaintenanceWindows"; + throw error; + } + const dbTransactions = monitorIds.map((monitorId) => { return this.db.createMaintenanceWindow({ teamId, @@ -48,7 +65,13 @@ class MaintenanceWindowController { getMaintenanceWindowById = asyncHandler( async (req, res, next) => { await getMaintenanceWindowByIdParamValidation.validateAsync(req.params); - const maintenanceWindow = await this.db.getMaintenanceWindowById(req.params.id); + + const teamId = req.user.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + const maintenanceWindow = await this.db.getMaintenanceWindowById({ id: req.params.id, teamId }); return res.success({ msg: this.stringService.maintenanceWindowGetById, data: maintenanceWindow, @@ -62,7 +85,12 @@ class MaintenanceWindowController { async (req, res, next) => { await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query); - const { teamId } = req.user; + const teamId = req?.user?.teamId; + + if (!teamId) { + throw new Error("Team ID is required"); + } + const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(teamId, req.query); return res.success({ @@ -78,7 +106,14 @@ class MaintenanceWindowController { async (req, res, next) => { await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params); - const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId(req.params.monitorId); + const monitorId = req.params.monitorId; + + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId({ monitorId, teamId }); return res.success({ msg: this.stringService.maintenanceWindowGetByUser, @@ -92,7 +127,13 @@ class MaintenanceWindowController { deleteMaintenanceWindow = asyncHandler( async (req, res, next) => { await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params); - await this.db.deleteMaintenanceWindowById(req.params.id); + + const teamId = req?.user?.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + await this.db.deleteMaintenanceWindowById({ id: req.params.id, teamId }); return res.success({ msg: this.stringService.maintenanceWindowDelete, }); @@ -105,7 +146,14 @@ class MaintenanceWindowController { async (req, res, next) => { await editMaintenanceWindowByIdParamValidation.validateAsync(req.params); await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body); - const editedMaintenanceWindow = await this.db.editMaintenanceWindowById(req.params.id, req.body); + + const teamId = req.user.teamId; + if (!teamId) { + throw new Error("Team ID is required"); + } + + const editedMaintenanceWindow = await this.db.editMaintenanceWindowById({ id: req.params.id, body: req.body, teamId }); + return res.success({ msg: this.stringService.maintenanceWindowEdit, data: editedMaintenanceWindow, diff --git a/server/db/mongo/modules/maintenanceWindowModule.js b/server/db/mongo/modules/maintenanceWindowModule.js index 4f16fceb6..f7fea4636 100755 --- a/server/db/mongo/modules/maintenanceWindowModule.js +++ b/server/db/mongo/modules/maintenanceWindowModule.js @@ -34,10 +34,11 @@ const createMaintenanceWindow = async (maintenanceWindowData) => { } }; -const getMaintenanceWindowById = async (maintenanceWindowId) => { +const getMaintenanceWindowById = async ({ id, teamId }) => { try { - const maintenanceWindow = await MaintenanceWindow.findById({ - _id: maintenanceWindowId, + const maintenanceWindow = await MaintenanceWindow.findOne({ + _id: id, + teamId: teamId, }); return maintenanceWindow; } catch (error) { @@ -95,10 +96,11 @@ const getMaintenanceWindowsByTeamId = async (teamId, query) => { * @returns {Promise>} An array of MaintenanceWindow documents. * @throws {Error} If there is an error retrieving the documents. */ -const getMaintenanceWindowsByMonitorId = async (monitorId) => { +const getMaintenanceWindowsByMonitorId = async ({ monitorId, teamId }) => { try { const maintenanceWindows = await MaintenanceWindow.find({ monitorId: monitorId, + teamId: teamId, }); return maintenanceWindows; } catch (error) { @@ -116,9 +118,9 @@ const getMaintenanceWindowsByMonitorId = async (monitorId) => { * @returns {Promise} The deleted MaintenanceWindow document. * @throws {Error} If there is an error deleting the document. */ -const deleteMaintenanceWindowById = async (maintenanceWindowId) => { +const deleteMaintenanceWindowById = async ({ id, teamId }) => { try { - const maintenanceWindow = await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId); + const maintenanceWindow = await MaintenanceWindow.findOneAndDelete({ _id: id, teamId }); return maintenanceWindow; } catch (error) { error.service = SERVICE_NAME; @@ -167,9 +169,9 @@ const deleteMaintenanceWindowByUserId = async (userId) => { } }; -const editMaintenanceWindowById = async (maintenanceWindowId, maintenanceWindowData) => { +const editMaintenanceWindowById = async ({ id, body, teamId }) => { try { - const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(maintenanceWindowId, maintenanceWindowData, { new: true }); + const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(id, body, { new: true }); return editedMaintenanceWindow; } catch (error) { error.service = SERVICE_NAME; diff --git a/server/db/mongo/modules/monitorModule.js b/server/db/mongo/modules/monitorModule.js index 94829002b..b331bc337 100755 --- a/server/db/mongo/modules/monitorModule.js +++ b/server/db/mongo/modules/monitorModule.js @@ -461,6 +461,17 @@ const getMonitorById = async (monitorId) => { } }; +const getMonitorsByIds = async (monitorIds) => { + try { + const objectIds = monitorIds.map((id) => new ObjectId(id)); + return await Monitor.find({ _id: { $in: objectIds } }, { _id: 1, teamId: 1 }).lean(); + } catch (error) { + error.service = SERVICE_NAME; + error.method = "getMonitorsByIds"; + throw error; + } +}; + const getMonitorsByTeamId = async ({ limit, type, page, rowsPerPage, filter, field, order, teamId }) => { limit = parseInt(limit); page = parseInt(page); @@ -753,6 +764,7 @@ export { getAllMonitorsWithUptimeStats, getMonitorStatsById, getMonitorById, + getMonitorsByIds, getMonitorsByTeamId, getMonitorsAndSummaryByTeamId, getMonitorsWithChecksByTeamId, diff --git a/server/index.js b/server/index.js index e8aff74d6..5f391c754 100755 --- a/server/index.js +++ b/server/index.js @@ -343,16 +343,17 @@ const startApp = async () => { //routes app.use("/api/v1/auth", authRoutes.getRouter()); - app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter()); - app.use("/api/v1/invite", inviteRoutes.getRouter()); - app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter()); app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter()); - app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter()); - app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter()); - app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter()); - app.use("/api/v1/status-page", statusPageRoutes.getRouter()); - app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter()); app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter()); + app.use("/api/v1/invite", inviteRoutes.getRouter()); + app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter()); + app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter()); + app.use("/api/v1/monitors", verifyJWT, monitorRoutes.getRouter()); + app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter()); + app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter()); + app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter()); + app.use("/api/v1/status-page", statusPageRoutes.getRouter()); + app.use("/api/v1/health", (req, res) => { res.json({ status: "OK", diff --git a/server/routes/maintenanceWindowRoute.js b/server/routes/maintenanceWindowRoute.js index 7ba3ac855..774434ed6 100755 --- a/server/routes/maintenanceWindowRoute.js +++ b/server/routes/maintenanceWindowRoute.js @@ -1,7 +1,4 @@ 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) { @@ -13,11 +10,11 @@ class MaintenanceWindowRoutes { this.router.post("/", this.mwController.createMaintenanceWindows); this.router.get("/team/", this.mwController.getMaintenanceWindowsByTeamId); - this.router.get("/monitor/:monitorId", verifyOwnership(Monitor, "monitorId"), this.mwController.getMaintenanceWindowsByMonitorId); + this.router.get("/monitor/:monitorId", this.mwController.getMaintenanceWindowsByMonitorId); this.router.get("/:id", this.mwController.getMaintenanceWindowById); - this.router.put("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.editMaintenanceWindow); - this.router.delete("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.deleteMaintenanceWindow); + this.router.put("/:id", this.mwController.editMaintenanceWindow); + this.router.delete("/:id", this.mwController.deleteMaintenanceWindow); } getRouter() {