From 4d1f248a9b263728663218a6f6473a9a03cb6e6a Mon Sep 17 00:00:00 2001 From: Piotr Kozimor Date: Tue, 10 Aug 2021 10:41:49 +0200 Subject: [PATCH] Define Mailer interface and provide SmtpMailer implementation --- userapi/api/api.go | 12 +++++ userapi/mail/mail.go | 102 ++++++++++++++++++++++++++++++++++++++ userapi/mail/mail_test.go | 38 ++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 userapi/mail/mail.go create mode 100644 userapi/mail/mail_test.go diff --git a/userapi/api/api.go b/userapi/api/api.go index e976f0139..ee58ac007 100644 --- a/userapi/api/api.go +++ b/userapi/api/api.go @@ -22,6 +22,16 @@ import ( "github.com/matrix-org/gomatrixserverlib" ) +const ( + // Verification is used in + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-email-requesttoken + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-register-email-requesttoken + Verification ThreepidSessionType = iota + // Password is used in + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-password-email-requesttoken + Password +) + // UserInternalAPI is the internal API for information about users and devices. type UserInternalAPI interface { InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error @@ -365,3 +375,5 @@ type IsSessionValidatedResponse struct { Validated bool ValidatedAt int } + +type ThreepidSessionType int diff --git a/userapi/mail/mail.go b/userapi/mail/mail.go new file mode 100644 index 000000000..33cc84f69 --- /dev/null +++ b/userapi/mail/mail.go @@ -0,0 +1,102 @@ +package mail + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/smtp" + "text/template" + "time" + + "github.com/matrix-org/dendrite/internal" + "github.com/matrix-org/dendrite/setup/config" + "github.com/matrix-org/dendrite/userapi/api" +) + +const ( + messageIdByteLength = 48 +) + +type Mailer interface { + // Send is used in + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-email-requesttoken + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-register-email-requesttoken + // - https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-password-email-requesttoken + Send(*Mail, api.ThreepidSessionType) error +} +type SmtpMailer struct { + conf config.EmailConf + templates map[api.ThreepidSessionType]*template.Template +} + +type Mail struct { + To string + Link string + Token string + Extra []string +} + +type Substitutions struct { + *Mail + Date string + MessageId string +} + +func (m *SmtpMailer) Send(mail *Mail, t api.ThreepidSessionType) error { + return m.send(mail, m.templates[t]) +} + +func (m *SmtpMailer) send(mail *Mail, t *template.Template) error { + messageId, err := internal.GenerateBlob(messageIdByteLength) + if err != nil { + return err + } + s := Substitutions{ + Mail: mail, + Date: time.Now().Format(time.RFC1123Z), + MessageId: messageId, + } + b := bytes.Buffer{} + err = t.Execute(&b, s) + if err != nil { + return err + } + return smtp.SendMail( + m.conf.Smtp.Host, + smtp.PlainAuth( + "", + m.conf.Smtp.User, + m.conf.Smtp.Password, + m.conf.Smtp.Host, + ), + m.conf.From, + []string{ + mail.To, + }, + b.Bytes(), + ) +} + +func NewMailer(c *config.UserAPI) (Mailer, error) { + templateRaw, err := ioutil.ReadFile(fmt.Sprintf("%s/verification.eml", c.Email.TemplatesPath)) + if err != nil { + return nil, err + } + verificationT, err := template.New("verification").Parse(string(templateRaw)) + if err != nil { + return nil, err + } + templateRaw, err = ioutil.ReadFile(fmt.Sprintf("%s/password.eml", c.Email.TemplatesPath)) + if err != nil { + return nil, err + } + passwordT, err := template.New("password").Parse(string(templateRaw)) + return &SmtpMailer{ + conf: c.Email, + templates: map[api.ThreepidSessionType]*template.Template{ + api.Password: passwordT, + api.Verification: verificationT, + }, + }, err + +} diff --git a/userapi/mail/mail_test.go b/userapi/mail/mail_test.go new file mode 100644 index 000000000..7a4d97abf --- /dev/null +++ b/userapi/mail/mail_test.go @@ -0,0 +1,38 @@ +package mail + +import ( + "testing" + + "github.com/matrix-org/dendrite/setup/config" + "github.com/matrix-org/dendrite/userapi/api" + "github.com/matryer/is" +) + +func TestSendVerification(t *testing.T) { + is := is.New(t) + dut := mustNewMailer(is) + err := dut.Send( + &Mail{ + To: "kevil11378@186site.com", + Link: "my", + Token: "foo", + Extra: []string{ + "bar", + }, + }, api.Verification) + is.NoErr(err) +} + +func mustNewMailer(is *is.I) Mailer { + mailer, err := NewMailer(&config.UserAPI{ + Email: config.EmailConf{ + TemplatesPath: "../../res/default", + From: "test@matrix.com", + Smtp: config.Smtp{ + Host: "localhost:25", + }, + }, + }) + is.NoErr(err) + return mailer +}