Define Mailer interface and provide SmtpMailer implementation

This commit is contained in:
Piotr Kozimor 2021-08-10 10:41:49 +02:00
parent 503f43abe0
commit 4d1f248a9b
3 changed files with 152 additions and 0 deletions

View file

@ -22,6 +22,16 @@ import (
"github.com/matrix-org/gomatrixserverlib" "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. // UserInternalAPI is the internal API for information about users and devices.
type UserInternalAPI interface { type UserInternalAPI interface {
InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error
@ -365,3 +375,5 @@ type IsSessionValidatedResponse struct {
Validated bool Validated bool
ValidatedAt int ValidatedAt int
} }
type ThreepidSessionType int

102
userapi/mail/mail.go Normal file
View file

@ -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
}

38
userapi/mail/mail_test.go Normal file
View file

@ -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
}