From e1517d42437008c468f93ae719a54cbc66a2fd39 Mon Sep 17 00:00:00 2001 From: xmdhs Date: Sat, 25 Nov 2023 16:36:38 +0800 Subject: [PATCH] =?UTF-8?q?=E9=82=AE=E7=AE=B1=E6=AD=A3=E5=88=99=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.go | 8 ++++++- frontend/src/apis/model.ts | 2 ++ frontend/src/views/SendEmail.tsx | 5 ++++ handle/user.go | 39 ++++++++++++++++++++++++++++++++ model/model.go | 2 ++ service/user.go | 15 ------------ service/web.go | 2 ++ 7 files changed, 57 insertions(+), 16 deletions(-) diff --git a/config/config.go b/config/config.go index d685d38..b55aee1 100644 --- a/config/config.go +++ b/config/config.go @@ -45,12 +45,14 @@ type EmailConfig struct { Enable bool `toml:"enable" comment:"注册验证邮件,且允许使用邮箱找回账号"` Smtp []SmtpUser `toml:"smtp"` AllowDomain []string `toml:"allow_domain" comment:"允许用于注册的邮箱域名,留空则允许全部"` + EmailReg string `toml:"email_reg" comment:"邮箱正则,留空则不处理,如 ^[0-9]+@qq.com$|^[^+\\.A-Z]+@gmail.com$"` + EmailRegMsg string `toml:"email_reg_msg" comment:"不满足要求时的提示信息"` } type SmtpUser struct { Host string `toml:"host"` Port int `toml:"port"` - SSL bool `toml:"SSL"` + SSL bool `toml:"SSL" comment:"启用 ssl"` Name string `toml:"name"` Pass string `toml:"password"` } @@ -82,5 +84,9 @@ func Default() Config { WebBaseUrl: "", ServerName: "没有设置名字", Captcha: Captcha{}, + Email: EmailConfig{ + Smtp: []SmtpUser{}, + AllowDomain: []string{}, + }, } } diff --git a/frontend/src/apis/model.ts b/frontend/src/apis/model.ts index dffb170..5dc0828 100644 --- a/frontend/src/apis/model.ts +++ b/frontend/src/apis/model.ts @@ -42,6 +42,8 @@ export interface ApiConfig { serverName: string NeedEmail: boolean AllowDomain: string[] + EmailReg: string + EmailRegMsg: string } export interface UserInfo { diff --git a/frontend/src/views/SendEmail.tsx b/frontend/src/views/SendEmail.tsx index 7201c54..fbe3910 100644 --- a/frontend/src/views/SendEmail.tsx +++ b/frontend/src/views/SendEmail.tsx @@ -77,6 +77,11 @@ export default function SendEmail({ title, anyEmail = false, sendService }: { ti setHelperText("邮箱格式错误") return } + if (!anyEmail && server.data?.EmailReg && server.data?.EmailReg != "" + && !new RegExp(server.data?.EmailReg).test(sendEmail)) { + setHelperText(server.data?.EmailRegMsg ?? "邮箱不满足正则要求") + return + } if (server.data?.captcha.type != "" && captchaToken == "") { return diff --git a/handle/user.go b/handle/user.go index 9394515..b0af80e 100644 --- a/handle/user.go +++ b/handle/user.go @@ -3,11 +3,15 @@ package handle import ( "bytes" "context" + "errors" "fmt" "image/png" "io" "log/slog" "net/http" + "regexp" + "strings" + "sync" "github.com/go-chi/chi/v5" "github.com/go-playground/validator/v10" @@ -25,10 +29,16 @@ type UserHandel struct { logger *slog.Logger textureService *service.TextureService config config.Config + + emailReg func() (*regexp.Regexp, error) } func NewUserHandel(handleError *handelerror.HandleError, validate *validator.Validate, userService *service.UserService, logger *slog.Logger, textureService *service.TextureService, config config.Config) *UserHandel { + emailReg := sync.OnceValues[*regexp.Regexp, error](func() (*regexp.Regexp, error) { + return regexp.Compile(config.Email.EmailReg) + }) + return &UserHandel{ handleError: handleError, validate: validate, @@ -36,6 +46,8 @@ func NewUserHandel(handleError *handelerror.HandleError, validate *validator.Val logger: logger, textureService: textureService, config: config, + + emailReg: emailReg, } } @@ -227,6 +239,8 @@ func (h *UserHandel) NeedEnableEmail(handle http.Handler) http.Handler { }) } +var ErrNotAllowDomain = errors.New("不在允许域名列表内") + func (h *UserHandel) SendRegEmail() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -235,6 +249,31 @@ func (h *UserHandel) SendRegEmail() http.HandlerFunc { return } + if len(h.config.Email.AllowDomain) != 0 { + allow := false + for _, v := range h.config.Email.AllowDomain { + if strings.HasSuffix(c.Email, v) { + allow = true + break + } + } + if !allow { + h.handleError.Error(ctx, w, "不在允许邮箱域名内", model.ErrInput, 400, slog.LevelDebug) + return + } + } + if h.config.Email.EmailReg != "" { + r, err := h.emailReg() + if err != nil { + h.handleError.Error(ctx, w, "正则错误", model.ErrUnknown, 500, slog.LevelError) + return + } + if !r.MatchString(c.Email) { + h.handleError.Error(ctx, w, "邮箱不符合正则要求", model.ErrInput, 400, slog.LevelDebug) + return + } + } + err := h.userService.SendRegEmail(ctx, c.Email, c.CaptchaToken, r.Host, ip) if err != nil { h.handleError.Service(ctx, w, err) diff --git a/model/model.go b/model/model.go index bac1245..a430b85 100644 --- a/model/model.go +++ b/model/model.go @@ -65,6 +65,8 @@ type Config struct { ServerName string `json:"serverName"` NeedEmail bool AllowDomain []string + EmailReg string + EmailRegMsg string } type EditUser struct { diff --git a/service/user.go b/service/user.go index 3c8c4c3..247439e 100644 --- a/service/user.go +++ b/service/user.go @@ -238,22 +238,7 @@ func (w *UserService) ChangeName(ctx context.Context, newName string, t *model.T return nil } -var ErrNotAllowDomain = errors.New("不在允许域名列表内") - func (w *UserService) SendRegEmail(ctx context.Context, email, CaptchaToken, host, ip string) error { - if len(w.config.Email.AllowDomain) != 0 { - allow := false - for _, v := range w.config.Email.AllowDomain { - if strings.HasSuffix(email, v) { - allow = true - break - } - } - if !allow { - return fmt.Errorf("SendRegEmail: %w", ErrNotAllowDomain) - } - } - err := w.captchaService.VerifyCaptcha(ctx, CaptchaToken, ip) if err != nil { return fmt.Errorf("SendRegEmail: %w", err) diff --git a/service/web.go b/service/web.go index cfdaf29..0e81a88 100644 --- a/service/web.go +++ b/service/web.go @@ -37,5 +37,7 @@ func (w *WebService) GetConfig(ctx context.Context) model.Config { AllowChangeName: !w.config.OfflineUUID, NeedEmail: w.config.Email.Enable, AllowDomain: w.config.Email.AllowDomain, + EmailReg: w.config.Email.EmailReg, + EmailRegMsg: w.config.Email.EmailRegMsg, } }