mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-15 14:56:42 +00:00
feat(GODT-2799): SMTP service interacts directly with Server Manager
Bridge no longer needs to manually add and remove accounts from the service.
This commit is contained in:
@ -22,23 +22,12 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/identifier"
|
"github.com/ProtonMail/proton-bridge/v3/internal/identifier"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/user"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bridge *Bridge) restartSMTP(ctx context.Context) error {
|
func (bridge *Bridge) restartSMTP(ctx context.Context) error {
|
||||||
return bridge.serverManager.RestartSMTP(ctx)
|
return bridge.serverManager.RestartSMTP(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addSMTPUser connects the given user to the smtp server.
|
|
||||||
func (bridge *Bridge) addSMTPUser(ctx context.Context, user *user.User) error {
|
|
||||||
return bridge.serverManager.AddSMTPAccount(ctx, user.GetSMTPService())
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeSMTPUser disconnects the given user from the smtp server.
|
|
||||||
func (bridge *Bridge) removeSMTPUser(ctx context.Context, user *user.User) error {
|
|
||||||
return bridge.serverManager.RemoveSMTPAccount(ctx, user.GetSMTPService())
|
|
||||||
}
|
|
||||||
|
|
||||||
type bridgeSMTPSettings struct {
|
type bridgeSMTPSettings struct {
|
||||||
b *Bridge
|
b *Bridge
|
||||||
}
|
}
|
||||||
|
|||||||
@ -522,16 +522,13 @@ func (bridge *Bridge) addUserWithVault(
|
|||||||
statsPath,
|
statsPath,
|
||||||
bridge,
|
bridge,
|
||||||
bridge.serverManager,
|
bridge.serverManager,
|
||||||
|
bridge.serverManager,
|
||||||
&bridgeEventSubscription{b: bridge},
|
&bridgeEventSubscription{b: bridge},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create user: %w", err)
|
return fmt.Errorf("failed to create user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bridge.addSMTPUser(ctx, user); err != nil {
|
|
||||||
return fmt.Errorf("failed to add SMTP user: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle events coming from the user before forwarding them to the bridge.
|
// Handle events coming from the user before forwarding them to the bridge.
|
||||||
// For example, if the user's addresses change, we need to update them in gluon.
|
// For example, if the user's addresses change, we need to update them in gluon.
|
||||||
bridge.tasks.Once(func(ctx context.Context) {
|
bridge.tasks.Once(func(ctx context.Context) {
|
||||||
@ -593,10 +590,6 @@ func (bridge *Bridge) logoutUser(ctx context.Context, user *user.User, withAPI,
|
|||||||
"withData": withData,
|
"withData": withData,
|
||||||
}).Debug("Logging out user")
|
}).Debug("Logging out user")
|
||||||
|
|
||||||
if err := bridge.removeSMTPUser(ctx, user); err != nil {
|
|
||||||
logrus.WithError(err).Error("Failed to remove SMTP user")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := user.Logout(ctx, withAPI); err != nil {
|
if err := user.Logout(ctx, withAPI); err != nil {
|
||||||
logrus.WithError(err).Error("Failed to logout user")
|
logrus.WithError(err).Error("Failed to logout user")
|
||||||
}
|
}
|
||||||
|
|||||||
41
internal/services/smtp/server_manager.go
Normal file
41
internal/services/smtp/server_manager.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2023 Proton AG
|
||||||
|
//
|
||||||
|
// This file is part of Proton Mail Bridge.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package smtp
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type ServerManager interface {
|
||||||
|
AddSMTPAccount(ctx context.Context, service *Service) error
|
||||||
|
RemoveSMTPAccount(ctx context.Context, service *Service) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullServerManager struct{}
|
||||||
|
|
||||||
|
func NewNullServerManager() *NullServerManager {
|
||||||
|
return &NullServerManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NullServerManager) AddSMTPAccount(_ context.Context, _ *Service) error {
|
||||||
|
// Does nothing.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NullServerManager) RemoveSMTPAccount(_ context.Context, _ *Service) error {
|
||||||
|
// Does nothing.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -62,7 +62,8 @@ type Service struct {
|
|||||||
addressSubscriber *userevents.AddressChanneledSubscriber
|
addressSubscriber *userevents.AddressChanneledSubscriber
|
||||||
userSubscriber *userevents.UserChanneledSubscriber
|
userSubscriber *userevents.UserChanneledSubscriber
|
||||||
|
|
||||||
addressMode usertypes.AddressMode
|
addressMode usertypes.AddressMode
|
||||||
|
serverManager ServerManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(
|
func NewService(
|
||||||
@ -77,6 +78,7 @@ func NewService(
|
|||||||
eventService userevents.Subscribable,
|
eventService userevents.Subscribable,
|
||||||
mode usertypes.AddressMode,
|
mode usertypes.AddressMode,
|
||||||
identityState *useridentity.State,
|
identityState *useridentity.State,
|
||||||
|
serverManager ServerManager,
|
||||||
) *Service {
|
) *Service {
|
||||||
subscriberName := fmt.Sprintf("smpt-%v", userID)
|
subscriberName := fmt.Sprintf("smpt-%v", userID)
|
||||||
|
|
||||||
@ -102,7 +104,8 @@ func NewService(
|
|||||||
userSubscriber: userevents.NewUserSubscriber(subscriberName),
|
userSubscriber: userevents.NewUserSubscriber(subscriberName),
|
||||||
addressSubscriber: userevents.NewAddressSubscriber(subscriberName),
|
addressSubscriber: userevents.NewAddressSubscriber(subscriberName),
|
||||||
|
|
||||||
addressMode: mode,
|
addressMode: mode,
|
||||||
|
serverManager: serverManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +132,12 @@ func (s *Service) Resync(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) OnLogout(ctx context.Context) error {
|
||||||
|
_, err := s.cpc.Send(ctx, &onLogoutReq{})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) checkAuth(ctx context.Context, email string, password []byte) (string, error) {
|
func (s *Service) checkAuth(ctx context.Context, email string, password []byte) (string, error) {
|
||||||
return cpc.SendTyped[string](ctx, s.cpc, &checkAuthReq{
|
return cpc.SendTyped[string](ctx, s.cpc, &checkAuthReq{
|
||||||
email: email,
|
email: email,
|
||||||
@ -136,8 +145,13 @@ func (s *Service) checkAuth(ctx context.Context, email string, password []byte)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Start(ctx context.Context, group *orderedtasks.OrderedCancelGroup) {
|
func (s *Service) Start(ctx context.Context, group *orderedtasks.OrderedCancelGroup) error {
|
||||||
s.log.Debug("Starting service")
|
s.log.Debug("Starting service")
|
||||||
|
|
||||||
|
if err := s.serverManager.AddSMTPAccount(ctx, s); err != nil {
|
||||||
|
return fmt.Errorf("failed to add SMTP account to server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
group.Go(ctx, s.userID, "smtp-service", func(ctx context.Context) {
|
group.Go(ctx, s.userID, "smtp-service", func(ctx context.Context) {
|
||||||
logging.DoAnnotated(ctx, func(ctx context.Context) {
|
logging.DoAnnotated(ctx, func(ctx context.Context) {
|
||||||
s.run(ctx)
|
s.run(ctx)
|
||||||
@ -146,6 +160,8 @@ func (s *Service) Start(ctx context.Context, group *orderedtasks.OrderedCancelGr
|
|||||||
"service": "smtp",
|
"service": "smtp",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UserID() string {
|
func (s *Service) UserID() string {
|
||||||
@ -196,6 +212,10 @@ func (s *Service) run(ctx context.Context) {
|
|||||||
err := s.identityState.OnRefreshEvent(ctx)
|
err := s.identityState.OnRefreshEvent(ctx)
|
||||||
request.Reply(ctx, nil, err)
|
request.Reply(ctx, nil, err)
|
||||||
|
|
||||||
|
case *onLogoutReq:
|
||||||
|
err := s.serverManager.RemoveSMTPAccount(ctx, s)
|
||||||
|
request.Reply(ctx, nil, err)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
s.log.Error("Received unknown request")
|
s.log.Error("Received unknown request")
|
||||||
}
|
}
|
||||||
@ -262,3 +282,5 @@ type checkAuthReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type resyncReq struct{}
|
type resyncReq struct{}
|
||||||
|
|
||||||
|
type onLogoutReq struct{}
|
||||||
|
|||||||
@ -97,7 +97,8 @@ func New(
|
|||||||
maxSyncMemory uint64,
|
maxSyncMemory uint64,
|
||||||
statsDir string,
|
statsDir string,
|
||||||
telemetryManager telemetry.Availability,
|
telemetryManager telemetry.Availability,
|
||||||
serverManager imapservice.IMAPServerManager,
|
imapServerManager imapservice.IMAPServerManager,
|
||||||
|
smtpServerManager smtp.ServerManager,
|
||||||
eventSubscription events.Subscription,
|
eventSubscription events.Subscription,
|
||||||
) (*User, error) {
|
) (*User, error) {
|
||||||
user, err := newImpl(
|
user, err := newImpl(
|
||||||
@ -111,7 +112,8 @@ func New(
|
|||||||
maxSyncMemory,
|
maxSyncMemory,
|
||||||
statsDir,
|
statsDir,
|
||||||
telemetryManager,
|
telemetryManager,
|
||||||
serverManager,
|
imapServerManager,
|
||||||
|
smtpServerManager,
|
||||||
eventSubscription,
|
eventSubscription,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -138,7 +140,8 @@ func newImpl(
|
|||||||
maxSyncMemory uint64,
|
maxSyncMemory uint64,
|
||||||
statsDir string,
|
statsDir string,
|
||||||
telemetryManager telemetry.Availability,
|
telemetryManager telemetry.Availability,
|
||||||
serverManager imapservice.IMAPServerManager,
|
imapServerManager imapservice.IMAPServerManager,
|
||||||
|
smtpServerManager smtp.ServerManager,
|
||||||
eventSubscription events.Subscription,
|
eventSubscription events.Subscription,
|
||||||
) (*User, error) {
|
) (*User, error) {
|
||||||
logrus.WithField("userID", apiUser.ID).Info("Creating new user")
|
logrus.WithField("userID", apiUser.ID).Info("Creating new user")
|
||||||
@ -223,6 +226,7 @@ func newImpl(
|
|||||||
user.eventService,
|
user.eventService,
|
||||||
addressMode,
|
addressMode,
|
||||||
identityState.Clone(),
|
identityState.Clone(),
|
||||||
|
smtpServerManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
user.imapService = imapservice.NewService(
|
user.imapService = imapservice.NewService(
|
||||||
@ -231,7 +235,7 @@ func newImpl(
|
|||||||
user,
|
user,
|
||||||
encVault,
|
encVault,
|
||||||
user.eventService,
|
user.eventService,
|
||||||
serverManager,
|
imapServerManager,
|
||||||
user,
|
user,
|
||||||
encVault,
|
encVault,
|
||||||
encVault,
|
encVault,
|
||||||
@ -282,7 +286,9 @@ func newImpl(
|
|||||||
user.identityService.Start(ctx, user.serviceGroup)
|
user.identityService.Start(ctx, user.serviceGroup)
|
||||||
|
|
||||||
// Start SMTP Service
|
// Start SMTP Service
|
||||||
user.smtpService.Start(ctx, user.serviceGroup)
|
if err := user.smtpService.Start(ctx, user.serviceGroup); err != nil {
|
||||||
|
return user, fmt.Errorf("failed to start smtp service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Start IMAP Service
|
// Start IMAP Service
|
||||||
if err := user.imapService.Start(ctx, user.serviceGroup); err != nil {
|
if err := user.imapService.Start(ctx, user.serviceGroup); err != nil {
|
||||||
@ -548,8 +554,12 @@ func (user *User) Logout(ctx context.Context, withAPI bool) error {
|
|||||||
|
|
||||||
user.log.Debug("Canceling ongoing tasks")
|
user.log.Debug("Canceling ongoing tasks")
|
||||||
|
|
||||||
|
if err := user.smtpService.OnLogout(ctx); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove user from smtp server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := user.imapService.OnLogout(ctx); err != nil {
|
if err := user.imapService.OnLogout(ctx); err != nil {
|
||||||
return fmt.Errorf("failed to remove user from server: %w", err)
|
return fmt.Errorf("failed to remove user from imap server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop Services
|
// Stop Services
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/ProtonMail/proton-bridge/v3/internal/certs"
|
"github.com/ProtonMail/proton-bridge/v3/internal/certs"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice"
|
"github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice"
|
||||||
|
"github.com/ProtonMail/proton-bridge/v3/internal/services/smtp"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry/mocks"
|
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry/mocks"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/internal/vault"
|
"github.com/ProtonMail/proton-bridge/v3/internal/vault"
|
||||||
"github.com/ProtonMail/proton-bridge/v3/tests"
|
"github.com/ProtonMail/proton-bridge/v3/tests"
|
||||||
@ -155,7 +156,8 @@ func withUser(tb testing.TB, ctx context.Context, _ *server.Server, m *proton.Ma
|
|||||||
manager.EXPECT().IsTelemetryAvailable(context.Background()).AnyTimes()
|
manager.EXPECT().IsTelemetryAvailable(context.Background()).AnyTimes()
|
||||||
|
|
||||||
nullEventSubscription := events.NewNullSubscription()
|
nullEventSubscription := events.NewNullSubscription()
|
||||||
nullServerManager := imapservice.NewNullIMAPServerManager()
|
nullIMAPServerManager := imapservice.NewNullIMAPServerManager()
|
||||||
|
nullSMTPServerManager := smtp.NewNullServerManager()
|
||||||
|
|
||||||
user, err := New(
|
user, err := New(
|
||||||
ctx,
|
ctx,
|
||||||
@ -168,7 +170,8 @@ func withUser(tb testing.TB, ctx context.Context, _ *server.Server, m *proton.Ma
|
|||||||
vault.DefaultMaxSyncMemory,
|
vault.DefaultMaxSyncMemory,
|
||||||
tb.TempDir(),
|
tb.TempDir(),
|
||||||
manager,
|
manager,
|
||||||
nullServerManager,
|
nullIMAPServerManager,
|
||||||
|
nullSMTPServerManager,
|
||||||
nullEventSubscription,
|
nullEventSubscription,
|
||||||
)
|
)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user