优化:清理运行日志调用栈绝对路径,并修复SMTP中继配置保存校验
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-14 12:58:04 +08:00
parent 064455d09d
commit 85cce0044e
6 changed files with 46 additions and 5 deletions

View File

@ -155,7 +155,7 @@ func (l *logFormatter) Format(entry *log.Entry) ([]byte, error) {
}
}
if entry.Caller != nil {
b.WriteString(fmt.Sprintf("[%s:%d]", entry.Caller.File, entry.Caller.Line))
b.WriteString(fmt.Sprintf("[%s:%d]", runtimepath.CleanCallerPath(entry.Caller.File), entry.Caller.Line))
}
b.WriteString(entry.Message)
// 错误字段也是有效内容,不能在消息为空时被格式器丢弃。

View File

@ -883,6 +883,13 @@ func applySectionPayload(current RuntimeConfig, section Section, payload json.Ra
return RuntimeConfig{}, ErrInvalidSecretChange
}
value.SMTPSectionConfig.Relay.Password = current.SMTP.Relay.Password
if smtpRelayConfigured(value.SMTPSectionConfig.Relay) && value.SMTPSectionConfig.Relay.Security == "" {
if ResolveMailSecurity(value.SMTPSectionConfig.Listener) == MailSecurityImplicitTLS {
value.SMTPSectionConfig.Relay.Security = MailSecurityImplicitTLS
} else {
value.SMTPSectionConfig.Relay.Security = MailSecuritySTARTTLS
}
}
candidate.SMTP = value.SMTPSectionConfig
candidate.Email.Policy.LoginVerificationPolicy = candidate.SMTP.Relay.LoginPolicy
case SectionEmail:
@ -904,6 +911,13 @@ func applySectionPayload(current RuntimeConfig, section Section, payload json.Ra
return RuntimeConfig{}, ErrInvalidSecretChange
}
value.MailSectionConfig.Relay.Password = current.SMTP.Relay.Password
if smtpRelayConfigured(value.Relay) && value.Relay.Security == "" {
if ResolveMailSecurity(value.Listener) == MailSecurityImplicitTLS {
value.Relay.Security = MailSecurityImplicitTLS
} else {
value.Relay.Security = MailSecuritySTARTTLS
}
}
candidate.SMTP = SMTPSectionConfig{
Meta: value.Meta,
Listener: value.Listener,

View File

@ -1,6 +1,7 @@
package framework
import (
"git.pcux.cn/xuans/Smail/utils/runtimepath"
"bytes"
"crypto/subtle"
"encoding/json"
@ -141,7 +142,7 @@ func (l *logFormatter) Format(entry *log.Entry) ([]byte, error) {
b.WriteString(fmt.Sprintf("[%s]", ctx.GetValue(context.LogID)))
}
}
b.WriteString(fmt.Sprintf("[%s:%d]", entry.Caller.File, entry.Caller.Line))
b.WriteString(fmt.Sprintf("[%s:%d]", runtimepath.CleanCallerPath(entry.Caller.File), entry.Caller.Line))
b.WriteString(entry.Message)
b.WriteString("\n")

View File

@ -270,3 +270,26 @@ func migrate(root string, rename func(string, string) error) ([]Move, error) {
}
return completed, nil
}
// CleanCallerPath 清洗调用者代码路径,去除本地盘符和宿主机绝对目录,只保留模块相对路径。
func CleanCallerPath(path string) string {
if strings.TrimSpace(path) == "" {
return ""
}
normalized := strings.ReplaceAll(path, string(filepath.Separator), "/")
normalized = strings.ReplaceAll(normalized, "\\", "/")
for _, target := range []string{"backend/", "frontend/", "plugins/"} {
if index := strings.Index(normalized, target); index != -1 {
return normalized[index:]
}
}
marker := "smail/"
lower := strings.ToLower(normalized)
if index := strings.Index(lower, marker); index != -1 {
return normalized[index+len(marker):]
}
if len(normalized) >= 2 && normalized[1] == ':' {
return strings.TrimLeft(normalized[2:], "/")
}
return normalized
}

View File

@ -11,10 +11,10 @@ const mailSecurity = config => {
const value = normalizedMailSecurity(config.listener?.security)
return value || 'both'
}
const relaySecurityForMail = config => mailSecurity(config) === 'implicit_tls' ? 'implicit_tls' : 'starttls'
export const relaySecurityForMail = config => mailSecurity(config) === 'implicit_tls' ? 'implicit_tls' : 'starttls'
const startTLSMail = config => mailSecurity(config) === 'starttls'
const implicitTLSMail = config => mailSecurity(config) === 'implicit_tls'
const relayConfigured = config => !!(
export const relayConfigured = config => !!(
config.relay?.relayHost || config.relay?.username || config.relay?.password ||
config.relay?.from
)

View File

@ -3,7 +3,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { http } from '@/utils/axios'
import { useGlobalStatusStore } from '@/stores/useGlobalStatusStore'
import { isRecentAuthenticationCancelled, requestWithRecentAuthentication } from '@/utils/recentAuthentication'
import { readFormConfig, updateFormConfig, validateFormConfig } from './ConfigForm/ConfigForm.js'
import { readFormConfig, updateFormConfig, validateFormConfig, relayConfigured, relaySecurityForMail } from './ConfigForm/ConfigForm.js'
const sections = [
{ value: 'base', label: '基础配置' },
@ -493,6 +493,9 @@ export function usePage(pageKey = 'base') {
delete payload.relay
}
}
if (payload.relay && relayConfigured(payload) && !payload.relay.security) {
payload.relay.security = relaySecurityForMail(payload)
}
}
if (apiSection() === 'plugins' && payload.plugins && typeof payload.plugins === 'object') {
Object.values(payload.plugins).forEach(plugin => {