Fixed the login again?
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
import { NextRequest } from "next/server"
|
||||
import {
|
||||
comparePassword,
|
||||
getUserByEmail,
|
||||
@@ -13,6 +13,13 @@ import {
|
||||
SESSION_COOKIE,
|
||||
} from "@/lib/auth"
|
||||
|
||||
function jsonResponse(data: unknown, status: number) {
|
||||
return new Response(JSON.stringify(data), {
|
||||
status,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
})
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { email, username, password } = await request.json()
|
||||
@@ -20,16 +27,16 @@ export async function POST(request: NextRequest) {
|
||||
const credential = email || username
|
||||
|
||||
if (!credential || !password) {
|
||||
return NextResponse.json(
|
||||
return jsonResponse(
|
||||
{ error: "Email/Username and password are required." },
|
||||
{ status: 400 }
|
||||
400
|
||||
)
|
||||
}
|
||||
|
||||
if (credential.trim().length === 0 || password.trim().length === 0) {
|
||||
return NextResponse.json(
|
||||
return jsonResponse(
|
||||
{ error: "Credentials cannot be empty." },
|
||||
{ status: 400 }
|
||||
400
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,9 +66,9 @@ export async function POST(request: NextRequest) {
|
||||
false,
|
||||
"User not found"
|
||||
)
|
||||
return NextResponse.json(
|
||||
return jsonResponse(
|
||||
{ error: "Invalid email/username or password." },
|
||||
{ status: 401 }
|
||||
401
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,9 +82,9 @@ export async function POST(request: NextRequest) {
|
||||
false,
|
||||
lockStatus.reason
|
||||
)
|
||||
return NextResponse.json(
|
||||
return jsonResponse(
|
||||
{ error: lockStatus.reason },
|
||||
{ status: 423 }
|
||||
423
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,9 +99,9 @@ export async function POST(request: NextRequest) {
|
||||
false,
|
||||
"Invalid password"
|
||||
)
|
||||
return NextResponse.json(
|
||||
return jsonResponse(
|
||||
{ error: "Invalid email/username or password." },
|
||||
{ status: 401 }
|
||||
401
|
||||
)
|
||||
}
|
||||
|
||||
@@ -112,19 +119,20 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
const user = mapDbUserToSessionUser(dbUser)
|
||||
|
||||
const response = NextResponse.json({ user }, { status: 200 })
|
||||
response.cookies.set(SESSION_COOKIE, token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
const cookieStr = `${SESSION_COOKIE}=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=86400${process.env.NODE_ENV === "production" ? "; Secure" : ""}`
|
||||
|
||||
return new Response(JSON.stringify({ user }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Set-Cookie": cookieStr,
|
||||
},
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error("Login error:", error)
|
||||
return NextResponse.json(
|
||||
{ error: "Authentication service unavailable." },
|
||||
{ status: 503 }
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Authentication service unavailable." }),
|
||||
{ status: 503, headers: { "Content-Type": "application/json" } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import { NextResponse } from "next/server"
|
||||
import { SESSION_COOKIE } from "@/lib/auth"
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
const response = NextResponse.json({ success: true }, { status: 200 })
|
||||
response.cookies.set(SESSION_COOKIE, "", {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
maxAge: 0,
|
||||
return new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Set-Cookie": `${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`,
|
||||
},
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error("Logout error:", error)
|
||||
return NextResponse.json(
|
||||
{ error: "Logout failed." },
|
||||
{ status: 500 }
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Logout failed." }),
|
||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side
|
||||
>
|
||||
{/* Logo */}
|
||||
<div className={cn("flex h-16 items-center border-b border-sidebar-border px-4", collapsed ? "justify-center" : "justify-between")}>
|
||||
<Link href="/" className="flex items-center gap-3 overflow-hidden">
|
||||
<Link href="/dashboard" className="flex items-center gap-3 overflow-hidden">
|
||||
{collapsed ? (
|
||||
<div className="bc-logo" style={{padding: "8px 3px", fontSize: "16px"}}>B<span className="accent">C</span></div>
|
||||
) : (
|
||||
|
||||
+11
-6
@@ -2,14 +2,19 @@ import { SignJWT, jwtVerify } from "jose";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { query } from "@/lib/db";
|
||||
import { cookies } from "next/headers";
|
||||
import crypto from "crypto";
|
||||
|
||||
const RAW_SECRET = process.env.NODE_ENV === "production"
|
||||
? process.env.JWT_SECRET
|
||||
: crypto.randomUUID();
|
||||
if (!RAW_SECRET) {
|
||||
throw new Error("JWT_SECRET environment variable is required");
|
||||
function randomHex(length: number): string {
|
||||
const chars = "abcdef0123456789";
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += chars[Math.floor(Math.random() * chars.length)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const g = globalThis as typeof globalThis & { __JWT_RAW_SECRET?: string };
|
||||
const RAW_SECRET = process.env.JWT_SECRET || (g.__JWT_RAW_SECRET ??= randomHex(32));
|
||||
if (!RAW_SECRET) throw new Error("JWT_SECRET environment variable is required");
|
||||
const JWT_SECRET = new TextEncoder().encode(RAW_SECRET);
|
||||
|
||||
export const SESSION_COOKIE = "session";
|
||||
|
||||
+1
-18
@@ -1,12 +1,5 @@
|
||||
import { NextResponse } from "next/server"
|
||||
import type { NextRequest } from "next/server"
|
||||
import { jwtVerify } from "jose"
|
||||
|
||||
const RAW_SECRET = process.env.JWT_SECRET
|
||||
if (!RAW_SECRET) {
|
||||
throw new Error("JWT_SECRET environment variable is required")
|
||||
}
|
||||
const JWT_SECRET = new TextEncoder().encode(RAW_SECRET)
|
||||
|
||||
const publicRoutes = [
|
||||
"/login",
|
||||
@@ -41,17 +34,7 @@ export async function middleware(request: NextRequest) {
|
||||
return NextResponse.redirect(loginUrl)
|
||||
}
|
||||
|
||||
try {
|
||||
await jwtVerify(sessionCookie, JWT_SECRET)
|
||||
return NextResponse.next()
|
||||
} catch {
|
||||
if (pathname.startsWith("/api/")) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
|
||||
}
|
||||
const loginUrl = new URL("/login", request.url)
|
||||
loginUrl.searchParams.set("redirect", pathname)
|
||||
return NextResponse.redirect(loginUrl)
|
||||
}
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
export const config = {
|
||||
|
||||
Reference in New Issue
Block a user