From a907f261a577bbec389841ff7b07ddc0a6c8d118 Mon Sep 17 00:00:00 2001 From: Pea Tyczynska Date: Tue, 18 May 2021 14:50:25 +0100 Subject: [PATCH] Catch last credential error from API When we are unable to delete security key because it's the last one for that user, API throws an error. Here we catch that error and display useful message to the user. Use security key instead of webauthn credential in user facing message - for consistency and readability. We use security key term in user facing stuff and webauthn credential in the code. --- app/main/views/user_profile.py | 19 +++++++++++--- tests/app/main/views/test_user_profile.py | 31 +++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/main/views/user_profile.py b/app/main/views/user_profile.py index a53d0f76f..e994983f7 100644 --- a/app/main/views/user_profile.py +++ b/app/main/views/user_profile.py @@ -11,6 +11,7 @@ from flask import ( url_for, ) from flask_login import current_user +from notifications_python_client.errors import HTTPError from notifications_utils.url_safe_token import check_token from app import user_api_client @@ -283,8 +284,18 @@ def user_profile_manage_security_key(key_id): @main.route("/user-profile/security-keys//delete", methods=['POST']) @user_is_platform_admin def user_profile_delete_security_key(key_id): - user_api_client.delete_webauthn_credential_for_user( - user_id=current_user.id, - credential_id=key_id - ) + + try: + user_api_client.delete_webauthn_credential_for_user( + user_id=current_user.id, + credential_id=key_id + ) + except HTTPError as e: + message = "Cannot delete last remaining webauthn credential for user" + if e.message == message: + flash("You cannot delete your last security key.") + return redirect(url_for('.user_profile_manage_security_key', key_id=key_id)) + else: + raise e + return redirect(url_for('.user_profile_security_keys')) diff --git a/tests/app/main/views/test_user_profile.py b/tests/app/main/views/test_user_profile.py index 97300d072..c03efa40d 100644 --- a/tests/app/main/views/test_user_profile.py +++ b/tests/app/main/views/test_user_profile.py @@ -3,6 +3,7 @@ import uuid import pytest from flask import url_for +from notifications_python_client.errors import HTTPError from notifications_utils.url_safe_token import generate_token from tests.conftest import ( @@ -539,3 +540,33 @@ def test_delete_security_key( credential_id=webauthn_credential['id'], user_id=platform_admin_user["id"] ) + + +def test_delete_security_key_handles_last_credential_error( + client_request, + platform_admin_user, + webauthn_credential, + mocker, +): + client_request.login(platform_admin_user) + mocker.patch( + 'app.user_api_client.get_webauthn_credentials_for_user', + return_value=[webauthn_credential], + ) + + mocker.patch( + 'app.user_api_client.delete_webauthn_credential_for_user', + side_effect=HTTPError( + response={}, + message='Cannot delete last remaining webauthn credential for user' + ) + ) + + page = client_request.post( + '.user_profile_delete_security_key', + key_id=webauthn_credential['id'], + _follow_redirects=True + ) + assert 'Manage ‘Test credential’' in page.find('h1').text + expected_message = "You cannot delete your last security key." + assert expected_message in page.find('div', class_="banner-dangerous").text