From c0f6af9eb57347a616d29f20e861fcc4dec612ce Mon Sep 17 00:00:00 2001 From: James Houlahan Date: Fri, 26 Mar 2021 09:53:36 +0100 Subject: [PATCH] GODT-213: Complex external encrypted tests (multipart/alternative, message/rfc822 attachment) --- internal/imap/backend.go | 16 +- pkg/message/build_rfc822_custom.go | 33 +++ pkg/message/build_test.go | 126 +++++++++++ ...ed-embedded-message-rfc822-with-pubkey.eml | 212 ++++++++++++++++++ ...gned-multipart-alternative-with-pubkey.eml | 161 +++++++++++++ 5 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml create mode 100644 pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml diff --git a/internal/imap/backend.go b/internal/imap/backend.go index 697f4fa7..aff3778b 100644 --- a/internal/imap/backend.go +++ b/internal/imap/backend.go @@ -16,6 +16,19 @@ // along with ProtonMail Bridge. If not, see . // Package imap provides IMAP server of the Bridge. +// +// Methods are called by the go-imap library in parallel. +// Additional parallelism is achieved while handling each IMAP request. +// +// For example, ListMessages internally uses `fetchWorkers` workers to resolve each requested item. +// When IMAP clients request message literals (or parts thereof), we sometimes need to build RFC822 message literals. +// To do this, we pass build jobs to the message builder, which internally manages its own parallelism. +// Summary: +// - each IMAP fetch request is handled in parallel, +// - within each IMAP fetch request, individual items are handled by a pool of `fetchWorkers` workers, +// - within each worker, build jobs are posted to the message builder, +// - the message builder handles build jobs using its own, independent worker pool, +// The builder will handle jobs in parallel up to its own internal limit. This prevents it from overwhelming API. package imap import ( @@ -32,7 +45,8 @@ import ( ) const ( - // NOTE: Each fetch worker has its own set of attach workers so there can up to 20*5=100 API requests at once. + // NOTE: Each fetch worker has its own set of attach workers so there can be up to 20*5=100 API requests at once. + // This is a reasonable limit to not overwhelm API while still maintaining as much parallelism as possible. fetchWorkers = 20 // In how many workers to fetch message (group list on IMAP). attachWorkers = 5 // In how many workers to fetch attachments (for one message). buildWorkers = 20 // In how many workers to build messages. diff --git a/pkg/message/build_rfc822_custom.go b/pkg/message/build_rfc822_custom.go index 477f0e27..07d56da4 100644 --- a/pkg/message/build_rfc822_custom.go +++ b/pkg/message/build_rfc822_custom.go @@ -28,6 +28,39 @@ import ( ) // writeCustomTextPart writes an armored-PGP text part for a message body that couldn't be decrypted. +// The following is an example of such a message. +/* +Mime-Version: 1.0 +Content-Type: multipart/mixed; + boundary=d8a04ef2e12150946d27f84fc82b9e70a5e314f91a0f2190e38c7aad623466da +Message-Id: +Date: Fri, 26 Mar 2021 14:10:00 +0000 + +--d8a04ef2e12150946d27f84fc82b9e70a5e314f91a0f2190e38c7aad623466da +Content-Type: text/plain + +-----BEGIN PGP MESSAGE----- +Version: GopenPGP 2.1.3 +Comment: This message could not be decrypted: gopenpgp: error in reading message: openpgp: incorrect key + +wcBMA1iOyuyBImpHAQf/boKq75jyV5kGzl8ObcjLuaVrVEw5YbrI1M9gAb/5eq+t +Mzd2qK0owYwBmuvYj3pk2b15miOIPfAYlbQVyIaseq/O4XchPvtJZKxh42eDcYhD +zwqHrYxtCLOOBY6b15Aq8tVLORi4+/VCWJrTHtCdKq71UX7bvBdQRaZqOIJ+bUiP +72IkaWjdVmCgLCmzPN3R3VKsmjTNBt1GRMc6vosQyoAeClyf94wgE1sXGsumXBQs +MX69zK9a36Ya67PpQ9AGVR2peEF07s5O+t/PxkStWfFvMwnnOOSgdHfN0PSwkhoL +EIwDA6lh7+2UlbX9pFi908PDl0OuoLgrL+NyleUPtdLAugGUa0U1fn6K1gwFGcsj +DKflgAMXixhf83xpmz4fM3zzM988ecQsXozQcUDrxSTxzdfWXSaWQDWHguCiL0xM +aPkf4kUn4RX3AoZVTC4GXvupzAQUqjJhyd0p7lJGOwIw0Ik77PxeCFNvWiZHJ3W+ +7PYuehSUgyDJJe7q1GFFcMUspnPmuvhbenKIHlKwGfptnXLRIW15sdcca2Etz5i4 +H71rHKwzAPdNHBQVvN0Nmt77RGAIy4Az8fRwz7hD7E92r4BkaaYntrQe9DUXYc50 +HVXyeFcvpfbEaK+fObxk1ljig+Io2liPx7pn/YBFytMy1mlwhjroMPjMUXuTXqje +NHnOJVxnnXMwGh34wUIEwOmTskJoGkQjQbjvixkwNRGnLzIHuD6614pXtgTDtBzc +AKuQssqOky1Q7KjdusMWnoVL7gTbSrIUxXoKChear5XgPzFevQhQNEfTI8DDMbYR +La1Cc6aFtMPUShzNc3Wp3dVLM09WygEUsYZFmA== +=00ma +-----END PGP MESSAGE----- +--d8a04ef2e12150946d27f84fc82b9e70a5e314f91a0f2190e38c7aad623466da-- +*/ func writeCustomTextPart( w *message.Writer, msg *pmapi.Message, diff --git a/pkg/message/build_test.go b/pkg/message/build_test.go index 82e909b3..b5f92d93 100644 --- a/pkg/message/build_test.go +++ b/pkg/message/build_test.go @@ -326,6 +326,132 @@ func TestBuildSignedHTMLEncryptedMessageWithPubKey(t *testing.T) { expectContentDispositionParam(`filename`, is(`OpenPGP_signature`)) } +func TestBuildSignedMultipartAlternativeEncryptedMessageWithPubKey(t *testing.T) { + m := gomock.NewController(t) + defer m.Finish() + + b := NewBuilder(1, 1, 1) + defer b.Done() + + body := readerToString(getFileReader("pgp-mime-body-signed-multipart-alternative-with-pubkey.eml")) + + kr := tests.MakeKeyRing(t) + msg := newTestMessage(t, kr, "messageID", "addressID", "multipart/mixed", body, time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)) + + res, err := b.NewJob(context.Background(), newTestFetcher(m, kr, msg), msg.ID).GetResult() + require.NoError(t, err) + + section(t, res). + expectContentType(is(`multipart/mixed`)). + expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)) + + section(t, res, 1). + expectContentType(is(`multipart/signed`)). + expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) + + section(t, res, 1, 1). + expectContentType(is(`multipart/mixed`)). + expectContentTypeParam(`protected-headers`, is(`v1`)). + expectHeader(`Subject`, is(`Alternative`)). + expectHeader(`From`, is(`"pm.bridge.qa" `)). + expectHeader(`To`, is(`schizofrenic@pm.me`)). + expectSection(verifiesAgainst(section(t, res, 1, 1, 1, 3).pubKey(), section(t, res, 1, 2).signature())) + + section(t, res, 1, 1, 1). + expectContentType(is(`multipart/mixed`)) + + section(t, res, 1, 1, 1, 1). + expectContentType(is(`multipart/alternative`)) + + section(t, res, 1, 1, 1, 1, 1). + expectContentType(is(`text/plain`)). + expectBody(contains(`This Rich formated text`)). + expectBody(contains(`What kind of shoes do ninjas wear`)). + expectBody(contains(`How does a penguin build its house`)) + + section(t, res, 1, 1, 1, 1, 2). + expectContentType(is(`text/html`)). + expectBody(contains(`This Rich formated text`)). + expectBody(contains(`What kind of shoes do ninjas wear`)). + expectBody(contains(`How does a penguin build its house`)) + + section(t, res, 1, 1, 1, 2). + expectContentType(is(`application/pdf`)). + expectTransferEncoding(is(`base64`)). + expectContentTypeParam(`name`, is(`minimal.pdf`)). + expectContentDispositionParam(`filename`, is(`minimal.pdf`)) + + section(t, res, 1, 1, 1, 3). + expectContentType(is(`application/pgp-keys`)). + expectContentTypeParam(`name`, is(`OpenPGP_0x161C0875822359F7.asc`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`OpenPGP_0x161C0875822359F7.asc`)) + + section(t, res, 1, 2). + expectContentType(is(`application/pgp-signature`)). + expectContentTypeParam(`name`, is(`OpenPGP_signature.asc`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`OpenPGP_signature`)) +} + +func TestBuildSignedEmbeddedMessageRFC822EncryptedMessageWithPubKey(t *testing.T) { + m := gomock.NewController(t) + defer m.Finish() + + b := NewBuilder(1, 1, 1) + defer b.Done() + + body := readerToString(getFileReader("pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml")) + + kr := tests.MakeKeyRing(t) + msg := newTestMessage(t, kr, "messageID", "addressID", "multipart/mixed", body, time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)) + + res, err := b.NewJob(context.Background(), newTestFetcher(m, kr, msg), msg.ID).GetResult() + require.NoError(t, err) + + section(t, res). + expectContentType(is(`multipart/mixed`)). + expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)) + + section(t, res, 1). + expectContentType(is(`multipart/signed`)). + expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) + + section(t, res, 1, 1). + expectContentType(is(`multipart/mixed`)). + expectContentTypeParam(`protected-headers`, is(`v1`)). + expectHeader(`Subject`, is(`Fwd: HTML with attachment external PGP`)). + expectHeader(`From`, is(`"pm.bridge.qa" `)). + expectHeader(`To`, is(`schizofrenic@pm.me`)). + expectSection(verifiesAgainst(section(t, res, 1, 1, 1, 2).pubKey(), section(t, res, 1, 2).signature())) + + section(t, res, 1, 1, 1). + expectContentType(is(`multipart/mixed`)) + + section(t, res, 1, 1, 1, 1). + expectContentType(is(`text/plain`)) + + section(t, res, 1, 1, 1, 2). + expectContentType(is(`application/pgp-keys`)). + expectContentTypeParam(`name`, is(`OpenPGP_0x161C0875822359F7.asc`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`OpenPGP_0x161C0875822359F7.asc`)) + + section(t, res, 1, 1, 1, 3). + expectContentType(is(`message/rfc822`)). + expectContentTypeParam(`name`, is(`HTML with attachment external PGP.eml`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`HTML with attachment external PGP.eml`)) + + section(t, res, 1, 2). + expectContentType(is(`application/pgp-signature`)). + expectContentTypeParam(`name`, is(`OpenPGP_signature.asc`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`OpenPGP_signature`)) +} + func TestBuildHTMLMessageWithAttachment(t *testing.T) { m := gomock.NewController(t) defer m.Finish() diff --git a/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml new file mode 100644 index 00000000..69a0c258 --- /dev/null +++ b/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml @@ -0,0 +1,212 @@ +Content-Type: multipart/signed; micalg=pgp-sha256; + protocol="application/pgp-signature"; + boundary="Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS" + +This is an OpenPGP/MIME signed message (RFC 4880 and 3156) +--Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS +Content-Type: multipart/mixed; boundary="avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc"; + protected-headers="v1" +Subject: Fwd: HTML with attachment external PGP +From: "pm.bridge.qa" +To: schizofrenic@pm.me +Message-ID: <7c04869b-c470-116f-b8e5-8b4fd5e1195d@gmail.com> +References: +In-Reply-To: + +--avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc +Content-Type: multipart/mixed; + boundary="------------2F19EE9A8A1A6F779F5D14AF" +Content-Language: en-US + +This is a multi-part message in MIME format. +--------------2F19EE9A8A1A6F779F5D14AF +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: quoted-printable + + + +--------------2F19EE9A8A1A6F779F5D14AF +Content-Type: application/pgp-keys; + name="OpenPGP_0x161C0875822359F7.asc" +Content-Transfer-Encoding: quoted-printable +Content-Disposition: attachment; + filename="OpenPGP_0x161C0875822359F7.asc" + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= +pDh +I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= +f4S +PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= +Snd +NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= +OfN +H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= +XUt +RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= +BYC +AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= +/K8 +B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= +Vcz +1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= +V0U +u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= +6Pa +4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= +TVQ +IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= +D07 +kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= +88F +yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= +knm +3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= +utT +ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= +8RB +owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= +C32 +lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= +L6H +jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= +xI5 +RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= +osO +HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= +Etv +Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u +=3Dv/1p +-----END PGP PUBLIC KEY BLOCK----- + +--------------2F19EE9A8A1A6F779F5D14AF +Content-Type: message/rfc822; + name="HTML with attachment external PGP.eml" +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; + filename="HTML with attachment external PGP.eml" + +Delivered-To: pm.bridge.qa@gmail.com +Received: by 2002:a17:906:a051:0:0:0:0 with SMTP id bg17csp66709ejb; + Wed, 24 Mar 2021 22:03:32 -0700 (PDT) +X-Google-Smtp-Source: ABdhPJxllBuHnnJzKWy77R291tZbVFVk0iahkLm1TQsluEYTvyAXdOWB/zp1y10e60UlGGZYH3YF +X-Received: by 2002:a05:6000:118c:: with SMTP id g12mr6758087wrx.353.1616648612550; + Wed, 24 Mar 2021 22:03:32 -0700 (PDT) +ARC-Seal: i=1; a=rsa-sha256; t=1616648612; cv=none; + d=google.com; s=arc-20160816; + b=Jf4vmKEoeJQ3rIDMbI2twiDkfn50ejNnqIbs2nkaFruITcw6XhvhbcfV9HLC80Yt8E + tfN7TV9qoBneSWzfSJ+Sqw31hBKKtKpMhuqZT9GPzBN5gdMJKj5ISAQ8Lgm9zvR3Zbjn + N0nOzCu/oT1amMMm+48hpKj8VL2tydjvNG+g/a5lk1Aw7JdqIKV6t1XhsyyYaa1O+NFC + rQThdalcQj2NjoZWba1mjZSzI7B7hJdZg5d+jado2TPMQXe2kz2wGmr3+/JcKvPJjrSA + S+jzhpjcd7ZnctkzTfpsdlBJAGKoDBnSvQc3eMJ/AgRHFc+5ks5nRDt/1DowSjQ7i7rp + 4a+g== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=mime-version:message-id:subject:reply-to:from:to:dkim-signature + :date; + bh=vmJ0JT+IfeO4idMYP7zPvldBkdONjKTXWTp7ly/B9qk=; + b=f8VY+ajsE/XNYrqD666FM0WCtNEQtUyU/Zh3pFCI9sFrMnAui4Qp9Gs1fe/8HLxt2v + /C4l4eHELvPBv4vX0KtUvOlRZYPZbLZCNdtTcFtiuZEKUHWx370p7yyMWcmSMdlUbq4J + NrKMPGfaYiZe5Rt3MyD5RKm4RJpqvep34VCHMYtoFQP/0Po4/1JMDw0Fy6SXUJ54rBRw + bmzqNNBkonda3YghhK3WNrxTxzZ8I7KW9YdpENNS9ewJLeVtFQKdiLZwz5EpMZxOxG0I + LW0jRtDlmZnqRe7bvTAo51IuLf9okHRI8PRiK0UHl+4Vr5Igq4mub7Ee8pC/Nz3Yj29G + KODw== +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@protonmail.com header.s=protonmail header.b=EX07e46H; + spf=pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) smtp.mailfrom=bridge-test-user@protonmail.com; + dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com +Return-Path: +Received: from mail2.protonmail.ch (mail2.protonmail.ch. [185.70.40.22]) + by mx.google.com with ESMTPS id g6si2999785wrr.110.2021.03.24.22.03.32 + for + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Wed, 24 Mar 2021 22:03:32 -0700 (PDT) +Received-SPF: pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) client-ip=185.70.40.22; +Authentication-Results: mx.google.com; + dkim=pass header.i=@protonmail.com header.s=protonmail header.b=EX07e46H; + spf=pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) smtp.mailfrom=bridge-test-user@protonmail.com; + dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com +Date: Thu, 25 Mar 2021 05:03:27 +0000 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; + s=protonmail; t=1616648611; + bh=vmJ0JT+IfeO4idMYP7zPvldBkdONjKTXWTp7ly/B9qk=; + h=Date:To:From:Reply-To:Subject:From; + b=EX07e46H5/HmotAWZ69I4qa5jCVRao/p3KEM3eQn/AQ8s+cLMaR5b2ozdHrPCsTw5 + i5b1DLUHZHBf+6Ven47WJfKNwLUfkAGD2P0aI/dAk/h/h0Bg4Ni85pv+uPpRHLNQKv + T3VnDP9MSwl6IUJu5zoM2EC70MLoiHS07lxhM2pw= +To: External Bridge +From: Bridge Test +Reply-To: Bridge Test +Subject: HTML with attachment external PGP +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA" +X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, + DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE + shortcircuit=no autolearn=disabled version=3.4.4 +X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on + mailout.protonmail.ch + +This is a multi-part message in MIME format. + +--b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA +Content-Type: multipart/alternative; + boundary="b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA" + +--b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 + +VGhpcyBpcyBib2R5IG9mIEhUTUwgbWFpbCB3aXRoIGF0dGFjaG1lbnQ= + +--b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: base64 + +PGh0bWw+PGhlYWQ+PC9oZWFkPjxib2R5PlRoaXMgaXMgYm9keSBvZiA8Yj5IVE1MIG1haWw8L2I+ +IHdpdGggYXR0YWNobWVudA0KPC9ib2R5PjwvaHRtbD4= + + +--b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA-- + +--b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA +Content-Type: image/png; name=outline-light-instagram-48.png +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename=outline-light-instagram-48.png + +iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD///////////////// +//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd +OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg +WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv +1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I +BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6 +9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0 +YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP +HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy +KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg== + +--b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA-- + + +--------------2F19EE9A8A1A6F779F5D14AF-- + +--avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc-- + +--Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS +Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename="OpenPGP_signature" + +-----BEGIN PGP SIGNATURE----- + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBciIAFAwAAAAAACgkQFhwIdYIjWfcN +ZQf+NzAoEJRTSW5JFNgSGkwLsH89wAbw3wEt4PYuZaa+35xBuU8Sojm1oLOyuPkIasQf98Iu5P1o +8cokViEa6wm+ZZpcFMi6T2/3+UNlSm81Epm7GrFyjAFTWrdTPLb4k4x47sz77RoTp/UEwm/7fVI5 +gMYhQyIYaocXHmDk61UshWE9q/Po6qjHBnnWS8YBnhUS9lK8uimpfRO9UQ9bIUjIYDGDPAtBoYnb +X9V4SjBvbbdNrgoVaDxPw6HYCb3RhzRXunr5Icdnjfbc2H40/FayVi/p7GzFh+8zv/TzRxMkHo72 +DBsONaC7r8bxQ9BwJvpmWufqL7ZXHfVXQ6z+M43e1Q== +=Stx+ +-----END PGP SIGNATURE----- + +--Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS-- diff --git a/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml new file mode 100644 index 00000000..cfbf3434 --- /dev/null +++ b/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml @@ -0,0 +1,161 @@ +Content-Type: multipart/signed; micalg=pgp-sha256; + protocol="application/pgp-signature"; + boundary="MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM" + +This is an OpenPGP/MIME signed message (RFC 4880 and 3156) +--MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM +Content-Type: multipart/mixed; boundary="FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378"; + protected-headers="v1" +Subject: Alternative +From: "pm.bridge.qa" +To: schizofrenic@pm.me +Message-ID: <753d0314-0286-2c88-2abb-f8080ac7a4cb@gmail.com> + +--FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378 +Content-Type: multipart/mixed; + boundary="------------F97C8ED4878E94675762AE43" +Content-Language: en-US + +This is a multi-part message in MIME format. +--------------F97C8ED4878E94675762AE43 +Content-Type: multipart/alternative; + boundary="------------041318B15DD3FA540FED32C6" + + +--------------041318B15DD3FA540FED32C6 +Content-Type: text/plain; charset=utf-8; format=flowed +Content-Transfer-Encoding: quoted-printable + +This Rich formated text + + * /What kind of shoes do ninjas wear? /*Sneakers!* + * /How does a penguin build its house?/**_/*Igloos it together.*/_ + + + + +--------------041318B15DD3FA540FED32C6 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + + + + + + +

This Rich formated text

+
    +
  • What kind of shoes do ninjas wear? Sneakers!
  • = + +
  • How does a penguin build its house? Iglo= +os + it together.
  • +
+


+

+


+

+ + + +--------------041318B15DD3FA540FED32C6-- + +--------------F97C8ED4878E94675762AE43 +Content-Type: application/pdf; + name="minimal.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="minimal.pdf" + +JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1Bh +Z2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAg +L0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0 +NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVu +dCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8 +IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAv +U3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21h +bgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29u +dGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0 +cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBU +agogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAK +MDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAw +MDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAg +ICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg== +--------------F97C8ED4878E94675762AE43 +Content-Type: application/pgp-keys; + name="OpenPGP_0x161C0875822359F7.asc" +Content-Transfer-Encoding: quoted-printable +Content-Disposition: attachment; + filename="OpenPGP_0x161C0875822359F7.asc" + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= +pDh +I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= +f4S +PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= +Snd +NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= +OfN +H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= +XUt +RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= +BYC +AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= +/K8 +B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= +Vcz +1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= +V0U +u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= +6Pa +4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= +TVQ +IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= +D07 +kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= +88F +yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= +knm +3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= +utT +ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= +8RB +owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= +C32 +lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= +L6H +jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= +xI5 +RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= +osO +HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= +Etv +Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u +=3Dv/1p +-----END PGP PUBLIC KEY BLOCK----- + +--------------F97C8ED4878E94675762AE43-- + +--FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378-- + +--MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM +Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename="OpenPGP_signature" + +-----BEGIN PGP SIGNATURE----- + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBciUoFAwAAAAAACgkQFhwIdYIjWfez +rgf+NZCibnCUTovpWRVRiiPQtBPGeHUPEwz2xq2zz4AaqrHC2v4mYUIPe6am7INk8fkBLsa8Dj/A +UN/28Qh7tNb7JsXtHDT4PIoXszukQ8VIRbe09mSkkP6jR4WzNR166d6n3rSxzHpviOyQldjjpOMr +Zl7LxmgGr4ojsgCf6pvurWwCCOGJqbSusrD6JVv6DsmPmmQeBmnlTK/0oG9pnlNkugpNB1WS2K5d +RY6+kWkSrxbq95HrgILpHip8Y/+ITWvQocm14PBIAAdW8Hr7iFQLETFJ/KDA+VP19Bt8n4Kitdi8 +DPqMsV0oOhATqBjnD63AePJ0VWg8R1z6GEK5A+WOpg== +=Bc6p +-----END PGP SIGNATURE----- + +--MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM--