diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
index 4671348..9e6ce07 100644
--- a/app/[locale]/layout.tsx
+++ b/app/[locale]/layout.tsx
@@ -1,4 +1,5 @@
// @auto-i18n-check. Please do not delete the line.
+import { auth } from "@/auth";
import { locales } from "@/i18n-metadata";
import getEnv from "@/lib/env-entry";
import { cn } from "@/lib/utils";
@@ -54,6 +55,7 @@ export default function LocaleLayout({
unstable_setRequestLocale(locale);
const messages = useMessages();
+
return (
diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..87f6488
--- /dev/null
+++ b/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,4 @@
+import { handlers } from "@/auth";
+
+// Referring to the auth.ts we just created
+export const { GET, POST } = handlers;
diff --git a/app/api/detail/route.ts b/app/api/detail/route.ts
index b0f8bc1..17ef913 100644
--- a/app/api/detail/route.ts
+++ b/app/api/detail/route.ts
@@ -1,4 +1,6 @@
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
+import { auth } from "@/auth";
+import getEnv from "@/lib/env-entry";
import { GetServerDetail } from "@/lib/serverFetch";
import { NextResponse } from "next/server";
@@ -9,7 +11,11 @@ interface NezhaDataResponse {
data?: NezhaAPISafe;
}
-export async function GET(req: Request) {
+export const GET = auth(async function GET(req) {
+ if (!req.auth && getEnv("SITE_PASSWORD")) {
+ return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
+ }
+
const { searchParams } = new URL(req.url);
const server_id = searchParams.get("server_id");
if (!server_id) {
@@ -26,4 +32,4 @@ export async function GET(req: Request) {
return NextResponse.json({ error: response.error }, { status: 400 });
}
return NextResponse.json(response, { status: 200 });
-}
+});
diff --git a/app/api/monitor/route.ts b/app/api/monitor/route.ts
index e03fe89..528de95 100644
--- a/app/api/monitor/route.ts
+++ b/app/api/monitor/route.ts
@@ -1,4 +1,6 @@
import { ServerMonitorChart } from "@/app/[locale]/types/nezha-api";
+import { auth } from "@/auth";
+import getEnv from "@/lib/env-entry";
import { GetServerMonitor } from "@/lib/serverFetch";
import { NextResponse } from "next/server";
@@ -9,7 +11,11 @@ interface NezhaDataResponse {
data?: ServerMonitorChart;
}
-export async function GET(req: Request) {
+export const GET = auth(async function GET(req) {
+ if (!req.auth && getEnv("SITE_PASSWORD")) {
+ return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
+ }
+
const { searchParams } = new URL(req.url);
const server_id = searchParams.get("server_id");
if (!server_id) {
@@ -26,4 +32,4 @@ export async function GET(req: Request) {
return NextResponse.json({ error: response.error }, { status: 400 });
}
return NextResponse.json(response, { status: 200 });
-}
+});
diff --git a/app/api/server/route.ts b/app/api/server/route.ts
index e34a83c..f201247 100644
--- a/app/api/server/route.ts
+++ b/app/api/server/route.ts
@@ -1,4 +1,6 @@
import { ServerApi } from "@/app/[locale]/types/nezha-api";
+import { auth } from "@/auth";
+import getEnv from "@/lib/env-entry";
import { GetNezhaData } from "@/lib/serverFetch";
import { NextResponse } from "next/server";
@@ -9,11 +11,15 @@ interface NezhaDataResponse {
data?: ServerApi;
}
-export async function GET(_: Request) {
+export const GET = auth(async function GET(req) {
+ if (!req.auth && getEnv("SITE_PASSWORD")) {
+ return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
+ }
+
const response = (await GetNezhaData()) as NezhaDataResponse;
if (response.error) {
console.log(response.error);
return NextResponse.json({ error: response.error }, { status: 400 });
}
return NextResponse.json(response, { status: 200 });
-}
+});
diff --git a/auth.ts b/auth.ts
new file mode 100644
index 0000000..ca98657
--- /dev/null
+++ b/auth.ts
@@ -0,0 +1,21 @@
+import NextAuth from "next-auth";
+import Credentials from "next-auth/providers/credentials";
+
+import getEnv from "./lib/env-entry";
+
+export const { handlers, signIn, signOut, auth } = NextAuth({
+ secret: "this_is_nezha_dash_web_secret",
+ providers: [
+ Credentials({
+ credentials: {
+ password: {},
+ },
+ authorize: async (credentials) => {
+ if (credentials.password === getEnv("SITE_PASSWORD")) {
+ return { id: "0" };
+ }
+ return null;
+ },
+ }),
+ ],
+});
diff --git a/bun.lockb b/bun.lockb
index e99d417..a0f7e64 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/components/sign-in.tsx b/components/sign-in.tsx
new file mode 100644
index 0000000..c8adbea
--- /dev/null
+++ b/components/sign-in.tsx
@@ -0,0 +1,45 @@
+import Footer from "@/app/[locale]/(main)/footer";
+import Header from "@/app/[locale]/(main)/header";
+import { signIn } from "@/auth";
+import { useLocale } from "next-intl";
+import { redirect } from "next/navigation";
+
+export function SignIn() {
+ const locale = useLocale();
+
+ async function handleSubmit(formData: FormData) {
+ "use server";
+ try {
+ await signIn("credentials", formData);
+ } catch (error) {
+ redirect(`/${locale}`);
+ }
+ }
+
+ return (
+
+ );
+}
diff --git a/middleware.ts b/middleware.ts
index 92342ad..fa0386d 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -3,6 +3,8 @@ import createMiddleware from "next-intl/middleware";
import { defaultLocale, locales } from "./i18n-metadata";
+// export { auth as middleware } from "@/auth"
+
export default createMiddleware({
// A list of all locales that are supported
locales: locales,
diff --git a/next.config.mjs b/next.config.mjs
index 86bfbf5..a68be47 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -23,6 +23,11 @@ const withPWA = withPWAInit({
const nextConfig = {
output: "standalone",
reactStrictMode: true,
+ experimental: {
+ serverActions: {
+ allowedOrigins: ["*"],
+ },
+ },
logging: {
fetches: {
fullUrl: true,
diff --git a/package.json b/package.json
index e94e7b2..76c090f 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"lucide-react": "^0.451.0",
"luxon": "^3.5.0",
"next": "^14.2.15",
+ "next-auth": "^5.0.0-beta.25",
"next-intl": "^3.21.1",
"next-runtime-env": "^3.2.2",
"next-themes": "^0.3.0",