diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/auth/user_form.go | 8 | ||||
-rw-r--r-- | modules/mailer/mail.go | 37 | ||||
-rw-r--r-- | modules/mailer/mailer.go | 71 | ||||
-rw-r--r-- | modules/setting/setting.go | 10 |
4 files changed, 99 insertions, 27 deletions
diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 4dfe2499f1..becd5cbca8 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -97,6 +97,14 @@ func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) b return validate(errs, ctx.Data, f, ctx.Locale) } +type AddEmailForm struct { + Email string `form:"email" binding:"Required;Email;MaxSize(50)"` +} + +func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} + type ChangePasswordForm struct { OldPassword string `form:"old_password" binding:"Required;MinSize(6);MaxSize(255)"` Password string `form:"password" binding:"Required;MinSize(6);MaxSize(255)"` diff --git a/modules/mailer/mail.go b/modules/mailer/mail.go index 6c73e7e58f..ae8ce6531a 100644 --- a/modules/mailer/mail.go +++ b/modules/mailer/mail.go @@ -21,6 +21,7 @@ import ( const ( AUTH_ACTIVE base.TplName = "mail/auth/active" + AUTH_ACTIVATE_EMAIL base.TplName = "mail/auth/activate_email" AUTH_REGISTER_SUCCESS base.TplName = "mail/auth/register_success" AUTH_RESET_PASSWORD base.TplName = "mail/auth/reset_passwd" @@ -30,9 +31,7 @@ const ( // Create New mail message use MailFrom and MailUser func NewMailMessageFrom(To []string, from, subject, body string) Message { - msg := NewHtmlMessage(To, from, subject, body) - msg.User = setting.MailService.User - return msg + return NewHtmlMessage(To, from, subject, body) } // Create New mail message use MailFrom and MailUser @@ -64,6 +63,17 @@ func CreateUserActiveCode(u *models.User, startInf interface{}) string { return code } +// create a time limit code for user active +func CreateUserEmailActivateCode(u *models.User, e *models.EmailAddress, startInf interface{}) string { + minutes := setting.Service.ActiveCodeLives + data := com.ToStr(u.Id) + e.Email + u.LowerName + u.Passwd + u.Rands + code := base.CreateTimeLimitCode(data, minutes, startInf) + + // add tail hex username + code += hex.EncodeToString([]byte(u.LowerName)) + return code +} + // Send user register mail with active code func SendRegisterMail(r macaron.Render, u *models.User) { code := CreateUserActiveCode(u, nil) @@ -103,6 +113,27 @@ func SendActiveMail(r macaron.Render, u *models.User) { SendAsync(&msg) } +// Send email to verify secondary email. +func SendActivateEmail(r macaron.Render, user *models.User, email *models.EmailAddress) { + code := CreateUserEmailActivateCode(user, email, nil) + + subject := "Verify your e-mail address" + + data := GetMailTmplData(user) + data["Code"] = code + data["Email"] = email.Email + body, err := r.HTMLString(string(AUTH_ACTIVATE_EMAIL), data) + if err != nil { + log.Error(4, "mail.SendActiveMail(fail to render): %v", err) + return + } + + msg := NewMailMessage([]string{email.Email}, subject, body) + msg.Info = fmt.Sprintf("UID: %d, send activate email to %s", user.Id, email.Email) + + SendAsync(&msg) +} + // Send reset password email. func SendResetPasswdMail(r macaron.Render, u *models.User) { code := CreateUserActiveCode(u, nil) diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go index 474e1481cd..e2d185d82d 100644 --- a/modules/mailer/mailer.go +++ b/modules/mailer/mailer.go @@ -8,6 +8,7 @@ import ( "crypto/tls" "fmt" "net" + "net/mail" "net/smtp" "strings" @@ -20,7 +21,6 @@ type Message struct { From string Subject string Body string - User string Type string Massive bool Info string @@ -35,8 +35,7 @@ func (m Message) Content() string { } // create mail content - content := "From: \"" + m.From + "\" <" + m.User + - ">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body + content := "From: " + m.From + "\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body return content } @@ -67,29 +66,67 @@ func processMailQueue() { } // sendMail allows mail with self-signed certificates. -func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error { - client, err := smtp.Dial(hostAddressWithPort) +func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte) error { + host, port, err := net.SplitHostPort(settings.Host) if err != nil { return err } - host, _, _ := net.SplitHostPort(hostAddressWithPort) - tlsConn := &tls.Config{ - InsecureSkipVerify: true, + tlsconfig := &tls.Config{ + InsecureSkipVerify: settings.SkipVerify, ServerName: host, } - if err = client.StartTLS(tlsConn); err != nil { + + conn, err := net.Dial("tcp", net.JoinHostPort(host, port)) + if err != nil { return err } + defer conn.Close() + + isSecureConn := false + // Start TLS directly if the port ends with 465 (SMTPS protocol) + if strings.HasSuffix(port, "465") { + conn = tls.Client(conn, tlsconfig) + isSecureConn = true + } - if ok, _ := client.Extension("AUTH"); ok && auth != nil { - if err = client.Auth(auth); err != nil { + client, err := smtp.NewClient(conn, host) + if err != nil { + return err + } + + // If not using SMTPS, alway use STARTTLS if available + hasStartTLS, _ := client.Extension("STARTTLS") + if !isSecureConn && hasStartTLS { + if err = client.StartTLS(tlsconfig); err != nil { return err } } - if err = client.Mail(from); err != nil { + canAuth, options := client.Extension("AUTH") + + if canAuth && len(settings.User) > 0 { + var auth smtp.Auth + + if strings.Contains(options, "CRAM-MD5") { + auth = smtp.CRAMMD5Auth(settings.User, settings.Passwd) + } else if strings.Contains(options, "PLAIN") { + auth = smtp.PlainAuth("", settings.User, settings.Passwd, host) + } + + if auth != nil { + if err = client.Auth(auth); err != nil { + return err + } + } + } + + if fromAddress, err := mail.ParseAddress(settings.From); err != nil { return err + } else { + if err = client.Mail(fromAddress.Address); err != nil { + return err + } } for _, rec := range recipients { @@ -116,7 +153,6 @@ func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipient // Direct Send mail message func Send(msg *Message) (int, error) { log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) - host := strings.Split(setting.MailService.Host, ":") // get message body content := msg.Content() @@ -127,17 +163,12 @@ func Send(msg *Message) (int, error) { return 0, fmt.Errorf("empty email body") } - var auth smtp.Auth - if len(setting.MailService.Passwd) > 0 { - auth = smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0]) - } - if msg.Massive { // send mail to multiple emails one by one num := 0 for _, to := range msg.To { body := []byte("To: " + to + "\r\n" + content) - err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) + err := sendMail(setting.MailService, []string{to}, body) if err != nil { return num, err } @@ -148,7 +179,7 @@ func Send(msg *Message) (int, error) { body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) // send to multiple emails in one message - err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body) + err := sendMail(setting.MailService, msg.To, body) if err != nil { return 0, err } else { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7765a859ab..76e1ab7696 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -437,6 +437,7 @@ type Mailer struct { Host string From string User, Passwd string + SkipVerify bool } type OauthInfo struct { @@ -463,10 +464,11 @@ func newMailService() { } MailService = &Mailer{ - Name: Cfg.MustValue("mailer", "NAME", AppName), - Host: Cfg.MustValue("mailer", "HOST"), - User: Cfg.MustValue("mailer", "USER"), - Passwd: Cfg.MustValue("mailer", "PASSWD"), + Name: Cfg.MustValue("mailer", "NAME", AppName), + Host: Cfg.MustValue("mailer", "HOST"), + User: Cfg.MustValue("mailer", "USER"), + Passwd: Cfg.MustValue("mailer", "PASSWD"), + SkipVerify: Cfg.MustBool("mailer", "SKIP_VERIFY", false), } MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User) log.Info("Mail Service Enabled") |