Phase 8
This commit is contained in:
82 files changed
+4903
-287
No files matched your search
+43
-2
@@ -1,6 +1,7 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { NextResponse } from "next/server";
|
||||
import { authConfig } from "@/auth.config";
|
||||
import { isInstalledForRequest } from "@/lib/installation/installation-state";
|
||||
|
||||
// /home, /appointments and /settings are intentionally NOT hard-gated here
|
||||
// as of Phase 4 — Home must work for guests (public business browsing +
|
||||
@@ -10,6 +11,25 @@ import { authConfig } from "@/auth.config";
|
||||
// permission-based tooling with no meaningful "guest" experience at all.
|
||||
const PROTECTED_PREFIXES = ["/staff", "/owner"];
|
||||
|
||||
// Reachable before installation completes: the installer itself, and the
|
||||
// small set of static/manifest assets a browser requests independently of
|
||||
// the page it's rendering (favicon, PWA manifest/icons, the offline
|
||||
// fallback, the service worker script). Everything else redirects to
|
||||
// /install until ApplicationInstallation flips to INSTALLED — see
|
||||
// src/lib/installation/installation-state.ts. `/api/*` never reaches this
|
||||
// file at all (excluded by `config.matcher` below); API routes that need
|
||||
// business data guard themselves (see /api/health and
|
||||
// /api/cron/process-notifications).
|
||||
const INSTALL_EXEMPT_PREFIXES = [
|
||||
"/install",
|
||||
"/offline",
|
||||
"/manifest.webmanifest",
|
||||
"/icon.png",
|
||||
"/apple-icon.png",
|
||||
"/icons/",
|
||||
"/sw.js",
|
||||
];
|
||||
|
||||
// Lightweight instance built from the DB-free config — see auth.config.ts.
|
||||
// Next.js 16 renamed this file convention from `middleware` to `proxy`
|
||||
// (https://nextjs.org/docs/messages/middleware-to-proxy); it now always
|
||||
@@ -57,12 +77,33 @@ function buildCsp(): string {
|
||||
].join("; ");
|
||||
}
|
||||
|
||||
export default auth((req) => {
|
||||
export default auth(async (req) => {
|
||||
const { pathname } = req.nextUrl;
|
||||
const csp = buildCsp();
|
||||
|
||||
const isInstallExempt = INSTALL_EXEMPT_PREFIXES.some(
|
||||
(prefix) => pathname === prefix || pathname.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`),
|
||||
);
|
||||
const installed = await isInstalledForRequest();
|
||||
|
||||
if (!installed && !isInstallExempt) {
|
||||
const response = NextResponse.redirect(new URL("/install", req.nextUrl.origin));
|
||||
response.headers.set("Content-Security-Policy", csp);
|
||||
return response;
|
||||
}
|
||||
if (installed && pathname === "/install") {
|
||||
// The wizard itself also refuses to render/submit once installed (see
|
||||
// src/app/install/page.tsx and the installer Server Action) — this
|
||||
// redirect is a convenience for direct navigation, not the actual
|
||||
// enforcement boundary.
|
||||
const response = NextResponse.redirect(new URL("/", req.nextUrl.origin));
|
||||
response.headers.set("Content-Security-Policy", csp);
|
||||
return response;
|
||||
}
|
||||
|
||||
const isProtected = PROTECTED_PREFIXES.some(
|
||||
(prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`),
|
||||
);
|
||||
const csp = buildCsp();
|
||||
|
||||
if (isProtected && !req.auth) {
|
||||
const signInUrl = new URL("/sign-in", req.nextUrl.origin);
|
||||
|
||||
Reference in new issue
Block a user