| |
| |
| |
| |
| |
| |
| import { getSetting, setSetting } from "./db"; |
| import { config } from "./config"; |
|
|
| export type TempProviderType = "php" | "cf"; |
|
|
| export type TempProvider = { |
| id: string; |
| name: string; |
| type: TempProviderType; |
| endpoint: string; |
| domain: string; |
| password: string; |
| }; |
|
|
| export type TempProviderPublic = Omit<TempProvider, "password"> & { hasPassword: boolean }; |
|
|
| const KEY = "cf.providers"; |
|
|
| function slug(s: string): string { |
| return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "temp"; |
| } |
|
|
| |
| |
| function legacyProvider(): TempProvider | null { |
| const endpoint = |
| getSetting("cf.endpoint") ?? |
| config.CF_TEMP_EMAIL_API_ENDPOINT ?? |
| (config.CF_TEMP_EMAIL_BASE_URL ? `${config.CF_TEMP_EMAIL_BASE_URL.replace(/\/+$/, "")}/api.php` : undefined); |
| const password = getSetting("cf.password") ?? config.CF_TEMP_EMAIL_ADMIN_PASSWORD; |
| const domain = getSetting("cf.domain") ?? config.CF_TEMP_EMAIL_DOMAIN ?? ""; |
| if (!endpoint || !password) return null; |
| return { id: "edu", name: domain || "edu", type: "php", endpoint, domain, password }; |
| } |
|
|
| export function listProviders(): TempProvider[] { |
| const raw = getSetting(KEY); |
| if (raw) { |
| try { |
| const arr = JSON.parse(raw); |
| if (Array.isArray(arr)) return arr.filter((p) => p && p.id && p.endpoint).map(normalize); |
| } catch { |
| |
| } |
| } |
| const legacy = legacyProvider(); |
| return legacy ? [legacy] : []; |
| } |
|
|
| function normalize(p: any): TempProvider { |
| return { |
| id: String(p.id), |
| name: String(p.name || p.domain || p.id), |
| type: p.type === "cf" ? "cf" : "php", |
| endpoint: String(p.endpoint || "").replace(/\/+$/, ""), |
| domain: String(p.domain || ""), |
| password: String(p.password || "") |
| }; |
| } |
|
|
| export function getProvider(id?: string): TempProvider | undefined { |
| const list = listProviders(); |
| if (!id) return list[0]; |
| return list.find((p) => p.id === id); |
| } |
|
|
| export function requireProvider(id?: string): TempProvider { |
| const p = getProvider(id); |
| if (!p) throw new Error(id ? `临时邮箱源 ${id} 不存在` : "尚未配置任何临时邮箱源"); |
| return p; |
| } |
|
|
| export function listProvidersPublic(): TempProviderPublic[] { |
| return listProviders().map(({ password, ...rest }) => ({ ...rest, hasPassword: Boolean(password) })); |
| } |
|
|
| function persist(list: TempProvider[]): void { |
| setSetting(KEY, JSON.stringify(list)); |
| } |
|
|
| export function addProvider(input: { |
| name: string; |
| type?: TempProviderType; |
| endpoint: string; |
| domain?: string; |
| password: string; |
| }): TempProvider { |
| const list = listProviders(); |
| let id = slug(input.name || input.domain || "temp"); |
| let n = 1; |
| while (list.some((p) => p.id === id)) id = `${slug(input.name || "temp")}-${++n}`; |
| const provider: TempProvider = { |
| id, |
| name: input.name?.trim() || input.domain || id, |
| type: input.type === "cf" ? "cf" : "php", |
| endpoint: input.endpoint.trim().replace(/\/+$/, ""), |
| domain: (input.domain ?? "").trim(), |
| password: input.password |
| }; |
| persist([...list, provider]); |
| return provider; |
| } |
|
|
| export function updateProvider( |
| id: string, |
| patch: Partial<Pick<TempProvider, "name" | "type" | "endpoint" | "domain" | "password">> |
| ): TempProvider | undefined { |
| const list = listProviders(); |
| const idx = list.findIndex((p) => p.id === id); |
| if (idx === -1) return undefined; |
| const cur = list[idx]; |
| const next: TempProvider = { |
| ...cur, |
| name: patch.name?.trim() || cur.name, |
| type: patch.type ?? cur.type, |
| endpoint: (patch.endpoint ?? cur.endpoint).trim().replace(/\/+$/, ""), |
| domain: patch.domain !== undefined ? patch.domain.trim() : cur.domain, |
| |
| password: patch.password && patch.password.trim() ? patch.password : cur.password |
| }; |
| list[idx] = next; |
| persist(list); |
| return next; |
| } |
|
|
| export function removeProvider(id: string): boolean { |
| const list = listProviders(); |
| const next = list.filter((p) => p.id !== id); |
| if (next.length === list.length) return false; |
| persist(next); |
| return true; |
| } |
|
|
| export function tempConfigured(): boolean { |
| return listProviders().length > 0; |
| } |
|
|