mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 08:24:37 +00:00
Compare commits
1 Commits
basic-post
...
mailname
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6a94944e0 |
@@ -59,7 +59,7 @@ def lookup_passdb(db, user, password):
|
|||||||
return userdata
|
return userdata
|
||||||
|
|
||||||
|
|
||||||
def handle_dovecot_request(msg, db):
|
def handle_dovecot_request(msg, db, mail_domain):
|
||||||
print(f"received msg: {msg!r}", file=sys.stderr)
|
print(f"received msg: {msg!r}", file=sys.stderr)
|
||||||
short_command = msg[0]
|
short_command = msg[0]
|
||||||
if short_command == "L": # LOOKUP
|
if short_command == "L": # LOOKUP
|
||||||
@@ -70,13 +70,15 @@ def handle_dovecot_request(msg, db):
|
|||||||
res = ""
|
res = ""
|
||||||
if namespace == "shared":
|
if namespace == "shared":
|
||||||
if type == "userdb":
|
if type == "userdb":
|
||||||
res = lookup_userdb(db, user)
|
if user.endswith(f"@{mail_domain}"):
|
||||||
|
res = lookup_userdb(db, user)
|
||||||
if res:
|
if res:
|
||||||
reply_command = "O"
|
reply_command = "O"
|
||||||
else:
|
else:
|
||||||
reply_command = "N"
|
reply_command = "N"
|
||||||
elif type == "passdb":
|
elif type == "passdb":
|
||||||
res = lookup_passdb(db, user, password=args[0])
|
if user.endswith(f"@{mail_domain}"):
|
||||||
|
res = lookup_passdb(db, user, password=args[0])
|
||||||
if res:
|
if res:
|
||||||
reply_command = "O"
|
reply_command = "O"
|
||||||
else:
|
else:
|
||||||
@@ -95,6 +97,8 @@ def main():
|
|||||||
socket = sys.argv[1]
|
socket = sys.argv[1]
|
||||||
passwd_entry = pwd.getpwnam(sys.argv[2])
|
passwd_entry = pwd.getpwnam(sys.argv[2])
|
||||||
db = Database(sys.argv[3])
|
db = Database(sys.argv[3])
|
||||||
|
with open("/etc/mailname", "r") as fp:
|
||||||
|
mail_domain = fp.read().strip()
|
||||||
|
|
||||||
class Handler(StreamRequestHandler):
|
class Handler(StreamRequestHandler):
|
||||||
def handle(self):
|
def handle(self):
|
||||||
@@ -102,7 +106,7 @@ def main():
|
|||||||
msg = self.rfile.readline().strip().decode()
|
msg = self.rfile.readline().strip().decode()
|
||||||
if not msg:
|
if not msg:
|
||||||
break
|
break
|
||||||
res = handle_dovecot_request(msg, db)
|
res = handle_dovecot_request(msg, db, mail_domain)
|
||||||
if res:
|
if res:
|
||||||
print(f"sending result: {res!r}", file=sys.stderr)
|
print(f"sending result: {res!r}", file=sys.stderr)
|
||||||
self.wfile.write(res.encode("ascii"))
|
self.wfile.write(res.encode("ascii"))
|
||||||
|
|||||||
@@ -244,6 +244,13 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
|
|||||||
restarted=dovecot_need_restart,
|
restarted=dovecot_need_restart,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# This file is used by auth proxy.
|
||||||
|
# https://wiki.debian.org/EtcMailName
|
||||||
|
server.shell(
|
||||||
|
name="Setup /etc/mailname",
|
||||||
|
commands=[f"echo {mail_domain} >/etc/mailname; chmod 644 /etc/mailname"],
|
||||||
|
)
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
result = server.shell(
|
result = server.shell(
|
||||||
commands=[
|
commands=[
|
||||||
|
|||||||
@@ -29,9 +29,6 @@ myhostname = {{ config.domain_name }}
|
|||||||
alias_maps = hash:/etc/aliases
|
alias_maps = hash:/etc/aliases
|
||||||
alias_database = hash:/etc/aliases
|
alias_database = hash:/etc/aliases
|
||||||
|
|
||||||
# hard limit, also on internal messages
|
|
||||||
smtpd_client_message_rate_limit = 80
|
|
||||||
|
|
||||||
# Postfix does not deliver mail for any domain by itself.
|
# Postfix does not deliver mail for any domain by itself.
|
||||||
# Primary domain is listed in `virtual_mailbox_domains` instead
|
# Primary domain is listed in `virtual_mailbox_domains` instead
|
||||||
# and handed over to Dovecot.
|
# and handed over to Dovecot.
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import smtplib
|
|
||||||
|
|
||||||
|
|
||||||
def test_login_basic_functioning(imap_or_smtp, gencreds, lp):
|
def test_login_basic_functioning(imap_or_smtp, gencreds, lp):
|
||||||
@@ -35,178 +34,3 @@ def test_login_same_password(imap_or_smtp, gencreds):
|
|||||||
imap_or_smtp.login(user1, password1)
|
imap_or_smtp.login(user1, password1)
|
||||||
imap_or_smtp.connect()
|
imap_or_smtp.connect()
|
||||||
imap_or_smtp.login(user2, password1)
|
imap_or_smtp.login(user2, password1)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason="Only rate limit is internal as well now")
|
|
||||||
def test_no_internal_rate_limit(smtp, gencreds):
|
|
||||||
"""Test that there is no rate limit between accounts on the same chatmail server."""
|
|
||||||
user, password = gencreds()
|
|
||||||
to_addr, = gencreds()
|
|
||||||
smtp.connect()
|
|
||||||
smtp.login(user, password)
|
|
||||||
|
|
||||||
mail = "\r\n".join(
|
|
||||||
[
|
|
||||||
"Subject: ...",
|
|
||||||
f"From: <{user}>",
|
|
||||||
f"To: <{to_addr}>",
|
|
||||||
"Date: Sun, 15 Oct 2023 16:43:21 +0000",
|
|
||||||
"Message-ID: <Mr.UVyJWZmkCKM.hGzNc6glBE_@c2.testrun.org>",
|
|
||||||
"In-Reply-To: <Mr.MvmCz-GQbi_.6FGRkhDf05c@c2.testrun.org>",
|
|
||||||
"References: <Mr.3gckbNy5bch.uK3Hd2Ws6-w@c2.testrun.org>",
|
|
||||||
"\t<Mr.MvmCz-GQbi_.6FGRkhDf05c@c2.testrun.org>",
|
|
||||||
"Chat-Version: 1.0",
|
|
||||||
f"Autocrypt: addr={user}; prefer-encrypt=mutual;",
|
|
||||||
"\tkeydata=xjMEZSwWjhYJKwYBBAHaRw8BAQdAQBEhqeJh0GueHB6kF/DUQqYCxARNBVokg/AzT+7LqH",
|
|
||||||
"\trNFzxiYXJiYXpAYzIudGVzdHJ1bi5vcmc+wosEEBYIADMCGQEFAmUsFo4CGwMECwkIBwYVCAkKCwID",
|
|
||||||
"\tFgIBFiEEFTfUNvVnY3b9F7yHnmme1PfUhX8ACgkQnmme1PfUhX9A4AEAnHWHp49eBCMHK5t66gYPiW",
|
|
||||||
"\tXQuB1mwUjzGfYWB+0RXUoA/0xcQ3FbUNlGKW7Blp6eMFfViv6Mv2d3kNSXACB6nmcMzjgEZSwWjhIK",
|
|
||||||
"\tKwYBBAGXVQEFAQEHQBpY5L2M1XHo0uxf8SX1wNLBp/OVvidoWHQF2Jz+kJsUAwEIB8J4BBgWCAAgBQ",
|
|
||||||
"\tJlLBaOAhsMFiEEFTfUNvVnY3b9F7yHnmme1PfUhX8ACgkQnmme1PfUhX/INgEA37AJaNvruYsJVanP",
|
|
||||||
"\tIXnYw4CKd55UAwl8Zcy+M2diAbkA/0fHHcGV4r78hpbbL1Os52DPOdqYQRauIeJUeG+G6bQO",
|
|
||||||
"MIME-Version: 1.0",
|
|
||||||
'Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";',
|
|
||||||
'\tboundary="YFrteb74qSXmggbOxZL9dRnhymywAi"',
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi",
|
|
||||||
"Content-Description: PGP/MIME version identification",
|
|
||||||
"Content-Type: application/pgp-encrypted",
|
|
||||||
"",
|
|
||||||
"Version: 1",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi",
|
|
||||||
"Content-Description: OpenPGP encrypted message",
|
|
||||||
'Content-Disposition: inline; filename="encrypted.asc";',
|
|
||||||
'Content-Type: application/octet-stream; name="encrypted.asc"',
|
|
||||||
"",
|
|
||||||
"-----BEGIN PGP MESSAGE-----",
|
|
||||||
"",
|
|
||||||
"wU4DhW3gBZ/VvCYSAQdA8bMs2spwbKdGjVsL1ByPkNrqD7frpB73maeL6I6SzDYg",
|
|
||||||
"O5G53tv339RdKq3WRcCtEEvxjHlUx2XNwXzC04BpmfvBTgNfPUyLDzjXnxIBB0Ae",
|
|
||||||
"8ymwGvXMCCimHXN0Dg8Ui62KOi03h0UgheoHWovJSCDF4CKre/xtFr3nL7lq/PKI",
|
|
||||||
"JsjVNz7/RK9FSXF6WwfONtLCyQGEuVAsB/KXfCBEyfKhaMwGHvhujRidGW5uV1no",
|
|
||||||
"lMGl3ODmo29Lgeu2uSE7EpJRZoe6hU6ddmBkqxax61ZtkaFlGFFpdo2K8balNNdz",
|
|
||||||
"ZsJ/9mmI9x3oOJ4/l1nhQbUO9ADbs7gJhFdV5Qkp30b5fCI7bU+aoe1ccBbLe/WM",
|
|
||||||
"YUty1PqcuQT7XjA+XmYuL261tvW8pBetT+i33/E2d8PzzYt2IuK9qeevyS+yxdwA",
|
|
||||||
"kfwejFWzzsUlJaDxs1x4XOxkMgSj+jo+g12dFOb7fyClsAnq23iDb8AuaT/BScAI",
|
|
||||||
"+lO+gher69+6LmM7VGHLG5k762J1jTaQCaKt1s8TAWV99Eo4491vL6fyvk3l/Cfg",
|
|
||||||
"RXSwiWFgj19Pn0Rq7CD9v22UE2vdUMBTcV4aw79mClk1YQ23jbF0y5DCjPdJ62Zo",
|
|
||||||
"tskBgFt3NoWV80jZ76zIBLrrjLwCCll8JjJtFwSkt2GX5RFBsVa4A8IDht9RtEk7",
|
|
||||||
"rrHgbSZQfkauEi/mH3/6CDZoLqSHudUZ7d4MaJwun1TkFYGe2ORwGJd4OBj3oGJp",
|
|
||||||
"H8YBwCpk///L/fKjX0Gg3M8nrpM4wrRFhPKidAgO/kcm25X4+ZHlVkWBTCt5RWKI",
|
|
||||||
"fHh6oLDZCqCfcgMkE1KKmwfIHaUkhq5BPRigwy6i5dh1DM4+1UCLh3dxzVbqE9b9",
|
|
||||||
"61NB19nXdRtDA2sOUnj9ve6m/wEPyCb6/zBQZqvCBYb1/AjdXpUrFT+DbpfyxaXN",
|
|
||||||
"XfhDVb5mNqNM/IVj0V5fvTc6vOfYbzQtPm10H+FdWWfb+rJRfyC3MA2w2IqstFe3",
|
|
||||||
"w3bu2iE6CQvSqRvge+ZqLKt/NqYwOURiUmpuklbl3kPJ97+mfKWoiqk8Iz1VY+bb",
|
|
||||||
"NMUC7aoGv+jcoj+WS6PYO8N6BeRVUUB3ZJSf8nzjgxm1/BcM+UD3BPrlhT11ODRs",
|
|
||||||
"baifGbprMWwt3dhb8cQgRT8GPdpO1OsDkzL6iikMjLHWWiA99GV6ruiHsIPw6boW",
|
|
||||||
"A6/uSOskbDHOROotKmddGTBd0iiHXAoQsJFt1ZjUkt6EHrgWs+GAvrvKpXs1mrz8",
|
|
||||||
"uj3GwEFrHS+Xuf2UDgpszYT3hI2cL/kUtGakVR7m7vVMZqXBUbZdGAEb1PZNPwsI",
|
|
||||||
"E4aMK02+EVB+tSN4Fzj99N2YD0inVYt+oPjr2tHhUS6aSGBNS/48Ki47DOg4Sxkn",
|
|
||||||
"lkOWnEbCD+XTnbDd",
|
|
||||||
"=agR5",
|
|
||||||
"-----END PGP MESSAGE-----",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi--",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
).encode()
|
|
||||||
for i in range(100):
|
|
||||||
print("Sending mail", str(i))
|
|
||||||
smtp.conn.sendmail(user, to_addr, mail)
|
|
||||||
|
|
||||||
|
|
||||||
def test_exceed_rate_limit(smtp, gencreds):
|
|
||||||
"""Test that the outbound rate limit is exceeded if we send a lot of messages at once."""
|
|
||||||
user, password = gencreds()
|
|
||||||
smtp.connect()
|
|
||||||
smtp.login(user, password)
|
|
||||||
|
|
||||||
to_addr = "foobar@example.org"
|
|
||||||
mail = "\r\n".join(
|
|
||||||
[
|
|
||||||
"Subject: ...",
|
|
||||||
f"From: <{user}>",
|
|
||||||
f"To: <{to_addr}>",
|
|
||||||
"Date: Sun, 15 Oct 2023 16:43:21 +0000",
|
|
||||||
"Message-ID: <Mr.UVyJWZmkCKM.hGzNc6glBE_@c2.testrun.org>",
|
|
||||||
"In-Reply-To: <Mr.MvmCz-GQbi_.6FGRkhDf05c@c2.testrun.org>",
|
|
||||||
"References: <Mr.3gckbNy5bch.uK3Hd2Ws6-w@c2.testrun.org>",
|
|
||||||
"\t<Mr.MvmCz-GQbi_.6FGRkhDf05c@c2.testrun.org>",
|
|
||||||
"Chat-Version: 1.0",
|
|
||||||
f"Autocrypt: addr={user}; prefer-encrypt=mutual;",
|
|
||||||
"\tkeydata=xjMEZSwWjhYJKwYBBAHaRw8BAQdAQBEhqeJh0GueHB6kF/DUQqYCxARNBVokg/AzT+7LqH",
|
|
||||||
"\trNFzxiYXJiYXpAYzIudGVzdHJ1bi5vcmc+wosEEBYIADMCGQEFAmUsFo4CGwMECwkIBwYVCAkKCwID",
|
|
||||||
"\tFgIBFiEEFTfUNvVnY3b9F7yHnmme1PfUhX8ACgkQnmme1PfUhX9A4AEAnHWHp49eBCMHK5t66gYPiW",
|
|
||||||
"\tXQuB1mwUjzGfYWB+0RXUoA/0xcQ3FbUNlGKW7Blp6eMFfViv6Mv2d3kNSXACB6nmcMzjgEZSwWjhIK",
|
|
||||||
"\tKwYBBAGXVQEFAQEHQBpY5L2M1XHo0uxf8SX1wNLBp/OVvidoWHQF2Jz+kJsUAwEIB8J4BBgWCAAgBQ",
|
|
||||||
"\tJlLBaOAhsMFiEEFTfUNvVnY3b9F7yHnmme1PfUhX8ACgkQnmme1PfUhX/INgEA37AJaNvruYsJVanP",
|
|
||||||
"\tIXnYw4CKd55UAwl8Zcy+M2diAbkA/0fHHcGV4r78hpbbL1Os52DPOdqYQRauIeJUeG+G6bQO",
|
|
||||||
"MIME-Version: 1.0",
|
|
||||||
'Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";',
|
|
||||||
'\tboundary="YFrteb74qSXmggbOxZL9dRnhymywAi"',
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi",
|
|
||||||
"Content-Description: PGP/MIME version identification",
|
|
||||||
"Content-Type: application/pgp-encrypted",
|
|
||||||
"",
|
|
||||||
"Version: 1",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi",
|
|
||||||
"Content-Description: OpenPGP encrypted message",
|
|
||||||
'Content-Disposition: inline; filename="encrypted.asc";',
|
|
||||||
'Content-Type: application/octet-stream; name="encrypted.asc"',
|
|
||||||
"",
|
|
||||||
"-----BEGIN PGP MESSAGE-----",
|
|
||||||
"",
|
|
||||||
"wU4DhW3gBZ/VvCYSAQdA8bMs2spwbKdGjVsL1ByPkNrqD7frpB73maeL6I6SzDYg",
|
|
||||||
"O5G53tv339RdKq3WRcCtEEvxjHlUx2XNwXzC04BpmfvBTgNfPUyLDzjXnxIBB0Ae",
|
|
||||||
"8ymwGvXMCCimHXN0Dg8Ui62KOi03h0UgheoHWovJSCDF4CKre/xtFr3nL7lq/PKI",
|
|
||||||
"JsjVNz7/RK9FSXF6WwfONtLCyQGEuVAsB/KXfCBEyfKhaMwGHvhujRidGW5uV1no",
|
|
||||||
"lMGl3ODmo29Lgeu2uSE7EpJRZoe6hU6ddmBkqxax61ZtkaFlGFFpdo2K8balNNdz",
|
|
||||||
"ZsJ/9mmI9x3oOJ4/l1nhQbUO9ADbs7gJhFdV5Qkp30b5fCI7bU+aoe1ccBbLe/WM",
|
|
||||||
"YUty1PqcuQT7XjA+XmYuL261tvW8pBetT+i33/E2d8PzzYt2IuK9qeevyS+yxdwA",
|
|
||||||
"kfwejFWzzsUlJaDxs1x4XOxkMgSj+jo+g12dFOb7fyClsAnq23iDb8AuaT/BScAI",
|
|
||||||
"+lO+gher69+6LmM7VGHLG5k762J1jTaQCaKt1s8TAWV99Eo4491vL6fyvk3l/Cfg",
|
|
||||||
"RXSwiWFgj19Pn0Rq7CD9v22UE2vdUMBTcV4aw79mClk1YQ23jbF0y5DCjPdJ62Zo",
|
|
||||||
"tskBgFt3NoWV80jZ76zIBLrrjLwCCll8JjJtFwSkt2GX5RFBsVa4A8IDht9RtEk7",
|
|
||||||
"rrHgbSZQfkauEi/mH3/6CDZoLqSHudUZ7d4MaJwun1TkFYGe2ORwGJd4OBj3oGJp",
|
|
||||||
"H8YBwCpk///L/fKjX0Gg3M8nrpM4wrRFhPKidAgO/kcm25X4+ZHlVkWBTCt5RWKI",
|
|
||||||
"fHh6oLDZCqCfcgMkE1KKmwfIHaUkhq5BPRigwy6i5dh1DM4+1UCLh3dxzVbqE9b9",
|
|
||||||
"61NB19nXdRtDA2sOUnj9ve6m/wEPyCb6/zBQZqvCBYb1/AjdXpUrFT+DbpfyxaXN",
|
|
||||||
"XfhDVb5mNqNM/IVj0V5fvTc6vOfYbzQtPm10H+FdWWfb+rJRfyC3MA2w2IqstFe3",
|
|
||||||
"w3bu2iE6CQvSqRvge+ZqLKt/NqYwOURiUmpuklbl3kPJ97+mfKWoiqk8Iz1VY+bb",
|
|
||||||
"NMUC7aoGv+jcoj+WS6PYO8N6BeRVUUB3ZJSf8nzjgxm1/BcM+UD3BPrlhT11ODRs",
|
|
||||||
"baifGbprMWwt3dhb8cQgRT8GPdpO1OsDkzL6iikMjLHWWiA99GV6ruiHsIPw6boW",
|
|
||||||
"A6/uSOskbDHOROotKmddGTBd0iiHXAoQsJFt1ZjUkt6EHrgWs+GAvrvKpXs1mrz8",
|
|
||||||
"uj3GwEFrHS+Xuf2UDgpszYT3hI2cL/kUtGakVR7m7vVMZqXBUbZdGAEb1PZNPwsI",
|
|
||||||
"E4aMK02+EVB+tSN4Fzj99N2YD0inVYt+oPjr2tHhUS6aSGBNS/48Ki47DOg4Sxkn",
|
|
||||||
"lkOWnEbCD+XTnbDd",
|
|
||||||
"=agR5",
|
|
||||||
"-----END PGP MESSAGE-----",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--YFrteb74qSXmggbOxZL9dRnhymywAi--",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
).encode()
|
|
||||||
for i in range(100):
|
|
||||||
print("Sending mail", str(i))
|
|
||||||
try:
|
|
||||||
smtp.conn.sendmail(user, to_addr, mail)
|
|
||||||
except smtplib.SMTPSenderRefused as e:
|
|
||||||
if i == 0:
|
|
||||||
pytest.fail(f"rate limit was exceeded too early with msg {i} - maybe wait a minute before testing?")
|
|
||||||
if i < 41:
|
|
||||||
pytest.fail(f"rate limit was exceeded too early with msg {i}")
|
|
||||||
assert e.smtp_code == 450
|
|
||||||
assert b'4.7.1 Error: too much mail from' in e.smtp_error
|
|
||||||
return
|
|
||||||
pytest.fail("Rate limit was not exceeded")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user