From 3bdea4970e609d4aa58699ba51399ebcdcf1dd6c Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:29:54 +0530 Subject: [PATCH 1/7] feat: basic email validation --- src/pages/Register.tsx | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index d9bdd64c..81474977 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -9,9 +9,8 @@ import { useThemeMode } from "../context/theme-provider"; import { useTranslation } from 'react-i18next'; import i18n from '../i18n'; - const Register = () => { - const {t} = useTranslation(); + const { t } = useTranslation(); const [form, setForm] = useState({ email: "", password: "", @@ -39,6 +38,20 @@ const Register = () => { const submitForm = async (e: any) => { e.preventDefault(); + + // Basic "@" check (minimal) + if (!email.includes("@")) { + notify("error", t('register.error.invalid_email') || "Invalid email format"); + return; + } + + // Optional: Better regex-based email format check + // const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + // if (!emailRegex.test(email)) { + // notify("error", t('register.error.invalid_email') || "Invalid email format"); + // return; + // } + setLoading(true); try { const { data } = await axios.post(`${apiUrl}/auth/register`, { email, password }); @@ -46,12 +59,12 @@ const Register = () => { notify("success", t('register.welcome_notification')); window.localStorage.setItem("user", JSON.stringify(data)); navigate("/"); - } catch (error:any) { + } catch (error: any) { const errorResponse = error.response?.data; - const errorMessage = errorResponse?.code - ? t(errorResponse.code) - : t('register.error.generic'); + const errorMessage = errorResponse?.code + ? t(errorResponse.code) + : t('register.error.generic'); notify("error", errorMessage); setLoading(false); @@ -68,7 +81,6 @@ const Register = () => { mt: 6, padding: 4, backgroundColor: darkMode ? "#121212" : "#ffffff", - }} > { color: darkMode ? "#ffffff" : "#333333", padding: 6, borderRadius: 5, - boxShadow: "0px 20px 40px rgba(0, 0, 0, 0.2), 0px -5px 10px rgba(0, 0, 0, 0.15)", + boxShadow: + "0px 20px 40px rgba(0, 0, 0, 0.2), 0px -5px 10px rgba(0, 0, 0, 0.15)", display: "flex", flexDirection: "column", alignItems: "center", @@ -143,9 +156,13 @@ const Register = () => { t('register.button') )} - + {t('register.register_prompt')}{" "} - + {t('register.login_link')} @@ -154,4 +171,4 @@ const Register = () => { ); }; -export default Register; +export default Register; \ No newline at end of file From a57ca1c35aabc5af66ea061795b0727d01145f26 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:30:30 +0530 Subject: [PATCH 2/7] feat: proper error message --- src/pages/Register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index 81474977..f223d169 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -41,7 +41,7 @@ const Register = () => { // Basic "@" check (minimal) if (!email.includes("@")) { - notify("error", t('register.error.invalid_email') || "Invalid email format"); + notify("error", "Invalid email format"); return; } From eb02ce797b6c51582299eab8295fb2a39b416580 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:32:18 +0530 Subject: [PATCH 3/7] feat: use regex --- src/pages/Register.tsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index f223d169..ccba328c 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -39,18 +39,11 @@ const Register = () => { const submitForm = async (e: any) => { e.preventDefault(); - // Basic "@" check (minimal) - if (!email.includes("@")) { - notify("error", "Invalid email format"); - return; - } - - // Optional: Better regex-based email format check - // const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - // if (!emailRegex.test(email)) { - // notify("error", t('register.error.invalid_email') || "Invalid email format"); - // return; - // } + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + notify("error", "Invalid email format"); + return; + } setLoading(true); try { From 8e3a22c67570ad109900b999cf644f9659a7d993 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:32:31 +0530 Subject: [PATCH 4/7] chore: lint --- src/pages/Register.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index ccba328c..bc4faf27 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -39,11 +39,11 @@ const Register = () => { const submitForm = async (e: any) => { e.preventDefault(); - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { - notify("error", "Invalid email format"); - return; - } + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + notify("error", "Invalid email format"); + return; + } setLoading(true); try { From 640693aeef396749b875fb8c3218042c1317a212 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:36:03 +0530 Subject: [PATCH 5/7] feat: basic email validation --- src/pages/Login.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index b76f1fd8..91df171b 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -42,6 +42,12 @@ const Login = () => { const submitForm = async (e: any) => { e.preventDefault(); + +if (!email.includes("@")) { + notify("error", "Please enter a valid email."); + return; +} + setLoading(true); try { const { data } = await axios.post( From a56bef3f62d27348c2984b87633e68940f383fc1 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:36:11 +0530 Subject: [PATCH 6/7] chore: lint --- src/pages/Login.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 91df171b..2d34bd81 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -43,10 +43,10 @@ const Login = () => { const submitForm = async (e: any) => { e.preventDefault(); -if (!email.includes("@")) { - notify("error", "Please enter a valid email."); - return; -} + if (!email.includes("@")) { + notify("error", "Please enter a valid email."); + return; + } setLoading(true); try { @@ -61,11 +61,11 @@ if (!email.includes("@")) { navigate("/"); } catch (err: any) { const errorResponse = err.response?.data; - - const errorMessage = errorResponse?.code - ? t(errorResponse.code) - : t('login.error.generic'); - + + const errorMessage = errorResponse?.code + ? t(errorResponse.code) + : t('login.error.generic'); + notify("error", errorMessage); setLoading(false); } From 9d7661231addf58bbf062c22a8304f7cae658666 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 12 Jul 2025 01:38:14 +0530 Subject: [PATCH 7/7] feat: email regex check --- server/src/routes/auth.ts | 54 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/server/src/routes/auth.ts b/server/src/routes/auth.ts index 1ce415b1..34933466 100644 --- a/server/src/routes/auth.ts +++ b/server/src/routes/auth.ts @@ -33,6 +33,14 @@ router.post("/register", async (req, res) => { }); } + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + return res.status(400).json({ + error: "VALIDATION_ERROR", + code: "register.validation.invalid_email_format" + }); + } + if (!password || password.length < 6) { return res.status(400).json({ error: "VALIDATION_ERROR", @@ -74,16 +82,16 @@ router.post("/register", async (req, res) => { res.cookie("token", token, { httpOnly: true, }); - + capture("maxun-oss-user-registered", { email: user.email, userId: user.id, registeredAt: new Date().toISOString(), }); - + console.log(`User registered`); res.json(user); - + } catch (error: any) { console.log(`Could not register user - ${error}`); return res.status(500).json({ @@ -150,23 +158,23 @@ router.post("/login", async (req, res) => { }); router.get("/logout", async (req, res) => { - try { - res.clearCookie("token"); - return res.status(200).json({ - ok: true, - message: "Logged out successfully", - code: "success" - }); - } catch (error) { - console.error('Logout error:', error); - return res.status(500).json({ - ok: false, - message: "Error during logout", - code: "server", - error: process.env.NODE_ENV === 'development' ? error : undefined - }); - } + try { + res.clearCookie("token"); + return res.status(200).json({ + ok: true, + message: "Logged out successfully", + code: "success" + }); + } catch (error) { + console.error('Logout error:', error); + return res.status(500).json({ + ok: false, + message: "Error during logout", + code: "server", + error: process.env.NODE_ENV === 'development' ? error : undefined + }); } +} ); router.get( @@ -678,7 +686,7 @@ router.get("/airtable", requireSignIn, (req: Request, res) => { router.get("/airtable/callback", requireSignIn, async (req: Request, res) => { const authenticatedReq = req as AuthenticatedRequest; const baseUrl = process.env.PUBLIC_URL || "http://localhost:5173"; - + try { const { code, state, error } = authenticatedReq.query; @@ -694,7 +702,7 @@ router.get("/airtable/callback", requireSignIn, async (req: Request, res) => { // Verify session data if (!authenticatedReq.session?.code_verifier || authenticatedReq.session.robotId !== state.toString()) { - return res.status(400).json({ + return res.status(400).json({ message: "Session expired - please restart the OAuth flow" }); } @@ -708,7 +716,7 @@ router.get("/airtable/callback", requireSignIn, async (req: Request, res) => { body: new URLSearchParams({ grant_type: "authorization_code", code: code.toString(), - client_id: process.env.AIRTABLE_CLIENT_ID!, + client_id: process.env.AIRTABLE_CLIENT_ID!, redirect_uri: process.env.AIRTABLE_REDIRECT_URI!, code_verifier: authenticatedReq.session.code_verifier }), @@ -811,7 +819,7 @@ router.get("/airtable/bases", requireSignIn, async (req: Request, res) => { // Update robot with selected base router.post("/airtable/update", requireSignIn, async (req: Request, res) => { const authenticatedReq = req as AuthenticatedRequest; - const { baseId, robotId , baseName, tableName, tableId} = req.body; + const { baseId, robotId, baseName, tableName, tableId } = req.body; if (!baseId || !robotId) { return res.status(400).json({ message: "Base ID and Robot ID are required" });