-
Notifications
You must be signed in to change notification settings - Fork 292
fix(frontend): validate Full Name and Work Email on Get Started form #4045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -61,6 +61,20 @@ function AdminSignup() { | |||||||||||||||||||||||||||||||||||||||||||
| return null; // valid | ||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const validateFullName = (name) => { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!name || !name.trim()) return null; | ||||||||||||||||||||||||||||||||||||||||||||
| if (name.trim().length < 2) return 'Full Name must be at least 2 characters long.'; | ||||||||||||||||||||||||||||||||||||||||||||
| if (!/^[\p{L}\s'-]+$/u.test(name)) return 'Full Name can only contain letters, spaces, hyphens, and apostrophes.'; | ||||||||||||||||||||||||||||||||||||||||||||
| if (/\s{2,}|^['\s-]|['\s-]$/.test(name)) return 'Full Name contains invalid spacing or punctuation.'; | ||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const validateEmail = (email) => { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!email || !email.trim()) return null; | ||||||||||||||||||||||||||||||||||||||||||||
| if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) return 'Please enter a valid work email (e.g. name@company.com).'; | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Reject whitespace-only values.
Return a required-field error for trimmed-empty values, or trim the values in the required check. Suggested fix const validateFullName = (name) => {
- if (!name || !name.trim()) return null;
+ if (!name || !name.trim()) return 'Full Name is required.';
if (name.trim().length < 2) return 'Full Name must be at least 2 characters long.';
if (!/^[\p{L}\s'-]+$/u.test(name)) return 'Full Name can only contain letters, spaces, hyphens, and apostrophes.';
if (/\s{2,}|^['\s-]|['\s-]$/.test(name)) return 'Full Name contains invalid spacing or punctuation.';
return null;
};
const validateEmail = (email) => {
- if (!email || !email.trim()) return null;
+ if (!email || !email.trim()) return 'Work Email is required.';
if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) return 'Please enter a valid work email (e.g. name@company.com).';
return null;
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+72
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Reject malformed dot and hyphen placement in email addresses. The current pattern accepts Suggested structured validation const validateEmail = (email) => {
if (!email || !email.trim()) return null;
- if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) return 'Please enter a valid work email (e.g. name@company.com).';
+ const parts = email.split("@");
+ const [local, domain] = parts;
+ const labels = domain?.split(".") ?? [];
+ const isValid =
+ parts.length === 2 &&
+ /^[a-zA-Z0-9._%+-]+$/.test(local) &&
+ !local.startsWith(".") &&
+ !local.endsWith(".") &&
+ !local.includes("..") &&
+ labels.length >= 2 &&
+ labels.every((label) => /^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(label)) &&
+ /^[a-zA-Z]{2,}$/.test(labels[labels.length - 1]);
+ if (!isValid) return 'Please enter a valid work email (e.g. name@company.com).';
return null;
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Password strength calculation | ||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||
| const pw = formData.password; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,6 +101,16 @@ function AdminSignup() { | |||||||||||||||||||||||||||||||||||||||||||
| setError("Please fill in all required personal information."); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const nameError = validateFullName(formData.fullName); | ||||||||||||||||||||||||||||||||||||||||||||
| if (nameError) { | ||||||||||||||||||||||||||||||||||||||||||||
| setError(nameError); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| const emailError = validateEmail(formData.email); | ||||||||||||||||||||||||||||||||||||||||||||
| if (emailError) { | ||||||||||||||||||||||||||||||||||||||||||||
| setError(emailError); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+104
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Guard the form submission path, not only The new checks run only in Route non-final submissions through Suggested fix const handleSubmit = async (e) => {
e.preventDefault();
+ if (step !== 3) {
+ nextStep();
+ return;
+ }
if (!formData.agreedToTerms || !formData.isAuthorized) {
setError("You must agree to the terms and authorize company registration.");
return;🧰 Tools🪛 ast-grep (0.45.0)[warning] 105-105: Avoid using the initial state variable in setState (setstate-same-var) [warning] 110-110: Avoid using the initial state variable in setState (setstate-same-var) 🤖 Prompt for AI Agents🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate the signup implementation and downstream handlers.
while IFS= read -r file; do
rg -n -C 8 '\bsignup\b|auth\.signUp|fullName|email' "$file" || true
done < <(fd -t f -i 'authStore' .)
rg -n -C 6 \
'auth\.signUp|signUp\s*\(|fullName|full_name|email|profiles|admin' \
--glob '*.js' \
--glob '*.jsx' \
--glob '*.ts' \
--glob '*.tsx' \
--glob '*.sql' \
. || true
# Expected: server-side validation rejects invalid names and emails before persistence.Repository: riteshbonthalakoti/HELPDESK.AI Length of output: 220 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "## files matching auth/admin signup"
git ls-files | rg -n 'AdminSignup|App\.jsx|auth|signup|AuthStore|supabase|schema|profiles|admin' || true
echo
echo "## AdminSignup relevant lines"
if [ -f Frontend/src/pages/AdminSignup.jsx ]; then
nl -ba Frontend/src/pages/AdminSignup.jsx | sed -n '1,220p'
fi
echo
echo "## App signup route lines"
if [ -f Frontend/src/App.jsx ]; then
nl -ba Frontend/src/App.jsx | sed -n '1,220p'
fi
echo
echo "## target identifiers in tracked files"
python3 - <<'PY'
import subprocess
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
terms = ['signup','signUp','auth.signUp','fullName','full_name','email','profiles','admin']
for term in terms:
matches = []
for f,fname in zip(files,files):
if fname.endswith(('.js','.jsx','.ts','.tsx','.sql','.json','.env*','.md'))):
try:
text = open(f,'r',errors='ignore').read()
except Exception:
continue
if term in text:
matches.append(fname)
print(f"\n# {term}")
for m in matches[:200]:
print(m)
PYRepository: riteshbonthalakoti/HELPDESK.AI Length of output: 2899 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "## frontend lines"
for f in Frontend/src/pages/AdminSignup.jsx Frontend/src/App.jsx Frontend/src/store/authStore.js Frontend/src/store/adminStore.js Frontend/src/lib/supabaseClient.js; do
if [ -f "$f" ]; then
echo "--- $f"
awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,240p'
fi
done
echo
echo "## backend/auth/relevant lines"
for f in supabase/functions/ai-proxy/index.ts supabase/functions/email-notifier/index.ts supabase/functions/send-user-approval-email/index.ts supabase/migrations/20260330231301_knowledge_base.sql supabase/migrations/20260330231302_webhook-trigger.sql supabase/migrations/20260331000000_resolve_vault_sync.sql supabase/migrations/20260331000001_sync_vault.sql; do
if [ -f "$f" ]; then
echo "--- $f"
awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,220p'
fi
done
echo
echo "## search exact identifiers"
python3 - <<'PY'
import subprocess, re
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
terms = [r'\bsignup\b', r'/admin-signup', r'\bauth\.signUp\b', r'\bsignUp\s*\(', r'\bfullName\b', r'\bfull_name\b', r'\bemail\b', r'\bprofiles\b', r'\badmin\b']
for term in terms:
print(f"\n# {term}")
pat = re.compile(term)
count = 0
for f in files:
if f.endswith(('.js','.jsx','.ts','.tsx','.sql','.json','.env','.md'))):
try:
text = open(f,'r',errors='ignore').read()
except Exception:
continue
for i,line in enumerate(text.splitlines(),1):
if pat.search(line):
print(f"{f}:{i}:{line.strip()}")
count += 1
print(f"totalCount={count}")
PYRepository: riteshbonthalakoti/HELPDESK.AI Length of output: 50386 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "## supabase migration files list"
git ls-files supabase/migrations | awk '{printf "%6d\t%s\n", NR, $0}' | sed -n '1,120p'
echo
echo "## migrations containing profiles/auth hooks/email validation"
for f in $(git ls-files supabase/migrations); do
if rg -q 'CREATE TABLE "profiles"|FULL NAME|full_name|user_details|auth\.users|security\s+definer|check\(|is_email|email' "$f"; then
echo "--- $f"
rg -n -C 5 'profiles|full_name|security\s+definer|check\(|is_email|email|admin|role' "$f" || true
fi
done
echo
echo "## Supabase Edge functions signup/profile handling"
git ls-files supabase/functions | while read -r f; do
if rg -q 'auth\.signUp|insert\(|profiles|full_name|send-user-approval|approval|after.*auth' "$f" 2>/dev/null; then
echo "--- $f"
rg -n -C 4 'auth\.signUp|insert\(|profiles|full_name|send-user-approval|approval|after.*auth|RECORD' "$f" || true
fi
done
echo
echo "## exact targeted references (limited)"
python3 - <<'PY'
import subprocess, re
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
terms=[
r'\bsignup\b', r'/admin-signup', r'\bauth\.signUp\b',
r'auth\.signUp\s*\(',
r'\bfullName\b', r'\bfull_name\b',
r'\bemail\b', r'profiles',
r'(create\s+trigger|CREATE\s+TRIGGER|security\s+definer|RECORD\.full_name|record\.full_name|new\.full_name|old\.full_name)',
]
for term in terms:
print(f"\n# {term}")
pat=re.compile(term, re.I)
for f in files:
if f.endswith(('.js','.jsx','.ts','.tsx','.sql','.json','.env','.md')) and (f.startswith('Frontend/src') or f.startswith('supabase') or f.startswith('backend')):
try: text=open(f,errors='ignore').read()
except Exception: continue
try: lines=text.splitlines()
except Exception: continue
for i,line in enumerate(lines,1):
if pat.search(line) and not f.endswith(('.tmp','.lock','package-lock.json')):
print(f"{f}:{i}:{line.strip()}")
PYRepository: riteshbonthalakoti/HELPDESK.AI Length of output: 50386 Reject invalid admin signup values server-side.
🧰 Tools🪛 ast-grep (0.45.0)[warning] 105-105: Avoid using the initial state variable in setState (setstate-same-var) [warning] 110-110: Avoid using the initial state variable in setState (setstate-same-var) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| const pwError = validatePassword(formData.password); | ||||||||||||||||||||||||||||||||||||||||||||
| if (pwError) { | ||||||||||||||||||||||||||||||||||||||||||||
| setError(pwError); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Restrict Full Name separators to spaces.
The
\scharacter class accepts tabs, line breaks, and other whitespace. A value such as"Grace\tHopper"passes the allowed-character check because the spacing rule only rejects repeated whitespace or boundary punctuation. Use a literal space or explicitly define the accepted Unicode separators.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents