diff --git a/package.json b/package.json
index e7e4c4a..fe2f208 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/app/auth/signIn/page.tsx b/src/app/auth/signIn/page.tsx
index 2e7b28a..69e5e0f 100644
--- a/src/app/auth/signIn/page.tsx
+++ b/src/app/auth/signIn/page.tsx
@@ -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 (
diff --git a/src/lib/auth/actions.ts b/src/lib/auth/actions.ts
index 9e88d8b..82c9e78 100644
--- a/src/lib/auth/actions.ts
+++ b/src/lib/auth/actions.ts
@@ -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
{
- "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);
diff --git a/src/lib/auth/zod.ts b/src/lib/auth/zod.ts
new file mode 100644
index 0000000..9d3af86
--- /dev/null
+++ b/src/lib/auth/zod.ts
@@ -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' }),
+})
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 6b7bd78..aef9af9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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==