72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { env } from "cloudflare:workers";
|
|
import { redirect } from "next/navigation";
|
|
import {
|
|
getChatGPTUser,
|
|
requireChatGPTUser,
|
|
type ChatGPTUser,
|
|
} from "./chatgpt-auth";
|
|
import type { CloudIdentity } from "@/db/repository";
|
|
|
|
export type CloudViewer = CloudIdentity & {
|
|
isLocalDemo: boolean;
|
|
isAdmin: boolean;
|
|
};
|
|
|
|
function toIdentity(user: ChatGPTUser): CloudIdentity {
|
|
return {
|
|
userId: user.userId,
|
|
email: user.email,
|
|
displayName: user.displayName,
|
|
};
|
|
}
|
|
|
|
function localDemoIdentity(): CloudIdentity | null {
|
|
if (process.env.NODE_ENV === "production") return null;
|
|
return {
|
|
userId: "local-demo-user",
|
|
email: "demo@nekonest.local",
|
|
displayName: "本地演示账户",
|
|
};
|
|
}
|
|
|
|
function isAdminEmail(email: string, isLocalDemo: boolean): boolean {
|
|
if (isLocalDemo) return true;
|
|
const configured = env.NEKONEST_CLOUD_ADMIN_EMAILS ?? "";
|
|
const allowed = configured
|
|
.split(",")
|
|
.map((item) => item.trim().toLowerCase())
|
|
.filter(Boolean);
|
|
return allowed.includes(email.toLowerCase());
|
|
}
|
|
|
|
export async function getCloudViewer(): Promise<CloudViewer | null> {
|
|
const signedIn = await getChatGPTUser();
|
|
const demo = signedIn ? null : localDemoIdentity();
|
|
const identity = signedIn ? toIdentity(signedIn) : demo;
|
|
if (!identity) return null;
|
|
const isLocalDemo = Boolean(demo);
|
|
return {
|
|
...identity,
|
|
isLocalDemo,
|
|
isAdmin: isAdminEmail(identity.email, isLocalDemo),
|
|
};
|
|
}
|
|
|
|
export async function requireCloudViewer(returnTo: string): Promise<CloudViewer> {
|
|
const viewer = await getCloudViewer();
|
|
if (viewer) return viewer;
|
|
const user = await requireChatGPTUser(returnTo);
|
|
const identity = toIdentity(user);
|
|
return {
|
|
...identity,
|
|
isLocalDemo: false,
|
|
isAdmin: isAdminEmail(identity.email, false),
|
|
};
|
|
}
|
|
|
|
export async function requireAdminViewer(returnTo = "/admin"): Promise<CloudViewer> {
|
|
const viewer = await requireCloudViewer(returnTo);
|
|
if (!viewer.isAdmin) redirect("/dashboard?admin=denied");
|
|
return viewer;
|
|
}
|