diff --git a/internal/email/email.go b/internal/email/email.go index 96301cc..d760689 100644 --- a/internal/email/email.go +++ b/internal/email/email.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/url" + "strings" "text/template" "time" @@ -119,8 +120,9 @@ type captchaPayload struct { } type retrievePasswordPayload struct { - Host string - Url string + Captcha string + Host string + Url string Year int } @@ -293,16 +295,22 @@ func SendRetrievePasswordCaptchaEmail(userID, email, host string) error { if userID == "" { return errors.New("user id is empty") } - if email == "" { return errors.New("email is empty") } + if host == "" { + return errors.New("host is empty") + } + if !strings.HasPrefix(host, "http://") && !strings.HasPrefix(host, "https://") { + log.Errorf("host: %s must start with http:// or https://", host) + return errors.New("get host error") + } u, err := url.Parse(host) if err != nil { return err } - u.Path = `/web/auth/reset` + u.Path = `web/auth/reset` pool, err := getSmtpPool() if err != nil { @@ -318,16 +326,17 @@ func SendRetrievePasswordCaptchaEmail(userID, email, host string) error { entry.SetExpiration(time.Now().Add(time.Minute * 5)) } - q := u.Query() + q := url.Values{} q.Set("captcha", entry.Value()) q.Set("email", email) u.RawQuery = q.Encode() out := bytes.NewBuffer(nil) err = retrievePasswordTemplate.Execute(out, retrievePasswordPayload{ - Host: host, - Url: u.String(), - Year: time.Now().Year(), + Captcha: entry.Value(), + Host: host, + Url: u.String(), + Year: time.Now().Year(), }) if err != nil { return err diff --git a/internal/email/template/retrieve_password.mjml b/internal/email/template/retrieve_password.mjml index 4cabe7e..1196c5d 100644 --- a/internal/email/template/retrieve_password.mjml +++ b/internal/email/template/retrieve_password.mjml @@ -22,8 +22,10 @@ - 忘记密码: - Hi! 你在 SyncTV 中提交了重置密码的请求,请前往修改: + 忘记密码? + Hi! 你在 SyncTV 中提交了重置密码的请求 + 你的验证码为: + {{ .Captcha }} 前往站点修改 该验证码有效期为5分钟,如果您并没有访问过我们的网站,或没有进行上述操作,请忽略这封邮件。 diff --git a/server/handlers/init.go b/server/handlers/init.go index 9cc1300..5fda669 100644 --- a/server/handlers/init.go +++ b/server/handlers/init.go @@ -1,6 +1,10 @@ package handlers import ( + "errors" + "net/url" + "strings" + "github.com/gin-gonic/gin" "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/settings" @@ -17,6 +21,16 @@ var ( "host", "", model.SettingGroupServer, + settings.WithValidatorString(func(s string) error { + if s == "" { + return nil + } + if !strings.HasPrefix(s, "http://") && !strings.HasPrefix(s, "https://") { + return errors.New("host must start with http:// or https://") + } + _, err := url.Parse(s) + return err + }), ) ) diff --git a/server/handlers/user.go b/server/handlers/user.go index 75522a8..64abbef 100644 --- a/server/handlers/user.go +++ b/server/handlers/user.go @@ -3,6 +3,7 @@ package handlers import ( "math/rand" "net/http" + "net/url" "strings" "time" @@ -505,7 +506,10 @@ func SendUserRetrievePasswordEmailCaptcha(ctx *gin.Context) { host := HOST.Get() if host == "" { - host = ctx.Request.Host + host = (&url.URL{ + Scheme: "http", + Host: ctx.Request.Host, + }).String() } if host == "" { log.Error("failed to get host on send retrieve password email")