Browse Source

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
main
npmrun 3 weeks ago
parent
commit
29385f0ebe
  1. 8
      app/composables/useGlobalConfig.ts
  2. 5
      app/pages/me/admin/config/index.vue
  3. 18
      server/api/config/global.get.ts

8
app/composables/useGlobalConfig.ts

@ -13,7 +13,7 @@ export type GlobalConfig = {
} }
type GlobalConfigResult = { type GlobalConfigResult = {
config: GlobalConfig config: Partial<GlobalConfig>
} }
const DEFAULT_GLOBAL_CONFIG: GlobalConfig = { const DEFAULT_GLOBAL_CONFIG: GlobalConfig = {
@ -33,7 +33,11 @@ export function useGlobalConfig() {
'global:config', 'global:config',
async () => { async () => {
const payload = await request<ApiResponse<GlobalConfigResult>>('/api/config/global') const payload = await request<ApiResponse<GlobalConfigResult>>('/api/config/global')
return unwrapApiBody(payload).config const config = unwrapApiBody(payload).config ?? {}
return {
...DEFAULT_GLOBAL_CONFIG,
...config,
}
}, },
{ {
default: () => ({ ...DEFAULT_GLOBAL_CONFIG }), default: () => ({ ...DEFAULT_GLOBAL_CONFIG }),

5
app/pages/me/admin/config/index.vue

@ -90,7 +90,10 @@ async function save() {
await putKey('commentSmtpPort', commentSmtpPort.value) await putKey('commentSmtpPort', commentSmtpPort.value)
await putKey('commentSmtpSecure', commentSmtpSecure.value) await putKey('commentSmtpSecure', commentSmtpSecure.value)
await putKey('commentSmtpUser', commentSmtpUser.value.trim()) 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 load()
await refreshGlobalConfig() await refreshGlobalConfig()
toast.add({ title: '配置已保存', color: 'success' }) toast.add({ title: '配置已保存', color: 'success' })

18
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<KnownConfigKey>(["commentSmtpPass"]);
export default defineWrappedResponseHandler(async (event) => { 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( const entries = await Promise.all(
KNOWN_CONFIG_KEYS.map(async (key) => { keys.map(async (key) => {
const value = await event.context.config.getGlobal(key); const value = await event.context.config.getGlobal(key);
return [key, value] as const satisfies [KnownConfigKey, KnownConfigValue<KnownConfigKey>]; const safeValue =
SECRET_MASKED_GLOBAL_CONFIG_KEYS.has(key)
? ""
: value;
return [key, safeValue] as const satisfies [KnownConfigKey, KnownConfigValue<KnownConfigKey>];
}), }),
); );

Loading…
Cancel
Save