diff --git a/app/account/signup/page.tsx b/app/account/signup/page.tsx
index 950ef60..b8560c5 100644
--- a/app/account/signup/page.tsx
+++ b/app/account/signup/page.tsx
@@ -10,12 +10,13 @@ import { Button } from "@/components/ui/button"
import { Switch } from "@/components/ui/switch"
import Link from "next/link"
import { motion, AnimatePresence } from "motion/react"
-import { UserPlus, UserCog, Heart, AlertCircle, CheckCircle2, Mail, Lock, User, Bot, Loader, ArrowLeft } from "lucide-react"
+import { UserPlus, UserCog, Heart, AlertCircle, CheckCircle2, Mail, Lock, User, Bot, Loader2, ArrowLeft } from "lucide-react"
import { useRouter } from "next/navigation"
-import { validateEmail, validatePassword } from "@/lib/utils"
+import { validateEmail, validatePassword, validateName } from "@/lib/utils"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import EmailField from "@/components/custom/signup/EmailField"
import Altcha from "@/components/custom/Altcha"
+import { useSession } from "next-auth/react"
export default function Signup() {
const router = useRouter()
@@ -76,9 +77,11 @@ export default function Signup() {
useEffect(() => {
if (formType === "create") {
const { name, emailUsername, emailDomain, password, terms } = formData
- if (name.length < 2) {
+
+ const nameValidation = validateName(name)
+ if (!nameValidation.valid) {
setIsValid(false)
- setValidationMessage("Enter your name")
+ setValidationMessage(nameValidation.message)
return
}
@@ -112,9 +115,11 @@ export default function Signup() {
setValidationMessage("Create Account")
} else if (formType === "migrate") {
const { emailUsername, emailDomain, migratePassword, migrateTerms, migrateName } = formData
- if (migrateName.length < 2) {
+
+ const nameValidation = validateName(migrateName)
+ if (!nameValidation.valid) {
setIsValid(false)
- setValidationMessage("Enter your name")
+ setValidationMessage(nameValidation.message)
return
}
@@ -151,11 +156,12 @@ export default function Signup() {
const getButtonIcon = () => {
if (isValid) return
- if (validationMessage.includes("name")) return
+ if (validationMessage.includes("name") || validationMessage.includes("Name")) return
if (validationMessage.includes("Email") || validationMessage.includes("email")) return
if (validationMessage.includes("Password") || validationMessage.includes("password")) return
if (validationMessage.includes("terms")) return
if (validationMessage.includes("robot") || validationMessage.includes("Security")) return
+ if (validationMessage.includes("special characters")) return
return null
}
@@ -219,12 +225,54 @@ export default function Signup() {
}
}
+ const { data: session } = useSession()
+
+ useEffect(() => {
+ if (session) {
+ router.push("/account/dashboard")
+ }
+ }, [session, router])
+
return (
- Account Setup
- Create a new account or migrate an existing one.
+
+ {formType === "initial" ? (
+
+ Account Setup
+ Create a new account or migrate an existing one.
+
+ ) : formType === "create" ? (
+
+ Create New Account
+ Set up your new LibreCloud account.
+
+ ) : (
+
+ Migrate Account
+ Transfer your p0ntus mail account to LibreCloud.
+
+ )}
+
{errorAlert && (
@@ -301,11 +349,11 @@ export default function Signup() {
/>
@@ -378,11 +426,11 @@ export default function Signup() {
/>
@@ -416,7 +464,7 @@ export default function Signup() {
onClick={handleSubmit}
>
{isSubmitting ? (
-
+
) : (
getButtonIcon()
)}
@@ -445,5 +493,4 @@ export default function Signup() {
)
-}
-
+}
\ No newline at end of file
diff --git a/app/account/signup/success/page.tsx b/app/account/signup/success/page.tsx
index 1ad52d4..df7fa60 100644
--- a/app/account/signup/success/page.tsx
+++ b/app/account/signup/success/page.tsx
@@ -140,7 +140,7 @@ const WelcomePage = () => {
From here, you can proceed to sign in to your newly created account with Authentik. It will handle all the sign-ins for your account except for Pass (Vaultwarden).
-
+
diff --git a/app/api/auth/password/route.ts b/app/api/auth/password/route.ts
index 7ac92d2..cec0612 100644
--- a/app/api/auth/password/route.ts
+++ b/app/api/auth/password/route.ts
@@ -1,6 +1,7 @@
import { auth } from "@/auth"
import axios from "axios"
import { NextResponse } from "next/server"
+import { validatePassword } from "@/lib/utils"
export async function POST(request: Request) {
try {
@@ -14,6 +15,11 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "Invalid password" }, { status: 400 })
}
+ const passwordValidation = validatePassword(password)
+ if (!passwordValidation.valid) {
+ return NextResponse.json({ error: passwordValidation.message }, { status: 400 })
+ }
+
// Get user ID from email
const user = await axios.request({
method: "get",
diff --git a/app/api/mail/password/route.ts b/app/api/mail/password/route.ts
index 29040c4..80e311b 100644
--- a/app/api/mail/password/route.ts
+++ b/app/api/mail/password/route.ts
@@ -1,5 +1,6 @@
import { auth } from "@/auth"
import { NextResponse } from "next/server"
+import { validatePassword } from "@/lib/utils"
export async function POST(request: Request) {
try {
@@ -13,6 +14,11 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "Invalid password" }, { status: 400 })
}
+ const passwordValidation = validatePassword(password)
+ if (!passwordValidation.valid) {
+ return NextResponse.json({ error: passwordValidation.message }, { status: 400 })
+ }
+
const { email } = session.user
const response = await fetch(`${process.env.MAIL_CONNECT_API_URL}/accounts/update/password`, {
diff --git a/app/api/users/create/route.ts b/app/api/users/create/route.ts
index 6c22d9e..e2781fc 100644
--- a/app/api/users/create/route.ts
+++ b/app/api/users/create/route.ts
@@ -1,6 +1,7 @@
import axios from "axios"
import { NextResponse } from "next/server"
-import { validateToken } from "@/lib/utils"
+import { validateToken, validateName, validateEmail } from "@/lib/utils"
+import { auth } from "@/auth"
// This endpoint has two functions:
// (1) Create a new LibreCloud user (Authentik, Email)
@@ -68,15 +69,33 @@ export async function POST(request: Request) {
let atkCreated = false
let userID = ""
+ const session = await auth()
+ if (session) {
+ return NextResponse.json({ success: false, message: "You are already logged in" }, { status: 403 })
+ }
+
try {
const body = await request.json()
const { name, email, password, migrate, token } = body
- // Validate fields
+ // Make sure all fields are present
if (!name || !email || !password) {
return NextResponse.json({ success: false, message: "The form you submitted is incomplete" }, { status: 400 })
}
+ // Validate name again
+ const nameValidation = validateName(name)
+ if (!nameValidation.valid) {
+ return NextResponse.json({ success: false, message: nameValidation.message }, { status: 400 })
+ }
+
+ // and email
+ const [emailUsername, emailDomain] = email.split('@')
+ const emailValidation = validateEmail(emailUsername, emailDomain)
+ if (!emailValidation.valid) {
+ return NextResponse.json({ success: false, message: emailValidation.message }, { status: 400 })
+ }
+
const tokenValidation = await validateToken(token)
if (!tokenValidation.success) {
console.error("Altcha validation failed:", tokenValidation.error)
diff --git a/components/cards/dashboard/Settings/ChangeEmailPassword.tsx b/components/cards/dashboard/Settings/ChangeEmailPassword.tsx
index d32fa5a..ff5a3b7 100644
--- a/components/cards/dashboard/Settings/ChangeEmailPassword.tsx
+++ b/components/cards/dashboard/Settings/ChangeEmailPassword.tsx
@@ -4,7 +4,7 @@ import React, { useState, useRef, useEffect, useCallback } from "react"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
-import { CheckCircleIcon, Key, Loader2, XCircleIcon } from "lucide-react"
+import { CheckCircleIcon, Key, Loader2, XCircleIcon, AlertCircle } from "lucide-react"
import Link from "next/link"
import {
Dialog,
@@ -17,6 +17,7 @@ import {
} from "@/components/ui/dialog"
import { toast } from "sonner"
import { motion, useAnimationControls } from "framer-motion"
+import { validatePassword } from "@/lib/utils"
export function ChangeEmailPassword() {
const [newPassword, setNewPassword] = useState("")
@@ -28,6 +29,7 @@ export function ChangeEmailPassword() {
const [isHolding, setIsHolding] = useState(false)
const holdDuration = 10
const [remainingTime, setRemainingTime] = useState(holdDuration)
+ const [passwordError, setPasswordError] = useState(null)
const submitPasswordChange = async () => {
setLoading(true)
@@ -86,17 +88,16 @@ export function ChangeEmailPassword() {
},
})
controls.set({ "--progress": "0%" })
- } finally {
- setLoading(false)
- setIsHolding(false)
- if (holdTimeoutRef.current) {
- clearTimeout(holdTimeoutRef.current)
- holdTimeoutRef.current = null
- }
- if (intervalRef.current) {
- clearInterval(intervalRef.current)
- intervalRef.current = null
- }
+ }
+ setLoading(false)
+ setIsHolding(false)
+ if (holdTimeoutRef.current) {
+ clearTimeout(holdTimeoutRef.current)
+ holdTimeoutRef.current = null
+ }
+ if (intervalRef.current) {
+ clearInterval(intervalRef.current)
+ intervalRef.current = null
}
}
@@ -104,10 +105,23 @@ export function ChangeEmailPassword() {
e.preventDefault()
}
+ const handlePasswordChange = (e: React.ChangeEvent) => {
+ const value = e.target.value
+ setNewPassword(value)
+
+ // Validate password
+ const validation = validatePassword(value)
+ if (!validation.valid) {
+ setPasswordError(validation.message)
+ } else {
+ setPasswordError(null)
+ }
+ }
+
const holdDurationMs = holdDuration * 1000
const handleHoldStart = () => {
- if (loading || newPassword.length < 8) return
+ if (loading || newPassword.length < 8 || passwordError) return
setIsHolding(true)
controls.set({ "--progress": "0%" })
@@ -205,12 +219,19 @@ export function ChangeEmailPassword() {
id="new-password"
type="password"
value={newPassword}
- onChange={(e) => setNewPassword(e.target.value)}
+ onChange={handlePasswordChange}
className="mt-1.5"
/>
-
- Password must be at least 8 characters long.
-
+ {passwordError ? (
+
+
+ {passwordError}
+
+ ) : (
+
+ Password must be 8-128 characters long, include letters and digits, and not contain spaces.
+
+ )}