diff --git a/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts b/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts index 3345500b97f2..0aa348713b80 100644 --- a/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts +++ b/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts @@ -80,7 +80,17 @@ export function importLegacyCredentials(tx: Parameters name !== "server")) + : undefined, + }) : value.type === "wellknown" ? Credential.Key.make({ type: "key", key: value.token }) : Credential.OAuth.make({ diff --git a/packages/core/src/plugin/provider/mars.ts b/packages/core/src/plugin/provider/mars.ts index 4d3a304c2ca3..3886bd9b0090 100644 --- a/packages/core/src/plugin/provider/mars.ts +++ b/packages/core/src/plugin/provider/mars.ts @@ -9,7 +9,22 @@ import { Credential } from "../../credential.js" import { Integration } from "../../integration.js" import { Provider } from "../../provider.js" -const defaultServer = (process.env.MARSAI_URL ?? "https://marsai.click").replace(/\/+$/, "").replace(/\/v1$/i, "") +const fallbackServer = "https://marsai.click" + +function normalizeServer(raw: string) { + try { + const url = new URL(raw) + const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]" + if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) return undefined + return `${url.origin}${url.pathname.replace(/\/+$/, "").replace(/\/v1$/i, "")}` + } catch { + return undefined + } +} + +// MARSAI_URL gets the same check as a credential server. Without it the +// fallback itself could point the key at a remote host over plaintext http. +const defaultServer = (process.env.MARSAI_URL ? normalizeServer(process.env.MARSAI_URL) : undefined) ?? fallbackServer const integrationID = Integration.ID.make("marsai") const providerID = Provider.ID.make("marsai") const ModelsResponse = Schema.Struct({ @@ -27,7 +42,9 @@ const ModelsResponse = Schema.Struct({ }) function serverUrl(value: Credential.Key) { - return typeof value.metadata?.server === "string" ? value.metadata.server : defaultServer + const raw = value.metadata?.server + if (typeof raw !== "string") return defaultServer + return normalizeServer(raw) ?? defaultServer } function modelsFor(http: HttpClient.HttpClient, value: Credential.Key) {