fix(server): keep users' keys at their own endpoints, and more fixes from the third review

- Bedrock: a user's AWS keys no longer go to an endpoint the server sets
  in AWS_ENDPOINT_URL_BEDROCK_RUNTIME / AWS_ENDPOINT_URL (read by the
  upgraded SDK), and admin panel keys win over AWS_BEARER_TOKEN_BEDROCK,
  as the Test button checks them. Checked with Bedrock.
- Ollama: a server key without a base URL (admin panel, OLLAMA_API_KEY)
  goes to Ollama Cloud, as env.example says, instead of 127.0.0.1.
- Quota: EdgeOne counts whatever key header comes along, keyless Ollama at
  a private address counts, and their provider texts stay in the log.
- An EdgeOne server model (admin panel, ai-models.json) works: the route
  checked the raw provider header, which holds the name's slug.
- parse-url ends downloads it does not read (too large, PDF, errors).
- Desktop app: the port follows where the chats are (IndexedDB per
  origin) instead of a remembered port, which could hide them for good;
  a same-port restart tells the page to refetch the server models; a
  failed preset switch no longer undoes a newer choice; a presets file
  removed after a failed read can be saved again; .env values quoted from
  start to end keep their inner quotes, as dotenv reads them.
This commit is contained in:
dayuan.jiang
2026-10-05 13:04:51 +09:00
parent cfbf17f97e
commit 50c7ad3ec4
20 changed files with 466 additions and 160 deletions
+31 -7
View File
@@ -617,6 +617,20 @@ function validateProviderCredentials(
}
}
/** AWS's Bedrock endpoint for a region, as the Bedrock SDK builds it */
function bedrockRuntimeUrl(region: string): string {
const suffix =
[
["cn-", "amazonaws.com.cn"],
["us-iso-", "c2s.ic.gov"],
["us-isob-", "sc2s.sgov.gov"],
["eu-isoe-", "cloud.adc-e.uk"],
["us-isof-", "csp.hci.ic.gov"],
["eusc-", "amazonaws.eu"],
].find(([prefix]) => region.startsWith(prefix))?.[1] ?? "amazonaws.com"
return `https://bedrock-runtime.${region}.${suffix}`
}
/**
* Providers whose SDK has the official endpoint built in. The others are
* OpenAI-compatible APIs (or Anthropic) that are called at
@@ -903,12 +917,17 @@ export function getAIModel(clientOverrides?: ClientOverrides): ModelConfig {
// Without an apiKey the SDK reads the server's
// AWS_BEARER_TOKEN_BEDROCK, which wins over the keys
apiKey: "",
// Without a baseURL it reads the server's
// AWS_ENDPOINT_URL_BEDROCK_RUNTIME / AWS_ENDPOINT_URL
baseURL: bedrockRuntimeUrl(bedrockRegion),
})
: adminAccessKeyId && adminSecretAccessKey
? createAmazonBedrock({
region: bedrockRegion,
accessKeyId: adminAccessKeyId,
secretAccessKey: adminSecretAccessKey,
// The keys the admin panel's Test button checked
apiKey: "",
})
: createAmazonBedrock({
region: bedrockRegion,
@@ -959,19 +978,24 @@ export function getAIModel(clientOverrides?: ClientOverrides): ModelConfig {
}
case "ollama": {
// Like other providers, a user's key never goes to the server's
// base URL; without a base URL it is an Ollama Cloud key
const baseURL =
overrides?.baseUrl ||
(overrides?.apiKey
? PROVIDER_INFO.ollama.defaultBaseUrl
: process.env.OLLAMA_BASE_URL)
// SECURITY: When client provides a custom base URL, only use
// client-provided API key. Never fall back to server OLLAMA_API_KEY
// to prevent leaking server credentials to user-controlled endpoints.
const apiKey = overrides?.baseUrl
? overrides?.apiKey || undefined
: resolveApiKey(overrides, "OLLAMA_API_KEY")
// Like other providers, a user's key never goes to the server's
// base URL. A key without a base URL is an Ollama Cloud key
// (local Ollama has no keys); without either, the SDK's local
// default.
const baseURL =
overrides?.baseUrl ||
(overrides?.apiKey
? PROVIDER_INFO.ollama.defaultBaseUrl
: process.env.OLLAMA_BASE_URL ||
(apiKey
? PROVIDER_INFO.ollama.defaultBaseUrl
: undefined))
model = createOllama({
...(baseURL && { baseURL }),
...(apiKey && {