From d1ddf4d9e0ec9adadcbfd5683413fb1103d0b303 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 7 Nov 2023 21:07:50 +0000 Subject: [PATCH] fix(dictproxy): check that user exists and create it in a transaction Otherwise user may be already created by another connection as checking if the user exists happens in a different read-only transaction. This happens when Delta Chat connects IMAP and SMTP at the same time. Also update last_login time on login. --- chatmaild/src/chatmaild/database.py | 7 ----- chatmaild/src/chatmaild/dictproxy.py | 38 ++++++++++++++++------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/chatmaild/src/chatmaild/database.py b/chatmaild/src/chatmaild/database.py index dbb8d9dc..a7197e14 100644 --- a/chatmaild/src/chatmaild/database.py +++ b/chatmaild/src/chatmaild/database.py @@ -33,13 +33,6 @@ class Connection: def cursor(self): return self._sqlconn.cursor() - def create_user(self, addr: str, password: str): - """Create a row in the users table.""" - self.execute("PRAGMA foreign_keys=on") - q = """INSERT INTO users (addr, password, last_login) - VALUES (?, ?, ?)""" - self.execute(q, (addr, password, int(time.time()))) - def get_user(self, addr: str) -> {}: """Get a row from the users table.""" q = "SELECT addr, password, last_login from users WHERE addr = ?" diff --git a/chatmaild/src/chatmaild/dictproxy.py b/chatmaild/src/chatmaild/dictproxy.py index 35e72f3e..208785a2 100644 --- a/chatmaild/src/chatmaild/dictproxy.py +++ b/chatmaild/src/chatmaild/dictproxy.py @@ -1,5 +1,6 @@ import logging import os +import time import sys import json import crypt @@ -46,17 +47,6 @@ def is_allowed_to_create(user, cleartext_password) -> bool: return True -def create_user(db, user, encrypted_password): - with db.write_transaction() as conn: - conn.create_user(user, encrypted_password) - return dict( - home=f"/home/vmail/{user}", - uid="vmail", - gid="vmail", - password=encrypted_password, - ) - - def get_user_data(db, user): with db.read_connection() as conn: result = conn.get_user(user) @@ -71,14 +61,30 @@ def lookup_userdb(db, user): def lookup_passdb(db, user, cleartext_password): - userdata = get_user_data(db, user) - if not userdata: + with db.write_transaction() as conn: + userdata = conn.get_user(user) + if userdata: + # Update last login time. + conn.execute( + "UPDATE users SET last_login=? WHERE addr=?", (int(time.time()), user) + ) + + userdata["uid"] = "vmail" + userdata["gid"] = "vmail" + return userdata if not is_allowed_to_create(user, cleartext_password): return + encrypted_password = encrypt_password(cleartext_password) - userdata = create_user(db=db, user=user, encrypted_password=encrypted_password) - userdata["password"] = userdata["password"].strip() - return userdata + q = """INSERT INTO users (addr, password, last_login) + VALUES (?, ?, ?)""" + conn.execute(q, (user, encrypted_password, int(time.time()))) + return dict( + home=f"/home/vmail/{user}", + uid="vmail", + gid="vmail", + password=encrypted_password, + ) def handle_dovecot_request(msg, db, mail_domain):