mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 08:24:37 +00:00
Compare commits
7 Commits
privacy-de
...
hagi/insta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
345d3f9b35 | ||
|
|
2b5b06316d | ||
|
|
76b56d7b78 | ||
|
|
c1163228f6 | ||
|
|
8af825d7ea | ||
|
|
0a968aae93 | ||
|
|
879cffc056 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -2,8 +2,14 @@
|
||||
|
||||
## untagged
|
||||
|
||||
- Added a config option for an intro to the privacy policy
|
||||
([#285](https://github.com/deltachat/chatmail/pull/285))
|
||||
- fix writing of multiple obs repositories in `/etc/apt/sources.list`
|
||||
([#272](https://github.com/deltachat/chatmail/issues/272))
|
||||
|
||||
- metadata: add support for `/shared/vendor/deltachat/irohrelay`
|
||||
([#284](https://github.com/deltachat/chatmail/pull/284))
|
||||
|
||||
- Emit "XCHATMAIL" capability from IMAP server
|
||||
([#278](https://github.com/deltachat/chatmail/pull/278))
|
||||
|
||||
- Move echobot `into /var/lib/echobot`
|
||||
([#281](https://github.com/deltachat/chatmail/pull/281))
|
||||
|
||||
@@ -36,6 +36,16 @@ log_format = "%(asctime)s %(levelname)s %(message)s"
|
||||
log_date_format = "%Y-%m-%d %H:%M:%S"
|
||||
log_level = "INFO"
|
||||
|
||||
[tool.ruff]
|
||||
lint.select = [
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
|
||||
"PLC", # Pylint Convention
|
||||
"PLE", # Pylint Error
|
||||
"PLW", # Pylint Warning
|
||||
]
|
||||
|
||||
[tool.tox]
|
||||
legacy_tox_ini = """
|
||||
[tox]
|
||||
@@ -47,10 +57,9 @@ skipdist = True
|
||||
skip_install = True
|
||||
deps =
|
||||
ruff
|
||||
black
|
||||
commands =
|
||||
black --quiet --check --diff src/
|
||||
ruff src/
|
||||
ruff format --quiet --diff src/
|
||||
ruff check src/
|
||||
|
||||
[testenv]
|
||||
deps = pytest
|
||||
|
||||
@@ -20,11 +20,11 @@ class Config:
|
||||
self.passthrough_recipients = params["passthrough_recipients"].split()
|
||||
self.filtermail_smtp_port = int(params["filtermail_smtp_port"])
|
||||
self.postfix_reinject_port = int(params["postfix_reinject_port"])
|
||||
self.iroh_relay = params.get("iroh_relay")
|
||||
self.privacy_postal = params.get("privacy_postal")
|
||||
self.privacy_mail = params.get("privacy_mail")
|
||||
self.privacy_pdo = params.get("privacy_pdo")
|
||||
self.privacy_supervisor = params.get("privacy_supervisor")
|
||||
self.privacy_intro = params.get("privacy_intro")
|
||||
|
||||
def _getbytefile(self):
|
||||
return open(self._inipath, "rb")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import sqlite3
|
||||
import contextlib
|
||||
import sqlite3
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import crypt
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
import json
|
||||
import crypt
|
||||
import time
|
||||
from pathlib import Path
|
||||
from socketserver import (
|
||||
UnixStreamServer,
|
||||
StreamRequestHandler,
|
||||
ThreadingMixIn,
|
||||
UnixStreamServer,
|
||||
)
|
||||
|
||||
from .config import Config, read_config
|
||||
from .database import Database
|
||||
from .config import read_config, Config
|
||||
|
||||
NOCREATE_FILE = "/etc/chatmail-nocreate"
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ it will echo back any message that has non-empty text and also supports the /hel
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from deltachat_rpc_client import Bot, DeltaChat, EventType, Rpc, events
|
||||
from pathlib import Path
|
||||
|
||||
from chatmaild.config import read_config
|
||||
from chatmaild.newemail import create_newemail_dict
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
import filelock
|
||||
import logging
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
|
||||
import filelock
|
||||
|
||||
|
||||
class FileDict:
|
||||
"""Concurrency-safe multi-reader/single-writer persistent dict."""
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
import sys
|
||||
from email.parser import BytesParser
|
||||
import time
|
||||
from email import policy
|
||||
from email.parser import BytesParser
|
||||
from email.utils import parseaddr
|
||||
from smtplib import SMTP as SMTPClient
|
||||
|
||||
from aiosmtpd.controller import Controller
|
||||
from smtplib import SMTP as SMTPClient
|
||||
|
||||
from .config import read_config
|
||||
|
||||
|
||||
@@ -61,4 +61,3 @@ privacy_pdo =
|
||||
# postal address of the privacy supervisor
|
||||
privacy_supervisor =
|
||||
|
||||
privacy_intro =
|
||||
|
||||
@@ -14,7 +14,3 @@ privacy_pdo =
|
||||
privacy_supervisor =
|
||||
State Commissioner for Data Protection and Freedom of Information of
|
||||
Baden-Württemberg in 70173 Stuttgart, Germany.
|
||||
privacy_intro =
|
||||
This is the default onboarding server for Delta Chat.
|
||||
If you don't choose to login to an existing email account,
|
||||
you can get one on this server.
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
from pathlib import Path
|
||||
from socketserver import (
|
||||
UnixStreamServer,
|
||||
StreamRequestHandler,
|
||||
ThreadingMixIn,
|
||||
)
|
||||
import sys
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from socketserver import (
|
||||
StreamRequestHandler,
|
||||
ThreadingMixIn,
|
||||
UnixStreamServer,
|
||||
)
|
||||
|
||||
from .config import read_config
|
||||
from .filedict import FileDict
|
||||
from .notifier import Notifier
|
||||
|
||||
|
||||
DICTPROXY_HELLO_CHAR = "H"
|
||||
DICTPROXY_LOOKUP_CHAR = "L"
|
||||
DICTPROXY_ITERATE_CHAR = "I"
|
||||
@@ -49,32 +49,40 @@ class Metadata:
|
||||
return mdict.get(self.DEVICETOKEN_KEY, [])
|
||||
|
||||
|
||||
def handle_dovecot_protocol(rfile, wfile, notifier, metadata):
|
||||
def handle_dovecot_protocol(rfile, wfile, notifier, metadata, iroh_relay=None):
|
||||
transactions = {}
|
||||
while True:
|
||||
msg = rfile.readline().strip().decode()
|
||||
if not msg:
|
||||
break
|
||||
|
||||
res = handle_dovecot_request(msg, transactions, notifier, metadata)
|
||||
res = handle_dovecot_request(msg, transactions, notifier, metadata, iroh_relay)
|
||||
if res:
|
||||
wfile.write(res.encode("ascii"))
|
||||
wfile.flush()
|
||||
|
||||
|
||||
def handle_dovecot_request(msg, transactions, notifier, metadata):
|
||||
def handle_dovecot_request(msg, transactions, notifier, metadata, iroh_relay=None):
|
||||
# see https://doc.dovecot.org/3.0/developer_manual/design/dict_protocol/
|
||||
short_command = msg[0]
|
||||
parts = msg[1:].split("\t")
|
||||
if short_command == DICTPROXY_LOOKUP_CHAR:
|
||||
# Lpriv/43f5f508a7ea0366dff30200c15250e3/devicetoken\tlkj123poi@c2.testrun.org
|
||||
keyparts = parts[0].split("/")
|
||||
keyparts = parts[0].split("/", 2)
|
||||
if keyparts[0] == "priv":
|
||||
keyname = keyparts[2]
|
||||
addr = parts[1]
|
||||
if keyname == metadata.DEVICETOKEN_KEY:
|
||||
res = " ".join(metadata.get_tokens_for_addr(addr))
|
||||
return f"O{res}\n"
|
||||
elif keyparts[0] == "shared":
|
||||
keyname = keyparts[2]
|
||||
if (
|
||||
keyname == "vendor/vendor.dovecot/pvt/server/vendor/deltachat/irohrelay"
|
||||
and iroh_relay
|
||||
):
|
||||
# Handle `GETMETADATA "" /shared/vendor/deltachat/irohrelay`
|
||||
return f"O{iroh_relay}\n"
|
||||
logging.warning("lookup ignored: %r", msg)
|
||||
return "N\n"
|
||||
elif short_command == DICTPROXY_ITERATE_CHAR:
|
||||
@@ -120,7 +128,10 @@ class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
|
||||
|
||||
|
||||
def main():
|
||||
socket, vmail_dir = sys.argv[1:]
|
||||
socket, vmail_dir, config_path = sys.argv[1:]
|
||||
|
||||
config = read_config(config_path)
|
||||
iroh_relay = config.iroh_relay
|
||||
|
||||
vmail_dir = Path(vmail_dir)
|
||||
if not vmail_dir.exists():
|
||||
@@ -136,7 +147,9 @@ def main():
|
||||
class Handler(StreamRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
handle_dovecot_protocol(self.rfile, self.wfile, notifier, metadata)
|
||||
handle_dovecot_protocol(
|
||||
self.rfile, self.wfile, notifier, metadata, iroh_relay
|
||||
)
|
||||
except Exception:
|
||||
logging.exception("Exception in the dovecot dictproxy handler")
|
||||
raise
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import time
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main(vmail_dir=None):
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/usr/local/lib/chatmaild/venv/bin/python3
|
||||
|
||||
""" CGI script for creating new accounts. """
|
||||
"""CGI script for creating new accounts."""
|
||||
|
||||
import json
|
||||
import random
|
||||
import secrets
|
||||
import string
|
||||
|
||||
from chatmaild.config import read_config, Config
|
||||
from chatmaild.config import Config, read_config
|
||||
|
||||
CONFIG_PATH = "/usr/local/lib/chatmaild/chatmail.ini"
|
||||
ALPHANUMERIC = string.ascii_lowercase + string.digits
|
||||
|
||||
@@ -25,15 +25,16 @@ The meaning and format of tokens is basically a matter of Delta-Chat Core and
|
||||
the `notification.delta.chat` service.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
import math
|
||||
import logging
|
||||
from uuid import uuid4
|
||||
from threading import Thread
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from queue import PriorityQueue
|
||||
from dataclasses import dataclass
|
||||
from threading import Thread
|
||||
from uuid import uuid4
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import random
|
||||
from pathlib import Path
|
||||
import os
|
||||
import importlib.resources
|
||||
import itertools
|
||||
from email.parser import BytesParser
|
||||
import os
|
||||
import random
|
||||
from email import policy
|
||||
import pytest
|
||||
from email.parser import BytesParser
|
||||
from pathlib import Path
|
||||
|
||||
from chatmaild.database import Database
|
||||
import pytest
|
||||
from chatmaild.config import read_config, write_initial_config
|
||||
from chatmaild.database import Database
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import io
|
||||
import json
|
||||
import pytest
|
||||
import queue
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
import chatmaild.doveauth
|
||||
import pytest
|
||||
from chatmaild.database import DBError
|
||||
from chatmaild.doveauth import (
|
||||
get_user_data,
|
||||
lookup_passdb,
|
||||
handle_dovecot_request,
|
||||
handle_dovecot_protocol,
|
||||
handle_dovecot_request,
|
||||
lookup_passdb,
|
||||
)
|
||||
from chatmaild.database import DBError
|
||||
|
||||
|
||||
def test_basic(db, example_config):
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import pytest
|
||||
from chatmaild.filtermail import (
|
||||
check_encrypted,
|
||||
BeforeQueueHandler,
|
||||
SendRateLimiter,
|
||||
check_encrypted,
|
||||
check_mdn,
|
||||
)
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def maildomain():
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import io
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from chatmaild.metadata import (
|
||||
handle_dovecot_request,
|
||||
handle_dovecot_protocol,
|
||||
Metadata,
|
||||
handle_dovecot_protocol,
|
||||
handle_dovecot_request,
|
||||
)
|
||||
from chatmaild.notifier import (
|
||||
Notifier,
|
||||
@@ -296,3 +296,17 @@ def test_persistent_queue_items(tmp_path, testaddr, token):
|
||||
item2.delete()
|
||||
assert not item2.path.exists()
|
||||
assert not queue_item < item2 and not item2 < queue_item
|
||||
|
||||
|
||||
def test_iroh_relay(metadata):
|
||||
rfile = io.BytesIO(
|
||||
b"\n".join(
|
||||
[
|
||||
b"H",
|
||||
b"Lshared/0123/vendor/vendor.dovecot/pvt/server/vendor/deltachat/irohrelay\tuser@example.org",
|
||||
]
|
||||
)
|
||||
)
|
||||
wfile = io.BytesIO()
|
||||
handle_dovecot_protocol(rfile, wfile, notifier, metadata, "https://example.org/")
|
||||
assert wfile.getvalue() == b"Ohttps://example.org/\n"
|
||||
|
||||
@@ -16,7 +16,6 @@ dependencies = [
|
||||
"build",
|
||||
"tox",
|
||||
"ruff",
|
||||
"black",
|
||||
"pytest",
|
||||
"pytest-xdist",
|
||||
"imap_tools",
|
||||
@@ -31,3 +30,13 @@ cmdeploy = "cmdeploy.cmdeploy:main"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "-v -ra --strict-markers"
|
||||
|
||||
[tool.ruff]
|
||||
lint.select = [
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
|
||||
"PLC", # Pylint Convention
|
||||
"PLE", # Pylint Error
|
||||
"PLW", # Pylint Warning
|
||||
]
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
Chat Mail pyinfra deploy.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib.resources
|
||||
import subprocess
|
||||
import shutil
|
||||
import io
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from chatmaild.config import Config, read_config
|
||||
from pyinfra import host
|
||||
from pyinfra.operations import apt, files, server, systemd, pip
|
||||
from pyinfra.facts.files import File
|
||||
from pyinfra.facts.systemd import SystemdEnabled
|
||||
from .acmetool import deploy_acmetool
|
||||
from pyinfra.operations import apt, files, pip, server, systemd
|
||||
|
||||
from chatmaild.config import read_config, Config
|
||||
from .acmetool import deploy_acmetool
|
||||
|
||||
|
||||
def _build_chatmaild(dist_dir) -> None:
|
||||
@@ -486,19 +486,20 @@ def deploy_chatmail(config_path: Path) -> None:
|
||||
|
||||
# Add our OBS repository for dovecot_no_delay
|
||||
files.put(
|
||||
name = "Add Deltachat OBS GPG key to apt keyring",
|
||||
src = importlib.resources.files(__package__).joinpath("obs-home-deltachat.gpg"),
|
||||
dest = "/etc/apt/keyrings/obs-home-deltachat.gpg",
|
||||
name="Add Deltachat OBS GPG key to apt keyring",
|
||||
src=importlib.resources.files(__package__).joinpath("obs-home-deltachat.gpg"),
|
||||
dest="/etc/apt/keyrings/obs-home-deltachat.gpg",
|
||||
user="root",
|
||||
group="root",
|
||||
mode="644",
|
||||
)
|
||||
|
||||
files.line(
|
||||
name = "Add DeltaChat OBS home repository to sources.list",
|
||||
path = "/etc/apt/sources.list",
|
||||
line = "deb [signed-by=/etc/apt/keyrings/obs-home-deltachat.gpg] https://download.opensuse.org/repositories/home:/deltachat/Debian_12/ ./",
|
||||
ensure_newline = True,
|
||||
name="Add DeltaChat OBS home repository to sources.list",
|
||||
path="/etc/apt/sources.list",
|
||||
line="deb [signed-by=/etc/apt/keyrings/obs-home-deltachat.gpg] https://download.opensuse.org/repositories/home:/deltachat/Debian_12/ ./",
|
||||
escape_regex_characters=True,
|
||||
ensure_newline=True,
|
||||
)
|
||||
|
||||
apt.update(name="apt update", cache_time=24 * 3600)
|
||||
@@ -534,6 +535,12 @@ def deploy_chatmail(config_path: Path) -> None:
|
||||
domains=[mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"],
|
||||
)
|
||||
|
||||
apt.packages(
|
||||
# required for setfacl for echobot
|
||||
name="Install acl",
|
||||
packages="acl",
|
||||
)
|
||||
|
||||
apt.packages(
|
||||
name="Install Postfix",
|
||||
packages="postfix",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import importlib.resources
|
||||
|
||||
from pyinfra.operations import apt, files, systemd, server
|
||||
from pyinfra import host
|
||||
from pyinfra.facts.systemd import SystemdStatus
|
||||
from pyinfra.operations import apt, files, server, systemd
|
||||
|
||||
|
||||
def deploy_acmetool(email="", domains=[]):
|
||||
|
||||
@@ -4,19 +4,18 @@ along with command line option and subcommand parsing.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import subprocess
|
||||
import importlib.resources
|
||||
import importlib.util
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
from termcolor import colored
|
||||
from chatmaild.config import read_config, write_initial_config
|
||||
from cmdeploy.dns import show_dns, check_necessary_dns
|
||||
from termcolor import colored
|
||||
|
||||
from cmdeploy.dns import check_necessary_dns, show_dns
|
||||
|
||||
#
|
||||
# cmdeploy sub commands and options
|
||||
@@ -157,26 +156,26 @@ def fmt_cmd_options(parser):
|
||||
|
||||
|
||||
def fmt_cmd(args, out):
|
||||
"""Run formattting fixes (ruff and black) on all chatmail source code."""
|
||||
"""Run formattting fixes on all chatmail source code."""
|
||||
|
||||
sources = [str(importlib.resources.files(x)) for x in ("chatmaild", "cmdeploy")]
|
||||
black_args = [shutil.which("black")]
|
||||
ruff_args = [shutil.which("ruff")]
|
||||
format_args = [shutil.which("ruff"), "format"]
|
||||
check_args = [shutil.which("ruff"), "check"]
|
||||
|
||||
if args.check:
|
||||
black_args.append("--check")
|
||||
format_args.append("--diff")
|
||||
else:
|
||||
ruff_args.append("--fix")
|
||||
check_args.append("--fix")
|
||||
|
||||
if not args.verbose:
|
||||
black_args.append("-q")
|
||||
ruff_args.append("-q")
|
||||
check_args.append("--quiet")
|
||||
format_args.append("--quiet")
|
||||
|
||||
black_args.extend(sources)
|
||||
ruff_args.extend(sources)
|
||||
format_args.extend(sources)
|
||||
check_args.extend(sources)
|
||||
|
||||
out.check_call(" ".join(black_args), quiet=not args.verbose)
|
||||
out.check_call(" ".join(ruff_args), quiet=not args.verbose)
|
||||
out.check_call(" ".join(format_args), quiet=not args.verbose)
|
||||
out.check_call(" ".join(check_args), quiet=not args.verbose)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -232,7 +231,7 @@ class Out:
|
||||
if not quiet:
|
||||
cmdstring = " ".join(args)
|
||||
self(f"[$ {cmdstring}]", file=sys.stderr)
|
||||
proc = subprocess.run(args, env=env)
|
||||
proc = subprocess.run(args, env=env, check=False)
|
||||
return proc.returncode
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import os
|
||||
import importlib.resources
|
||||
import os
|
||||
|
||||
import pyinfra
|
||||
|
||||
from cmdeploy import deploy_chatmail
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import datetime
|
||||
import importlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import requests
|
||||
import importlib
|
||||
import subprocess
|
||||
import datetime
|
||||
|
||||
|
||||
class DNS:
|
||||
@@ -104,8 +104,8 @@ def show_dns(args, out) -> int:
|
||||
return 0
|
||||
except TypeError:
|
||||
pass
|
||||
for line in zonefile.splitlines():
|
||||
line = line.format(
|
||||
for raw_line in zonefile.splitlines():
|
||||
line = raw_line.format(
|
||||
acme_account_url=acme_account_url,
|
||||
sts_id=datetime.datetime.now().strftime("%Y%m%d%H%M"),
|
||||
chatmail_domain=args.config.mail_domain,
|
||||
|
||||
@@ -27,7 +27,7 @@ mail_plugins = quota
|
||||
# these are the capabilities Delta Chat cares about actually
|
||||
# so let's keep the network overhead per login small
|
||||
# https://github.com/deltachat/deltachat-core-rust/blob/master/src/imap/capabilities.rs
|
||||
imap_capability = IMAP4rev1 IDLE MOVE QUOTA CONDSTORE NOTIFY METADATA XDELTAPUSH
|
||||
imap_capability = IMAP4rev1 IDLE MOVE QUOTA CONDSTORE NOTIFY METADATA XDELTAPUSH XCHATMAIL
|
||||
|
||||
|
||||
# Authentication for system users.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import importlib
|
||||
import qrcode
|
||||
import os
|
||||
from PIL import ImageFont, ImageDraw, Image
|
||||
import io
|
||||
import os
|
||||
|
||||
import qrcode
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
def gen_qr_png_data(maildomain):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Description=Chatmail dict proxy for IMAP METADATA
|
||||
|
||||
[Service]
|
||||
ExecStart={execpath} /run/chatmail-metadata/metadata.socket /home/vmail/mail/{mail_domain}
|
||||
ExecStart={execpath} /run/chatmail-metadata/metadata.socket /home/vmail/mail/{mail_domain} {config_path}
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
User=vmail
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import pytest
|
||||
import threading
|
||||
import queue
|
||||
import socket
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
from chatmaild.config import read_config
|
||||
|
||||
from cmdeploy.cmdeploy import main
|
||||
|
||||
|
||||
@@ -14,6 +15,13 @@ def test_init(tmp_path, maildomain):
|
||||
assert config.mail_domain == maildomain
|
||||
|
||||
|
||||
def test_capabilities(imap):
|
||||
imap.connect()
|
||||
capas = imap.conn.capabilities
|
||||
assert "XCHATMAIL" in capas
|
||||
assert "XDELTAPUSH" in capas
|
||||
|
||||
|
||||
def test_login_basic_functioning(imap_or_smtp, gencreds, lp):
|
||||
"""Test a) that an initial login creates a user automatically
|
||||
and b) verify we can also login a second time with the same password
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import smtplib
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import time
|
||||
import re
|
||||
import ipaddress
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
|
||||
import imap_tools
|
||||
import pytest
|
||||
import requests
|
||||
import ipaddress
|
||||
import imap_tools
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import os
|
||||
import io
|
||||
import time
|
||||
import random
|
||||
import subprocess
|
||||
import imaplib
|
||||
import smtplib
|
||||
import io
|
||||
import itertools
|
||||
import os
|
||||
import random
|
||||
import smtplib
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from chatmaild.database import Database
|
||||
from chatmaild.config import read_config
|
||||
|
||||
from chatmaild.database import Database
|
||||
|
||||
conftestdir = Path(__file__).parent
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from cmdeploy.cmdeploy import get_parser, main
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import importlib.resources
|
||||
import webbrowser
|
||||
import hashlib
|
||||
import importlib.resources
|
||||
import time
|
||||
import traceback
|
||||
import webbrowser
|
||||
|
||||
import markdown
|
||||
from jinja2 import Template
|
||||
from .genqr import gen_qr_png_data
|
||||
from chatmaild.config import read_config
|
||||
from jinja2 import Template
|
||||
|
||||
from .genqr import gen_qr_png_data
|
||||
|
||||
|
||||
def snapshot_dir_stats(somedir):
|
||||
@@ -120,7 +121,8 @@ def main():
|
||||
print(f"watching {src_path} directory for changes")
|
||||
|
||||
changenum = 0
|
||||
for count in range(0, 1000000):
|
||||
count = 0
|
||||
while True:
|
||||
newstats = snapshot_dir_stats(src_path)
|
||||
if newstats == stats and count % 60 != 0:
|
||||
count += 1
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
# Privacy Policy for {{ config.mail_domain }}
|
||||
|
||||
{{ config.privacy_intro }}
|
||||
|
||||
We want to show you in a fair and transparent way
|
||||
what personal data is processed by us.
|
||||
We follow a strict privacy-by-design approach
|
||||
|
||||
Reference in New Issue
Block a user