mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
fix(ai): use provider name instead of config name for auth profile keys
This commit is contained in:
1 parent
0bd5bc9f38
commit
415dcefc7d
2 files changed
+55
-34
No files matched your search
@@ -13,6 +13,31 @@ import type { Migration, MigrationContext } from './types'
|
||||
import { isEncrypted, decryptApiKey } from './crypto-legacy'
|
||||
import { writeAuthProfile } from '../auth-profiles'
|
||||
|
||||
/**
|
||||
* Derive a human-readable profile name from config fields.
|
||||
* Official providers → provider id (e.g. "deepseek")
|
||||
* openai-compatible → hostname from baseUrl (e.g. "api.example.com") or config name
|
||||
*/
|
||||
function deriveProfileName(provider: string, config: Record<string, unknown>): string {
|
||||
if (provider !== 'openai-compatible') {
|
||||
return provider.toLowerCase().replace(/\s+/g, '-')
|
||||
}
|
||||
|
||||
const baseUrl = config.baseUrl as string
|
||||
if (baseUrl) {
|
||||
try {
|
||||
return new URL(baseUrl).hostname.toLowerCase()
|
||||
} catch {
|
||||
// invalid URL, fall through
|
||||
}
|
||||
}
|
||||
|
||||
const name = config.name as string
|
||||
if (name) return name.toLowerCase().replace(/\s+/g, '-')
|
||||
|
||||
return 'custom'
|
||||
}
|
||||
|
||||
export const m004EncryptedKeysToAuthProfiles: Migration = {
|
||||
version: 4,
|
||||
name: 'encrypted-keys-to-auth-profiles',
|
||||
@@ -31,34 +56,40 @@ export const m004EncryptedKeysToAuthProfiles: Migration = {
|
||||
|
||||
const configs = (data.configs as Array<Record<string, unknown>>) || []
|
||||
let migrated = false
|
||||
const usedProfileNames = new Set<string>()
|
||||
|
||||
for (const config of configs) {
|
||||
const apiKey = config.apiKey as string
|
||||
if (!apiKey) continue
|
||||
|
||||
if (isEncrypted(apiKey)) {
|
||||
const plainKey = decryptApiKey(apiKey)
|
||||
if (plainKey) {
|
||||
const provider = (config.provider as string) || 'unknown'
|
||||
const name = (config.name as string) || provider
|
||||
const profileName = name.toLowerCase().replace(/\s+/g, '-')
|
||||
const provider = (config.provider as string) || 'unknown'
|
||||
let plainKey: string | null = null
|
||||
|
||||
writeAuthProfile(profileName, { type: 'api_key', provider, key: plainKey })
|
||||
config.apiKey = ''
|
||||
migrated = true
|
||||
ctx.logger.info('Migration', `Migrated API key for "${name}" to auth-profiles.json`)
|
||||
} else {
|
||||
if (isEncrypted(apiKey)) {
|
||||
plainKey = decryptApiKey(apiKey)
|
||||
if (!plainKey) {
|
||||
ctx.logger.warn('Migration', `Failed to decrypt API key for "${config.name}", skipping`)
|
||||
continue
|
||||
}
|
||||
} else if (apiKey.length > 0) {
|
||||
const provider = (config.provider as string) || 'unknown'
|
||||
const name = (config.name as string) || provider
|
||||
const profileName = name.toLowerCase().replace(/\s+/g, '-')
|
||||
plainKey = apiKey
|
||||
}
|
||||
|
||||
writeAuthProfile(profileName, { type: 'api_key', provider, key: apiKey })
|
||||
if (plainKey) {
|
||||
const baseName = deriveProfileName(provider, config)
|
||||
|
||||
let profileName = baseName
|
||||
if (usedProfileNames.has(profileName)) {
|
||||
let i = 2
|
||||
while (usedProfileNames.has(`${profileName}-${i}`)) i++
|
||||
profileName = `${profileName}-${i}`
|
||||
}
|
||||
usedProfileNames.add(profileName)
|
||||
|
||||
writeAuthProfile(profileName, { type: 'api_key', provider, key: plainKey })
|
||||
config.apiKey = ''
|
||||
migrated = true
|
||||
ctx.logger.info('Migration', `Migrated plaintext API key for "${name}" to auth-profiles.json`)
|
||||
ctx.logger.info('Migration', `Migrated API key → profile "${profileName}"`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -597,32 +597,22 @@ export function useAIConfigForm(props: {
|
||||
// ============ 保存 ============
|
||||
|
||||
function generateName(): string {
|
||||
let providerName: string
|
||||
|
||||
if (isCompatMode.value && formData.value.baseUrl) {
|
||||
try {
|
||||
const url = new URL(formData.value.baseUrl)
|
||||
providerName = url.hostname
|
||||
return url.hostname
|
||||
} catch {
|
||||
providerName = t('settings.aiConfig.modal.customService')
|
||||
return t('settings.aiConfig.modal.customService')
|
||||
}
|
||||
} else {
|
||||
const def = currentProviderDef.value
|
||||
providerName = def
|
||||
? getLocalizedProviderName(def.id) || def.name
|
||||
: (() => {
|
||||
const legacy = props.providers.value.find((p) => p.id === formData.value.provider)
|
||||
if (legacy) return legacy.name
|
||||
return formData.value.baseUrl || t('settings.aiConfig.modal.customService')
|
||||
})()
|
||||
}
|
||||
|
||||
const modelId = formData.value.model.trim()
|
||||
if (!modelId) return providerName
|
||||
const def = currentProviderDef.value
|
||||
if (def) return getLocalizedProviderName(def.id) || def.name
|
||||
|
||||
const modelDef = llmStore.getModelById(formData.value.provider, modelId)
|
||||
const modelName = modelDef?.name || modelId
|
||||
return `${providerName} - ${modelName}`
|
||||
const legacy = props.providers.value.find((p) => p.id === formData.value.provider)
|
||||
if (legacy) return legacy.name
|
||||
|
||||
return formData.value.baseUrl || t('settings.aiConfig.modal.customService')
|
||||
}
|
||||
|
||||
async function doSave() {
|
||||
|
||||
Reference in new issue
Block a user