fix: enhance Exchange configuration security and UI display

修复交易所配置的显示问题,并加强API接口安全性:

🎨 UI改进:
- 优化交易所配置信息的编辑和显示逻辑
- 改进前端交易所配置组件的交互体验

🛡️ 安全加固:
- 修复交易所配置接口中的敏感信息泄露漏洞
- handleGetExchangeConfigs: 清空返回数据中的敏感密钥
- handleGetSupportedExchanges: 加固无认证公开接口安全性

📋 密钥过滤策略:
- aster: 清空 asterPrivateKey 私钥
- binance: 清空 secretKey API密钥
- hyperliquid: 清空 apiKey API密钥

🔒 影响范围:
- GET /api/exchanges (需认证)
- GET /api/supported-exchanges (公开接口)
- 交易所配置前端组件

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: tinkle-community <tinklefund@gmail.com>
This commit is contained in:
sue
2025-11-05 21:36:37 +08:00
parent aecc5e58a1
commit d99eb198b0
2 changed files with 41 additions and 4 deletions

View File

@@ -697,6 +697,21 @@ func (s *Server) handleGetExchangeConfigs(c *gin.Context) {
}
log.Printf("✅ 找到 %d 个交易所配置", len(exchanges))
// 🛡️ 安全过滤:根据交易所类型清空对应的敏感密钥字段
for _, exchange := range exchanges {
switch exchange.ID {
case "aster":
// Aster交易所清空私钥
exchange.AsterPrivateKey = ""
case "binance":
// Binance交易所清空Secret Key
exchange.SecretKey = ""
case "hyperliquid":
// Hyperliquid交易所清空API Key
exchange.APIKey = ""
}
}
c.JSON(http.StatusOK, exchanges)
}
@@ -1458,6 +1473,21 @@ func (s *Server) handleGetSupportedExchanges(c *gin.Context) {
return
}
// 🛡️ 安全过滤:根据交易所类型清空对应的敏感密钥字段(此接口无需认证,风险更高)
for _, exchange := range exchanges {
switch exchange.ID {
case "aster":
// Aster交易所清空私钥
exchange.AsterPrivateKey = ""
case "binance":
// Binance交易所清空Secret Key
exchange.SecretKey = ""
case "hyperliquid":
// Hyperliquid交易所清空API Key
exchange.APIKey = ""
}
}
c.JSON(http.StatusOK, exchanges)
}

View File

@@ -812,6 +812,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
{showExchangeModal && (
<ExchangeConfigModal
allExchanges={supportedExchanges}
configuredExchanges={allExchanges}
editingExchangeId={editingExchange}
onSave={handleSaveExchangeConfig}
onDelete={handleDeleteExchangeConfig}
@@ -1144,6 +1145,7 @@ function ModelConfigModal({
// Exchange Configuration Modal Component
function ExchangeConfigModal({
allExchanges,
configuredExchanges,
editingExchangeId,
onSave,
onDelete,
@@ -1151,6 +1153,7 @@ function ExchangeConfigModal({
language
}: {
allExchanges: Exchange[];
configuredExchanges: Exchange[];
editingExchangeId: string | null;
onSave: (exchangeId: string, apiKey: string, secretKey?: string, testnet?: boolean, hyperliquidWalletAddr?: string, asterUser?: string, asterSigner?: string, asterPrivateKey?: string) => Promise<void>;
onDelete: (exchangeId: string) => void;
@@ -1171,8 +1174,12 @@ function ExchangeConfigModal({
const [asterSigner, setAsterSigner] = useState('');
const [asterPrivateKey, setAsterPrivateKey] = useState('');
// 获取当前编辑的交易所信息
const selectedExchange = allExchanges?.find(e => e.id === selectedExchangeId);
// 获取当前选择的交易所信息
// 编辑模式:从 configuredExchanges 查找(包含用户配置的 apiKey、secretKey 等)
// 新增模式:从 allExchanges 查找(系统支持的交易所列表)
const selectedExchange = editingExchangeId
? configuredExchanges?.find(e => e.id === selectedExchangeId)
: allExchanges?.find(e => e.id === selectedExchangeId);
// 如果是编辑现有交易所,初始化表单数据
useEffect(() => {
@@ -1181,10 +1188,10 @@ function ExchangeConfigModal({
setSecretKey(selectedExchange.secretKey || '');
setPassphrase(''); // Don't load existing passphrase for security
setTestnet(selectedExchange.testnet || false);
// Hyperliquid 字段
setHyperliquidWalletAddr(selectedExchange.hyperliquidWalletAddr || '');
// Aster 字段
setAsterUser(selectedExchange.asterUser || '');
setAsterSigner(selectedExchange.asterSigner || '');