From 635e51f32f31ed6adff319353a07186e8738da6e Mon Sep 17 00:00:00 2001 From: Michal Horejsek Date: Fri, 20 Nov 2020 15:44:16 +0100 Subject: [PATCH] Upgrade to latest go-smtp --- go.mod | 3 +- go.sum | 2 + internal/bridge/credits.go | 4 +- internal/imap/server.go | 8 +- internal/importexport/credits.go | 4 +- internal/smtp/backend.go | 12 ++- internal/smtp/server.go | 16 ++-- internal/smtp/user.go | 57 ++++++++++++- test/features/bridge/smtp/auth.feature | 12 +-- test/features/bridge/smtp/init.feature | 83 +++++++++++++++++++ .../bridge/smtp/send/failures.feature | 2 +- test/smtp_actions_test.go | 16 ++-- unreleased.md | 4 + 13 files changed, 192 insertions(+), 31 deletions(-) create mode 100644 test/features/bridge/smtp/init.feature diff --git a/go.mod b/go.mod index 06851867..1eef68f5 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ go 1.13 // They are in a separate require block to highlight this. require ( github.com/docker/docker-credential-helpers v0.6.3 - github.com/emersion/go-smtp v0.0.0-20180712174835-db5eec195e67 github.com/jameskeane/bcrypt v0.0.0-20170924085257-7509ea014998 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 ) @@ -38,6 +37,7 @@ require ( github.com/emersion/go-mbox v1.0.2 github.com/emersion/go-message v0.12.1-0.20200903165315-e1abe21f389a github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 + github.com/emersion/go-smtp v0.14.0 github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5 // indirect github.com/fatih/color v1.9.0 @@ -75,7 +75,6 @@ require ( replace ( github.com/docker/docker-credential-helpers => github.com/ProtonMail/docker-credential-helpers v1.1.0 github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201102134601-418cd74e9474 - github.com/emersion/go-smtp => github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309 github.com/jameskeane/bcrypt => github.com/ProtonMail/bcrypt v0.0.0-20170924085257-7509ea014998 golang.org/x/crypto => github.com/ProtonMail/crypto v0.0.0-20200818122824-ed5d25e28db8 ) diff --git a/go.sum b/go.sum index bd9323b0..6380ce30 100644 --- a/go.sum +++ b/go.sum @@ -94,6 +94,8 @@ github.com/emersion/go-message v0.12.1-0.20200903165315-e1abe21f389a/go.mod h1:k github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k= github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ= github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= +github.com/emersion/go-smtp v0.14.0 h1:RYW203p+EcPjL8Z/ZpT9lZ6iOc8MG1MQzEx1UKEkXlA= +github.com/emersion/go-smtp v0.14.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe h1:40SWqY0zE3qCi6ZrtTf5OUdNm5lDnGnjRSq9GgmeTrg= github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U= github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5 h1:n9qx98xiS5V4x2WIpPC2rr9mUM5ri9r/YhCEKbhCHro= diff --git a/internal/bridge/credits.go b/internal/bridge/credits.go index 5913ab56..2aa22075 100644 --- a/internal/bridge/credits.go +++ b/internal/bridge/credits.go @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . -// Code generated by ./credits.sh at Fri Nov 27 09:08:56 CET 2020. DO NOT EDIT. +// Code generated by ./credits.sh at Fri Nov 27 09:23:06 CET 2020. DO NOT EDIT. package bridge -const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" +const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" diff --git a/internal/imap/server.go b/internal/imap/server.go index 0628d77e..b3351e1a 100644 --- a/internal/imap/server.go +++ b/internal/imap/server.go @@ -126,7 +126,9 @@ func (s *imapServer) ListenAndServe() { // Stops the server. func (s *imapServer) Close() { - _ = s.server.Close() + if err := s.server.Close(); err != nil { + log.WithError(err).Error("Failed to close the connection") + } } func (s *imapServer) monitorDisconnectedUsers() { @@ -139,7 +141,9 @@ func (s *imapServer) monitorDisconnectedUsers() { disconnectUser := func(conn imapserver.Conn) { connUser := conn.Context().User if connUser != nil && strings.EqualFold(connUser.Username(), address) { - _ = conn.Close() + if err := conn.Close(); err != nil { + log.WithError(err).Error("Failed to close the connection") + } } } s.server.ForEachConn(disconnectUser) diff --git a/internal/importexport/credits.go b/internal/importexport/credits.go index 9b29292b..b582f358 100644 --- a/internal/importexport/credits.go +++ b/internal/importexport/credits.go @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . -// Code generated by ./credits.sh at Fri Nov 27 09:08:56 CET 2020. DO NOT EDIT. +// Code generated by ./credits.sh at Fri Nov 27 09:23:06 CET 2020. DO NOT EDIT. package importexport -const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" +const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" diff --git a/internal/smtp/backend.go b/internal/smtp/backend.go index eae408ee..0611285a 100644 --- a/internal/smtp/backend.go +++ b/internal/smtp/backend.go @@ -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 { diff --git a/internal/smtp/server.go b/internal/smtp/server.go index ad06bf5d..f60b8531 100644 --- a/internal/smtp/server.go +++ b/internal/smtp/server.go @@ -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) diff --git a/internal/smtp/user.go b/internal/smtp/user.go index b438256c..5442647c 100644 --- a/internal/smtp/user.go +++ b/internal/smtp/user.go @@ -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. diff --git a/test/features/bridge/smtp/auth.feature b/test/features/bridge/smtp/auth.feature index cfa2bf34..7c4188d3 100644 --- a/test/features/bridge/smtp/auth.feature +++ b/test/features/bridge/smtp/auth.feature @@ -1,29 +1,29 @@ Feature: SMTP auth Scenario: Ask EHLO Given there is connected user "user" - When SMTP client sends EHLO + When SMTP client sends "EHLO example.com" Then SMTP response is "OK" Scenario: Authenticates successfully and EHLO successfully Given there is connected user "user" When SMTP client authenticates "user" Then SMTP response is "OK" - When SMTP client sends EHLO + When SMTP client sends "EHLO example.com" Then SMTP response is "OK" Scenario: Authenticates with bad password Given there is connected user "user" When SMTP client authenticates "user" with bad password - Then SMTP response is "SMTP error: 454 backend/credentials: incorrect password" + Then SMTP response is "SMTP error: 454 4.7.0 backend/credentials: incorrect password" Scenario: Authenticates with disconnected user Given there is disconnected user "user" When SMTP client authenticates "user" - Then SMTP response is "SMTP error: 454 account is logged out, use the app to login again" + Then SMTP response is "SMTP error: 454 4.7.0 account is logged out, use the app to login again" Scenario: Authenticates with no user When SMTP client authenticates with username "user@pm.me" and password "bridgepassword" - Then SMTP response is "SMTP error: 454 user user@pm.me not found" + Then SMTP response is "SMTP error: 454 4.7.0 user user@pm.me not found" Scenario: Authenticates with capital letter Given there is connected user "userAddressWithCapitalLetter" @@ -43,7 +43,7 @@ Feature: SMTP auth Scenario: Authenticates with more addresses - disabled address Given there is connected user "userMoreAddresses" When SMTP client authenticates "userMoreAddresses" with address "disabled" - Then SMTP response is "SMTP error: 454 user .* not found" + Then SMTP response is "SMTP error: 454 4.7.0 user .* not found" @ignore-live Scenario: Authenticates with secondary address of account with disabled primary address diff --git a/test/features/bridge/smtp/init.feature b/test/features/bridge/smtp/init.feature new file mode 100644 index 00000000..606fbe27 --- /dev/null +++ b/test/features/bridge/smtp/init.feature @@ -0,0 +1,83 @@ +Feature: SMTP initiation + Scenario: Empty FROM + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM:<>" + Then SMTP response is "OK" + + Scenario: Send without FROM and TO + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "DATA" + Then SMTP response is "SMTP error: 502 5.5.1 Missing RCPT TO command." + + Scenario: Reset is the same as without FROM and TO + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM:" + Then SMTP response is "OK" + When SMTP client sends "RCPT TO:" + Then SMTP response is "OK" + When SMTP client sends "RSET" + Then SMTP response is "OK" + When SMTP client sends "DATA" + Then SMTP response is "SMTP error: 502 5.5.1 Missing RCPT TO command" + + Scenario: Send without FROM + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "RCPT TO:" + Then SMTP response is "SMTP error: 502 5.5.1 Missing MAIL FROM command." + + Scenario: Send without TO + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM:" + Then SMTP response is "OK" + When SMTP client sends "DATA" + Then SMTP response is "SMTP error: 502 5.5.1 Missing RCPT TO command." + + Scenario: Send with empty FROM + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM:<>" + Then SMTP response is "OK" + When SMTP client sends "RCPT TO:" + Then SMTP response is "OK" + When SMTP client sends "DATA" + Then SMTP response is "OK" + When SMTP client sends "hello\r\n." + Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: missing sender" + + Scenario: Send with empty TO + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM:" + Then SMTP response is "OK" + When SMTP client sends "RCPT TO:<>" + Then SMTP response is "OK" + When SMTP client sends "DATA" + Then SMTP response is "OK" + When SMTP client sends "hello\r\n." + Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: missing recipient" + + Scenario: Allow BODY parameter of MAIL FROM command + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM: BODY=7BIT" + Then SMTP response is "OK" + + Scenario: Allow AUTH parameter of MAIL FROM command + Given there is connected user "user" + When SMTP client authenticates "user" + Then SMTP response is "OK" + When SMTP client sends "MAIL FROM: AUTH=<>" + Then SMTP response is "OK" diff --git a/test/features/bridge/smtp/send/failures.feature b/test/features/bridge/smtp/send/failures.feature index f641dd2d..e4b62421 100644 --- a/test/features/bridge/smtp/send/failures.feature +++ b/test/features/bridge/smtp/send/failures.feature @@ -38,4 +38,4 @@ Feature: SMTP wrong messages """ - Then SMTP response is "SMTP error: 554 Error: transaction failed, blame it on the weather: failed to create new parser: unexpected EOF" + Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: failed to create new parser: unexpected EOF" diff --git a/test/smtp_actions_test.go b/test/smtp_actions_test.go index 0283e404..6aa12e06 100644 --- a/test/smtp_actions_test.go +++ b/test/smtp_actions_test.go @@ -33,10 +33,10 @@ func SMTPActionsAuthFeatureContext(s *godog.Suite) { s.Step(`^SMTP client authenticates with username "([^"]*)" and password "([^"]*)"$`, smtpClientAuthenticatesWithUsernameAndPassword) s.Step(`^SMTP client logs out$`, smtpClientLogsOut) s.Step(`^SMTP client sends message$`, smtpClientSendsMessage) - s.Step(`^SMTP client sends EHLO$`, smtpClientSendsEHLO) s.Step(`^SMTP client "([^"]*)" sends message$`, smtpClientNamedSendsMessage) s.Step(`^SMTP client sends message with bcc "([^"]*)"$`, smtpClientSendsMessageWithBCC) s.Step(`^SMTP client "([^"]*)" sends message with bcc "([^"]*)"$`, smtpClientNamedSendsMessageWithBCC) + s.Step(`^SMTP client sends "([^"]*)"$`, smtpClientSendsCommand) } func smtpClientAuthenticates(bddUserID string) error { @@ -93,12 +93,6 @@ func smtpClientSendsMessage(message *gherkin.DocString) error { return smtpClientNamedSendsMessage("smtp", message) } -func smtpClientSendsEHLO() error { - res := ctx.GetSMTPClient("smtp").SendCommands("EHLO ateist.test") - ctx.SetSMTPLastResponse("smtp", res) - return nil -} - func smtpClientNamedSendsMessage(clientID string, message *gherkin.DocString) error { return smtpClientNamedSendsMessageWithBCC(clientID, "", message) } @@ -112,3 +106,11 @@ func smtpClientNamedSendsMessageWithBCC(clientID, bcc string, message *gherkin.D ctx.SetSMTPLastResponse(clientID, res) return nil } + +func smtpClientSendsCommand(command string) error { + command = strings.ReplaceAll(command, "\\r", "\r") + command = strings.ReplaceAll(command, "\\n", "\n") + res := ctx.GetSMTPClient("smtp").SendCommands(command) + ctx.SetSMTPLastResponse("smtp", res) + return nil +} diff --git a/unreleased.md b/unreleased.md index cacff4f6..a2189f06 100644 --- a/unreleased.md +++ b/unreleased.md @@ -11,3 +11,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ### Removed * GODT-651 Build creates proper binary names. * GODT-148 Allow import (using the Import-Export app) of already encrypted messages as is. +* GODT-202 Update to latest go-smtp. + +### Fixed +* GODT-135 Support parameters in SMTP `FROM MAIL` command, such as `BODY=7BIT`, or empty value `FROM MAIL:<>` used by some clients.