feat: add MCP creator screenshot metrics recognition

This commit is contained in:
巫凤萍
2026-08-19 15:08:17 +08:00
parent 8f7ea0558d
commit ab3a544eec
12 changed files with 342 additions and 36 deletions

View File

@@ -0,0 +1,60 @@
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();
}