From e689384977274f5f5f94e578ad553c74f57daecc Mon Sep 17 00:00:00 2001 From: Syasya Date: Wed, 20 Aug 2025 12:41:52 +0800 Subject: [PATCH 1/6] fix auth flow --- .env.example | 11 +- .gitea/workflows/pr-build-check.yml | 4 +- app/(admin)/adminDashboard/page.tsx | 31 +++++- app/(auth)/login/page.tsx | 153 ++++++++++++++++------------ components/layouts/header.tsx | 2 +- middleware.ts | 4 +- package-lock.json | 15 +++ package.json | 1 + pages/api/logout.ts | 36 +++---- 9 files changed, 163 insertions(+), 94 deletions(-) diff --git a/.env.example b/.env.example index 0150039..48af7c8 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,6 @@ -NEXT_PUBLIC_API_BASE_URL=http://localhost:3005 +NEXT_PUBLIC_API_BASE_URL="http://localhost:8000" +INTERNAL_API_BASE_URL="http://localhost:3005" + DATABASE_URL="postgresql://postgres:root@localhost:5432/rooftop?schema=public" JWT_SECRET="secret_key" - -#SUNGROW -SUNGROW_SECRET_KEY= -SUNGROW_APP_KEY= - -#CHINT -NEXT_PUBLIC_CHINT_TOKEN= diff --git a/.gitea/workflows/pr-build-check.yml b/.gitea/workflows/pr-build-check.yml index 7673ebe..5022fc2 100644 --- a/.gitea/workflows/pr-build-check.yml +++ b/.gitea/workflows/pr-build-check.yml @@ -27,8 +27,8 @@ jobs: - name: Build run: npm run build env: - NEXT_PUBLIC_URL: 'http://localhost:3000' - NEXT_PUBLIC_FORECAST_URL: 'http://localhost:3001' + NEXT_PUBLIC_URL: 'http://localhost:3005' + NEXT_PUBLIC_FORECAST_URL: 'http://localhost:3005' DATABASE_URL: 'postgresql://dummy:dummy@localhost:5432/dummy' SMTP_EMAIL: 'dummy@example.com' SMTP_EMAIL_PASSWORD: 'dummy' diff --git a/app/(admin)/adminDashboard/page.tsx b/app/(admin)/adminDashboard/page.tsx index bc97fce..3fdf0cf 100644 --- a/app/(admin)/adminDashboard/page.tsx +++ b/app/(admin)/adminDashboard/page.tsx @@ -59,6 +59,7 @@ const AdminDashboard = () => { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); + const [authChecked, setAuthChecked] = useState(false); // --- load CRM projects dynamically --- const [sites, setSites] = useState([]); @@ -67,6 +68,30 @@ const AdminDashboard = () => { // near other refs const loggingRef = useRef(null); + useEffect(() => { + const checkAuth = async () => { + try { + const res = await fetch('/api/auth/me', { credentials: 'include' }); + if (!res.ok) { + router.replace('/login'); + return; + } + const data = await res.json(); + if (!data.user) { + router.replace('/login'); + return; + } + } catch { + router.replace('/login'); + } finally { + setAuthChecked(true); + } + }; + + checkAuth(); + }, [router]); + + useEffect(() => { setSitesLoading(true); @@ -288,7 +313,7 @@ const AdminDashboard = () => { setHasTodayData(true); // and today has data too break; } - } catch { + } catch { // ignore and keep polling } await new Promise(r => setTimeout(r, 3000)); @@ -300,6 +325,10 @@ const AdminDashboard = () => { }; // ---------- RENDER ---------- + if (!authChecked) { + return
Checking authentication…
; + } + if (sitesLoading) { return ( diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index ef76b0c..ee9e9bc 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -1,73 +1,100 @@ +// app/login/page.tsx +'use client'; + import Link from 'next/link'; -import { Metadata } from 'next'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; import ComponentsAuthLoginForm from '@/components/auth/components-auth-login-form'; -type Props = {} +export default function LoginPage() { + const router = useRouter(); + const [ready, setReady] = useState(false); // gate to avoid UI flash -const LoginPage = (props: Props) => { - return ( -
- {/* Background gradient layer */} -
- background gradient -
-
+ useEffect(() => { + let cancelled = false; - {/* Background decorative objects */} - left decor - right decor + (async () => { + try { + const res = await fetch('/api/auth/me', { + method: 'GET', + cache: 'no-store', + credentials: 'include', // safe even if same-origin + }); + if (!cancelled && res.ok) { + router.replace('/adminDashboard'); + return; + } + } catch { + // ignore errors; just show the form + } + if (!cancelled) setReady(true); + })(); - {/* Centered card wrapper */} -
-
{ cancelled = true; }; + }, [router]); + + if (!ready) return null; // or a small spinner if you prefer + + return ( +
+ {/* Background gradient layer */} +
+ background gradient +
+
+ + {/* Background decorative objects */} + left decor + right decor + + {/* Centered card wrapper */} +
+
+ {/* Inner card (glassmorphic effect) */} +
+
+ {/* Header */} +

+ Sign In +

+

+ Enter your email and password to access your account. +

+ + {/* Login form */} + + + {/* Footer link */} +
+ Don’t have an account?{' '} + - {/* Inner card (glassmorphic effect) */} -
-
- {/* Header */} -

- Sign In -

-

- Enter your email and password to access your account. -

- - {/* Login form */} - - - {/* Footer link */} -
- Don’t have an account?{" "} - - SIGN UP - -
-
-
-
+ SIGN UP + +
+
- ); -}; +
+
+ ); +} - -export default LoginPage diff --git a/components/layouts/header.tsx b/components/layouts/header.tsx index 19402f0..e03b460 100644 --- a/components/layouts/header.tsx +++ b/components/layouts/header.tsx @@ -72,7 +72,7 @@ useEffect(() => { }, [pathname]); // re-fetch on route change (after login redirect) const handleLogout = async () => { - await fetch('/api/auth/logout', { method: 'POST' }); + await fetch('/api/logout', { method: 'POST' }); setUser(null); router.push('/login'); // go to login }; diff --git a/middleware.ts b/middleware.ts index c499d26..e9b2947 100644 --- a/middleware.ts +++ b/middleware.ts @@ -10,10 +10,10 @@ export function middleware(req: NextRequest) { try { jwt.verify(token, SECRET_KEY); - return NextResponse.next(); + return NextResponse.next(); } catch (error) { return NextResponse.redirect(new URL("/login", req.url)); } -} + } export const config = { matcher: ["/dashboard", "/profile"] }; diff --git a/package-lock.json b/package-lock.json index dba53c1..98ba282 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "he": "^1.2.0", "html2canvas": "^1.4.1", "i18next": "^22.4.10", + "jose": "^6.0.12", "jsonwebtoken": "^9.0.2", "jspdf": "^3.0.1", "next": "14.0.3", @@ -7107,6 +7108,15 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.12.tgz", + "integrity": "sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -14693,6 +14703,11 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==" }, + "jose": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.12.tgz", + "integrity": "sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==" + }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", diff --git a/package.json b/package.json index 83a132d..f1be8f8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "he": "^1.2.0", "html2canvas": "^1.4.1", "i18next": "^22.4.10", + "jose": "^6.0.12", "jsonwebtoken": "^9.0.2", "jspdf": "^3.0.1", "next": "14.0.3", diff --git a/pages/api/logout.ts b/pages/api/logout.ts index f341c0f..50c42f5 100644 --- a/pages/api/logout.ts +++ b/pages/api/logout.ts @@ -1,20 +1,22 @@ -// pages/api/auth/logout.ts -import type { NextApiRequest, NextApiResponse } from "next"; +// pages/api/logout.ts -> /api/logout +import type { NextApiRequest, NextApiResponse } from 'next'; +import { serialize } from 'cookie'; export default function handler(req: NextApiRequest, res: NextApiResponse) { - const isProd = process.env.NODE_ENV === "production"; - res.setHeader( - "Set-Cookie", - [ - "token=", // empty token - "HttpOnly", - "Path=/", - "SameSite=Strict", - "Max-Age=0", // expire immediately - isProd ? "Secure" : "", - ] - .filter(Boolean) - .join("; ") - ); - return res.status(200).json({ message: "Logged out" }); + const isProd = process.env.NODE_ENV === 'production'; + + const setCookie = serialize('token', '', { + httpOnly: true, + secure: isProd, + sameSite: 'strict', // matches login + path: '/', // matches login + maxAge: 0, + expires: new Date(0), + }); + + res.setHeader('Set-Cookie', setCookie); + res.setHeader('Cache-Control', 'no-store'); + return res.status(200).json({ message: 'Logged out' }); } + + From 209516b1a6aae8b637ccdda7e359885a4f9f2736 Mon Sep 17 00:00:00 2001 From: Syasya Date: Thu, 21 Aug 2025 15:07:19 +0800 Subject: [PATCH 2/6] metadata and env update --- .env.example | 2 +- app/layout.tsx | 43 +++++++++++++++++++------------------------ app/utils/api.ts | 2 +- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/.env.example b/.env.example index 48af7c8..b062194 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -NEXT_PUBLIC_API_BASE_URL="http://localhost:8000" +FASTAPI_URL="http://localhost:8000" INTERNAL_API_BASE_URL="http://localhost:3005" diff --git a/app/layout.tsx b/app/layout.tsx index ce1fc5c..0dc96eb 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,30 +1,25 @@ -'use client'; -import ProviderComponent from '@/components/layouts/provider-component'; -import 'react-perfect-scrollbar/dist/css/styles.css'; -import '../styles/tailwind.css'; -import { Metadata } from 'next'; -import { Nunito } from 'next/font/google'; +// app/layout.tsx +import type { Metadata } from "next"; +import ProviderComponent from "@/components/layouts/provider-component"; +import "react-perfect-scrollbar/dist/css/styles.css"; +import "../styles/tailwind.css"; +import { Nunito } from "next/font/google"; import { Exo_2 } from "next/font/google"; -const exo2 = Exo_2({ - subsets: ["latin"], - variable: "--font-exo2", - weight: ["200", "400"], -}); +const exo2 = Exo_2({ subsets: ["latin"], variable: "--font-exo2", weight: ["200", "400"] }); +const nunito = Nunito({ weight: ["400","500","600","700","800"], subsets: ["latin"], display: "swap", variable: "--font-nunito" }); -const nunito = Nunito({ - weight: ['400', '500', '600', '700', '800'], - subsets: ['latin'], - display: 'swap', - variable: '--font-nunito', -}); +export const metadata: Metadata = { + title: "Rooftop Meter", + icons: { icon: "/favicon.png" }, // or "/favicon.ico" +}; export default function RootLayout({ children }: { children: React.ReactNode }) { - return ( - - - {children} - - - ) + return ( + + + {children} + + + ); } diff --git a/app/utils/api.ts b/app/utils/api.ts index 09773e1..67b9cbf 100644 --- a/app/utils/api.ts +++ b/app/utils/api.ts @@ -10,7 +10,7 @@ export interface TimeSeriesResponse { } const API_BASE_URL = - process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://127.0.0.1:8000"; + process.env.FASTAPI_URL ?? "http://127.0.0.1:8000"; export const crmapi = { getProjects: async () => { From 1133e52ec0b23e712fa6906adfd1da0beec7d52b Mon Sep 17 00:00:00 2001 From: Syasya Date: Thu, 21 Aug 2025 15:07:43 +0800 Subject: [PATCH 3/6] favicon --- public/favicon.png | Bin 3275 -> 80434 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.png b/public/favicon.png index 9ee75c535232cc957bcb7bd63c81a2bd099b8a12..ca9cec21644ad77421996911ae71dd19b0baaefa 100644 GIT binary patch literal 80434 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 BiJSlc literal 3275 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 JPDHLkV1hS#EfxR( From 79c611d0610194d4c0260ebb4efe8a3281fc4bf1 Mon Sep 17 00:00:00 2001 From: Syasya Date: Thu, 21 Aug 2025 16:45:21 +0800 Subject: [PATCH 4/6] change auth to fastapi --- app/(admin)/adminDashboard/page.tsx | 54 ++++++----- app/(auth)/login/page.tsx | 43 ++++++--- .../auth/components-auth-login-form.tsx | 40 +++++--- .../auth/components-auth-register-form.tsx | 8 +- components/layouts/header.tsx | 93 ++++++++++--------- 5 files changed, 146 insertions(+), 92 deletions(-) diff --git a/app/(admin)/adminDashboard/page.tsx b/app/(admin)/adminDashboard/page.tsx index 3fdf0cf..83c287a 100644 --- a/app/(admin)/adminDashboard/page.tsx +++ b/app/(admin)/adminDashboard/page.tsx @@ -68,28 +68,40 @@ const AdminDashboard = () => { // near other refs const loggingRef = useRef(null); - useEffect(() => { - const checkAuth = async () => { - try { - const res = await fetch('/api/auth/me', { credentials: 'include' }); - if (!res.ok) { - router.replace('/login'); - return; - } - const data = await res.json(); - if (!data.user) { - router.replace('/login'); - return; - } - } catch { - router.replace('/login'); - } finally { - setAuthChecked(true); - } - }; + const API = process.env.NEXT_PUBLIC_FASTAPI_URL || 'http://127.0.0.1:8000'; - checkAuth(); - }, [router]); +useEffect(() => { + let cancelled = false; + + const checkAuth = async () => { + try { + const res = await fetch(`${API}/auth/me`, { + credentials: 'include', + cache: 'no-store', + }); + + if (!res.ok) { + router.replace('/login'); + return; + } + + const user = await res.json().catch(() => null); + if (!user?.id) { + router.replace('/login'); + return; + } + // authenticated + } catch { + router.replace('/login'); + return; + } finally { + if (!cancelled) setAuthChecked(true); + } + }; + + checkAuth(); + return () => { cancelled = true; }; +}, [router, API]); diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index ee9e9bc..b1dcf64 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -10,30 +10,48 @@ export default function LoginPage() { const router = useRouter(); const [ready, setReady] = useState(false); // gate to avoid UI flash + // Use ONE client-exposed API env var everywhere + const API = process.env.NEXT_PUBLIC_FASTAPI_URL || 'http://127.0.0.1:8000'; + useEffect(() => { let cancelled = false; + const controller = new AbortController(); (async () => { try { - const res = await fetch('/api/auth/me', { - method: 'GET', - cache: 'no-store', - credentials: 'include', // safe even if same-origin + const res = await fetch(`${API}/auth/me`, { + credentials: 'include', + cache: 'no-store', // don't reuse a cached 401 + signal: controller.signal, }); - if (!cancelled && res.ok) { + + if (!res.ok) { + if (!cancelled) setReady(true); + return; + } + + const user = await res.json().catch(() => null); + if (user?.id) { + // already logged in -> go straight to dashboard router.replace('/adminDashboard'); return; } + + // not logged in -> show form + if (!cancelled) setReady(true); } catch { - // ignore errors; just show the form + // network/error -> show form + if (!cancelled) setReady(true); } - if (!cancelled) setReady(true); })(); - return () => { cancelled = true; }; - }, [router]); + return () => { + cancelled = true; + controller.abort(); + }; + }, [router, API]); - if (!ready) return null; // or a small spinner if you prefer + if (!ready) return null; // or a spinner/skeleton return (
@@ -66,10 +84,8 @@ export default function LoginPage() { bg-[linear-gradient(45deg,#fffbe6_0%,rgba(255,251,230,0)_25%,rgba(255,251,230,0)_75%,#fffbe6_100%)] dark:bg-[linear-gradient(52.22deg,#facc15_0%,rgba(250,204,21,0)_20%,rgba(250,204,21,0)_80%,#facc15_100%)]" > - {/* Inner card (glassmorphic effect) */}
- {/* Header */}

Sign In

@@ -77,10 +93,8 @@ export default function LoginPage() { Enter your email and password to access your account.

- {/* Login form */} - {/* Footer link */}
Don’t have an account?{' '} { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [loading, setLoading] = useState(false); const router = useRouter(); + const API = process.env.NEXT_PUBLIC_FASTAPI_URL; // e.g. http://localhost:8000 - const submitForm = async (e: React.FormEvent) => { + const submitForm = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { - const res = await axios.post('/api/login', { email, password }); - toast.success(res.data?.message || 'Login successful!'); + const res = await fetch(`${API}/auth/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password }), + credentials: 'include', // cookie from FastAPI + }); + + let data: any = null; + try { + data = await res.json(); + } catch { + // non-JSON error + } + + if (!res.ok) { + const msg = data?.detail || data?.message || 'Invalid credentials'; + throw new Error(msg); + } + + const user: User = data; + toast.success(`Welcome ${user.email}`); router.push('/adminDashboard'); router.refresh(); - // token cookie is already set by the server: } catch (err: any) { - console.error('Login error:', err); - const msg = - err?.response?.data?.message || - err?.message || - 'Invalid credentials'; - toast.error(msg); + toast.error(err?.message ?? 'Login failed'); } finally { setLoading(false); } @@ -52,6 +67,7 @@ const ComponentsAuthLoginForm = () => {
+
@@ -70,6 +86,7 @@ const ComponentsAuthLoginForm = () => {
+ -
- +
{/* Right-side actions */}
@@ -124,21 +131,21 @@ useEffect(() => { )} {/* User dropdown */} -
+
{loadingUser ? (
) : user ? ( - - -
- } + + +
+ } > -
    {/* make sure this stays transparent */} +
    • {user.email}

      From 036bff862ade3578893b43cf4e10108a5d2f8170 Mon Sep 17 00:00:00 2001 From: Syasya Date: Thu, 21 Aug 2025 16:48:14 +0800 Subject: [PATCH 5/6] delete deploy --- .gitea/workflows/deploy.yml | 59 ------------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 .gitea/workflows/deploy.yml diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml deleted file mode 100644 index d4f647e..0000000 --- a/.gitea/workflows/deploy.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Build and Deploy - -on: - push: - tags: - - 'v*' - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Extract Tag Name - id: extract_tag - run: | - TAG_NAME=${GITHUB_REF#refs/tags/} - echo "tag=$TAG_NAME" >> $GITHUB_OUTPUT - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - - - name: Build and Push Docker Image - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - push: true - tags: | - rooftopenergy/rooftop_dpmdashboard:${{ steps.extract_tag.outputs.tag }} - - - name: Install sshpass - run: sudo apt-get update && sudo apt-get install -y sshpass - - - name: Deploy to VPS - env: - SSHPASS: ${{ secrets.VPS_PASSWORD }} - run: | - sshpass -e ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} << EOF - set -e - - echo "Using tag: ${{ steps.extract_tag.outputs.tag }}" - - cd /root/UserDashboard - - sed -i "s|rooftopenergy/rooftop_dpmdashboard:.*|rooftopenergy/rooftop_dpmdashboard:${{ steps.extract_tag.outputs.tag }}|g" docker-compose.yml - - docker compose down - docker compose pull - docker compose up -d - EOF From 5041c5a27df16573502f372ffccf4d745b99b571 Mon Sep 17 00:00:00 2001 From: Syasya Date: Thu, 21 Aug 2025 16:51:16 +0800 Subject: [PATCH 6/6] delete unnecessary api --- pages/api/auth/me.ts | 46 ------------------------------------------- pages/api/login.ts | 42 --------------------------------------- pages/api/logout.ts | 22 --------------------- pages/api/register.ts | 42 --------------------------------------- 4 files changed, 152 deletions(-) delete mode 100644 pages/api/auth/me.ts delete mode 100644 pages/api/login.ts delete mode 100644 pages/api/logout.ts delete mode 100644 pages/api/register.ts diff --git a/pages/api/auth/me.ts b/pages/api/auth/me.ts deleted file mode 100644 index e5d94be..0000000 --- a/pages/api/auth/me.ts +++ /dev/null @@ -1,46 +0,0 @@ -// pages/api/auth/me.ts -import type { NextApiRequest, NextApiResponse } from "next"; -import jwt, { JwtPayload } from "jsonwebtoken"; -import { PrismaClient } from "@prisma/client"; - -const prisma = new PrismaClient(); -const SECRET_KEY = process.env.JWT_SECRET as string; - -function readCookieToken(req: NextApiRequest) { - const cookie = req.headers.cookie || ""; - const match = cookie.split("; ").find((c) => c.startsWith("token=")); - return match?.split("=")[1]; -} - -function readAuthBearer(req: NextApiRequest) { - const auth = req.headers.authorization; - if (!auth?.startsWith("Bearer ")) return undefined; - return auth.slice("Bearer ".length); -} - -function hasEmail(payload: string | JwtPayload): payload is JwtPayload & { email: string } { - return typeof payload === "object" && payload !== null && typeof (payload as any).email === "string"; -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "GET") return res.status(405).json({ message: "Method not allowed" }); - - try { - const token = readAuthBearer(req) ?? readCookieToken(req); - if (!token) return res.status(401).json({ message: "Unauthorized" }); - - const decoded = jwt.verify(token, SECRET_KEY); - if (!hasEmail(decoded)) return res.status(401).json({ message: "Invalid token" }); - - const user = await prisma.user.findUnique({ - where: { email: decoded.email }, - select: { id: true, email: true, createdAt: true }, - }); - - if (!user) return res.status(401).json({ message: "User not found" }); - return res.status(200).json({ user }); - } catch { - return res.status(401).json({ message: "Invalid token" }); - } -} - diff --git a/pages/api/login.ts b/pages/api/login.ts deleted file mode 100644 index 633e4dd..0000000 --- a/pages/api/login.ts +++ /dev/null @@ -1,42 +0,0 @@ -// pages/api/login.ts -import type { NextApiRequest, NextApiResponse } from "next"; -import { PrismaClient } from "@prisma/client"; -import bcrypt from "bcrypt"; -import jwt from "jsonwebtoken"; - -const prisma = new PrismaClient(); -const SECRET_KEY = process.env.JWT_SECRET as string; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); - - try { - const { email, password } = req.body as { email?: string; password?: string }; - if (!email || !password) return res.status(400).json({ message: "Email and password are required" }); - - const user = await prisma.user.findUnique({ where: { email } }); - if (!user) return res.status(401).json({ message: "Invalid credentials" }); - - const isMatch = await bcrypt.compare(password, user.password); - if (!isMatch) return res.status(401).json({ message: "Invalid credentials" }); - - const token = jwt.sign({ sub: String(user.id), email: user.email }, SECRET_KEY, { expiresIn: "1d" }); - - const isProd = process.env.NODE_ENV === "production"; - const cookie = [ - `token=${token}`, - "HttpOnly", - "Path=/", - "SameSite=Strict", - `Max-Age=${60 * 60 * 24}`, // 1 day - isProd ? "Secure" : "", // only secure in prod - ].filter(Boolean).join("; "); - - res.setHeader("Set-Cookie", cookie); - return res.status(200).json({ message: "Login successful" }); - } catch (e) { - console.error(e); - return res.status(500).json({ message: "Something went wrong" }); - } -} - diff --git a/pages/api/logout.ts b/pages/api/logout.ts deleted file mode 100644 index 50c42f5..0000000 --- a/pages/api/logout.ts +++ /dev/null @@ -1,22 +0,0 @@ -// pages/api/logout.ts -> /api/logout -import type { NextApiRequest, NextApiResponse } from 'next'; -import { serialize } from 'cookie'; - -export default function handler(req: NextApiRequest, res: NextApiResponse) { - const isProd = process.env.NODE_ENV === 'production'; - - const setCookie = serialize('token', '', { - httpOnly: true, - secure: isProd, - sameSite: 'strict', // matches login - path: '/', // matches login - maxAge: 0, - expires: new Date(0), - }); - - res.setHeader('Set-Cookie', setCookie); - res.setHeader('Cache-Control', 'no-store'); - return res.status(200).json({ message: 'Logged out' }); -} - - diff --git a/pages/api/register.ts b/pages/api/register.ts deleted file mode 100644 index fc570f8..0000000 --- a/pages/api/register.ts +++ /dev/null @@ -1,42 +0,0 @@ -// pages/api/register.ts -import type { NextApiRequest, NextApiResponse } from "next"; -import { PrismaClient } from "@prisma/client"; -import bcrypt from "bcrypt"; -import jwt from "jsonwebtoken"; - -const prisma = new PrismaClient(); -const SECRET_KEY = process.env.JWT_SECRET as string; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); - - try { - const { email, password } = req.body as { email?: string; password?: string }; - - if (!email || !password) return res.status(400).json({ message: "Email and password are required" }); - - const existingUser = await prisma.user.findUnique({ where: { email } }); - if (existingUser) return res.status(400).json({ message: "User already exists" }); - - const hashedPassword = await bcrypt.hash(password, 10); - const user = await prisma.user.create({ - data: { email, password: hashedPassword }, - select: { id: true, email: true, createdAt: true }, // do NOT expose password - }); - - const token = jwt.sign({ sub: String(user.id), email: user.email }, SECRET_KEY, { expiresIn: "1d" }); - - // Set a secure, httpOnly cookie - const maxAge = 60 * 60 * 24; // 1 day - res.setHeader( - "Set-Cookie", - `token=${token}; HttpOnly; Path=/; Max-Age=${maxAge}; SameSite=Strict; Secure` - ); - - return res.status(201).json({ message: "User registered", user }); - } catch (err) { - console.error(err); - return res.status(500).json({ message: "Something went wrong" }); - } -} -