feat: zod form validation

This commit is contained in:
2024-05-04 17:57:08 +00:00
parent 6438a3d679
commit 99c907a2b5
5 changed files with 32 additions and 44 deletions

View File

@@ -28,7 +28,8 @@
"react-dom": "^18",
"sonner": "^1.4.41",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.6"
},
"devDependencies": {
"@types/node": "^20",

View File

@@ -5,9 +5,16 @@ import Link from "next/link";
import { useFormState } from "react-dom";
import { login } from "@/lib/auth/actions";
import SubmitButton from "@/components/app/SubmitButton/SubmitButton";
import { useEffect } from "react";
import { toast } from "sonner";
export default function Page() {
const [, formAction] = useFormState(login, null);
const [formData, formAction] = useFormState(login, null);
useEffect(() => {
if (formData?.error) {
toast.error(formData.error)
}
}, [formData])
return (
<div className="flex items-center p-4 lg:p-8">

View File

@@ -6,6 +6,7 @@ import { redirect } from "next/navigation";
import prisma from "../db";
import { Argon2id } from "oslo/password";
import { generateId } from "lucia";
import { accountSchema } from "./zod";
export async function logout() {
const { session } = await validateRequest();
@@ -16,25 +17,13 @@ export async function logout() {
}
export async function login(prev: any, data: FormData) {
const username = data.get("username");
if (
typeof username !== "string" ||
username.length < 3 ||
username.length > 31 ||
!/^[a-z0-9_-]+$/.test(username)
) {
const checkSchema = await accountSchema.safeParseAsync(Object.fromEntries(data.entries()))
if (!checkSchema.success)
return {
error: "Invalid username",
error: `From ${checkSchema.error.errors[0].path[0]}: ${checkSchema.error.errors[0].message}`,
success: false,
};
}
const password = data.get("password");
if (typeof password !== "string" || password.length < 6 || password.length > 255) {
return {
error: "Invalid password",
success: false,
};
}
const { username, password } = checkSchema.data;
const existingUser = await prisma.user.findUnique({
where: {
@@ -72,35 +61,13 @@ export async function login(prev: any, data: FormData) {
}
export async function signup(prev: any, formData: FormData): Promise<ActionResult> {
"use server";
const username = formData.get("username");
console.log(username)
// username must be between 4 ~ 31 characters, and only consists of lowercase letters, 0-9, -, and _
// keep in mind some database (e.g. mysql) are case insensitive
if (
typeof username !== "string" ||
username.length < 3 ||
username.length > 31 ||
!/^[a-z0-9_-]+$/.test(username)
) {
const checkSchema = await accountSchema.safeParseAsync(Object.fromEntries(formData.entries()))
if (!checkSchema.success)
return {
error: "Invalid username",
error: `From ${checkSchema.error.errors[0].path[0]}: ${checkSchema.error.errors[0].message}`,
success: false,
};
}
if (await prisma.user.findUnique({ where: { username: username } })) {
return {
error: "Username is already taken",
success: false,
};
}
const password = formData.get("password");
if (typeof password !== "string" || password.length < 6 || password.length > 255) {
return {
error: "Invalid password",
success: false,
};
}
const { username, password } = checkSchema.data;
const hashedPassword = await new Argon2id().hash(password);
const userId = generateId(15);

8
src/lib/auth/zod.ts Normal file
View File

@@ -0,0 +1,8 @@
'use server'
import { z } from 'zod'
export const accountSchema = z.object({
username: z.string().min(3, { message: 'Mininum 3 characters' }).max(31, { message: 'Maximum 31 characters' }).regex(/^[a-z0-9_-]+$/, { message: 'Only characters from a-z, 0-9, underscores and dashes' }),
password: z.string().min(6, { message: 'Minimum 6 characters' }).max(255, { message: 'Maximum 255 characters' }),
})

View File

@@ -3392,3 +3392,8 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.23.6:
version "3.23.6"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.6.tgz#c08a977e2255dab1fdba933651584a05fcbf19e1"
integrity sha512-RTHJlZhsRbuA8Hmp/iNL7jnfc4nZishjsanDAfEY1QpDQZCahUp3xDzl+zfweE9BklxMUcgBgS1b7Lvie/ZVwA==