61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
|
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
||
|
|
import { getRuntimeEnv } from "./runtime-env";
|
||
|
|
|
||
|
|
function accessSecret() {
|
||
|
|
const env = getRuntimeEnv();
|
||
|
|
return (
|
||
|
|
env.KOC_MCP_API_KEY ||
|
||
|
|
env.KOC_LOOP_MCP_API_KEY ||
|
||
|
|
env.ADMIN_INTERNAL_TOKEN ||
|
||
|
|
env.AI_TOOL_CENTER_MCP_KEY ||
|
||
|
|
""
|
||
|
|
).trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
function signature(distributionId: string, screenshotKey: string, expiresAt: number) {
|
||
|
|
return createHmac("sha256", accessSecret())
|
||
|
|
.update(`${distributionId}:${screenshotKey}:${expiresAt}`)
|
||
|
|
.digest("hex");
|
||
|
|
}
|
||
|
|
|
||
|
|
export function creatorScreenshotAccessToken(
|
||
|
|
distributionId: string,
|
||
|
|
screenshotKey: string,
|
||
|
|
expiresAt = Math.floor(Date.now() / 1000) + 300,
|
||
|
|
) {
|
||
|
|
const secret = accessSecret();
|
||
|
|
if (!secret) throw new Error("图片识别访问密钥未配置");
|
||
|
|
return `${expiresAt}.${signature(distributionId, screenshotKey, expiresAt)}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function verifyCreatorScreenshotAccessToken(
|
||
|
|
distributionId: string,
|
||
|
|
screenshotKey: string,
|
||
|
|
token: string,
|
||
|
|
) {
|
||
|
|
const [expiresText, received] = token.split(".");
|
||
|
|
const expiresAt = Number(expiresText);
|
||
|
|
if (!Number.isInteger(expiresAt) || expiresAt < Math.floor(Date.now() / 1000)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
const expected = signature(distributionId, screenshotKey, expiresAt);
|
||
|
|
if (!received || received.length !== expected.length) return false;
|
||
|
|
return timingSafeEqual(Buffer.from(received), Buffer.from(expected));
|
||
|
|
}
|
||
|
|
|
||
|
|
export function creatorScreenshotMcpUrl(
|
||
|
|
request: Request,
|
||
|
|
distributionId: string,
|
||
|
|
screenshotKey: string,
|
||
|
|
) {
|
||
|
|
const env = getRuntimeEnv();
|
||
|
|
const origin = (env.APP_ORIGIN || new URL(request.url).origin).replace(/\/$/, "");
|
||
|
|
const url = new URL(`${origin}/api/creator-screenshot`);
|
||
|
|
url.searchParams.set("distribution", distributionId);
|
||
|
|
url.searchParams.set(
|
||
|
|
"mcp_token",
|
||
|
|
creatorScreenshotAccessToken(distributionId, screenshotKey),
|
||
|
|
);
|
||
|
|
return url.toString();
|
||
|
|
}
|