- 48 个 Go 文件所有注释(行注释/块注释/行尾注释,含 _test.go)翻译为中文 - 保留技术标识符:SECURITY_TODO(n)、unsafe-inline、sqlite/mysql、路由参数等 - 代码、字符串字面量、日志消息保持英文原文,零逻辑改动 - go build/vet 通过,go test -count=1 ./... 全绿
97 lines
3.0 KiB
Go
97 lines
3.0 KiB
Go
package handlers
|
||
|
||
import (
|
||
"net/mail"
|
||
"strings"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// minPasswordLength 是接受的最小密码长度,由注册、个人资料密码修改和
|
||
// 管理员用户管理共用(SECURITY_TODO #23)。与注册策略保持一致。
|
||
const minPasswordLength = 6
|
||
|
||
// validatePassword 报告明文密码是否符合平台策略(与注册相同的最小长度)。
|
||
func validatePassword(pw string) bool {
|
||
return len(pw) >= minPasswordLength
|
||
}
|
||
|
||
// validateEmail 报告邮箱地址是否格式正确。空值始终合法(该字段在多数表单中为可选项)。
|
||
func validateEmail(email string) bool {
|
||
email = strings.TrimSpace(email)
|
||
if email == "" {
|
||
return true
|
||
}
|
||
_, err := mail.ParseAddress(email)
|
||
return err == nil
|
||
}
|
||
|
||
// DefaultData 构建基础 gin.H 映射,填充由 SetUserContext 中间件设置的值
|
||
// (翻译、语言、认证状态)。处理器在其上添加页面特定字段并传给 c.HTML()。
|
||
func DefaultData(c *gin.Context) gin.H {
|
||
tr, _ := c.Get("tr")
|
||
isLoggedIn, _ := c.Get("is_logged_in")
|
||
username, _ := c.Get("username")
|
||
lang, _ := c.Get("lang")
|
||
switchLang, _ := c.Get("switch_lang")
|
||
avatar, _ := c.Get("avatar")
|
||
displayName, _ := c.Get("display_name")
|
||
role, _ := c.Get("role")
|
||
siteSetting, _ := c.Get("site_setting")
|
||
siteLogo, _ := c.Get("site_logo")
|
||
siteLogoIsURL, _ := c.Get("site_logo_is_url")
|
||
siteFavicon, _ := c.Get("site_favicon")
|
||
siteFaviconIsURL, _ := c.Get("site_favicon_is_url")
|
||
siteLogoText, _ := c.Get("site_logo_text")
|
||
siteHeaderText, _ := c.Get("site_header_text")
|
||
siteHomeWelcome, _ := c.Get("site_home_welcome")
|
||
siteHomeSubtitle, _ := c.Get("site_home_subtitle")
|
||
siteFooterText, _ := c.Get("site_footer_text")
|
||
navLinks, _ := c.Get("nav_links")
|
||
csrfToken, _ := c.Get("csrf_token")
|
||
|
||
return gin.H{
|
||
"Tr": tr,
|
||
"IsLoggedIn": isLoggedIn,
|
||
"Username": username,
|
||
"Lang": lang,
|
||
"SwitchLang": switchLang,
|
||
"Avatar": avatar,
|
||
"DisplayName": displayName,
|
||
"Role": role,
|
||
"SiteSetting": siteSetting,
|
||
"SiteLogo": siteLogo,
|
||
"SiteLogoIsURL": siteLogoIsURL,
|
||
"SiteFavicon": siteFavicon,
|
||
"SiteFaviconIsURL": siteFaviconIsURL,
|
||
"SiteLogoText": siteLogoText,
|
||
"SiteHeaderText": siteHeaderText,
|
||
"SiteHomeWelcome": siteHomeWelcome,
|
||
"SiteHomeSubtitle": siteHomeSubtitle,
|
||
"SiteFooterText": siteFooterText,
|
||
"NavLinks": navLinks,
|
||
"CSRFToken": csrfToken,
|
||
}
|
||
}
|
||
|
||
// getTr 是一个便捷辅助函数,从 Gin 上下文返回翻译映射,
|
||
// 未设置时回退到空映射。
|
||
func getTr(c *gin.Context) map[string]string {
|
||
tr, ok := c.Get("tr")
|
||
if !ok {
|
||
return map[string]string{}
|
||
}
|
||
m, ok := tr.(map[string]string)
|
||
if !ok {
|
||
return map[string]string{}
|
||
}
|
||
return m
|
||
}
|
||
|
||
// GetClientIP 返回真实客户端 IP。它依赖 gin 的代理感知 ClientIP(),
|
||
// 遵循 trusted_proxies 配置:只有该列表中的 IP 才能影响
|
||
// X-Forwarded-For,因此直接客户端无法伪造该值。
|
||
func GetClientIP(c *gin.Context) string {
|
||
return c.ClientIP()
|
||
}
|