mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 12:46:46 +00:00
feat(GODT-1264): constraint on Scheduled mailbox in connector + Integration tests.
This commit is contained in:
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
||||
github.com/Masterminds/semver/v3 v3.1.1
|
||||
github.com/ProtonMail/gluon v0.14.2-0.20230207142445-9f98ae47a031
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||
github.com/ProtonMail/go-proton-api v0.4.0
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1
|
||||
github.com/ProtonMail/go-rfc5322 v0.11.0
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.4.10
|
||||
github.com/PuerkitoBio/goquery v1.8.0
|
||||
|
||||
6
go.sum
6
go.sum
@ -41,8 +41,10 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NB
|
||||
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f h1:4IWzKjHzZxdrW9k4zl/qCwenOVHDbVDADPPHFLjs0Oc=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM=
|
||||
github.com/ProtonMail/go-proton-api v0.4.0 h1:Tw8Ieuc355ljPqpIzh/uttpE+5ia0z8GA/ca5iyl/9w=
|
||||
github.com/ProtonMail/go-proton-api v0.4.0/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214112101-944a29edf66a h1:/31/wWgxpBWREaRGRMVH4AVgQGpPtTK9BsLjt1a8uwc=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214112101-944a29edf66a/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1 h1:AjdiuiUwDz9ADIzEccii+D91YYz0w0doGXZs12j4XcY=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos=
|
||||
github.com/ProtonMail/go-rfc5322 v0.11.0 h1:o5Obrm4DpmQEffvgsVqG6S4BKwC1Wat+hYwjIp2YcCY=
|
||||
github.com/ProtonMail/go-rfc5322 v0.11.0/go.mod h1:6oOKr0jXvpoE6pwTx/HukigQpX2J9WUf6h0auplrFTw=
|
||||
github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg=
|
||||
|
||||
@ -24,7 +24,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@ -44,8 +43,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const scheduled = "Scheduled"
|
||||
|
||||
func TestBridge_Sync(t *testing.T) {
|
||||
numMsg := 1 << 8
|
||||
|
||||
@ -471,45 +468,3 @@ func countBytesRead(ctl *proton.NetCtl, fn func()) uint64 {
|
||||
|
||||
return read
|
||||
}
|
||||
|
||||
func TestBridge_ScheduledLabel(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
hasScheduledSystemLabel := func(imapClient *client.Client) bool {
|
||||
return xslices.Any(clientList(imapClient), func(mailboxInfo *imap.MailboxInfo) bool { return mailboxInfo.Name == scheduled })
|
||||
}
|
||||
|
||||
_, _, err := s.CreateUser(username, password)
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(b *bridge.Bridge, _ *bridge.Mocks) {
|
||||
// Perform initial sync
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
userID, err := b.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, userID, (<-syncCh).UserID)
|
||||
|
||||
// connect an IMAP client
|
||||
info, err := b.GetUserInfo(userID)
|
||||
require.NoError(t, err)
|
||||
imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Login(info.Addresses[0], string(info.BridgePass)))
|
||||
defer func() { _ = imapClient.Logout() }()
|
||||
|
||||
// Scheduled mailbox is empty. It's not listed.
|
||||
require.False(t, hasScheduledSystemLabel(imapClient))
|
||||
|
||||
// Add a message to the Schedule mailbox. It's now listed.
|
||||
require.NoError(t, imapClient.Append(scheduled, []string{}, time.Now(), strings.NewReader("To: no_reply@pm.me")))
|
||||
require.True(t, hasScheduledSystemLabel(imapClient))
|
||||
|
||||
// delete message from Scheduled. The mailbox is now empty and not listed anymore
|
||||
_, err = imapClient.Select(scheduled, false)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, clientStore(imapClient, 1, 1, true, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag))
|
||||
require.NoError(t, imapClient.Expunge(nil))
|
||||
require.False(t, hasScheduledSystemLabel(imapClient))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -380,7 +380,7 @@ func (conn *imapConnector) GetMessageLiteral(ctx context.Context, id imap.Messag
|
||||
func (conn *imapConnector) AddMessagesToMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
|
||||
defer conn.goPollAPIEvents(false)
|
||||
|
||||
if mailboxID == proton.AllMailLabel {
|
||||
if isAllMailOrScheduled(mailboxID) {
|
||||
return fmt.Errorf("not allowed")
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ func (conn *imapConnector) AddMessagesToMailbox(ctx context.Context, messageIDs
|
||||
func (conn *imapConnector) RemoveMessagesFromMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
|
||||
defer conn.goPollAPIEvents(false)
|
||||
|
||||
if mailboxID == proton.AllMailLabel {
|
||||
if isAllMailOrScheduled(mailboxID) {
|
||||
return fmt.Errorf("not allowed")
|
||||
}
|
||||
|
||||
@ -440,8 +440,8 @@ func (conn *imapConnector) MoveMessages(ctx context.Context, messageIDs []imap.M
|
||||
|
||||
if (labelFromID == proton.InboxLabel && labelToID == proton.SentLabel) ||
|
||||
(labelFromID == proton.SentLabel && labelToID == proton.InboxLabel) ||
|
||||
labelFromID == proton.AllMailLabel ||
|
||||
labelToID == proton.AllMailLabel {
|
||||
isAllMailOrScheduled(labelFromID) ||
|
||||
isAllMailOrScheduled(labelToID) {
|
||||
return false, fmt.Errorf("not allowed")
|
||||
}
|
||||
|
||||
@ -691,3 +691,7 @@ func toIMAPMailbox(label proton.Label, flags, permFlags, attrs imap.FlagSet) ima
|
||||
Attributes: attrs,
|
||||
}
|
||||
}
|
||||
|
||||
func isAllMailOrScheduled(mailboxID imap.MailboxID) bool {
|
||||
return (mailboxID == proton.AllMailLabel) || (mailboxID == proton.AllScheduledLabel)
|
||||
}
|
||||
|
||||
@ -36,4 +36,27 @@ Feature: IMAP list mailboxes
|
||||
Then IMAP client "1" counts 20 mailboxes under "Folders"
|
||||
And IMAP client "1" counts 60 mailboxes under "Labels"
|
||||
Then IMAP client "2" counts 20 mailboxes under "Folders"
|
||||
And IMAP client "2" counts 60 mailboxes under "Labels"
|
||||
And IMAP client "2" counts 60 mailboxes under "Labels"
|
||||
|
||||
Scenario: List with scheduled mail
|
||||
Given there exists an account with username "[user:user]" and password "password"
|
||||
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Scheduled":
|
||||
| from | to | subject | unread |
|
||||
| john.doe@mail.com | [user:user]@[domain] | sch | false |
|
||||
When bridge starts
|
||||
And the user logs in with username "[user:user]" and password "password"
|
||||
And user "[user:user]" finishes syncing
|
||||
And user "[user:user]" connects and authenticates IMAP client "1"
|
||||
Then IMAP client "1" eventually sees the following mailbox info:
|
||||
| name | total |
|
||||
| INBOX | 0 |
|
||||
| Drafts | 0 |
|
||||
| Sent | 0 |
|
||||
| Starred | 0 |
|
||||
| Archive | 0 |
|
||||
| Spam | 0 |
|
||||
| Trash | 0 |
|
||||
| All Mail | 1 |
|
||||
| Folders | 0 |
|
||||
| Labels | 0 |
|
||||
| Scheduled | 1 |
|
||||
|
||||
@ -6,6 +6,7 @@ Feature: IMAP remove messages from mailbox
|
||||
| mbox | folder |
|
||||
| label | label |
|
||||
And the address "[user:user]@[domain]" of account "[user:user]" has 10 messages in "Folders/mbox"
|
||||
And the address "[user:user]@[domain]" of account "[user:user]" has 1 messages in "Scheduled"
|
||||
And bridge starts
|
||||
And the user logs in with username "[user:user]" and password "password"
|
||||
And user "[user:user]" finishes syncing
|
||||
@ -44,4 +45,11 @@ Feature: IMAP remove messages from mailbox
|
||||
And IMAP client "1" marks message 2 as deleted
|
||||
And it succeeds
|
||||
And IMAP client "1" expunges
|
||||
Then it fails
|
||||
Then it fails
|
||||
|
||||
Scenario: Not possible to delete from Scheduled and expunge does nothing
|
||||
When IMAP client "1" selects "Scheduled"
|
||||
And IMAP client "1" marks message 1 as deleted
|
||||
Then it succeeds
|
||||
And IMAP client "1" expunges
|
||||
Then it fails
|
||||
|
||||
@ -16,6 +16,9 @@ Feature: IMAP move messages
|
||||
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Sent":
|
||||
| from | to | subject | unread |
|
||||
| john.doe@mail.com | [user:user]@[domain] | bax | false |
|
||||
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Scheduled":
|
||||
| from | to | subject | unread |
|
||||
| john.doe@mail.com | [user:user]@[domain] | sch | false |
|
||||
And bridge starts
|
||||
And the user logs in with username "[user:user]" and password "password"
|
||||
And user "[user:user]" finishes syncing
|
||||
@ -96,8 +99,17 @@ Feature: IMAP move messages
|
||||
| jane.doe@mail.com | name@[domain] | bar | true |
|
||||
| john.doe@mail.com | [user:user]@[domain] | baz | false |
|
||||
| john.doe@mail.com | [user:user]@[domain] | bax | false |
|
||||
| john.doe@mail.com | [user:user]@[domain] | sch | false |
|
||||
|
||||
Scenario: Move message from Inbox to Sent is not possible
|
||||
Scenario: Move message from Scheduled is not possible
|
||||
Given test skips reporter checks
|
||||
When IMAP client "1" moves the message with subject "sch" from "Scheduled" to "Inbox"
|
||||
Then it fails
|
||||
And IMAP client "1" eventually sees the following messages in "Scheduled":
|
||||
| from | to | subject | unread |
|
||||
| john.doe@mail.com | [user:user]@[domain] | sch | false |
|
||||
|
||||
Scenario: Move message from Inbox to Sent is not possible
|
||||
Given test skips reporter checks
|
||||
When IMAP client "1" moves the message with subject "bar" from "Inbox" to "Sent"
|
||||
Then it fails
|
||||
@ -105,4 +117,4 @@ Feature: IMAP move messages
|
||||
Scenario: Move message from Sent to Inbox is not possible
|
||||
Given test skips reporter checks
|
||||
When IMAP client "1" moves the message with subject "bax" from "Sent" to "Inbox"
|
||||
Then it fails
|
||||
Then it fails
|
||||
|
||||
@ -193,14 +193,6 @@ func (s *scenario) theAddressOfAccountHasTheFollowingMessagesInMailbox(address,
|
||||
return err
|
||||
}
|
||||
|
||||
var messageFlags proton.MessageFlag
|
||||
|
||||
if !strings.EqualFold(mailbox, "Sent") {
|
||||
messageFlags = proton.MessageFlagReceived
|
||||
} else {
|
||||
messageFlags = proton.MessageFlagSent
|
||||
}
|
||||
|
||||
return s.t.createMessages(ctx, username, addrID, xslices.Map(wantMessages, func(message Message) proton.ImportReq {
|
||||
return proton.ImportReq{
|
||||
|
||||
@ -208,7 +200,7 @@ func (s *scenario) theAddressOfAccountHasTheFollowingMessagesInMailbox(address,
|
||||
AddressID: addrID,
|
||||
LabelIDs: []string{mboxID},
|
||||
Unread: proton.Bool(message.Unread),
|
||||
Flags: messageFlags,
|
||||
Flags: flagsForMailbox(mailbox),
|
||||
},
|
||||
Message: message.Build(),
|
||||
}
|
||||
@ -228,7 +220,7 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
|
||||
Metadata: proton.ImportMetadata{
|
||||
AddressID: addrID,
|
||||
LabelIDs: []string{mboxID},
|
||||
Flags: proton.MessageFlagReceived,
|
||||
Flags: flagsForMailbox(mailbox),
|
||||
},
|
||||
Message: Message{
|
||||
Subject: fmt.Sprintf("%d", idx),
|
||||
@ -240,6 +232,18 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
|
||||
})))
|
||||
}
|
||||
|
||||
func flagsForMailbox(mailboxName string) proton.MessageFlag {
|
||||
if strings.EqualFold(mailboxName, "Sent") {
|
||||
return proton.MessageFlagSent
|
||||
}
|
||||
|
||||
if strings.EqualFold(mailboxName, "Scheduled") {
|
||||
return proton.MessageFlagScheduledSend
|
||||
}
|
||||
|
||||
return proton.MessageFlagReceived
|
||||
}
|
||||
|
||||
// accountDraftChanged changes the draft attributes, where draftIndex is
|
||||
// similar to sequential ID i.e. 1 represents the first message of draft folder
|
||||
// sorted by API creation time.
|
||||
|
||||
Reference in New Issue
Block a user