diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index 0a5ad7f7cb1..2570a0bf3a9 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -429,7 +429,7 @@ module Email when :reply email_log = destination[:obj] - if email_log.user_id != user.id + if email_log.user_id != user.id && !forwareded_reply_key?(email_log, user) raise ReplyUserNotMatchingError, "email_log.user_id => #{email_log.user_id.inspect}, user.id => #{user.id.inspect}" end @@ -442,6 +442,40 @@ module Email end end + def forwareded_reply_key?(email_log, user) + incoming_emails = IncomingEmail + .joins(:post) + .where('posts.topic_id = ?', email_log.topic_id) + .where('incoming_emails.to_addresses ILIKE :email OR incoming_emails.cc_addresses ILIKE :email', email: "%#{email_log.reply_key}%") + .where('incoming_emails.to_addresses ILIKE :email OR incoming_emails.cc_addresses ILIKE :email', email: "%#{user.email}%") + + incoming_emails.each do |email| + next unless contains_email_address?(email.to_addresses, user.email) || + contains_email_address?(email.cc_addresses, user.email) + + return true if contains_reply_by_email_address(email.to_addresses, email_log.reply_key) || + contains_reply_by_email_address(email.cc_addresses, email_log.reply_key) + end + + false + end + + def contains_email_address?(addresses, email) + return false if addresses.blank? + addresses.split(";").include?(email) + end + + def contains_reply_by_email_address(addresses, reply_key) + return false if addresses.blank? + + addresses.split(";").each do |address| + match = Email::Receiver.reply_by_email_address_regex.match(address) + return true if match && match.captures&.include?(reply_key) + end + + false + end + def has_been_forwarded? subject[/^[[:blank:]]*(fwd?|tr)[[:blank:]]?:/i] && embedded_email_raw.present? end diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index cdfe82fc9e4..75ef299f93f 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -397,7 +397,29 @@ describe Email::Receiver do end it "accepts emails with wrong reply key if the system knows about the forwareded email" do + Fabricate(:incoming_email, + raw: <<~RAW, + Return-Path: + From: Alice + To: dave@bar.com, reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com + CC: carol@bar.com, bob@bar.com + Subject: Hello world + Date: Fri, 15 Jan 2016 00:12:43 +0100 + Message-ID: <10@foo.bar.mail> + Mime-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: quoted-printable + This post was created by email. + RAW + from_address: "discourse@bar.com", + to_addresses: "dave@bar.com;reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com", + cc_addresses: "carol@bar.com;bob@bar.com", + topic: topic, + post: post, + user: user) + + expect { process(:reply_user_not_matching_but_known) }.to change { topic.posts.count } end end diff --git a/spec/fixtures/emails/reply_user_not_matching_but_known.eml b/spec/fixtures/emails/reply_user_not_matching_but_known.eml new file mode 100644 index 00000000000..f0c3c7d7246 --- /dev/null +++ b/spec/fixtures/emails/reply_user_not_matching_but_known.eml @@ -0,0 +1,11 @@ +Return-Path: +From: Bob +To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com +CC: Alice , carol@bar.com +Date: Fri, 15 Jan 2016 02:12:43 +0100 +Message-ID: <11@foo.bar.mail> +Mime-Version: 1.0 +Content-Type: text/plain +Content-Transfer-Encoding: 7bit + +Lorem ipsum dolor sit amet, consectetur adipiscing elit.