mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
149 lines
4.4 KiB
TypeScript
149 lines
4.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import type { NextAuthRequest } from "next-auth";
|
|
|
|
import { auth } from "@/auth.config";
|
|
import { getCspHeader } from "@/lib/csp";
|
|
import {
|
|
GATED_INTEGRATIONS,
|
|
isGatedIntegrationEnabled,
|
|
readGatedEnv,
|
|
} from "@/lib/integrations";
|
|
import {
|
|
SLACK_CALLBACK_PATH,
|
|
SLACK_EXPIRED_CALLBACK_URL,
|
|
} from "@/lib/integrations/slack-connect-status";
|
|
import { REGISTRY_ACCESS } from "@/lib/registry/access";
|
|
import { evaluateRegistryAccess } from "@/lib/registry/access.server";
|
|
import { getRegistryPresentation } from "@/lib/registry/presentation";
|
|
import { readEnv } from "@/lib/runtime-env";
|
|
import { isCloud } from "@/lib/shared/env";
|
|
import { copyAttributionParams } from "@/lib/utm";
|
|
|
|
const publicRoutes = [
|
|
"/sign-in",
|
|
"/sign-up",
|
|
"/invitation/accept",
|
|
// In Cloud uncomment the following lines:
|
|
// "/reset-password",
|
|
// "/email-verification",
|
|
// "/set-password",
|
|
];
|
|
|
|
const isPublicRoute = (pathname: string): boolean => {
|
|
return publicRoutes.some((route) => pathname.startsWith(route));
|
|
};
|
|
|
|
const withSecurityHeaders = (response: NextResponse): NextResponse => {
|
|
response.headers.set(
|
|
"Content-Security-Policy",
|
|
getCspHeader({
|
|
cloudEnabled: isCloud(),
|
|
registryImageOrigins: getRegistryPresentation(
|
|
readEnv("UI_REGISTRY_URL"),
|
|
readEnv("UI_REGISTRY_MEDIA_URL"),
|
|
).imageOrigins,
|
|
posthogEnabled: isGatedIntegrationEnabled(GATED_INTEGRATIONS.posthog),
|
|
posthogKey: readGatedEnv(
|
|
"UI_POSTHOG_ENABLED",
|
|
"UI_POSTHOG_KEY",
|
|
"POSTHOG_KEY",
|
|
),
|
|
posthogIngestionHost: readGatedEnv(
|
|
"UI_POSTHOG_ENABLED",
|
|
"UI_POSTHOG_HOST",
|
|
"POSTHOG_HOST",
|
|
),
|
|
posthogUiHost: readGatedEnv("UI_POSTHOG_ENABLED", "UI_POSTHOG_UI_HOST"),
|
|
posthogToolbarEnabled: process.env.NODE_ENV === "development",
|
|
}),
|
|
);
|
|
return response;
|
|
};
|
|
|
|
const redirect = (url: URL): NextResponse =>
|
|
withSecurityHeaders(NextResponse.redirect(url));
|
|
|
|
// NextAuth's auth() wrapper - renamed from middleware to proxy
|
|
export default auth(async (req: NextAuthRequest) => {
|
|
const { pathname } = req.nextUrl;
|
|
|
|
const user = req.auth?.user;
|
|
const sessionError = req.auth?.error;
|
|
const cloudBillingEnabled =
|
|
(readEnv("CLOUD_BILLING_ENABLED") ?? "false") !== "false";
|
|
|
|
// If there's a session error (e.g., RefreshAccessTokenError), redirect to login with error info
|
|
if (sessionError && !isPublicRoute(pathname)) {
|
|
const signInUrl = new URL("/sign-in", req.url);
|
|
signInUrl.searchParams.set("error", sessionError);
|
|
signInUrl.searchParams.set(
|
|
"callbackUrl",
|
|
pathname === SLACK_CALLBACK_PATH
|
|
? SLACK_EXPIRED_CALLBACK_URL
|
|
: pathname + req.nextUrl.search,
|
|
);
|
|
if (pathname !== SLACK_CALLBACK_PATH) {
|
|
copyAttributionParams(req.nextUrl.searchParams, signInUrl.searchParams);
|
|
}
|
|
return redirect(signInUrl);
|
|
}
|
|
|
|
if (!user && !isPublicRoute(pathname)) {
|
|
const signInUrl = new URL("/sign-in", req.url);
|
|
signInUrl.searchParams.set(
|
|
"callbackUrl",
|
|
pathname === SLACK_CALLBACK_PATH
|
|
? SLACK_EXPIRED_CALLBACK_URL
|
|
: pathname + req.nextUrl.search,
|
|
);
|
|
if (pathname !== SLACK_CALLBACK_PATH) {
|
|
copyAttributionParams(req.nextUrl.searchParams, signInUrl.searchParams);
|
|
}
|
|
return redirect(signInUrl);
|
|
}
|
|
|
|
if (
|
|
pathname.startsWith("/billing") &&
|
|
(!isCloud() ||
|
|
!cloudBillingEnabled ||
|
|
user?.permissions?.manage_billing !== true)
|
|
) {
|
|
return redirect(new URL("/profile", req.url));
|
|
}
|
|
|
|
if (
|
|
(pathname === "/registry" || pathname.startsWith("/registry/")) &&
|
|
(await evaluateRegistryAccess(req.auth?.accessToken)).status !==
|
|
REGISTRY_ACCESS.ELIGIBLE
|
|
) {
|
|
return redirect(new URL("/profile", req.url));
|
|
}
|
|
|
|
if (user?.permissions) {
|
|
const permissions = user.permissions;
|
|
|
|
if (
|
|
pathname.startsWith("/integrations") &&
|
|
!permissions.manage_integrations
|
|
) {
|
|
return redirect(new URL("/profile", req.url));
|
|
}
|
|
}
|
|
|
|
return withSecurityHeaders(NextResponse.next());
|
|
});
|
|
|
|
export const config = {
|
|
matcher: [
|
|
/*
|
|
* Match all request paths except for the ones starting with:
|
|
* - api (API routes)
|
|
* - _next/static (static files)
|
|
* - _next/image (image optimization files)
|
|
* - favicon.ico (favicon file)
|
|
* - *.png, *.jpg, *.jpeg, *.svg, *.ico (image files)
|
|
*/
|
|
"/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:png|jpg|jpeg|svg|ico|css|js)$).*)",
|
|
],
|
|
};
|