mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-15 05:35:07 +08:00
fix: fully mask web secret previews
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import { X } from 'lucide-react'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { maskSecret } from '../../utils/maskSecret'
|
||||
|
||||
export default function AddKeyModal({ show, t, editingKey, newKey, setNewKey, loading, onClose, onAdd }) {
|
||||
if (!show) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isEditing = Boolean(editingKey?.key)
|
||||
const displayKey = isEditing ? maskSecret(editingKey?.key || newKey.key) : newKey.key
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4 animate-in fade-in">
|
||||
@@ -25,7 +28,7 @@ export default function AddKeyModal({ show, t, editingKey, newKey, setNewKey, lo
|
||||
type="text"
|
||||
className={isEditing ? "input-field bg-muted/30 flex-1 cursor-not-allowed" : "input-field bg-[#09090b] flex-1"}
|
||||
placeholder={isEditing ? t('accountManager.keyReadonlyPlaceholder') : t('accountManager.newKeyPlaceholder')}
|
||||
value={newKey.key}
|
||||
value={displayKey}
|
||||
onChange={e => setNewKey({ ...newKey, key: e.target.value })}
|
||||
autoFocus={!isEditing}
|
||||
readOnly={isEditing}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useState } from 'react'
|
||||
import { Check, ChevronDown, Copy, Pencil, Plus, Trash2 } from 'lucide-react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { maskSecret } from '../../utils/maskSecret'
|
||||
|
||||
function fallbackCopyText(text) {
|
||||
const textArea = document.createElement('textarea')
|
||||
textArea.value = text
|
||||
@@ -102,7 +104,7 @@ export default function ApiKeysPanel({
|
||||
className="font-mono text-sm bg-muted/50 px-3 py-1 rounded inline-block hover:bg-muted transition-colors"
|
||||
title={t('accountManager.copyKeyTitle')}
|
||||
>
|
||||
{(item.key || '').slice(0, 16)}****
|
||||
{maskSecret(item.key)}
|
||||
</button>
|
||||
<div className="text-sm text-muted-foreground truncate">{item.remark || '-'}</div>
|
||||
{copiedKey === item.key && (
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
} from 'lucide-react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { maskSecret } from '../../utils/maskSecret'
|
||||
|
||||
export default function ConfigPanel({
|
||||
t,
|
||||
configExpanded,
|
||||
@@ -40,6 +42,7 @@ export default function ConfigPanel({
|
||||
}
|
||||
const selectedModel = models.find(m => m.id === model) || models[0]
|
||||
const SelectedModelIcon = selectedModel ? (iconMap[selectedModel.icon] || MessageSquare) : MessageSquare
|
||||
const defaultKeyPreview = maskSecret(config.keys?.[0])
|
||||
|
||||
return (
|
||||
<div className={clsx(
|
||||
@@ -158,7 +161,7 @@ export default function ConfigPanel({
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
className="w-full h-10 px-3 bg-muted/30 border border-border rounded-lg text-sm font-mono placeholder:text-muted-foreground/40 focus:outline-none focus:ring-1 focus:ring-ring focus:border-ring transition-all"
|
||||
placeholder={config.keys?.[0] ? t('apiTester.apiKeyDefault', { suffix: config.keys[0].slice(-6) }) : t('apiTester.apiKeyPlaceholder')}
|
||||
placeholder={defaultKeyPreview ? t('apiTester.apiKeyDefault', { preview: defaultKeyPreview }) : t('apiTester.apiKeyPlaceholder')}
|
||||
value={apiKey}
|
||||
onChange={e => setApiKey(e.target.value)}
|
||||
/>
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
"accountSelector": "Account",
|
||||
"autoRandom": "🤖 Auto / Random",
|
||||
"apiKeyOptional": "API Key (optional)",
|
||||
"apiKeyDefault": "Default: ...{suffix}",
|
||||
"apiKeyDefault": "Default: {preview}",
|
||||
"apiKeyPlaceholder": "Enter a custom key",
|
||||
"modeManaged": "Managed key mode (uses account pool).",
|
||||
"modeDirect": "Direct token mode (requires a valid DeepSeek token).",
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
"accountSelector": "选择账号",
|
||||
"autoRandom": "🤖 自动 / 随机",
|
||||
"apiKeyOptional": "API 密钥 (可选)",
|
||||
"apiKeyDefault": "默认: ...{suffix}",
|
||||
"apiKeyDefault": "默认: {preview}",
|
||||
"apiKeyPlaceholder": "输入自定义密钥",
|
||||
"modeManaged": "当前使用托管 key 模式(会走账号池)。",
|
||||
"modeDirect": "当前使用直通 token 模式(需填写有效 DeepSeek token)。",
|
||||
|
||||
10
webui/src/utils/maskSecret.js
Normal file
10
webui/src/utils/maskSecret.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export function maskSecret(secret) {
|
||||
const value = String(secret ?? '')
|
||||
if (!value) {
|
||||
return ''
|
||||
}
|
||||
if (value.length <= 4) {
|
||||
return '*'.repeat(value.length)
|
||||
}
|
||||
return `${value.slice(0, 2)}****${value.slice(-2)}`
|
||||
}
|
||||
Reference in New Issue
Block a user