fix(GODT-2407): Replace invalid email addresses with emtpy for new Drafts

This commit is contained in:
Leander Beernaert
2023-03-17 13:11:07 +01:00
parent b3d0dfc60b
commit 02ca6428b5
4 changed files with 70 additions and 14 deletions

View File

@ -626,7 +626,7 @@ func (conn *imapConnector) createDraft(ctx context.Context, literal []byte, addr
return proton.Message{}, fmt.Errorf("failed to create parser: %w", err) return proton.Message{}, fmt.Errorf("failed to create parser: %w", err)
} }
message, err := message.ParseWithParser(parser) message, err := message.ParseWithParser(parser, true)
if err != nil { if err != nil {
return proton.Message{}, fmt.Errorf("failed to parse message: %w", err) return proton.Message{}, fmt.Errorf("failed to parse message: %w", err)
} }

View File

@ -137,7 +137,7 @@ func (user *User) sendMail(authID string, from string, to []string, r io.Reader)
} }
// Parse the message we want to send (after we have attached the public key). // Parse the message we want to send (after we have attached the public key).
message, err := message.ParseWithParser(parser) message, err := message.ParseWithParser(parser, false)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse message: %w", err) return fmt.Errorf("failed to parse message: %w", err)
} }

View File

@ -73,6 +73,15 @@ type Attachment struct {
// Parse parses an RFC822 message. // Parse parses an RFC822 message.
func Parse(r io.Reader) (m Message, err error) { func Parse(r io.Reader) (m Message, err error) {
return parseIOReaderImpl(r, false)
}
// ParseAndAllowInvalidAddressLists parses an RFC822 message and allows email address lists to be invalid.
func ParseAndAllowInvalidAddressLists(r io.Reader) (m Message, err error) {
return parseIOReaderImpl(r, true)
}
func parseIOReaderImpl(r io.Reader, allowInvalidAddressLists bool) (m Message, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
err = fmt.Errorf("panic while parsing message: %v", r) err = fmt.Errorf("panic while parsing message: %v", r)
@ -84,21 +93,21 @@ func Parse(r io.Reader) (m Message, err error) {
return Message{}, errors.Wrap(err, "failed to create new parser") return Message{}, errors.Wrap(err, "failed to create new parser")
} }
return parse(p) return parse(p, allowInvalidAddressLists)
} }
// ParseWithParser parses an RFC822 message using an existing parser. // ParseWithParser parses an RFC822 message using an existing parser.
func ParseWithParser(p *parser.Parser) (m Message, err error) { func ParseWithParser(p *parser.Parser, allowInvalidAddressLists bool) (m Message, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
err = fmt.Errorf("panic while parsing message: %v", r) err = fmt.Errorf("panic while parsing message: %v", r)
} }
}() }()
return parse(p) return parse(p, allowInvalidAddressLists)
} }
func parse(p *parser.Parser) (Message, error) { func parse(p *parser.Parser, allowInvalidAddressLists bool) (Message, error) {
if err := convertEncodedTransferEncoding(p); err != nil { if err := convertEncodedTransferEncoding(p); err != nil {
return Message{}, errors.Wrap(err, "failed to convert encoded transfer encoding") return Message{}, errors.Wrap(err, "failed to convert encoded transfer encoding")
} }
@ -107,7 +116,7 @@ func parse(p *parser.Parser) (Message, error) {
return Message{}, errors.Wrap(err, "failed to convert foreign encodings") return Message{}, errors.Wrap(err, "failed to convert foreign encodings")
} }
m, err := parseMessageHeader(p.Root().Header) m, err := parseMessageHeader(p.Root().Header, allowInvalidAddressLists)
if err != nil { if err != nil {
return Message{}, errors.Wrap(err, "failed to parse message header") return Message{}, errors.Wrap(err, "failed to parse message header")
} }
@ -433,7 +442,7 @@ func getPlainBody(part *parser.Part) []byte {
} }
} }
func parseMessageHeader(h message.Header) (Message, error) { func parseMessageHeader(h message.Header, allowInvalidAddressLists bool) (Message, error) {
var m Message var m Message
for fields := h.Fields(); fields.Next(); { for fields := h.Fields(); fields.Next(); {
@ -451,9 +460,13 @@ func parseMessageHeader(h message.Header) (Message, error) {
case "from": case "from":
sender, err := rfc5322.ParseAddressList(fields.Value()) sender, err := rfc5322.ParseAddressList(fields.Value())
if err != nil { if err != nil {
if !allowInvalidAddressLists {
return Message{}, errors.Wrap(err, "failed to parse from") return Message{}, errors.Wrap(err, "failed to parse from")
} }
logrus.WithError(err).Warn("failed to parse from")
}
if len(sender) > 0 { if len(sender) > 0 {
m.Sender = sender[0] m.Sender = sender[0]
} }
@ -461,33 +474,49 @@ func parseMessageHeader(h message.Header) (Message, error) {
case "to": case "to":
toList, err := rfc5322.ParseAddressList(fields.Value()) toList, err := rfc5322.ParseAddressList(fields.Value())
if err != nil { if err != nil {
if !allowInvalidAddressLists {
return Message{}, errors.Wrap(err, "failed to parse to") return Message{}, errors.Wrap(err, "failed to parse to")
} }
logrus.WithError(err).Warn("failed to parse to")
}
m.ToList = toList m.ToList = toList
case "reply-to": case "reply-to":
replyTos, err := rfc5322.ParseAddressList(fields.Value()) replyTos, err := rfc5322.ParseAddressList(fields.Value())
if err != nil { if err != nil {
if !allowInvalidAddressLists {
return Message{}, errors.Wrap(err, "failed to parse reply-to") return Message{}, errors.Wrap(err, "failed to parse reply-to")
} }
logrus.WithError(err).Warn("failed to parse reply-to")
}
m.ReplyTos = replyTos m.ReplyTos = replyTos
case "cc": case "cc":
ccList, err := rfc5322.ParseAddressList(fields.Value()) ccList, err := rfc5322.ParseAddressList(fields.Value())
if err != nil { if err != nil {
if !allowInvalidAddressLists {
return Message{}, errors.Wrap(err, "failed to parse cc") return Message{}, errors.Wrap(err, "failed to parse cc")
} }
logrus.WithError(err).Warn("failed to parse cc")
}
m.CCList = ccList m.CCList = ccList
case "bcc": case "bcc":
bccList, err := rfc5322.ParseAddressList(fields.Value()) bccList, err := rfc5322.ParseAddressList(fields.Value())
if err != nil { if err != nil {
if !allowInvalidAddressLists {
return Message{}, errors.Wrap(err, "failed to parse bcc") return Message{}, errors.Wrap(err, "failed to parse bcc")
} }
logrus.WithError(err).Warn("failed to parse bcc")
}
m.BCCList = bccList m.BCCList = bccList
case "message-id": case "message-id":

View File

@ -23,6 +23,7 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/ProtonMail/go-proton-api" "github.com/ProtonMail/go-proton-api"
@ -444,7 +445,7 @@ func TestParseWithAttachedPublicKey(t *testing.T) {
p, err := parser.New(f) p, err := parser.New(f)
require.NoError(t, err) require.NoError(t, err)
m, err := ParseWithParser(p) m, err := ParseWithParser(p, false)
require.NoError(t, err) require.NoError(t, err)
p.AttachPublicKey("publickey", "publickeyname") p.AttachPublicKey("publickey", "publickeyname")
@ -636,6 +637,32 @@ func TestParseIcsAttachment(t *testing.T) {
assert.Equal(t, string(m.Attachments[0].Data), "This is an ics calendar invite") assert.Equal(t, string(m.Attachments[0].Data), "This is an ics calendar invite")
} }
func TestParseAllowInvalidAddress(t *testing.T) {
const literal = `To: foo
From: bar
BCC: fff
CC: FFF
Reply-To: AAA
Subject: Test
`
// This will fail as the addresses are not valid.
{
_, err := Parse(strings.NewReader(literal))
require.Error(t, err)
}
// This will work as invalid addresses will be ignored.
m, err := ParseAndAllowInvalidAddressLists(strings.NewReader(literal))
require.NoError(t, err)
assert.Empty(t, m.ToList)
assert.Empty(t, m.Sender)
assert.Empty(t, m.CCList)
assert.Empty(t, m.BCCList)
assert.Empty(t, m.ReplyTos)
}
func TestParsePanic(t *testing.T) { func TestParsePanic(t *testing.T) {
var err error var err error