diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 261442c6..74c992cd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,11 +27,6 @@ jobs: sudo apt update sudo apt install -y libre2-dev libpq-dev - - name: "Set up Python" - uses: actions/setup-python@v5 - with: - python-version-file: "pyproject.toml" - - name: Install dependencies if: steps.setup-uv.outputs.cache-hit != 'true' run: uv sync --locked --all-extras diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8cd06123..7dac4243 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -215,7 +215,7 @@ python email_handler.py 4) Send a test email ```bash -swaks --to e1@sl.local --from hey@google.com --server 127.0.0.1:20381 +swaks --to e1@sl.lan --from hey@google.com --server 127.0.0.1:20381 ``` Now open http://localhost:1080/ (or http://localhost:1080/ for MailHog), you should see the forwarded email. diff --git a/app/api/views/auth.py b/app/api/views/auth.py index ed8d0457..3786de1d 100644 --- a/app/api/views/auth.py +++ b/app/api/views/auth.py @@ -1,7 +1,6 @@ import secrets import string -import facebook import google.oauth2.credentials import googleapiclient.discovery from flask import jsonify, request @@ -261,6 +260,8 @@ def auth_facebook(): } """ + import facebook + data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 diff --git a/app/developer/views/index.py b/app/developer/views/index.py index deef6ed6..6aa6dd82 100644 --- a/app/developer/views/index.py +++ b/app/developer/views/index.py @@ -1,4 +1,5 @@ """List of clients""" + from flask import render_template from flask_login import current_user, login_required diff --git a/app/email/headers.py b/app/email/headers.py index bfbcb9a7..74a2bf8b 100644 --- a/app/email/headers.py +++ b/app/email/headers.py @@ -1,4 +1,5 @@ """Email headers""" + MESSAGE_ID = "Message-ID" IN_REPLY_TO = "In-Reply-To" REFERENCES = "References" diff --git a/app/email_utils.py b/app/email_utils.py index 731b0988..979a66c9 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -1355,7 +1355,9 @@ def get_queue_id(msg: Message) -> Optional[str]: search_result = re.search(r"with E?SMTP[AS]? id ([0-9a-zA-Z]{1,})", received_header) if search_result: return search_result.group(1) - search_result = re.search("\(Postfix\)\r\n\tid ([a-zA-Z0-9]{1,});", received_header) + search_result = re.search( + r"\(Postfix\)\r\n\tid ([a-zA-Z0-9]{1,});", received_header + ) if search_result: return search_result.group(1) return None diff --git a/app/fake_data.py b/app/fake_data.py index 6f43db75..6ee17bb2 100644 --- a/app/fake_data.py +++ b/app/fake_data.py @@ -90,7 +90,7 @@ def fake_data(): user_id=user.id, alias_id=alias.id, website_email="hey@google.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) EmailLog.create( @@ -166,7 +166,7 @@ def fake_data(): # user_id=user.id, # alias_id=a.id, # website_email=f"contact{i}@example.com", - # reply_email=f"rep{i}@sl.local", + # reply_email=f"rep{i}@sl.lan", # ) # Session.commit() # for _ in range(3): diff --git a/app/spamassassin_utils.py b/app/spamassassin_utils.py index f1e2d54c..665f3c23 100644 --- a/app/spamassassin_utils.py +++ b/app/spamassassin_utils.py @@ -1,6 +1,7 @@ """Inspired from https://github.com/petermat/spamassassin_client """ + import logging import socket from io import BytesIO diff --git a/docs/api.md b/docs/api.md index cb646e32..abf8347d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -369,8 +369,8 @@ For ex: "is_premium": false }, { - "signed_suffix": ".yeah@sl.local.X6_7OQ.i8XL4xsMsn7dxDEWU8eF-Zap0qo", - "suffix": ".yeah@sl.local", + "signed_suffix": ".yeah@sl.lan.X6_7OQ.i8XL4xsMsn7dxDEWU8eF-Zap0qo", + "suffix": ".yeah@sl.lan", "is_custom": true, "is_premium": false } @@ -465,7 +465,7 @@ Here's an example: { "creation_date": "2020-04-06 17:57:14+00:00", "creation_timestamp": 1586195834, - "email": "prefix1.cat@sl.local", + "email": "prefix1.cat@sl.lan", "name": "A Name", "enabled": true, "id": 3, @@ -518,7 +518,7 @@ Alias info, use the same format as in /api/v2/aliases. For example: { "creation_date": "2020-04-06 17:57:14+00:00", "creation_timestamp": 1586195834, - "email": "prefix1.cat@sl.local", + "email": "prefix1.cat@sl.lan", "name": "A Name", "enabled": true, "id": 3, @@ -608,7 +608,7 @@ If success, 200 with the list of activities, for example: "activities": [ { "action": "reply", - "from": "yes_meo_chat@sl.local", + "from": "yes_meo_chat@sl.lan", "timestamp": 1580903760, "to": "marketing@example.com", "reverse_alias": "\"marketing at example.com\" ", @@ -703,7 +703,7 @@ Return 200 and `existed=true` if contact is already added. "creation_timestamp": 1584186761, "last_email_sent_date": null, "last_email_sent_timestamp": null, - "reverse_alias": "First Last first@example.com ", + "reverse_alias": "First Last first@example.com ", "reverse_alias_address": "reply+bzvpazcdedcgcpztehxzgjgzmxskqa@sl.co", "existed": false } @@ -992,7 +992,7 @@ Return user setting. { "alias_generator": "word", "notification": true, - "random_alias_default_domain": "sl.local", + "random_alias_default_domain": "sl.lan", "sender_format": "AT", "random_alias_suffix": "random_string" } @@ -1029,7 +1029,7 @@ Return domains that user can use to create random alias "is_custom": false }, { - "domain": "sl.local", + "domain": "sl.lan", "is_custom": false }, { diff --git a/email_handler.py b/email_handler.py index f732fb73..cbb052fc 100644 --- a/email_handler.py +++ b/email_handler.py @@ -30,6 +30,7 @@ It should contain the following info: """ + import argparse import email import time @@ -1668,7 +1669,7 @@ def handle_bounce_reply_phase(envelope, msg: Message, email_log: EmailLog): ) Notification.create( user_id=user.id, - title=f"Email cannot be sent to { contact.email } from your alias { alias.email }", + title=f"Email cannot be sent to {contact.email} from your alias {alias.email}", message=Notification.render( "notification/bounce-reply-phase.html", alias=alias, @@ -1681,7 +1682,7 @@ def handle_bounce_reply_phase(envelope, msg: Message, email_log: EmailLog): user, ALERT_BOUNCE_EMAIL_REPLY_PHASE, mailbox.email, - f"Email cannot be sent to { contact.email } from your alias { alias.email }", + f"Email cannot be sent to {contact.email} from your alias {alias.email}", render( "transactional/bounce/bounce-email-reply-phase.txt", user=user, diff --git a/example.env b/example.env index 45716f82..b7a6a5b3 100644 --- a/example.env +++ b/example.env @@ -19,7 +19,7 @@ URL=http://localhost:7777 NOT_SEND_EMAIL=true # domain used to create alias -EMAIL_DOMAIN=sl.local +EMAIL_DOMAIN=sl.lan # Allow SimpleLogin to enforce SPF by using the extra headers from postfix # ENFORCE_SPF=true @@ -37,18 +37,18 @@ EMAIL_DOMAIN=sl.local # FIRST_ALIAS_DOMAIN = another-domain.com # transactional email is sent from this email address -SUPPORT_EMAIL=support@sl.local +SUPPORT_EMAIL=support@sl.lan SUPPORT_NAME=Son from SimpleLogin # To use VERP # prefix must end with + and suffix must start with + # BOUNCE_PREFIX = "bounces+" -# BOUNCE_SUFFIX = "+@sl.local" +# BOUNCE_SUFFIX = "+@sl.lan" # same as BOUNCE_PREFIX but used for reply phase. Note it doesn't have the plus sign (+) at the end. # BOUNCE_PREFIX_FOR_REPLY_PHASE = "bounce_reply" # to receive general stats. -# ADMIN_EMAIL=admin@sl.local +# ADMIN_EMAIL=admin@sl.lan # Max number emails user can generate for free plan # Set to 5 by default diff --git a/oauth_tester.py b/oauth_tester.py index 0dd18c40..ad024678 100644 --- a/oauth_tester.py +++ b/oauth_tester.py @@ -5,6 +5,7 @@ The step-to-step guide can be found on https://simplelogin.io/docs/siwsl/app/ This example is based on https://requests-oauthlib.readthedocs.io/en/latest/examples/real_world_example.html """ + import os from flask import Flask, request, redirect, session, url_for diff --git a/oneshot/emulate_dummy_load.py b/oneshot/emulate_dummy_load.py index 9766abf4..8ab5f5eb 100644 --- a/oneshot/emulate_dummy_load.py +++ b/oneshot/emulate_dummy_load.py @@ -34,4 +34,4 @@ for i in range(tests): end = time.time() time_taken = end - start -print(f"Took {time_taken} -> {time_taken/tests} per test") +print(f"Took {time_taken} -> {time_taken / tests} per test") diff --git a/pyproject.toml b/pyproject.toml index 36d11c9b..4f2f2663 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "sqlalchemy_utils ~= 0.36.8", "psycopg2-binary ~= 2.9.10", "sentry_sdk ~= 2.20.0", - "blinker ~= 1.4", + "blinker ~= 1.9.0", "arrow ~= 0.16.0", "Flask-WTF ~= 0.14.3", "boto3 ~= 1.35.37", @@ -41,7 +41,7 @@ dependencies = [ "requests_oauthlib ~= 1.3.0", "pyopenssl ~= 19.1.0", "aiosmtpd ~= 1.2", - "dnspython==2.0.0", + "dnspython ~= 2.7.0", "coloredlogs ~= 14.0", "pycryptodome ~= 3.9.8", "phpserialize ~= 1.3", @@ -53,11 +53,14 @@ dependencies = [ "google-auth-httplib2 ~= 0.0.4", "python-gnupg ~= 0.4.6", "webauthn ~= 0.4.7", - "pyspf ~= 2.0.14", + + # Git dependency until pyspf creates a new release + "pyspf @ git+https://github.com/sdgathman/pyspf.git@665a6df079485a9824be0829e7d71088453db7f6", + "Flask-Limiter == 1.4", "memory_profiler ~= 0.57.0", "gevent ~= 24.11.1", - "email-validator ~= 1.1.3", + "email-validator ~= 2.2.0", "PGPy == 0.5.4", "coinbase-commerce ~= 1.0.1", "requests ~= 2.25.1", @@ -103,8 +106,9 @@ exclude = ''' ''' [tool.ruff] -ignore-init-module-imports = true exclude = [".venv", "migrations", "app/events/generated"] +[tool.ruff.lint] +ignore-init-module-imports = true [tool.djlint] indent = 2 diff --git a/tests/api/test_alias.py b/tests/api/test_alias.py index 010b396e..b718477a 100644 --- a/tests/api/test_alias.py +++ b/tests/api/test_alias.py @@ -647,8 +647,8 @@ def test_get_alias(flask_client): def test_is_reverse_alias(flask_client): - assert is_reverse_alias("ra+abcd@sl.local") - assert is_reverse_alias("reply+abcd@sl.local") + assert is_reverse_alias("ra+abcd@sl.lan") + assert is_reverse_alias("reply+abcd@sl.lan") assert not is_reverse_alias("ra+abcd@test.org") assert not is_reverse_alias("reply+abcd@test.org") diff --git a/tests/api/test_new_random_alias.py b/tests/api/test_new_random_alias.py index 8611d2ea..a2d687fc 100644 --- a/tests/api/test_new_random_alias.py +++ b/tests/api/test_new_random_alias.py @@ -17,7 +17,7 @@ def test_with_hostname(flask_client): ) assert r.status_code == 201 - assert r.json["alias"].endswith("d1.test") + assert r.json["alias"].endswith("d1.lan") # make sure alias starts with the suggested prefix assert r.json["alias"].startswith("test") diff --git a/tests/api/test_serializer.py b/tests/api/test_serializer.py index 25d22b20..4e57de60 100644 --- a/tests/api/test_serializer.py +++ b/tests/api/test_serializer.py @@ -112,14 +112,14 @@ def test_get_alias_infos_with_pagination_v3_no_duplicate_when_empty_contact( user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", ) Contact.create( user_id=user.id, alias_id=alias.id, website_email="contact2@example.com", - reply_email="rep2@sl.local", + reply_email="rep2@sl.lan", ) alias_infos = get_alias_infos_with_pagination_v3(user) diff --git a/tests/api/test_setting.py b/tests/api/test_setting.py index 698596ee..2db8824b 100644 --- a/tests/api/test_setting.py +++ b/tests/api/test_setting.py @@ -15,7 +15,7 @@ def test_get_setting(flask_client): assert r.json == { "alias_generator": "word", "notification": True, - "random_alias_default_domain": "sl.local", + "random_alias_default_domain": "sl.lan", "sender_format": "AT", "random_alias_suffix": "word", } @@ -47,7 +47,7 @@ def test_update_settings_random_alias_default_domain(flask_client): custom_domain = CustomDomain.create( domain=random_domain(), verified=True, user_id=user.id, flush=True ) - assert user.default_random_alias_domain() == "sl.local" + assert user.default_random_alias_domain() == "sl.lan" r = flask_client.patch( "/api/setting", json={"random_alias_default_domain": "invalid"} @@ -55,10 +55,10 @@ def test_update_settings_random_alias_default_domain(flask_client): assert r.status_code == 400 r = flask_client.patch( - "/api/setting", json={"random_alias_default_domain": "d1.test"} + "/api/setting", json={"random_alias_default_domain": "d1.lan"} ) assert r.status_code == 200 - assert user.default_random_alias_domain() == "d1.test" + assert user.default_random_alias_domain() == "d1.lan" r = flask_client.patch( "/api/setting", json={"random_alias_default_domain": custom_domain.domain} diff --git a/tests/conftest.py b/tests/conftest.py index 43ea7ac6..2b4ead52 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,7 +23,7 @@ from init_app import add_sl_domains, add_proton_partner app = create_app() app.config["TESTING"] = True app.config["WTF_CSRF_ENABLED"] = False -app.config["SERVER_NAME"] = "sl.test" +app.config["SERVER_NAME"] = "sl.lan" # enable pg_trgm extension with engine.connect() as conn: diff --git a/tests/email_tests/test_rate_limit.py b/tests/email_tests/test_rate_limit.py index b5f464a2..c7c90c27 100644 --- a/tests/email_tests/test_rate_limit.py +++ b/tests/email_tests/test_rate_limit.py @@ -28,7 +28,7 @@ def test_rate_limited_forward_phase_for_alias(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", ) Session.commit() for _ in range(MAX_ACTIVITY_DURING_MINUTE_PER_ALIAS + 1): @@ -52,7 +52,7 @@ def test_rate_limited_forward_phase_for_mailbox(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", ) Session.commit() for _ in range(MAX_ACTIVITY_DURING_MINUTE_PER_MAILBOX + 1): @@ -90,7 +90,7 @@ def test_rate_limited_reply_phase(flask_client): alias = Alias.create_new_random(user) Session.commit() - reply_email = f"reply-{random.random()}@sl.local" + reply_email = f"reply-{random.random()}@sl.lan" contact = Contact.create( user_id=user.id, alias_id=alias.id, diff --git a/tests/handler/test_provider_complaints.py b/tests/handler/test_provider_complaints.py index e5b8c89c..98244a4a 100644 --- a/tests/handler/test_provider_complaints.py +++ b/tests/handler/test_provider_complaints.py @@ -37,7 +37,7 @@ def prepare_complaint( contact = Contact.create( user_id=alias.user.id, alias_id=alias.id, - website_email=f"contact{random.random()}@mailbox.test", + website_email=f"contact{random.random()}@mailbox.lan", reply_email="d@e.f", commit=True, ) diff --git a/tests/handler/test_unsubscribe_generator.py b/tests/handler/test_unsubscribe_generator.py index a08a9227..fef53e9c 100644 --- a/tests/handler/test_unsubscribe_generator.py +++ b/tests/handler/test_unsubscribe_generator.py @@ -27,7 +27,7 @@ def generate_unsub_block_contact_data() -> Iterable: user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) @@ -86,7 +86,7 @@ def generate_unsub_disable_alias_data() -> Iterable: user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) @@ -145,7 +145,7 @@ def generate_unsub_preserve_original_data() -> Iterable: user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) @@ -215,7 +215,7 @@ def test_unsub_preserves_sl_unsubscriber(): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) message = Message() diff --git a/tests/handler/test_unsubscribe_handler.py b/tests/handler/test_unsubscribe_handler.py index ab76598e..a1804fb2 100644 --- a/tests/handler/test_unsubscribe_handler.py +++ b/tests/handler/test_unsubscribe_handler.py @@ -49,7 +49,7 @@ def test_old_subject_block_contact(): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email=f"{random()}@sl.local", + reply_email=f"{random()}@sl.lan", block_forward=False, commit=True, ) @@ -92,7 +92,7 @@ def test_new_subject_block_contact(): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email=f"{random()}@sl.local", + reply_email=f"{random()}@sl.lan", block_forward=False, commit=True, ) @@ -172,7 +172,7 @@ def test_request_disable_contact(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email=f"{random()}@sl.local", + reply_email=f"{random()}@sl.lan", block_forward=False, commit=True, ) diff --git a/tests/monitor/test_upcloud_get_metric.py b/tests/monitor/test_upcloud_get_metric.py index fb3fd27d..98995426 100644 --- a/tests/monitor/test_upcloud_get_metric.py +++ b/tests/monitor/test_upcloud_get_metric.py @@ -140,13 +140,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:12:00Z", value=3.275132296130991, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:12:00Z", value=4.196249043309251, ), @@ -157,13 +157,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=5.654416415900109, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=5.58959125727556, ), @@ -174,13 +174,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=0, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=0, ), @@ -191,13 +191,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=4, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=3, ), @@ -208,13 +208,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=0.14, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=0.09, ), @@ -225,13 +225,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=11.488581675749048, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=12.272260458006759, ), @@ -242,13 +242,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=466, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=458, ), @@ -259,13 +259,13 @@ def test_get_metrics(): records=[ UpcloudRecord( db_role="master", - label="test-1 " "(master)", + label="test-1 (master)", time="2022-01-21T13:11:30Z", value=694, ), UpcloudRecord( db_role="standby", - label="test-2 " "(standby)", + label="test-2 (standby)", time="2022-01-21T13:11:30Z", value=573, ), diff --git a/tests/test.env b/tests/test.env index 0c492223..a872df0c 100644 --- a/tests/test.env +++ b/tests/test.env @@ -5,9 +5,9 @@ LOCAL_FILE_UPLOAD=1 # Email related settings # Only print email content, not sending it NOT_SEND_EMAIL=true -EMAIL_DOMAIN=sl.local -OTHER_ALIAS_DOMAINS=["d1.test", "d2.test", "sl.local"] -SUPPORT_EMAIL=support@sl.local +EMAIL_DOMAIN=sl.lan +OTHER_ALIAS_DOMAINS=["d1.lan", "d2.lan", "sl.lan"] +SUPPORT_EMAIL=support@sl.lan ADMIN_EMAIL=to_fill # Max number emails user can generate for free plan MAX_NB_EMAIL_FREE_PLAN=3 diff --git a/tests/test_email_handler.py b/tests/test_email_handler.py index e77a9714..bb415c1d 100644 --- a/tests/test_email_handler.py +++ b/tests/test_email_handler.py @@ -214,7 +214,7 @@ def test_avoid_add_to_header_already_present_in_cc(): def test_email_sent_to_noreply(flask_client): msg = EmailMessage() envelope = Envelope() - envelope.mail_from = "from@domain.test" + envelope.mail_from = "from@domain.lan" envelope.rcpt_tos = [config.NOREPLY] result = email_handler.handle(envelope, msg) assert result == status.E200 @@ -223,10 +223,10 @@ def test_email_sent_to_noreply(flask_client): def test_email_sent_to_noreplies(flask_client): msg = EmailMessage() envelope = Envelope() - envelope.mail_from = "from@domain.test" - config.NOREPLIES = ["other-no-reply@sl.test"] + envelope.mail_from = "from@domain.lan" + config.NOREPLIES = ["other-no-reply@sl.lan"] - envelope.rcpt_tos = ["other-no-reply@sl.test"] + envelope.rcpt_tos = ["other-no-reply@sl.lan"] result = email_handler.handle(envelope, msg) assert result == status.E200 diff --git a/tests/test_email_utils.py b/tests/test_email_utils.py index cf498e13..b01be49e 100644 --- a/tests/test_email_utils.py +++ b/tests/test_email_utils.py @@ -78,17 +78,17 @@ def test_get_email_domain_part(): def test_email_belongs_to_alias_domains(): # default alias domain - assert can_create_directory_for_address("ab@sl.local") - assert not can_create_directory_for_address("ab@not-exist.local") + assert can_create_directory_for_address("ab@sl.lan") + assert not can_create_directory_for_address("ab@not-exist.lan") - assert can_create_directory_for_address("hey@d1.test") - assert not can_create_directory_for_address("hey@d3.test") + assert can_create_directory_for_address("hey@d1.lan") + assert not can_create_directory_for_address("hey@d3.lan") def test_can_be_used_as_personal_email(flask_client): # default alias domain - assert not email_can_be_used_as_mailbox("ab@sl.local") - assert not email_can_be_used_as_mailbox("hey@d1.test") + assert not email_can_be_used_as_mailbox("ab@sl.lan") + assert not email_can_be_used_as_mailbox("hey@d1.lan") # custom domain as SL domain domain = random_domain() @@ -115,7 +115,7 @@ def test_can_be_used_as_personal_email(flask_client): def test_disabled_user_prevents_email_from_being_used_as_mailbox(): - email = f"user_{random_token(10)}@mailbox.test" + email = f"user_{random_token(10)}@mailbox.lan" assert email_can_be_used_as_mailbox(email) user = create_new_user(email) user.disabled = True @@ -124,7 +124,7 @@ def test_disabled_user_prevents_email_from_being_used_as_mailbox(): def test_disabled_user_with_secondary_mailbox_prevents_email_from_being_used_as_mailbox(): - email = f"user_{random_token(10)}@mailbox.test" + email = f"user_{random_token(10)}@mailbox.lan" assert email_can_be_used_as_mailbox(email) user = create_new_user() Mailbox.create(user_id=user.id, email=email) @@ -592,8 +592,8 @@ def test_generate_reply_email_include_sender_in_reverse_alias(flask_client): def test_normalize_reply_email(flask_client): - assert normalize_reply_email("re+abcd@sl.local") == "re+abcd@sl.local" - assert normalize_reply_email('re+"ab cd"@sl.local') == "re+_ab_cd_@sl.local" + assert normalize_reply_email("re+abcd@sl.lan") == "re+abcd@sl.lan" + assert normalize_reply_email('re+"ab cd"@sl.lan') == "re+_ab_cd_@sl.lan" def test_get_encoding(): @@ -669,7 +669,7 @@ def test_should_disable(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) for _ in range(20): @@ -702,7 +702,7 @@ def test_should_disable_bounces_every_day(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) for i in range(9): @@ -730,7 +730,7 @@ def test_should_disable_bounces_account(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) @@ -758,7 +758,7 @@ def test_should_disable_bounce_consecutive_days(flask_client): user_id=user.id, alias_id=alias.id, website_email="contact@example.com", - reply_email="rep@sl.local", + reply_email="rep@sl.lan", commit=True, ) diff --git a/tests/test_models.py b/tests/test_models.py index b84488d0..5ea11d96 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -36,7 +36,9 @@ def test_generate_email(flask_client): def test_profile_picture_url(flask_client): user = create_new_user() - assert user.profile_picture_url() == "http://sl.test/static/default-avatar.png" + assert ( + user.profile_picture_url() == f"http://{EMAIL_DOMAIN}/static/default-avatar.png" + ) def test_suggested_emails_for_user_who_cannot_create_new_alias(flask_client): @@ -303,7 +305,7 @@ def test_create_contact_for_noreply(flask_client): Contact.create( user_id=user.id, alias_id=alias.id, - website_email=f"{random.random()}@contact.test", + website_email=f"{random.random()}@contact.lan", reply_email=NOREPLY, commit=True, ) diff --git a/tests/test_server.py b/tests/test_server.py index 3d3dc446..dbcc5338 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,5 +1,6 @@ import arrow +from app.config import EMAIL_DOMAIN from app.db import Session from app.models import CoinbaseSubscription from app.payments.coinbase import handle_coinbase_event @@ -11,7 +12,7 @@ def test_redirect_login_page(flask_client): rv = flask_client.get("/") assert rv.status_code == 302 - assert rv.location == "http://sl.test/auth/login" + assert rv.location == f"http://{EMAIL_DOMAIN}/auth/login" def test_coinbase_webhook(flask_client): diff --git a/tests/utils.py b/tests/utils.py index b7798d01..d0a65948 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -16,7 +16,7 @@ from app.utils import random_string def create_new_user(email: Optional[str] = None, name: Optional[str] = None) -> User: if not email: - email = f"user_{random_token(10)}@mailbox.test" + email = f"user_{random_token(10)}@mailbox.lan" if not name: name = "Test User" # new user has a different email address @@ -60,7 +60,7 @@ def login(flask_client, user: Optional[User] = None) -> User: def random_domain() -> str: - return random_token() + ".test" + return random_token() + ".lan" def random_token(length: int = 10) -> str: diff --git a/uv.lock b/uv.lock index 65d7e835..0d4e5c24 100644 --- a/uv.lock +++ b/uv.lock @@ -179,6 +179,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/df/479736ae1ef59842f512548bacefad1abed705e400212acba43f9b0fa556/attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc", size = 48140 }, ] +[[package]] +name = "authres" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/29/e28209b5d3d56c102845cca5a4a3abaf2724f79e83476a52b94d775ecce6/authres-1.2.0.tar.gz", hash = "sha256:93d1b995ad7ce21e62db649f361048125dd6022563a0ae8a23909465f1fd25b7", size = 23226 } + [[package]] name = "backcall" version = "0.2.0" @@ -227,9 +233,12 @@ wheels = [ [[package]] name = "blinker" -version = "1.4" +version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/51/e2a9f3b757eb802f61dc1f2b09c8c99f6eb01cf06416c0671253536517b6/blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6", size = 111476 } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, +] [[package]] name = "boto3" @@ -497,11 +506,11 @@ sdist = { url = "https://files.pythonhosted.org/packages/b5/33/9c60f3a34d4d7237e [[package]] name = "dnspython" -version = "2.0.0" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/d0/639a9b5273103a18c5c68a7a9fc02b01cffa3403e72d553acec444f85d5b/dnspython-2.0.0.zip", hash = "sha256:044af09374469c3a39eeea1a146e8cac27daec951f1f1f157b1962fc7cb9d1b7", size = 324706 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/49/cb426577c28ca3e35332815b795a99e467523843fc83cc85ca0d6be2515a/dnspython-2.0.0-py3-none-any.whl", hash = "sha256:40bb3c24b9d4ec12500f0124288a65df232a3aa749bb0c39734b782873a2544d", size = 208262 }, + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, ] [[package]] @@ -515,15 +524,15 @@ wheels = [ [[package]] name = "email-validator" -version = "1.1.3" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/f3/017ab4619ee83e79fc1c9572ac601671cf9cfb33a0523021b46851b4d9a4/email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7", size = 24484 } +sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/e4/e01e92092fdac940f10fa4c8ac3481bf70fc74023a76f5c72020c9445e68/email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b", size = 18318 }, + { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] [[package]] @@ -1487,6 +1496,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378", size = 98708 }, ] +[[package]] +name = "py3dns" +version = "4.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/67/d7e745a5248bd7ecf2b76d3a1c8280255cbbdcb21174b171cf3c87740836/py3dns-4.0.2.tar.gz", hash = "sha256:98652e80ecec143c60f78f0e6b341631ca9a7560edd8dddfc864c02902618a39", size = 33982 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/43/1ff28f5302a0f423d4210cacc1f12fb416b6ba1f4c7107e020d264acb625/py3dns-4.0.2-py3-none-any.whl", hash = "sha256:36bffe62b59a72cfa09c03f0bd3473e0126f20ee4285d14c07415dbf6f5fd571", size = 29589 }, +] + [[package]] name = "pyasn1" version = "0.4.8" @@ -1604,9 +1622,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/bc/7c/d724ef1ec3ab2125f [[package]] name = "pyspf" -version = "2.0.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/dc/5b3838ff90474e21fe0914920c53430f73402e07d6598ea228e61b74963e/pyspf-2.0.14.tar.gz", hash = "sha256:57a7ef01bda090173aafb6af0106251686ed73f03db4e911fcd34c57fc347186", size = 69446 } +version = "2.1.0" +source = { git = "https://github.com/sdgathman/pyspf.git?rev=665a6df079485a9824be0829e7d71088453db7f6#665a6df079485a9824be0829e7d71088453db7f6" } +dependencies = [ + { name = "authres" }, + { name = "py3dns" }, +] [[package]] name = "pytest" @@ -1960,15 +1981,15 @@ requires-dist = [ { name = "alembic", specifier = "~=1.4.3" }, { name = "arrow", specifier = "~=0.16.0" }, { name = "bcrypt", specifier = "~=3.2.0" }, - { name = "blinker", specifier = "~=1.4" }, + { name = "blinker", specifier = "~=1.9.0" }, { name = "boto3", specifier = "~=1.35.37" }, { name = "coinbase-commerce", specifier = "~=1.0.1" }, { name = "coloredlogs", specifier = "~=14.0" }, { name = "cryptography", specifier = "~=37.0.1" }, { name = "deprecated", specifier = "~=1.2.13" }, { name = "dkimpy", specifier = "~=1.0.5" }, - { name = "dnspython", specifier = "==2.0.0" }, - { name = "email-validator", specifier = "~=1.1.3" }, + { name = "dnspython", specifier = "~=2.7.0" }, + { name = "email-validator", specifier = "~=2.2.0" }, { name = "facebook-sdk", specifier = "~=3.1.0" }, { name = "flanker", specifier = "~=0.9.11" }, { name = "flask", specifier = "~=1.1.2" }, @@ -2000,7 +2021,7 @@ requires-dist = [ { name = "pyopenssl", specifier = "~=19.1.0" }, { name = "pyotp", specifier = "~=2.4.0" }, { name = "pyre2", specifier = "~=0.3.6" }, - { name = "pyspf", specifier = "~=2.0.14" }, + { name = "pyspf", git = "https://github.com/sdgathman/pyspf.git?rev=665a6df079485a9824be0829e7d71088453db7f6#665a6df079485a9824be0829e7d71088453db7f6" }, { name = "python-dotenv", specifier = "~=0.14.0" }, { name = "python-gnupg", specifier = "~=0.4.6" }, { name = "redis", specifier = "==4.6.0" },