Compare commits

...

10 Commits

Author SHA1 Message Date
link2xt
2e616a7b5c ci: delete old files when backing up acmetool state and DKIM keys 2025-12-17 11:57:58 +01:00
j4n
df21076e9b acmetool: use a fixed name and reconcile instead of want 2025-12-17 11:57:41 +01:00
missytake
70da217442 opendkim: only display last sigerror 2025-12-17 10:39:50 +01:00
missytake
40fd62c562 opendkim: report DKIM error code in SMTP response 2025-12-17 10:39:50 +01:00
cliffmccarthy
d76b33def1 feat: Remove echo from passthrough recipients 2025-12-17 10:35:47 +01:00
cliffmccarthy
bab3de9768 feat: Remove echobot user from deployment 2025-12-17 10:35:47 +01:00
cliffmccarthy
49c66116bf feat: Remove echobot special cases 2025-12-17 10:35:47 +01:00
373
9bf99cc8a9 removes development notice 2025-12-16 15:06:45 +01:00
Mark Felder
1188aed061 Related: Add the Chatmail Cookbook project 2025-12-14 20:32:08 +01:00
Mark Felder
e15b8ebf11 docs README update
There is no sphinx-build to pip install
2025-12-14 20:31:19 +01:00
12 changed files with 47 additions and 27 deletions

View File

@@ -35,11 +35,11 @@ jobs:
chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519
ssh-keyscan staging-ipv4.testrun.org > ~/.ssh/known_hosts ssh-keyscan staging-ipv4.testrun.org > ~/.ssh/known_hosts
# save previous acme & dkim state # save previous acme & dkim state
rsync -avz root@staging-ipv4.testrun.org:/var/lib/acme acme-ipv4 || true rsync -avz --delete root@staging-ipv4.testrun.org:/var/lib/acme acme-ipv4
rsync -avz root@staging-ipv4.testrun.org:/etc/dkimkeys dkimkeys-ipv4 || true rsync -avz --delete root@staging-ipv4.testrun.org:/etc/dkimkeys dkimkeys-ipv4
# store previous acme & dkim state on ns.testrun.org, if it contains useful certs # store previous acme & dkim state on ns.testrun.org, if it contains useful certs
if [ -f dkimkeys-ipv4/dkimkeys/opendkim.private ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" dkimkeys-ipv4 root@ns.testrun.org:/tmp/ || true; fi test -f dkimkeys-ipv4/dkimkeys/opendkim.private && rsync -avz --delete -e "ssh -o StrictHostKeyChecking=accept-new" dkimkeys-ipv4 root@ns.testrun.org:/tmp/
if [ "$(ls -A acme-ipv4/acme/certs)" ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" acme-ipv4 root@ns.testrun.org:/tmp/ || true; fi test -n "$(ls -A acme-ipv4/acme/certs)" && rsync -avz --delete -e "ssh -o StrictHostKeyChecking=accept-new" acme-ipv4 root@ns.testrun.org:/tmp/
# make sure CAA record isn't set # make sure CAA record isn't set
scp -o StrictHostKeyChecking=accept-new .github/workflows/staging-ipv4.testrun.org-default.zone root@ns.testrun.org:/etc/nsd/staging-ipv4.testrun.org.zone scp -o StrictHostKeyChecking=accept-new .github/workflows/staging-ipv4.testrun.org-default.zone root@ns.testrun.org:/etc/nsd/staging-ipv4.testrun.org.zone
ssh root@ns.testrun.org sed -i '/CAA/d' /etc/nsd/staging-ipv4.testrun.org.zone ssh root@ns.testrun.org sed -i '/CAA/d' /etc/nsd/staging-ipv4.testrun.org.zone

View File

@@ -35,11 +35,11 @@ jobs:
chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519
ssh-keyscan staging2.testrun.org > ~/.ssh/known_hosts ssh-keyscan staging2.testrun.org > ~/.ssh/known_hosts
# save previous acme & dkim state # save previous acme & dkim state
rsync -avz root@staging2.testrun.org:/var/lib/acme . || true rsync -avz --delete root@staging2.testrun.org:/var/lib/acme .
rsync -avz root@staging2.testrun.org:/etc/dkimkeys . || true rsync -avz --delete root@staging2.testrun.org:/etc/dkimkeys .
# store previous acme & dkim state on ns.testrun.org, if it contains useful certs # store previous acme & dkim state on ns.testrun.org, if it contains useful certs
if [ -f dkimkeys/opendkim.private ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" dkimkeys root@ns.testrun.org:/tmp/ || true; fi test -f dkimkeys/opendkim.private && rsync -avz --delete -e "ssh -o StrictHostKeyChecking=accept-new" dkimkeys root@ns.testrun.org:/tmp/
if [ "$(ls -A acme/certs)" ]; then rsync -avz -e "ssh -o StrictHostKeyChecking=accept-new" acme root@ns.testrun.org:/tmp/ || true; fi test -n "$(ls -A acme/certs)" && rsync -avz --delete -e "ssh -o StrictHostKeyChecking=accept-new" acme root@ns.testrun.org:/tmp/
# make sure CAA record isn't set # make sure CAA record isn't set
scp -o StrictHostKeyChecking=accept-new .github/workflows/staging.testrun.org-default.zone root@ns.testrun.org:/etc/nsd/staging2.testrun.org.zone scp -o StrictHostKeyChecking=accept-new .github/workflows/staging.testrun.org-default.zone root@ns.testrun.org:/etc/nsd/staging2.testrun.org.zone
ssh root@ns.testrun.org sed -i '/CAA/d' /etc/nsd/staging2.testrun.org.zone ssh root@ns.testrun.org sed -i '/CAA/d' /etc/nsd/staging2.testrun.org.zone

View File

@@ -43,7 +43,7 @@ passthrough_senders =
# list of e-mail recipients for which to accept outbound un-encrypted mails # list of e-mail recipients for which to accept outbound un-encrypted mails
# (space-separated, item may start with "@" to whitelist whole recipient domains) # (space-separated, item may start with "@" to whitelist whole recipient domains)
passthrough_recipients = echo@{mail_domain} passthrough_recipients =
# path to www directory - documented here: https://chatmail.at/doc/relay/getting_started.html#custom-web-pages # path to www directory - documented here: https://chatmail.at/doc/relay/getting_started.html#custom-web-pages
#www_folder = www #www_folder = www

View File

@@ -13,8 +13,6 @@ class LastLoginDictProxy(DictProxy):
keyname = parts[1].split("/") keyname = parts[1].split("/")
value = parts[2] if len(parts) > 2 else "" value = parts[2] if len(parts) > 2 else ""
if keyname[0] == "shared" and keyname[1] == "last-login": if keyname[0] == "shared" and keyname[1] == "last-login":
if addr.startswith("echo@"):
return True
addr = keyname[2] addr = keyname[2]
timestamp = int(value) timestamp = int(value)
user = self.config.get_user(addr) user = self.config.get_user(addr)

View File

@@ -19,7 +19,7 @@ class User:
@property @property
def can_track(self): def can_track(self):
return "@" in self.addr and not self.addr.startswith("echo@") return "@" in self.addr
def get_userdb_dict(self): def get_userdb_dict(self):
"""Return a non-empty dovecot 'userdb' style dict """Return a non-empty dovecot 'userdb' style dict
@@ -55,11 +55,9 @@ class User:
try: try:
write_bytes_atomic(self.password_path, password) write_bytes_atomic(self.password_path, password)
except PermissionError: except PermissionError:
if not self.addr.startswith("echo@"): logging.error(f"could not write password for: {self.addr}")
logging.error(f"could not write password for: {self.addr}") raise
raise self.enforce_E2EE_path.touch()
if not self.addr.startswith("echo@"):
self.enforce_E2EE_path.touch()
def set_last_login_timestamp(self, timestamp): def set_last_login_timestamp(self, timestamp):
"""Track login time with daily granularity """Track login time with daily granularity

View File

@@ -61,6 +61,19 @@ class AcmetoolDeployer(Deployer):
mode="644", mode="644",
) )
server.shell(
name=f"Remove old acmetool desired files for {self.domains[0]}",
commands=[f"rm -f /var/lib/acme/desired/{self.domains[0]}-*"],
)
files.template(
src=importlib.resources.files(__package__).joinpath("desired.yaml.j2"),
dest=f"/var/lib/acme/desired/{self.domains[0]}", # 0 is mailhost TLD
user="root",
group="root",
mode="644",
domains=self.domains,
)
service_file = files.put( service_file = files.put(
src=importlib.resources.files(__package__).joinpath( src=importlib.resources.files(__package__).joinpath(
"acmetool-redirector.service" "acmetool-redirector.service"
@@ -123,6 +136,6 @@ class AcmetoolDeployer(Deployer):
self.need_restart_reconcile_timer = False self.need_restart_reconcile_timer = False
server.shell( server.shell(
name=f"Request certificate for: {', '.join(self.domains)}", name=f"Reconcile certificates for: {', '.join(self.domains)}",
commands=[f"acmetool want --xlog.severity=debug {' '.join(self.domains)}"], commands=["acmetool --batch --xlog.severity=debug reconcile"],
) )

View File

@@ -0,0 +1,6 @@
satisfy:
names:
{%- for domain in domains %}
- {{ domain }}
{%- endfor %}

View File

@@ -440,7 +440,6 @@ class ChatmailVenvDeployer(Deployer):
class ChatmailDeployer(Deployer): class ChatmailDeployer(Deployer):
required_users = [ required_users = [
("vmail", "vmail", None), ("vmail", "vmail", None),
("echobot", None, None),
("iroh", None, None), ("iroh", None, None),
] ]

View File

@@ -10,6 +10,7 @@ if nsigs == nil then
end end
local valid = false local valid = false
local error_msg = "No valid DKIM signature found."
for i = 1, nsigs do for i = 1, nsigs do
sig = odkim.get_sighandle(ctx, i - 1) sig = odkim.get_sighandle(ctx, i - 1)
sigres = odkim.sig_result(sig) sigres = odkim.sig_result(sig)
@@ -21,6 +22,8 @@ for i = 1, nsigs do
-- means the message is acceptable. -- means the message is acceptable.
if sigres == 0 then if sigres == 0 then
valid = true valid = true
else
error_msg = "DKIM signature is invalid, error code " .. tostring(sigres) .. ", search https://github.com/trusteddomainproject/OpenDKIM/blob/master/libopendkim/dkim.h#L108"
end end
end end
@@ -31,7 +34,7 @@ if valid then
odkim.del_header(ctx, "DKIM-Signature", i) odkim.del_header(ctx, "DKIM-Signature", i)
end end
else else
odkim.set_reply(ctx, "554", "5.7.1", "No valid DKIM signature found") odkim.set_reply(ctx, "554", "5.7.1", error_msg)
odkim.set_result(ctx, SMFIS_REJECT) odkim.set_result(ctx, SMFIS_REJECT)
end end

View File

@@ -6,7 +6,7 @@ You can use the `make` command and `make html` to build web pages.
You need a Python environment where the following install was excuted: You need a Python environment where the following install was excuted:
pip install sphinx-build furo sphinx-autobuild pip install furo sphinx-autobuild
To develop/change documentation, you can then do: To develop/change documentation, you can then do:

View File

@@ -7,7 +7,7 @@ Active development takes place in the `chatmail/relay github repository <https:/
You can check out the `'chatmail' tag in the support.delta.chat forum <https://support.delta.chat/tag/chatmail>`_ You can check out the `'chatmail' tag in the support.delta.chat forum <https://support.delta.chat/tag/chatmail>`_
and ask to get added to a non-public support chat for debugging issues. and ask to get added to a non-public support chat for debugging issues.
We know of two work-in-progress alternative implementation efforts: We know of three work-in-progress alternative implementation efforts:
- `Mox <https://github.com/mjl-/mox>`_: A Golang email server. `Work - `Mox <https://github.com/mjl-/mox>`_: A Golang email server. `Work
is in progress <https://github.com/mjl-/mox/issues/251>`_ to modify is in progress <https://github.com/mjl-/mox/issues/251>`_ to modify
@@ -18,3 +18,10 @@ We know of two work-in-progress alternative implementation efforts:
plugin for the `Maddy email server <https://maddy.email/>`_ which plugin for the `Maddy email server <https://maddy.email/>`_ which
aims to implement the chatmail relay features and configuration aims to implement the chatmail relay features and configuration
options. options.
- `Chatmail Cookbook <https://github.com/feld/chatmail-cookbook>`_:
A Chef Cookbook implementing a relay server. The project follows the
official relay server software and configurations converted to a Chef
Cookbook with only minor differences. The cookbook uses DNS-01 for
certificate validation and additionally supports FreeBSD. It does not
require a Chef server to use.

View File

@@ -23,7 +23,3 @@ you can also **scan this QR code** with Delta Chat:
🐣 **Choose** your Avatar and Name 🐣 **Choose** your Avatar and Name
💬 **Start** chatting with any Delta Chat contacts using [QR invite codes](https://delta.chat/en/help#howtoe2ee) 💬 **Start** chatting with any Delta Chat contacts using [QR invite codes](https://delta.chat/en/help#howtoe2ee)
{% if config.mail_domain != "nine.testrun.org" %}
<div class="experimental">Note: this is only a temporary development chatmail service</div>
{% endif %}