This commit is contained in:
@@ -15,6 +15,75 @@ function getPassword(): string {
|
||||
return process.env.ADMIN_PASSWORD ?? "";
|
||||
}
|
||||
|
||||
function parseHostname(value: string | undefined): string | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const trimmed = value.trim().toLowerCase();
|
||||
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return new URL(trimmed).hostname.toLowerCase();
|
||||
} catch {
|
||||
return trimmed.replace(/^https?:\/\//, "").split("/")[0]?.replace(/:\d+$/, "") || undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function isCookieDomainCandidate(hostname: string | undefined): hostname is string {
|
||||
return Boolean(
|
||||
hostname &&
|
||||
hostname !== "localhost" &&
|
||||
!hostname.endsWith(".localhost") &&
|
||||
!/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname) &&
|
||||
!hostname.includes(":"),
|
||||
);
|
||||
}
|
||||
|
||||
function getSharedCookieHostname(hostnames: string[]): string | undefined {
|
||||
const validHostnames = hostnames.filter(isCookieDomainCandidate);
|
||||
|
||||
if (validHostnames.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (validHostnames.length === 1) {
|
||||
return validHostnames[0];
|
||||
}
|
||||
|
||||
const reversedSegments = validHostnames.map((hostname) => hostname.split(".").reverse());
|
||||
const sharedSegments: string[] = [];
|
||||
|
||||
for (let index = 0; index < reversedSegments[0].length; index += 1) {
|
||||
const segment = reversedSegments[0][index];
|
||||
|
||||
if (!segment || reversedSegments.some((parts) => parts[index] !== segment)) {
|
||||
break;
|
||||
}
|
||||
|
||||
sharedSegments.push(segment);
|
||||
}
|
||||
|
||||
if (sharedSegments.length < 2) {
|
||||
return validHostnames[0];
|
||||
}
|
||||
|
||||
return sharedSegments.reverse().join(".");
|
||||
}
|
||||
|
||||
function getAdminCookieDomain(): string | undefined {
|
||||
const hostname = getSharedCookieHostname([
|
||||
parseHostname(process.env.NEXT_PUBLIC_SITE_URL),
|
||||
parseHostname(process.env.NEXT_PUBLIC_ADMIN_URL),
|
||||
parseHostname(process.env.ADMIN_HOST),
|
||||
].filter((value): value is string => Boolean(value)));
|
||||
|
||||
return hostname ? `.${hostname}` : undefined;
|
||||
}
|
||||
|
||||
function signValue(value: string): string {
|
||||
return createHmac("sha256", getSecret()).update(value).digest("hex");
|
||||
}
|
||||
@@ -71,6 +140,7 @@ export async function setAdminSessionCookie(): Promise<void> {
|
||||
sameSite: "lax",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
path: "/",
|
||||
domain: getAdminCookieDomain(),
|
||||
maxAge: 60 * 60 * 8,
|
||||
});
|
||||
}
|
||||
@@ -82,6 +152,7 @@ export async function clearAdminSessionCookie(): Promise<void> {
|
||||
sameSite: "lax",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
path: "/",
|
||||
domain: getAdminCookieDomain(),
|
||||
maxAge: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
type RootNavigationCopy = {
|
||||
type AdminNavigationCopy = {
|
||||
overview: string;
|
||||
maintenance: string;
|
||||
uiKit: string;
|
||||
@@ -24,21 +24,21 @@ type RootNavigationCopy = {
|
||||
contactProtection?: string;
|
||||
};
|
||||
|
||||
export type RootNavItem = {
|
||||
export type AdminNavItem = {
|
||||
label: string;
|
||||
href: string;
|
||||
icon: LucideIcon;
|
||||
active?: boolean;
|
||||
expanded?: boolean;
|
||||
children?: RootNavItem[];
|
||||
children?: AdminNavItem[];
|
||||
};
|
||||
|
||||
export function getRootNavigation(
|
||||
copy: RootNavigationCopy,
|
||||
export function getAdminNavigation(
|
||||
copy: AdminNavigationCopy,
|
||||
active: "overview" | "maintenance" | "ui-kit" | "portfolio" | "media" | "site-settings" | "smtp" | "marquee",
|
||||
smtpChild?: "settings" | "contact-protection",
|
||||
portfolioChild?: "overview" | "projects" | "new-project" | "categories",
|
||||
): RootNavItem[] {
|
||||
): AdminNavItem[] {
|
||||
return [
|
||||
{
|
||||
label: copy.overview,
|
||||
Reference in New Issue
Block a user