fix(api): require access codes and limit sizes on helper routes

- Shared checkAccessCode for validate-diagram, validate-model, parse-url, verify-access-code
- parse-url: 5 MB streamed body limit; validate-diagram: 5 MB image limit
- validate-model refuses redirects when private URLs are blocked
- Admin settings state shared across module instances via globalThis
- Server model ids: unique slugs (non-ASCII names encoded), duplicates rejected
- Panel Bedrock credentials stored as ADMIN_AWS_* so the DynamoDB client keeps its own
- Locale redirect keeps basePath and query; EdgeOne function drops open CORS and checks the access code
- Providers payload reports whether .env sets a default model
This commit is contained in:
dayuan.jiang
2026-10-03 17:45:41 +09:00
parent 366480426d
commit 528b6e54c8
16 changed files with 622 additions and 93 deletions
+47 -4
View File
@@ -69,7 +69,7 @@ describe("deriveEnvUpdates", () => {
expect(updates.ADMIN_OPENAI_API_KEY_2).toBe("sk-second")
})
it("maps bedrock credentials to AWS env vars", () => {
it("maps bedrock credentials to ADMIN_AWS_* env vars", () => {
const updates = deriveEnvUpdates(
[
provider({
@@ -83,9 +83,26 @@ describe("deriveEnvUpdates", () => {
],
[],
)
expect(updates.AWS_ACCESS_KEY_ID).toBe("AKIA123")
expect(updates.AWS_SECRET_ACCESS_KEY).toBe("secret")
expect(updates.AWS_REGION).toBe("us-west-2")
expect(updates.ADMIN_AWS_ACCESS_KEY_ID).toBe("AKIA123")
expect(updates.ADMIN_AWS_SECRET_ACCESS_KEY).toBe("secret")
expect(updates.ADMIN_AWS_REGION).toBe("us-west-2")
// Standard AWS vars are left to the environment
expect(updates.AWS_ACCESS_KEY_ID).toBeUndefined()
})
it("clears AWS_* bedrock keys written by older versions", () => {
const bedrock = provider({
provider: "bedrock",
apiKey: undefined,
awsAccessKeyId: "AKIA123",
awsSecretAccessKey: "secret",
models: ["claude-x"],
})
const updates = deriveEnvUpdates([bedrock], [bedrock])
expect(updates.AWS_ACCESS_KEY_ID).toBeNull()
expect(updates.AWS_SECRET_ACCESS_KEY).toBeNull()
expect(updates.AWS_REGION).toBeNull()
expect(updates.ADMIN_AWS_ACCESS_KEY_ID).toBe("AKIA123")
})
it("clears keys owned by the previous list when providers are removed", () => {
@@ -315,6 +332,32 @@ describe("validateAdminProviders", () => {
expect(validateAdminProviders(list)).toMatch(/unique/)
})
it("rejects names that differ only in case or punctuation", () => {
const list = [
provider({ id: "p1", name: "Open AI" }),
provider({ id: "p2", name: "open-ai" }),
]
expect(validateAdminProviders(list)).toMatch(/unique/)
})
it("rejects a case-only clash with an env-configured name", () => {
expect(
validateAdminProviders([provider({ name: "openai" })], {
providers: [
{ name: "OpenAI", provider: "openai", models: ["gpt-x"] },
],
}),
).toMatch(/already defined/)
})
it("accepts distinct CJK names", () => {
const list = [
provider({ id: "p1", provider: "deepseek", name: "主力" }),
provider({ id: "p2", provider: "deepseek", name: "备用" }),
]
expect(validateAdminProviders(list)).toBeNull()
})
it("rejects multiple defaults", () => {
const list = [
provider({ id: "p1", isDefault: true }),