diff --git a/.env.example b/.env.example deleted file mode 100644 index 7334213..0000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -# !STARTERCONF Duplicate this to .env.local - -# DEVELOPMENT TOOLS -# Ideally, don't add them to production deployment envs -# !STARTERCONF Change to true if you want to log data -NEXT_PUBLIC_SHOW_LOGGER="false" \ No newline at end of file diff --git a/next.config.js b/next.config.js index 76b805a..a68985a 100644 --- a/next.config.js +++ b/next.config.js @@ -8,18 +8,6 @@ const nextConfig = { reactStrictMode: true, swcMinify: true, - /** - * 在编译阶段将 STORAGE_TYPE 写入环境变量,供浏览器端与服务端统一读取。 - */ - env: (function () { - // 编译阶段优先使用传入的环境变量;默认 localstorage - const storageType = process.env.STORAGE_TYPE || 'localstorage'; - - return { - STORAGE_TYPE: storageType, - }; - })(), - // Uncoment to add domain whitelist images: { remotePatterns: [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 509f6b9..f3f974f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: artplayer: specifier: ^5.2.3 version: 5.2.3 + bcryptjs: + specifier: ^2.4.3 + version: 2.4.3 clsx: specifier: ^2.0.0 version: 2.1.1 @@ -69,6 +72,9 @@ importers: '@testing-library/react': specifier: ^15.0.7 version: 15.0.7(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/bcryptjs': + specifier: ^2.4.2 + version: 2.4.6 '@types/node': specifier: 24.0.3 version: 24.0.3 @@ -87,6 +93,9 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.21(postcss@8.5.6) + dotenv: + specifier: ^16.5.0 + version: 16.5.0 eslint: specifier: ^8.57.1 version: 8.57.1 @@ -1317,6 +1326,9 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/bcryptjs@2.4.6': + resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} + '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} @@ -1755,6 +1767,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2146,6 +2161,10 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} + dotenv@16.5.0: + resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -5938,6 +5957,8 @@ snapshots: dependencies: '@babel/types': 7.27.6 + '@types/bcryptjs@2.4.6': {} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 24.0.3 @@ -6415,6 +6436,8 @@ snapshots: balanced-match@1.0.2: {} + bcryptjs@2.4.3: {} + binary-extensions@2.3.0: {} boolbase@1.0.0: {} @@ -6800,6 +6823,8 @@ snapshots: dependencies: is-obj: 2.0.0 + dotenv@16.5.0: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 diff --git a/src/app/api/login/route.ts b/src/app/api/login/route.ts new file mode 100644 index 0000000..d8d0dc6 --- /dev/null +++ b/src/app/api/login/route.ts @@ -0,0 +1,29 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function POST(req: NextRequest) { + try { + const result = process.env.PASSWORD; + + if (!result) { + return NextResponse.json({ ok: true }); + } + + const { password } = await req.json(); + if (typeof password !== 'string') { + return NextResponse.json({ error: '密码不能为空' }, { status: 400 }); + } + + const matched = password === result; + + if (!matched) { + return NextResponse.json( + { ok: false, error: '密码错误' }, + { status: 401 } + ); + } + + return NextResponse.json({ ok: true }); + } catch (error) { + return NextResponse.json({ error: '服务器错误' }, { status: 500 }); + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d7afc12..5d1de65 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,8 @@ import { Inter } from 'next/font/google'; import './globals.css'; +import AuthProvider from '../components/AuthProvider'; + const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { @@ -18,7 +20,7 @@ export default function RootLayout({ return (
- {children} +