mirror of
https://github.com/simple-login/app.git
synced 2025-09-07 15:14:17 +08:00
feat: allow to limit max email recipients (#2436)
* feat: allow to limit max email recipients * Set cmake min version --------- Co-authored-by: Adrià Casajús <adria.casajus@proton.ch>
This commit is contained in:
parent
c7cbc7a4c8
commit
0e95f3d047
6 changed files with 75 additions and 0 deletions
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
|
@ -8,6 +8,9 @@ on:
|
|||
- v*
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
CMAKE_POLICY_VERSION_MINIMUM: 3.5
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -685,3 +685,4 @@ MAILBOX_VERIFICATION_OVERRIDE_CODE: Optional[str] = os.environ.get(
|
|||
AUDIT_LOG_MAX_DAYS = int(os.environ.get("AUDIT_LOG_MAX_DAYS", 30))
|
||||
ALIAS_TRASH_DAYS = int(os.environ.get("ALIAS_TRASH_DAYS", 30))
|
||||
ALLOWED_OAUTH_SCHEMES = get_env_csv("ALLOWED_OAUTH_SCHEMES", "auth.simplelogin,https")
|
||||
MAX_EMAIL_FORWARD_RECIPIENTS = int(os.environ.get("MAX_EMAIL_FORWARD_RECIPIENTS", 30))
|
||||
|
|
18
app/email/checks.py
Normal file
18
app/email/checks.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from app.email import headers
|
||||
from app.log import LOG
|
||||
from email.message import Message
|
||||
from flanker.addresslib import address
|
||||
|
||||
|
||||
def check_recipient_limit(msg: Message, limit: int) -> bool:
|
||||
# Count total recipients in TO and CC
|
||||
to_addrs = address.parse_list(str(msg.get(headers.TO, "")))
|
||||
cc_addrs = address.parse_list(str(msg.get(headers.CC, "")))
|
||||
total_recipients = len(to_addrs) + len(cc_addrs)
|
||||
|
||||
if total_recipients > limit:
|
||||
LOG.w(
|
||||
f"Too many recipients ({total_recipients}). Max allowed: {limit}. Refusing to forward"
|
||||
)
|
||||
return False
|
||||
return True
|
|
@ -61,4 +61,5 @@ E522 = (
|
|||
E523 = "550 SL E523 Unknown error"
|
||||
E524 = "550 SL E524 Wrong use of reverse-alias"
|
||||
E525 = "550 SL E525 Alias loop"
|
||||
E526 = "550 SL E526 Too many recipients"
|
||||
# endregion
|
||||
|
|
|
@ -86,9 +86,11 @@ from app.config import (
|
|||
OLD_UNSUBSCRIBER,
|
||||
ALERT_FROM_ADDRESS_IS_REVERSE_ALIAS,
|
||||
ALERT_TO_NOREPLY,
|
||||
MAX_EMAIL_FORWARD_RECIPIENTS,
|
||||
)
|
||||
from app.db import Session
|
||||
from app.email import status, headers
|
||||
from app.email.checks import check_recipient_limit
|
||||
from app.email.rate_limit import rate_limited
|
||||
from app.email.spam import get_spam_score
|
||||
from app.email_utils import (
|
||||
|
@ -911,6 +913,10 @@ def forward_email_to_mailbox(
|
|||
add_or_replace_header(msg, "Reply-To", new_reply_to_header)
|
||||
LOG.d("Reply-To header, new:%s, old:%s", new_reply_to_header, original_reply_to)
|
||||
|
||||
# Check recipient limit
|
||||
if not check_recipient_limit(msg, MAX_EMAIL_FORWARD_RECIPIENTS):
|
||||
return False, status.E526
|
||||
|
||||
# replace CC & To emails by reverse-alias for all emails that are not alias
|
||||
try:
|
||||
replace_header_when_forward(msg, alias, headers.CC)
|
||||
|
|
46
tests/email_tests/test_checks.py
Normal file
46
tests/email_tests/test_checks.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from email.message import Message
|
||||
|
||||
from app.email.checks import check_recipient_limit
|
||||
from app.email import headers
|
||||
from tests.utils import random_email
|
||||
|
||||
|
||||
def _email_list(size: int) -> str:
|
||||
emails = []
|
||||
for i in range(size):
|
||||
emails.append(random_email())
|
||||
|
||||
return ", ".join(emails)
|
||||
|
||||
|
||||
def _create_message(to: str, cc: str) -> Message:
|
||||
message = Message()
|
||||
message[headers.CC] = cc
|
||||
message[headers.TO] = to
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def test_can_forward_if_below_limit():
|
||||
msg = _create_message(to=_email_list(1), cc=_email_list(1))
|
||||
assert check_recipient_limit(msg, 5)
|
||||
|
||||
|
||||
def test_can_forward_if_just_limit():
|
||||
msg = _create_message(to=_email_list(1), cc=_email_list(1))
|
||||
assert check_recipient_limit(msg, 2)
|
||||
|
||||
|
||||
def test_cannot_forward_if_single_list_above_limit():
|
||||
msg = _create_message(to=_email_list(3), cc=_email_list(0))
|
||||
assert check_recipient_limit(msg, 2) is False
|
||||
|
||||
|
||||
def test_cannot_forward_if_both_lists_above_limit():
|
||||
msg = _create_message(to=_email_list(3), cc=_email_list(3))
|
||||
assert check_recipient_limit(msg, 2) is False
|
||||
|
||||
|
||||
def test_cannot_forward_if_both_lists_add_up_to_limit():
|
||||
msg = _create_message(to=_email_list(3), cc=_email_list(3))
|
||||
assert check_recipient_limit(msg, 5) is False
|
Loading…
Add table
Reference in a new issue