fix(ai): trim API keys before authentication
This commit is contained in:
4 files changed
+60
-23
No files matched your search
@@ -2378,7 +2378,7 @@ function currentAiEditConfig() {
|
||||
const reasoningLevel = aiIsClaudeCodeCli.value ? normalizeClaudeCodeReasoningLevel(aiEditReasoningLevel.value, aiSelectedModelInfo.value) : aiEditReasoningLevel.value;
|
||||
return {
|
||||
provider: aiEditProvider.value,
|
||||
apiKey: aiEditApiKey.value,
|
||||
apiKey: aiEditApiKey.value.trim(),
|
||||
authMethod: aiEditAuthMethod.value,
|
||||
endpoint: aiEditEndpoint.value,
|
||||
model: aiEditModel.value,
|
||||
@@ -2503,7 +2503,7 @@ async function aiFetchModelList() {
|
||||
try {
|
||||
const models = await aiListModels({
|
||||
provider: aiEditProvider.value,
|
||||
apiKey: aiEditApiKey.value,
|
||||
apiKey: aiEditApiKey.value.trim(),
|
||||
endpoint: aiEditEndpoint.value,
|
||||
model: aiEditModel.value,
|
||||
authMethod: aiEditAuthMethod.value,
|
||||
|
||||
+26
-1
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { enforceRightSidebarPanelExclusivity, EXECUTE_MODE_CURRENT_DEFAULT_VERSION, normalizeDesktopSettings, normalizeEditorSettings, normalizeMcpGlobalPolicy, transitionRightSidebarPanels, type RightSidebarPanelState } from "@/stores/settingsStore";
|
||||
import { enforceRightSidebarPanelExclusivity, EXECUTE_MODE_CURRENT_DEFAULT_VERSION, normalizeAiConfig, normalizeDesktopSettings, normalizeEditorSettings, normalizeMcpGlobalPolicy, transitionRightSidebarPanels, type RightSidebarPanelState } from "@/stores/settingsStore";
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { isProxy } from "vue";
|
||||
import type { AiConfigItem } from "@/types/ai";
|
||||
@@ -318,6 +318,31 @@ function makeTestConfig(overrides: Partial<AiConfigItem> & { id: string }): AiCo
|
||||
} as AiConfigItem;
|
||||
}
|
||||
|
||||
describe("settingsStore AI API key normalization", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
it("trims API keys before persisting new configurations", async () => {
|
||||
const saveAiConfigItem = vi.fn().mockResolvedValue(undefined);
|
||||
vi.doMock("@/lib/backend/api", () => ({ saveAiConfigItem }));
|
||||
|
||||
const { useSettingsStore } = await import("@/stores/settingsStore");
|
||||
const store = useSettingsStore();
|
||||
const config = makeTestConfig({ id: "trimmed-key", apiKey: " \tsecret\r\n" });
|
||||
|
||||
await store.createAiConfig(config);
|
||||
|
||||
expect(saveAiConfigItem).toHaveBeenCalledWith(expect.objectContaining({ apiKey: "secret" }));
|
||||
expect(store.aiConfigs[0].apiKey).toBe("secret");
|
||||
});
|
||||
|
||||
it("trims API keys when normalizing loaded configurations", () => {
|
||||
expect(normalizeAiConfig({ provider: "openai", apiKey: " secret " }).apiKey).toBe("secret");
|
||||
});
|
||||
});
|
||||
|
||||
describe("settingsStore MCP policy persistence", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
|
||||
@@ -250,9 +250,9 @@ export function normalizeAiConfig(config: Partial<AiConfig> | null | undefined):
|
||||
const provider = config?.provider && config.provider in AI_PROVIDER_PRESETS ? config.provider : inferAiProviderFromConfig(config);
|
||||
return {
|
||||
...defaultConfigs[provider],
|
||||
apiKey: config?.apiKey ?? "",
|
||||
...config,
|
||||
provider,
|
||||
apiKey: (config?.apiKey ?? "").trim(),
|
||||
apiStyle: config?.apiStyle ?? defaultConfigs[provider].apiStyle,
|
||||
authMethod: config?.authMethod ?? defaultConfigs[provider].authMethod,
|
||||
proxyEnabled: !!config?.proxyEnabled,
|
||||
@@ -267,6 +267,10 @@ export function normalizeAiConfig(config: Partial<AiConfig> | null | undefined):
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAiConfigItem(config: AiConfigItem): AiConfigItem {
|
||||
return { ...config, ...normalizeAiConfig(config) };
|
||||
}
|
||||
|
||||
function inferAiProviderFromConfig(config: Partial<AiConfig> | null | undefined): AiProvider {
|
||||
const endpoint = config?.endpoint?.toLowerCase() ?? "";
|
||||
const model = config?.model?.toLowerCase() ?? "";
|
||||
@@ -1087,7 +1091,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
const newConfigs = await api.loadAiConfigs();
|
||||
|
||||
if (newConfigs.length > 0) {
|
||||
aiConfigs.value = newConfigs;
|
||||
aiConfigs.value = newConfigs.map(normalizeAiConfigItem);
|
||||
} else {
|
||||
// 迁移旧格式
|
||||
await migrateToMultiConfig();
|
||||
@@ -1146,17 +1150,18 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
}
|
||||
|
||||
async function createAiConfig(config: AiConfigItem): Promise<void> {
|
||||
await api.saveAiConfigItem(config);
|
||||
aiConfigs.value.push(config);
|
||||
const normalized = normalizeAiConfigItem(config);
|
||||
await api.saveAiConfigItem(normalized);
|
||||
aiConfigs.value.push(normalized);
|
||||
if (aiConfigs.value.length === 1) {
|
||||
activeModel.value = { configId: config.id, modelId: config.model };
|
||||
activeModel.value = { configId: normalized.id, modelId: normalized.model };
|
||||
}
|
||||
}
|
||||
|
||||
async function updateAiConfigItem(id: string, config: Partial<AiConfigItem>): Promise<void> {
|
||||
const index = aiConfigs.value.findIndex((c) => c.id === id);
|
||||
if (index !== -1) {
|
||||
const updated = { ...aiConfigs.value[index], ...config };
|
||||
const updated = normalizeAiConfigItem({ ...aiConfigs.value[index], ...config });
|
||||
await api.saveAiConfigItem(updated);
|
||||
aiConfigs.value[index] = updated;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user