mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2026-02-04 08:18:34 +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/Masterminds/semver/v3 v3.1.1
|
||||||
github.com/ProtonMail/gluon v0.14.2-0.20230207142445-9f98ae47a031
|
github.com/ProtonMail/gluon v0.14.2-0.20230207142445-9f98ae47a031
|
||||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
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/go-rfc5322 v0.11.0
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.4.10
|
github.com/ProtonMail/gopenpgp/v2 v2.4.10
|
||||||
github.com/PuerkitoBio/goquery v1.8.0
|
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-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 h1:4IWzKjHzZxdrW9k4zl/qCwenOVHDbVDADPPHFLjs0Oc=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM=
|
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.1-0.20230214112101-944a29edf66a h1:/31/wWgxpBWREaRGRMVH4AVgQGpPtTK9BsLjt1a8uwc=
|
||||||
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/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 h1:o5Obrm4DpmQEffvgsVqG6S4BKwC1Wat+hYwjIp2YcCY=
|
||||||
github.com/ProtonMail/go-rfc5322 v0.11.0/go.mod h1:6oOKr0jXvpoE6pwTx/HukigQpX2J9WUf6h0auplrFTw=
|
github.com/ProtonMail/go-rfc5322 v0.11.0/go.mod h1:6oOKr0jXvpoE6pwTx/HukigQpX2J9WUf6h0auplrFTw=
|
||||||
github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg=
|
github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg=
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -44,8 +43,6 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
const scheduled = "Scheduled"
|
|
||||||
|
|
||||||
func TestBridge_Sync(t *testing.T) {
|
func TestBridge_Sync(t *testing.T) {
|
||||||
numMsg := 1 << 8
|
numMsg := 1 << 8
|
||||||
|
|
||||||
@ -471,45 +468,3 @@ func countBytesRead(ctl *proton.NetCtl, fn func()) uint64 {
|
|||||||
|
|
||||||
return read
|
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 {
|
func (conn *imapConnector) AddMessagesToMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
|
||||||
defer conn.goPollAPIEvents(false)
|
defer conn.goPollAPIEvents(false)
|
||||||
|
|
||||||
if mailboxID == proton.AllMailLabel {
|
if isAllMailOrScheduled(mailboxID) {
|
||||||
return fmt.Errorf("not allowed")
|
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 {
|
func (conn *imapConnector) RemoveMessagesFromMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
|
||||||
defer conn.goPollAPIEvents(false)
|
defer conn.goPollAPIEvents(false)
|
||||||
|
|
||||||
if mailboxID == proton.AllMailLabel {
|
if isAllMailOrScheduled(mailboxID) {
|
||||||
return fmt.Errorf("not allowed")
|
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) ||
|
if (labelFromID == proton.InboxLabel && labelToID == proton.SentLabel) ||
|
||||||
(labelFromID == proton.SentLabel && labelToID == proton.InboxLabel) ||
|
(labelFromID == proton.SentLabel && labelToID == proton.InboxLabel) ||
|
||||||
labelFromID == proton.AllMailLabel ||
|
isAllMailOrScheduled(labelFromID) ||
|
||||||
labelToID == proton.AllMailLabel {
|
isAllMailOrScheduled(labelToID) {
|
||||||
return false, fmt.Errorf("not allowed")
|
return false, fmt.Errorf("not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,3 +691,7 @@ func toIMAPMailbox(label proton.Label, flags, permFlags, attrs imap.FlagSet) ima
|
|||||||
Attributes: attrs,
|
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"
|
Then IMAP client "1" counts 20 mailboxes under "Folders"
|
||||||
And IMAP client "1" counts 60 mailboxes under "Labels"
|
And IMAP client "1" counts 60 mailboxes under "Labels"
|
||||||
Then IMAP client "2" counts 20 mailboxes under "Folders"
|
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 |
|
| mbox | folder |
|
||||||
| label | label |
|
| 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 10 messages in "Folders/mbox"
|
||||||
|
And the address "[user:user]@[domain]" of account "[user:user]" has 1 messages in "Scheduled"
|
||||||
And bridge starts
|
And bridge starts
|
||||||
And the user logs in with username "[user:user]" and password "password"
|
And the user logs in with username "[user:user]" and password "password"
|
||||||
And user "[user:user]" finishes syncing
|
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 IMAP client "1" marks message 2 as deleted
|
||||||
And it succeeds
|
And it succeeds
|
||||||
And IMAP client "1" expunges
|
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":
|
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Sent":
|
||||||
| from | to | subject | unread |
|
| from | to | subject | unread |
|
||||||
| john.doe@mail.com | [user:user]@[domain] | bax | false |
|
| 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 bridge starts
|
||||||
And the user logs in with username "[user:user]" and password "password"
|
And the user logs in with username "[user:user]" and password "password"
|
||||||
And user "[user:user]" finishes syncing
|
And user "[user:user]" finishes syncing
|
||||||
@ -96,8 +99,17 @@ Feature: IMAP move messages
|
|||||||
| jane.doe@mail.com | name@[domain] | bar | true |
|
| jane.doe@mail.com | name@[domain] | bar | true |
|
||||||
| john.doe@mail.com | [user:user]@[domain] | baz | false |
|
| 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] | 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
|
Given test skips reporter checks
|
||||||
When IMAP client "1" moves the message with subject "bar" from "Inbox" to "Sent"
|
When IMAP client "1" moves the message with subject "bar" from "Inbox" to "Sent"
|
||||||
Then it fails
|
Then it fails
|
||||||
@ -105,4 +117,4 @@ Feature: IMAP move messages
|
|||||||
Scenario: Move message from Sent to Inbox is not possible
|
Scenario: Move message from Sent to Inbox is not possible
|
||||||
Given test skips reporter checks
|
Given test skips reporter checks
|
||||||
When IMAP client "1" moves the message with subject "bax" from "Sent" to "Inbox"
|
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
|
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 s.t.createMessages(ctx, username, addrID, xslices.Map(wantMessages, func(message Message) proton.ImportReq {
|
||||||
return proton.ImportReq{
|
return proton.ImportReq{
|
||||||
|
|
||||||
@ -208,7 +200,7 @@ func (s *scenario) theAddressOfAccountHasTheFollowingMessagesInMailbox(address,
|
|||||||
AddressID: addrID,
|
AddressID: addrID,
|
||||||
LabelIDs: []string{mboxID},
|
LabelIDs: []string{mboxID},
|
||||||
Unread: proton.Bool(message.Unread),
|
Unread: proton.Bool(message.Unread),
|
||||||
Flags: messageFlags,
|
Flags: flagsForMailbox(mailbox),
|
||||||
},
|
},
|
||||||
Message: message.Build(),
|
Message: message.Build(),
|
||||||
}
|
}
|
||||||
@ -228,7 +220,7 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
|
|||||||
Metadata: proton.ImportMetadata{
|
Metadata: proton.ImportMetadata{
|
||||||
AddressID: addrID,
|
AddressID: addrID,
|
||||||
LabelIDs: []string{mboxID},
|
LabelIDs: []string{mboxID},
|
||||||
Flags: proton.MessageFlagReceived,
|
Flags: flagsForMailbox(mailbox),
|
||||||
},
|
},
|
||||||
Message: Message{
|
Message: Message{
|
||||||
Subject: fmt.Sprintf("%d", idx),
|
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
|
// accountDraftChanged changes the draft attributes, where draftIndex is
|
||||||
// similar to sequential ID i.e. 1 represents the first message of draft folder
|
// similar to sequential ID i.e. 1 represents the first message of draft folder
|
||||||
// sorted by API creation time.
|
// sorted by API creation time.
|
||||||
|
|||||||
Reference in New Issue
Block a user