diff --git a/client/src/Components/TabPanels/Account/PasswordPanel.jsx b/client/src/Components/TabPanels/Account/PasswordPanel.jsx index 88604c72b..84d16e8b0 100644 --- a/client/src/Components/TabPanels/Account/PasswordPanel.jsx +++ b/client/src/Components/TabPanels/Account/PasswordPanel.jsx @@ -4,7 +4,7 @@ import { useTheme } from "@emotion/react"; import { Box, Stack, Typography, Button } from "@mui/material"; import { PasswordEndAdornment } from "../../Inputs/TextInput/Adornments"; import TextInput from "../../Inputs/TextInput"; -import { credentials } from "../../../Validation/validation"; +import { newOrChangedCredentials } from "../../../Validation/validation"; import Alert from "../../Alert"; import { update } from "../../../Features/Auth/authSlice"; import { useDispatch, useSelector } from "react-redux"; @@ -61,7 +61,7 @@ const PasswordPanel = () => { [name]: true, }; - const validation = credentials.validate( + const validation = newOrChangedCredentials.validate( { ...updatedData }, { abortEarly: false, context: { password: updatedData.newPassword } } ); @@ -79,7 +79,7 @@ const PasswordPanel = () => { const handleSubmit = async (event) => { event.preventDefault(); - const { error } = credentials.validate(localData, { + const { error } = newOrChangedCredentials.validate(localData, { abortEarly: false, context: { password: localData.newPassword }, }); diff --git a/client/src/Components/TabPanels/Account/ProfilePanel.jsx b/client/src/Components/TabPanels/Account/ProfilePanel.jsx index 53a8a8d77..46a2bdb79 100644 --- a/client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -5,7 +5,7 @@ import { Box, Button, Divider, Stack, Typography } from "@mui/material"; import Avatar from "../../Avatar"; import TextInput from "../../Inputs/TextInput"; import ImageUpload from "../../Inputs/ImageUpload"; -import { credentials } from "../../../Validation/validation"; +import { newOrChangedCredentials } from "../../../Validation/validation"; import { useDispatch, useSelector } from "react-redux"; import { clearAuthState, deleteUser, update } from "../../../Features/Auth/authSlice"; import { clearUptimeMonitorState } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; @@ -58,7 +58,7 @@ const ProfilePanel = () => { [name]: value, })); - validateField({ [name]: value }, credentials, name); + validateField({ [name]: value }, newOrChangedCredentials, name); }; // Validates input against provided schema and updates error state diff --git a/client/src/Components/TabPanels/Account/TeamPanel.jsx b/client/src/Components/TabPanels/Account/TeamPanel.jsx index c29762233..52e3ea9ee 100644 --- a/client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -4,7 +4,7 @@ import { Button, ButtonGroup, Stack, Typography } from "@mui/material"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import TextInput from "../../Inputs/TextInput"; -import { credentials } from "../../../Validation/validation"; +import { newOrChangedCredentials } from "../../../Validation/validation"; import { networkService } from "../../../main"; import { createToast } from "../../../Utils/toastUtils"; import Select from "../../Inputs/Select"; @@ -115,7 +115,7 @@ const TeamPanel = () => { email: newEmail, })); - const validation = credentials.validate({ email: newEmail }, { abortEarly: false }); + const validation = newOrChangedCredentials.validate({ email: newEmail }, { abortEarly: false }); setErrors((prev) => { const updatedErrors = { ...prev }; @@ -142,7 +142,7 @@ const TeamPanel = () => { if (!toInvite.role.includes("user") || !toInvite.role.includes("admin")) setToInvite((prev) => ({ ...prev, role: ["user"] })); - const { error } = credentials.validate( + const { error } = newOrChangedCredentials.validate( { email: toInvite.email }, { abortEarly: false, diff --git a/client/src/Pages/Auth/ForgotPassword.jsx b/client/src/Pages/Auth/ForgotPassword.jsx index 344bddac1..47b8fc3bf 100644 --- a/client/src/Pages/Auth/ForgotPassword.jsx +++ b/client/src/Pages/Auth/ForgotPassword.jsx @@ -4,7 +4,7 @@ import { createToast } from "../../Utils/toastUtils"; import { useDispatch, useSelector } from "react-redux"; import { forgotPassword } from "../../Features/Auth/authSlice"; import { useEffect, useState } from "react"; -import { credentials } from "../../Validation/validation"; +import { newOrChangedCredentials } from "../../Validation/validation"; import { useNavigate } from "react-router-dom"; import TextInput from "../../Components/Inputs/TextInput"; import Logo from "../../assets/icons/checkmate-icon.svg?react"; @@ -35,7 +35,7 @@ const ForgotPassword = () => { const handleSubmit = async (event) => { event.preventDefault(); - const { error } = credentials.validate(form, { abortEarly: false }); + const { error } = newOrChangedCredentials.validate(form, { abortEarly: false }); if (error) { // validation errors @@ -75,7 +75,7 @@ const ForgotPassword = () => { const { value } = event.target; setForm({ email: value }); - const { error } = credentials.validate({ email: value }, { abortEarly: false }); + const { error } = newOrChangedCredentials.validate({ email: value }, { abortEarly: false }); if (error) setErrors({ email: error.details[0].message }); else delete errors.email; diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index c81f0b892..f3b2253d2 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; -import { credentials } from "../../../Validation/validation"; +import { loginCredentials } from "../../../Validation/validation"; import { login } from "../../../Features/Auth/authSlice"; import { useDispatch, useSelector } from "react-redux"; import { createToast } from "../../../Utils/toastUtils"; @@ -59,7 +59,7 @@ const Login = () => { [name]: lowerCasedValue, })); - const { error } = credentials.validate( + const { error } = loginCredentials.validate( { [name]: lowerCasedValue }, { abortEarly: false } ); @@ -76,7 +76,7 @@ const Login = () => { event.preventDefault(); if (step === 0) { - const { error } = credentials.validate( + const { error } = loginCredentials.validate( { email: form.email }, { abortEarly: false } ); @@ -91,7 +91,7 @@ const Login = () => { setStep(1); } } else if (step === 1) { - const { error } = credentials.validate(form, { abortEarly: false }); + const { error } = loginCredentials.validate(form, { abortEarly: false }); if (error) { // validation errors diff --git a/client/src/Pages/Auth/Register/Register.jsx b/client/src/Pages/Auth/Register/Register.jsx index fd3f20cd9..49997e8cb 100644 --- a/client/src/Pages/Auth/Register/Register.jsx +++ b/client/src/Pages/Auth/Register/Register.jsx @@ -8,7 +8,7 @@ import { StepOne } from "./StepOne"; import { StepTwo } from "./StepTwo"; import { StepThree } from "./StepThree"; import { networkService } from "../../../main"; -import { credentials } from "../../../Validation/validation"; +import { newOrChangedCredentials } from "../../../Validation/validation"; import { createToast } from "../../../Utils/toastUtils"; import { register } from "../../../Features/Auth/authSlice"; import Background from "../../../assets/Images/background-grid.svg?react"; @@ -171,7 +171,7 @@ const Register = ({ isSuperAdmin }) => { * @returns {Object | undefined} - Returns the validation error object if there are validation errors; otherwise, `undefined`. */ const validateForm = (data, options = {}) => { - const { error } = credentials.validate(data, { + const { error } = newOrChangedCredentials.validate(data, { abortEarly: false, ...options, }); @@ -271,7 +271,7 @@ const Register = ({ isSuperAdmin }) => { [name]: lowerCasedValue, })); - const { error } = credentials.validate( + const { error } = newOrChangedCredentials.validate( { [name]: lowerCasedValue }, { abortEarly: false, context: { password: form.password } } ); diff --git a/client/src/Pages/Auth/SetNewPassword.jsx b/client/src/Pages/Auth/SetNewPassword.jsx index 2d0aa01bc..21dfe2d39 100644 --- a/client/src/Pages/Auth/SetNewPassword.jsx +++ b/client/src/Pages/Auth/SetNewPassword.jsx @@ -6,7 +6,7 @@ import { useTheme } from "@emotion/react"; import { Box, Stack, Typography, Button } from "@mui/material"; import { setNewPassword } from "../../Features/Auth/authSlice"; import { createToast } from "../../Utils/toastUtils"; -import { credentials } from "../../Validation/validation"; +import { newOrChangedCredentials } from "../../Validation/validation"; import Check from "../../Components/Check/Check"; import TextInput from "../../Components/Inputs/TextInput"; import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; @@ -34,7 +34,7 @@ const SetNewPassword = () => { const handleSubmit = async (e) => { e.preventDefault(); - const { error } = credentials.validate(form, { + const { error } = newOrChangedCredentials.validate(form, { abortEarly: false, context: { password: form.password }, }); diff --git a/client/src/Pages/Auth/hooks/useValidatePassword.jsx b/client/src/Pages/Auth/hooks/useValidatePassword.jsx index b49d0944b..102d8d73e 100644 --- a/client/src/Pages/Auth/hooks/useValidatePassword.jsx +++ b/client/src/Pages/Auth/hooks/useValidatePassword.jsx @@ -1,5 +1,5 @@ import { useMemo, useState } from "react"; -import { credentials } from "../../../Validation/validation"; +import { newOrChangedCredentials } from "../../../Validation/validation"; const getFeedbackStatus = (form, errors, field, criteria) => { const fieldErrors = errors[field]; @@ -36,7 +36,7 @@ function useValidatePassword() { validateValue.password = form.password; } - const { error } = credentials.validate(validateValue, validateOptions); + const { error } = newOrChangedCredentials.validate(validateValue, validateOptions); const errors = error?.details.map((error) => ({ path: error.path[0], type: error.type, diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index b79d4c824..acb05116e 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -27,7 +27,7 @@ const lastnameSchema = joi "Surname must contain only letters, spaces, apostrophes, or hyphens", }); -const passwordSchema = joi +const newPasswordSchema = joi .string() .trim() .min(8) @@ -64,7 +64,7 @@ const passwordSchema = joi special: "Password must contain at least one special character", }); -const credentials = joi.object({ +const newOrChangedCredentials = joi.object({ firstName: nameSchema, lastName: lastnameSchema, email: joi @@ -76,8 +76,8 @@ const credentials = joi.object({ "string.empty": "authRegisterEmailRequired", "string.email": "authRegisterEmailInvalid", }), - password: passwordSchema, - newPassword: passwordSchema, + password: newPasswordSchema, + newPassword: newPasswordSchema, confirm: joi .string() .trim() @@ -97,6 +97,23 @@ const credentials = joi.object({ inviteToken: joi.string().allow(""), }); +const loginCredentials = joi.object({ + email: joi + .string() + .trim() + .email({ tlds: { allow: false } }) + .lowercase() + .messages({ + "string.empty": "authRegisterEmailRequired", + "string.email": "authRegisterEmailInvalid", + }), + password: joi + .string() + .messages({ + "string.empty": "Please enter your password", + }), +}); + const monitorValidation = joi.object({ url: joi.when("type", { is: "docker", @@ -391,7 +408,8 @@ const infrastructureMonitorValidation = joi.object({ }); export { - credentials, + newOrChangedCredentials, + loginCredentials, imageValidation, monitorValidation, settingsValidation, diff --git a/server/validation/joi.js b/server/validation/joi.js index 3efd202b5..9a3c61a7c 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -26,14 +26,10 @@ const loginValidation = joi.object({ .string() .email() .required() - .custom((value, helpers) => { - const lowercasedValue = value.toLowerCase(); - if (value !== lowercasedValue) { - return helpers.message("Email must be in lowercase"); - } - return lowercasedValue; - }), - password: joi.string().min(8).required().pattern(passwordPattern), + .lowercase(), + password: joi + .string() + .required(), }); const nameValidation = joi .string()