diff --git a/apps/web/src/pages/change-password-page.tsx b/apps/web/src/pages/change-password-page.tsx index 6f912747..98023226 100644 --- a/apps/web/src/pages/change-password-page.tsx +++ b/apps/web/src/pages/change-password-page.tsx @@ -1,11 +1,40 @@ import { type FormEvent, useState } from "react"; +function generatePassword(): string { + const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const lower = "abcdefghijklmnopqrstuvwxyz"; + const digits = "0123456789"; + const all = upper + lower + digits; + // Guarantee at least one of each required character class + const required = [ + upper[Math.floor(Math.random() * upper.length)], + lower[Math.floor(Math.random() * lower.length)], + digits[Math.floor(Math.random() * digits.length)], + ]; + const rest = Array.from({ length: 13 }, () => all[Math.floor(Math.random() * all.length)]); + // Shuffle so the required chars aren't always at the start + const chars = [...required, ...rest]; + for (let i = chars.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [chars[i], chars[j]] = [chars[j], chars[i]]; + } + return chars.join(""); +} + export function ChangePasswordPage() { const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); + const [showGenerated, setShowGenerated] = useState(false); + + const handleGenerate = () => { + const pw = generatePassword(); + setNewPassword(pw); + setConfirmPassword(pw); + setShowGenerated(true); + }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); @@ -58,6 +87,13 @@ export function ChangePasswordPage() {