diff --git a/canaille/core/endpoints/auth.py b/canaille/core/endpoints/auth.py index 1d794cbf..efb9d574 100644 --- a/canaille/core/endpoints/auth.py +++ b/canaille/core/endpoints/auth.py @@ -121,7 +121,7 @@ def password(): if otp_methods: session["remaining_otp_methods"] = otp_methods session["attempt_login_with_correct_password"] = session.pop("attempt_login") - return redirect_to_verify_2fa( + return redirect_to_verify_mfa( user, otp_methods[0], request_ip, url_for("core.auth.password") ) else: @@ -277,7 +277,7 @@ def reset(user, hash): return render_template("core/reset-password.html", form=form, user=user, hash=hash) -@bp.route("/setup-2fa") +@bp.route("/setup-mfa") def setup_two_factor_auth(): if not current_app.features.has_otp: abort(404) @@ -298,14 +298,14 @@ def setup_two_factor_auth(): uri = user.get_otp_authentication_setup_uri() base64_qr_image = get_b64encoded_qr_image(uri) return render_template( - "core/setup-2fa.html", + "core/setup-mfa.html", secret=user.secret_token, qr_image=base64_qr_image, user=user, ) -@bp.route("/verify-2fa", methods=["GET", "POST"]) +@bp.route("/verify-mfa", methods=["GET", "POST"]) def verify_two_factor_auth(): if current_user(): return redirect( @@ -335,7 +335,7 @@ def verify_two_factor_auth(): if not request.form or form.form_control(): return render_template( - "core/verify-2fa.html", + "core/verify-mfa.html", form=form, username=session["attempt_login_with_correct_password"], method=current_otp_method, @@ -349,7 +349,7 @@ def verify_two_factor_auth(): session["remaining_otp_methods"].pop(0) request_ip = request.remote_addr or "unknown IP" if session["remaining_otp_methods"]: - return redirect_to_verify_2fa( + return redirect_to_verify_mfa( user, session["remaining_otp_methods"][0], request_ip, @@ -465,7 +465,7 @@ def send_sms_otp(): return redirect(url_for("core.auth.verify_two_factor_auth")) -def redirect_to_verify_2fa(user, otp_method, request_ip, fail_redirect_url): +def redirect_to_verify_mfa(user, otp_method, request_ip, fail_redirect_url): if otp_method in ["HOTP", "TOTP"]: if not user.last_otp_login: flash( diff --git a/canaille/templates/core/setup-2fa.html b/canaille/templates/core/setup-mfa.html similarity index 100% rename from canaille/templates/core/setup-2fa.html rename to canaille/templates/core/setup-mfa.html diff --git a/canaille/templates/core/verify-2fa.html b/canaille/templates/core/verify-mfa.html similarity index 100% rename from canaille/templates/core/verify-2fa.html rename to canaille/templates/core/verify-mfa.html diff --git a/tests/core/test_email_sms_otp.py b/tests/core/test_email_sms_otp.py index 6611c15c..4b6d06ae 100644 --- a/tests/core/test_email_sms_otp.py +++ b/tests/core/test_email_sms_otp.py @@ -16,7 +16,7 @@ def test_email_otp_disabled(testclient): with testclient.session_transaction() as session: session["remaining_otp_methods"] = ["EMAIL_OTP"] session["attempt_login_with_correct_password"] = "id" - testclient.get("/verify-2fa", status=404) + testclient.get("/verify-mfa", status=404) testclient.app.config["WTF_CSRF_ENABLED"] = False testclient.post("/send-mail-otp", status=404) @@ -27,7 +27,7 @@ def test_sms_otp_disabled(testclient): with testclient.session_transaction() as session: session["remaining_otp_methods"] = ["SMS_OTP"] session["attempt_login_with_correct_password"] = "id" - testclient.get("/verify-2fa", status=404) + testclient.get("/verify-mfa", status=404) testclient.app.config["WTF_CSRF_ENABLED"] = False testclient.post("/send-sms-otp", status=404) @@ -64,7 +64,7 @@ def test_signin_and_out_with_email_otp(smtpd, testclient, backend, user, caplog) assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") backend.reload(user) otp = user.one_time_password @@ -266,7 +266,7 @@ def test_signin_and_out_with_sms_otp(testclient, backend, user, caplog, mock_smp assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") backend.reload(user) otp = user.one_time_password @@ -373,7 +373,7 @@ def test_verify_mail_or_sms_otp_page_without_signin_in_redirects_to_login_page( ): testclient.app.config["CANAILLE"][otp_method] = True - res = testclient.get("/verify-2fa", status=302) + res = testclient.get("/verify-mfa", status=302) assert res.location == "/login" assert res.flashes == [ ("warning", "Cannot remember the login you attempted to sign in with") @@ -386,7 +386,7 @@ def test_verify_mail_or_sms_otp_page_already_logged_in( ): testclient.app.config["CANAILLE"][otp_method] = True - res = testclient.get("/verify-2fa", status=302) + res = testclient.get("/verify-mfa", status=302) assert res.location == "/profile/user" @@ -458,7 +458,7 @@ def test_send_new_mail_otp(smtpd, testclient, backend, user, caplog): "Sent one-time password for user to john@doe.test from unknown IP", ) in caplog.record_tuples - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" def test_send_mail_otp_multiple_attempts(testclient, backend, user, caplog): @@ -470,7 +470,7 @@ def test_send_mail_otp_multiple_attempts(testclient, backend, user, caplog): session["attempt_login_with_correct_password"] = user.user_name res = testclient.post("/send-mail-otp", status=302) - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" traveller.shift(datetime.timedelta(seconds=SEND_NEW_OTP_DELAY - 1)) res = testclient.post("/send-mail-otp", status=302) @@ -478,7 +478,7 @@ def test_send_mail_otp_multiple_attempts(testclient, backend, user, caplog): "danger", f"Too many attempts. Please try again in {SEND_NEW_OTP_DELAY} seconds.", ) in res.flashes - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" traveller.shift(datetime.timedelta(seconds=1)) @@ -503,7 +503,7 @@ def test_send_new_mail_otp_failed(testclient, user): "Error while sending one-time password. Please try again.", ) in res.flashes - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" def test_send_new_sms_otp(testclient, backend, user, caplog, mock_smpp): @@ -529,7 +529,7 @@ def test_send_new_sms_otp(testclient, backend, user, caplog, mock_smpp): "Sent one-time password for user to 555-000-000 from unknown IP", ) in caplog.record_tuples - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" def test_send_sms_otp_multiple_attempts(testclient, backend, user, caplog, mock_smpp): @@ -541,7 +541,7 @@ def test_send_sms_otp_multiple_attempts(testclient, backend, user, caplog, mock_ session["attempt_login_with_correct_password"] = user.user_name res = testclient.post("/send-sms-otp", status=302) - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" traveller.shift(datetime.timedelta(seconds=SEND_NEW_OTP_DELAY - 1)) res = testclient.post("/send-sms-otp", status=302) @@ -549,7 +549,7 @@ def test_send_sms_otp_multiple_attempts(testclient, backend, user, caplog, mock_ "danger", f"Too many attempts. Please try again in {SEND_NEW_OTP_DELAY} seconds.", ) in res.flashes - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" traveller.shift(datetime.timedelta(seconds=1)) @@ -574,7 +574,7 @@ def test_send_new_sms_otp_failed(testclient, user): "Error while sending one-time password. Please try again.", ) in res.flashes - assert res.location == "/verify-2fa" + assert res.location == "/verify-mfa" def test_signin_with_multiple_otp_methods( @@ -604,12 +604,12 @@ def test_signin_with_multiple_otp_methods( assert "user" == session.get("attempt_login_with_correct_password") # TOTP/HOTP - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") res.form["otp"] = user_otp.generate_otp() res = res.form.submit(status=302).follow(status=200) # EMAIL_OTP - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") backend.reload(user_otp) otp = user_otp.one_time_password main_form = res.forms[0] @@ -617,7 +617,7 @@ def test_signin_with_multiple_otp_methods( res = main_form.submit(status=302).follow(status=200) # SMS_OTP - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") backend.reload(user_otp) otp = user_otp.one_time_password main_form = res.forms[0] diff --git a/tests/core/test_totp_hotp.py b/tests/core/test_totp_hotp.py index e3e6470e..96ea658b 100644 --- a/tests/core/test_totp_hotp.py +++ b/tests/core/test_totp_hotp.py @@ -13,8 +13,8 @@ def test_otp_disabled(testclient): with testclient.session_transaction() as session: session["remaining_otp_methods"] = ["TOTP"] session["attempt_login_with_correct_password"] = "id" - testclient.get("/setup-2fa", status=404) - testclient.get("/verify-2fa", status=404) + testclient.get("/setup-mfa", status=404) + testclient.get("/verify-mfa", status=404) @pytest.mark.parametrize("otp_method", ["TOTP", "HOTP"]) @@ -45,7 +45,7 @@ def test_signin_and_out_with_otp(testclient, user_otp, caplog, otp_method): assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") res.form["otp"] = user_otp.generate_otp() res = res.form.submit(status=302) @@ -174,15 +174,15 @@ def test_new_user_setup_otp(testclient, backend, caplog, otp_method): res.form["password"] = "correct horse battery staple" res = res.form.submit(status=302) - assert res.location == "/setup-2fa" + assert res.location == "/setup-mfa" assert ( "info", "You have not enabled multi-factor authentication. Please enable it first to login.", ) in res.flashes - res = testclient.get("/setup-2fa", status=200) + res = testclient.get("/setup-mfa", status=200) assert u.secret_token == res.form["secret"].value - res = testclient.get("/verify-2fa", status=200) + res = testclient.get("/verify-mfa", status=200) res.form["otp"] = u.generate_otp() res = res.form.submit(status=302) @@ -213,7 +213,7 @@ def test_verify_otp_page_without_signin_in_redirects_to_login_page( ): testclient.app.config["CANAILLE"]["OTP_METHOD"] = otp_method - res = testclient.get("/verify-2fa", status=302) + res = testclient.get("/verify-mfa", status=302) assert res.location == "/login" assert res.flashes == [ ("warning", "Cannot remember the login you attempted to sign in with") @@ -226,7 +226,7 @@ def test_setup_otp_page_without_signin_in_redirects_to_login_page( ): testclient.app.config["CANAILLE"]["OTP_METHOD"] = otp_method - res = testclient.get("/setup-2fa", status=302) + res = testclient.get("/setup-mfa", status=302) assert res.location == "/login" assert res.flashes == [ ("warning", "Cannot remember the login you attempted to sign in with") @@ -237,7 +237,7 @@ def test_setup_otp_page_without_signin_in_redirects_to_login_page( def test_verify_otp_page_already_logged_in(testclient, logged_user_otp, otp_method): testclient.app.config["CANAILLE"]["OTP_METHOD"] = otp_method - res = testclient.get("/verify-2fa", status=302) + res = testclient.get("/verify-mfa", status=302) assert res.location == "/profile/user" @@ -266,7 +266,7 @@ def test_signin_multiple_attempts_doesnt_desynchronize_hotp( assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") for _x in range(3): res.form["otp"] = "111111" res = res.form.submit(status=302).follow() @@ -290,7 +290,7 @@ def test_signin_multiple_attempts_doesnt_desynchronize_hotp( def test_setup_otp_page_already_logged_in(testclient, logged_user_otp, otp_method): testclient.app.config["CANAILLE"]["OTP_METHOD"] = otp_method - res = testclient.get("/setup-2fa", status=302) + res = testclient.get("/setup-mfa", status=302) assert res.location == "/profile/user" @@ -319,7 +319,7 @@ def test_signin_inside_hotp_look_ahead_window(testclient, backend, user_otp, cap assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") res.form["otp"] = user_otp.generate_otp(HOTP_LOOK_AHEAD_WINDOW) res = res.form.submit(status=302) @@ -365,7 +365,7 @@ def test_signin_outside_hotp_look_ahead_window(testclient, backend, user_otp, ca assert "attempt_login" not in session assert "user" == session.get("attempt_login_with_correct_password") - res = testclient.get("/verify-2fa") + res = testclient.get("/verify-mfa") res.form["otp"] = user_otp.generate_otp(HOTP_LOOK_AHEAD_WINDOW + 1) res = res.form.submit(status=302)