From ab264a30822b5d16c6edb56b9c37a57ff56377f3 Mon Sep 17 00:00:00 2001 From: groovecoder Date: Fri, 27 Sep 2024 10:00:08 -0500 Subject: [PATCH] MPP-3119: moves _disable_masks_for_complaint() into complained_recipients loop To ensure the Relay mask belongs to the user from whom we received the spam complaint, moves _disable_masks_for_complaint() into complained_recipients loop. Also, change _disable_masks_for_complaint to search the original mail "source" field for a Relay mask address to find the mask thru which the spam email was sent. --- emails/tests/views_tests.py | 3 +++ emails/views.py | 35 +++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/emails/tests/views_tests.py b/emails/tests/views_tests.py index 933eeb7816..1b49db83c2 100644 --- a/emails/tests/views_tests.py +++ b/emails/tests/views_tests.py @@ -1160,6 +1160,9 @@ def test_complaint_disables_mask(self): spam_mail_content = json.loads( russian_spam_notification.get("Message", "") ).get("mail", {}) + spam_mail_content["source"] = ( + f"hello@ac.spam.example.com [via Relay] <{self.ra.full_address}>" + ) complaint_body_message = json.loads(self.complaint_body["Message"]) complaint_body_message["mail"] = spam_mail_content complaint_body_with_spam_mail = {"Message": json.dumps(complaint_body_message)} diff --git a/emails/views.py b/emails/views.py index 9119ae8e17..298956b814 100644 --- a/emails/views.py +++ b/emails/views.py @@ -1640,19 +1640,42 @@ def _send_disabled_mask_for_spam_email( incr_if_enabled("free_user_reply_attempt", 1) -def _disable_masks_for_complaint(message_json: dict) -> None: +def _disable_masks_for_complaint(message_json: dict, user: User) -> None: + """ + See https://docs.aws.amazon.com/ses/latest/dg/notification-contents.html#mail-object + + message_json.mail.source contains the envelope MAIL FROM address from which the + original message was sent. + + Relay sends emails From: "original-From" . + + So, we can find the mask that sent the spam email by parsing the source value. + """ + flag_name = "disable_mask_on_complaint" _, _ = get_waffle_flag_model().objects.get_or_create( - name="disable_mask_on_complaint", + name=flag_name, defaults={ "note": ( "MPP-3119: When a Relay user marks an email as spam, disable the mask." ) }, ) - for destination_address in message_json.get("mail", {}).get("destination", []): + source = message_json.get("mail", {}).get("source", "") + # parseaddr is confused by 2 email addresses in the value, so use this + # regular expression to extract the mask address by searching for any relay domains + email_domains = get_domains_from_settings().values() + domain_pattern = "|".join(re.escape(domain) for domain in email_domains) + email_regex = rf"[\w\.-]+@(?:{domain_pattern})" + matches = re.findall(email_regex, source) + if not matches: + return + for mask_address in matches: try: - address = _get_address(destination_address, False) - if flag_is_active_in_task("disable_mask_on_complaint", address.user): + address = _get_address(mask_address, False) + # ensure the mask belongs to the user for whom Relay received a complaint + if address.user != user: + continue + if flag_is_active_in_task(flag_name, address.user): address.enabled = False address.save() _send_disabled_mask_for_spam_email( @@ -1740,7 +1763,7 @@ def _handle_complaint(message_json: AWS_SNSMessageJSON) -> HttpResponse: profile.auto_block_spam = True profile.save() - _disable_masks_for_complaint(message_json) + _disable_masks_for_complaint(message_json, user) if not complaint_data: # Data when there are no identified recipients