mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
198 lines
5.3 KiB
Go
198 lines
5.3 KiB
Go
// Copyright (c) 2024 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 imapservice
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/ProtonMail/go-proton-api"
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/services/useridentity"
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/usertypes"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func (s *Service) HandleAddressEvents(ctx context.Context, events []proton.AddressEvent) error {
|
|
s.log.Debug("handling address event")
|
|
|
|
if s.addressMode == usertypes.AddressModeCombined {
|
|
oldPrimaryAddr, err := s.identityState.GetPrimaryAddress()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get primary addr: %w", err)
|
|
}
|
|
|
|
if err := s.identityState.Write(func(identity *useridentity.State) error {
|
|
identity.OnAddressEvents(events)
|
|
return nil
|
|
}); err != nil {
|
|
s.log.WithError(err).Error("Failed to apply address events to identity state")
|
|
return err
|
|
}
|
|
|
|
newPrimaryAddr, err := s.identityState.GetPrimaryAddress()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get primary addr after update: %w", err)
|
|
}
|
|
|
|
if oldPrimaryAddr.ID == newPrimaryAddr.ID {
|
|
return nil
|
|
}
|
|
|
|
connector, ok := s.connectors[oldPrimaryAddr.ID]
|
|
if !ok {
|
|
return fmt.Errorf("could not find old primary addr conncetor after default address change")
|
|
}
|
|
|
|
s.connectors[newPrimaryAddr.ID] = connector
|
|
delete(s.connectors, oldPrimaryAddr.ID)
|
|
|
|
s.log.WithFields(logrus.Fields{
|
|
"old": oldPrimaryAddr.Email,
|
|
"new": newPrimaryAddr.Email,
|
|
}).Debug("Primary address changed")
|
|
|
|
return nil
|
|
}
|
|
|
|
for _, event := range events {
|
|
switch event.Action {
|
|
case proton.EventCreate:
|
|
var status useridentity.AddressUpdate
|
|
|
|
if err := s.identityState.Write(func(identity *useridentity.State) error {
|
|
status = identity.OnAddressCreated(event)
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("failed to update identity state: %w", err)
|
|
}
|
|
|
|
if status == useridentity.AddressUpdateCreated {
|
|
if err := addNewAddressSplitMode(ctx, s, event.Address.ID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
case proton.EventUpdateFlags, proton.EventUpdate:
|
|
var addr proton.Address
|
|
var status useridentity.AddressUpdate
|
|
|
|
if err := s.identityState.Write(func(identity *useridentity.State) error {
|
|
addr, status = identity.OnAddressUpdated(event)
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("failed to update identity state: %w", err)
|
|
}
|
|
|
|
// nolint:exhaustive
|
|
switch status {
|
|
case useridentity.AddressUpdateCreated:
|
|
if err := addNewAddressSplitMode(ctx, s, addr.ID); err != nil {
|
|
return err
|
|
}
|
|
|
|
case useridentity.AddressUpdateDisabled:
|
|
if err := removeAddressSplitMode(ctx, s, addr.ID); err != nil {
|
|
return err
|
|
}
|
|
|
|
case useridentity.AddressUpdateEnabled:
|
|
if err := addNewAddressSplitMode(ctx, s, addr.ID); err != nil {
|
|
return err
|
|
}
|
|
|
|
default:
|
|
continue
|
|
}
|
|
|
|
case proton.EventDelete:
|
|
var status useridentity.AddressUpdate
|
|
|
|
if err := s.identityState.Write(func(identity *useridentity.State) error {
|
|
_, status = identity.OnAddressDeleted(event)
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("failed to update identity state: %w", err)
|
|
}
|
|
if status == useridentity.AddressUpdateDeleted {
|
|
if err := removeAddressSplitMode(ctx, s, event.ID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
default:
|
|
return fmt.Errorf("unknown event action: %v", event.Action)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func addNewAddressSplitMode(ctx context.Context, s *Service, addrID string) error {
|
|
connector := NewConnector(
|
|
addrID,
|
|
s.client,
|
|
s.labels,
|
|
s.identityState,
|
|
s.addressMode,
|
|
s.sendRecorder,
|
|
s.panicHandler,
|
|
s.telemetry,
|
|
s.reporter,
|
|
s.showAllMail,
|
|
s.syncStateProvider,
|
|
)
|
|
|
|
if err := s.serverManager.AddIMAPUser(ctx, connector, connector.addrID, s.gluonIDProvider, s.syncStateProvider); err != nil {
|
|
return fmt.Errorf("failed to add new account to server: %w", err)
|
|
}
|
|
|
|
s.connectors[connector.addrID] = connector
|
|
|
|
updates, err := syncLabels(ctx, s.labels.GetLabelMap(), []*Connector{connector})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create labels updates for new address: %w", err)
|
|
}
|
|
|
|
if err := waitOnIMAPUpdates(ctx, updates); err != nil {
|
|
return fmt.Errorf("failed to sync labels for new address: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func removeAddressSplitMode(ctx context.Context, s *Service, addrID string) error {
|
|
connector, ok := s.connectors[addrID]
|
|
if !ok {
|
|
s.log.Warnf("Could not find connector ")
|
|
return nil
|
|
}
|
|
|
|
if err := s.serverManager.RemoveIMAPUser(ctx, true, s.gluonIDProvider, addrID); err != nil {
|
|
return fmt.Errorf("failed to remove user from server: %w", err)
|
|
}
|
|
|
|
connector.StateClose()
|
|
|
|
delete(s.connectors, addrID)
|
|
|
|
return nil
|
|
}
|