fix ops admin frontend fallback
This commit is contained in:
@@ -43,6 +43,19 @@ export function runTests() {
|
||||
"ops server page gate must honor localhost ops access before Supabase/admin-email redirects",
|
||||
);
|
||||
|
||||
assert(
|
||||
opsAdminSource.includes("verifyOpsAdminWithBackend") &&
|
||||
opsAdminSource.includes("POLYWEATHER_API_BASE_URL") &&
|
||||
opsAdminSource.includes("/api/ops/online-users") &&
|
||||
opsAdminSource.includes("Authorization") &&
|
||||
opsAdminSource.includes("BACKEND_ENTITLEMENT_HEADER") &&
|
||||
opsAdminSource.includes("await supabase.auth.getSession()") &&
|
||||
opsAdminSource.includes("if (allowedEmails.includes(email))") &&
|
||||
opsAdminSource.includes("if (await verifyOpsAdminWithBackend(accessToken))") &&
|
||||
!opsAdminSource.includes("if (!allowedEmails.length || !hasSupabaseServerEnv())"),
|
||||
"ops admin page gate must fall back to the backend ops admin check when the frontend admin email env is missing or stale",
|
||||
);
|
||||
|
||||
assert(
|
||||
opsProxyAuthSource.includes("isLocalOpsAccessHost") &&
|
||||
opsProxyAuthSource.includes("x-forwarded-host") &&
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { cookies, headers } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { BACKEND_ENTITLEMENT_HEADER } from "@/lib/backend-auth";
|
||||
import { isLocalOpsAccessHost } from "@/lib/ops-local-access";
|
||||
import {
|
||||
createSupabaseServerClient,
|
||||
@@ -7,6 +8,7 @@ import {
|
||||
hasSupabaseSessionCookieValues,
|
||||
} from "@/lib/supabase/server";
|
||||
|
||||
const API_BASE = process.env.POLYWEATHER_API_BASE_URL;
|
||||
const LOCAL_DEV_OPS_EMAIL = "local-dev@polyweather.local";
|
||||
|
||||
function parseAdminEmails() {
|
||||
@@ -16,6 +18,30 @@ function parseAdminEmails() {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
async function verifyOpsAdminWithBackend(accessToken: string) {
|
||||
const token = String(accessToken || "").trim();
|
||||
if (!API_BASE || !token) return false;
|
||||
|
||||
const headers = new Headers({
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
});
|
||||
const backendToken = process.env.POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN?.trim();
|
||||
if (backendToken) {
|
||||
headers.set(BACKEND_ENTITLEMENT_HEADER, backendToken);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE.replace(/\/+$/, "")}/api/ops/online-users`, {
|
||||
cache: "no-store",
|
||||
headers,
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function requireOpsAdmin(nextPath = "/ops") {
|
||||
const headerStore = await headers();
|
||||
const requestHost =
|
||||
@@ -25,7 +51,7 @@ export async function requireOpsAdmin(nextPath = "/ops") {
|
||||
}
|
||||
|
||||
const allowedEmails = parseAdminEmails();
|
||||
if (!allowedEmails.length || !hasSupabaseServerEnv()) {
|
||||
if (!hasSupabaseServerEnv()) {
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
@@ -57,9 +83,18 @@ export async function requireOpsAdmin(nextPath = "/ops") {
|
||||
if (!email) {
|
||||
redirect(`/auth/login?next=${encodeURIComponent(nextPath)}`);
|
||||
}
|
||||
if (!allowedEmails.includes(email)) {
|
||||
redirect("/");
|
||||
|
||||
if (allowedEmails.includes(email)) {
|
||||
return { email };
|
||||
}
|
||||
|
||||
return { email };
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
const accessToken = session?.access_token || "";
|
||||
if (await verifyOpsAdminWithBackend(accessToken)) {
|
||||
return { email };
|
||||
}
|
||||
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user