Spaces:
Running
Running
ChandimaPrabath
commited on
Commit
·
2ea6bf5
1
Parent(s):
92f01f5
username validation
Browse files- frontend/app/layout.js +1 -1
- frontend/app/page.js +3 -0
- frontend/components/NexusAuth.js +35 -3
frontend/app/layout.js
CHANGED
@@ -6,7 +6,7 @@ import { ToastContainer, Flip } from 'react-toastify';
|
|
6 |
import { CheckCircleIcon, InformationCircleIcon, ExclamationCircleIcon } from '@heroicons/react/20/solid';
|
7 |
import Sidebar from "@components/Sidebar";
|
8 |
|
9 |
-
import { ToastProvider } from "
|
10 |
|
11 |
export default function RootLayout({ children }) {
|
12 |
const contentStyle = {
|
|
|
6 |
import { CheckCircleIcon, InformationCircleIcon, ExclamationCircleIcon } from '@heroicons/react/20/solid';
|
7 |
import Sidebar from "@components/Sidebar";
|
8 |
|
9 |
+
import { ToastProvider } from "@lib/ToastContext";
|
10 |
|
11 |
export default function RootLayout({ children }) {
|
12 |
const contentStyle = {
|
frontend/app/page.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
'use client';
|
2 |
|
3 |
import { useState, useEffect } from "react";
|
|
|
4 |
import NexusAuthApi from "@lib/Nexus_Auth_API";
|
5 |
|
6 |
export default function Home() {
|
@@ -8,6 +9,7 @@ export default function Home() {
|
|
8 |
const [userID, setUserID] = useState(null);
|
9 |
const [token, setToken] = useState(null);
|
10 |
const [accessLevel, setAccessLevel] = useState(null);
|
|
|
11 |
|
12 |
useEffect(() => {
|
13 |
setUsername(localStorage.getItem('me'));
|
@@ -28,6 +30,7 @@ export default function Home() {
|
|
28 |
NexusAuthApi.logout(userID, token)
|
29 |
.then(() => {
|
30 |
clearLocalStorage();
|
|
|
31 |
window.location.reload();
|
32 |
})
|
33 |
.catch((error) => {
|
|
|
1 |
'use client';
|
2 |
|
3 |
import { useState, useEffect } from "react";
|
4 |
+
import { useRouter } from "next/router";
|
5 |
import NexusAuthApi from "@lib/Nexus_Auth_API";
|
6 |
|
7 |
export default function Home() {
|
|
|
9 |
const [userID, setUserID] = useState(null);
|
10 |
const [token, setToken] = useState(null);
|
11 |
const [accessLevel, setAccessLevel] = useState(null);
|
12 |
+
const router = useRouter();
|
13 |
|
14 |
useEffect(() => {
|
15 |
setUsername(localStorage.getItem('me'));
|
|
|
30 |
NexusAuthApi.logout(userID, token)
|
31 |
.then(() => {
|
32 |
clearLocalStorage();
|
33 |
+
router.push('/');
|
34 |
window.location.reload();
|
35 |
})
|
36 |
.catch((error) => {
|
frontend/components/NexusAuth.js
CHANGED
@@ -12,10 +12,14 @@ const SignupForm = ({ onSignup }) => {
|
|
12 |
const [confirmPassword, setConfirmPassword] = useState('');
|
13 |
const [email, setEmail] = useState('');
|
14 |
const [usernameAvailable, setUsernameAvailable] = useState(null); // null for initial state
|
|
|
|
|
15 |
const [passwordValid, setPasswordValid] = useState(false); // Initially invalid
|
16 |
const [formValid, setFormValid] = useState(false);
|
17 |
const [debounceTimeout, setDebounceTimeout] = useState(null); // Store timeout ID
|
18 |
|
|
|
|
|
19 |
const validatePassword = (password) => {
|
20 |
return password.length >= 8;
|
21 |
};
|
@@ -32,11 +36,29 @@ const SignupForm = ({ onSignup }) => {
|
|
32 |
clearTimeout(debounceTimeout);
|
33 |
}
|
34 |
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
// Set a new timeout to check availability
|
37 |
const newTimeout = setTimeout(async () => {
|
38 |
try {
|
39 |
-
const response = await NexusAuthApi.isUsernameAvailable(
|
40 |
setUsernameAvailable(response?.is_available === true);
|
41 |
} catch (error) {
|
42 |
console.error('Error checking username availability:', error);
|
@@ -48,6 +70,9 @@ const SignupForm = ({ onSignup }) => {
|
|
48 |
} else {
|
49 |
setUsernameAvailable(null); // Reset availability check when input is empty
|
50 |
}
|
|
|
|
|
|
|
51 |
};
|
52 |
|
53 |
const handlePasswordChange = (e) => {
|
@@ -76,7 +101,8 @@ const SignupForm = ({ onSignup }) => {
|
|
76 |
usernameAvailable === true &&
|
77 |
password === confirmPassword &&
|
78 |
passwordValid &&
|
79 |
-
username.length
|
|
|
80 |
);
|
81 |
}, [username, password, confirmPassword, usernameAvailable, passwordValid]);
|
82 |
|
@@ -94,6 +120,12 @@ const SignupForm = ({ onSignup }) => {
|
|
94 |
{usernameAvailable === true && username.length > 0 && (
|
95 |
<CheckCircleIcon className="h-5 w-5 text-green-500" />
|
96 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
{usernameAvailable === false && (
|
98 |
<p className="error-message text-red-500">Username is already taken</p>
|
99 |
)}
|
|
|
12 |
const [confirmPassword, setConfirmPassword] = useState('');
|
13 |
const [email, setEmail] = useState('');
|
14 |
const [usernameAvailable, setUsernameAvailable] = useState(null); // null for initial state
|
15 |
+
const [doesUsernameContainInvalidChars, setDoesUsernameContainInvalidChars] = useState(false);
|
16 |
+
const [doesUsernameExceedMinLength, setDoesUsernameExceedMinLength] = useState(false);
|
17 |
const [passwordValid, setPasswordValid] = useState(false); // Initially invalid
|
18 |
const [formValid, setFormValid] = useState(false);
|
19 |
const [debounceTimeout, setDebounceTimeout] = useState(null); // Store timeout ID
|
20 |
|
21 |
+
const minUsernameLength = 3;
|
22 |
+
|
23 |
const validatePassword = (password) => {
|
24 |
return password.length >= 8;
|
25 |
};
|
|
|
36 |
clearTimeout(debounceTimeout);
|
37 |
}
|
38 |
|
39 |
+
// Check for invalid characters
|
40 |
+
const invalidChars = /[^a-zA-Z0-9_]/g;
|
41 |
+
if (invalidChars.test(newUsername)) {
|
42 |
+
setDoesUsernameContainInvalidChars(true);
|
43 |
+
setTimeout(() => {
|
44 |
+
setDoesUsernameContainInvalidChars(false);
|
45 |
+
}, 2000); // Show error for 2 seconds
|
46 |
+
}
|
47 |
+
|
48 |
+
// Basic sanitization to prevent SQL injection
|
49 |
+
const sanitizedUsername = newUsername.replace(invalidChars, '');
|
50 |
+
|
51 |
+
if (sanitizedUsername.length < minUsernameLength) {
|
52 |
+
setDoesUsernameExceedMinLength(false);
|
53 |
+
return;
|
54 |
+
} else {
|
55 |
+
setDoesUsernameExceedMinLength(true);}
|
56 |
+
|
57 |
+
if (sanitizedUsername.trim().length > 0) {
|
58 |
// Set a new timeout to check availability
|
59 |
const newTimeout = setTimeout(async () => {
|
60 |
try {
|
61 |
+
const response = await NexusAuthApi.isUsernameAvailable(sanitizedUsername);
|
62 |
setUsernameAvailable(response?.is_available === true);
|
63 |
} catch (error) {
|
64 |
console.error('Error checking username availability:', error);
|
|
|
70 |
} else {
|
71 |
setUsernameAvailable(null); // Reset availability check when input is empty
|
72 |
}
|
73 |
+
|
74 |
+
// Set sanitized username
|
75 |
+
setUsername(sanitizedUsername);
|
76 |
};
|
77 |
|
78 |
const handlePasswordChange = (e) => {
|
|
|
101 |
usernameAvailable === true &&
|
102 |
password === confirmPassword &&
|
103 |
passwordValid &&
|
104 |
+
username.length >= minUsernameLength &&
|
105 |
+
!doesUsernameContainInvalidChars
|
106 |
);
|
107 |
}, [username, password, confirmPassword, usernameAvailable, passwordValid]);
|
108 |
|
|
|
120 |
{usernameAvailable === true && username.length > 0 && (
|
121 |
<CheckCircleIcon className="h-5 w-5 text-green-500" />
|
122 |
)}
|
123 |
+
{doesUsernameExceedMinLength === false && (
|
124 |
+
<p className="error-message text-red-500">Username must have more than {minUsernameLength} characters.</p>
|
125 |
+
)}
|
126 |
+
{doesUsernameContainInvalidChars === true && (
|
127 |
+
<p className="error-message text-red-500">Username cannot contain invalid characters.</p>
|
128 |
+
)}
|
129 |
{usernameAvailable === false && (
|
130 |
<p className="error-message text-red-500">Username is already taken</p>
|
131 |
)}
|