diff --git a/src/app/(editor)/page.tsx b/src/app/(editor)/page.tsx
index 231d4f6..13cda23 100644
--- a/src/app/(editor)/page.tsx
+++ b/src/app/(editor)/page.tsx
@@ -13,10 +13,12 @@ export default async function Home() {
return (
-
- Changes are not saved!
- Log in to save your notes.
-
+ {!auth && (
+
+ Changes are not saved!
+ Log in to save your notes.
+
+ )}
);
}
diff --git a/src/app/(noneditor)/auth/page.tsx b/src/app/(noneditor)/auth/page.tsx
index 6d05536..417f29c 100644
--- a/src/app/(noneditor)/auth/page.tsx
+++ b/src/app/(noneditor)/auth/page.tsx
@@ -11,12 +11,14 @@ export default function About() {
<>
Authenticate
-
Please, use this form to log in/register:
-
+
-
Welcome to rhyme!
-
Free service for writing and saving notes, lyrics, poetry, etc...
+
Welcome to Rhyme!
+
Free service for writing and saving notes, lyrics, poetry, etc
Made with ❤️ by Kirill Siukhin
>
diff --git a/src/app/(noneditor)/notes/page.tsx b/src/app/(noneditor)/notes/page.tsx
index a6e6b8b..359cd30 100644
--- a/src/app/(noneditor)/notes/page.tsx
+++ b/src/app/(noneditor)/notes/page.tsx
@@ -1,7 +1,7 @@
import { Metadata } from "next";
export const metadata: Metadata = {
- title: "My notes - Rhyme",
+ title: "Notes - Rhyme",
description: "View, create and edit your notes",
};
diff --git a/src/app/actions.ts b/src/app/actions.ts
index f4a1bc3..316a001 100644
--- a/src/app/actions.ts
+++ b/src/app/actions.ts
@@ -10,7 +10,7 @@ import bcrypt from "bcrypt";
const JWT_SECRET = process.env.JWT_SECRET!;
-export async function authenticate(_prevState: unknown, formData: FormData) {
+export async function login(_prevState: unknown, formData: FormData) {
const username = formData.get("username") as string;
const password = formData.get("password") as string;
@@ -25,12 +25,9 @@ export async function authenticate(_prevState: unknown, formData: FormData) {
.where(eq(usersTable.username, username));
if (users.length === 0) {
- await db.insert(usersTable).values({
- username,
- password: bcrypt.hashSync(password, bcrypt.genSaltSync()),
- });
+ return { error: "Invalid password or username!" };
} else if (!bcrypt.compareSync(password, users[0].password)) {
- return { error: "Invalid password or username is already taken" };
+ return { error: "Invalid password or username!" };
}
const token = jwt.sign({ sub: username }, JWT_SECRET, { expiresIn: "7d" });
@@ -45,6 +42,46 @@ export async function authenticate(_prevState: unknown, formData: FormData) {
redirect("/notes");
}
+export async function register(_prevState: unknown, formData: FormData) {
+ const username = formData.get("username") as string;
+ const password = formData.get("password") as string;
+ const passwordConfirm = formData.get("password_confirm") as string;
+
+ if (password !== passwordConfirm) {
+ return { error: "Passwords do not match!" };
+ }
+
+ if (username.length < 3) {
+ return { error: "Username is too short!" };
+ } else if (password.length < 8) {
+ return { error: "Password is too short!" };
+ }
+
+ const users = await db.select()
+ .from(usersTable)
+ .where(eq(usersTable.username, username));
+
+ if (users.length !== 0) {
+ return { error: "Username is already taken!" };
+ }
+
+ await db.insert(usersTable).values({
+ username,
+ password: bcrypt.hashSync(password, bcrypt.genSaltSync()),
+ });
+
+ const token = jwt.sign({ sub: username }, JWT_SECRET, { expiresIn: "7d" });
+
+ const cookieStore = await cookies();
+ cookieStore.set("session", token, {
+ httpOnly: true,
+ path: "/",
+ maxAge: 60 * 60 * 24 * 7,
+ });
+
+ redirect("/notes");
+}
+
export async function logOut() {
const cookieStore = await cookies();
cookieStore.delete("session");
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 1cb83bc..d52903f 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,8 +1,8 @@
import Link from "next/link";
import { ArrowRightFromLine, CircleQuestionMark, List, Plus, UserRound, UserRoundMinus } from "lucide-react";
+import { logOut } from "@/app/actions";
import { getAuth } from "@/lib/auth";
import HeaderButton from "./HeaderButton";
-import { logOut } from "@/app/actions";
export default async function Header({ showToolbar = false }: { showToolbar?: boolean }) {
const auth = await getAuth();
@@ -16,8 +16,12 @@ export default async function Header({ showToolbar = false }: { showToolbar?: bo
{auth && (
<>
-
} />
- {showToolbar &&
} />}
+
+
} />
+
+
+
} />
+
>
)}
{showToolbar &&
} />}
diff --git a/src/components/forms/AuthForm.tsx b/src/components/forms/AuthForm.tsx
index 8d26e68..fca0b99 100644
--- a/src/components/forms/AuthForm.tsx
+++ b/src/components/forms/AuthForm.tsx
@@ -1,17 +1,25 @@
"use client";
import { useActionState } from "react";
-import { authenticate } from "@/app/actions";
+import { login, register } from "@/app/actions";
-export default function AuthForm() {
- const [state, formAction] = useActionState(authenticate, null);
+export default function AuthForm({ isRegister = false }: { isRegister?: boolean }) {
+ const [state, formAction] = useActionState(isRegister ? register : login, null);
return (
-
+
+
{isRegister ? "Register" : "Login"}
+
+
);
}
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..6839fa2
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,16 @@
+import { NextRequest, NextResponse } from "next/server";
+import { getAuth } from "./lib/auth";
+
+export async function middleware(request: NextRequest) {
+ const auth = await getAuth();
+
+ if (auth) {
+ return NextResponse.next();
+ } else {
+ return NextResponse.redirect(new URL("/auth", request.url));
+ }
+}
+
+export const config = {
+ matcher: "/notes/:path*",
+};