feat: encrypt API Key

# Conflicts:
#	web-app/package.json
This commit is contained in:
Louis 2025-09-25 23:58:12 +07:00
parent abb0da491b
commit 5363022634
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
3 changed files with 30 additions and 4 deletions

View File

@ -82,6 +82,7 @@
"remark-math": "6.0.0",
"sonner": "2.0.5",
"tailwindcss": "4.1.4",
"crypto-js": "^4.2.0",
"token.js": "npm:token.js-fork@0.7.27",
"tw-animate-css": "1.2.8",
"ulidx": "2.4.1",

View File

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import CryptoJS from 'crypto-js'
import {
ContentType,
ChatCompletionRole,
@ -168,9 +169,25 @@ export const sendCompletion = async (
if (!Object.keys(models).some((key) => key === providerName))
providerName = 'openai-compatible'
// Decrypt API key if it exists and is encrypted
const secretKey = await getServiceHub().core().getAppToken()
const decryptApiKey = (encryptedKey: string, key: string): string => {
try {
const bytes = CryptoJS.AES.decrypt(encryptedKey, key)
const decryptedKey = bytes.toString(CryptoJS.enc.Utf8)
return decryptedKey || encryptedKey // Return original if decryption fails
} catch (error) {
console.warn('Failed to decrypt API key, using original value:', error)
return encryptedKey
}
}
const apiKey = provider.api_key
? decryptApiKey(provider.api_key, secretKey || 'fallback-key')
: (secretKey ?? '')
const tokenJS = new TokenJS({
apiKey:
provider.api_key ?? (await getServiceHub().core().getAppToken()) ?? '',
apiKey,
// TODO: Retrieve from extension settings
baseURL: provider.base_url,
// Use Tauri's fetch to avoid CORS issues only for openai-compatible provider

View File

@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import CryptoJS from 'crypto-js'
import { Card, CardItem } from '@/containers/Card'
import HeaderPage from '@/containers/HeaderPage'
import SettingsMenu from '@/containers/SettingsMenu'
import { useModelProvider } from '@/hooks/useModelProvider'
import { getServiceHub } from '@/hooks/useServiceHub'
import { cn, getProviderTitle } from '@/lib/utils'
import {
createFileRoute,
@ -508,7 +510,7 @@ function ProviderDetail() {
'third-step-setup-remote-provider',
setting.key === 'device' && 'hidden'
)}
onChange={(newValue) => {
onChange={async (newValue) => {
if (provider) {
const newSettings = [...provider.settings]
// Handle different value types by forcing the type
@ -531,7 +533,13 @@ function ProviderDetail() {
settingKey === 'api-key' &&
typeof newValue === 'string'
) {
updateObj.api_key = newValue
const secretKey = await getServiceHub()
.core()
.getAppToken()
updateObj.api_key = CryptoJS.AES.encrypt(
newValue,
secretKey || 'fallback-key'
).toString()
} else if (
settingKey === 'base-url' &&
typeof newValue === 'string'