Skip to content

Commit

Permalink
improve secure-join message detection (#473)
Browse files Browse the repository at this point in the history
  • Loading branch information
adbenitez authored Jan 28, 2025
1 parent 9e6ba1a commit 4d915f9
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
- migration guide: let opendkim own the DKIM keys directory
([#468](https://github.com/deltachat/chatmail/pull/468))

- improve secure-join message detection
([#473](https://github.com/deltachat/chatmail/pull/473))

## 1.5.0 2024-12-20

- cmdeploy dns: always show recommended DNS records
Expand Down
29 changes: 23 additions & 6 deletions chatmaild/src/chatmaild/filtermail.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,27 @@ def check_armored_payload(payload: str):
return False


def is_securejoin(message):
if message.get("secure-join") not in ["vc-request", "vg-request"]:
return False
if not message.is_multipart():
return False
parts_count = 0
for part in message.iter_parts():
parts_count += 1
if parts_count > 1:
return False
if part.is_multipart():
return False
if part.get_content_type() != "text/plain":
return False

payload = part.get_payload().strip().lower()
if payload not in ("secure-join: vc-request", "secure-join: vg-request"):
return False
return True


def check_encrypted(message):
"""Check that the message is an OpenPGP-encrypted message.
Expand Down Expand Up @@ -203,11 +224,7 @@ def check_DATA(self, envelope):

passthrough_recipients = self.config.passthrough_recipients

is_securejoin = message.get("secure-join") in [
"vc-request",
"vg-request",
]
if is_securejoin:
if mail_encrypted or is_securejoin(message):
return

for recipient in envelope.rcpt_tos:
Expand All @@ -222,7 +239,7 @@ def check_DATA(self, envelope):
_recipient_addr, recipient_domain = res

is_outgoing = recipient_domain != envelope_from_domain
if is_outgoing and not mail_encrypted:
if is_outgoing:
print("Rejected unencrypted mail.", file=sys.stderr)
return f"500 Invalid unencrypted mail to <{recipient}>"

Expand Down
21 changes: 21 additions & 0 deletions chatmaild/src/chatmaild/tests/mail-data/securejoin-vc-fake.eml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Subject: Message from {from_addr}
From: <{from_addr}>
To: <{to_addr}>
Date: Sun, 15 Oct 2023 16:43:25 +0000
Message-ID: <Mr.78MWtlV7RAi.goCFzBhCYfy@c2.testrun.org>
Chat-Version: 1.0
Secure-Join: vc-request
Secure-Join-Invitenumber: RANDOM-TOKEN
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi"


--Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi
Content-Type: text/plain; charset=utf-8
Buy viagra!
--Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi--


21 changes: 21 additions & 0 deletions chatmaild/src/chatmaild/tests/mail-data/securejoin-vc.eml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Subject: Message from {from_addr}
From: <{from_addr}>
To: <{to_addr}>
Date: Sun, 15 Oct 2023 16:43:25 +0000
Message-ID: <Mr.78MWtlV7RAi.goCFzBhCYfy@c2.testrun.org>
Chat-Version: 1.0
Secure-Join: vc-request
Secure-Join-Invitenumber: RANDOM-TOKEN
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi"


--Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi
Content-Type: text/plain; charset=utf-8
Secure-Join: vc-request
--Gl92xgZjOShJ5PGHntqYkoo2OK2Dvi--


15 changes: 15 additions & 0 deletions chatmaild/src/chatmaild/tests/test_filtermail.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
check_armored_payload,
check_encrypted,
common_encrypted_subjects,
is_securejoin,
)


Expand Down Expand Up @@ -55,6 +56,20 @@ def test_filtermail_no_encryption_detection(maildata):
assert not check_encrypted(msg)


def test_filtermail_securejoin_detection(maildata):
msg = maildata(
"securejoin-vc.eml", from_addr="some@example.org", to_addr="other@example.org"
)
assert is_securejoin(msg)

msg = maildata(
"securejoin-vc-fake.eml",
from_addr="some@example.org",
to_addr="other@example.org",
)
assert not is_securejoin(msg)


def test_filtermail_encryption_detection(maildata):
for subject in common_encrypted_subjects:
msg = maildata(
Expand Down

0 comments on commit 4d915f9

Please sign in to comment.