Compare commits

..

1 Commits

Author SHA1 Message Date
link2xt
32fa1d6cb8 acmetool: Increase RSA key size from 2048 to 4096 2025-10-22 21:07:51 +00:00
14 changed files with 37 additions and 72 deletions

View File

@@ -1 +1,5 @@
blank_issues_enabled: true blank_issues_enabled: true
contact_links:
- name: Mutual Help Chat Group
url: https://i.delta.chat/#6CBFF8FFD505C0FDEA20A66674F2916EA8FBEE99&a=invitebot%40nine.testrun.org&g=Chatmail%20Mutual%20Help&x=7sFF7Ik50pWv6J1z7RVC5527&i=X69wTFfvCfs3d-JzqP0kVA3i&s=ibp-447dU-wUq-52QanwAtWc
about: If you have troubles setting up the relay server, feel free to ask here.

View File

@@ -2,15 +2,9 @@
## untagged ## untagged
- acmetool: use ECDSA keys instead of RSA
([#689](https://github.com/chatmail/relay/pull/689))
- Require TLS 1.2 for outgoing SMTP connections - Require TLS 1.2 for outgoing SMTP connections
([#685](https://github.com/chatmail/relay/pull/685)) ([#685](https://github.com/chatmail/relay/pull/685))
- require STARTTLS for incoming port 25 connections
([#684](https://github.com/chatmail/relay/pull/684))
- filtermail: run CPU-intensive handle_DATA in a thread pool executor - filtermail: run CPU-intensive handle_DATA in a thread pool executor
([#676](https://github.com/chatmail/relay/pull/676)) ([#676](https://github.com/chatmail/relay/pull/676))
@@ -30,7 +24,7 @@
([#650](https://github.com/chatmail/relay/pull/650)) ([#650](https://github.com/chatmail/relay/pull/650))
- filtermail: accept mails from Protonmail - filtermail: accept mails from Protonmail
([#616](https://github.com/chatmail/relay/pull/616)) ([#616](https://github.com/chatmail/relay/pull/655))
- Ignore all RCPT TO: parameters - Ignore all RCPT TO: parameters
([#651](https://github.com/chatmail/relay/pull/651)) ([#651](https://github.com/chatmail/relay/pull/651))
@@ -63,7 +57,7 @@
to only do a single iteration over sometimes millions of messages to only do a single iteration over sometimes millions of messages
instead of doing "find" commands that iterate 9 times over the messages. instead of doing "find" commands that iterate 9 times over the messages.
Provide an "fsreport" CLI for more fine grained analysis of message files. Provide an "fsreport" CLI for more fine grained analysis of message files.
([#637](https://github.com/chatmail/relay/pull/637)) ([#637](https://github.com/chatmail/relay/pull/632))
## 1.7.0 2025-09-11 ## 1.7.0 2025-09-11

View File

@@ -180,10 +180,6 @@ The components of chatmail are:
- [Iroh relay](https://www.iroh.computer/docs/concepts/relay) - [Iroh relay](https://www.iroh.computer/docs/concepts/relay)
which helps client devices to establish Peer-to-Peer connections which helps client devices to establish Peer-to-Peer connections
- [TURN](https://github.com/chatmail/chatmail-turn)
to enable relay users to start webRTC calls
even if a p2p connection can't be established
- and the chatmaild services, explained in the next section: - and the chatmaild services, explained in the next section:
### chatmaild ### chatmaild
@@ -308,8 +304,6 @@ Chatmail address creation will be denied while this file is present.
[Nginx](https://www.nginx.com/) listens on port 8443 (HTTPS-ALT) and 443 (HTTPS). [Nginx](https://www.nginx.com/) listens on port 8443 (HTTPS-ALT) and 443 (HTTPS).
Port 443 multiplexes HTTPS, IMAP and SMTP using ALPN to redirect connections to ports 8443, 465 or 993. Port 443 multiplexes HTTPS, IMAP and SMTP using ALPN to redirect connections to ports 8443, 465 or 993.
[acmetool](https://hlandau.github.io/acmetool/) listens on port 80 (HTTP). [acmetool](https://hlandau.github.io/acmetool/) listens on port 80 (HTTP).
[chatmail-turn](https://github.com/chatmail/chatmail-turn) listens on UDP port 3478 (STUN/TURN),
and temporarily opens UDP ports when users request them. UDP port range is not restricted, any free port may be allocated.
chatmail-core based apps will, however, discover all ports and configurations chatmail-core based apps will, however, discover all ports and configurations
automatically by reading the [autoconfig XML file](https://www.ietf.org/archive/id/draft-bucksch-autoconfig-00.html) from the chatmail relay server. automatically by reading the [autoconfig XML file](https://www.ietf.org/archive/id/draft-bucksch-autoconfig-00.html) from the chatmail relay server.

View File

@@ -6,4 +6,4 @@ def turn_credentials() -> str:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client_socket: with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client_socket:
client_socket.connect("/run/chatmail-turn/turn.socket") client_socket.connect("/run/chatmail-turn/turn.socket")
with client_socket.makefile("rb") as file: with client_socket.makefile("rb") as file:
return file.readline().decode("utf-8").strip() return file.readline().decode("utf-8")

View File

@@ -338,9 +338,9 @@ def _install_dovecot_package(package: str, arch: str):
match (package, arch): match (package, arch):
case ("core", "amd64"): case ("core", "amd64"):
sha256 = "dd060706f52a306fa863d874717210b9fe10536c824afe1790eec247ded5b27d" sha256 = "43f593332e22ac7701c62d58b575d2ca409e0f64857a2803be886c22860f5587"
case ("core", "arm64"): case ("core", "arm64"):
sha256 = "e7548e8a82929722e973629ecc40fcfa886894cef3db88f23535149e7f730dc9" sha256 = "4d21eba1a83f51c100f08f2e49f0c9f8f52f721ebc34f75018e043306da993a7"
case ("imapd", "amd64"): case ("imapd", "amd64"):
sha256 = "8d8dc6fc00bbb6cdb25d345844f41ce2f1c53f764b79a838eb2a03103eebfa86" sha256 = "8d8dc6fc00bbb6cdb25d345844f41ce2f1c53f764b79a838eb2a03103eebfa86"
case ("imapd", "arm64"): case ("imapd", "arm64"):
@@ -681,7 +681,7 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
check_config(config) check_config(config)
mail_domain = config.mail_domain mail_domain = config.mail_domain
from .www import build_webpages, find_merge_conflict, get_paths from .www import build_webpages, get_paths
server.group(name="Create vmail group", group="vmail", system=True) server.group(name="Create vmail group", group="vmail", system=True)
server.user(name="Create vmail user", user="vmail", group="vmail", system=True) server.user(name="Create vmail user", user="vmail", group="vmail", system=True)
@@ -823,8 +823,6 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
# if www_folder was set to a non-existing folder, skip upload # if www_folder was set to a non-existing folder, skip upload
if not www_path.is_dir(): if not www_path.is_dir():
logger.warning("Building web pages is disabled in chatmail.ini, skipping") logger.warning("Building web pages is disabled in chatmail.ini, skipping")
elif (path := find_merge_conflict(src_dir)) is not None:
logger.warning(f"Merge conflict found in {path}, skipping")
else: else:
# if www_folder is a hugo page, build it # if www_folder is a hugo page, build it
if build_dir: if build_dir:

View File

@@ -1,8 +1,8 @@
request: request:
provider: https://acme-v02.api.letsencrypt.org/directory provider: https://acme-v02.api.letsencrypt.org/directory
key: key:
type: ecdsa type: rsa
ecdsa-curve: nistp256 rsa-size: 4096
challenge: challenge:
webroot-paths: webroot-paths:
- /var/www/html/.well-known/acme-challenge - /var/www/html/.well-known/acme-challenge

View File

@@ -70,12 +70,6 @@ userdb {
# Mailboxes are stored in the "mail" directory of the vmail user home. # Mailboxes are stored in the "mail" directory of the vmail user home.
mail_location = maildir:{{ config.mailboxes_dir }}/%u mail_location = maildir:{{ config.mailboxes_dir }}/%u
# index/cache files are not very useful for chatmail relay operations
# but it's not clear how to disable them completely.
# According to https://doc.dovecot.org/2.3/settings/advanced/#core_setting-mail_cache_max_size
# if the cache file becomes larger than the specified size, it is truncated by dovecot
mail_cache_max_size = 500K
namespace inbox { namespace inbox {
inbox = yes inbox = yes

View File

@@ -14,7 +14,6 @@ smtp inet n - y - - smtpd -v
{%- else %} {%- else %}
smtp inet n - y - - smtpd smtp inet n - y - - smtpd
{%- endif %} {%- endif %}
-o smtpd_tls_security_level=encrypt
-o smtpd_proxy_filter=127.0.0.1:{{ config.filtermail_smtp_port_incoming }} -o smtpd_proxy_filter=127.0.0.1:{{ config.filtermail_smtp_port_incoming }}
submission inet n - y - 5000 smtpd submission inet n - y - 5000 smtpd
-o syslog_name=postfix/submission -o syslog_name=postfix/submission

View File

@@ -37,7 +37,7 @@ class TestDC:
def test_ping_pong(self, benchmark, cmfactory): def test_ping_pong(self, benchmark, cmfactory):
ac1, ac2 = cmfactory.get_online_accounts(2) ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2) chat = cmfactory.get_protected_chat(ac1, ac2)
def dc_ping_pong(): def dc_ping_pong():
chat.send_text("ping") chat.send_text("ping")
@@ -49,7 +49,7 @@ class TestDC:
def test_send_10_receive_10(self, benchmark, cmfactory, lp): def test_send_10_receive_10(self, benchmark, cmfactory, lp):
ac1, ac2 = cmfactory.get_online_accounts(2) ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2) chat = cmfactory.get_protected_chat(ac1, ac2)
def dc_send_10_receive_10(): def dc_send_10_receive_10():
for i in range(10): for i in range(10):

View File

@@ -1,5 +1,5 @@
import queue import queue
import smtplib import socket
import threading import threading
import pytest import pytest
@@ -91,23 +91,25 @@ def test_concurrent_logins_same_account(
def test_no_vrfy(chatmail_config): def test_no_vrfy(chatmail_config):
domain = chatmail_config.mail_domain domain = chatmail_config.mail_domain
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = smtplib.SMTP(domain) sock.settimeout(10)
s.starttls() try:
sock.connect((domain, 25))
s.putcmd("vrfy", f"wrongaddress@{chatmail_config.mail_domain}") except socket.timeout:
result = s.getreply() pytest.skip(f"port 25 not reachable for {domain}")
banner = sock.recv(1024)
print(banner)
sock.send(b"VRFY wrongaddress@%s\r\n" % (chatmail_config.mail_domain.encode(),))
result = sock.recv(1024)
print(result) print(result)
s.putcmd("vrfy", f"echo@{chatmail_config.mail_domain}") sock.send(b"VRFY echo@%s\r\n" % (chatmail_config.mail_domain.encode(),))
result2 = s.getreply() result2 = sock.recv(1024)
print(result2) print(result2)
assert result[0] == result2[0] == 252 assert result[0:10] == result2[0:10]
assert result[1][0:6] == result2[1][0:6] == b"2.0.0 " sock.send(b"VRFY wrongaddress\r\n")
s.putcmd("vrfy", "wrongaddress") result = sock.recv(1024)
result = s.getreply()
print(result) print(result)
s.putcmd("vrfy", "echo") sock.send(b"VRFY echo\r\n")
result2 = s.getreply() result2 = sock.recv(1024)
print(result2) print(result2)
assert result[0] == result2[0] == 252 assert result[0:10] == result2[0:10] == b"252 2.0.0 "
assert result[1][0:6] == result2[1][0:6] == b"2.0.0 "

View File

@@ -143,7 +143,6 @@ def test_reject_missing_dkim(cmsetup, maildata, from_addr):
"encrypted.eml", from_addr=from_addr, to_addr=recipient.addr "encrypted.eml", from_addr=from_addr, to_addr=recipient.addr
).as_string() ).as_string()
conn = smtplib.SMTP(cmsetup.maildomain, 25, timeout=10) conn = smtplib.SMTP(cmsetup.maildomain, 25, timeout=10)
conn.starttls()
with conn as s: with conn as s:
with pytest.raises(smtplib.SMTPDataError, match="No valid DKIM signature"): with pytest.raises(smtplib.SMTPDataError, match="No valid DKIM signature"):

View File

@@ -56,7 +56,7 @@ class TestEndToEndDeltaChat:
"""Test that a DC account can send a message to a second DC account """Test that a DC account can send a message to a second DC account
on the same chat-mail instance.""" on the same chat-mail instance."""
ac1, ac2 = cmfactory.get_online_accounts(2) ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2) chat = cmfactory.get_protected_chat(ac1, ac2)
chat.send_text("message0") chat.send_text("message0")
lp.sec("wait for ac2 to receive message") lp.sec("wait for ac2 to receive message")
@@ -70,7 +70,7 @@ class TestEndToEndDeltaChat:
before quota is exceeded, and thus depends on the speed of the upload. before quota is exceeded, and thus depends on the speed of the upload.
""" """
ac1, ac2 = cmfactory.get_online_accounts(2) ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2) chat = cmfactory.get_protected_chat(ac1, ac2)
user = ac2.get_config("configured_addr") user = ac2.get_config("configured_addr")
@@ -153,7 +153,7 @@ def test_hide_senders_ip_address(cmfactory):
assert ipaddress.ip_address(public_ip) assert ipaddress.ip_address(public_ip)
user1, user2 = cmfactory.get_online_accounts(2) user1, user2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(user1, user2) chat = cmfactory.get_protected_chat(user1, user2)
chat.send_text("testing submission header cleanup") chat.send_text("testing submission header cleanup")
user2._evtracker.wait_next_incoming_message() user2._evtracker.wait_next_incoming_message()

View File

@@ -4,7 +4,6 @@ import time
import traceback import traceback
import webbrowser import webbrowser
from pathlib import Path from pathlib import Path
import re
import markdown import markdown
from chatmaild.config import read_config from chatmaild.config import read_config
@@ -13,9 +12,6 @@ from jinja2 import Template
from .genqr import gen_qr_png_data from .genqr import gen_qr_png_data
_MERGE_CONFLICT_RE = re.compile(r"^<<<<<<<.+^=======.+^>>>>>>>", re.DOTALL | re.MULTILINE)
def snapshot_dir_stats(somedir): def snapshot_dir_stats(somedir):
d = {} d = {}
for path in somedir.iterdir(): for path in somedir.iterdir():
@@ -120,17 +116,6 @@ def _build_webpages(src_dir, build_dir, config):
return build_dir return build_dir
def find_merge_conflict(src_dir) -> Path:
assert src_dir.exists(), src_dir
result = None
for path in src_dir.iterdir():
if path.suffix in [".css", ".html", ".md"]:
if _MERGE_CONFLICT_RE.search(path.read_text()):
result = path
break
return result
def main(): def main():
path = importlib.resources.files(__package__) path = importlib.resources.files(__package__)
reporoot = path.joinpath("../../../").resolve() reporoot = path.joinpath("../../../").resolve()

View File

@@ -9,11 +9,7 @@
<title>{{ config.mail_domain }} {{ pagename }}</title> <title>{{ config.mail_domain }} {{ pagename }}</title>
<link rel="stylesheet" href="./main.css"> <link rel="stylesheet" href="./main.css">
<link rel="icon" href="/logo.svg"> <link rel="icon" href="/logo.svg">
<<<<<<< HEAD <link rel=”mask-icon” href=”/logo.svg” color=”#000000">
<link rel="mask-icon" href="/logo.svg" color="#000000">
=======
<link rel=”mask-icon” href=”/logo.svg” color=”#000001">
>>>>>>> 2da7de8 (make logo slightly brighter)
</head> </head>
<body> <body>