From 29385f0ebe65cc7194a120050ff2b663553a3a6e Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Mon, 20 Apr 2026 20:16:46 +0800 Subject: [PATCH] fix(config): mask smtp secret and avoid empty password overwrite Restrict global config GET for non-admin users and always mask commentSmtpPass in responses, while preventing admin save from sending empty smtp passwords that would clear existing secrets. Made-with: Cursor --- app/composables/useGlobalConfig.ts | 8 ++++++-- app/pages/me/admin/config/index.vue | 5 ++++- server/api/config/global.get.ts | 18 +++++++++++++++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/app/composables/useGlobalConfig.ts b/app/composables/useGlobalConfig.ts index c3e03a1..43dea96 100644 --- a/app/composables/useGlobalConfig.ts +++ b/app/composables/useGlobalConfig.ts @@ -13,7 +13,7 @@ export type GlobalConfig = { } type GlobalConfigResult = { - config: GlobalConfig + config: Partial } const DEFAULT_GLOBAL_CONFIG: GlobalConfig = { @@ -33,7 +33,11 @@ export function useGlobalConfig() { 'global:config', async () => { const payload = await request>('/api/config/global') - return unwrapApiBody(payload).config + const config = unwrapApiBody(payload).config ?? {} + return { + ...DEFAULT_GLOBAL_CONFIG, + ...config, + } }, { default: () => ({ ...DEFAULT_GLOBAL_CONFIG }), diff --git a/app/pages/me/admin/config/index.vue b/app/pages/me/admin/config/index.vue index 46efdcd..5d39e90 100644 --- a/app/pages/me/admin/config/index.vue +++ b/app/pages/me/admin/config/index.vue @@ -90,7 +90,10 @@ async function save() { await putKey('commentSmtpPort', commentSmtpPort.value) await putKey('commentSmtpSecure', commentSmtpSecure.value) await putKey('commentSmtpUser', commentSmtpUser.value.trim()) - await putKey('commentSmtpPass', commentSmtpPass.value.trim()) + const nextCommentSmtpPass = commentSmtpPass.value.trim() + if (nextCommentSmtpPass.length > 0) { + await putKey('commentSmtpPass', nextCommentSmtpPass) + } await load() await refreshGlobalConfig() toast.add({ title: '配置已保存', color: 'success' }) diff --git a/server/api/config/global.get.ts b/server/api/config/global.get.ts index 13879a8..c97bad2 100644 --- a/server/api/config/global.get.ts +++ b/server/api/config/global.get.ts @@ -1,10 +1,22 @@ -import { KNOWN_CONFIG_KEYS, KnownConfigKey, KnownConfigValue } from "#server/service/config/registry"; +import { KNOWN_CONFIG_KEYS } from "#server/service/config/registry"; +import type { KnownConfigKey, KnownConfigValue } from "#server/service/config/registry"; + +const PUBLIC_GLOBAL_CONFIG_KEYS = ["siteName", "allowRegister"] as const satisfies readonly KnownConfigKey[]; +const SECRET_MASKED_GLOBAL_CONFIG_KEYS = new Set(["commentSmtpPass"]); export default defineWrappedResponseHandler(async (event) => { + const user = await event.context.auth.getCurrent(); + const isAdmin = user?.role === "admin"; + const keys: readonly KnownConfigKey[] = isAdmin ? KNOWN_CONFIG_KEYS : PUBLIC_GLOBAL_CONFIG_KEYS; + const entries = await Promise.all( - KNOWN_CONFIG_KEYS.map(async (key) => { + keys.map(async (key) => { const value = await event.context.config.getGlobal(key); - return [key, value] as const satisfies [KnownConfigKey, KnownConfigValue]; + const safeValue = + SECRET_MASKED_GLOBAL_CONFIG_KEYS.has(key) + ? "" + : value; + return [key, safeValue] as const satisfies [KnownConfigKey, KnownConfigValue]; }), );