mirror of
https://git.coastit.co.za/caitlin/CRM_ENVR.git
synced 2026-07-10 03:05:43 +02:00
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 {
|
import {
|
||||||
comparePassword,
|
comparePassword,
|
||||||
getUserByEmail,
|
getUserByEmail,
|
||||||
@@ -13,6 +13,13 @@ import {
|
|||||||
SESSION_COOKIE,
|
SESSION_COOKIE,
|
||||||
} from "@/lib/auth"
|
} 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) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const { email, username, password } = await request.json()
|
const { email, username, password } = await request.json()
|
||||||
@@ -20,16 +27,16 @@ export async function POST(request: NextRequest) {
|
|||||||
const credential = email || username
|
const credential = email || username
|
||||||
|
|
||||||
if (!credential || !password) {
|
if (!credential || !password) {
|
||||||
return NextResponse.json(
|
return jsonResponse(
|
||||||
{ error: "Email/Username and password are required." },
|
{ error: "Email/Username and password are required." },
|
||||||
{ status: 400 }
|
400
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (credential.trim().length === 0 || password.trim().length === 0) {
|
if (credential.trim().length === 0 || password.trim().length === 0) {
|
||||||
return NextResponse.json(
|
return jsonResponse(
|
||||||
{ error: "Credentials cannot be empty." },
|
{ error: "Credentials cannot be empty." },
|
||||||
{ status: 400 }
|
400
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +66,9 @@ export async function POST(request: NextRequest) {
|
|||||||
false,
|
false,
|
||||||
"User not found"
|
"User not found"
|
||||||
)
|
)
|
||||||
return NextResponse.json(
|
return jsonResponse(
|
||||||
{ error: "Invalid email/username or password." },
|
{ error: "Invalid email/username or password." },
|
||||||
{ status: 401 }
|
401
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,9 +82,9 @@ export async function POST(request: NextRequest) {
|
|||||||
false,
|
false,
|
||||||
lockStatus.reason
|
lockStatus.reason
|
||||||
)
|
)
|
||||||
return NextResponse.json(
|
return jsonResponse(
|
||||||
{ error: lockStatus.reason },
|
{ error: lockStatus.reason },
|
||||||
{ status: 423 }
|
423
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +99,9 @@ export async function POST(request: NextRequest) {
|
|||||||
false,
|
false,
|
||||||
"Invalid password"
|
"Invalid password"
|
||||||
)
|
)
|
||||||
return NextResponse.json(
|
return jsonResponse(
|
||||||
{ error: "Invalid email/username or password." },
|
{ error: "Invalid email/username or password." },
|
||||||
{ status: 401 }
|
401
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,19 +119,20 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
const user = mapDbUserToSessionUser(dbUser)
|
const user = mapDbUserToSessionUser(dbUser)
|
||||||
|
|
||||||
const response = NextResponse.json({ user }, { status: 200 })
|
const cookieStr = `${SESSION_COOKIE}=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=86400${process.env.NODE_ENV === "production" ? "; Secure" : ""}`
|
||||||
response.cookies.set(SESSION_COOKIE, token, {
|
|
||||||
httpOnly: true,
|
return new Response(JSON.stringify({ user }), {
|
||||||
secure: process.env.NODE_ENV === "production",
|
status: 200,
|
||||||
sameSite: "strict",
|
headers: {
|
||||||
path: "/",
|
"Content-Type": "application/json",
|
||||||
|
"Set-Cookie": cookieStr,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return response
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Login error:", error)
|
console.error("Login error:", error)
|
||||||
return NextResponse.json(
|
return new Response(
|
||||||
{ error: "Authentication service unavailable." },
|
JSON.stringify({ error: "Authentication service unavailable." }),
|
||||||
{ status: 503 }
|
{ status: 503, headers: { "Content-Type": "application/json" } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
import { NextResponse } from "next/server"
|
|
||||||
import { SESSION_COOKIE } from "@/lib/auth"
|
import { SESSION_COOKIE } from "@/lib/auth"
|
||||||
|
|
||||||
export async function POST() {
|
export async function POST() {
|
||||||
try {
|
try {
|
||||||
const response = NextResponse.json({ success: true }, { status: 200 })
|
return new Response(JSON.stringify({ success: true }), {
|
||||||
response.cookies.set(SESSION_COOKIE, "", {
|
status: 200,
|
||||||
httpOnly: true,
|
headers: {
|
||||||
secure: process.env.NODE_ENV === "production",
|
"Content-Type": "application/json",
|
||||||
sameSite: "strict",
|
"Set-Cookie": `${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`,
|
||||||
path: "/",
|
},
|
||||||
maxAge: 0,
|
|
||||||
})
|
})
|
||||||
return response
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Logout error:", error)
|
console.error("Logout error:", error)
|
||||||
return NextResponse.json(
|
return new Response(
|
||||||
{ error: "Logout failed." },
|
JSON.stringify({ error: "Logout failed." }),
|
||||||
{ status: 500 }
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side
|
|||||||
>
|
>
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className={cn("flex h-16 items-center border-b border-sidebar-border px-4", collapsed ? "justify-center" : "justify-between")}>
|
<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 ? (
|
{collapsed ? (
|
||||||
<div className="bc-logo" style={{padding: "8px 3px", fontSize: "16px"}}>B<span className="accent">C</span></div>
|
<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 bcrypt from "bcryptjs";
|
||||||
import { query } from "@/lib/db";
|
import { query } from "@/lib/db";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import crypto from "crypto";
|
|
||||||
|
|
||||||
const RAW_SECRET = process.env.NODE_ENV === "production"
|
function randomHex(length: number): string {
|
||||||
? process.env.JWT_SECRET
|
const chars = "abcdef0123456789";
|
||||||
: crypto.randomUUID();
|
let result = "";
|
||||||
if (!RAW_SECRET) {
|
for (let i = 0; i < length; i++) {
|
||||||
throw new Error("JWT_SECRET environment variable is required");
|
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);
|
const JWT_SECRET = new TextEncoder().encode(RAW_SECRET);
|
||||||
|
|
||||||
export const SESSION_COOKIE = "session";
|
export const SESSION_COOKIE = "session";
|
||||||
|
|||||||
+1
-18
@@ -1,12 +1,5 @@
|
|||||||
import { NextResponse } from "next/server"
|
import { NextResponse } from "next/server"
|
||||||
import type { NextRequest } 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 = [
|
const publicRoutes = [
|
||||||
"/login",
|
"/login",
|
||||||
@@ -41,17 +34,7 @@ export async function middleware(request: NextRequest) {
|
|||||||
return NextResponse.redirect(loginUrl)
|
return NextResponse.redirect(loginUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return NextResponse.next()
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
|
|||||||
Reference in New Issue
Block a user