mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
Prefer From header instead of MAIL FROM address
This commit is contained in:
@ -70,7 +70,7 @@ func (im *imapMailbox) CreateMessage(flags []string, date time.Time, body imap.L
|
||||
// Called from go-imap in goroutines - we need to handle panics for each function.
|
||||
defer im.panicHandler.HandlePanic()
|
||||
|
||||
m, _, _, readers, err := message.Parse(body, "", "")
|
||||
m, _, _, readers, err := message.Parse(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -31,7 +31,8 @@ import (
|
||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||
"github.com/ProtonMail/proton-bridge/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||
pkgMessage "github.com/ProtonMail/proton-bridge/pkg/message"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/message/parser"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
goSMTPBackend "github.com/emersion/go-smtp"
|
||||
"github.com/pkg/errors"
|
||||
@ -47,8 +48,8 @@ type smtpUser struct {
|
||||
username string
|
||||
addressID string
|
||||
|
||||
from string
|
||||
to []string
|
||||
returnPath string
|
||||
to []string
|
||||
}
|
||||
|
||||
// newSMTPUser returns struct implementing go-smtp/session interface.
|
||||
@ -154,13 +155,13 @@ func (su *smtpUser) getAPIKeyData(recipient string) (apiKeys []pmapi.PublicKey,
|
||||
// Discard currently processed message.
|
||||
func (su *smtpUser) Reset() {
|
||||
log.Trace("Resetting the session")
|
||||
su.from = ""
|
||||
su.returnPath = ""
|
||||
su.to = []string{}
|
||||
}
|
||||
|
||||
// Set return path for currently processed message.
|
||||
func (su *smtpUser) Mail(from string, opts goSMTPBackend.MailOptions) error {
|
||||
log.WithField("from", from).WithField("opts", opts).Trace("Setting mail from")
|
||||
func (su *smtpUser) Mail(returnPath string, opts goSMTPBackend.MailOptions) error {
|
||||
log.WithField("returnPath", returnPath).WithField("opts", opts).Trace("Setting mail from")
|
||||
|
||||
// REQUIRETLS and SMTPUTF8 have to be announced to be used by client.
|
||||
// Bridge does not use those extensions so this should not happen.
|
||||
@ -175,7 +176,14 @@ func (su *smtpUser) Mail(from string, opts goSMTPBackend.MailOptions) error {
|
||||
return errors.New("changing identity is not supported")
|
||||
}
|
||||
|
||||
su.from = from
|
||||
if returnPath != "" {
|
||||
addr := su.client().Addresses().ByEmail(returnPath)
|
||||
if addr == nil {
|
||||
return errors.New("backend: invalid return path: not owned by user")
|
||||
}
|
||||
}
|
||||
|
||||
su.returnPath = returnPath
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -191,17 +199,17 @@ func (su *smtpUser) Rcpt(to string) error {
|
||||
// Set currently processed message contents and send it.
|
||||
func (su *smtpUser) Data(r io.Reader) error {
|
||||
log.Trace("Sending the message")
|
||||
if su.from == "" {
|
||||
return errors.New("missing sender")
|
||||
if su.returnPath == "" {
|
||||
return errors.New("missing return path")
|
||||
}
|
||||
if len(su.to) == 0 {
|
||||
return errors.New("missing recipient")
|
||||
}
|
||||
return su.Send(su.from, su.to, r)
|
||||
return su.Send(su.returnPath, su.to, r)
|
||||
}
|
||||
|
||||
// Send sends an email from the given address to the given addresses with the given body.
|
||||
func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err error) { //nolint[funlen]
|
||||
func (su *smtpUser) Send(returnPath string, to []string, messageReader io.Reader) (err error) { //nolint[funlen]
|
||||
// Called from go-smtp in goroutines - we need to handle panics for each function.
|
||||
defer su.panicHandler.HandlePanic()
|
||||
|
||||
@ -210,7 +218,34 @@ func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err
|
||||
return err
|
||||
}
|
||||
|
||||
var addr *pmapi.Address = su.client().Addresses().ByEmail(from)
|
||||
returnPathAddr := su.client().Addresses().ByEmail(returnPath)
|
||||
if returnPathAddr == nil {
|
||||
err = errors.New("backend: invalid return path: not owned by user")
|
||||
return
|
||||
}
|
||||
|
||||
parser, err := parser.New(messageReader)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "failed to create new parser")
|
||||
return
|
||||
}
|
||||
message, plainBody, attReaders, err := pkgMessage.ParserWithParser(parser)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse message")
|
||||
return
|
||||
}
|
||||
richBody := message.Body
|
||||
|
||||
externalID := message.Header.Get("Message-Id")
|
||||
externalID = strings.Trim(externalID, "<>")
|
||||
|
||||
draftID, parentID := su.handleReferencesHeader(message)
|
||||
|
||||
if err = su.handleSenderAndRecipients(message, returnPathAddr, returnPath, to); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr := su.client().Addresses().ByEmail(message.Sender.Address)
|
||||
if addr == nil {
|
||||
err = errors.New("backend: invalid email address: not owned by user")
|
||||
return
|
||||
@ -237,20 +272,14 @@ func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err
|
||||
attachedPublicKeyName = fmt.Sprintf("publickey - %v - %v", kr.GetIdentities()[0].Name, firstKey.GetFingerprint()[:8])
|
||||
}
|
||||
|
||||
message, mimeBody, plainBody, attReaders, err := message.Parse(messageReader, attachedPublicKey, attachedPublicKeyName)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse message")
|
||||
return
|
||||
if attachedPublicKey != "" {
|
||||
pkgMessage.AttachPublicKey(parser, attachedPublicKey, attachedPublicKeyName)
|
||||
}
|
||||
richBody := message.Body
|
||||
|
||||
externalID := message.Header.Get("Message-Id")
|
||||
externalID = strings.Trim(externalID, "<>")
|
||||
|
||||
draftID, parentID := su.handleReferencesHeader(message)
|
||||
|
||||
if err = su.handleSenderAndRecipients(message, addr, from, to); err != nil {
|
||||
return err
|
||||
mimeBody, err := pkgMessage.BuildMIMEBody(parser)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to build message")
|
||||
return
|
||||
}
|
||||
|
||||
message.AddressID = addr.ID
|
||||
@ -415,14 +444,14 @@ func (su *smtpUser) handleReferencesHeader(m *pmapi.Message) (draftID, parentID
|
||||
return draftID, parentID
|
||||
}
|
||||
|
||||
func (su *smtpUser) handleSenderAndRecipients(m *pmapi.Message, addr *pmapi.Address, from string, to []string) (err error) {
|
||||
from = pmapi.ConstructAddress(from, addr.Email)
|
||||
func (su *smtpUser) handleSenderAndRecipients(m *pmapi.Message, returnPathAddr *pmapi.Address, returnPath string, to []string) (err error) {
|
||||
returnPath = pmapi.ConstructAddress(returnPath, returnPathAddr.Email)
|
||||
|
||||
// Check sender.
|
||||
if m.Sender == nil {
|
||||
m.Sender = &mail.Address{Address: from}
|
||||
} else {
|
||||
m.Sender.Address = from
|
||||
m.Sender = &mail.Address{Address: returnPath}
|
||||
} else if m.Sender.Address == "" {
|
||||
m.Sender.Address = returnPath
|
||||
}
|
||||
|
||||
// Check recipients.
|
||||
|
||||
@ -263,7 +263,7 @@ func (p *PMAPIProvider) parseMessage(msg Message) (m *pmapi.Message, r []io.Read
|
||||
}
|
||||
}
|
||||
}()
|
||||
message, _, _, attachmentReaders, err := pkgMessage.Parse(bytes.NewBuffer(msg.Body), "", "")
|
||||
message, _, _, attachmentReaders, err := pkgMessage.Parse(bytes.NewBuffer(msg.Body))
|
||||
return message, attachmentReaders, err
|
||||
}
|
||||
|
||||
|
||||
@ -36,15 +36,30 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeBody, plainBody string, attReaders []io.Reader, err error) {
|
||||
logrus.Trace("Parsing message")
|
||||
|
||||
// Parse parses RAW message.
|
||||
func Parse(r io.Reader) (m *pmapi.Message, mimeBody, plainBody string, attReaders []io.Reader, err error) {
|
||||
p, err := parser.New(r)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "failed to create new parser")
|
||||
return
|
||||
return nil, "", "", nil, errors.Wrap(err, "failed to create new parser")
|
||||
}
|
||||
|
||||
m, plainBody, attReaders, err = ParserWithParser(p)
|
||||
if err != nil {
|
||||
return nil, "", "", nil, errors.Wrap(err, "failed to parse the message")
|
||||
}
|
||||
|
||||
mimeBody, err = BuildMIMEBody(p)
|
||||
if err != nil {
|
||||
return nil, "", "", nil, errors.Wrap(err, "failed to build mime body")
|
||||
}
|
||||
|
||||
return m, mimeBody, plainBody, attReaders, nil
|
||||
}
|
||||
|
||||
// ParserWithParser parses message from Parser without building MIME body.
|
||||
func ParserWithParser(p *parser.Parser) (m *pmapi.Message, plainBody string, attReaders []io.Reader, err error) {
|
||||
logrus.Trace("Parsing message")
|
||||
|
||||
if err = convertEncodedTransferEncoding(p); err != nil {
|
||||
err = errors.Wrap(err, "failed to convert encoded transfer encodings")
|
||||
return
|
||||
@ -77,13 +92,11 @@ func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeBody, plainB
|
||||
return
|
||||
}
|
||||
|
||||
// We only attach the public key manually to the MIME body for
|
||||
// signed/encrypted external recipients. It's not important for it to be
|
||||
// collected as an attachment; that's already done when we upload the draft.
|
||||
if key != "" {
|
||||
attachPublicKey(p.Root(), key, keyName)
|
||||
}
|
||||
return m, plainBody, attReaders, nil
|
||||
}
|
||||
|
||||
// BuildMIMEBody builds mime body from the parser returned by NewParser.
|
||||
func BuildMIMEBody(p *parser.Parser) (mimeBody string, err error) {
|
||||
mimeBodyBuffer := new(bytes.Buffer)
|
||||
|
||||
if err = p.NewWriter().Write(mimeBodyBuffer); err != nil {
|
||||
@ -91,7 +104,7 @@ func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeBody, plainB
|
||||
return
|
||||
}
|
||||
|
||||
return m, mimeBodyBuffer.String(), plainBody, attReaders, nil
|
||||
return mimeBodyBuffer.String(), nil
|
||||
}
|
||||
|
||||
// convertEncodedTransferEncoding decodes any RFC2047-encoded content transfer encodings.
|
||||
@ -381,14 +394,14 @@ func getPlainBody(part *parser.Part) []byte {
|
||||
}
|
||||
}
|
||||
|
||||
func attachPublicKey(p *parser.Part, key, keyName string) {
|
||||
func AttachPublicKey(p *parser.Parser, key, keyName string) {
|
||||
h := message.Header{}
|
||||
|
||||
h.Set("Content-Type", fmt.Sprintf(`application/pgp-keys; name="%v.asc"; filename="%v.asc"`, keyName, keyName))
|
||||
h.Set("Content-Disposition", fmt.Sprintf(`attachment; name="%v.asc"; filename="%v.asc"`, keyName, keyName))
|
||||
h.Set("Content-Transfer-Encoding", "base64")
|
||||
|
||||
p.AddChild(&parser.Part{
|
||||
p.Root().AddChild(&parser.Part{
|
||||
Header: h,
|
||||
Body: []byte(key),
|
||||
})
|
||||
|
||||
@ -25,6 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/message/parser"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
@ -33,7 +34,7 @@ import (
|
||||
func TestParseTextPlain(t *testing.T) {
|
||||
f := getFileReader("text_plain.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -48,7 +49,7 @@ func TestParseTextPlain(t *testing.T) {
|
||||
func TestParseTextPlainUTF8(t *testing.T) {
|
||||
f := getFileReader("text_plain_utf8.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -63,7 +64,7 @@ func TestParseTextPlainUTF8(t *testing.T) {
|
||||
func TestParseTextPlainLatin1(t *testing.T) {
|
||||
f := getFileReader("text_plain_latin1.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -78,7 +79,7 @@ func TestParseTextPlainLatin1(t *testing.T) {
|
||||
func TestParseTextPlainUTF8Subject(t *testing.T) {
|
||||
f := getFileReader("text_plain_utf8_subject.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -94,7 +95,7 @@ func TestParseTextPlainUTF8Subject(t *testing.T) {
|
||||
func TestParseTextPlainLatin2Subject(t *testing.T) {
|
||||
f := getFileReader("text_plain_latin2_subject.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -110,7 +111,7 @@ func TestParseTextPlainLatin2Subject(t *testing.T) {
|
||||
func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) {
|
||||
f := getFileReader("text_plain_unknown_latin1.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -125,7 +126,7 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) {
|
||||
func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) {
|
||||
f := getFileReader("text_plain_unknown_latin2.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -146,7 +147,7 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) {
|
||||
func TestParseTextPlainAlready7Bit(t *testing.T) {
|
||||
f := getFileReader("text_plain_7bit.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -161,7 +162,7 @@ func TestParseTextPlainAlready7Bit(t *testing.T) {
|
||||
func TestParseTextPlainWithOctetAttachment(t *testing.T) {
|
||||
f := getFileReader("text_plain_octet_attachment.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -177,7 +178,7 @@ func TestParseTextPlainWithOctetAttachment(t *testing.T) {
|
||||
func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) {
|
||||
f := getFileReader("text_plain_octet_attachment_good_2231_filename.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -194,7 +195,7 @@ func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) {
|
||||
func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) {
|
||||
f := getFileReader("text_plain_octet_attachment_bad_2231_filename.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -211,7 +212,7 @@ func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) {
|
||||
func TestParseTextPlainWithPlainAttachment(t *testing.T) {
|
||||
f := getFileReader("text_plain_plain_attachment.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -227,7 +228,7 @@ func TestParseTextPlainWithPlainAttachment(t *testing.T) {
|
||||
func TestParseTextPlainEmptyAddresses(t *testing.T) {
|
||||
f := getFileReader("text_plain_empty_addresses.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -242,7 +243,7 @@ func TestParseTextPlainEmptyAddresses(t *testing.T) {
|
||||
func TestParseTextPlainWithImageInline(t *testing.T) {
|
||||
f := getFileReader("text_plain_image_inline.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -262,7 +263,7 @@ func TestParseTextPlainWithImageInline(t *testing.T) {
|
||||
func TestParseTextPlainWithDuplicateCharset(t *testing.T) {
|
||||
f := getFileReader("text_plain_duplicate_charset.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -277,7 +278,7 @@ func TestParseTextPlainWithDuplicateCharset(t *testing.T) {
|
||||
func TestParseWithMultipleTextParts(t *testing.T) {
|
||||
f := getFileReader("multiple_text_parts.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -292,7 +293,7 @@ func TestParseWithMultipleTextParts(t *testing.T) {
|
||||
func TestParseTextHTML(t *testing.T) {
|
||||
f := getFileReader("text_html.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -307,7 +308,7 @@ func TestParseTextHTML(t *testing.T) {
|
||||
func TestParseTextHTMLAlready7Bit(t *testing.T) {
|
||||
f := getFileReader("text_html_7bit.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -322,7 +323,7 @@ func TestParseTextHTMLAlready7Bit(t *testing.T) {
|
||||
func TestParseTextHTMLWithOctetAttachment(t *testing.T) {
|
||||
f := getFileReader("text_html_octet_attachment.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -338,7 +339,7 @@ func TestParseTextHTMLWithOctetAttachment(t *testing.T) {
|
||||
func TestParseTextHTMLWithPlainAttachment(t *testing.T) {
|
||||
f := getFileReader("text_html_plain_attachment.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -355,7 +356,7 @@ func TestParseTextHTMLWithPlainAttachment(t *testing.T) {
|
||||
func TestParseTextHTMLWithImageInline(t *testing.T) {
|
||||
f := getFileReader("text_html_image_inline.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -375,7 +376,10 @@ func TestParseTextHTMLWithImageInline(t *testing.T) {
|
||||
func TestParseWithAttachedPublicKey(t *testing.T) {
|
||||
f := getFileReader("text_plain.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "publickey", "publickeyname")
|
||||
p, err := parser.New(f)
|
||||
require.NoError(t, err)
|
||||
m, plainBody, attReaders, err := ParserWithParser(p)
|
||||
AttachPublicKey(p, "publickey", "publickeyname")
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -392,7 +396,7 @@ func TestParseWithAttachedPublicKey(t *testing.T) {
|
||||
func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) {
|
||||
f := getFileReader("text_html_embedded_foreign_encoding.eml")
|
||||
|
||||
m, _, plainBody, attReaders, err := Parse(f, "", "")
|
||||
m, _, plainBody, attReaders, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||
@ -407,7 +411,7 @@ func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) {
|
||||
func TestParseMultipartAlternative(t *testing.T) {
|
||||
f := getFileReader("multipart_alternative.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"schizofrenic" <schizofrenic@pm.me>`, m.Sender.String())
|
||||
@ -428,7 +432,7 @@ func TestParseMultipartAlternative(t *testing.T) {
|
||||
func TestParseMultipartAlternativeNested(t *testing.T) {
|
||||
f := getFileReader("multipart_alternative_nested.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"schizofrenic" <schizofrenic@pm.me>`, m.Sender.String())
|
||||
@ -449,7 +453,7 @@ func TestParseMultipartAlternativeNested(t *testing.T) {
|
||||
func TestParseMultipartAlternativeLatin1(t *testing.T) {
|
||||
f := getFileReader("multipart_alternative_latin1.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"schizofrenic" <schizofrenic@pm.me>`, m.Sender.String())
|
||||
@ -470,7 +474,7 @@ func TestParseMultipartAlternativeLatin1(t *testing.T) {
|
||||
func TestParseWithTrailingEndOfMailIndicator(t *testing.T) {
|
||||
f := getFileReader("text_html_trailing_end_of_mail.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@sender.com>`, m.Sender.String())
|
||||
@ -483,7 +487,7 @@ func TestParseWithTrailingEndOfMailIndicator(t *testing.T) {
|
||||
func TestParseEncodedContentType(t *testing.T) {
|
||||
f := getFileReader("rfc2047-content-transfer-encoding.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@sender.com>`, m.Sender.String())
|
||||
@ -495,7 +499,7 @@ func TestParseEncodedContentType(t *testing.T) {
|
||||
func TestParseNonEncodedContentType(t *testing.T) {
|
||||
f := getFileReader("non-encoded-content-transfer-encoding.eml")
|
||||
|
||||
m, _, plainBody, _, err := Parse(f, "", "")
|
||||
m, _, plainBody, _, err := Parse(f)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `"Sender" <sender@sender.com>`, m.Sender.String())
|
||||
@ -507,7 +511,7 @@ func TestParseNonEncodedContentType(t *testing.T) {
|
||||
func TestParseEncodedContentTypeBad(t *testing.T) {
|
||||
f := getFileReader("rfc2047-content-transfer-encoding-bad.eml")
|
||||
|
||||
_, _, _, _, err := Parse(f, "", "") // nolint[dogsled]
|
||||
_, _, _, _, err := Parse(f) // nolint[dogsled]
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
|
||||
@ -211,7 +211,7 @@ func (api *FakePMAPI) Import(importMessageRequests []*pmapi.ImportMsgReq) ([]*pm
|
||||
}
|
||||
|
||||
func (api *FakePMAPI) generateMessageFromImportRequest(msgReq *pmapi.ImportMsgReq) (*pmapi.Message, error) {
|
||||
m, _, _, _, err := message.Parse(bytes.NewReader(msgReq.Body), "", "") // nolint[dogsled]
|
||||
m, _, _, _, err := message.Parse(bytes.NewReader(msgReq.Body)) // nolint[dogsled]
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ Feature: SMTP initiation
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.me>"
|
||||
When SMTP client sends "MAIL FROM:<[userAddress]>"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "RCPT TO:<user@pm.me>"
|
||||
Then SMTP response is "OK"
|
||||
@ -37,7 +37,7 @@ Feature: SMTP initiation
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.me>"
|
||||
When SMTP client sends "MAIL FROM:<[userAddress]>"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "DATA"
|
||||
Then SMTP response is "SMTP error: 502 5.5.1 Missing RCPT TO command."
|
||||
@ -53,13 +53,13 @@ Feature: SMTP initiation
|
||||
When SMTP client sends "DATA"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "hello\r\n."
|
||||
Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: missing sender"
|
||||
Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: missing return path"
|
||||
|
||||
Scenario: Send with empty TO
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.me>"
|
||||
When SMTP client sends "MAIL FROM:<[userAddress]>"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "RCPT TO:<>"
|
||||
Then SMTP response is "OK"
|
||||
@ -72,12 +72,19 @@ Feature: SMTP initiation
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.me> BODY=7BIT"
|
||||
When SMTP client sends "MAIL FROM:<[userAddress]> BODY=7BIT"
|
||||
Then SMTP response is "OK"
|
||||
|
||||
Scenario: Allow AUTH parameter of MAIL FROM command
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.me> AUTH=<>"
|
||||
When SMTP client sends "MAIL FROM:<[userAddress]> AUTH=<>"
|
||||
Then SMTP response is "OK"
|
||||
|
||||
Scenario: FROM not owned by user
|
||||
Given there is connected user "user"
|
||||
When SMTP client authenticates "user"
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends "MAIL FROM:<user@pm.test>"
|
||||
Then SMTP response is "SMTP error: 451 4.0.0 backend: invalid return path: not owned by user"
|
||||
|
||||
@ -7,7 +7,7 @@ Feature: SMTP with bcc
|
||||
When SMTP client sends message with bcc "bridgetest2@protonmail.com"
|
||||
"""
|
||||
Subject: hello
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
@ -43,7 +43,7 @@ Feature: SMTP with bcc
|
||||
When SMTP client sends message with bcc "bridgetest@protonmail.com"
|
||||
"""
|
||||
Subject: hello
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
|
||||
hello
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ Feature: SMTP wrong messages
|
||||
Scenario: Message with attachment and wrong boundaries
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: With attachment (wrong boundaries)
|
||||
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
|
||||
@ -39,3 +39,14 @@ Feature: SMTP wrong messages
|
||||
|
||||
"""
|
||||
Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: failed to create new parser: unexpected EOF"
|
||||
|
||||
Scenario: Invalid from
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
|
||||
"""
|
||||
Then SMTP response is "SMTP error: 554 5.0.0 Error: transaction failed, blame it on the weather: backend: invalid email address: not owned by user"
|
||||
|
||||
@ -6,7 +6,7 @@ Feature: SMTP sending of HTML messages
|
||||
Scenario: HTML message to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: HTML text external
|
||||
Content-Disposition: inline
|
||||
@ -45,7 +45,7 @@ Feature: SMTP sending of HTML messages
|
||||
Scenario: HTML message with inline image to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Html Inline External
|
||||
Content-Disposition: inline
|
||||
@ -120,7 +120,7 @@ Feature: SMTP sending of HTML messages
|
||||
Scenario: HTML message with alternative inline to internal account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Html Inline Alternative Internal
|
||||
Content-Disposition: inline
|
||||
@ -209,7 +209,7 @@ Feature: SMTP sending of HTML messages
|
||||
Scenario: HTML message with alternative inline to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Html Inline Alternative External
|
||||
Content-Disposition: inline
|
||||
|
||||
@ -6,7 +6,7 @@ Feature: SMTP sending of HTML messages with attachments
|
||||
Scenario: HTML message with attachment to internal account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: HTML with attachment internal
|
||||
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
|
||||
@ -65,7 +65,7 @@ Feature: SMTP sending of HTML messages with attachments
|
||||
Scenario: HTML message with attachment to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: HTML with attachment external PGP
|
||||
Content-Type: multipart/mixed; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
|
||||
|
||||
@ -6,7 +6,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Only from and to headers to internal account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
@ -40,7 +40,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Only from and to headers to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
|
||||
hello
|
||||
@ -74,7 +74,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Basic message to internal account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Plain text internal
|
||||
Content-Disposition: inline
|
||||
@ -111,7 +111,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Basic message to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Plain text external
|
||||
Content-Disposition: inline
|
||||
@ -148,7 +148,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Message without charset is utf8
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Plain text no charset external
|
||||
Content-Disposition: inline
|
||||
@ -185,7 +185,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Message without charset is base64-encoded latin1
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Plain text no charset external
|
||||
Content-Disposition: inline
|
||||
@ -225,7 +225,7 @@ Feature: SMTP sending of plain messages
|
||||
Scenario: Message without charset and content is detected as HTML
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Plain, no charset, no content, external
|
||||
Content-Disposition: inline
|
||||
|
||||
@ -6,7 +6,7 @@ Feature: SMTP sending of plain messages with attachments
|
||||
Scenario: Basic message with attachment to internal account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Plain with attachment
|
||||
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
|
||||
@ -65,7 +65,7 @@ Feature: SMTP sending of plain messages with attachments
|
||||
Scenario: Plain message with attachment to external account
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge <pm.bridge.qa@gmail.com>
|
||||
Subject: Plain with attachment external
|
||||
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
|
||||
@ -124,7 +124,7 @@ Feature: SMTP sending of plain messages with attachments
|
||||
Scenario: Plain message with attachment to two external accounts
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: External Bridge 1 <pm.bridge.qa@gmail.com>
|
||||
CC: External Bridge 2 <bridgeqa@seznam.cz>
|
||||
Subject: Plain with attachment external PGP and external CC
|
||||
|
||||
@ -4,7 +4,7 @@ Feature: SMTP sending the same message twice
|
||||
And there is SMTP client logged in as "user"
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Hello
|
||||
|
||||
@ -16,7 +16,7 @@ Feature: SMTP sending the same message twice
|
||||
Scenario: The exact same message is not sent twice
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Hello
|
||||
|
||||
@ -31,7 +31,7 @@ Feature: SMTP sending the same message twice
|
||||
Scenario: Slight change means different message and is sent twice
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
Subject: Hello.
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ Feature: SMTP sending two messages
|
||||
And there is SMTP client logged in as "user"
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
@ -13,7 +13,7 @@ Feature: SMTP sending two messages
|
||||
Then SMTP response is "OK"
|
||||
When SMTP client sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
world
|
||||
@ -28,7 +28,7 @@ Feature: SMTP sending two messages
|
||||
And there is SMTP client "smtp2" logged in as "userMoreAddresses" with address "secondary"
|
||||
When SMTP client "smtp1" sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
@ -37,7 +37,7 @@ Feature: SMTP sending two messages
|
||||
Then SMTP response to "smtp1" is "OK"
|
||||
When SMTP client "smtp2" sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
world
|
||||
@ -53,7 +53,7 @@ Feature: SMTP sending two messages
|
||||
|
||||
When SMTP client "smtp1" sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
hello
|
||||
@ -62,7 +62,7 @@ Feature: SMTP sending two messages
|
||||
Then SMTP response to "smtp1" is "OK"
|
||||
When SMTP client "smtp2" sends message
|
||||
"""
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
From: Bridge Test <[userAddress]>
|
||||
To: Internal Bridge <bridgetest@protonmail.com>
|
||||
|
||||
world
|
||||
|
||||
@ -74,6 +74,8 @@ func (c *SMTPClient) SendCommands(commands ...string) *SMTPResponse {
|
||||
smtpResponse := &SMTPResponse{t: c.t}
|
||||
|
||||
for _, command := range commands {
|
||||
command = strings.ReplaceAll(command, "[userAddress]", c.address)
|
||||
|
||||
tstart := time.Now()
|
||||
|
||||
c.debug.printReq(command)
|
||||
|
||||
@ -17,3 +17,6 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
||||
### Changed
|
||||
* GODT-858 Bump go-rfc5322 dependency to v0.4.0 to handle some invalid RFC5322 groups.
|
||||
* GODT-923 Fix listener locking.
|
||||
|
||||
### Changed
|
||||
* GODT-389 Prefer `From` header instead of `MAIL FROM` address.
|
||||
|
||||
Reference in New Issue
Block a user