fix(GODT-2337): filter reply-to on draft.

This commit is contained in:
Romain LE JEUNE
2023-04-12 08:31:35 +02:00
parent 4e7a669260
commit 54b209f9e1
7 changed files with 93 additions and 19 deletions

View File

@ -451,6 +451,65 @@ func TestBridge_User_DropConn_NoBadEvent(t *testing.T) {
}, server.WithListener(dropListener)) }, server.WithListener(dropListener))
} }
func TestBridge_User_UpdateDraft(t *testing.T) {
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
// Create a bridge user.
_, _, err := s.CreateUser("user", password)
require.NoError(t, err)
// Initially sync the user.
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
userLoginAndSync(ctx, t, bridge, "user", password)
})
withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) {
user, err := c.GetUser(ctx)
require.NoError(t, err)
addrs, err := c.GetAddresses(ctx)
require.NoError(t, err)
salts, err := c.GetSalts(ctx)
require.NoError(t, err)
keyPass, err := salts.SaltForKey(password, user.Keys.Primary().ID)
require.NoError(t, err)
_, addrKRs, err := proton.Unlock(user, addrs, keyPass, async.NoopPanicHandler{})
require.NoError(t, err)
// Create a draft (generating a "create draft message" event).
draft, err := c.CreateDraft(ctx, addrKRs[addrs[0].ID], proton.CreateDraftReq{
Message: proton.DraftTemplate{
Subject: "subject",
Sender: &mail.Address{Name: "sender", Address: addrs[0].Email},
Body: "body",
MIMEType: rfc822.TextPlain,
},
})
require.NoError(t, err)
require.Empty(t, draft.ReplyTos)
// Process those events
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
userContinueEventProcess(ctx, t, s, bridge)
})
// Update the draft (generating an "update draft message" event).
draft2, err := c.UpdateDraft(ctx, draft.ID, addrKRs[addrs[0].ID], proton.UpdateDraftReq{
Message: proton.DraftTemplate{
Subject: "subject 2",
Sender: &mail.Address{Name: "sender", Address: addrs[0].Email},
Body: "body 2",
MIMEType: rfc822.TextPlain,
},
})
require.NoError(t, err)
require.Empty(t, draft2.ReplyTos)
})
})
}
func TestBridge_User_UpdateDraftAndCreateOtherMessage(t *testing.T) { func TestBridge_User_UpdateDraftAndCreateOtherMessage(t *testing.T) {
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
// Create a bridge user. // Create a bridge user.

View File

@ -441,7 +441,7 @@ func getMessageHeader(msg proton.Message, opts JobOptions) message.Header {
hdr.Set("From", msg.Sender.String()) hdr.Set("From", msg.Sender.String())
} }
if len(msg.ReplyTos) > 0 { if len(msg.ReplyTos) > 0 && !msg.IsDraft() {
if !(len(msg.ReplyTos) == 1 && addressEmpty(msg.ReplyTos[0])) { if !(len(msg.ReplyTos) == 1 && addressEmpty(msg.ReplyTos[0])) {
hdr.Set("Reply-To", toAddressList(msg.ReplyTos)) hdr.Set("Reply-To", toAddressList(msg.ReplyTos))
} }

View File

@ -209,6 +209,7 @@ func TestFeatures(testingT *testing.T) {
ctx.Step(`^IMAP client "([^"]*)" appends "([^"]*)" to "([^"]*)"$`, s.imapClientAppendsToMailbox) ctx.Step(`^IMAP client "([^"]*)" appends "([^"]*)" to "([^"]*)"$`, s.imapClientAppendsToMailbox)
ctx.Step(`^IMAP clients "([^"]*)" and "([^"]*)" move message with subject "([^"]*)" of "([^"]*)" to "([^"]*)" by ([^"]*) ([^"]*) ([^"]*)`, s.imapClientsMoveMessageWithSubjectUserFromToByOrderedOperations) ctx.Step(`^IMAP clients "([^"]*)" and "([^"]*)" move message with subject "([^"]*)" of "([^"]*)" to "([^"]*)" by ([^"]*) ([^"]*) ([^"]*)`, s.imapClientsMoveMessageWithSubjectUserFromToByOrderedOperations)
ctx.Step(`^IMAP client "([^"]*)" sees header "([^"]*)" in message with subject "([^"]*)" in "([^"]*)"$`, s.imapClientSeesHeaderInMessageWithSubject) ctx.Step(`^IMAP client "([^"]*)" sees header "([^"]*)" in message with subject "([^"]*)" in "([^"]*)"$`, s.imapClientSeesHeaderInMessageWithSubject)
ctx.Step(`^IMAP client "([^"]*)" does not see header "([^"]*)" in message with subject "([^"]*)" in "([^"]*)"$`, s.imapClientDoesNotSeeHeaderInMessageWithSubject)
// ==== SMTP ==== // ==== SMTP ====
ctx.Step(`^user "([^"]*)" connects SMTP client "([^"]*)"$`, s.userConnectsSMTPClient) ctx.Step(`^user "([^"]*)" connects SMTP client "([^"]*)"$`, s.userConnectsSMTPClient)

View File

@ -34,6 +34,7 @@ Feature: IMAP Draft messages
| to | subject | body | | to | subject | body |
| someone@example.com | Basic Draft | This is a draft, but longer | | someone@example.com | Basic Draft | This is a draft, but longer |
And IMAP client "1" eventually sees 1 messages in "Drafts" And IMAP client "1" eventually sees 1 messages in "Drafts"
And IMAP client "1" does not see header "Reply-To" in message with subject "Basic Draft" in "Drafts"
Scenario: Draft edited remotely Scenario: Draft edited remotely
When the following fields were changed in draft 1 for address "[user:user]@[domain]" of account "[user:user]": When the following fields were changed in draft 1 for address "[user:user]@[domain]" of account "[user:user]":
@ -43,6 +44,7 @@ Feature: IMAP Draft messages
| to | subject | body | | to | subject | body |
| someone@example.com | Basic Draft | This is a draft body, but longer | | someone@example.com | Basic Draft | This is a draft body, but longer |
And IMAP client "1" eventually sees 1 messages in "Drafts" And IMAP client "1" eventually sees 1 messages in "Drafts"
And IMAP client "1" does not see header "Reply-To" in message with subject "Basic Draft" in "Drafts"
Scenario: Draft moved to trash remotely Scenario: Draft moved to trash remotely
When draft 1 for address "[user:user]@[domain]" of account "[user:user]" was moved to trash When draft 1 for address "[user:user]@[domain]" of account "[user:user]" was moved to trash

View File

@ -5,9 +5,9 @@ Feature: SMTP send reply
And there exists an account with username "[user:user2]" and password "password" And there exists an account with username "[user:user2]" and password "password"
And bridge starts And bridge starts
And the user logs in with username "[user:user1]" and password "password" And the user logs in with username "[user:user1]" and password "password"
And user "[user:user1]" finishes syncing
And user "[user:user1]" connects and authenticates SMTP client "1" And user "[user:user1]" connects and authenticates SMTP client "1"
And user "[user:user1]" connects and authenticates IMAP client "1" And user "[user:user1]" connects and authenticates IMAP client "1"
And user "[user:user1]" finishes syncing
@long-black @long-black
Scenario: Reply with In-Reply-To but no References Scenario: Reply with In-Reply-To but no References
@ -33,8 +33,8 @@ Feature: SMTP send reply
And user "[user:user2]" finishes syncing And user "[user:user2]" finishes syncing
# User2 receive the message. # User2 receive the message.
Then IMAP client "2" eventually sees the following messages in "INBOX": Then IMAP client "2" eventually sees the following messages in "INBOX":
| from | subject | message-id | | from | subject | message-id | reply-to |
| [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | | [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | [user:user1]@[domain] |
# User2 reply to it. # User2 reply to it.
When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]":
""" """
@ -53,8 +53,8 @@ Feature: SMTP send reply
| [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> |
# User1 receive the reply.| # User1 receive the reply.|
And IMAP client "1" eventually sees the following messages in "INBOX": And IMAP client "1" eventually sees the following messages in "INBOX":
| from | subject | body | in-reply-to | references | | from | subject | body | in-reply-to | references | reply-to |
| [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | [user:user2]@[domain] |
@long-black @long-black
Scenario: Reply with References but no In-Reply-To Scenario: Reply with References but no In-Reply-To
@ -80,8 +80,8 @@ Feature: SMTP send reply
And user "[user:user2]" finishes syncing And user "[user:user2]" finishes syncing
# User2 receive the message. # User2 receive the message.
Then IMAP client "2" eventually sees the following messages in "INBOX": Then IMAP client "2" eventually sees the following messages in "INBOX":
| from | subject | message-id | | from | subject | message-id | reply-to |
| [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | | [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | [user:user1]@[domain] |
# User2 reply to it. # User2 reply to it.
When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]":
""" """
@ -100,8 +100,8 @@ Feature: SMTP send reply
| [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> |
# User1 receive the reply.| # User1 receive the reply.|
And IMAP client "1" eventually sees the following messages in "INBOX": And IMAP client "1" eventually sees the following messages in "INBOX":
| from | subject | body | in-reply-to | references | | from | subject | body | in-reply-to | references | reply-to |
| [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | [user:user2]@[domain] |
@long-black @long-black
@ -128,8 +128,8 @@ Feature: SMTP send reply
And user "[user:user2]" finishes syncing And user "[user:user2]" finishes syncing
# User2 receive the message. # User2 receive the message.
Then IMAP client "2" eventually sees the following messages in "INBOX": Then IMAP client "2" eventually sees the following messages in "INBOX":
| from | subject | message-id | | from | subject | message-id | reply-to |
| [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | | [user:user1]@[domain] | Please Reply | <something@protonmail.ch> | [user:user1]@[domain] |
# User2 reply to it. # User2 reply to it.
When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]":
""" """
@ -149,5 +149,5 @@ Feature: SMTP send reply
| [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | <something@protonmail.ch> | <something@protonmail.ch> |
# User1 receive the reply.| # User1 receive the reply.|
And IMAP client "1" eventually sees the following messages in "INBOX": And IMAP client "1" eventually sees the following messages in "INBOX":
| from | subject | body | in-reply-to | references | | from | subject | body | in-reply-to | references | reply-to |
| [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | | [user:user2]@[domain] | FW - Please Reply | Heya | <something@protonmail.ch> | <something@protonmail.ch> | [user:user2]@[domain] |

View File

@ -297,7 +297,6 @@ func (s *scenario) imapClientSeesTheFollowingMessagesInMailbox(clientID, mailbox
if err != nil { if err != nil {
return err return err
} }
return matchMessages(haveMessages, wantMessages) return matchMessages(haveMessages, wantMessages)
} }
@ -575,6 +574,14 @@ func (s *scenario) imapClientSeesHeaderInMessageWithSubject(clientID, headerStri
return fmt.Errorf("could not find message with given subject '%v'", subject) return fmt.Errorf("could not find message with given subject '%v'", subject)
} }
func (s *scenario) imapClientDoesNotSeeHeaderInMessageWithSubject(clientID, headerString, subject, mailbox string) error {
err := s.imapClientSeesHeaderInMessageWithSubject(clientID, headerString, subject, mailbox)
if err == nil {
return fmt.Errorf("message header contains '%v'", headerString)
}
return nil
}
func clientList(client *client.Client) []*imap.MailboxInfo { func clientList(client *client.Client) []*imap.MailboxInfo {
resCh := make(chan *imap.MailboxInfo) resCh := make(chan *imap.MailboxInfo)

View File

@ -47,6 +47,7 @@ type Message struct {
To string `bdd:"to"` To string `bdd:"to"`
CC string `bdd:"cc"` CC string `bdd:"cc"`
BCC string `bdd:"bcc"` BCC string `bdd:"bcc"`
ReplyTo string `bdd:"reply-to"`
Unread bool `bdd:"unread"` Unread bool `bdd:"unread"`
Deleted bool `bdd:"deleted"` Deleted bool `bdd:"deleted"`
@ -158,6 +159,10 @@ func newMessageFromIMAP(msg *imap.Message) Message {
message.BCC = msg.Envelope.Bcc[0].Address() message.BCC = msg.Envelope.Bcc[0].Address()
} }
if len(msg.Envelope.ReplyTo) > 0 {
message.ReplyTo = msg.Envelope.ReplyTo[0].Address()
}
return message return message
} }