From 1195ddeb2c2e125d8624260a1f2fcdd2a8bd38ec Mon Sep 17 00:00:00 2001 From: Martin Mares <mj@ucw.cz> Date: Fri, 13 Jan 2023 21:59:42 +0100 Subject: [PATCH] =?UTF-8?q?Registrace=20o=C5=A1et=C5=99uje=20kolize=20p?= =?UTF-8?q?=C5=99i=20zm=C4=9Bn=C4=9B=20e-mailu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Při implementaci registrace jsme na to úplně zapomněli. Closes #307 and #321. --- mo/web/acct.py | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/mo/web/acct.py b/mo/web/acct.py index e54311a2..24f34bc2 100644 --- a/mo/web/acct.py +++ b/mo/web/acct.py @@ -193,19 +193,23 @@ def user_settings_personal(): sess.commit() flash('Heslo změněno.', 'success') if form.email.data != user.email: - rr = mo.users.new_reg_request(db.RegReqType.change_email, request.remote_addr) - if rr: - rr.user_id = user.user_id - rr.email = form.email.data - sess.add(rr) - sess.commit() - app.logger.info(f'Settings: Požadavek na změnu e-mailu uživatele #{user.user_id}') - flash('Odeslán e-mail s odkazem na potvrzení nové adresy.', 'success') - mo.email.send_confirm_change_email(user, rr.email_token) - else: - app.logger.info('Settings: Rate limit') - flash('Příliš mnoho požadavků na změny e-mailu. Počkejte prosím chvíli a zkuste to znovu.', 'danger') + if mo.users.user_by_email(form.email.data) is not None: + flash('Tuto e-mailovou adresu už používá jiný uživatel.', 'danger') ok = False + else: + rr = mo.users.new_reg_request(db.RegReqType.change_email, request.remote_addr) + if rr: + rr.user_id = user.user_id + rr.email = form.email.data + sess.add(rr) + sess.commit() + app.logger.info(f'Settings: Požadavek na změnu e-mailu uživatele #{user.user_id}') + flash('Odeslán e-mail s odkazem na potvrzení nové adresy.', 'success') + mo.email.send_confirm_change_email(user, rr.email_token) + else: + app.logger.info('Settings: Rate limit') + flash('Příliš mnoho požadavků na změny e-mailu. Počkejte prosím chvíli a zkuste to znovu.', 'danger') + ok = False if ok: return redirect(url_for('user_settings')) @@ -436,6 +440,7 @@ class Reg2: RegStatus.new: 'Chybný potvrzovací kód. Zkontrolujte, že jste odkaz z e-mailu zkopírovali správně.', RegStatus.expired: 'Vypršela platnost potvrzovacího kódu, požádejte prosím o změnu e-mailu znovu.', RegStatus.already_spent: 'Tento odkaz na potvrzení změny e-mailu byl již využit.', + RegStatus.already_exists: 'Tuto adresu už použivá jiný účet.', }, db.RegReqType.reset_passwd: { RegStatus.new: 'Chybný kód pro obnovení hesla. Zkontrolujte, že jste odkaz z e-mailu zkopírovali správně.', @@ -519,9 +524,16 @@ class Reg2: self.user = user return True - def change_email(self): + def change_email(self) -> bool: sess = db.get_session() user = self.rr.user + + if mo.users.user_by_email(self.rr.email) is not None: + app.logger.info(f'Reg2: Uživatel #{user.user_id} si chce změnit email na <{user.email}>, ale už je použitý jiným účtem.') + self.status = RegStatus.already_exists + return False + + # Tady je krátké okénko, kdy může nastat race condition. Chytí ji integritní omezení v DB a vznikne výjimka. user.email = self.rr.email app.logger.info(f'Reg2: Uživatel #{user.user_id} si změnil email na <{user.email}>') @@ -536,6 +548,7 @@ class Reg2: self.rr.used_at = mo.now sess.commit() + return True def change_passwd(self, new_passwd: str): sess = db.get_session() @@ -610,13 +623,15 @@ def confirm_email(): form = ConfirmEmailForm() if form.validate_on_submit(): if form.submit.data: - reg2.change_email() - flash('E-mail změněn.', 'success') + if reg2.change_email(): + flash('E-mail změněn.', 'success') + return redirect(url_for('user_settings')) elif form.cancel.data: reg2.spend_request() flash('Požadavek na změnu e-mailu zrušen.', 'success') - return redirect(url_for('user_settings')) + return redirect(url_for('user_settings')) + reg2.flash_message() form.orig_email.data = reg2.rr.user.email form.new_email.data = reg2.rr.email -- GitLab