diff --git a/server/controllers/authController.js b/server/controllers/authController.js index 88580d147..208b981fc 100755 --- a/server/controllers/authController.js +++ b/server/controllers/authController.js @@ -5,6 +5,10 @@ import { recoveryValidation, recoveryTokenValidation, newPasswordValidation, + getUserByIdParamValidation, + editUserByIdParamValidation, + editUserByIdBodyValidation, + editSuperadminUserByIdBodyValidation, } from "../validation/joi.js"; import jwt from "jsonwebtoken"; import { getTokenFromHeaders } from "../utils/utils.js"; @@ -396,6 +400,7 @@ class AuthController { getUserById = asyncHandler( async (req, res, next) => { + await getUserByIdParamValidation.validateAsync(req.params); const userId = req?.params?.userId; const roles = req?.user?.role; @@ -417,14 +422,22 @@ class AuthController { editUserById = asyncHandler( async (req, res, next) => { - const userId = req.params.userId; - const user = req.body; - const roles = req?.user?.role; if (!roles.includes("superadmin")) { throw createError("Unauthorized", 403); } + const userId = req.params.userId; + const user = { ...req.body }; + + await editUserByIdParamValidation.validateAsync(req.params); + // If this is superadmin self edit, allow "superadmin" role + if (userId === req.user._id) { + await editSuperadminUserByIdBodyValidation.validateAsync(req.body); + } else { + await editUserByIdBodyValidation.validateAsync(req.body); + } + await this.db.editUserById(userId, user); return res.success({ msg: "ok" }); }, diff --git a/server/validation/joi.js b/server/validation/joi.js index 57c8b7350..619a30ea9 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -1,4 +1,5 @@ import joi from "joi"; +import { ROLES, VALID_ROLES } from "../../client/src/Utils/roleUtils.js"; //**************************************** // Custom Validators @@ -164,11 +165,7 @@ const createMonitorBodyValidation = joi.object({ .custom((value, helpers) => { // 1. Standard URLs: must have protocol and pass canParse() if (/^(https?:\/\/)/.test(value)) { - if ( - typeof URL !== "undefined" && - typeof URL.canParse === "function" && - URL.canParse(value) - ) { + if (typeof URL !== "undefined" && typeof URL.canParse === "function" && URL.canParse(value)) { return value; } // else, it's a malformed URL with protocol @@ -197,8 +194,7 @@ const createMonitorBodyValidation = joi.object({ .messages({ "string.empty": "This field is required.", "string.uri": "The URL you provided is not valid.", - "string.invalidUrl": - "Please enter a valid URL, hostname, or container name (with optional port).", + "string.invalidUrl": "Please enter a valid URL, hostname, or container name (with optional port).", }), ignoreTlsErrors: joi.boolean().default(false), port: joi.number(), @@ -657,6 +653,36 @@ const sendTestEmailBodyValidation = joi.object({ systemEmailTLSServername: joi.string().allow("").optional(), }); +const getUserByIdParamValidation = joi.object({ + userId: joi.string().required(), +}); + +const editUserByIdParamValidation = joi.object({ + userId: joi.string().required(), +}); + +const editUserByIdBodyValidation = joi.object({ + firstName: nameValidation.required(), + lastName: nameValidation.required(), + email: joi.string().email().required(), + role: joi + .array() + .items(joi.string().valid(...VALID_ROLES)) + .min(1) + .required(), +}); + +const editSuperadminUserByIdBodyValidation = joi.object({ + firstName: nameValidation.required(), + lastName: nameValidation.required(), + email: joi.string().email().required(), + role: joi + .array() + .items(joi.string().valid(...VALID_ROLES, ROLES.SUPERADMIN)) + .min(1) + .required(), +}); + export { roleValidatior, loginValidation, @@ -724,4 +750,8 @@ export { webhookConfigValidation, createAnnouncementValidation, sendTestEmailBodyValidation, + getUserByIdParamValidation, + editUserByIdParamValidation, + editUserByIdBodyValidation, + editSuperadminUserByIdBodyValidation, };