From eb62056755030b6b2d3774bbe2365b0646c49df8 Mon Sep 17 00:00:00 2001 From: James Houlahan Date: Mon, 21 Nov 2022 17:12:31 +0100 Subject: [PATCH] GODT-2119: Only show supported label IDs to clients --- internal/user/events.go | 13 ++++----- internal/user/sync.go | 58 ++++++++++++++++++++++++++++++------- internal/user/sync_build.go | 13 +++++---- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/internal/user/events.go b/internal/user/events.go index a0b0b474..e4563a0a 100644 --- a/internal/user/events.go +++ b/internal/user/events.go @@ -28,7 +28,6 @@ import ( "github.com/ProtonMail/proton-bridge/v2/internal/logging" "github.com/ProtonMail/proton-bridge/v2/internal/safe" "github.com/ProtonMail/proton-bridge/v2/internal/vault" - "github.com/bradenaw/juniper/xslices" "github.com/sirupsen/logrus" "gitlab.protontech.ch/go/liteapi" ) @@ -437,7 +436,7 @@ func (user *User) handleCreateMessageEvent(ctx context.Context, event liteapi.Me }).Info("Handling message created event") return withAddrKR(user.apiUser, user.apiAddrs[event.Message.AddressID], user.vault.KeyPass(), func(_, addrKR *crypto.KeyRing) error { - buildRes, err := buildRFC822(full, addrKR) + buildRes, err := buildRFC822(user.apiLabels, full, addrKR) if err != nil { return fmt.Errorf("failed to build RFC822 message: %w", err) } @@ -446,7 +445,7 @@ func (user *User) handleCreateMessageEvent(ctx context.Context, event liteapi.Me return nil }) - }, user.apiUserLock, user.apiAddrsLock, user.updateChLock) + }, user.apiUserLock, user.apiAddrsLock, user.apiLabelsLock, user.updateChLock) } func (user *User) handleUpdateMessageEvent(ctx context.Context, event liteapi.MessageEvent) error { //nolint:unparam @@ -458,13 +457,13 @@ func (user *User) handleUpdateMessageEvent(ctx context.Context, event liteapi.Me user.updateCh[event.Message.AddressID].Enqueue(imap.NewMessageMailboxesUpdated( imap.MessageID(event.ID), - mapTo[string, imap.MailboxID](xslices.Filter(event.Message.LabelIDs, wantLabelID)), + mapTo[string, imap.MailboxID](wantLabels(user.apiLabels, event.Message.LabelIDs)), event.Message.Seen(), event.Message.Starred(), )) return nil - }, user.updateChLock) + }, user.apiLabelsLock, user.updateChLock) } func (user *User) handleDeleteMessageEvent(ctx context.Context, event liteapi.MessageEvent) error { //nolint:unparam @@ -492,7 +491,7 @@ func (user *User) handleUpdateDraftEvent(ctx context.Context, event liteapi.Mess } return withAddrKR(user.apiUser, user.apiAddrs[event.Message.AddressID], user.vault.KeyPass(), func(_, addrKR *crypto.KeyRing) error { - buildRes, err := buildRFC822(full, addrKR) + buildRes, err := buildRFC822(user.apiLabels, full, addrKR) if err != nil { return fmt.Errorf("failed to build RFC822 draft: %w", err) } @@ -506,7 +505,7 @@ func (user *User) handleUpdateDraftEvent(ctx context.Context, event liteapi.Mess return nil }) - }, user.apiUserLock, user.apiAddrsLock, user.updateChLock) + }, user.apiUserLock, user.apiAddrsLock, user.apiLabelsLock, user.updateChLock) } func getMailboxName(label liteapi.Label) []string { diff --git a/internal/user/sync.go b/internal/user/sync.go index 0e06da70..c0ef6403 100644 --- a/internal/user/sync.go +++ b/internal/user/sync.go @@ -113,6 +113,7 @@ func (user *User) sync(ctx context.Context) error { user.ID(), user.client, user.vault, + user.apiLabels, addrKRs, user.updateCh, user.eventCh, @@ -147,12 +148,14 @@ func syncLabels(ctx context.Context, apiLabels map[string]liteapi.Label, updateC // Sync the user's labels. for labelID, label := range apiLabels { + if !wantLabel(label) { + continue + } + switch label.Type { case liteapi.LabelTypeSystem: - if wantLabelID(labelID) { - for _, updateCh := range updateCh { - updateCh.Enqueue(newSystemMailboxCreatedUpdate(imap.MailboxID(label.ID), label.Name)) - } + for _, updateCh := range updateCh { + updateCh.Enqueue(newSystemMailboxCreatedUpdate(imap.MailboxID(label.ID), label.Name)) } case liteapi.LabelTypeFolder, liteapi.LabelTypeLabel: @@ -181,6 +184,7 @@ func syncMessages( //nolint:funlen userID string, client *liteapi.Client, vault *vault.User, + apiLabels map[string]liteapi.Label, addrKRs map[string]*crypto.KeyRing, updateCh map[string]*queue.QueuedChannel[imap.Update], eventCh *queue.QueuedChannel[events.Event], @@ -196,7 +200,7 @@ func syncMessages( //nolint:funlen buildCh := stream.Map( client.GetFullMessages(ctx, syncWorkers, syncBuffer, messageIDs...), func(_ context.Context, full liteapi.FullMessage) (*buildRes, error) { - return buildRFC822(full, addrKRs[full.AddressID]) + return buildRFC822(apiLabels, full, addrKRs[full.AddressID]) }, ) @@ -293,14 +297,46 @@ func newMailboxCreatedUpdate(labelID imap.MailboxID, labelName []string) *imap.M }) } -func wantLabelID(labelID string) bool { - switch labelID { - case liteapi.AllDraftsLabel, liteapi.AllSentLabel, liteapi.OutboxLabel: - return false - - default: +func wantLabel(label liteapi.Label) bool { + if label.Type != liteapi.LabelTypeSystem { return true } + + // nolint:exhaustive + switch label.ID { + case liteapi.InboxLabel: + return true + + case liteapi.TrashLabel: + return true + + case liteapi.SpamLabel: + return true + + case liteapi.AllMailLabel: + return true + + case liteapi.ArchiveLabel: + return true + + case liteapi.SentLabel: + return true + + case liteapi.DraftsLabel: + return true + + case liteapi.StarredLabel: + return true + + default: + return false + } +} + +func wantLabels(apiLabels map[string]liteapi.Label, labelIDs []string) []string { + return xslices.Filter(labelIDs, func(labelID string) bool { + return wantLabel(apiLabels[labelID]) + }) } func forEach[T any](ctx context.Context, streamer stream.Stream[T], fn func(T) error) error { diff --git a/internal/user/sync_build.go b/internal/user/sync_build.go index 78f5d626..b007d9fd 100644 --- a/internal/user/sync_build.go +++ b/internal/user/sync_build.go @@ -23,7 +23,6 @@ import ( "github.com/ProtonMail/gluon/imap" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/proton-bridge/v2/pkg/message" - "github.com/bradenaw/juniper/xslices" "gitlab.protontech.ch/go/liteapi" ) @@ -44,13 +43,13 @@ func defaultJobOpts() message.JobOptions { } } -func buildRFC822(full liteapi.FullMessage, addrKR *crypto.KeyRing) (*buildRes, error) { +func buildRFC822(apiLabels map[string]liteapi.Label, full liteapi.FullMessage, addrKR *crypto.KeyRing) (*buildRes, error) { literal, err := message.BuildRFC822(addrKR, full.Message, full.AttData, defaultJobOpts()) if err != nil { return nil, fmt.Errorf("failed to build message %s: %w", full.ID, err) } - update, err := newMessageCreatedUpdate(full.MessageMetadata, literal) + update, err := newMessageCreatedUpdate(apiLabels, full.MessageMetadata, literal) if err != nil { return nil, fmt.Errorf("failed to create IMAP update for message %s: %w", full.ID, err) } @@ -62,7 +61,11 @@ func buildRFC822(full liteapi.FullMessage, addrKR *crypto.KeyRing) (*buildRes, e }, nil } -func newMessageCreatedUpdate(message liteapi.MessageMetadata, literal []byte) (*imap.MessageCreated, error) { +func newMessageCreatedUpdate( + apiLabels map[string]liteapi.Label, + message liteapi.MessageMetadata, + literal []byte, +) (*imap.MessageCreated, error) { parsedMessage, err := imap.NewParsedMessage(literal) if err != nil { return nil, err @@ -71,7 +74,7 @@ func newMessageCreatedUpdate(message liteapi.MessageMetadata, literal []byte) (* return &imap.MessageCreated{ Message: toIMAPMessage(message), Literal: literal, - MailboxIDs: mapTo[string, imap.MailboxID](xslices.Filter(message.LabelIDs, wantLabelID)), + MailboxIDs: mapTo[string, imap.MailboxID](wantLabels(apiLabels, message.LabelIDs)), ParsedMessage: parsedMessage, }, nil }