Replace old date to not crash Apple Mail

This commit is contained in:
Michal Horejsek
2020-12-07 13:22:09 +01:00
parent 2de202ca02
commit 40db822450
7 changed files with 69 additions and 1 deletions

View File

@ -40,6 +40,10 @@ import (
openpgperrors "golang.org/x/crypto/openpgp/errors"
)
var (
rfc822Birthday = time.Date(1982, 8, 13, 0, 0, 0, 0, time.UTC) //nolint[gochecknoglobals]
)
type doNotCacheError struct{ e error }
func (dnc *doNotCacheError) Error() string { return dnc.e.Error() }
@ -605,7 +609,7 @@ func (im *imapMailbox) buildMessageInner(m *pmapi.Message, kr *crypto.KeyRing) (
}
tmpBuf := &bytes.Buffer{}
mainHeader := message.GetHeader(m)
mainHeader := buildHeader(m)
if err = writeHeader(tmpBuf, mainHeader); err != nil {
return
}
@ -703,3 +707,23 @@ func (im *imapMailbox) buildMessageInner(m *pmapi.Message, kr *crypto.KeyRing) (
}
return structure, msgBody, err
}
func buildHeader(msg *pmapi.Message) textproto.MIMEHeader {
header := message.GetHeader(msg)
msgTime := time.Unix(msg.Time, 0)
// Apple Mail crashes fetching messages with date older than 1970.
// There is no point having message older than RFC itself, it's not possible.
d, err := msg.Header.Date()
if err != nil || d.Before(rfc822Birthday) || msgTime.Before(rfc822Birthday) {
if err != nil || d.IsZero() {
header.Set("X-Original-Date", msgTime.Format(time.RFC1123Z))
} else {
header.Set("X-Original-Date", d.Format(time.RFC1123Z))
}
header.Set("Date", rfc822Birthday.Format(time.RFC1123Z))
}
return header
}

View File

@ -20,8 +20,10 @@ package fakeapi
import (
"errors"
"fmt"
"net/mail"
"strings"
messageUtils "github.com/ProtonMail/proton-bridge/pkg/message"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
)
@ -139,6 +141,7 @@ func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) (
}
message.ID = ctl.messageIDGenerator.next("")
message.LabelIDs = append(message.LabelIDs, pmapi.AllMailLabel)
message.Header = mail.Header(messageUtils.GetHeader(message))
ctl.messagesByUsername[username] = append(ctl.messagesByUsername[username], message)
ctl.resetUsers()
return message.ID, nil

View File

@ -60,3 +60,17 @@ Feature: IMAP fetch messages
When IMAP client fetches by UID "1:*"
Then IMAP response is "OK"
And IMAP response has 2 message
Scenario: Fetch of very old message sent from the moon succeeds with modified date
Given there are messages in mailbox "Folders/mbox" for "user"
| from | to | subject | time |
| john.doe@mail.com | user@pm.me | foo | 1969-07-20T00:00:00 |
And there is IMAP client logged in as "user"
And there is IMAP client selected in "Folders/mbox"
When IMAP client sends command "FETCH 1:* rfc822"
Then IMAP response is "OK"
And IMAP response contains "Date: Fri, 13 Aug 1982"
And IMAP response contains "X-Original-Date: Sun, 20 Jul 1969"
# We had bug to incorectly set empty date, so let's make sure
# there is no reference anywhere in the response.
And IMAP response does not contain "Date: Thu, 01 Jan 1970"

View File

@ -32,6 +32,8 @@ func IMAPChecksFeatureContext(s *godog.Suite) {
s.Step(`^IMAP response to "([^"]*)" contains "([^"]*)"$`, imapResponseNamedContains)
s.Step(`^IMAP response has (\d+) message(?:s)?$`, imapResponseHasNumberOfMessages)
s.Step(`^IMAP response to "([^"]*)" has (\d+) message(?:s)?$`, imapResponseNamedHasNumberOfMessages)
s.Step(`^IMAP response does not contain "([^"]*)"$`, imapResponseDoesNotContain)
s.Step(`^IMAP response to "([^"]*)" does not contain "([^"]*)"$`, imapResponseNamedDoesNotContain)
s.Step(`^IMAP client receives update marking message seq "([^"]*)" as read within (\d+) seconds$`, imapClientReceivesUpdateMarkingMessageSeqAsReadWithin)
s.Step(`^IMAP client "([^"]*)" receives update marking message seq "([^"]*)" as read within (\d+) seconds$`, imapClientNamedReceivesUpdateMarkingMessageSeqAsReadWithin)
s.Step(`^IMAP client receives update marking message seq "([^"]*)" as unread within (\d+) seconds$`, imapClientReceivesUpdateMarkingMessageSeqAsUnreadWithin)
@ -73,6 +75,16 @@ func imapResponseNamedHasNumberOfMessages(clientID string, expectedCount int) er
return ctx.GetTestingError()
}
func imapResponseDoesNotContain(notExpectedResponse string) error {
return imapResponseNamedDoesNotContain("imap", notExpectedResponse)
}
func imapResponseNamedDoesNotContain(clientID, notExpectedResponse string) error {
res := ctx.GetIMAPLastResponse(clientID)
res.AssertNotSections(notExpectedResponse)
return ctx.GetTestingError()
}
func imapClientReceivesUpdateMarkingMessageSeqAsReadWithin(messageSeq string, seconds int) error {
return imapClientNamedReceivesUpdateMarkingMessageSeqAsReadWithin("imap", messageSeq, seconds)
}

View File

@ -160,6 +160,16 @@ func (ir *IMAPResponse) AssertSections(wantRegexps ...string) *IMAPResponse {
return ir
}
// AssertNotSections is similar to AssertSections but is the opposite.
// It means it just tries to find all "regexps" in the response.
func (ir *IMAPResponse) AssertNotSections(unwantedRegexps ...string) *IMAPResponse {
ir.wait()
for _, unwantedRegexp := range unwantedRegexps {
a.Error(ir.t, ir.hasSectionRegexp(unwantedRegexp), "regexp %v found\nSections: %v", unwantedRegexp, ir.sections)
}
return ir
}
// WaitForSections is the same as AssertSections but waits for `timeout` before giving up.
func (ir *IMAPResponse) WaitForSections(timeout time.Duration, wantRegexps ...string) {
a.Eventually(ir.t, func() bool {

View File

@ -20,6 +20,7 @@ package tests
import (
"fmt"
"net/mail"
"net/textproto"
"strconv"
"strings"
"time"
@ -97,6 +98,7 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd
LabelIDs: labelIDs,
AddressID: account.AddressID(),
}
header := make(textproto.MIMEHeader)
if message.HasLabelID(pmapi.SentLabel) {
message.Flags |= pmapi.FlagSent
@ -143,12 +145,14 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd
return internalError(err, "parsing time")
}
message.Time = date.Unix()
header.Set("Date", date.Format(time.RFC1123Z))
case "deleted":
hasDeletedFlag = cell.Value == "true"
default:
return fmt.Errorf("unexpected column name: %s", head[n].Value)
}
}
message.Header = mail.Header(header)
lastMessageID, err := ctx.GetPMAPIController().AddUserMessage(account.Username(), message)
if err != nil {
return internalError(err, "adding message")

View File

@ -20,3 +20,4 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
### Fixed
* GODT-135 Support parameters in SMTP `FROM MAIL` command, such as `BODY=7BIT`, or empty value `FROM MAIL:<>` used by some clients.
* GODT-338 GODT-781 GODT-857 GODT-866 Flaky tests.
* GODT-773 Replace old dates with birthday of RFC822 to not crash Apple Mail. Original is available under `X-Original-Date` header.