mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
Support iterating over all users with doveadm commands (#344)
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## untagged
|
||||
|
||||
- Support iterating over all users with doveadm commands
|
||||
([#344](https://github.com/deltachat/chatmail/pull/344))
|
||||
|
||||
- Test and fix for attempts to create inadmissible accounts
|
||||
([#333](https://github.com/deltachat/chatmail/pull/321))
|
||||
|
||||
|
||||
@@ -129,6 +129,15 @@ def lookup_passdb(db, config: Config, user, cleartext_password):
|
||||
)
|
||||
|
||||
|
||||
def iter_userdb(db, config: Config) -> list:
|
||||
"""Get a list of all user addresses."""
|
||||
with db.read_connection() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT addr from users",
|
||||
).fetchall()
|
||||
return [x[0] for x in rows]
|
||||
|
||||
|
||||
def split_and_unescape(s):
|
||||
"""Split strings using double quote as a separator and backslash as escape character
|
||||
into parts."""
|
||||
@@ -192,6 +201,15 @@ def handle_dovecot_request(msg, db, config: Config):
|
||||
reply_command = "N"
|
||||
json_res = json.dumps(res) if res else ""
|
||||
return f"{reply_command}{json_res}\n"
|
||||
elif short_command == "I": # ITERATE
|
||||
# example: I0\t0\tshared/userdb/
|
||||
parts = msg[1:].split("\t")
|
||||
if parts[2] == "shared/userdb/":
|
||||
result = "".join(
|
||||
f"Oshared/userdb/{user}\t\n" for user in iter_userdb(db, config)
|
||||
)
|
||||
return f"{result}\n"
|
||||
|
||||
raise UnknownCommand(msg)
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from chatmaild.doveauth import (
|
||||
handle_dovecot_protocol,
|
||||
handle_dovecot_request,
|
||||
is_allowed_to_create,
|
||||
iter_userdb,
|
||||
lookup_passdb,
|
||||
)
|
||||
from chatmaild.newemail import create_newemail_dict
|
||||
@@ -27,6 +28,16 @@ def test_basic(db, example_config):
|
||||
assert data == data2
|
||||
|
||||
|
||||
def test_iterate_addresses(db, example_config):
|
||||
addresses = []
|
||||
|
||||
for i in range(10):
|
||||
addresses.append(f"asdf1234{i}@chat.example.org")
|
||||
lookup_passdb(db, example_config, addresses[-1], "q9mr3faue")
|
||||
res = iter_userdb(db, example_config)
|
||||
assert res == addresses
|
||||
|
||||
|
||||
def test_invalid_username_length(example_config):
|
||||
config = example_config
|
||||
config.username_min_length = 6
|
||||
@@ -108,6 +119,18 @@ def test_handle_dovecot_protocol(db, example_config):
|
||||
assert wfile.getvalue() == b"N\n"
|
||||
|
||||
|
||||
def test_handle_dovecot_protocol_iterate(db, gencreds, example_config):
|
||||
lookup_passdb(db, example_config, "asdf00000@chat.example.org", "q9mr3faue")
|
||||
lookup_passdb(db, example_config, "asdf11111@chat.example.org", "q9mr3faue")
|
||||
rfile = io.BytesIO(b"H3\t2\t0\t\tauth\nI0\t0\tshared/userdb/")
|
||||
wfile = io.BytesIO()
|
||||
handle_dovecot_protocol(rfile, wfile, db, example_config)
|
||||
lines = wfile.getvalue().decode("ascii").split("\n")
|
||||
assert lines[0] == "Oshared/userdb/asdf00000@chat.example.org\t"
|
||||
assert lines[1] == "Oshared/userdb/asdf11111@chat.example.org\t"
|
||||
assert not lines[2]
|
||||
|
||||
|
||||
def test_50_concurrent_lookups_different_accounts(db, gencreds, example_config):
|
||||
num_threads = 50
|
||||
req_per_thread = 5
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
uri = proxy:/run/doveauth/doveauth.socket:auth
|
||||
iterate_disable = yes
|
||||
iterate_disable = no
|
||||
iterate_prefix = userdb/
|
||||
|
||||
default_pass_scheme = plain
|
||||
# %E escapes characters " (double quote), ' (single quote) and \ (backslash) with \ (backslash).
|
||||
# See <https://doc.dovecot.org/configuration_manual/config_file/config_variables/#modifiers>
|
||||
|
||||
Reference in New Issue
Block a user