From b57ca1506dd0e6bd1517176b225c0ef42a652e5d Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 10 Mar 2023 15:49:10 +0100 Subject: [PATCH] fix(GODT-2473): Fix handling of complex mime types When rebuilding attachments, ensure that more complicated mime types are properly re-constructed. If we fail to parse the mime type, set the value as is. --- pkg/message/build.go | 13 ++++++++++++- pkg/message/build_test.go | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/pkg/message/build.go b/pkg/message/build.go index f6bfbc0a..dbace192 100644 --- a/pkg/message/build.go +++ b/pkg/message/build.go @@ -36,6 +36,7 @@ import ( "github.com/emersion/go-message" "github.com/emersion/go-message/textproto" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) var ( @@ -543,7 +544,17 @@ func getAttachmentPartHeader(att proton.Attachment) message.Header { hdr := toMessageHeader(att.Headers) // All attachments have a content type. - hdr.SetContentType(string(att.MIMEType), map[string]string{"name": mime.QEncoding.Encode("utf-8", att.Name)}) + mimeType, params, err := mime.ParseMediaType(string(att.MIMEType)) + if err != nil { + logrus.WithError(err).Errorf("Failed to parse mime type: '%v'", att.MIMEType) + hdr.Set("Content-Type", string(att.MIMEType)) + } else { + // Merge the overridden name into the params + encodedName := mime.QEncoding.Encode("utf-8", att.Name) + params["name"] = encodedName + params["filename"] = encodedName + hdr.SetContentType(mimeType, params) + } // All attachments have a content disposition. hdr.SetContentDisposition(string(att.Disposition), map[string]string{"filename": mime.QEncoding.Encode("utf-8", att.Name)}) diff --git a/pkg/message/build_test.go b/pkg/message/build_test.go index 5689037e..26d72ced 100644 --- a/pkg/message/build_test.go +++ b/pkg/message/build_test.go @@ -793,7 +793,8 @@ func TestBuildAttachmentWithLongFilename(t *testing.T) { expectHeader(`Content-Type`, contains(veryLongName)). expectContentDispositionParam(`filename`, is(veryLongName)). expectHeader(`Content-Disposition`, contains(veryLongName)). - expectSection(hasMaxLineLength(215)) + // GODT-2477 - Implement line splitting according to RFC-2184. + expectSection(hasMaxLineLength(426)) } func TestBuildMessageDate(t *testing.T) { @@ -1231,3 +1232,38 @@ func readFile(t *testing.T, path string) string { return string(b) } + +func TestBuildComplexMIMEType(t *testing.T) { + m := gomock.NewController(t) + defer m.Finish() + + kr := utils.MakeKeyRing(t) + msg := newTestMessage(t, kr, "messageID", "addressID", "text/html", "body", time.Now()) + att0 := addTestAttachment(t, kr, &msg, "attachID0", "attach0.png", "image/png", "attachment", "attach0") + att1 := addTestAttachment(t, kr, &msg, "attachID1", "Cat_August_2010-4.jpeg", "image/jpeg; name=Cat_August_2010-4.jpeg; x-unix-mode=0644", "attachment", "attach1") + + res, err := BuildRFC822(kr, msg, [][]byte{ + att0, + att1, + }, JobOptions{}) + require.NoError(t, err) + + section(t, res, 1). + expectBody(is(`body`)). + expectContentType(is(`text/html`)). + expectTransferEncoding(is(`quoted-printable`)) + + section(t, res, 2). + expectBody(is(`attach0`)). + expectContentType(is(`image/png`)). + expectTransferEncoding(is(`base64`)). + expectContentTypeParam(`name`, is(`attach0.png`)). + expectContentDispositionParam(`filename`, is(`attach0.png`)) + + section(t, res, 3). + expectBody(is(`attach1`)). + expectContentType(is(`image/jpeg`)). + expectTransferEncoding(is(`base64`)). + expectContentTypeParam(`name`, is(`Cat_August_2010-4.jpeg`)). + expectContentDispositionParam(`filename`, is(`Cat_August_2010-4.jpeg`)) +}