From 4b8511859a59dbaccf14fe0e9db7750bfbcd339b Mon Sep 17 00:00:00 2001 From: Jan Sterba Date: Fri, 21 Oct 2022 20:04:35 +0200 Subject: [PATCH] Fix ingress controllers' ability to accept non UTF-8 encoded emails Since most of the ingress controllers receive raw MIME data in POST body, it is impossible to guaratee that these are in UTF-8 as email comes in all possible encodings. This patch disables force transcoding to UTF-8 by ActionController params processing for params that contain RAW MIME email bodies. Fix #46297 --- actionmailbox/CHANGELOG.md | 6 +++ .../mailgun/inbound_emails_controller.rb | 1 + .../postmark/inbound_emails_controller.rb | 1 + .../sendgrid/inbound_emails_controller.rb | 1 + .../mailgun/inbound_emails_controller_test.rb | 18 +++++++++ .../inbound_emails_controller_test.rb | 13 +++++++ .../relay/inbound_emails_controller_test.rb | 13 +++++++ .../inbound_emails_controller_test.rb | 13 +++++++ .../test/fixtures/files/invalid_utf.eml | 39 +++++++++++++++++++ 9 files changed, 105 insertions(+) create mode 100644 actionmailbox/test/fixtures/files/invalid_utf.eml diff --git a/actionmailbox/CHANGELOG.md b/actionmailbox/CHANGELOG.md index fd3af5385c3d..828e00514de1 100644 --- a/actionmailbox/CHANGELOG.md +++ b/actionmailbox/CHANGELOG.md @@ -1,3 +1,9 @@ +* Fixed ingress controllers' ability to accept emails that contain no UTF-8 encoded parts. + + Fixes #46297. + + *Jan Honza Sterba* + * Add X-Forwarded-To addresses to recipients. *Andrew Stewart* diff --git a/actionmailbox/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb b/actionmailbox/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb index 3d39c9a837e4..c14e5334755e 100644 --- a/actionmailbox/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb +++ b/actionmailbox/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb @@ -44,6 +44,7 @@ module ActionMailbox # https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime. class Ingresses::Mailgun::InboundEmailsController < ActionMailbox::BaseController before_action :authenticate + param_encoding :create, "body-mime", Encoding::ASCII_8BIT def create ActionMailbox::InboundEmail.create_and_extract_message_id! mail diff --git a/actionmailbox/app/controllers/action_mailbox/ingresses/postmark/inbound_emails_controller.rb b/actionmailbox/app/controllers/action_mailbox/ingresses/postmark/inbound_emails_controller.rb index 4f7db02faebe..7d0be1178ecb 100644 --- a/actionmailbox/app/controllers/action_mailbox/ingresses/postmark/inbound_emails_controller.rb +++ b/actionmailbox/app/controllers/action_mailbox/ingresses/postmark/inbound_emails_controller.rb @@ -46,6 +46,7 @@ module ActionMailbox # content in JSON payload"*. Action Mailbox needs the raw email content to work. class Ingresses::Postmark::InboundEmailsController < ActionMailbox::BaseController before_action :authenticate_by_password + param_encoding :create, "RawEmail", Encoding::ASCII_8BIT def create ActionMailbox::InboundEmail.create_and_extract_message_id! params.require("RawEmail") diff --git a/actionmailbox/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb b/actionmailbox/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb index 4cb6c7bddccb..fc2d7aba926f 100644 --- a/actionmailbox/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb +++ b/actionmailbox/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb @@ -46,6 +46,7 @@ module ActionMailbox # full MIME message."* Action Mailbox needs the raw MIME message to work. class Ingresses::Sendgrid::InboundEmailsController < ActionMailbox::BaseController before_action :authenticate_by_password + param_encoding :create, :email, Encoding::ASCII_8BIT def create ActionMailbox::InboundEmail.create_and_extract_message_id! mail diff --git a/actionmailbox/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb index bacf57330814..dfed9fa63c46 100644 --- a/actionmailbox/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb +++ b/actionmailbox/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb @@ -25,6 +25,24 @@ class ActionMailbox::Ingresses::Mailgun::InboundEmailsControllerTest < ActionDis assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id end + test "receiving an inbound email from Mailgun with non UTF-8 characters" do + assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do + travel_to "2018-10-09 15:15:00 EDT" + post rails_mailgun_inbound_emails_url, params: { + timestamp: 1539112500, + token: "7VwW7k6Ak7zcTwoSoNm7aTtbk1g67MKAnsYLfUB7PdszbgR5Xi", + signature: "ef24c5225322217bb065b80bb54eb4f9206d764e3e16abab07f0a64d1cf477cc", + "body-mime" => file_fixture("../files/invalid_utf.eml").read + } + end + + assert_response :no_content + + inbound_email = ActionMailbox::InboundEmail.last + assert_equal file_fixture("../files/invalid_utf.eml").binread, inbound_email.raw_email.download + assert_equal "05988AA6EC0D44318855A5E39E3B6F9E@jansterba.com", inbound_email.message_id + end + test "add X-Original-To to email from Mailgun" do assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do travel_to "2018-10-09 15:15:00 EDT" diff --git a/actionmailbox/test/controllers/ingresses/postmark/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/ingresses/postmark/inbound_emails_controller_test.rb index 11b579b39cd0..3ef7288a7218 100644 --- a/actionmailbox/test/controllers/ingresses/postmark/inbound_emails_controller_test.rb +++ b/actionmailbox/test/controllers/ingresses/postmark/inbound_emails_controller_test.rb @@ -18,6 +18,19 @@ class ActionMailbox::Ingresses::Postmark::InboundEmailsControllerTest < ActionDi assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id end + test "receiving an inbound email from Postmark with non UTF-8 characters" do + assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do + post rails_postmark_inbound_emails_url, + headers: { authorization: credentials }, params: { RawEmail: file_fixture("../files/invalid_utf.eml").read } + end + + assert_response :no_content + + inbound_email = ActionMailbox::InboundEmail.last + assert_equal file_fixture("../files/invalid_utf.eml").binread, inbound_email.raw_email.download + assert_equal "05988AA6EC0D44318855A5E39E3B6F9E@jansterba.com", inbound_email.message_id + end + test "rejecting when RawEmail param is missing" do assert_no_difference -> { ActionMailbox::InboundEmail.count } do post rails_postmark_inbound_emails_url, diff --git a/actionmailbox/test/controllers/ingresses/relay/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/ingresses/relay/inbound_emails_controller_test.rb index 67c5993f7f35..dcf698ae4a25 100644 --- a/actionmailbox/test/controllers/ingresses/relay/inbound_emails_controller_test.rb +++ b/actionmailbox/test/controllers/ingresses/relay/inbound_emails_controller_test.rb @@ -18,6 +18,19 @@ class ActionMailbox::Ingresses::Relay::InboundEmailsControllerTest < ActionDispa assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id end + test "receiving an inbound email relayed from an SMTP server with non UTF-8 characters" do + assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do + post rails_relay_inbound_emails_url, headers: { "Authorization" => credentials, "Content-Type" => "message/rfc822" }, + params: file_fixture("../files/invalid_utf.eml").read + end + + assert_response :no_content + + inbound_email = ActionMailbox::InboundEmail.last + assert_equal file_fixture("../files/invalid_utf.eml").binread, inbound_email.raw_email.download + assert_equal "05988AA6EC0D44318855A5E39E3B6F9E@jansterba.com", inbound_email.message_id + end + test "rejecting an unauthorized inbound email" do assert_no_difference -> { ActionMailbox::InboundEmail.count } do post rails_relay_inbound_emails_url, headers: { "Content-Type" => "message/rfc822" }, diff --git a/actionmailbox/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb index 282d061b3647..3454585088e9 100644 --- a/actionmailbox/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb +++ b/actionmailbox/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb @@ -18,6 +18,19 @@ class ActionMailbox::Ingresses::Sendgrid::InboundEmailsControllerTest < ActionDi assert_equal "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com", inbound_email.message_id end + test "receiving an inbound email from Sendgrid with non UTF-8 characters" do + assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do + post rails_sendgrid_inbound_emails_url, + headers: { authorization: credentials }, params: { email: file_fixture("../files/invalid_utf.eml").read } + end + + assert_response :no_content + + inbound_email = ActionMailbox::InboundEmail.last + assert_equal file_fixture("../files/invalid_utf.eml").binread, inbound_email.raw_email.download + assert_equal "05988AA6EC0D44318855A5E39E3B6F9E@jansterba.com", inbound_email.message_id + end + test "add X-Original-To to email from Sendgrid" do assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do post rails_sendgrid_inbound_emails_url, diff --git a/actionmailbox/test/fixtures/files/invalid_utf.eml b/actionmailbox/test/fixtures/files/invalid_utf.eml new file mode 100644 index 000000000000..c5c03d572b64 --- /dev/null +++ b/actionmailbox/test/fixtures/files/invalid_utf.eml @@ -0,0 +1,39 @@ +thread-index: Adjkg/rniynGRZvvRu2Ftd4zu7/YrA== +Thread-Topic: =?iso-8859-2?Q?Informace_o_skladov=FDch_z=E1sob=E1ch_Copmany?= +From: +To: , +Message-ID: <05988AA6EC0D44318855A5E39E3B6F9E@jansterba.com> +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_168F_01D8E494.BE7019A0" +Content-Class: urn:content-classes:message +Importance: normal +Priority: normal +X-MimeOLE: Produced By Microsoft MimeOLE V6.3.9600.20564 +X-EOPAttributedMessage: 0 +X-Spam-IndexStatus: 0 + +This is a multi-part message in MIME format. + +------=_NextPart_000_168F_01D8E494.BE7019A0 +Content-Type: multipart/alternative; + boundary="----=_NextPart_001_1690_01D8E494.BE7019A0" + +------=_NextPart_001_1690_01D8E494.BE7019A0 +Content-Type: text/plain; + charset="iso-8859-2" +Content-Transfer-Encoding: quoted-printable + +V=E1=BEen=FD z=E1kazn=EDku, + +v p=F8=EDloze zas=EDl=E1me aktu=E1ln=ED informace o skladov=FDch = +z=E1sob=E1ch. + +------=_NextPart_001_1690_01D8E494.BE7019A0 +Content-Type: text/html; + charset="iso-8859-2" +Content-Transfer-Encoding: 8bit + +Vážený zákazníku,

v příloze zasíláme aktuální informace o skladových zásobách. + +------=_NextPart_000_168F_01D8E494.BE7019A0--