Compare commits

..

6 Commits

6 changed files with 29 additions and 14 deletions

View File

@@ -767,6 +767,7 @@
"api_key_added": "API key added successfully",
"api_key_updated": "API key updated successfully",
"api_key_deleted": "API key deleted successfully",
"api_key_invalid_chars": "API key can only contain letters, numbers, and symbols",
"gemini_key_added": "Gemini key added successfully",
"gemini_key_updated": "Gemini key updated successfully",
"gemini_key_deleted": "Gemini key deleted successfully",

View File

@@ -767,6 +767,7 @@
"api_key_added": "API密钥添加成功",
"api_key_updated": "API密钥更新成功",
"api_key_deleted": "API密钥删除成功",
"api_key_invalid_chars": "API密钥仅支持英文字母、数字和符号",
"gemini_key_added": "Gemini密钥添加成功",
"gemini_key_updated": "Gemini密钥更新成功",
"gemini_key_deleted": "Gemini密钥删除成功",

View File

@@ -9,6 +9,7 @@ import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
import { useAuthStore, useConfigStore, useNotificationStore } from '@/stores';
import { apiKeysApi } from '@/services/api';
import { maskApiKey } from '@/utils/format';
import { isValidApiKeyCharset } from '@/utils/validation';
import styles from './ApiKeysPage.module.scss';
export function ApiKeysPage() {
@@ -83,6 +84,10 @@ export function ApiKeysPage() {
showNotification(`${t('notification.please_enter')} ${t('notification.api_key')}`, 'error');
return;
}
if (!isValidApiKeyCharset(trimmed)) {
showNotification(t('notification.api_key_invalid_chars'), 'error');
return;
}
const isEdit = editingIndex !== null;
const nextKeys = isEdit

View File

@@ -133,14 +133,18 @@
.editorWrapper {
width: 100%;
flex: 1;
min-height: 800px;
flex: 0 0 auto;
height: clamp(360px, 60vh, 920px);
border: 1px solid var(--border-color);
border-radius: $radius-lg;
overflow: hidden;
position: relative;
--floating-controls-height: 0px;
@supports (height: 100dvh) {
height: clamp(360px, 60dvh, 920px);
}
// Floating search toolbar on top of the editor (but not covering content).
.floatingControls {
position: absolute;
@@ -219,8 +223,8 @@
.configCard {
display: flex;
flex-direction: column;
height: 1120px;
flex-shrink: 0;
flex: 1;
min-height: 0;
overflow: visible;
}
@@ -253,11 +257,6 @@
}
.configCard {
height: 880px;
padding: $spacing-md;
}
.editorWrapper {
min-height: 600px;
}
}

View File

@@ -4,16 +4,17 @@
*/
/**
* 隐藏 API Key 中间部分
* 隐藏 API Key 中间部分,仅保留前后两位
*/
export function maskApiKey(key: string, visibleChars: number = 4): string {
if (!key || key.length <= visibleChars * 2) {
return key;
export function maskApiKey(key: string): string {
if (!key) {
return '';
}
const visibleChars = 2;
const start = key.slice(0, visibleChars);
const end = key.slice(-visibleChars);
const maskedLength = Math.min(key.length - visibleChars * 2, 20);
const maskedLength = Math.max(key.length - visibleChars * 2, 1);
const masked = '*'.repeat(maskedLength);
return `${start}${masked}${end}`;

View File

@@ -35,6 +35,14 @@ export function isValidApiKey(key: string): boolean {
return !/\s/.test(key);
}
/**
* 验证 API Key 字符集(仅允许 ASCII 可见字符)
*/
export function isValidApiKeyCharset(key: string): boolean {
if (!key) return false;
return /^[\x21-\x7E]+$/.test(key);
}
/**
* 验证 JSON 格式
*/