Upgrade to latest go-smtp

This commit is contained in:
Michal Horejsek
2020-11-20 15:44:16 +01:00
parent ca962ce5ad
commit 635e51f32f
13 changed files with 192 additions and 31 deletions

View File

@ -27,6 +27,7 @@ import (
"github.com/ProtonMail/proton-bridge/pkg/confirmer"
"github.com/ProtonMail/proton-bridge/pkg/listener"
goSMTPBackend "github.com/emersion/go-smtp"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -70,7 +71,7 @@ func newSMTPBackend(
}
// Login authenticates a user.
func (sb *smtpBackend) Login(username, password string) (goSMTPBackend.User, error) {
func (sb *smtpBackend) Login(_ *goSMTPBackend.ConnectionState, username, password string) (goSMTPBackend.Session, error) {
// Called from go-smtp in goroutines - we need to handle panics for each function.
defer sb.panicHandler.HandlePanic()
username = strings.ToLower(username)
@ -97,7 +98,14 @@ func (sb *smtpBackend) Login(username, password string) (goSMTPBackend.User, err
if user.IsCombinedAddressMode() {
addressID = ""
}
return newSMTPUser(sb.panicHandler, sb.eventListener, sb, user, addressID)
return newSMTPUser(sb.panicHandler, sb.eventListener, sb, user, username, addressID)
}
func (sb *smtpBackend) AnonymousLogin(_ *goSMTPBackend.ConnectionState) (goSMTPBackend.Session, error) {
// Called from go-smtp in goroutines - we need to handle panics for each function.
defer sb.panicHandler.HandlePanic()
return nil, errors.New("anonymous login not supported")
}
func (sb *smtpBackend) shouldReportOutgoingNoEnc() bool {

View File

@ -51,12 +51,12 @@ func NewSMTPServer(debug bool, port int, useSSL bool, tls *tls.Config, smtpBacke
s.EnableAuth(sasl.Login, func(conn *goSMTP.Conn) sasl.Server {
return sasl.NewLoginServer(func(address, password string) error {
user, err := conn.Server().Backend.Login(address, password)
user, err := conn.Server().Backend.Login(nil, address, password)
if err != nil {
return err
}
conn.SetUser(user)
conn.SetSession(user)
return nil
})
})
@ -85,14 +85,16 @@ func (s *smtpServer) ListenAndServe() {
l.Error("SMTP failed: ", err)
return
}
defer s.server.Close()
defer s.server.Close() //nolint[errcheck]
l.Info("SMTP server stopped")
}
// Stops the server.
func (s *smtpServer) Close() {
s.server.Close()
if err := s.server.Close(); err != nil {
log.WithError(err).Error("Failed to close the connection")
}
}
func (s *smtpServer) monitorDisconnectedUsers() {
@ -102,9 +104,11 @@ func (s *smtpServer) monitorDisconnectedUsers() {
for address := range ch {
log.Info("Disconnecting all open SMTP connections for ", address)
disconnectUser := func(conn *goSMTP.Conn) {
connUser := conn.User()
connUser := conn.Session()
if connUser != nil {
_ = conn.Close()
if err := conn.Close(); err != nil {
log.WithError(err).Error("Failed to close the connection")
}
}
}
s.server.ForEachConn(disconnectUser)

View File

@ -44,7 +44,11 @@ type smtpUser struct {
backend *smtpBackend
user bridgeUser
storeUser storeUserProvider
username string
addressID string
from string
to []string
}
// newSMTPUser returns struct implementing go-smtp/session interface.
@ -53,8 +57,9 @@ func newSMTPUser(
eventListener listener.Listener,
smtpBackend *smtpBackend,
user bridgeUser,
username string,
addressID string,
) (goSMTPBackend.User, error) {
) (goSMTPBackend.Session, error) {
storeUser := user.GetStore()
if storeUser == nil {
return nil, errors.New("user database is not initialized")
@ -66,6 +71,7 @@ func newSMTPUser(
backend: smtpBackend,
user: user,
storeUser: storeUser,
username: username,
addressID: addressID,
}, nil
}
@ -145,6 +151,55 @@ func (su *smtpUser) getAPIKeyData(recipient string) (apiKeys []pmapi.PublicKey,
return su.client().GetPublicKeysForEmail(recipient)
}
// Discard currently processed message.
func (su *smtpUser) Reset() {
log.Trace("Resetting the session")
su.from = ""
su.to = []string{}
}
// Set return path for currently processed message.
func (su *smtpUser) Mail(from string, opts goSMTPBackend.MailOptions) error {
log.WithField("from", from).WithField("opts", opts).Trace("Setting mail from")
// REQUIRETLS and SMTPUTF8 have to be announced to be used by client.
// Bridge does not use those extensions so this should not happen.
if opts.RequireTLS {
return errors.New("REQUIRETLS extension is not supported")
}
if opts.UTF8 {
return errors.New("SMTPUTF8 extension is not supported")
}
if opts.Auth != nil && *opts.Auth != "" && *opts.Auth != su.username {
return errors.New("changing identity is not supported")
}
su.from = from
return nil
}
// Add recipient for currently processed message.
func (su *smtpUser) Rcpt(to string) error {
log.WithField("to", to).Trace("Adding recipient")
if to != "" {
su.to = append(su.to, to)
}
return nil
}
// Set currently processed message contents and send it.
func (su *smtpUser) Data(r io.Reader) error {
log.Trace("Sending the message")
if su.from == "" {
return errors.New("missing sender")
}
if len(su.to) == 0 {
return errors.New("missing recipient")
}
return su.Send(su.from, su.to, r)
}
// Send sends an email from the given address to the given addresses with the given body.
func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err error) { //nolint[funlen]
// Called from go-smtp in goroutines - we need to handle panics for each function.