chore: fix regex warnings on python 3.12 (#2400)

* deps: update some dependencies to fix warnings

* chore: move from sl.local to sl.lan for local development

* fix: mark string as regex

* chore: move facebook import to handler so its not global

* test: fix tests

* style: lint fixes

* test: move all .test and .local to .lan

* ci: do not use setup-python in lint
This commit is contained in:
Carlos Quintana 2025-02-26 15:41:50 +01:00 committed by GitHub
parent f5de78f2e1
commit 59957ec08b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 139 additions and 108 deletions

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -1,4 +1,5 @@
"""List of clients"""
from flask import render_template
from flask_login import current_user, login_required

View file

@ -1,4 +1,5 @@
"""Email headers"""
MESSAGE_ID = "Message-ID"
IN_REPLY_TO = "In-Reply-To"
REFERENCES = "References"

View file

@ -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

View file

@ -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):

View file

@ -1,6 +1,7 @@
"""Inspired from
https://github.com/petermat/spamassassin_client
"""
import logging
import socket
from io import BytesIO

View file

@ -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\" <reply@a.b>",
@ -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 <ra+qytyzjhrumrreuszrbjxqjlkh@sl.local>",
"reverse_alias": "First Last first@example.com <ra+qytyzjhrumrreuszrbjxqjlkh@sl.lan>",
"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
},
{

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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")

View file

@ -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")

View file

@ -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)

View file

@ -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}

View file

@ -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:

View file

@ -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,

View file

@ -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,
)

View file

@ -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()

View file

@ -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,
)

View file

@ -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,
),

View file

@ -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

View file

@ -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

View file

@ -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,
)

View file

@ -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,
)

View file

@ -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):

View file

@ -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:

51
uv.lock generated
View file

@ -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" },