import type { Permission, ServiceTokenEntry } from "@/lib/constants/auth"; import { forbidden, unauthorized } from "@/modules/auth/errors"; export type VerifiedServiceToken = { customerId: string; permissions: Permission[]; }; let cachedTokenMap: Map | null = null; function loadTokenMap(): Map { if (cachedTokenMap) { return cachedTokenMap; } const raw = process.env.HOST_SERVICE_TOKENS; if (!raw) { cachedTokenMap = new Map(); return cachedTokenMap; } let parsed: Record; try { parsed = JSON.parse(raw) as Record; } catch { throw new Error("HOST_SERVICE_TOKENS 配置无效"); } cachedTokenMap = new Map(Object.entries(parsed)); return cachedTokenMap; } /** 测试专用:重置缓存 */ export function resetServiceTokenCache(): void { cachedTokenMap = null; } /** 校验宿主 Service Token 与 customer_id 租户绑定 */ export function verifyServiceToken( token: string, customerId: string, ): VerifiedServiceToken { const entry = loadTokenMap().get(token); if (!entry) { throw unauthorized("Service Token 无效"); } if (entry.customerId !== customerId) { throw forbidden("customer_id 与令牌租户不匹配"); } return { customerId: entry.customerId, permissions: entry.permissions ?? [], }; } /** 已注册宿主客户 ID 集合(markup 写操作校验用) */ export function listRegisteredCustomerIds(): string[] { const ids = new Set(); for (const entry of loadTokenMap().values()) { ids.add(entry.customerId); } const registry = process.env.CUSTOMER_REGISTRY; if (registry) { for (const part of registry.split(",")) { const id = part.trim(); if (id) { ids.add(id); } } } return [...ids].sort(); } export function isKnownCustomer(customerId: string): boolean { return listRegisteredCustomerIds().includes(customerId); } /** 仅校验 token 存在(middleware 用,不含 customer 绑定) */ export function parseServiceToken(token: string): VerifiedServiceToken | null { const entry = loadTokenMap().get(token); if (!entry) { return null; } return { customerId: entry.customerId, permissions: entry.permissions ?? [], }; }