diff --git a/.env.example b/.env.example index 8d88136..8e97209 100644 --- a/.env.example +++ b/.env.example @@ -4,4 +4,6 @@ UPLOADTHING_SECRET= UPLOADTHING_APP_ID= ADMIN_USERNAME= -ADMIN_PASSWORD= \ No newline at end of file +ADMIN_PASSWORD= + +NEXTAUTH_SECRET= \ No newline at end of file diff --git a/app/(auth)/admin/changelogs/page.tsx b/app/(auth)/admin/changelogs/page.tsx index ae89cb2..0865006 100644 --- a/app/(auth)/admin/changelogs/page.tsx +++ b/app/(auth)/admin/changelogs/page.tsx @@ -20,6 +20,12 @@ import { logsSchema } from "@/lib/validations/validation"; const AdminPage = () => { const form = useForm>({ resolver: zodResolver(logsSchema), + defaultValues: { + fileName: "", + version: "", + downloadLink: "", + fileSize: "", + }, }); const onSubmit: SubmitHandler> = async (data) => { @@ -42,8 +48,8 @@ const AdminPage = () => { }; return ( -
-

Admin Upload Section

+
+

Server Logs Form

{ const form = useForm>({ resolver: zodResolver(downloadSchema), + defaultValues: { + fileName: "", + version: "", + downloadLink: "", + fileSize: "", + }, }); const onSubmit: SubmitHandler> = async ( @@ -44,8 +50,8 @@ const AdminPage = () => { }; return ( -
-

Admin Upload Section

+
+

Mods Form

{ const form = useForm>({ resolver: zodResolver(modsSchema), + defaultValues: { + fileName: "", + version: "", + downloadLink: "", + fileSize: "", + }, }); const onSubmit: SubmitHandler> = async (data) => { @@ -42,8 +48,8 @@ const AdminPage = () => { }; return ( -
-

Admin Upload Section

+
+

Download Form

{ + const adminUsername = process.env.ADMIN_USERNAME; + const adminPassword = process.env.ADMIN_PASSWORD; + + if ( + credentials.username === adminUsername && + credentials.password === adminPassword + ) { + // Any object returned will be saved in `user` property of the JWT + return { id: 1, name: "svrjsAdmin" }; + } else { + // If you return null then an error will be displayed advising the user to check their details. + return null; + } + }, + }), + ], + callbacks: { + async jwt({ token, user }) { + // Add user info to token + if (user) { + token.id = user.id; + token.name = user.name; + } + return token; + }, + async session({ session, token }) { + // Add token info to session + // session.user.id = token.id; + // session.user.name = token.name; + return session; + }, + }, + pages: { + signIn: "/login", + }, + session: { + strategy: "jwt", + }, + secret: process.env.NEXTAUTH_SECRET, +}; diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..3ebad5c --- /dev/null +++ b/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,6 @@ +import NextAuth from "next-auth/next"; +import { authOptions } from "./options"; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; diff --git a/app/login/page.tsx b/app/login/page.tsx index 9e0fdbe..40cd24c 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -1,64 +1,61 @@ "use client"; import React, { useState } from "react"; +import { signIn } from "next-auth/react"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; const LoginPage = () => { - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [error, setError] = useState(""); - const router = useRouter(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const router = useRouter(); - const handleLogin = async (e: React.FormEvent) => { - e.preventDefault(); + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + const res = await signIn("credentials", { + redirect: false, + username, + password, + }); - const response = await fetch("/api/login", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ username, password }), - }); + if (res?.ok) { + router.push("/admin"); + } else { + setError("Invalid credentials"); + } + }; - if (response.ok) { - router.push("/admin"); - } else { - const data = await response.json(); - setError(data.message); - } - }; - - return ( -
-

SVRJS ADMIN PANEL

- {error &&

{error}

} - -
- setUsername(e.target.value)} - className="mt-1 block w-full bg-gray-800 rounded-full px-5 py-2 shadow-sm p-2" - /> -
-
- setPassword(e.target.value)} - className="mt-1 block w-full bg-gray-800 rounded-full px-5 py-2 shadow-sm" - /> -
- - -
- ); + return ( +
+

SVRJS ADMIN PANEL

+ {error &&

{error}

} +
+
+ setUsername(e.target.value)} + className="mt-1 block w-full bg-gray-800 rounded-full px-5 py-2 shadow-sm p-2" + /> +
+
+ setPassword(e.target.value)} + className="mt-1 block w-full bg-gray-800 rounded-full px-5 py-2 shadow-sm" + /> +
+ +
+
+ ); }; export default LoginPage; diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 0000000..8339e17 Binary files /dev/null and b/bun.lockb differ diff --git a/middleware.ts b/middleware.ts index 23a1642..0f8f0f6 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,21 +1,19 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; +import { getToken } from "next-auth/jwt"; -export function middleware(req: NextRequest) { - const url = req.nextUrl.clone(); +export async function middleware(req: NextRequest) { + const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET }); - if (url.pathname.startsWith("/admin")) { - const authCookie = req.cookies.get("auth"); + if (req.nextUrl.pathname.startsWith("/admin") && !token) { + const url = req.nextUrl.clone(); + url.pathname = "/login"; + return NextResponse.redirect(url); + } - if (!authCookie) { - url.pathname = "/login"; - return NextResponse.redirect(url); - } - } - - return NextResponse.next(); + return NextResponse.next(); } export const config = { - matcher: ["/admin/:path*"], + matcher: ["/admin/:path*"], }; diff --git a/package.json b/package.json index 4fabc88..abbde25 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lucide-react": "^0.394.0", "mini-svg-data-uri": "^1.4.4", "mongoose": "^8.4.3", + "next-auth": "^4.24.7", "next-themes": "^0.3.0", "nextra": "^2.13.4", "nextra-theme-docs": "^2.13.4",