feat: validate runway api key format
This commit is contained in:
parent
1eb23a015f
commit
404e50a4d6
@ -6877,7 +6877,13 @@ export function AdminSettingsClient() {
|
||||
value={providerForm.apiKey}
|
||||
onChange={(e) => setProviderForm({ ...providerForm, apiKey: e.target.value })}
|
||||
autoComplete="new-password"
|
||||
placeholder={editingProvider ? "留空则不修改" : "sk-..."}
|
||||
placeholder={
|
||||
editingProvider
|
||||
? "留空则不修改"
|
||||
: providerForm.type === "runway"
|
||||
? "key_ 后跟 128 位十六进制字符"
|
||||
: "sk-..."
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
type="button" variant="ghost" size="sm"
|
||||
@ -6887,6 +6893,11 @@ export function AdminSettingsClient() {
|
||||
{showApiKey ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
{providerForm.type === "runway" && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Runway Key 必须以 `key_` 开头,后面是 128 位十六进制字符。不要粘贴带“Bearer ”、“API Key:”或中文标点的内容。
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
|
||||
@ -61,6 +61,7 @@ const OPENAI_IMAGE_BASE_URL = "https://api.openai.com/v1";
|
||||
const MIDJOURNEY_BASE_URL = "https://your-midjourney-api.example.com";
|
||||
const TRIPO_3D_BASE_URL = "https://api.tripo3d.ai/v2/openapi";
|
||||
const RUNWAY_BASE_URL = "https://api.dev.runwayml.com";
|
||||
const RUNWAY_API_KEY_PATTERN = /^key_[0-9a-f]{128}$/;
|
||||
|
||||
function normalizeProviderTypeForStorage(
|
||||
type?: ProviderType
|
||||
@ -70,6 +71,26 @@ function normalizeProviderTypeForStorage(
|
||||
return type;
|
||||
}
|
||||
|
||||
function normalizeRunwayApiKey(value: string) {
|
||||
return String(value || "")
|
||||
.replace(/\u00a0/g, " ")
|
||||
.trim()
|
||||
.normalize("NFKC")
|
||||
.replace(/^bearer\s+/i, "")
|
||||
.replace(/^key\s+/i, "")
|
||||
.replace(/^(?:runway[_-]?api[_-]?key|api[_-]?key|token)\s*[::]\s*/i, "")
|
||||
.replace(/[^\x20-\x7E]/g, "");
|
||||
}
|
||||
|
||||
function validateRunwayApiKey(apiKey: string) {
|
||||
if (!RUNWAY_API_KEY_PATTERN.test(apiKey)) {
|
||||
throw new ChatSDKError(
|
||||
"bad_request:api",
|
||||
"Runway API Key 格式无效,应为 key_ 开头并跟随 128 位十六进制字符"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function isZhipuBaseUrl(baseUrl: string) {
|
||||
return baseUrl.includes("open.bigmodel.cn");
|
||||
}
|
||||
@ -154,11 +175,17 @@ export async function POST(request: Request) {
|
||||
console.log("[Admin API] Create provider request body:", JSON.stringify(sanitizeProviderPayload(body)));
|
||||
|
||||
const data = createProviderSchema.parse(body);
|
||||
const normalizedApiKey =
|
||||
data.type === "runway" ? normalizeRunwayApiKey(data.apiKey) : data.apiKey;
|
||||
if (data.type === "runway") {
|
||||
validateRunwayApiKey(normalizedApiKey);
|
||||
}
|
||||
console.log("[Admin API] Validation passed, creating provider...");
|
||||
const storageType = normalizeProviderTypeForStorage(data.type) ?? "custom";
|
||||
|
||||
const provider = await createAiProvider({
|
||||
...data,
|
||||
apiKey: normalizedApiKey,
|
||||
type: storageType,
|
||||
baseUrl:
|
||||
data.type === "zhipu"
|
||||
@ -204,9 +231,23 @@ export async function PUT(request: Request) {
|
||||
|
||||
const body = await request.json();
|
||||
const data = updateProviderSchema.parse(body);
|
||||
const existingProvider = await getAiProviderById({ id: data.id });
|
||||
if (!existingProvider) {
|
||||
return new ChatSDKError("bad_request:api", "Provider not found").toResponse();
|
||||
}
|
||||
|
||||
const effectiveType = data.type || (existingProvider.type as ProviderType);
|
||||
const normalizedApiKey =
|
||||
effectiveType === "runway" && data.apiKey !== undefined
|
||||
? normalizeRunwayApiKey(data.apiKey)
|
||||
: data.apiKey;
|
||||
if (effectiveType === "runway" && normalizedApiKey !== undefined) {
|
||||
validateRunwayApiKey(normalizedApiKey);
|
||||
}
|
||||
|
||||
const provider = await updateAiProvider({
|
||||
...data,
|
||||
apiKey: normalizedApiKey,
|
||||
type: normalizeProviderTypeForStorage(data.type),
|
||||
updatedBy: session.user.id,
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user