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,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user