diff --git a/go.mod b/go.mod index b3fd48e8..c00e0e21 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.17.1-0.20231114153341-2ecbdd2739f7 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20231114153253-d2fbf42bb036 + github.com/ProtonMail/go-proton-api v0.4.1-0.20231115131212-0ea2258e7bbf github.com/ProtonMail/gopenpgp/v2 v2.7.4-proton github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index 70076895..2effaff8 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7 h1:+j+Kd/ github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= -github.com/ProtonMail/go-proton-api v0.4.1-0.20231114153253-d2fbf42bb036 h1:nlvJaayeMa3ZSFtPyiO1NoIQnA7MAuXFvv1ZKf6i91E= -github.com/ProtonMail/go-proton-api v0.4.1-0.20231114153253-d2fbf42bb036/go.mod h1:WEXJqj5DSc2YI77SgXdpMY0nk33Qy92Vu2r4tOEazA8= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231115131212-0ea2258e7bbf h1:Zu1VnheQV2ybcrUyGd2wCzAZIwqEgBOpYrg/SKUEvYo= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231115131212-0ea2258e7bbf/go.mod h1:WEXJqj5DSc2YI77SgXdpMY0nk33Qy92Vu2r4tOEazA8= github.com/ProtonMail/go-smtp v0.0.0-20231109081432-2b3d50599865 h1:EP1gnxLL5Z7xBSymE9nSTM27nRYINuvssAtDmG0suD8= github.com/ProtonMail/go-smtp v0.0.0-20231109081432-2b3d50599865/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= diff --git a/internal/bridge/send_test.go b/internal/bridge/send_test.go index dfc44fbc..b17be0af 100644 --- a/internal/bridge/send_test.go +++ b/internal/bridge/send_test.go @@ -33,6 +33,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/bridge" "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/events" + smtpservice "github.com/ProtonMail/proton-bridge/v3/internal/services/smtp" "github.com/emersion/go-imap" "github.com/emersion/go-sasl" "github.com/emersion/go-smtp" @@ -701,3 +702,56 @@ Hello world }) }) } + +func TestBridge_SendAddressDisabled(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { + recipientUserID, _, err := s.CreateUser("recipient", password) + require.NoError(t, err) + + senderUserID, addrID, err := s.CreateUser("sender", password) + require.NoError(t, err) + + require.NoError(t, s.ChangeAddressAllowSend(senderUserID, addrID, false)) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { + smtpWaiter := waitForSMTPServerReady(bridge) + defer smtpWaiter.Done() + + senderUserID, err := bridge.LoginFull(ctx, "sender", password, nil, nil) + require.NoError(t, err) + + _, err = bridge.LoginFull(ctx, "recipient", password, nil, nil) + require.NoError(t, err) + + smtpWaiter.Wait() + + recipientInfo, err := bridge.GetUserInfo(recipientUserID) + require.NoError(t, err) + + senderInfo, err := bridge.GetUserInfo(senderUserID) + require.NoError(t, err) + + // Dial the server. + client, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort()))) + require.NoError(t, err) + defer client.Close() //nolint:errcheck + + // Upgrade to TLS. + require.NoError(t, client.StartTLS(&tls.Config{InsecureSkipVerify: true})) + require.NoError(t, client.Auth(sasl.NewLoginClient( + senderInfo.Addresses[0], + string(senderInfo.BridgePass)), + )) + + // Send the message. + err = client.SendMail( + senderInfo.Addresses[0], + []string{recipientInfo.Addresses[0]}, + strings.NewReader("Subject: Test 1\r\n\r\nHello world!"), + ) + + smtpErr := smtpservice.NewErrCanNotSendOnAddress(senderInfo.Addresses[0]) + require.Equal(t, fmt.Sprintf("Error: %v", smtpErr.Error()), err.Error()) + }) + }) +} diff --git a/internal/services/smtp/errors.go b/internal/services/smtp/errors.go index b0221773..a206b73e 100644 --- a/internal/services/smtp/errors.go +++ b/internal/services/smtp/errors.go @@ -17,9 +17,24 @@ package smtp -import "errors" +import ( + "errors" + "fmt" +) var ErrInvalidRecipient = errors.New("invalid recipient") var ErrInvalidReturnPath = errors.New("invalid return path") var ErrNoSuchUser = errors.New("no such user") var ErrTooManyErrors = errors.New("too many failed requests, please try again later") + +type ErrCanNotSendOnAddress struct { + address string +} + +func NewErrCanNotSendOnAddress(address string) *ErrCanNotSendOnAddress { + return &ErrCanNotSendOnAddress{address: address} +} + +func (e ErrCanNotSendOnAddress) Error() string { + return fmt.Sprintf("can't send on address: %v", e.address) +} diff --git a/internal/services/smtp/smtp.go b/internal/services/smtp/smtp.go index a3acbe32..522e5ce0 100644 --- a/internal/services/smtp/smtp.go +++ b/internal/services/smtp/smtp.go @@ -97,11 +97,16 @@ func (s *Service) smtpSendMail(ctx context.Context, authID string, from string, from = sender fromAddr, err = s.identityState.GetAddr(from) if err != nil { - logrus.WithError(err).Errorf("Failed to get identity from sender address %v", sender) + logrus.WithError(err).Errorf("Failed to get identity for from address %v", sender) return ErrInvalidReturnPath } } + if !fromAddr.Send { + s.log.Errorf("Can't send emails on address: %v", fromAddr.Email) + return &ErrCanNotSendOnAddress{address: fromAddr.Email} + } + // Load the user's mail settings. settings, err := s.client.GetMailSettings(ctx) if err != nil {