Restrict ops page access to configured admin emails
This commit is contained in:
@@ -30,5 +30,6 @@ POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN=
|
|||||||
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=
|
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=
|
||||||
NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL=https://polygon-bor-rpc.publicnode.com
|
NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL=https://polygon-bor-rpc.publicnode.com
|
||||||
NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS=polyweather-pro.vercel.app
|
NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS=polyweather-pro.vercel.app
|
||||||
|
POLYWEATHER_OPS_ADMIN_EMAILS=yhrsc30@gmail.com
|
||||||
NEXT_PUBLIC_TELEGRAM_GROUP_URL=https://t.me/your_group
|
NEXT_PUBLIC_TELEGRAM_GROUP_URL=https://t.me/your_group
|
||||||
NEXT_PUBLIC_TELEGRAM_BOT_URL=https://t.me/WeatherQuant_bot
|
NEXT_PUBLIC_TELEGRAM_BOT_URL=https://t.me/WeatherQuant_bot
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { OpsDashboard } from "@/components/ops/OpsDashboard";
|
import { OpsDashboard } from "@/components/ops/OpsDashboard";
|
||||||
|
import { requireOpsAdmin } from "@/lib/ops-admin";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "PolyWeather Ops",
|
title: "PolyWeather Ops",
|
||||||
description: "PolyWeather lightweight operations dashboard.",
|
description: "PolyWeather lightweight operations dashboard.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function OpsPage() {
|
export default async function OpsPage() {
|
||||||
|
await requireOpsAdmin("/ops");
|
||||||
return <OpsDashboard />;
|
return <OpsDashboard />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { createSupabaseServerClient, hasSupabaseServerEnv } from "@/lib/supabase/server";
|
||||||
|
|
||||||
|
function parseAdminEmails() {
|
||||||
|
return String(process.env.POLYWEATHER_OPS_ADMIN_EMAILS || "")
|
||||||
|
.split(",")
|
||||||
|
.map((item) => item.trim().toLowerCase())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function requireOpsAdmin(nextPath = "/ops") {
|
||||||
|
const allowedEmails = parseAdminEmails();
|
||||||
|
if (!allowedEmails.length || !hasSupabaseServerEnv()) {
|
||||||
|
redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const supabase = createSupabaseServerClient({
|
||||||
|
getAll() {
|
||||||
|
return cookieStore.getAll().map((item) => ({
|
||||||
|
name: item.name,
|
||||||
|
value: item.value,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
setAll() {
|
||||||
|
// Server components cannot persist refreshed cookies. Route handlers keep
|
||||||
|
// the session fresh; here we only need read access for page gating.
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { user },
|
||||||
|
} = await supabase.auth.getUser();
|
||||||
|
|
||||||
|
const email = String(user?.email || "").trim().toLowerCase();
|
||||||
|
if (!email) {
|
||||||
|
redirect(`/auth/login?next=${encodeURIComponent(nextPath)}`);
|
||||||
|
}
|
||||||
|
if (!allowedEmails.includes(email)) {
|
||||||
|
redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { email };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user