diff --git a/web/frontend/src/views/Config.vue b/web/frontend/src/views/Config.vue
index 5b336bf..34dce3a 100644
--- a/web/frontend/src/views/Config.vue
+++ b/web/frontend/src/views/Config.vue
@@ -39,13 +39,22 @@
v-for="(value, key) in config[activeTab]"
:key="key"
class="field-row"
- :class="{ edited: edited[activeTab]?.[key] !== undefined && edited[activeTab][key] !== value }"
+ :class="{ edited: isEdited(activeTab, key, value) }"
>
+ = {
WebAuth: 'Web 认证',
}
+const SENSITIVE_KEYS = new Set(['api_key', 'secret_key', 'token', 'password', 'api_secret', 'access_key'])
+
+function isSensitive(key: string): boolean {
+ return SENSITIVE_KEYS.has(key.toLowerCase())
+}
+
+function isEdited(section: string, key: string, original: string): boolean {
+ const val = edited[section]?.[key]
+ if (val === undefined) return false
+ if (isSensitive(key)) return val !== ''
+ return val !== original
+
async function loadConfig() {
loading.value = true
try {
@@ -109,6 +130,10 @@ async function saveAll() {
const updates: { section: string; key: string; value: string }[] = []
for (const [section, keys] of Object.entries(edited)) {
for (const [key, value] of Object.entries(keys)) {
+ // Skip empty sensitive fields (user left placeholder unchanged)
+ if (isSensitive(key) && !value) continue
+ // Skip masked values that somehow got through
+ if (isSensitive(key) && value.includes('*')) continue
updates.push({ section, key, value })
}
}