From ef82a186d82a1f7dfa3383d369f7328eec469f92 Mon Sep 17 00:00:00 2001 From: missytake Date: Thu, 12 Mar 2026 20:28:01 +0100 Subject: [PATCH] www: generate dclogin codes for IPv4-only relays --- chatmaild/src/chatmaild/newemail.py | 29 +++++++++---------- chatmaild/src/chatmaild/tests/plugin.py | 5 ++++ chatmaild/src/chatmaild/tests/test_newmail.py | 25 +++++++++++----- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/chatmaild/src/chatmaild/newemail.py b/chatmaild/src/chatmaild/newemail.py index 4aa54aee..7d2f42c1 100644 --- a/chatmaild/src/chatmaild/newemail.py +++ b/chatmaild/src/chatmaild/newemail.py @@ -2,7 +2,6 @@ """CGI script for creating new accounts.""" -import ipaddress import json import secrets import string @@ -15,16 +14,6 @@ ALPHANUMERIC = string.ascii_lowercase + string.digits ALPHANUMERIC_PUNCT = string.ascii_letters + string.digits + string.punctuation -def wrap_ip(host): - if host.startswith("[") and host.endswith("]"): - return host - try: - ipaddress.ip_address(host) - return f"[{host}]" - except ValueError: - return host - - def create_newemail_dict(config: Config): user = "".join( secrets.choice(ALPHANUMERIC) for _ in range(config.username_max_length) @@ -33,16 +22,24 @@ def create_newemail_dict(config: Config): secrets.choice(ALPHANUMERIC_PUNCT) for _ in range(config.password_min_length + 3) ) - return dict(email=f"{user}@{wrap_ip(config.mail_domain)}", password=f"{password}") + return dict( + email=f"{user}@{config.mail_domain_deliverable}", password=f"{password}" + ) -def create_dclogin_url(email, password): +def create_dclogin_url(config, email, password): """Build a dclogin: URL with credentials and self-signed cert acceptance. Uses ic=3 (AcceptInvalidCertificates) so chatmail clients can connect to servers with self-signed TLS certificates. """ - return f"dclogin:{quote(email, safe='@')}?p={quote(password, safe='')}&v=1&ic=3" + if config.mail_domain != config.mail_domain_deliverable: + imap_host = "&ih=" + config.mail_domain + smtp_host = "&sh=" + config.mail_domain + else: + imap_host = "" + smtp_host = "" + return f"dclogin:{quote(email, safe='@[]')}?p={quote(password, safe='')}&v=1{imap_host}{smtp_host}&ic=3" def print_new_account(): @@ -51,7 +48,9 @@ def print_new_account(): result = dict(email=creds["email"], password=creds["password"]) if config.tls_cert_mode == "self": - result["dclogin_url"] = create_dclogin_url(creds["email"], creds["password"]) + result["dclogin_url"] = create_dclogin_url( + config, creds["email"], creds["password"] + ) print("Content-Type: application/json") print("") diff --git a/chatmaild/src/chatmaild/tests/plugin.py b/chatmaild/src/chatmaild/tests/plugin.py index b57418a3..27de56af 100644 --- a/chatmaild/src/chatmaild/tests/plugin.py +++ b/chatmaild/src/chatmaild/tests/plugin.py @@ -31,6 +31,11 @@ def example_config(make_config): return make_config("chat.example.org") +@pytest.fixture +def ipv4_config(make_config): + return make_config("1.3.3.7") + + @pytest.fixture def maildomain(example_config): return example_config.mail_domain diff --git a/chatmaild/src/chatmaild/tests/test_newmail.py b/chatmaild/src/chatmaild/tests/test_newmail.py index b266d11e..f7046ca3 100644 --- a/chatmaild/src/chatmaild/tests/test_newmail.py +++ b/chatmaild/src/chatmaild/tests/test_newmail.py @@ -19,24 +19,35 @@ def test_create_newemail_dict(example_config): assert ac1["password"] != ac2["password"] -def test_create_newemail_dict_ip(make_config): - config = make_config("1.2.3.4") - ac = create_newemail_dict(config) - assert ac["email"].endswith("@[1.2.3.4]") +def test_create_newemail_dict_ip(ipv4_config): + ac = create_newemail_dict(ipv4_config) + assert ac["email"].endswith("@[1.3.3.7]") -def test_create_dclogin_url(): - url = create_dclogin_url("user@example.org", "p@ss w+rd") +def test_create_dclogin_url(example_config): + addr = "user@example.org" + password = "p@ss w+rd" + url = create_dclogin_url(example_config, addr, password) assert url.startswith("dclogin:") assert "v=1" in url assert "ic=3" in url - assert "user@example.org" in url + assert addr in url # password special chars must be encoded assert "p%40ss" in url assert "w%2Brd" in url +def test_create_dclogin_url_ipv4(ipv4_config): + addr = "user@[1.3.3.7]" + password = "p@ss w+rd" + url = create_dclogin_url(ipv4_config, addr, password) + assert url.startswith("dclogin:") + assert "v=1" in url + assert "ic=3" in url + assert addr in url + + def test_print_new_account(capsys, monkeypatch, maildomain, tmpdir, example_config): monkeypatch.setattr(chatmaild.newemail, "CONFIG_PATH", str(example_config._inipath)) print_new_account()