mirror of
https://github.com/chatmail/relay.git
synced 2026-05-23 14:28:02 +00:00
Compare commits
14 Commits
hagi/#295-
...
hagi/#318-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3eae1657de | ||
|
|
736c67ac1f | ||
|
|
295072e57b | ||
|
|
dc17088517 | ||
|
|
514a063142 | ||
|
|
2b96586e12 | ||
|
|
8fde4d929d | ||
|
|
683aefa37c | ||
|
|
b951ec12c5 | ||
|
|
3d8ac6b598 | ||
|
|
9515a37687 | ||
|
|
b5d0b0ad9a | ||
|
|
3f4989223d | ||
|
|
9be0408ab8 |
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## untagged
|
## untagged
|
||||||
|
|
||||||
|
- replace crypt with passlib, as crypt will be deprecated in Python 3.13
|
||||||
|
([#319](https://github.com/deltachat/chatmail/pull/319))
|
||||||
|
|
||||||
- Reject DKIM signatures that do not cover the whole message body.
|
- Reject DKIM signatures that do not cover the whole message body.
|
||||||
([#321](https://github.com/deltachat/chatmail/pull/321))
|
([#321](https://github.com/deltachat/chatmail/pull/321))
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ dependencies = [
|
|||||||
"deltachat-rpc-client",
|
"deltachat-rpc-client",
|
||||||
"filelock",
|
"filelock",
|
||||||
"requests",
|
"requests",
|
||||||
|
"passlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
@@ -26,7 +27,6 @@ chatmail-metadata = "chatmaild.metadata:main"
|
|||||||
filtermail = "chatmaild.filtermail:main"
|
filtermail = "chatmaild.filtermail:main"
|
||||||
echobot = "chatmaild.echo:main"
|
echobot = "chatmaild.echo:main"
|
||||||
chatmail-metrics = "chatmaild.metrics:main"
|
chatmail-metrics = "chatmaild.metrics:main"
|
||||||
rm_accounts = "chatmaild.rm_accounts:main"
|
|
||||||
|
|
||||||
[project.entry-points.pytest11]
|
[project.entry-points.pytest11]
|
||||||
"chatmaild.testplugin" = "chatmaild.tests.plugin"
|
"chatmaild.testplugin" = "chatmaild.tests.plugin"
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ class Config:
|
|||||||
self.max_user_send_per_minute = int(params["max_user_send_per_minute"])
|
self.max_user_send_per_minute = int(params["max_user_send_per_minute"])
|
||||||
self.max_mailbox_size = params["max_mailbox_size"]
|
self.max_mailbox_size = params["max_mailbox_size"]
|
||||||
self.delete_mails_after = params["delete_mails_after"]
|
self.delete_mails_after = params["delete_mails_after"]
|
||||||
self.delete_accounts_after = int(params["delete_accounts_after"])
|
|
||||||
self.username_min_length = int(params["username_min_length"])
|
self.username_min_length = int(params["username_min_length"])
|
||||||
self.username_max_length = int(params["username_max_length"])
|
self.username_max_length = int(params["username_max_length"])
|
||||||
self.password_min_length = int(params["password_min_length"])
|
self.password_min_length = int(params["password_min_length"])
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import crypt
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -11,6 +10,8 @@ from socketserver import (
|
|||||||
UnixStreamServer,
|
UnixStreamServer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import passlib.hash
|
||||||
|
|
||||||
from .config import Config, read_config
|
from .config import Config, read_config
|
||||||
from .database import Database
|
from .database import Database
|
||||||
|
|
||||||
@@ -23,8 +24,9 @@ class UnknownCommand(ValueError):
|
|||||||
|
|
||||||
def encrypt_password(password: str):
|
def encrypt_password(password: str):
|
||||||
# https://doc.dovecot.org/configuration_manual/authentication/password_schemes/
|
# https://doc.dovecot.org/configuration_manual/authentication/password_schemes/
|
||||||
passhash = crypt.crypt(password, crypt.METHOD_SHA512)
|
pw = passlib.hash.sha512_crypt.hash(password).split("$")
|
||||||
return "{SHA512-CRYPT}" + passhash
|
|
||||||
|
return "{SHA512-CRYPT}$" + pw[1] + "$" + pw[3] + "$" + pw[4]
|
||||||
|
|
||||||
|
|
||||||
def is_allowed_to_create(config: Config, user, cleartext_password) -> bool:
|
def is_allowed_to_create(config: Config, user, cleartext_password) -> bool:
|
||||||
@@ -106,8 +108,7 @@ def lookup_passdb(db, config: Config, user, cleartext_password):
|
|||||||
if userdata:
|
if userdata:
|
||||||
# Update last login time.
|
# Update last login time.
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"UPDATE users SET last_login=? WHERE addr=?",
|
"UPDATE users SET last_login=? WHERE addr=?", (int(time.time()), user)
|
||||||
(int(time.time() // 86400), user),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
userdata["home"] = f"/home/vmail/mail/{config.mail_domain}/{user}"
|
userdata["home"] = f"/home/vmail/mail/{config.mail_domain}/{user}"
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ max_mailbox_size = 100M
|
|||||||
# days after which mails are unconditionally deleted
|
# days after which mails are unconditionally deleted
|
||||||
delete_mails_after = 20
|
delete_mails_after = 20
|
||||||
|
|
||||||
# days after which accounts are deleted if nobody logged in
|
|
||||||
delete_accounts_after = 25
|
|
||||||
|
|
||||||
# minimum length a username must have
|
# minimum length a username must have
|
||||||
username_min_length = 9
|
username_min_length = 9
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import sys
|
|
||||||
import time
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from .config import read_config
|
|
||||||
from .database import Database
|
|
||||||
|
|
||||||
|
|
||||||
def remove_users(db: Database, cutoff_date: int):
|
|
||||||
with db.write_transaction() as conn:
|
|
||||||
delete_query = "DELETE FROM users WHERE last_login <?"
|
|
||||||
conn.execute(delete_query, (cutoff_date))
|
|
||||||
|
|
||||||
|
|
||||||
def remove_user_data(db: Database, cutoff_date: int, vmail_basedir: Path):
|
|
||||||
"""Collects all users where last_login < cutoff_date and deletes corresponding directories."""
|
|
||||||
|
|
||||||
with db.write_transaction() as conn:
|
|
||||||
select_query = "SELECT user FROM users WHERE last_login <?"
|
|
||||||
cursor = conn.execute(select_query, (cutoff_date,))
|
|
||||||
usernames = cursor.fetchall()
|
|
||||||
|
|
||||||
for username in usernames:
|
|
||||||
user_dir = vmail_basedir / username[0]
|
|
||||||
if user_dir.exists() and user_dir.is_dir():
|
|
||||||
shutil.rmtree(user_dir, ignore_errors=True)
|
|
||||||
print(f"Deleted directory: {user_dir}")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
db = Database(sys.argv[2])
|
|
||||||
config = read_config(sys.argv[3])
|
|
||||||
today = int(time.time() // 86400)
|
|
||||||
|
|
||||||
cutoff_date = today - config.delete_accounts_after
|
|
||||||
remove_user_data(db, cutoff_date)
|
|
||||||
Reference in New Issue
Block a user