From 71063ac5eecd165ce2db327426d7102f1be484c5 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 1 Sep 2023 14:44:27 +0200 Subject: [PATCH 01/29] fix(GODT-2902): do not check for changed values. Related to GODT-2857. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5cdf8ab2..eae0c022 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.16.1-0.20230808094407-85a10f17ae92 + github.com/ProtonMail/gluon v0.16.1-0.20230901124123-075229a92cc4 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230727082922-9115b4750ec7 github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton diff --git a/go.sum b/go.sum index 69f79877..1e4090b0 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.16.1-0.20230808094407-85a10f17ae92 h1:yoaUatxdB6EXChiWdfIBpasJJxrQ6dHJknG0hwBAqmQ= -github.com/ProtonMail/gluon v0.16.1-0.20230808094407-85a10f17ae92/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= +github.com/ProtonMail/gluon v0.16.1-0.20230901124123-075229a92cc4 h1:Uq2v2NYEtlTaK2WTh9BMph2Kv51JxMgvTkd7CjGPYc8= +github.com/ProtonMail/gluon v0.16.1-0.20230901124123-075229a92cc4/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= From a80fd92018438d8ec05d5d11560054537b9d947f Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 1 Sep 2023 15:12:34 +0200 Subject: [PATCH 02/29] chore: Trift Bridge 3.4.2 changelog. --- Changelog.md | 6 ++++++ Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index e635f946..ff849841 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,12 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Trift Bridge 3.4.2 + +### Fixed +* GODT-2902: Do not check for changed values. Related to GODT-2857. + + ## Trift Bridge 3.4.1 ### Fixed diff --git a/Makefile b/Makefile index e61b1f7d..4aff7b68 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.4.1+git +BRIDGE_APP_VERSION?=3.4.2+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From 86e8a566c741d0d4ac72bc355daa92eb8cd1f216 Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 12 Sep 2023 07:45:08 +0200 Subject: [PATCH 03/29] chore: Umshiang Bridge 3.5.0 changelog. --- Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog.md b/Changelog.md index 75db7f60..9f72ff55 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,8 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ## Umshiang Bridge 3.5.0 ### Added +* GODT-2734: Add testing steps to modify account settings. +* GODT-2746: Integration tests for reporting a problem. * GODT-2891: Allow message create & delete during sync. * GODT-2848: Decouple IMAP service from Event Loop. * Add trace profiling option. @@ -19,6 +21,8 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) * GODT-2803: Bridge Database access. ### Changed +* GODT-2909: Remove Timeout on event publish. +* GODT-2913: Reduce the number of configuration failure detected. * GODT-2828: Increase sync progress report frequency. * Test: Fix TestBridge_SyncWithOnGoingEvents. * GODT-2871: Is telemetry enabled as service. From 45d2e9ea639a9c1f9c12781e815b4e7cd071874d Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 13 Sep 2023 10:25:47 +0200 Subject: [PATCH 04/29] chore: update changelog. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 9f72ff55..918165f2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -75,6 +75,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) * GODT-2780: Fix 'QSystemTrayIcon::setVisible: No Icon set' warning in bridge-gui log on startup. * GODT-2778: Fix login screen being disabled after an 'already logged in' error. * Fix typos found by codespell. +* GODT-2577: Answered flag should only be applied to replied messages. ## Trift Bridge 3.4.1 From e6b312b437494ed8866490ed7be4474625596b5f Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 26 Sep 2023 09:08:25 +0200 Subject: [PATCH 05/29] fix(GODT-2949): Fix close of close channel in event service This issue is triggered due to the `Service.Close()` call after the go-routine for the event service exists. It is possible that during this period a recently added subscriber with `pendingOpAdd` gets cancelled and closed. However, the subscriber later also enqueues a `pendingOpRemove` which gets processed again with a call in `user.eventService.Close()` leading to the double close panic. This patch simply removes the `s.Close()` from the service, and leaves the cleanup to called externally from user.Close() or user.Logout(). --- internal/services/userevents/service.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/services/userevents/service.go b/internal/services/userevents/service.go index 52e6d83d..104dfbe8 100644 --- a/internal/services/userevents/service.go +++ b/internal/services/userevents/service.go @@ -192,7 +192,6 @@ func (s *Service) run(ctx context.Context, lastEventID string) { defer s.cpc.Close() defer s.timer.Stop() defer s.log.Info("Exiting service") - defer s.Close() client := network.NewClientRetryWrapper(s.eventSource, &network.ExpCoolDown{}) @@ -303,14 +302,15 @@ func (s *Service) Close() { // Cleanup pending removes. for _, s := range s.pendingSubscriptions { - if s.op == pendingOpRemove { - if !processed.Contains(s.sub) { + if !processed.Contains(s.sub) { + processed.Add(s.sub) + + if s.op == pendingOpRemove { + s.sub.close() + } else { + s.sub.cancel() s.sub.close() } - } else { - s.sub.cancel() - s.sub.close() - processed.Add(s.sub) } } From 236c958703ed2b14702019bd0a2e1ab864b01ce8 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 26 Sep 2023 09:20:01 +0200 Subject: [PATCH 06/29] fix(GODT-2590): Fix send on closed channel Ensure periodic user tasks are terminated before the other user services. The panic triggered due to the fact that the telemetry service was shutdown before this periodic task. --- internal/user/user.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/user/user.go b/internal/user/user.go index 4e1470a6..e916bc81 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -589,6 +589,8 @@ func (user *User) Logout(ctx context.Context, withAPI bool) error { return fmt.Errorf("failed to remove user from imap server: %w", err) } + user.tasks.CancelAndWait() + // Stop Services user.serviceGroup.CancelAndWait() @@ -598,8 +600,6 @@ func (user *User) Logout(ctx context.Context, withAPI bool) error { // Close imap service. user.imapService.Close() - user.tasks.CancelAndWait() - if withAPI { user.log.Debug("Logging out from API") @@ -621,6 +621,9 @@ func (user *User) Logout(ctx context.Context, withAPI bool) error { func (user *User) Close() { user.log.Info("Closing user") + // Stop any ongoing background tasks. + user.tasks.CancelAndWait() + // Stop Services user.serviceGroup.CancelAndWait() @@ -630,9 +633,6 @@ func (user *User) Close() { // Close imap service. user.imapService.Close() - // Stop any ongoing background tasks. - user.tasks.CancelAndWait() - // Close the user's API client. user.client.Close() From bfe25e3a46c88725d9cd63a73de1b1b462c13239 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 26 Sep 2023 09:45:27 +0200 Subject: [PATCH 07/29] fix(GODT-2951): Negative WaitGroup Counter Do not defer call to `wg.Done()` in `job.onJobFinished`. If there is an error it will also call `wg.Done()`. --- internal/services/syncservice/job.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/services/syncservice/job.go b/internal/services/syncservice/job.go index 8978ae6b..cad55c90 100644 --- a/internal/services/syncservice/job.go +++ b/internal/services/syncservice/job.go @@ -113,13 +113,14 @@ func (j *Job) onStageCompleted(ctx context.Context, count int64) { } func (j *Job) onJobFinished(ctx context.Context, lastMessageID string, count int64) { - defer j.wg.Done() - if err := j.state.SetLastMessageID(ctx, lastMessageID, count); err != nil { j.log.WithError(err).Error("Failed to store last synced message id") j.onError(err) return } + + // j.onError() also calls j.wg.Done(). + j.wg.Done() j.syncReporter.OnProgress(ctx, count) } From bbe19bf960fba367cfd22e559c12e3d5f19534f5 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 26 Sep 2023 12:47:53 +0200 Subject: [PATCH 08/29] fix(GODT-2956): Restore old deletion rules When unlabeling a message from trash we have to check if this message is present in another folder before perma-deleting. --- internal/services/imapservice/connector.go | 66 ++++++++++++++++++- tests/features/imap/message/copy.feature | 15 +++++ .../imap/message/delete_from_trash.feature | 6 +- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/internal/services/imapservice/connector.go b/internal/services/imapservice/connector.go index 03ca7dbe..e026752f 100644 --- a/internal/services/imapservice/connector.go +++ b/internal/services/imapservice/connector.go @@ -37,6 +37,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/pkg/message" "github.com/ProtonMail/proton-bridge/v3/pkg/message/parser" "github.com/bradenaw/juniper/stream" + "github.com/bradenaw/juniper/xslices" "github.com/sirupsen/logrus" "golang.org/x/exp/slices" ) @@ -334,8 +335,69 @@ func (s *Connector) RemoveMessagesFromMailbox(ctx context.Context, _ connector.I } if mboxID == proton.TrashLabel || mboxID == proton.DraftsLabel { - if err := s.client.DeleteMessage(ctx, msgIDs...); err != nil { - return err + const ChunkSize = 150 + var msgToPermaDelete []string + + rdLabels := s.labels.Read() + defer rdLabels.Close() + + // There's currently no limit on how many IDs we can filter on, + // but to be nice to API, let's chunk it by 150. + for _, messageIDs := range xslices.Chunk(messageIDs, ChunkSize) { + metadata, err := s.client.GetMessageMetadataPage(ctx, 0, ChunkSize, proton.MessageFilter{ + ID: usertypes.MapTo[imap.MessageID, string](messageIDs), + }) + if err != nil { + return err + } + + // If a message is not preset in any other label other than AllMail, AllDrafts and AllSent, it can be + // permanently deleted. + for _, m := range metadata { + var remainingLabels []string + + for _, id := range m.LabelIDs { + label, ok := rdLabels.GetLabel(id) + if !ok { + // Handle case where this label was newly introduced and we do not yet know about it. + logrus.WithField("labelID", id).Warnf("Unknown label found during expung from Trash, attempting to locate it") + label, err = s.client.GetLabel(ctx, id, proton.LabelTypeFolder, proton.LabelTypeSystem, proton.LabelTypeSystem) + if err != nil { + if errors.Is(err, proton.ErrNoSuchLabel) { + logrus.WithField("labelID", id).Warn("Label does not exist, ignoring") + continue + } + + logrus.WithField("labelID", id).Errorf("Failed to resolve label: %v", err) + return fmt.Errorf("failed to resolve label: %w", err) + } + } + if !WantLabel(label) { + continue + } + + if label.Type == proton.LabelTypeSystem && (id == proton.AllDraftsLabel || + id == proton.AllMailLabel || + id == proton.AllSentLabel || + id == proton.AllScheduledLabel) { + continue + } + + remainingLabels = append(remainingLabels, m.ID) + } + + if len(remainingLabels) == 0 { + msgToPermaDelete = append(msgToPermaDelete, m.ID) + } + } + } + + if len(msgToPermaDelete) != 0 { + logrus.Debugf("Following message(s) will be perma-deleted: %v", msgToPermaDelete) + + if err := s.client.DeleteMessage(ctx, msgToPermaDelete...); err != nil { + return err + } } } diff --git a/tests/features/imap/message/copy.feature b/tests/features/imap/message/copy.feature index 4dd0b6c6..1b44d794 100644 --- a/tests/features/imap/message/copy.feature +++ b/tests/features/imap/message/copy.feature @@ -85,3 +85,18 @@ Feature: IMAP copy messages | from | to | subject | unread | | john.doe@mail.com | [user:user]@[domain] | foo | false | + Scenario: Move message to trash then copy to folder does not delete message + When IMAP client "1" moves the message with subject "foo" from "INBOX" to "Trash" + And it succeeds + Then IMAP client "1" eventually sees the following messages in "Trash": + | from | to | subject | unread | + | john.doe@mail.com | [user:user]@[domain] | foo | false | + When IMAP client "1" copies the message with subject "foo" from "Trash" to "Folders/mbox" + And it succeeds + When IMAP client "1" marks the message with subject "foo" as deleted + Then it succeeds + When IMAP client "1" expunges + Then it succeeds + Then IMAP client "1" eventually sees the following messages in "Folders/mbox": + | from | to | subject | unread | + | john.doe@mail.com | [user:user]@[domain] | foo | false | diff --git a/tests/features/imap/message/delete_from_trash.feature b/tests/features/imap/message/delete_from_trash.feature index a8323e91..15446eed 100644 --- a/tests/features/imap/message/delete_from_trash.feature +++ b/tests/features/imap/message/delete_from_trash.feature @@ -7,7 +7,7 @@ Feature: IMAP remove messages from Trash | label | label | Then it succeeds - Scenario Outline: Message in Trash and some other label is permanently deleted + Scenario Outline: Message in Trash and some other label is not permanently deleted Given the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Trash": | from | to | subject | body | | john.doe@mail.com | [user:user]@[domain] | foo | hello | @@ -27,8 +27,8 @@ Feature: IMAP remove messages from Trash When IMAP client "1" expunges Then it succeeds And IMAP client "1" eventually sees 1 messages in "Trash" - And IMAP client "1" eventually sees 1 messages in "All Mail" - And IMAP client "1" eventually sees 0 messages in "Labels/label" + And IMAP client "1" eventually sees 2 messages in "All Mail" + And IMAP client "1" eventually sees 1 messages in "Labels/label" Scenario Outline: Message in Trash only is permanently deleted Given the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Trash": From 949666724d81e7619f4f79f523c5a0e31314c327 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 27 Sep 2023 10:54:50 +0200 Subject: [PATCH 09/29] chore: Umshiang Bridge 3.5.1 changelog. --- Changelog.md | 9 +++++++++ Makefile | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 918165f2..9538c1f9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,15 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Umshiang Bridge 3.5.1 + +### Fixed +* GODT-2956: Restore old deletion rules. +* GODT-2951: Negative WaitGroup Counter. +* GODT-2590: Fix send on closed channel. +* GODT-2949: Fix close of close channel in event service. + + ## Umshiang Bridge 3.5.0 ### Added diff --git a/Makefile b/Makefile index 6f010be6..24d3ba27 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.5.0+git +BRIDGE_APP_VERSION?=3.5.1+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From 0d03f84711a5399c640b71dfa1dde64ba372b94e Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 27 Sep 2023 11:30:46 +0200 Subject: [PATCH 10/29] fix(GODT-2963): Use multi error to report file removal errors Do not abort removing files on first error. Collect errors and try to remove as many as possible. This would cause some state files to not be removed on windows. --- pkg/files/removal.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/files/removal.go b/pkg/files/removal.go index 8f0b8db3..594f3010 100644 --- a/pkg/files/removal.go +++ b/pkg/files/removal.go @@ -72,11 +72,12 @@ func remove(dir string, except ...string) error { sort.Sort(sort.Reverse(sort.StringSlice(toRemove))) + var multiErr error for _, target := range toRemove { if err := os.RemoveAll(target); err != nil { - return err + multiErr = multierror.Append(multiErr, err) } } - return nil + return multiErr } From b7ef6e1486a69b3ed7aeb1462d7e9ad4bdeb58db Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 27 Sep 2023 13:18:23 +0200 Subject: [PATCH 11/29] chore: Umshiang Bridge 3.5.1 changelog. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 9538c1f9..5dc72bc3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ## Umshiang Bridge 3.5.1 ### Fixed +* GODT-2963: Use multi error to report file removal errors. * GODT-2956: Restore old deletion rules. * GODT-2951: Negative WaitGroup Counter. * GODT-2590: Fix send on closed channel. From 80c852a5b234e1f7a7a0d17383dd87f1fb719461 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Tue, 3 Oct 2023 10:48:46 +0200 Subject: [PATCH 12/29] fix(GODT-2992): fix link in 'no account view' in main window after 2FA or TOTP are cancelled. (cherry picked from commit 1c344211d1ab436c80b4c0c185dc34af45d074e8) --- .../bridge-gui/qml/SetupWizard/LeftPane.qml | 10 ---------- .../bridge-gui/qml/SetupWizard/SetupWizard.qml | 11 +++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml index 433c1ac1..e809aa98 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml @@ -75,16 +75,6 @@ Item { root.iconWidth = 265; } - Connections { - function onLogin2FARequested() { - showLogin2FA(); - } - function onLogin2PasswordRequested() { - showLoginMailboxPassword(); - } - - target: Backend - } ColumnLayout { anchors.left: parent.left anchors.right: parent.right diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml index 3248184a..ae384e0e 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml @@ -186,6 +186,17 @@ Item { target: clientConfigAppleMail } + + Connections { + function onLogin2FARequested() { + leftContent.showLogin2FA(); + } + function onLogin2PasswordRequested() { + leftContent.showLoginMailboxPassword(); + } + + target: Backend + } } Image { id: mailLogoWithWordmark From d3582fa981a8f13f8a8a360d72d661604ac5a477 Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 3 Oct 2023 16:43:33 +0200 Subject: [PATCH 13/29] chore: Vasco da Gama Bridge 3.6.0 changelog. --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 06759abe..5e4ba62d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,7 +2,6 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) - ## Vasco da Gama Bridge 3.6.0 ### Added @@ -21,6 +20,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) * GODT-2664: Trigger QA installer. ### Fixed +* GODT-2992: Fix link in 'no account view' in main window after 2FA or TOTP are cancelled. * GODT-2989: Allow to send bug report when no account connected. * GODT-2988: Fix setup wizard KB links. * GODT-2968: Use proper base64 encoded string even for bad password test. From e7423a95190ee096a3e10f1372db8cf4770de498 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 6 Oct 2023 10:09:10 +0100 Subject: [PATCH 14/29] fix(GODT-3001): Only create system labels during system label sync --- internal/services/imapservice/sync_update_applier.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/services/imapservice/sync_update_applier.go b/internal/services/imapservice/sync_update_applier.go index 58230ae5..4ba043b1 100644 --- a/internal/services/imapservice/sync_update_applier.go +++ b/internal/services/imapservice/sync_update_applier.go @@ -119,6 +119,10 @@ func (s *SyncUpdateApplier) SyncSystemLabelsOnly(ctx context.Context, labels map continue } + if label.Type != proton.LabelTypeSystem { + continue + } + for _, c := range connectors { update := newSystemMailboxCreatedUpdate(imap.MailboxID(label.ID), label.Name) updates = append(updates, update) From 951c7c27fba64613fca2d8e323033c11da47ba8f Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 6 Oct 2023 15:00:36 +0100 Subject: [PATCH 15/29] fix(GODT-3003): Ensure IMAP State is reset after vault corruption After we detect that the user has suffered the GODT-3003 bug due the vault corruption not ensuring that a previous sync state would be erased, we patch the gluon db directly and then reset the sync state. After the account is added, the sync is automatically triggered and the account state fixes itself. --- Makefile | 1 + go.mod | 2 +- go.sum | 4 +- internal/bridge/bridge_test.go | 2 +- internal/bridge/sync_test.go | 62 ++++++ internal/services/imapservice/connector.go | 71 +++++- .../services/imapservice/connector_test.go | 205 ++++++++++++++++++ internal/services/imapservice/mocks/mocks.go | 138 ++++++++++++ internal/services/imapservice/service.go | 6 +- .../imapservice/service_address_events.go | 1 + .../imapservice/sync_state_provider.go | 4 +- .../imapservice/sync_state_provider_test.go | 4 +- internal/services/imapsmtpserver/service.go | 5 + 13 files changed, 493 insertions(+), 12 deletions(-) create mode 100644 internal/services/imapservice/connector_test.go create mode 100644 internal/services/imapservice/mocks/mocks.go diff --git a/Makefile b/Makefile index 24d3ba27..ec68628a 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ ApplyStageInput,BuildStageInput,BuildStageOutput,DownloadStageInput,DownloadStag StateProvider,Regulator,UpdateApplier,MessageBuilder,APIClient,Reporter,DownloadRateModifier \ > tmp mv tmp internal/services/syncservice/mocks_test.go + mockgen --package mocks github.com/ProtonMail/gluon/connector IMAPStateWrite > internal/services/imapservice/mocks/mocks.go lint: gofiles lint-golang lint-license lint-dependencies lint-changelog lint-bug-report diff --git a/go.mod b/go.mod index ad3f2697..af219a1a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.17.1-0.20230829112217-5d5c25c504b5 + github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36 github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton diff --git a/go.sum b/go.sum index 5177f714..7a1236b5 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.17.1-0.20230829112217-5d5c25c504b5 h1:C/8P5NHAKi2yCKez+OZ5rSR8SsL7k8si4pK4SE2QtV8= -github.com/ProtonMail/gluon v0.17.1-0.20230829112217-5d5c25c504b5/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= +github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c h1:gUDu4pOswgbou0QczfreNiXQFrmvVlpSh8Q+vft/JvI= +github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index acd0fd0c..6ce8b1bd 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -585,7 +585,7 @@ func TestBridge_MissingGluonStore(t *testing.T) { require.NoError(t, os.RemoveAll(gluonDir)) // Bridge starts but can't find the gluon store dir; there should be no error. - withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + withBridgeWaitForServers(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { // ... }) }) diff --git a/internal/bridge/sync_test.go b/internal/bridge/sync_test.go index 1d613bf3..07c0988a 100644 --- a/internal/bridge/sync_test.go +++ b/internal/bridge/sync_test.go @@ -37,6 +37,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" + "github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice" "github.com/bradenaw/juniper/iterator" "github.com/bradenaw/juniper/stream" "github.com/bradenaw/juniper/xslices" @@ -579,6 +580,67 @@ func TestBridge_MessageCreateDuringSync(t *testing.T) { }, server.WithTLS(false)) } +func TestBridge_CorruptedVaultClearsPreviousIMAPSyncState(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { + userID, addrID, err := s.CreateUser("imap", password) + require.NoError(t, err) + + labelID, err := s.CreateLabel(userID, "folder", "", proton.LabelTypeFolder) + require.NoError(t, err) + + withClient(ctx, t, s, "imap", password, func(ctx context.Context, c *proton.Client) { + createNumMessages(ctx, t, c, addrID, labelID, 100) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{})) + defer done() + + var err error + + userID, err = bridge.LoginFull(context.Background(), "imap", password, nil, nil) + require.NoError(t, err) + + // Wait for sync to finish + require.Equal(t, userID, (<-syncCh).UserID) + }) + + settingsPath, err := locator.ProvideSettingsPath() + require.NoError(t, err) + + syncConfigPath, err := locator.ProvideIMAPSyncConfigPath() + require.NoError(t, err) + + syncStatePath := imapservice.GetSyncConfigPath(syncConfigPath, userID) + // Check sync state is complete + { + state, err := imapservice.NewSyncState(syncStatePath) + require.NoError(t, err) + syncStatus, err := state.GetSyncStatus(context.Background()) + require.NoError(t, err) + require.True(t, syncStatus.IsComplete()) + } + + // corrupt the vault + require.NoError(t, os.WriteFile(filepath.Join(settingsPath, "vault.enc"), []byte("Trash!"), 0o600)) + + // Bridge starts but can't find the gluon database dir; there should be no error. + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + _, err := bridge.LoginFull(context.Background(), "imap", password, nil, nil) + require.NoError(t, err) + }) + + // Check sync state is reset. + { + state, err := imapservice.NewSyncState(syncStatePath) + require.NoError(t, err) + syncStatus, err := state.GetSyncStatus(context.Background()) + require.NoError(t, err) + require.False(t, syncStatus.IsComplete()) + } + }) +} + func withClient(ctx context.Context, t *testing.T, s *server.Server, username string, password []byte, fn func(context.Context, *proton.Client)) { //nolint:unparam m := proton.New( proton.WithHostURL(s.GetHostURL()), diff --git a/internal/services/imapservice/connector.go b/internal/services/imapservice/connector.go index e026752f..c21fe5ca 100644 --- a/internal/services/imapservice/connector.go +++ b/internal/services/imapservice/connector.go @@ -63,6 +63,7 @@ type Connector struct { log *logrus.Entry sharedCache *SharedCache + syncState *SyncState } func NewConnector( @@ -75,6 +76,7 @@ func NewConnector( panicHandler async.PanicHandler, telemetry Telemetry, showAllMail bool, + syncState *SyncState, ) *Connector { userID := identityState.UserID() @@ -106,6 +108,7 @@ func NewConnector( }), sharedCache: NewSharedCached(), + syncState: syncState, } } @@ -114,9 +117,35 @@ func (s *Connector) StateClose() { s.updateCh.CloseAndDiscardQueued() } -func (s *Connector) Init(_ context.Context, cache connector.IMAPState) error { +func (s *Connector) Init(ctx context.Context, cache connector.IMAPState) error { s.sharedCache.Set(cache) - return nil + + return cache.Write(ctx, func(ctx context.Context, write connector.IMAPStateWrite) error { + rd := s.labels.Read() + defer rd.Close() + + mboxes, err := write.GetMailboxesWithoutAttrib(ctx) + if err != nil { + return err + } + + // Attempt to fix bug when a vault got corrupted, but the sync state did not get reset leading to + // all labels being written to the root level. If we detect this happened, reset the sync state. + { + applied, err := fixGODT3003Labels(ctx, s.log, mboxes, rd, write) + if err != nil { + return err + } + + if applied { + s.log.Debug("Patched folders/labels after GODT-3003 incident, resetting sync state.") + if err := s.syncState.ClearSyncStatus(ctx); err != nil { + return err + } + } + } + return nil + }) } func (s *Connector) Authorize(ctx context.Context, username string, password []byte) bool { @@ -745,3 +774,41 @@ func (s *Connector) createDraft(ctx context.Context, literal []byte, addrKR *cry func (s *Connector) publishUpdate(_ context.Context, update imap.Update) { s.updateCh.Enqueue(update) } + +func fixGODT3003Labels( + ctx context.Context, + log *logrus.Entry, + mboxes []imap.MailboxNoAttrib, + rd labelsRead, + write connector.IMAPStateWrite, +) (bool, error) { + var applied bool + for _, mbox := range mboxes { + lbl, ok := rd.GetLabel(string(mbox.ID)) + if !ok { + continue + } + + if lbl.Type == proton.LabelTypeFolder { + if mbox.Name[0] != folderPrefix { + log.WithField("labelID", mbox.ID.ShortID()).Debug("Found folder without prefix, patching") + if err := write.PatchMailboxHierarchyWithoutTransforms(ctx, mbox.ID, xslices.Insert(mbox.Name, 0, folderPrefix)); err != nil { + return false, fmt.Errorf("failed to update mailbox name: %w", err) + } + + applied = true + } + } else if lbl.Type == proton.LabelTypeLabel { + if mbox.Name[0] != labelPrefix { + log.WithField("labelID", mbox.ID.ShortID()).Debug("Found label without prefix, patching") + if err := write.PatchMailboxHierarchyWithoutTransforms(ctx, mbox.ID, xslices.Insert(mbox.Name, 0, labelPrefix)); err != nil { + return false, fmt.Errorf("failed to update mailbox name: %w", err) + } + + applied = true + } + } + } + + return applied, nil +} diff --git a/internal/services/imapservice/connector_test.go b/internal/services/imapservice/connector_test.go new file mode 100644 index 00000000..f79b885d --- /dev/null +++ b/internal/services/imapservice/connector_test.go @@ -0,0 +1,205 @@ +// 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 . + +package imapservice + +import ( + "context" + "testing" + + "github.com/ProtonMail/gluon/imap" + "github.com/ProtonMail/go-proton-api" + "github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice/mocks" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func TestFixGODT3003Labels(t *testing.T) { + mockCtrl := gomock.NewController(t) + + log := logrus.WithField("test", "test") + + sharedLabels := newRWLabels() + wr := sharedLabels.Write() + wr.SetLabel("foo", proton.Label{ + ID: "foo", + ParentID: "bar", + Name: "Foo", + Path: []string{"bar", "Foo"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("0", proton.Label{ + ID: "0", + ParentID: "", + Name: "Inbox", + Path: []string{"Inbox"}, + Color: "", + Type: proton.LabelTypeSystem, + }) + + wr.SetLabel("bar", proton.Label{ + ID: "bar", + ParentID: "", + Name: "boo", + Path: []string{"bar"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("my_label", proton.Label{ + ID: "my_label", + ParentID: "", + Name: "MyLabel", + Path: []string{"MyLabel"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + + wr.SetLabel("my_label2", proton.Label{ + ID: "my_label2", + ParentID: "", + Name: "MyLabel2", + Path: []string{labelPrefix, "MyLabel2"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + wr.Close() + + mboxs := []imap.MailboxNoAttrib{ + { + ID: "0", + Name: []string{"Inbox"}, + }, + { + ID: "bar", + Name: []string{"bar"}, + }, + { + ID: "foo", + Name: []string{"bar", "Foo"}, + }, + { + ID: "my_label", + Name: []string{"MyLabel"}, + }, + { + ID: "my_label2", + Name: []string{labelPrefix, "MyLabel2"}, + }, + } + + rd := sharedLabels.Read() + defer rd.Close() + + imapState := mocks.NewMockIMAPStateWrite(mockCtrl) + + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("bar")), gomock.Eq([]string{folderPrefix, "bar"})) + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("foo")), gomock.Eq([]string{folderPrefix, "bar", "Foo"})) + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("my_label")), gomock.Eq([]string{labelPrefix, "MyLabel"})) + + applied, err := fixGODT3003Labels(context.Background(), log, mboxs, rd, imapState) + require.NoError(t, err) + require.True(t, applied) +} + +func TestFixGODT3003Labels_Noop(t *testing.T) { + mockCtrl := gomock.NewController(t) + + log := logrus.WithField("test", "test") + + sharedLabels := newRWLabels() + wr := sharedLabels.Write() + wr.SetLabel("foo", proton.Label{ + ID: "foo", + ParentID: "bar", + Name: "Foo", + Path: []string{folderPrefix, "bar", "Foo"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("0", proton.Label{ + ID: "0", + ParentID: "", + Name: "Inbox", + Path: []string{"Inbox"}, + Color: "", + Type: proton.LabelTypeSystem, + }) + + wr.SetLabel("bar", proton.Label{ + ID: "bar", + ParentID: "", + Name: "bar", + Path: []string{folderPrefix, "bar"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("my_label", proton.Label{ + ID: "my_label", + ParentID: "", + Name: "MyLabel", + Path: []string{labelPrefix, "MyLabel"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + + wr.SetLabel("my_label2", proton.Label{ + ID: "my_label2", + ParentID: "", + Name: "MyLabel2", + Path: []string{labelPrefix, "MyLabel2"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + wr.Close() + + mboxs := []imap.MailboxNoAttrib{ + { + ID: "0", + Name: []string{"Inbox"}, + }, + { + ID: "bar", + Name: []string{folderPrefix, "bar"}, + }, + { + ID: "foo", + Name: []string{folderPrefix, "bar", "Foo"}, + }, + { + ID: "my_label", + Name: []string{labelPrefix, "MyLabel"}, + }, + { + ID: "my_label2", + Name: []string{labelPrefix, "MyLabel2"}, + }, + } + + rd := sharedLabels.Read() + defer rd.Close() + + imapState := mocks.NewMockIMAPStateWrite(mockCtrl) + applied, err := fixGODT3003Labels(context.Background(), log, mboxs, rd, imapState) + require.NoError(t, err) + require.False(t, applied) +} diff --git a/internal/services/imapservice/mocks/mocks.go b/internal/services/imapservice/mocks/mocks.go new file mode 100644 index 00000000..17e5b7cd --- /dev/null +++ b/internal/services/imapservice/mocks/mocks.go @@ -0,0 +1,138 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ProtonMail/gluon/connector (interfaces: IMAPStateWrite) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + imap "github.com/ProtonMail/gluon/imap" + gomock "github.com/golang/mock/gomock" +) + +// MockIMAPStateWrite is a mock of IMAPStateWrite interface. +type MockIMAPStateWrite struct { + ctrl *gomock.Controller + recorder *MockIMAPStateWriteMockRecorder +} + +// MockIMAPStateWriteMockRecorder is the mock recorder for MockIMAPStateWrite. +type MockIMAPStateWriteMockRecorder struct { + mock *MockIMAPStateWrite +} + +// NewMockIMAPStateWrite creates a new mock instance. +func NewMockIMAPStateWrite(ctrl *gomock.Controller) *MockIMAPStateWrite { + mock := &MockIMAPStateWrite{ctrl: ctrl} + mock.recorder = &MockIMAPStateWriteMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIMAPStateWrite) EXPECT() *MockIMAPStateWriteMockRecorder { + return m.recorder +} + +// CreateMailbox mocks base method. +func (m *MockIMAPStateWrite) CreateMailbox(arg0 context.Context, arg1 imap.Mailbox) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateMailbox", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateMailbox indicates an expected call of CreateMailbox. +func (mr *MockIMAPStateWriteMockRecorder) CreateMailbox(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateMailbox", reflect.TypeOf((*MockIMAPStateWrite)(nil).CreateMailbox), arg0, arg1) +} + +// GetMailboxCount mocks base method. +func (m *MockIMAPStateWrite) GetMailboxCount(arg0 context.Context) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMailboxCount", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMailboxCount indicates an expected call of GetMailboxCount. +func (mr *MockIMAPStateWriteMockRecorder) GetMailboxCount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMailboxCount", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetMailboxCount), arg0) +} + +// GetMailboxesWithoutAttrib mocks base method. +func (m *MockIMAPStateWrite) GetMailboxesWithoutAttrib(arg0 context.Context) ([]imap.MailboxNoAttrib, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMailboxesWithoutAttrib", arg0) + ret0, _ := ret[0].([]imap.MailboxNoAttrib) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMailboxesWithoutAttrib indicates an expected call of GetMailboxesWithoutAttrib. +func (mr *MockIMAPStateWriteMockRecorder) GetMailboxesWithoutAttrib(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMailboxesWithoutAttrib", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetMailboxesWithoutAttrib), arg0) +} + +// GetSettings mocks base method. +func (m *MockIMAPStateWrite) GetSettings(arg0 context.Context) (string, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSettings", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetSettings indicates an expected call of GetSettings. +func (mr *MockIMAPStateWriteMockRecorder) GetSettings(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSettings", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetSettings), arg0) +} + +// PatchMailboxHierarchyWithoutTransforms mocks base method. +func (m *MockIMAPStateWrite) PatchMailboxHierarchyWithoutTransforms(arg0 context.Context, arg1 imap.MailboxID, arg2 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchMailboxHierarchyWithoutTransforms", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// PatchMailboxHierarchyWithoutTransforms indicates an expected call of PatchMailboxHierarchyWithoutTransforms. +func (mr *MockIMAPStateWriteMockRecorder) PatchMailboxHierarchyWithoutTransforms(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchMailboxHierarchyWithoutTransforms", reflect.TypeOf((*MockIMAPStateWrite)(nil).PatchMailboxHierarchyWithoutTransforms), arg0, arg1, arg2) +} + +// StoreSettings mocks base method. +func (m *MockIMAPStateWrite) StoreSettings(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoreSettings", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// StoreSettings indicates an expected call of StoreSettings. +func (mr *MockIMAPStateWriteMockRecorder) StoreSettings(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreSettings", reflect.TypeOf((*MockIMAPStateWrite)(nil).StoreSettings), arg0, arg1) +} + +// UpdateMessageFlags mocks base method. +func (m *MockIMAPStateWrite) UpdateMessageFlags(arg0 context.Context, arg1 imap.MessageID, arg2 imap.FlagSet) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateMessageFlags", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateMessageFlags indicates an expected call of UpdateMessageFlags. +func (mr *MockIMAPStateWriteMockRecorder) UpdateMessageFlags(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMessageFlags", reflect.TypeOf((*MockIMAPStateWrite)(nil).UpdateMessageFlags), arg0, arg1, arg2) +} diff --git a/internal/services/imapservice/service.go b/internal/services/imapservice/service.go index 701a62c6..79e4b9f0 100644 --- a/internal/services/imapservice/service.go +++ b/internal/services/imapservice/service.go @@ -158,7 +158,7 @@ func NewService( syncUpdateApplier: syncUpdateApplier, syncMessageBuilder: syncMessageBuilder, syncReporter: syncReporter, - syncConfigPath: getSyncConfigPath(syncConfigDir, identityState.User.ID), + syncConfigPath: GetSyncConfigPath(syncConfigDir, identityState.User.ID), } } @@ -498,6 +498,7 @@ func (s *Service) buildConnectors() (map[string]*Connector, error) { s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) return connectors, nil @@ -514,6 +515,7 @@ func (s *Service) buildConnectors() (map[string]*Connector, error) { s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) } @@ -644,6 +646,6 @@ type setAddressModeReq struct { type getSyncFailedMessagesReq struct{} -func getSyncConfigPath(path string, userID string) string { +func GetSyncConfigPath(path string, userID string) string { return filepath.Join(path, fmt.Sprintf("sync-%v", userID)) } diff --git a/internal/services/imapservice/service_address_events.go b/internal/services/imapservice/service_address_events.go index 2c5aed9c..78abe4a3 100644 --- a/internal/services/imapservice/service_address_events.go +++ b/internal/services/imapservice/service_address_events.go @@ -128,6 +128,7 @@ func addNewAddressSplitMode(ctx context.Context, s *Service, addrID string) erro s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) if err := s.serverManager.AddIMAPUser(ctx, connector, connector.addrID, s.gluonIDProvider, s.syncStateProvider); err != nil { diff --git a/internal/services/imapservice/sync_state_provider.go b/internal/services/imapservice/sync_state_provider.go index 190d67a5..9b3723d2 100644 --- a/internal/services/imapservice/sync_state_provider.go +++ b/internal/services/imapservice/sync_state_provider.go @@ -220,7 +220,7 @@ func (s *SyncState) loadUnsafe() error { } func DeleteSyncState(configDir, userID string) error { - path := getSyncConfigPath(configDir, userID) + path := GetSyncConfigPath(configDir, userID) if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) { return err @@ -234,7 +234,7 @@ func MigrateVaultSettings( hasLabels, hasMessages bool, failedMessageIDs []string, ) (bool, error) { - filePath := getSyncConfigPath(configDir, userID) + filePath := GetSyncConfigPath(configDir, userID) _, err := os.ReadFile(filePath) //nolint:gosec if err == nil { diff --git a/internal/services/imapservice/sync_state_provider_test.go b/internal/services/imapservice/sync_state_provider_test.go index 0852c53f..e4dd93b7 100644 --- a/internal/services/imapservice/sync_state_provider_test.go +++ b/internal/services/imapservice/sync_state_provider_test.go @@ -29,7 +29,7 @@ import ( func TestMigrateSyncSettings_AlreadyExists(t *testing.T) { tmpDir := t.TempDir() - testFile := getSyncConfigPath(tmpDir, "test") + testFile := GetSyncConfigPath(tmpDir, "test") expected, err := generateTestState(testFile) require.NoError(t, err) @@ -53,7 +53,7 @@ func TestMigrateSyncSettings_DoesNotExist(t *testing.T) { require.NoError(t, err) require.True(t, migrated) - state, err := NewSyncState(getSyncConfigPath(tmpDir, "test")) + state, err := NewSyncState(GetSyncConfigPath(tmpDir, "test")) require.NoError(t, err) status, err := state.GetSyncStatus(context.Background()) require.NoError(t, err) diff --git a/internal/services/imapsmtpserver/service.go b/internal/services/imapsmtpserver/service.go index de186eb9..f2e22176 100644 --- a/internal/services/imapsmtpserver/service.go +++ b/internal/services/imapsmtpserver/service.go @@ -390,6 +390,11 @@ func (sm *Service) handleAddIMAPUserImpl(ctx context.Context, } else { log.Info("Creating new IMAP user") + // GODT-3003: Ensure previous IMAP sync state is cleared if we run into code path after vault corruption. + if err := syncStateProvider.ClearSyncStatus(ctx); err != nil { + return fmt.Errorf("failed to reset sync status: %w", err) + } + gluonID, err := sm.imapServer.AddUser(ctx, connector, idProvider.GluonKey()) if err != nil { return fmt.Errorf("failed to add IMAP user: %w", err) From 4b95ef4d8219f1ce15d48d913b353bef9f55e695 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 9 Oct 2023 13:25:44 +0200 Subject: [PATCH 16/29] chore: Umshiang Bridge 3.5.2 changelog. --- Changelog.md | 7 +++++++ Makefile | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 5dc72bc3..d896445a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,13 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Umshiang Bridge 3.5.2 + +### Fixed +* GODT-3003: Ensure IMAP State is reset after vault corruption. +* GODT-3001: Only create system labels during system label sync. + + ## Umshiang Bridge 3.5.1 ### Fixed diff --git a/Makefile b/Makefile index ec68628a..b99c44b9 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.5.1+git +BRIDGE_APP_VERSION?=3.5.2+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From ba65ffdbc7e85a49262bfff15e96d06cc9dded10 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 9 Oct 2023 13:25:44 +0200 Subject: [PATCH 17/29] chore: Umshiang Bridge 3.5.2 changelog. --- Changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changelog.md b/Changelog.md index 5e4ba62d..e033fbb2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -33,6 +33,13 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Umshiang Bridge 3.5.2 + +### Fixed +* GODT-3003: Ensure IMAP State is reset after vault corruption. +* GODT-3001: Only create system labels during system label sync. + + ## Umshiang Bridge 3.5.1 ### Fixed From cf9651bb9498d025b1e1697b97d448ed74e267a7 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 6 Oct 2023 10:09:10 +0100 Subject: [PATCH 18/29] fix(GODT-3001): Only create system labels during system label sync --- internal/services/imapservice/sync_update_applier.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/services/imapservice/sync_update_applier.go b/internal/services/imapservice/sync_update_applier.go index 58230ae5..4ba043b1 100644 --- a/internal/services/imapservice/sync_update_applier.go +++ b/internal/services/imapservice/sync_update_applier.go @@ -119,6 +119,10 @@ func (s *SyncUpdateApplier) SyncSystemLabelsOnly(ctx context.Context, labels map continue } + if label.Type != proton.LabelTypeSystem { + continue + } + for _, c := range connectors { update := newSystemMailboxCreatedUpdate(imap.MailboxID(label.ID), label.Name) updates = append(updates, update) From bf244e5c863671bad0c131c515cf3b1c05622f68 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 6 Oct 2023 15:00:36 +0100 Subject: [PATCH 19/29] fix(GODT-3003): Ensure IMAP State is reset after vault corruption After we detect that the user has suffered the GODT-3003 bug due the vault corruption not ensuring that a previous sync state would be erased, we patch the gluon db directly and then reset the sync state. After the account is added, the sync is automatically triggered and the account state fixes itself. --- Makefile | 1 + go.mod | 2 +- go.sum | 4 +- internal/bridge/bridge_test.go | 2 +- internal/bridge/sync_test.go | 62 ++++++ internal/services/imapservice/connector.go | 71 +++++- .../services/imapservice/connector_test.go | 205 ++++++++++++++++++ internal/services/imapservice/mocks/mocks.go | 138 ++++++++++++ internal/services/imapservice/service.go | 6 +- .../imapservice/service_address_events.go | 1 + .../imapservice/sync_state_provider.go | 4 +- .../imapservice/sync_state_provider_test.go | 4 +- internal/services/imapsmtpserver/service.go | 5 + 13 files changed, 493 insertions(+), 12 deletions(-) create mode 100644 internal/services/imapservice/connector_test.go create mode 100644 internal/services/imapservice/mocks/mocks.go diff --git a/Makefile b/Makefile index 462ce114..0ae1998a 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ ApplyStageInput,BuildStageInput,BuildStageOutput,DownloadStageInput,DownloadStag StateProvider,Regulator,UpdateApplier,MessageBuilder,APIClient,Reporter,DownloadRateModifier \ > tmp mv tmp internal/services/syncservice/mocks_test.go + mockgen --package mocks github.com/ProtonMail/gluon/connector IMAPStateWrite > internal/services/imapservice/mocks/mocks.go lint: gofiles lint-golang lint-license lint-dependencies lint-changelog lint-bug-report diff --git a/go.mod b/go.mod index a1a498b0..fc5a08aa 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.17.1-0.20230911134257-5eb2eeebbef5 + github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230925123025-331ad8e6d5ee github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton diff --git a/go.sum b/go.sum index 4c9c029b..cb4e1e30 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.17.1-0.20230911134257-5eb2eeebbef5 h1:O4BusNL870VgVVDSUX2Oaz8A/fNtJhakUKwx0YBIdn8= -github.com/ProtonMail/gluon v0.17.1-0.20230911134257-5eb2eeebbef5/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= +github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c h1:gUDu4pOswgbou0QczfreNiXQFrmvVlpSh8Q+vft/JvI= +github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index acd0fd0c..6ce8b1bd 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -585,7 +585,7 @@ func TestBridge_MissingGluonStore(t *testing.T) { require.NoError(t, os.RemoveAll(gluonDir)) // Bridge starts but can't find the gluon store dir; there should be no error. - withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + withBridgeWaitForServers(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { // ... }) }) diff --git a/internal/bridge/sync_test.go b/internal/bridge/sync_test.go index 1d613bf3..07c0988a 100644 --- a/internal/bridge/sync_test.go +++ b/internal/bridge/sync_test.go @@ -37,6 +37,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" + "github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice" "github.com/bradenaw/juniper/iterator" "github.com/bradenaw/juniper/stream" "github.com/bradenaw/juniper/xslices" @@ -579,6 +580,67 @@ func TestBridge_MessageCreateDuringSync(t *testing.T) { }, server.WithTLS(false)) } +func TestBridge_CorruptedVaultClearsPreviousIMAPSyncState(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { + userID, addrID, err := s.CreateUser("imap", password) + require.NoError(t, err) + + labelID, err := s.CreateLabel(userID, "folder", "", proton.LabelTypeFolder) + require.NoError(t, err) + + withClient(ctx, t, s, "imap", password, func(ctx context.Context, c *proton.Client) { + createNumMessages(ctx, t, c, addrID, labelID, 100) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{})) + defer done() + + var err error + + userID, err = bridge.LoginFull(context.Background(), "imap", password, nil, nil) + require.NoError(t, err) + + // Wait for sync to finish + require.Equal(t, userID, (<-syncCh).UserID) + }) + + settingsPath, err := locator.ProvideSettingsPath() + require.NoError(t, err) + + syncConfigPath, err := locator.ProvideIMAPSyncConfigPath() + require.NoError(t, err) + + syncStatePath := imapservice.GetSyncConfigPath(syncConfigPath, userID) + // Check sync state is complete + { + state, err := imapservice.NewSyncState(syncStatePath) + require.NoError(t, err) + syncStatus, err := state.GetSyncStatus(context.Background()) + require.NoError(t, err) + require.True(t, syncStatus.IsComplete()) + } + + // corrupt the vault + require.NoError(t, os.WriteFile(filepath.Join(settingsPath, "vault.enc"), []byte("Trash!"), 0o600)) + + // Bridge starts but can't find the gluon database dir; there should be no error. + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + _, err := bridge.LoginFull(context.Background(), "imap", password, nil, nil) + require.NoError(t, err) + }) + + // Check sync state is reset. + { + state, err := imapservice.NewSyncState(syncStatePath) + require.NoError(t, err) + syncStatus, err := state.GetSyncStatus(context.Background()) + require.NoError(t, err) + require.False(t, syncStatus.IsComplete()) + } + }) +} + func withClient(ctx context.Context, t *testing.T, s *server.Server, username string, password []byte, fn func(context.Context, *proton.Client)) { //nolint:unparam m := proton.New( proton.WithHostURL(s.GetHostURL()), diff --git a/internal/services/imapservice/connector.go b/internal/services/imapservice/connector.go index 04ff2ab9..6e9dc031 100644 --- a/internal/services/imapservice/connector.go +++ b/internal/services/imapservice/connector.go @@ -63,6 +63,7 @@ type Connector struct { log *logrus.Entry sharedCache *SharedCache + syncState *SyncState } func NewConnector( @@ -75,6 +76,7 @@ func NewConnector( panicHandler async.PanicHandler, telemetry Telemetry, showAllMail bool, + syncState *SyncState, ) *Connector { userID := identityState.UserID() @@ -106,6 +108,7 @@ func NewConnector( }), sharedCache: NewSharedCached(), + syncState: syncState, } } @@ -114,9 +117,35 @@ func (s *Connector) StateClose() { s.updateCh.CloseAndDiscardQueued() } -func (s *Connector) Init(_ context.Context, cache connector.IMAPState) error { +func (s *Connector) Init(ctx context.Context, cache connector.IMAPState) error { s.sharedCache.Set(cache) - return nil + + return cache.Write(ctx, func(ctx context.Context, write connector.IMAPStateWrite) error { + rd := s.labels.Read() + defer rd.Close() + + mboxes, err := write.GetMailboxesWithoutAttrib(ctx) + if err != nil { + return err + } + + // Attempt to fix bug when a vault got corrupted, but the sync state did not get reset leading to + // all labels being written to the root level. If we detect this happened, reset the sync state. + { + applied, err := fixGODT3003Labels(ctx, s.log, mboxes, rd, write) + if err != nil { + return err + } + + if applied { + s.log.Debug("Patched folders/labels after GODT-3003 incident, resetting sync state.") + if err := s.syncState.ClearSyncStatus(ctx); err != nil { + return err + } + } + } + return nil + }) } func (s *Connector) Authorize(ctx context.Context, username string, password []byte) bool { @@ -745,3 +774,41 @@ func (s *Connector) createDraft(ctx context.Context, literal []byte, addrKR *cry func (s *Connector) publishUpdate(_ context.Context, update imap.Update) { s.updateCh.Enqueue(update) } + +func fixGODT3003Labels( + ctx context.Context, + log *logrus.Entry, + mboxes []imap.MailboxNoAttrib, + rd labelsRead, + write connector.IMAPStateWrite, +) (bool, error) { + var applied bool + for _, mbox := range mboxes { + lbl, ok := rd.GetLabel(string(mbox.ID)) + if !ok { + continue + } + + if lbl.Type == proton.LabelTypeFolder { + if mbox.Name[0] != folderPrefix { + log.WithField("labelID", mbox.ID.ShortID()).Debug("Found folder without prefix, patching") + if err := write.PatchMailboxHierarchyWithoutTransforms(ctx, mbox.ID, xslices.Insert(mbox.Name, 0, folderPrefix)); err != nil { + return false, fmt.Errorf("failed to update mailbox name: %w", err) + } + + applied = true + } + } else if lbl.Type == proton.LabelTypeLabel { + if mbox.Name[0] != labelPrefix { + log.WithField("labelID", mbox.ID.ShortID()).Debug("Found label without prefix, patching") + if err := write.PatchMailboxHierarchyWithoutTransforms(ctx, mbox.ID, xslices.Insert(mbox.Name, 0, labelPrefix)); err != nil { + return false, fmt.Errorf("failed to update mailbox name: %w", err) + } + + applied = true + } + } + } + + return applied, nil +} diff --git a/internal/services/imapservice/connector_test.go b/internal/services/imapservice/connector_test.go new file mode 100644 index 00000000..f79b885d --- /dev/null +++ b/internal/services/imapservice/connector_test.go @@ -0,0 +1,205 @@ +// 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 . + +package imapservice + +import ( + "context" + "testing" + + "github.com/ProtonMail/gluon/imap" + "github.com/ProtonMail/go-proton-api" + "github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice/mocks" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func TestFixGODT3003Labels(t *testing.T) { + mockCtrl := gomock.NewController(t) + + log := logrus.WithField("test", "test") + + sharedLabels := newRWLabels() + wr := sharedLabels.Write() + wr.SetLabel("foo", proton.Label{ + ID: "foo", + ParentID: "bar", + Name: "Foo", + Path: []string{"bar", "Foo"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("0", proton.Label{ + ID: "0", + ParentID: "", + Name: "Inbox", + Path: []string{"Inbox"}, + Color: "", + Type: proton.LabelTypeSystem, + }) + + wr.SetLabel("bar", proton.Label{ + ID: "bar", + ParentID: "", + Name: "boo", + Path: []string{"bar"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("my_label", proton.Label{ + ID: "my_label", + ParentID: "", + Name: "MyLabel", + Path: []string{"MyLabel"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + + wr.SetLabel("my_label2", proton.Label{ + ID: "my_label2", + ParentID: "", + Name: "MyLabel2", + Path: []string{labelPrefix, "MyLabel2"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + wr.Close() + + mboxs := []imap.MailboxNoAttrib{ + { + ID: "0", + Name: []string{"Inbox"}, + }, + { + ID: "bar", + Name: []string{"bar"}, + }, + { + ID: "foo", + Name: []string{"bar", "Foo"}, + }, + { + ID: "my_label", + Name: []string{"MyLabel"}, + }, + { + ID: "my_label2", + Name: []string{labelPrefix, "MyLabel2"}, + }, + } + + rd := sharedLabels.Read() + defer rd.Close() + + imapState := mocks.NewMockIMAPStateWrite(mockCtrl) + + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("bar")), gomock.Eq([]string{folderPrefix, "bar"})) + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("foo")), gomock.Eq([]string{folderPrefix, "bar", "Foo"})) + imapState.EXPECT().PatchMailboxHierarchyWithoutTransforms(gomock.Any(), gomock.Eq(imap.MailboxID("my_label")), gomock.Eq([]string{labelPrefix, "MyLabel"})) + + applied, err := fixGODT3003Labels(context.Background(), log, mboxs, rd, imapState) + require.NoError(t, err) + require.True(t, applied) +} + +func TestFixGODT3003Labels_Noop(t *testing.T) { + mockCtrl := gomock.NewController(t) + + log := logrus.WithField("test", "test") + + sharedLabels := newRWLabels() + wr := sharedLabels.Write() + wr.SetLabel("foo", proton.Label{ + ID: "foo", + ParentID: "bar", + Name: "Foo", + Path: []string{folderPrefix, "bar", "Foo"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("0", proton.Label{ + ID: "0", + ParentID: "", + Name: "Inbox", + Path: []string{"Inbox"}, + Color: "", + Type: proton.LabelTypeSystem, + }) + + wr.SetLabel("bar", proton.Label{ + ID: "bar", + ParentID: "", + Name: "bar", + Path: []string{folderPrefix, "bar"}, + Color: "", + Type: proton.LabelTypeFolder, + }) + + wr.SetLabel("my_label", proton.Label{ + ID: "my_label", + ParentID: "", + Name: "MyLabel", + Path: []string{labelPrefix, "MyLabel"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + + wr.SetLabel("my_label2", proton.Label{ + ID: "my_label2", + ParentID: "", + Name: "MyLabel2", + Path: []string{labelPrefix, "MyLabel2"}, + Color: "", + Type: proton.LabelTypeLabel, + }) + wr.Close() + + mboxs := []imap.MailboxNoAttrib{ + { + ID: "0", + Name: []string{"Inbox"}, + }, + { + ID: "bar", + Name: []string{folderPrefix, "bar"}, + }, + { + ID: "foo", + Name: []string{folderPrefix, "bar", "Foo"}, + }, + { + ID: "my_label", + Name: []string{labelPrefix, "MyLabel"}, + }, + { + ID: "my_label2", + Name: []string{labelPrefix, "MyLabel2"}, + }, + } + + rd := sharedLabels.Read() + defer rd.Close() + + imapState := mocks.NewMockIMAPStateWrite(mockCtrl) + applied, err := fixGODT3003Labels(context.Background(), log, mboxs, rd, imapState) + require.NoError(t, err) + require.False(t, applied) +} diff --git a/internal/services/imapservice/mocks/mocks.go b/internal/services/imapservice/mocks/mocks.go new file mode 100644 index 00000000..17e5b7cd --- /dev/null +++ b/internal/services/imapservice/mocks/mocks.go @@ -0,0 +1,138 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ProtonMail/gluon/connector (interfaces: IMAPStateWrite) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + imap "github.com/ProtonMail/gluon/imap" + gomock "github.com/golang/mock/gomock" +) + +// MockIMAPStateWrite is a mock of IMAPStateWrite interface. +type MockIMAPStateWrite struct { + ctrl *gomock.Controller + recorder *MockIMAPStateWriteMockRecorder +} + +// MockIMAPStateWriteMockRecorder is the mock recorder for MockIMAPStateWrite. +type MockIMAPStateWriteMockRecorder struct { + mock *MockIMAPStateWrite +} + +// NewMockIMAPStateWrite creates a new mock instance. +func NewMockIMAPStateWrite(ctrl *gomock.Controller) *MockIMAPStateWrite { + mock := &MockIMAPStateWrite{ctrl: ctrl} + mock.recorder = &MockIMAPStateWriteMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIMAPStateWrite) EXPECT() *MockIMAPStateWriteMockRecorder { + return m.recorder +} + +// CreateMailbox mocks base method. +func (m *MockIMAPStateWrite) CreateMailbox(arg0 context.Context, arg1 imap.Mailbox) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateMailbox", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateMailbox indicates an expected call of CreateMailbox. +func (mr *MockIMAPStateWriteMockRecorder) CreateMailbox(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateMailbox", reflect.TypeOf((*MockIMAPStateWrite)(nil).CreateMailbox), arg0, arg1) +} + +// GetMailboxCount mocks base method. +func (m *MockIMAPStateWrite) GetMailboxCount(arg0 context.Context) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMailboxCount", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMailboxCount indicates an expected call of GetMailboxCount. +func (mr *MockIMAPStateWriteMockRecorder) GetMailboxCount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMailboxCount", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetMailboxCount), arg0) +} + +// GetMailboxesWithoutAttrib mocks base method. +func (m *MockIMAPStateWrite) GetMailboxesWithoutAttrib(arg0 context.Context) ([]imap.MailboxNoAttrib, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMailboxesWithoutAttrib", arg0) + ret0, _ := ret[0].([]imap.MailboxNoAttrib) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMailboxesWithoutAttrib indicates an expected call of GetMailboxesWithoutAttrib. +func (mr *MockIMAPStateWriteMockRecorder) GetMailboxesWithoutAttrib(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMailboxesWithoutAttrib", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetMailboxesWithoutAttrib), arg0) +} + +// GetSettings mocks base method. +func (m *MockIMAPStateWrite) GetSettings(arg0 context.Context) (string, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSettings", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetSettings indicates an expected call of GetSettings. +func (mr *MockIMAPStateWriteMockRecorder) GetSettings(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSettings", reflect.TypeOf((*MockIMAPStateWrite)(nil).GetSettings), arg0) +} + +// PatchMailboxHierarchyWithoutTransforms mocks base method. +func (m *MockIMAPStateWrite) PatchMailboxHierarchyWithoutTransforms(arg0 context.Context, arg1 imap.MailboxID, arg2 []string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchMailboxHierarchyWithoutTransforms", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// PatchMailboxHierarchyWithoutTransforms indicates an expected call of PatchMailboxHierarchyWithoutTransforms. +func (mr *MockIMAPStateWriteMockRecorder) PatchMailboxHierarchyWithoutTransforms(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchMailboxHierarchyWithoutTransforms", reflect.TypeOf((*MockIMAPStateWrite)(nil).PatchMailboxHierarchyWithoutTransforms), arg0, arg1, arg2) +} + +// StoreSettings mocks base method. +func (m *MockIMAPStateWrite) StoreSettings(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoreSettings", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// StoreSettings indicates an expected call of StoreSettings. +func (mr *MockIMAPStateWriteMockRecorder) StoreSettings(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreSettings", reflect.TypeOf((*MockIMAPStateWrite)(nil).StoreSettings), arg0, arg1) +} + +// UpdateMessageFlags mocks base method. +func (m *MockIMAPStateWrite) UpdateMessageFlags(arg0 context.Context, arg1 imap.MessageID, arg2 imap.FlagSet) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateMessageFlags", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateMessageFlags indicates an expected call of UpdateMessageFlags. +func (mr *MockIMAPStateWriteMockRecorder) UpdateMessageFlags(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMessageFlags", reflect.TypeOf((*MockIMAPStateWrite)(nil).UpdateMessageFlags), arg0, arg1, arg2) +} diff --git a/internal/services/imapservice/service.go b/internal/services/imapservice/service.go index 701a62c6..79e4b9f0 100644 --- a/internal/services/imapservice/service.go +++ b/internal/services/imapservice/service.go @@ -158,7 +158,7 @@ func NewService( syncUpdateApplier: syncUpdateApplier, syncMessageBuilder: syncMessageBuilder, syncReporter: syncReporter, - syncConfigPath: getSyncConfigPath(syncConfigDir, identityState.User.ID), + syncConfigPath: GetSyncConfigPath(syncConfigDir, identityState.User.ID), } } @@ -498,6 +498,7 @@ func (s *Service) buildConnectors() (map[string]*Connector, error) { s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) return connectors, nil @@ -514,6 +515,7 @@ func (s *Service) buildConnectors() (map[string]*Connector, error) { s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) } @@ -644,6 +646,6 @@ type setAddressModeReq struct { type getSyncFailedMessagesReq struct{} -func getSyncConfigPath(path string, userID string) string { +func GetSyncConfigPath(path string, userID string) string { return filepath.Join(path, fmt.Sprintf("sync-%v", userID)) } diff --git a/internal/services/imapservice/service_address_events.go b/internal/services/imapservice/service_address_events.go index 2c5aed9c..78abe4a3 100644 --- a/internal/services/imapservice/service_address_events.go +++ b/internal/services/imapservice/service_address_events.go @@ -128,6 +128,7 @@ func addNewAddressSplitMode(ctx context.Context, s *Service, addrID string) erro s.panicHandler, s.telemetry, s.showAllMail, + s.syncStateProvider, ) if err := s.serverManager.AddIMAPUser(ctx, connector, connector.addrID, s.gluonIDProvider, s.syncStateProvider); err != nil { diff --git a/internal/services/imapservice/sync_state_provider.go b/internal/services/imapservice/sync_state_provider.go index 190d67a5..9b3723d2 100644 --- a/internal/services/imapservice/sync_state_provider.go +++ b/internal/services/imapservice/sync_state_provider.go @@ -220,7 +220,7 @@ func (s *SyncState) loadUnsafe() error { } func DeleteSyncState(configDir, userID string) error { - path := getSyncConfigPath(configDir, userID) + path := GetSyncConfigPath(configDir, userID) if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) { return err @@ -234,7 +234,7 @@ func MigrateVaultSettings( hasLabels, hasMessages bool, failedMessageIDs []string, ) (bool, error) { - filePath := getSyncConfigPath(configDir, userID) + filePath := GetSyncConfigPath(configDir, userID) _, err := os.ReadFile(filePath) //nolint:gosec if err == nil { diff --git a/internal/services/imapservice/sync_state_provider_test.go b/internal/services/imapservice/sync_state_provider_test.go index 0852c53f..e4dd93b7 100644 --- a/internal/services/imapservice/sync_state_provider_test.go +++ b/internal/services/imapservice/sync_state_provider_test.go @@ -29,7 +29,7 @@ import ( func TestMigrateSyncSettings_AlreadyExists(t *testing.T) { tmpDir := t.TempDir() - testFile := getSyncConfigPath(tmpDir, "test") + testFile := GetSyncConfigPath(tmpDir, "test") expected, err := generateTestState(testFile) require.NoError(t, err) @@ -53,7 +53,7 @@ func TestMigrateSyncSettings_DoesNotExist(t *testing.T) { require.NoError(t, err) require.True(t, migrated) - state, err := NewSyncState(getSyncConfigPath(tmpDir, "test")) + state, err := NewSyncState(GetSyncConfigPath(tmpDir, "test")) require.NoError(t, err) status, err := state.GetSyncStatus(context.Background()) require.NoError(t, err) diff --git a/internal/services/imapsmtpserver/service.go b/internal/services/imapsmtpserver/service.go index de186eb9..f2e22176 100644 --- a/internal/services/imapsmtpserver/service.go +++ b/internal/services/imapsmtpserver/service.go @@ -390,6 +390,11 @@ func (sm *Service) handleAddIMAPUserImpl(ctx context.Context, } else { log.Info("Creating new IMAP user") + // GODT-3003: Ensure previous IMAP sync state is cleared if we run into code path after vault corruption. + if err := syncStateProvider.ClearSyncStatus(ctx); err != nil { + return fmt.Errorf("failed to reset sync status: %w", err) + } + gluonID, err := sm.imapServer.AddUser(ctx, connector, idProvider.GluonKey()) if err != nil { return fmt.Errorf("failed to add IMAP user: %w", err) From 275b30e51810be24c4f15a2d8a16269bfd0fa594 Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 10 Oct 2023 11:29:36 +0200 Subject: [PATCH 20/29] chore: Vasco da Gama Bridge 3.6.0 changelog. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index e033fbb2..8a35fc7e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) + ## Vasco da Gama Bridge 3.6.0 ### Added From 94b44b383ae8a714e6391fec2ea5df13fc28ea3f Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 10 Oct 2023 15:48:30 +0200 Subject: [PATCH 21/29] feat(GODT-3004): update gopenpgp and dependencies. --- go.mod | 6 +++--- go.sum | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index af219a1a..e21f548e 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36 - github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton + github.com/ProtonMail/go-proton-api v0.4.1-0.20231011062329-f3b976b7dbca + github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 @@ -52,7 +52,7 @@ require ( require ( github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233 // indirect github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/go-srp v0.0.7 // indirect github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect diff --git a/go.sum b/go.sum index 7a1236b5..4a0bebe5 100644 --- a/go.sum +++ b/go.sum @@ -28,19 +28,18 @@ github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c/go.mod h1:Og5/ github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= -github.com/ProtonMail/go-crypto v0.0.0-20230322105811-d73448b7e800/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= +github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233 h1:bdoKdh0f66/lrgVfYlxw0aqISY/KOqXmFJyGt7rGmnc= +github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7 h1:+j+Kd/DyZ/qGfMT9htAT7HxqIEbZHsatsx+m8AoV6fc= 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.20230831064234-0e3a549b3f36 h1:JVMK2w90bCWayUCXJIb3wkQ5+j2P/NbnrX3BrDoLzsc= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230831064234-0e3a549b3f36/go.mod h1:nS8hMGjJLgC0Iej0JMYbsI388LesEkM1Hj/jCCxQeaQ= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231011062329-f3b976b7dbca h1:nO/xuvyEgWWLo2cBAqfxCHh7Ri0ofV3PXnTOfk0QcyI= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231011062329-f3b976b7dbca/go.mod h1:IGVXKy6NLHt4WeWiOnAFmSsXRpd6elkjDZMtr5vBLJ8= github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk= -github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton h1:YS6M20yvjCJPR1r4ADW5TPn6rahs4iAyZaACei86bEc= -github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton/go.mod h1:S1lYsaGHykYpxxh2SnJL6ypcAlANKj5NRSY6HxKryKQ= +github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton h1:wuAxBUU9qF2wyDVJprn/2xPDx000eol5gwlKbOUYY88= +github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton/go.mod h1:omVkSsfPAhmptzPF/piMXb16wKIWUvVhZbVW7sJKh0A= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= @@ -64,6 +63,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/bradenaw/juniper v0.12.0 h1:Q/7icpPQD1nH/La5DobQfNEtwyrBSiSu47jOQx7lJEM= github.com/bradenaw/juniper v0.12.0/go.mod h1:Z2B7aJlQ7xbfWsnMLROj5t/5FQ94/MkIdKC30J4WvzI= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -417,6 +417,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= @@ -464,6 +465,7 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= @@ -512,6 +514,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -519,6 +523,7 @@ golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= @@ -529,6 +534,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= From 01043e033e5b2fc848dc1a4638b993a1cd040f68 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 11 Oct 2023 08:37:28 +0200 Subject: [PATCH 22/29] chore: Umshiang Bridge 3.5.3 changelog. --- Changelog.md | 6 ++++++ Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index d896445a..13df6ffa 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,12 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Umshiang Bridge 3.5.3 + +### Changed +* GODT-3004: Update gopenpgp and dependencies. + + ## Umshiang Bridge 3.5.2 ### Fixed diff --git a/Makefile b/Makefile index b99c44b9..14dd0298 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.5.2+git +BRIDGE_APP_VERSION?=3.5.3+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From e580f89106e8efcb6aa6ea9c4cc1480edd75c6fd Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 11 Oct 2023 15:29:52 +0200 Subject: [PATCH 23/29] feat(GODT-3004): update gopenpgp and dependencies. --- go.mod | 6 +++--- go.sum | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index fc5a08aa..b6f6097d 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230925123025-331ad8e6d5ee - github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton + github.com/ProtonMail/go-proton-api v0.4.1-0.20231011132529-24b5b817ee1f + github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 @@ -53,7 +53,7 @@ require ( require ( github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233 // indirect github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/go-srp v0.0.7 // indirect github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect diff --git a/go.sum b/go.sum index cb4e1e30..157d4409 100644 --- a/go.sum +++ b/go.sum @@ -28,19 +28,18 @@ github.com/ProtonMail/gluon v0.17.1-0.20231009084701-3af0474b0b3c/go.mod h1:Og5/ github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= -github.com/ProtonMail/go-crypto v0.0.0-20230322105811-d73448b7e800/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= +github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233 h1:bdoKdh0f66/lrgVfYlxw0aqISY/KOqXmFJyGt7rGmnc= +github.com/ProtonMail/go-crypto v0.0.0-20230717121622-edf196117233/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7 h1:+j+Kd/DyZ/qGfMT9htAT7HxqIEbZHsatsx+m8AoV6fc= 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.20230925123025-331ad8e6d5ee h1:CzFXOiflEZZqT3HQqj2I5AkIprRbc/c6/lToPdEKzxM= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230925123025-331ad8e6d5ee/go.mod h1:Y3ea3i1UbqHz5vq43odmAAd6lmR4nx0ZIQ32tqMfxTY= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231011132529-24b5b817ee1f h1:n0oBMAz2dJhn5+1WA6NrjkWqkZN+22FQMkPlRwNGhpU= +github.com/ProtonMail/go-proton-api v0.4.1-0.20231011132529-24b5b817ee1f/go.mod h1:ZmvQMA8hanLiD1tFsvu9+qGBcuxbIRfch/4z/nqBhXA= github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI= github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk= -github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton h1:YS6M20yvjCJPR1r4ADW5TPn6rahs4iAyZaACei86bEc= -github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton/go.mod h1:S1lYsaGHykYpxxh2SnJL6ypcAlANKj5NRSY6HxKryKQ= +github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton h1:wuAxBUU9qF2wyDVJprn/2xPDx000eol5gwlKbOUYY88= +github.com/ProtonMail/gopenpgp/v2 v2.7.3-proton/go.mod h1:omVkSsfPAhmptzPF/piMXb16wKIWUvVhZbVW7sJKh0A= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= @@ -64,6 +63,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/bradenaw/juniper v0.12.0 h1:Q/7icpPQD1nH/La5DobQfNEtwyrBSiSu47jOQx7lJEM= github.com/bradenaw/juniper v0.12.0/go.mod h1:Z2B7aJlQ7xbfWsnMLROj5t/5FQ94/MkIdKC30J4WvzI= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -419,6 +419,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= @@ -466,6 +467,7 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= @@ -514,6 +516,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -521,6 +525,7 @@ golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= @@ -531,6 +536,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= From 8be4246f7e261322651a528fcdbe8a9e8c87cb81 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 11 Oct 2023 16:09:55 +0200 Subject: [PATCH 24/29] chore: Vasco da Gama Bridge 3.6.0 changelog. --- Changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog.md b/Changelog.md index 8a35fc7e..e2f7059f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -33,6 +33,11 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) * GODT-2929: Message dedup with different text transfer encoding. +## Umshiang Bridge 3.5.3 + +### Changed +* GODT-3004: Update gopenpgp and dependencies. + ## Umshiang Bridge 3.5.2 From 8b12a454eaa2c30638446b7c46ded4aa6654ede1 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 18 Oct 2023 14:29:27 +0200 Subject: [PATCH 25/29] fix(GODT-3033): Unable to receive new mail If the IMAP service happened to finish syncing and wanted to reset the user event service at a time the latter was publishing an event a deadlock would occur and the user would not receive any new messages. This change puts the request to revert the event id in a separate go-routine to avoid this situation from re-occurring. The operational flow remains unchanged as the event service will only process this request once the current set of events have been published. --- internal/services/imapservice/service.go | 42 ++++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/internal/services/imapservice/service.go b/internal/services/imapservice/service.go index 79e4b9f0..0ccbeced 100644 --- a/internal/services/imapservice/service.go +++ b/internal/services/imapservice/service.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "path/filepath" + "sync/atomic" "time" "github.com/ProtonMail/gluon/async" @@ -94,7 +95,7 @@ type Service struct { syncConfigPath string lastHandledEventID string - isSyncing bool + isSyncing atomic.Bool } func NewService( @@ -405,23 +406,28 @@ func (s *Service) run(ctx context.Context) { //nolint gocyclo continue } + // Start a goroutine to wait on event reset as it is possible that the sync received message + // was processed during an event publish. This in turn will block the imap service, since the + // event service is unable to reply to the request until the events have been processed. s.log.Info("Sync complete, starting API event stream") - if err := s.eventProvider.RewindEventID(ctx, s.lastHandledEventID); err != nil { - if errors.Is(err, context.Canceled) { - continue + go func() { + if err := s.eventProvider.RewindEventID(ctx, s.lastHandledEventID); err != nil { + if errors.Is(err, context.Canceled) { + return + } + + s.log.WithError(err).Error("Failed to rewind event service") + s.eventPublisher.PublishEvent(ctx, events.UserBadEvent{ + UserID: s.identityState.UserID(), + OldEventID: "", + NewEventID: "", + EventInfo: "", + Error: fmt.Errorf("failed to rewind event loop: %w", err), + }) } - s.log.WithError(err).Error("Failed to rewind event service") - s.eventPublisher.PublishEvent(ctx, events.UserBadEvent{ - UserID: s.identityState.UserID(), - OldEventID: "", - NewEventID: "", - EventInfo: "", - Error: fmt.Errorf("failed to rewind event loop: %w", err), - }) - } - - s.isSyncing = false + s.isSyncing.Store(false) + }() } case request, ok := <-s.syncUpdateApplier.requestCh: @@ -443,7 +449,7 @@ func (s *Service) run(ctx context.Context) { //nolint gocyclo continue } e.Consume(func(event proton.Event) error { - if s.isSyncing { + if s.isSyncing.Load() { if err := syncEventHandler.OnEvent(ctx, event); err != nil { return err } @@ -615,13 +621,13 @@ func (s *Service) setShowAllMail(v bool) { } func (s *Service) startSyncing() { - s.isSyncing = true + s.isSyncing.Store(true) s.syncHandler.Execute(s.syncReporter, s.labels.GetLabelMap(), s.syncUpdateApplier, s.syncMessageBuilder, syncservice.DefaultRetryCoolDown) } func (s *Service) cancelSync() { s.syncHandler.CancelAndWait() - s.isSyncing = false + s.isSyncing.Store(false) } type resyncReq struct{} From 248fbf5e33edd623f4d44b319dff4927d63a8d50 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 18 Oct 2023 15:41:01 +0200 Subject: [PATCH 26/29] chore: Vasco da Gama Bridge 3.6.1 changelog. --- Changelog.md | 6 ++++++ Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index e2f7059f..855d228e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,12 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Vasco da Gama Bridge 3.6.1 + +### Fixed +* GODT-3033: Unable to receive new mail. + + ## Vasco da Gama Bridge 3.6.0 ### Added diff --git a/Makefile b/Makefile index 0ae1998a..21d1087a 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.6.0+git +BRIDGE_APP_VERSION?=3.6.1+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From 097d6f86d31baf6358500f41d5ed4d92b66e5924 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 2 Feb 2024 17:34:32 +0100 Subject: [PATCH 27/29] fix(GODT-3235): update bridge update key --- internal/updater/key_default.go | 265 ++++++++++++++++---------------- 1 file changed, 132 insertions(+), 133 deletions(-) diff --git a/internal/updater/key_default.go b/internal/updater/key_default.go index 81baef8a..66cd635f 100644 --- a/internal/updater/key_default.go +++ b/internal/updater/key_default.go @@ -32,137 +32,136 @@ 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 -00IsXQemR6I8Qw== -=QiAL +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 +=I7Pt -----END PGP PUBLIC KEY BLOCK-----` From d65d6ee2e55560931790b601dc9a7226ed707147 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 2 Feb 2024 18:37:38 +0100 Subject: [PATCH 28/29] fix(GODT-3235): use release xikou for trigger build --- ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index d4eb7839..88107307 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -65,5 +65,5 @@ trigger-qa-installer: SRC_HASH: $CI_COMMIT_SHA trigger: project: "jcuth/bridge-release" - branch: master + branch: release/xikou From 495124440077cb6b4629b89936c89815962a6ec9 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 2 Feb 2024 19:32:58 +0100 Subject: [PATCH 29/29] chore: Xikou Bridge 3.8.2 changelog. --- Changelog.md | 6 ++++++ Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 64f7183e..be0cd045 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,12 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## Xikou Bridge 3.8.2 + +### Fixed +* GODT-3235: Update bridge update key. + + ## Xikou Bridge 3.8.1 ### Added diff --git a/Makefile b/Makefile index 9b381d3a..5130e681 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.8.1+git +BRIDGE_APP_VERSION?=3.8.2+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG