Skip to content

Commit

Permalink
fix: Do not recover messages if they exceed size limit
Browse files Browse the repository at this point in the history
  • Loading branch information
LBeernaertProton committed Apr 28, 2023
1 parent 8b3ec72 commit 2797a17
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
1 change: 1 addition & 0 deletions connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
)

var ErrOperationNotAllowed = errors.New("operation not allowed")
var ErrMessageSizeExceedsLimits = errors.New("message size exceeds limits")

// Connector connects the gluon server to a remote mail store.
type Connector interface {
Expand Down
6 changes: 6 additions & 0 deletions internal/state/mailbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"time"

"github.com/ProtonMail/gluon/connector"
"github.com/ProtonMail/gluon/imap"
"github.com/ProtonMail/gluon/imap/command"
"github.com/ProtonMail/gluon/internal/db"
Expand Down Expand Up @@ -238,6 +239,11 @@ var ErrKnownRecoveredMessage = errors.New("known recovered message, possible dup
func (m *Mailbox) Append(ctx context.Context, literal []byte, flags imap.FlagSet, date time.Time) (imap.UID, error) {
uid, err := m.AppendRegular(ctx, literal, flags, date)
if err != nil {
// Can't store messages that exceed size limits
if errors.Is(err, connector.ErrMessageSizeExceedsLimits) {
return uid, err
}

// Failed to append to mailbox attempt to insert into recovery mailbox.
knownMessage, recoverErr := db.WriteResult(ctx, m.state.db(), func(ctx context.Context, tx *ent.Tx) (bool, error) {
return m.state.actionCreateRecoveredMessage(ctx, tx, literal, flags, date)
Expand Down
57 changes: 57 additions & 0 deletions tests/recovery_mailbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,33 @@ func TestRecoveryMailboxOnlyReportsOnFirstDedupedMessage(t *testing.T) {
})
}

func TestRecoveryMailboxDoesNotStoreMessageWhichExceedLimit(t *testing.T) {
runOneToOneTestClientWithAuth(t, defaultServerOptions(t, withConnectorBuilder(&sizeExceededAppendConnectorBuilder{})), func(client *client.Client, s *testSession) {
{
status, err := client.Status(ids.GluonRecoveryMailboxName, []goimap.StatusItem{goimap.StatusMessages})
require.NoError(t, err)
require.Equal(t, uint32(0), status.Messages)
}

status, err := client.Select("INBOX", false)
require.NoError(t, err)
require.Equal(t, uint32(0), status.Messages)
require.Error(t, doAppendWithClientFromFile(t, client, "INBOX", "testdata/original.eml", time.Now()))
require.Error(t, doAppendWithClientFromFile(t, client, "INBOX", "testdata/duplicate.eml", time.Now()))

{
status, err := client.Status(ids.GluonRecoveryMailboxName, []goimap.StatusItem{goimap.StatusMessages})
require.NoError(t, err)
require.Equal(t, uint32(0), status.Messages)
}
{
status, err := client.Status("INBOX", []goimap.StatusItem{goimap.StatusMessages})
require.NoError(t, err)
require.Equal(t, uint32(0), status.Messages)
}
})
}

func TestRecoveryMBoxCanBeCopiedOutOfDedup(t *testing.T) {
runOneToOneTestClientWithAuth(t, defaultServerOptions(t, withConnectorBuilder(&recoveryDedupConnectorConnectorBuilder{})), func(client *client.Client, s *testSession) {
// Insert first message, fails.
Expand Down Expand Up @@ -524,3 +551,33 @@ func (failAppendLabelConnectorBuilder) New(usernames []string, password []byte,
Dummy: connector.NewDummy(usernames, password, period, flags, permFlags, attrs),
}
}

// failAppendLabelConnector simulate Create Message failures and also ensures that no calls to Add or Move can take place.
type sizeExceededAppendConnector struct {
*connector.Dummy
}

func (r *sizeExceededAppendConnector) CreateMessage(
_ context.Context,
_ imap.MailboxID,
_ []byte,
_ imap.FlagSet,
_ time.Time) (imap.Message, []byte, error) {
return imap.Message{}, nil, fmt.Errorf("messsage to large: %w", connector.ErrMessageSizeExceedsLimits)
}

func (r *sizeExceededAppendConnector) AddMessagesToMailbox(
_ context.Context,
_ []imap.MessageID,
_ imap.MailboxID,
) error {
return fmt.Errorf("messsage to large: %w", connector.ErrMessageSizeExceedsLimits)
}

type sizeExceededAppendConnectorBuilder struct{}

func (sizeExceededAppendConnectorBuilder) New(usernames []string, password []byte, period time.Duration, flags, permFlags, attrs imap.FlagSet) Connector {
return &sizeExceededAppendConnector{
Dummy: connector.NewDummy(usernames, password, period, flags, permFlags, attrs),
}
}

0 comments on commit 2797a17

Please sign in to comment.