Compare commits

...

9 Commits
1.10.0 ... cgi

Author SHA1 Message Date
holger krekel
aa3f12b2a0 mention QRcode in readme and modify nine.testrun.org index page to include it 2023-12-05 14:21:10 +01:00
holger krekel
1be1580454 revert unneccessary reformatting and unused file 2023-12-05 14:21:10 +01:00
holger krekel
bf8b69ae68 put index.html into www/ dir, as it's not config 2023-12-05 14:21:10 +01:00
holger krekel
4708533a0d streamline text to be less redundant 2023-12-05 14:21:10 +01:00
holger krekel
466e92ab37 Update deploy-chatmail/src/deploy_chatmail/nginx/index.html.j2
Co-authored-by: missytake <missytake@systemli.org>

use example config as recommended by fcgiwrap/README.debian
2023-12-05 14:21:10 +01:00
holger krekel
0f15a9d095 add origin of genqr code 2023-12-05 14:21:10 +01:00
holger krekel
9ef53806d5 streamline index.html 2023-12-05 14:21:10 +01:00
holger krekel
ab2cc5a687 make QR code clickable, verified it works on android and desktop 2023-12-05 14:21:10 +01:00
holger krekel
b8cf5da37f works 2023-12-05 14:21:05 +01:00
12 changed files with 249 additions and 14 deletions

View File

@@ -32,10 +32,17 @@ after which the initially specified password is required for using them.
5. Run `scripts/generate-dns-zone.sh` and
transfer the generated DNS records at your DNS provider
6. Start a Delta Chat app and create a new account
by typing an e-mail address with an arbitrary username
and `@<your-chatmail-domain>` appended.
Use an at least 10-character random password.
### Home page and getting started for users
- The `deploy.sh` script deploys a default `index.html`
along with a QR code that users can click to
create accounts on the chatmail provider.
- Start a Delta Chat app and create a new account
by typing an e-mail address with an arbitrary username
and `@<your-chatmail-domain>` appended.
Use an at least 10-character random password.
### Ports

View File

@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "chatmaild"
version = "0.1"
dependencies = [
"aiosmtpd"
"aiosmtpd",
]
[project.scripts]

View File

@@ -0,0 +1,28 @@
#!/usr/bin/python3
""" CGI script for creating new accounts. """
import json
import random
mailname_path = "/etc/mailname"
def create_newemail_dict(domain):
alphanumeric = "abcdefghijklmnopqrstuvwxyz1234567890"
user = "".join(random.choices(alphanumeric, k=9))
password = "".join(random.choices(alphanumeric, k=12))
return dict(email=f"{user}@{domain}", password=f"{password}")
def print_new_account():
domain = open(mailname_path).read().strip()
creds = create_newemail_dict(domain=domain)
print("Content-Type: application/json")
print("")
print(json.dumps(creds))
if __name__ == "__main__":
print_new_account()

View File

@@ -7,6 +7,7 @@ name = "deploy-chatmail"
version = "0.1"
dependencies = [
"pyinfra",
"qrcode",
]
[tool.pytest.ini_options]

View File

@@ -10,6 +10,8 @@ from pyinfra.facts.files import File
from pyinfra.facts.systemd import SystemdEnabled
from .acmetool import deploy_acmetool
from .genqr import gen_qr_png_data
def _install_chatmaild() -> None:
chatmaild_filename = "chatmaild-0.1.tar.gz"
@@ -44,6 +46,8 @@ def _install_chatmaild() -> None:
enabled=False,
)
# install systemd units
for fn in (
"doveauth",
"filtermail",
@@ -279,6 +283,36 @@ def _configure_nginx(domain: str, debug: bool = False) -> bool:
)
need_restart |= mta_sts_config.changed
# install CGI newemail script
#
cgi_dir = "/usr/lib/cgi-bin"
files.directory(
name=f"Ensure {cgi_dir} exists",
path=cgi_dir,
user="root",
group="root",
)
files.put(
name="Upload cgi newemail.py script",
src=importlib.resources.files("chatmaild").joinpath("newemail.py").open("rb"),
dest=f"{cgi_dir}/newemail.py",
user="root",
group="root",
mode="755",
)
qr_data = gen_qr_png_data(domain)
files.put(
name="Upload QR code for account creation",
src=qr_data,
dest="/var/www/html/qrcode.png",
user="root",
group="root",
mode="644",
)
return need_restart
@@ -328,19 +362,34 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
packages=["nginx"],
)
apt.packages(
name="Install fcgiwrap",
packages=["fcgiwrap"],
)
_install_chatmaild()
debug = False
dovecot_need_restart = _configure_dovecot(mail_server, debug=debug)
postfix_need_restart = _configure_postfix(mail_domain, debug=debug)
opendkim_need_restart = _configure_opendkim(mail_domain, dkim_selector)
nginx_need_restart = _configure_nginx(mail_domain)
mta_sts_need_restart = _install_mta_sts_daemon()
nginx_need_restart = _configure_nginx(mail_domain)
# deploy web pages and info if we have them
pkg_root = importlib.resources.files(__package__)
www_path = pkg_root.joinpath(f"../../../www/{mail_domain}").resolve()
if www_path.is_dir():
files.rsync(f"{www_path}/", "/var/www/html", flags=["-avz"])
else:
index_path = www_path.parent.joinpath("default/index.html.j2")
files.template(
src=index_path,
dest="/var/www/html/index.html",
user="root",
group="root",
mode="644",
config={"mail_domain": mail_domain},
)
systemd.service(
name="Start and enable OpenDKIM",

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,82 @@
import importlib
import qrcode
import os
from PIL import ImageFont, ImageDraw, Image
import io
def gen_qr_png_data(maildomain):
url = f"DCACCOUNT:https://{maildomain}/cgi-bin/newemail.py"
image = gen_qr(maildomain, url)
temp = io.BytesIO()
image.save(temp, format="png")
temp.seek(0)
return temp
def gen_qr(maildomain, url):
# taken and modified from
# https://github.com/deltachat/mailadm/blob/master/src/mailadm/gen_qr.py
info = f"{maildomain} invite code"
# load QR code
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=1,
border=1,
)
qr.add_data(url)
qr.make(fit=True)
qr_img = qr.make_image(fill_color="black", back_color="white")
# paint all elements
ttf_path = str(
importlib.resources.files(__package__).joinpath("data/opensans-regular.ttf")
)
logo_red_path = str(
importlib.resources.files(__package__).joinpath("data/delta-chat-bw.png")
)
assert os.path.exists(ttf_path), ttf_path
font_size = 16
font = ImageFont.truetype(font=ttf_path, size=font_size)
num_lines = (info).count("\n") + 1
size = width = 384
qr_padding = 6
text_height = font_size * num_lines
height = size + text_height + qr_padding * 2
image = Image.new("RGBA", (width, height), "white")
draw = ImageDraw.Draw(image)
qr_final_size = width - (qr_padding * 2)
# draw text
if hasattr(font, "getsize"):
info_pos = (width - font.getsize(info.strip())[0]) // 2
else:
info_pos = (width - font.getbbox(info.strip())[3]) // 2
draw.multiline_text(
(info_pos, size - qr_padding // 2), info, font=font, fill="black", align="right"
)
# paste QR code
image.paste(
qr_img.resize((qr_final_size, qr_final_size), resample=Image.NEAREST),
(qr_padding, qr_padding),
)
# background delta logo
logo2_img = Image.open(logo_red_path)
logo2_width = int(size / 6)
logo2 = logo2_img.resize((logo2_width, logo2_width), resample=Image.NEAREST)
pos = int((size / 2) - (logo2_width / 2))
image.paste(logo2, (pos, pos), mask=logo2)
return image

View File

@@ -40,6 +40,9 @@ http {
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# add cgi-bin support
include /usr/share/doc/fcgiwrap/examples/nginx.conf;
}
server {
listen 80 default_server;

View File

@@ -0,0 +1,28 @@
import json
import chatmaild
from chatmaild.newemail import create_newemail_dict, print_new_account
def test_create_newemail_dict():
ac1 = create_newemail_dict(domain="example.org")
assert "@" in ac1["email"]
assert len(ac1["password"]) >= 10
ac2 = create_newemail_dict(domain="example.org")
assert ac1["email"] != ac2["email"]
assert ac1["password"] != ac2["password"]
def test_print_new_account(capsys, monkeypatch, maildomain, tmpdir):
p = tmpdir.join("mailname")
p.write(maildomain)
monkeypatch.setattr(chatmaild.newemail, "mailname_path", str(p))
print_new_account()
out, err = capsys.readouterr()
lines = out.split("\n")
assert lines[0] == "Content-Type: application/json"
assert not lines[1]
dic = json.loads(lines[2])
assert dic["email"].endswith(f"@{maildomain}")
assert len(dic["password"]) >= 10

31
www/default/index.html.j2 Normal file
View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>chatmail instance</title>
</head>
<body>
<h1>Welcome to {{ config.mail_domain }}!</h1>
<h2>Getting started</h2>
<ol>
<li>Install <a href="https://get.delta.chat">https://get.delta.chat</a></li>
<li>Scan or Tap on the invite QR code</li>
<li>Choose Nickname and Avatar</li>
<li>Setup contact with others using <a href="https://delta.chat/en/help#howtoe2ee">
guaranteed end-to-end encryption via QR code scans</a>
</li>
</ol>
<a href="DCACCOUNT:https://{{ config.mail_domain }}/cgi-bin/newemail.py">
<img class="section" src="qrcode.png" />
</a>
<h2>Constraints</h2>
<ul>
<li>You can only send encrypted mails to anyone outside {{config.mail_domain }} </li>
<li>You may send up to 60 messages per minute</li>
<li>Messages are unconditionally removed 40 days after arrival</li>
<li>Max storage per user is 100MB</li>
</ul>
</body>
</html>

View File

@@ -38,16 +38,22 @@
<div class="section text">
<h1>Dear Delta Chat users and newcomers,</h1>
<p>
welcome to the first public "chat-mail instance",
a small and lean e-mail provider for smooth chatting.
Install Delta Chat or add an account:
welcome to the first public "chat-mail instance",
a small and lean e-mail provider for smooth chatting.
Install Delta Chat and then
Tap or scan this QR code to obtain a random e-mail address:
<a href="DCACCOUNT:https://nine.testrun.org/cgi-bin/newemail.py">
<img with=300 src="qrcode.png" /></a>
</p>
<p>
Alternatively, you can manually invent an e-mail address:
<ul>
<li>Tap "LOG INTO YOUR E-MAIL ACCOUNT".</li>
<li>Address: invent a word with <i>exactly</i> nine characters
and append @nine.testrun.org to it.</li>
<li>Password: invent at least 10 characters. The first login sets your password.</li>
<li>Tap "LOG INTO YOUR E-MAIL ACCOUNT".</li>
<li>Address: invent a word with <i>exactly</i> nine characters
and append @nine.testrun.org to it.</li>
<li>Password: invent at least 10 characters. The first login sets your password.</li>
</ul>
If the e-mail address is not yet taken, you'll get that account.
If the e-mail address is not yet taken, you'll get that account.
</p>
<p>
<img class="section" src="collage-down.png" />