Compare commits

..

7 Commits

Author SHA1 Message Date
holger krekel
9531d62f57 in webdev mode make page auto-refresh every 3 seconds 2023-12-08 14:31:03 +01:00
holger krekel
931305d454 avoid bailing out on jinja2 errors, and provide file-url for instant clickability 2023-12-08 14:02:51 +01:00
holger krekel
648174c226 don't depend on deltachat python package 2023-12-08 12:15:39 +01:00
holger krekel
2b5cdd143e add a note 2023-12-07 17:41:25 +01:00
holger krekel
f506a62196 fix README 2023-12-07 17:39:03 +01:00
holger krekel
e8107c6854 rename script 2023-12-07 17:34:43 +01:00
holger krekel
858e079418 create a wwwdev.sh entry point for developing the web part 2023-12-07 17:34:43 +01:00
9 changed files with 68 additions and 126 deletions

View File

@@ -1,5 +1,5 @@
<img width="800px" src="www/src/collage-top.png"/>
<img width="800px" src="www/collage-top.png"/>
# Chatmail instances optimized for Delta Chat apps

View File

@@ -2,7 +2,7 @@
Description=Dict authentication proxy for dovecot
[Service]
ExecStart={execpath} /run/dovecot/doveauth.socket vmail /home/vmail/passdb.sqlite
ExecStart=/usr/local/bin/doveauth /run/dovecot/doveauth.socket vmail /home/vmail/passdb.sqlite
Restart=always
RestartSec=30

View File

@@ -34,14 +34,6 @@ def check_encrypted(message):
return True
def is_passthrough_recipient(recipient):
"""Check whether a recipient is configured as passthrough."""
passthroughlist = ["privacy@testrun.org"]
if recipient in passthroughlist:
return True
return False
def check_mdn(message, envelope):
if len(envelope.rcpt_tos) != 1:
return False
@@ -126,9 +118,6 @@ def check_DATA(envelope):
if envelope.mail_from == recipient:
# Always allow sending emails to self.
continue
if is_passthrough_recipient(recipient):
# Always allow recipients marked as passthrough
continue
res = recipient.split("@")
if len(res) != 2:
return f"500 Invalid address <{recipient}>"

View File

@@ -2,7 +2,7 @@
Description=Chatmail Postfix BeforeQeue filter
[Service]
ExecStart={execpath} 10080
ExecStart=/usr/local/bin/filtermail 10080
Restart=always
RestartSec=30

View File

@@ -1,102 +1,75 @@
"""
Chat Mail pyinfra deploy.
"""
import sys
import importlib.resources
import subprocess
import shutil
import io
import configparser
from pathlib import Path
from pyinfra import host
from pyinfra.operations import apt, files, server, systemd, pip
from pyinfra.operations import apt, files, server, systemd
from pyinfra.facts.files import File
from pyinfra.facts.systemd import SystemdEnabled
from .acmetool import deploy_acmetool
def _build_chatmaild(dist_dir) -> None:
dist_dir = Path(dist_dir).resolve()
if dist_dir.exists():
shutil.rmtree(dist_dir)
dist_dir.mkdir()
subprocess.check_output(
[sys.executable, "-m", "build", "-n"]
+ ["--sdist", "chatmaild", "--outdir", str(dist_dir)]
def _install_chatmaild() -> None:
chatmaild_filename = "chatmaild-0.1.tar.gz"
chatmaild_path = importlib.resources.files(__package__).joinpath(
f"../../../dist/{chatmaild_filename}"
)
entries = list(dist_dir.iterdir())
assert len(entries) == 1
return entries[0]
def _install_remote_venv_with_chatmaild() -> None:
dist_file = _build_chatmaild(dist_dir=Path("chatmaild/dist"))
remote_base_dir = "/usr/local/lib/chatmaild"
remote_dist_file = f"{remote_base_dir}/dist/{dist_file.name}"
remote_venv_dir = f"{remote_base_dir}/venv"
root_owned = dict(user="root", group="root", mode="644")
apt.packages(
name="apt install python3-virtualenv",
packages=["python3-virtualenv"],
)
files.put(
name="Upload chatmaild source package",
src=dist_file.open("rb"),
dest=remote_dist_file,
create_remote_dir=True,
**root_owned,
)
pip.virtualenv(
name=f"chatmaild virtualenv {remote_venv_dir}",
path=remote_venv_dir,
always_copy=True,
)
server.shell(
name=f"forced pip-install {dist_file.name}",
commands=[
f"{remote_venv_dir}/bin/pip install --force-reinstall {remote_dist_file}"
],
)
# disable legacy doveauth-dictproxy.service
if host.get_fact(SystemdEnabled).get("doveauth-dictproxy.service"):
systemd.service(
name="Disable legacy doveauth-dictproxy.service",
service="doveauth-dictproxy.service",
running=False,
enabled=False,
)
# install systemd units
for fn in (
"doveauth",
"filtermail",
):
execpath = f"{remote_venv_dir}/bin/{fn}"
source_path = importlib.resources.files("chatmaild").joinpath(f"{fn}.service.f")
content = source_path.read_text().format(execpath=execpath).encode()
remote_path = f"/tmp/{chatmaild_filename}"
if Path(str(chatmaild_path)).exists():
files.put(
name=f"Upload {fn}.service",
src=io.BytesIO(content),
dest=f"/etc/systemd/system/{fn}.service",
**root_owned,
name="Upload chatmaild source package",
src=chatmaild_path.open("rb"),
dest=remote_path,
)
systemd.service(
name=f"Setup {fn} service",
service=f"{fn}.service",
running=True,
enabled=True,
restarted=True,
daemon_reload=True,
apt.packages(
name="apt install python3-aiosmtpd python3-pip python3-venv",
packages=["python3-aiosmtpd", "python3-pip", "python3-venv"],
)
# --no-deps because aiosmtplib is installed with `apt`.
server.shell(
name="install chatmaild with pip",
commands=[f"pip install --break-system-packages {remote_path}"],
)
# disable legacy doveauth-dictproxy.service
if host.get_fact(SystemdEnabled).get("doveauth-dictproxy.service"):
systemd.service(
name="Disable legacy doveauth-dictproxy.service",
service="doveauth-dictproxy.service",
running=False,
enabled=False,
)
# install systemd units
for fn in (
"doveauth",
"filtermail",
):
files.put(
name=f"Upload {fn}.service",
src=importlib.resources.files("chatmaild")
.joinpath(f"{fn}.service")
.open("rb"),
dest=f"/etc/systemd/system/{fn}.service",
user="root",
group="root",
mode="644",
)
systemd.service(
name=f"Setup {fn} service",
service=f"{fn}.service",
running=True,
enabled=True,
restarted=True,
daemon_reload=True,
)
def _configure_opendkim(domain: str, dkim_selector: str) -> bool:
"""Configures OpenDKIM"""
@@ -408,7 +381,7 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
build_webpages(src_dir, build_dir, config)
files.rsync(f"{build_dir}/", "/var/www/html", flags=["-avz"])
_install_remote_venv_with_chatmaild()
_install_chatmaild()
debug = False
dovecot_need_restart = _configure_dovecot(mail_server, debug=debug)
postfix_need_restart = _configure_postfix(mail_domain, debug=debug)

View File

@@ -52,7 +52,7 @@ def gen_qr(maildomain, url):
height = size + text_height
image = Image.new("RGBA", (width, height), "white")
qr_final_size = width - (qr_padding * 2)
qr_final_size = width
if num_lines:
draw = ImageDraw.Draw(image)

View File

@@ -4,5 +4,12 @@ echo -----------------------------------------
echo deploying to $CHATMAIL_DOMAIN
echo -----------------------------------------
echo WARNING: in five seconds deploy to $CHATMAIL_DOMAIN starts
sleep 5
venv/bin/python3 -m build -n --sdist chatmaild --outdir dist
venv/bin/pyinfra --ssh-user root "$CHATMAIL_DOMAIN" \
deploy-chatmail/src/deploy_chatmail/deploy.py
rm -r dist/

View File

@@ -1,4 +1,4 @@
from chatmaild.filtermail import check_encrypted, check_DATA, SendRateLimiter, check_mdn, is_passthrough_recipient
from chatmaild.filtermail import check_encrypted, check_DATA, SendRateLimiter, check_mdn
import pytest
@@ -80,28 +80,3 @@ def test_send_rate_limiter():
else:
assert i == SendRateLimiter.MAX_USER_SEND_PER_MINUTE + 1
break
def test_excempt_privacy(maildata, gencreds):
from_addr = gencreds()[0]
to_addr = "privacy@testrun.org"
false_to = "privacy@tstrn.org"
false_to2 = "prvcy@testrun.org"
assert is_passthrough_recipient(to_addr)
msg = maildata("plain.eml", from_addr, to_addr)
class env:
mail_from = from_addr
rcpt_tos = [to_addr]
content = msg.as_bytes()
# assert that None/no error is returned
assert not check_DATA(envelope=env)
class env2:
mail_from = from_addr
rcpt_tos = [to_addr, false_to, false_to2]
content = msg.as_bytes()
assert "500" in check_DATA(envelope=env2)

View File

@@ -283,10 +283,8 @@ def cmfactory(request, gencreds, tmpdir, maildomain):
pytest.importorskip("deltachat")
from deltachat.testplugin import ACFactory
data = request.getfixturevalue("data")
testproc = ChatmailTestProcess(request.config, maildomain, gencreds)
am = ACFactory(request=request, tmpdir=tmpdir, testprocess=testproc, data=data)
am = ACFactory(request=request, tmpdir=tmpdir, testprocess=testproc, data=None)
# nb. a bit hacky
# would probably be better if deltachat's test machinery grows native support