refactor: cleanup unused code and simplify internal packages
This commit performs a significant cleanup of the codebase by removing unused functions, methods, and entire files across various internal modules. This reduces technical debt and simplifies the project structure. Key changes include: - **cache**: Removed unused cache key generators and metrics snapshots. - **dto**: Removed redundant converter functions and segment creation helpers. - **middleware**: Deleted the unused `logger.go` middleware and simplified `ratelimit.go` and `casbin.go`. - **model**: Removed unused ID helpers, database closing functions, and batch decryption logic. - **pkg**: Cleaned up unused utility functions in `circuitbreaker`, `crypto`, `cursor`, `hook`, and `utils`. - **service**: Deleted `account_cleanup_service.go` and removed unused helper functions in `log_cleanup_service.go` and `sensitive_service.go`. - **repository**: Removed unused private loading methods in `comment_repo.go`.
This commit is contained in:
@@ -22,15 +22,6 @@ type Config struct {
|
||||
Name string // 熔断器名称,用于日志
|
||||
}
|
||||
|
||||
func DefaultConfig(name string) Config {
|
||||
return Config{
|
||||
FailureThreshold: 5,
|
||||
SuccessThreshold: 3,
|
||||
Timeout: 30 * time.Second,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
type Breaker struct {
|
||||
cfg Config
|
||||
mu sync.Mutex
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -75,35 +74,3 @@ func (e *MessageEncryptor) BatchDecrypt(ciphertexts []string, workerCount int) [
|
||||
return results
|
||||
}
|
||||
|
||||
// DecryptMessageSegments 解密消息段 JSON
|
||||
// 这是一个便捷方法,直接返回解析后的 MessageSegments
|
||||
func (e *MessageEncryptor) DecryptMessageSegments(ciphertext string) ([]byte, error) {
|
||||
if e == nil || ciphertext == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return e.Decrypt(ciphertext)
|
||||
}
|
||||
|
||||
// TryParseMessageSegments 尝试解析消息段
|
||||
// 先尝试解密,如果失败则尝试直接解析(兼容未加密的旧数据)
|
||||
func TryParseMessageSegments(ciphertext string, segments any) error {
|
||||
if ciphertext == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
encryptor := GetMessageEncryptor()
|
||||
if encryptor == nil {
|
||||
// 加密器未初始化,直接解析
|
||||
return json.Unmarshal([]byte(ciphertext), segments)
|
||||
}
|
||||
|
||||
// 尝试解密
|
||||
plaintext, err := encryptor.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
// 解密失败,可能是未加密的旧数据,尝试直接解析
|
||||
return json.Unmarshal([]byte(ciphertext), segments)
|
||||
}
|
||||
|
||||
// 解析解密后的数据
|
||||
return json.Unmarshal(plaintext, segments)
|
||||
}
|
||||
|
||||
@@ -167,7 +167,3 @@ func (e *MessageEncryptor) RotateKey(newKey string, newVersion int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsInitialized 检查加密器是否已初始化
|
||||
func IsInitialized() bool {
|
||||
return globalEncryptor != nil
|
||||
}
|
||||
|
||||
@@ -64,19 +64,6 @@ func (b *CursorBuilder) WithPageSize(size int) *CursorBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// WithDirection 设置分页方向
|
||||
func (b *CursorBuilder) WithDirection(direction Direction) *CursorBuilder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
if direction == "" {
|
||||
b.direction = Forward
|
||||
} else {
|
||||
b.direction = direction
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Error 返回构建过程中的错误
|
||||
func (b *CursorBuilder) Error() error {
|
||||
@@ -166,79 +153,11 @@ func HasMore(itemsLen int, pageSize int) bool {
|
||||
return itemsLen > pageSize
|
||||
}
|
||||
|
||||
// TrimItems 裁剪结果到实际页面大小
|
||||
func TrimItems(itemsLen int, pageSize int) int {
|
||||
if itemsLen > pageSize {
|
||||
return pageSize
|
||||
}
|
||||
return itemsLen
|
||||
}
|
||||
|
||||
// BuildResponse 从结果构建响应
|
||||
// items: 结果切片(需要是切片类型)
|
||||
// getSortValue: 获取排序字段值的函数
|
||||
// getID: 获取ID的函数
|
||||
func BuildResponse[T any](items []T, order SortOrder, pageSize int, getSortValue func(T) string, getID func(T) string) *PageResponse {
|
||||
hasMore := len(items) > pageSize
|
||||
|
||||
// 裁剪到实际页面大小
|
||||
if hasMore {
|
||||
items = items[:pageSize]
|
||||
}
|
||||
|
||||
var nextCursor, prevCursor string
|
||||
|
||||
// 生成下一页游标
|
||||
if hasMore && len(items) > 0 {
|
||||
lastItem := items[len(items)-1]
|
||||
nextCursor = NewCursor(getSortValue(lastItem), getID(lastItem), order).Encode()
|
||||
}
|
||||
|
||||
return &PageResponse{
|
||||
Items: items,
|
||||
NextCursor: nextCursor,
|
||||
PrevCursor: prevCursor,
|
||||
HasMore: hasMore,
|
||||
}
|
||||
}
|
||||
|
||||
// BuildResponseWithPrev 从结果构建响应(包含上一页游标)
|
||||
func BuildResponseWithPrev[T any](items []T, order SortOrder, pageSize int, getSortValue func(T) string, getID func(T) string) *PageResponse {
|
||||
hasMore := len(items) > pageSize
|
||||
|
||||
// 裁剪到实际页面大小
|
||||
if hasMore {
|
||||
items = items[:pageSize]
|
||||
}
|
||||
|
||||
var nextCursor, prevCursor string
|
||||
|
||||
// 生成下一页游标
|
||||
if hasMore && len(items) > 0 {
|
||||
lastItem := items[len(items)-1]
|
||||
nextCursor = NewCursor(getSortValue(lastItem), getID(lastItem), order).Encode()
|
||||
}
|
||||
|
||||
// 生成上一页游标
|
||||
if len(items) > 0 {
|
||||
firstItem := items[0]
|
||||
prevCursor = NewCursor(getSortValue(firstItem), getID(firstItem), order).Encode()
|
||||
}
|
||||
|
||||
return &PageResponse{
|
||||
Items: items,
|
||||
NextCursor: nextCursor,
|
||||
PrevCursor: prevCursor,
|
||||
HasMore: hasMore,
|
||||
}
|
||||
}
|
||||
|
||||
// FormatTime 格式化时间为字符串(用于游标)
|
||||
func FormatTime(t time.Time) string {
|
||||
return t.Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
// ParseTime 解析时间字符串(从游标)
|
||||
func ParseTime(s string) (time.Time, error) {
|
||||
return time.Parse(time.RFC3339Nano, s)
|
||||
}
|
||||
|
||||
@@ -99,15 +99,6 @@ type PageResponse struct {
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// NewPageResponse 创建分页响应
|
||||
func NewPageResponse(items any, nextCursor, prevCursor string, hasMore bool) *PageResponse {
|
||||
return &PageResponse{
|
||||
Items: items,
|
||||
NextCursor: nextCursor,
|
||||
PrevCursor: prevCursor,
|
||||
HasMore: hasMore,
|
||||
}
|
||||
}
|
||||
|
||||
// CursorPageResult 游标分页结果(泛型版本,供内部使用)
|
||||
type CursorPageResult[T any] struct {
|
||||
|
||||
@@ -187,11 +187,6 @@ func WithAsync() HookOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithTimeout(timeout time.Duration) HookOption {
|
||||
return func(h *Hook) {
|
||||
h.Timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Trigger(ctx context.Context, hookType HookType, userID uint, data any) error {
|
||||
return m.TriggerWithMetadata(ctx, hookType, userID, data, nil)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package hook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -196,144 +194,3 @@ func (b *BuiltinHooks) registerLoggingHooks() {
|
||||
func (b *BuiltinHooks) registerCacheInvalidationHooks() {
|
||||
}
|
||||
|
||||
type HookTriggerHelper struct {
|
||||
manager *Manager
|
||||
}
|
||||
|
||||
func NewHookTriggerHelper(manager *Manager) *HookTriggerHelper {
|
||||
return &HookTriggerHelper{manager: manager}
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerPostCreated(ctx context.Context, userID uint, data *PostHookData) {
|
||||
h.manager.Trigger(ctx, HookPostCreated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerPostUpdated(ctx context.Context, userID uint, data *PostHookData) {
|
||||
h.manager.Trigger(ctx, HookPostUpdated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerPostDeleted(ctx context.Context, userID uint, postID uint) {
|
||||
h.manager.Trigger(ctx, HookPostDeleted, userID, postID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerCommentCreated(ctx context.Context, userID uint, data *CommentHookData) {
|
||||
h.manager.Trigger(ctx, HookCommentCreated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerCommentDeleted(ctx context.Context, userID uint, commentID uint) {
|
||||
h.manager.Trigger(ctx, HookCommentDeleted, userID, commentID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserCreated(ctx context.Context, data *UserHookData) {
|
||||
h.manager.Trigger(ctx, HookUserCreated, data.UserID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserUpdated(ctx context.Context, userID uint, data *UserHookData) {
|
||||
h.manager.Trigger(ctx, HookUserUpdated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserDeleted(ctx context.Context, userID uint) {
|
||||
h.manager.Trigger(ctx, HookUserDeleted, userID, userID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserLogin(ctx context.Context, userID uint, data *UserHookData) {
|
||||
h.manager.Trigger(ctx, HookUserLogin, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserLogout(ctx context.Context, userID uint) {
|
||||
h.manager.Trigger(ctx, HookUserLogout, userID, userID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerGroupCreated(ctx context.Context, userID uint, data *GroupHookData) {
|
||||
h.manager.Trigger(ctx, HookGroupCreated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerGroupUpdated(ctx context.Context, userID uint, data *GroupHookData) {
|
||||
h.manager.Trigger(ctx, HookGroupUpdated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerGroupDeleted(ctx context.Context, userID uint, groupID uint) {
|
||||
h.manager.Trigger(ctx, HookGroupDeleted, userID, groupID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerGroupJoined(ctx context.Context, userID uint, groupID uint) {
|
||||
h.manager.Trigger(ctx, HookGroupJoined, userID, groupID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerGroupLeft(ctx context.Context, userID uint, groupID uint) {
|
||||
h.manager.Trigger(ctx, HookGroupLeft, userID, groupID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerMessageSent(ctx context.Context, userID uint, data *MessageHookData) {
|
||||
h.manager.Trigger(ctx, HookMessageSent, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerMessageRead(ctx context.Context, userID uint, messageID uint) {
|
||||
h.manager.Trigger(ctx, HookMessageRead, userID, messageID)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerNotificationSent(ctx context.Context, userID uint, data *NotificationHookData) {
|
||||
h.manager.Trigger(ctx, HookNotificationSent, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerVoteCreated(ctx context.Context, userID uint, data *VoteHookData) {
|
||||
h.manager.Trigger(ctx, HookVoteCreated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerVoteUpdated(ctx context.Context, userID uint, data *VoteHookData) {
|
||||
h.manager.Trigger(ctx, HookVoteUpdated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerFileUploaded(ctx context.Context, userID uint, data *FileHookData) {
|
||||
h.manager.Trigger(ctx, HookFileUploaded, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerPostPreModerate(ctx context.Context, userID uint, data *PostModerateHookData, result *ModerationResult) {
|
||||
h.manager.TriggerWithMetadata(ctx, HookPostPreModerate, userID, data, map[string]any{
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerPostModerated(ctx context.Context, userID uint, data *PostModeratedHookData) {
|
||||
h.manager.Trigger(ctx, HookPostModerated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerCommentPreModerate(ctx context.Context, userID uint, data *CommentModerateHookData, result *ModerationResult) {
|
||||
h.manager.TriggerWithMetadata(ctx, HookCommentPreModerate, userID, data, map[string]any{
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerCommentModerated(ctx context.Context, userID uint, data *CommentModeratedHookData) {
|
||||
h.manager.Trigger(ctx, HookCommentModerated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserAvatarPreModerate(ctx context.Context, userID uint, data *UserAvatarModerateHookData, result *ModerationResult) {
|
||||
h.manager.TriggerWithMetadata(ctx, HookUserAvatarPreModerate, userID, data, map[string]any{
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserAvatarModerated(ctx context.Context, userID uint, data *UserAvatarModeratedHookData) {
|
||||
h.manager.Trigger(ctx, HookUserAvatarModerated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserCoverPreModerate(ctx context.Context, userID uint, data *UserCoverModerateHookData, result *ModerationResult) {
|
||||
h.manager.TriggerWithMetadata(ctx, HookUserCoverPreModerate, userID, data, map[string]any{
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserCoverModerated(ctx context.Context, userID uint, data *UserCoverModeratedHookData) {
|
||||
h.manager.Trigger(ctx, HookUserCoverModerated, userID, data)
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserBioPreModerate(ctx context.Context, userID uint, data *UserBioModerateHookData, result *ModerationResult) {
|
||||
h.manager.TriggerWithMetadata(ctx, HookUserBioPreModerate, userID, data, map[string]any{
|
||||
"result": result,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HookTriggerHelper) TriggerUserBioModerated(ctx context.Context, userID uint, data *UserBioModeratedHookData) {
|
||||
h.manager.Trigger(ctx, HookUserBioModerated, userID, data)
|
||||
}
|
||||
|
||||
@@ -111,21 +111,6 @@ func Paginated(c *gin.Context, list any, total int64, page, pageSize int) {
|
||||
})
|
||||
}
|
||||
|
||||
// HandleServiceError 统一处理 Service 错误
|
||||
// 如果 err 是 *apperrors.AppError,返回对应的业务错误码和消息
|
||||
// 如果 err 是其他错误,返回 false(调用方应处理通用错误)
|
||||
// 返回 true 表示错误已处理,false 表示需要调用方继续处理
|
||||
func HandleServiceError(c *gin.Context, err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if se, ok := apperrors.As(err); ok {
|
||||
statusCode := statusCodeFromAppErrorCode(se.Code)
|
||||
ErrorWithStringCode(c, statusCode, se.Code, se.Message)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HandleError 统一处理错误(带默认消息)
|
||||
// 如果 err 是 *apperrors.AppError,返回对应的业务错误码和消息
|
||||
|
||||
@@ -46,13 +46,3 @@ type tencentAPIResponse struct {
|
||||
} `json:"Response"`
|
||||
}
|
||||
|
||||
func ConfigFromAppConfig(cfg *Config) Config {
|
||||
return Config{
|
||||
Enabled: cfg.Enabled,
|
||||
SecretID: cfg.SecretID,
|
||||
SecretKey: cfg.SecretKey,
|
||||
Region: cfg.Region,
|
||||
BizType: cfg.BizType,
|
||||
Timeout: cfg.Timeout,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,3 @@ func GetAvatarOrDefault(username, nickname, avatar string) string {
|
||||
return DefaultAvatarURL
|
||||
}
|
||||
|
||||
func GetAvatarOrDefaultFromInfo(info AvatarInfo) string {
|
||||
return GetAvatarOrDefault(info.Username, info.Nickname, info.Avatar)
|
||||
}
|
||||
|
||||
@@ -61,12 +61,6 @@ var (
|
||||
globalSnowflakeErr error
|
||||
)
|
||||
|
||||
// InitSnowflake 初始化全局雪花算法实例
|
||||
// nodeID: 机器ID,范围0-1023,可以通过环境变量 NODE_ID 配置
|
||||
func InitSnowflake(nodeID int64) error {
|
||||
globalSnowflake, globalSnowflakeErr = NewSnowflake(nodeID)
|
||||
return globalSnowflakeErr
|
||||
}
|
||||
|
||||
// GetSnowflake 获取全局雪花算法实例
|
||||
// 如果未初始化,会自动使用默认配置初始化
|
||||
@@ -191,71 +185,12 @@ func (s *Snowflake) waitNextMillis(timestamp int64) int64 {
|
||||
return now
|
||||
}
|
||||
|
||||
// ParseID 解析雪花算法ID,提取其中的信息
|
||||
// id: 要解析的雪花算法ID
|
||||
// 返回值:包含时间戳、机器ID、序列号的结构体
|
||||
func ParseID(id int64) *IDInfo {
|
||||
// 提取序列号(低12位)
|
||||
sequence := id & maxSequence
|
||||
|
||||
// 提取机器ID(中间10位)
|
||||
nodeID := (id >> nodeIDShift) & maxNodeID
|
||||
|
||||
// 提取时间戳(高41位)
|
||||
timestamp := (id >> timestampShift) + customEpoch
|
||||
|
||||
return &IDInfo{
|
||||
Timestamp: timestamp,
|
||||
NodeID: nodeID,
|
||||
Sequence: sequence,
|
||||
}
|
||||
}
|
||||
|
||||
// currentTimestamp 获取当前时间戳(毫秒)
|
||||
func currentTimestamp() int64 {
|
||||
return time.Now().UnixNano() / 1e6
|
||||
}
|
||||
|
||||
// GetNodeID 获取当前机器ID
|
||||
func (s *Snowflake) GetNodeID() int64 {
|
||||
return s.nodeID
|
||||
}
|
||||
|
||||
// GetCustomEpoch 获取自定义纪元时间
|
||||
func GetCustomEpoch() int64 {
|
||||
return customEpoch
|
||||
}
|
||||
|
||||
// IDToTime 将雪花算法ID转换为生成时间
|
||||
// 这是一个便捷方法,等价于 ParseID(id).Timestamp
|
||||
func IDToTime(id int64) time.Time {
|
||||
info := ParseID(id)
|
||||
return time.Unix(0, info.Timestamp*1e6) // 毫秒转纳秒
|
||||
}
|
||||
|
||||
// ValidateID 验证ID是否为有效的雪花算法ID
|
||||
// 检查时间戳是否在合理范围内
|
||||
func ValidateID(id int64) bool {
|
||||
if id <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
info := ParseID(id)
|
||||
|
||||
// 检查时间戳是否在合理范围内
|
||||
// 不能早于纪元时间,不能晚于当前时间太多(允许1分钟的时钟偏差)
|
||||
now := currentTimestamp()
|
||||
if info.Timestamp < customEpoch || info.Timestamp > now+60000 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查机器ID和序列号是否在有效范围内
|
||||
if info.NodeID < 0 || info.NodeID > maxNodeID {
|
||||
return false
|
||||
}
|
||||
if info.Sequence < 0 || info.Sequence > maxSequence {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package utils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ValidateEmail 验证邮箱
|
||||
@@ -43,39 +42,6 @@ func ValidatePassword(password string) bool {
|
||||
return hasUpper && hasLower && hasDigit
|
||||
}
|
||||
|
||||
// ValidatePasswordWithDetail 验证密码强度并返回详细信息
|
||||
func ValidatePasswordWithDetail(password string) (bool, string) {
|
||||
if len(password) < 8 {
|
||||
return false, "密码长度至少8位"
|
||||
}
|
||||
if len(password) > 50 {
|
||||
return false, "密码长度不能超过50位"
|
||||
}
|
||||
|
||||
var hasUpper, hasLower, hasDigit bool
|
||||
for _, c := range password {
|
||||
switch {
|
||||
case 'A' <= c && c <= 'Z':
|
||||
hasUpper = true
|
||||
case 'a' <= c && c <= 'z':
|
||||
hasLower = true
|
||||
case '0' <= c && c <= '9':
|
||||
hasDigit = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasUpper {
|
||||
return false, "密码必须包含大写字母"
|
||||
}
|
||||
if !hasLower {
|
||||
return false, "密码必须包含小写字母"
|
||||
}
|
||||
if !hasDigit {
|
||||
return false, "密码必须包含数字"
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// ValidatePhone 验证手机号
|
||||
func ValidatePhone(phone string) bool {
|
||||
@@ -84,13 +50,3 @@ func ValidatePhone(phone string) bool {
|
||||
return matched
|
||||
}
|
||||
|
||||
// SanitizeHTML 清理HTML,防止XSS攻击
|
||||
func SanitizeHTML(input string) string {
|
||||
input = strings.ReplaceAll(input, "&", "&")
|
||||
input = strings.ReplaceAll(input, "<", "<")
|
||||
input = strings.ReplaceAll(input, ">", ">")
|
||||
input = strings.ReplaceAll(input, "\"", """)
|
||||
input = strings.ReplaceAll(input, "'", "'")
|
||||
input = strings.ReplaceAll(input, "/", "/")
|
||||
return input
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user