From 95f8c4b269d2efe5225d163c56a7ac4279b2a998 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 5 Nov 2024 13:18:11 +0000 Subject: [PATCH] Update iroh and remove iroh. subdomain --- CHANGELOG.md | 4 +-- chatmaild/src/chatmaild/config.py | 2 +- cmdeploy/src/cmdeploy/__init__.py | 31 +++++++++--------- cmdeploy/src/cmdeploy/chatmail.zone.j2 | 1 - cmdeploy/src/cmdeploy/cmdeploy.py | 7 ++-- cmdeploy/src/cmdeploy/deploy.py | 3 +- cmdeploy/src/cmdeploy/dns.py | 9 ++---- cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 | 32 ++++++++++++------- cmdeploy/src/cmdeploy/remote/rdns.py | 7 ++-- .../src/cmdeploy/tests/online/test_1_basic.py | 8 ++--- cmdeploy/src/cmdeploy/tests/test_dns.py | 12 +++---- 11 files changed, 57 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98e1b8a9..097a8ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,9 @@ ## untagged -- deploy `iroh-relay` (requires new "iroh.{mail_domain}" DNS entry), - also update "realtime relay services" in privacy policy. +- deploy `iroh-relay` and also update "realtime relay services" in privacy policy. ([#434](https://github.com/deltachat/chatmail/pull/434)) + ([#451](https://github.com/deltachat/chatmail/pull/451)) - add guide to migrate chatmail to a new server ([#429](https://github.com/deltachat/chatmail/pull/429)) diff --git a/chatmaild/src/chatmaild/config.py b/chatmaild/src/chatmaild/config.py index b453389c..670b2042 100644 --- a/chatmaild/src/chatmaild/config.py +++ b/chatmaild/src/chatmaild/config.py @@ -34,7 +34,7 @@ class Config: self.disable_ipv6 = params.get("disable_ipv6", "false").lower() == "true" self.imap_rawlog = params.get("imap_rawlog", "false").lower() == "true" if "iroh_relay" not in params: - self.iroh_relay = "https://iroh." + params["mail_domain"] + self.iroh_relay = "https://" + params["mail_domain"] self.enable_iroh_relay = True else: self.iroh_relay = params["iroh_relay"].strip() diff --git a/cmdeploy/src/cmdeploy/__init__.py b/cmdeploy/src/cmdeploy/__init__.py index 120d0f4a..df5bbaa2 100644 --- a/cmdeploy/src/cmdeploy/__init__.py +++ b/cmdeploy/src/cmdeploy/__init__.py @@ -481,8 +481,14 @@ def deploy_mtail(config): def deploy_iroh_relay(config) -> None: (url, sha256sum) = { - "x86_64": ("https://github.com/n0-computer/iroh/releases/download/v0.27.0/iroh-relay-v0.27.0-x86_64-unknown-linux-musl.tar.gz", "8af7f6d29d17476ce5c3053c3161db5793cb2ac49057d0bcaf689436cdccbeab"), - "aarch64": ("https://github.com/n0-computer/iroh/releases/download/v0.27.0/iroh-relay-v0.27.0-aarch64-unknown-linux-musl.tar.gz", "18039f0d39df78922a5055a0d4a5a8fa98a2a0e19b1eaa4c3fe6db73b8698697") + "x86_64": ( + "https://github.com/n0-computer/iroh/releases/download/v0.28.1/iroh-relay-v0.28.1-x86_64-unknown-linux-musl.tar.gz", + "2ffacf7c0622c26b67a5895ee8e07388769599f60e5f52a3bd40a3258db89b2c", + ), + "aarch64": ( + "https://github.com/n0-computer/iroh/releases/download/v0.28.1/iroh-relay-v0.28.1-aarch64-unknown-linux-musl.tar.gz", + "b915037bcc1ff1110cc9fcb5de4a17c00ff576fd2f568cd339b3b2d54c420dc4", + ), }[host.get_fact(facts.server.Arch)] apt.packages( @@ -493,7 +499,7 @@ def deploy_iroh_relay(config) -> None: server.shell( name="Download iroh-relay", commands=[ - f"(echo '{sha256sum} /usr/local/bin/iroh-relay' | sha256sum -c) || curl -L {url} | gunzip | tar -x -f - ./iroh-relay -O >/usr/local/bin/iroh-relay", + f"(echo '{sha256sum} /usr/local/bin/iroh-relay' | sha256sum -c) || (curl -L {url} | gunzip | tar -x -f - ./iroh-relay -O >/usr/local/bin/iroh-relay.new && mv /usr/local/bin/iroh-relay.new /usr/local/bin/iroh-relay)", "chmod 755 /usr/local/bin/iroh-relay", ], ) @@ -502,9 +508,7 @@ def deploy_iroh_relay(config) -> None: systemd_unit = files.put( name="Upload iroh-relay systemd unit", - src=importlib.resources.files(__package__).joinpath( - "iroh-relay.service" - ), + src=importlib.resources.files(__package__).joinpath("iroh-relay.service"), dest="/etc/systemd/system/iroh-relay.service", user="root", group="root", @@ -514,13 +518,11 @@ def deploy_iroh_relay(config) -> None: iroh_config = files.put( name=f"Upload iroh-relay config", - src=importlib.resources.files(__package__).joinpath( - "iroh-relay.toml" - ), + src=importlib.resources.files(__package__).joinpath("iroh-relay.toml"), dest=f"/etc/iroh-relay.toml", - user="iroh", - group="iroh", - mode="600", + user="root", + group="root", + mode="644", ) need_restart |= iroh_config.changed @@ -533,12 +535,11 @@ def deploy_iroh_relay(config) -> None: ) -def deploy_chatmail(config_path: Path, disable_mail: bool, require_iroh: bool) -> None: +def deploy_chatmail(config_path: Path, disable_mail: bool) -> None: """Deploy a chat-mail instance. :param config_path: path to chatmail.ini :param disable_mail: whether to disable postfix & dovecot - :param require_iroh: whether to request a TLS certificate for iroh.$mail_domain """ config = read_config(config_path) check_config(config) @@ -616,8 +617,6 @@ def deploy_chatmail(config_path: Path, disable_mail: bool, require_iroh: bool) - # Deploy acmetool to have TLS certificates. tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"] - if require_iroh: - tls_domains.append(f"iroh.{mail_domain}") deploy_acmetool( domains=tls_domains, ) diff --git a/cmdeploy/src/cmdeploy/chatmail.zone.j2 b/cmdeploy/src/cmdeploy/chatmail.zone.j2 index 10b07758..f0ba176f 100644 --- a/cmdeploy/src/cmdeploy/chatmail.zone.j2 +++ b/cmdeploy/src/cmdeploy/chatmail.zone.j2 @@ -11,7 +11,6 @@ _mta-sts.{{ mail_domain }}. TXT "v=STSv1; id={{ sts_id }}" mta-sts.{{ mail_domain }}. CNAME {{ mail_domain }}. www.{{ mail_domain }}. CNAME {{ mail_domain }}. -iroh.{{ mail_domain }}. CNAME {{ mail_domain }}. {{ dkim_entry }} ; diff --git a/cmdeploy/src/cmdeploy/cmdeploy.py b/cmdeploy/src/cmdeploy/cmdeploy.py index fe7970dc..b36b29f0 100644 --- a/cmdeploy/src/cmdeploy/cmdeploy.py +++ b/cmdeploy/src/cmdeploy/cmdeploy.py @@ -70,8 +70,8 @@ def run_cmd(args, out): sshexec = args.get_sshexec() require_iroh = args.config.enable_iroh_relay - remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain, require_iroh) - if not dns.check_initial_remote_data(remote_data, require_iroh, print=out.red): + remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain) + if not dns.check_initial_remote_data(remote_data, print=out.red): return 1 env = os.environ.copy() @@ -111,8 +111,7 @@ def dns_cmd_options(parser): def dns_cmd(args, out): """Check DNS entries and optionally generate dns zone file.""" sshexec = args.get_sshexec() - require_iroh = args.config.enable_iroh_relay - remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain, require_iroh) + remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain) if not remote_data: return 1 diff --git a/cmdeploy/src/cmdeploy/deploy.py b/cmdeploy/src/cmdeploy/deploy.py index 9c8e7400..0ea153d7 100644 --- a/cmdeploy/src/cmdeploy/deploy.py +++ b/cmdeploy/src/cmdeploy/deploy.py @@ -12,9 +12,8 @@ def main(): importlib.resources.files("cmdeploy").joinpath("../../../chatmail.ini"), ) disable_mail = bool(os.environ.get('CHATMAIL_DISABLE_MAIL')) - require_iroh = bool(os.environ.get('CHATMAIL_REQUIRE_IROH')) - deploy_chatmail(config_path, disable_mail, require_iroh) + deploy_chatmail(config_path, disable_mail) if pyinfra.is_cli: diff --git a/cmdeploy/src/cmdeploy/dns.py b/cmdeploy/src/cmdeploy/dns.py index b8e05f21..d3c541bb 100644 --- a/cmdeploy/src/cmdeploy/dns.py +++ b/cmdeploy/src/cmdeploy/dns.py @@ -6,22 +6,19 @@ from jinja2 import Template from . import remote -def get_initial_remote_data(sshexec, mail_domain, iroh_enabled): +def get_initial_remote_data(sshexec, mail_domain): return sshexec.logged( - call=remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=mail_domain, iroh_enabled=iroh_enabled) + call=remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=mail_domain) ) -def check_initial_remote_data(remote_data, require_iroh, *, print=print): +def check_initial_remote_data(remote_data, *, print=print): mail_domain = remote_data["mail_domain"] if not remote_data["A"] and not remote_data["AAAA"]: print(f"Missing A and/or AAAA DNS records for {mail_domain}!") elif remote_data["MTA_STS"] != f"{mail_domain}.": print("Missing MTA-STS CNAME record:") print(f"mta-sts.{mail_domain}. CNAME {mail_domain}.") - elif require_iroh and remote_data["IROH"] != f"{mail_domain}.": - print("Missing iroh CNAME record:") - print(f"iroh.{mail_domain}. CNAME {mail_domain}.") elif remote_data["WWW"] != f"{mail_domain}.": print("Missing www CNAME record:") print(f"www.{mail_domain}. CNAME {mail_domain}.") diff --git a/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 b/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 index 5797b4c0..6cda5f1b 100644 --- a/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 +++ b/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2 @@ -96,6 +96,26 @@ http { include /etc/nginx/fastcgi_params; fastcgi_param SCRIPT_FILENAME /usr/lib/cgi-bin/newemail.py; } + + # Proxy to iroh-relay service. + location /relay { + proxy_pass http://127.0.0.1:3340; + proxy_http_version 1.1; + + # Upgrade header is normally set to "iroh derp http" or "websocket". + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location /relay/probe { + proxy_pass http://127.0.0.1:3340; + proxy_http_version 1.1; + } + + location /generate_204 { + proxy_pass http://127.0.0.1:3340; + proxy_http_version 1.1; + } } # Redirect www. to non-www @@ -108,16 +128,4 @@ http { return 301 $scheme://{{ config.domain_name }}$request_uri; access_log syslog:server=unix:/dev/log,facility=local7; } - - # Pass iroh. to iroh-relay service. - server { - listen 8443 ssl; - {% if not disable_ipv6 %} - listen [::]:8443 ssl; - {% endif %} - server_name iroh.{{ config.domain_name }}; - location / { - proxy_pass http://127.0.0.1:3340; - } - } } diff --git a/cmdeploy/src/cmdeploy/remote/rdns.py b/cmdeploy/src/cmdeploy/remote/rdns.py index 107d7d23..77093503 100644 --- a/cmdeploy/src/cmdeploy/remote/rdns.py +++ b/cmdeploy/src/cmdeploy/remote/rdns.py @@ -15,7 +15,7 @@ import re from .rshell import CalledProcessError, shell -def perform_initial_checks(mail_domain, iroh_enabled): +def perform_initial_checks(mail_domain): """Collecting initial DNS settings.""" assert mail_domain if not shell("dig", fail_ok=True): @@ -23,14 +23,13 @@ def perform_initial_checks(mail_domain, iroh_enabled): A = query_dns("A", mail_domain) AAAA = query_dns("AAAA", mail_domain) MTA_STS = query_dns("CNAME", f"mta-sts.{mail_domain}") - IROH = query_dns("CNAME", f"iroh.{mail_domain}") WWW = query_dns("CNAME", f"www.{mail_domain}") - res = dict(mail_domain=mail_domain, A=A, AAAA=AAAA, MTA_STS=MTA_STS, IROH=IROH, WWW=WWW) + res = dict(mail_domain=mail_domain, A=A, AAAA=AAAA, MTA_STS=MTA_STS, WWW=WWW) res["acme_account_url"] = shell("acmetool account-url", fail_ok=True) res["dkim_entry"] = get_dkim_entry(mail_domain, dkim_selector="opendkim") - if not MTA_STS or (not IROH and not iroh_enabled) or not WWW or (not A and not AAAA): + if not MTA_STS or not WWW or (not A and not AAAA): return res # parse out sts-id if exists, example: "v=STSv1; id=2090123" diff --git a/cmdeploy/src/cmdeploy/tests/online/test_1_basic.py b/cmdeploy/src/cmdeploy/tests/online/test_1_basic.py index 13424ef3..f5f2c023 100644 --- a/cmdeploy/src/cmdeploy/tests/online/test_1_basic.py +++ b/cmdeploy/src/cmdeploy/tests/online/test_1_basic.py @@ -18,13 +18,13 @@ class TestSSHExecutor: def test_perform_initial(self, sshexec, maildomain): res = sshexec( - remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True) + remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain) ) assert res["A"] or res["AAAA"] def test_logged(self, sshexec, maildomain, capsys): sshexec.logged( - remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True) + remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain) ) out, err = capsys.readouterr() assert err.startswith("Collecting") @@ -33,7 +33,7 @@ class TestSSHExecutor: sshexec.verbose = True sshexec.logged( - remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True) + remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain) ) out, err = capsys.readouterr() lines = err.split("\n") @@ -44,7 +44,7 @@ class TestSSHExecutor: try: sshexec.logged( remote.rdns.perform_initial_checks, - kwargs=dict(mail_domain=None, iroh_enabled=True), + kwargs=dict(mail_domain=None), ) except sshexec.FuncError as e: assert "rdns.py" in str(e) diff --git a/cmdeploy/src/cmdeploy/tests/test_dns.py b/cmdeploy/src/cmdeploy/tests/test_dns.py index a69a7f73..fd11095f 100644 --- a/cmdeploy/src/cmdeploy/tests/test_dns.py +++ b/cmdeploy/src/cmdeploy/tests/test_dns.py @@ -26,7 +26,6 @@ def mockdns(mockdns_base): "AAAA": {"some.domain": "fde5:cd7a:9e1c:3240:5a99:936f:cdac:53ae"}, "CNAME": { "mta-sts.some.domain": "some.domain.", - "iroh.some.domain": "some.domain.", "www.some.domain": "some.domain.", }, } @@ -36,31 +35,30 @@ def mockdns(mockdns_base): class TestPerformInitialChecks: def test_perform_initial_checks_ok1(self, mockdns): - remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True) + remote_data = remote.rdns.perform_initial_checks("some.domain") assert remote_data["A"] == mockdns["A"]["some.domain"] assert remote_data["AAAA"] == mockdns["AAAA"]["some.domain"] assert remote_data["MTA_STS"] == mockdns["CNAME"]["mta-sts.some.domain"] - assert remote_data["IROH"] == mockdns["CNAME"]["iroh.some.domain"] assert remote_data["WWW"] == mockdns["CNAME"]["www.some.domain"] @pytest.mark.parametrize("drop", ["A", "AAAA"]) def test_perform_initial_checks_with_one_of_A_AAAA(self, mockdns, drop): del mockdns[drop] - remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True) + remote_data = remote.rdns.perform_initial_checks("some.domain") assert not remote_data[drop] l = [] - res = check_initial_remote_data(remote_data, require_iroh=True, print=l.append) + res = check_initial_remote_data(remote_data, print=l.append) assert res assert not l def test_perform_initial_checks_no_mta_sts(self, mockdns): del mockdns["CNAME"]["mta-sts.some.domain"] - remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True) + remote_data = remote.rdns.perform_initial_checks("some.domain") assert not remote_data["MTA_STS"] l = [] - res = check_initial_remote_data(remote_data, require_iroh=True, print=l.append) + res = check_initial_remote_data(remote_data, print=l.append) assert not res assert len(l) == 2