mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 00:14:36 +00:00
Compare commits
4 Commits
link2xt/do
...
link2xt/si
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9456be5bc | ||
|
|
f5bfa6bd56 | ||
|
|
81a6f8808b | ||
|
|
be3685519f |
@@ -151,10 +151,12 @@ While this file is present, account creation will be blocked.
|
||||
|
||||
### Ports
|
||||
|
||||
Postfix listens on ports 25 (smtp) and 587 (submission) and 465 (submissions).
|
||||
Dovecot listens on ports 143(imap) and 993 (imaps).
|
||||
[Postfix](http://www.postfix.org/) listens on ports 25 (smtp) and 587 (submission) and 465 (submissions).
|
||||
[Dovecot](https://www.dovecot.org/) listens on ports 143 (imap) and 993 (imaps).
|
||||
[nginx](https://www.nginx.com/) listens on port 443 (https).
|
||||
[acmetool](https://hlandau.github.io/acmetool/) listens on port 80 (http).
|
||||
|
||||
Delta Chat apps will, however, discover all ports and configurations
|
||||
automatically by reading the `autoconfig.xml` file from the chatmail service.
|
||||
automatically by reading the [autoconfig XML file](https://web.archive.org/web/20210624004729/https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration) from the chatmail service.
|
||||
|
||||
|
||||
|
||||
@@ -98,6 +98,32 @@ def lookup_passdb(db, config: Config, user, cleartext_password):
|
||||
)
|
||||
|
||||
|
||||
def split_and_unescape(s):
|
||||
"""Split strings using double quote as a separator and backslash as escape character
|
||||
into parts."""
|
||||
|
||||
out = ""
|
||||
i = 0
|
||||
while i < len(s):
|
||||
c = s[i]
|
||||
if c == "\\":
|
||||
# Skip escape character.
|
||||
i += 1
|
||||
|
||||
# This will raise IndexError if there is no character
|
||||
# after escape character. This is expected
|
||||
# as this is an invalid input.
|
||||
out += s[i]
|
||||
elif c == '"':
|
||||
# Separator
|
||||
yield out
|
||||
out = ""
|
||||
else:
|
||||
out += c
|
||||
i += 1
|
||||
yield out
|
||||
|
||||
|
||||
def handle_dovecot_request(msg, db, config: Config):
|
||||
short_command = msg[0]
|
||||
if short_command == "L": # LOOKUP
|
||||
@@ -107,7 +133,9 @@ def handle_dovecot_request(msg, db, config: Config):
|
||||
# do not attempt to read any other parts for compatibility.
|
||||
keyname = parts[0]
|
||||
|
||||
namespace, type, *args = keyname.split("/")
|
||||
namespace, type, args = keyname.split("/", 2)
|
||||
args = list(split_and_unescape(args))
|
||||
|
||||
reply_command = "F"
|
||||
res = ""
|
||||
if namespace == "shared":
|
||||
|
||||
@@ -52,8 +52,9 @@ def test_too_high_db_version(db):
|
||||
|
||||
|
||||
def test_handle_dovecot_request(db, example_config):
|
||||
# Test that password can contain ", ', \ and /
|
||||
msg = (
|
||||
"Lshared/passdb/laksjdlaksjdlaksjdlk12j3l1k2j3123/"
|
||||
'Lshared/passdb/laksjdlaksjdlak\\\\sjdlk\\"12j\\\'3l1/k2j3123"'
|
||||
"some42123@chat.example.org\tsome42123@chat.example.org"
|
||||
)
|
||||
res = handle_dovecot_request(msg, db, example_config)
|
||||
|
||||
@@ -37,21 +37,15 @@ class DNS:
|
||||
|
||||
def get(self, typ: str, domain: str) -> str | None:
|
||||
"""Get a DNS entry"""
|
||||
dig_result = self.shell(f"dig {typ} {domain}")
|
||||
line_num = 0
|
||||
for line in dig_result.splitlines():
|
||||
line_num += 1
|
||||
if line.strip() == ";; ANSWER SECTION:":
|
||||
return dig_result.splitlines()[line_num].split("\t")[-1]
|
||||
dig_result = self.shell(f"dig -r -q {domain} -t {typ} +short")
|
||||
line = dig_result.partition("\n")[0]
|
||||
if line:
|
||||
return line
|
||||
|
||||
def check_ptr_record(self, ip: str, mail_domain) -> str:
|
||||
def check_ptr_record(self, ip: str, mail_domain) -> bool:
|
||||
"""Check the PTR record for an IPv4 or IPv6 address."""
|
||||
result = self.get("-x", ip)
|
||||
if result:
|
||||
if ip_address(ip).version == 6:
|
||||
result = result.split()[-1]
|
||||
if result[:-1] == mail_domain:
|
||||
return result
|
||||
result = self.shell(f"dig -r -x {ip} +short").rstrip()
|
||||
return result == f"{mail_domain}."
|
||||
|
||||
|
||||
def show_dns(args, out):
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
uri = proxy:/run/dovecot/doveauth.socket:auth
|
||||
iterate_disable = yes
|
||||
default_pass_scheme = plain
|
||||
password_key = passdb/%w/%u
|
||||
user_key = userdb/%u
|
||||
# %E escapes characters " (double quote), ' (single quote) and \ (backslash) with \ (backslash).
|
||||
# See <https://doc.dovecot.org/configuration_manual/config_file/config_variables/#modifiers>
|
||||
# for documentation.
|
||||
#
|
||||
# We escape user-provided input and use double quote as a separator.
|
||||
password_key = passdb/%Ew"%Eu
|
||||
user_key = userdb/%Eu
|
||||
|
||||
@@ -14,3 +14,12 @@ def test_fastcgi_working(maildomain, chatmail_config):
|
||||
res = requests.post(url)
|
||||
assert maildomain in res.json().get("email")
|
||||
assert len(res.json().get("password")) > chatmail_config.password_min_length
|
||||
|
||||
|
||||
def test_newemail_configure(maildomain, rpc):
|
||||
"""Test configuring accounts by scanning a QR code works."""
|
||||
url = f"DCACCOUNT:https://{maildomain}/cgi-bin/newemail.py"
|
||||
for i in range(3):
|
||||
account_id = rpc.add_account()
|
||||
rpc.set_config_from_qr(account_id, url)
|
||||
rpc.configure(account_id)
|
||||
|
||||
Reference in New Issue
Block a user