Initial commit: Craft2Prints with Stages 1-3
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { jwtVerify } from 'jose';
|
||||
|
||||
const CUSTOMER_SESSION_COOKIE = 'customer_session';
|
||||
const PUBLIC_ACCOUNT_PATHS = ['/account/login', '/account/register', '/account/forgot-password', '/account/reset-password'];
|
||||
|
||||
const ADMIN_SESSION_COOKIE = 'admin_session';
|
||||
const PUBLIC_ADMIN_PATHS = ['/admin/login'];
|
||||
|
||||
// Protects everything under /admin with the shop owner's own login session —
|
||||
// entirely separate cookie and secret from the customer auth below, so
|
||||
// logging into one never grants access to the other.
|
||||
async function checkAdminAuth(request: NextRequest, requestHeaders: Headers) {
|
||||
if (PUBLIC_ADMIN_PATHS.includes(request.nextUrl.pathname)) {
|
||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
||||
}
|
||||
|
||||
const token = request.cookies.get(ADMIN_SESSION_COOKIE)?.value;
|
||||
const secret = process.env.ADMIN_SESSION_SECRET;
|
||||
|
||||
if (token && secret) {
|
||||
try {
|
||||
await jwtVerify(token, new TextEncoder().encode(secret));
|
||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
||||
} catch {
|
||||
// fall through to redirect
|
||||
}
|
||||
}
|
||||
|
||||
const loginUrl = new URL('/admin/login', request.url);
|
||||
loginUrl.searchParams.set('next', request.nextUrl.pathname);
|
||||
return NextResponse.redirect(loginUrl);
|
||||
}
|
||||
|
||||
// Protects everything under /account (except the login/register/reset pages
|
||||
// themselves) with a customer's own login session — entirely separate cookie
|
||||
// and secret from the admin auth above, so one never grants access to the other.
|
||||
async function checkCustomerAuth(request: NextRequest, requestHeaders: Headers) {
|
||||
if (PUBLIC_ACCOUNT_PATHS.includes(request.nextUrl.pathname)) {
|
||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
||||
}
|
||||
|
||||
const token = request.cookies.get(CUSTOMER_SESSION_COOKIE)?.value;
|
||||
const secret = process.env.SESSION_SECRET;
|
||||
|
||||
if (token && secret) {
|
||||
try {
|
||||
await jwtVerify(token, new TextEncoder().encode(secret));
|
||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
||||
} catch {
|
||||
// fall through to redirect
|
||||
}
|
||||
}
|
||||
|
||||
const loginUrl = new URL('/account/login', request.url);
|
||||
loginUrl.searchParams.set('next', request.nextUrl.pathname);
|
||||
return NextResponse.redirect(loginUrl);
|
||||
}
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
// Expose the path to server components (the root layout reads x-pathname to
|
||||
// decide whether to show the maintenance page). Edge middleware can't read the
|
||||
// DB, so the maintenance flag itself is checked in the layout, not here.
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
requestHeaders.set('x-pathname', pathname);
|
||||
|
||||
if (pathname.startsWith('/admin')) {
|
||||
return checkAdminAuth(request, requestHeaders);
|
||||
}
|
||||
if (pathname.startsWith('/account')) {
|
||||
return checkCustomerAuth(request, requestHeaders);
|
||||
}
|
||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
||||
}
|
||||
|
||||
export const config = {
|
||||
// Run on everything except static assets, so the x-pathname header is set on
|
||||
// every page. The auth branches above still only gate /admin and /account.
|
||||
matcher: ['/((?!_next/static|_next/image|favicon.ico|logo.png).*)'],
|
||||
};
|
||||
Reference in New Issue
Block a user