2dac8bc47b
Deploy staging to test server / deploy (push) Successful in 3m11s
Use persisted self-hosted roles and the isolated admin origin so authorized staging accounts can discover the protected admin surface.
43 lines
1.1 KiB
TypeScript
43 lines
1.1 KiB
TypeScript
import "server-only";
|
|
|
|
import { queryAdminRows } from "@/lib/admin/database";
|
|
import {
|
|
createAdminSupabaseClient,
|
|
isAdminEmail,
|
|
} from "./admin-client-core";
|
|
|
|
export { createAdminSupabaseClient, isAdminEmail };
|
|
|
|
export async function isAdminUser(user: { id?: string; email?: string | null }) {
|
|
if (process.env.AUTH_PROVIDER?.trim() === "self-hosted") {
|
|
if (!user.id) return false;
|
|
try {
|
|
const rows = await queryAdminRows<{ role: string }>(
|
|
"select role from identity.users where id = $1 limit 1",
|
|
[user.id],
|
|
);
|
|
return rows[0]?.role
|
|
.split(",")
|
|
.map((role) => role.trim())
|
|
.some((role) => role === "admin" || role === "viewer") ?? false;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
if (isAdminEmail(user.email)) return true;
|
|
if (!user.id) return false;
|
|
|
|
try {
|
|
const admin = createAdminSupabaseClient();
|
|
const { data, error } = await admin
|
|
.from("admin_users")
|
|
.select("user_id")
|
|
.eq("user_id", user.id)
|
|
.is("revoked_at", null)
|
|
.maybeSingle();
|
|
return !error && Boolean(data);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|