From f2f6e13af74d8a199906bae3710f08a25b9035ea Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Sun, 17 May 2020 22:05:37 -0700 Subject: [PATCH 01/21] DB & Setup ready for multi-keys --- .../templates/dashboard/fido_setup.html | 2 ++ app/dashboard/views/fido_setup.py | 14 ++++++++++---- app/models.py | 9 ++++++--- server.py | 17 +++++++++++++++++ static/assets/js/vendors/webauthn.js | 11 +++++++++-- 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/app/dashboard/templates/dashboard/fido_setup.html b/app/dashboard/templates/dashboard/fido_setup.html index f82b8895..8770fd18 100644 --- a/app/dashboard/templates/dashboard/fido_setup.html +++ b/app/dashboard/templates/dashboard/fido_setup.html @@ -33,6 +33,8 @@ JSON.parse('{{credential_create_options|tojson|safe}}') ) + console.log(pkCredentialCreateOptions) + let credential try { credential = await navigator.credentials.create({ diff --git a/app/dashboard/views/fido_setup.py b/app/dashboard/views/fido_setup.py index bf1b00fd..50ffe3b2 100644 --- a/app/dashboard/views/fido_setup.py +++ b/app/dashboard/views/fido_setup.py @@ -12,6 +12,7 @@ from app.config import RP_ID, URL from app.dashboard.base import dashboard_bp from app.extensions import db from app.log import LOG +from app.models import FIDO class FidoTokenForm(FlaskForm): @@ -21,10 +22,6 @@ class FidoTokenForm(FlaskForm): @dashboard_bp.route("/fido_setup", methods=["GET", "POST"]) @login_required def fido_setup(): - if current_user.fido_enabled(): - flash("You have already registered your security key", "warning") - return redirect(url_for("dashboard.index")) - if not current_user.can_use_fido: flash( "This feature is currently in invitation-only beta. Please send us an email if you want to try", @@ -32,6 +29,8 @@ def fido_setup(): ) return redirect(url_for("dashboard.index")) + fido_model = FIDO.filter_by(uuid=current_user.fido_uuid).all() + fido_token_form = FidoTokenForm() # Handling POST requests @@ -91,6 +90,13 @@ def fido_setup(): registration_dict = credential_create_options.registration_dict del registration_dict["extensions"]["webauthn.loc"] + for record in fido_model: + registration_dict["excludeCredentials"].append({ + 'type': 'public-key', + 'id': record.credential_id, + 'transports': ['usb', 'nfc', 'ble', 'internal'], + }) + session["fido_uuid"] = fido_uuid session["fido_challenge"] = challenge.rstrip("=") diff --git a/app/models.py b/app/models.py index 7ce2f710..72747c50 100644 --- a/app/models.py +++ b/app/models.py @@ -119,6 +119,12 @@ class AliasGeneratorEnum(EnumE): word = 1 # aliases are generated based on random words uuid = 2 # aliases are generated based on uuid +class FIDO(db.Model, ModelMixin): + __tablename__ = "fido" + credential_id = db.Column(db.String(), nullable=False, unique=True, index=True) + uuid = db.Column(db.ForeignKey("users.fido_uuid", ondelete="cascade"), unique=False, nullable=False) + public_key = db.Column(db.String(), nullable=False, unique=True) + sign_count = db.Column(db.Integer(), nullable=False) class User(db.Model, ModelMixin, UserMixin): __tablename__ = "users" @@ -150,9 +156,6 @@ class User(db.Model, ModelMixin, UserMixin): # Fields for WebAuthn fido_uuid = db.Column(db.String(), nullable=True, unique=True) - fido_credential_id = db.Column(db.String(), nullable=True, unique=True) - fido_pk = db.Column(db.String(), nullable=True, unique=True) - fido_sign_count = db.Column(db.Integer(), nullable=True) # whether user can use Fido can_use_fido = db.Column( diff --git a/server.py b/server.py index d29727a7..2576e042 100644 --- a/server.py +++ b/server.py @@ -38,6 +38,7 @@ from app.log import LOG from app.models import ( Client, User, + FIDO, ClientUser, Alias, RedirectUri, @@ -142,8 +143,24 @@ def fake_data(): otp_secret="base32secret3232", can_use_fido=True, intro_shown=True, + fido_uuid="59576167-6c37-4d67-943b-4683b24ff821", ) db.session.commit() + + fido = FIDO.create( + credential_id = "umR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", + uuid = "59576167-6c37-4d67-943b-4683b24ff821", + public_key = "pQECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", + sign_count = 1, + ) + fido = FIDO.create( + credential_id = "1mR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", + uuid = "59576167-6c37-4d67-943b-4683b24ff821", + public_key = "1QECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", + sign_count = 1, + ) + db.session.commit() + user.trial_end = None LifetimeCoupon.create(code="coupon", nb_used=10) diff --git a/static/assets/js/vendors/webauthn.js b/static/assets/js/vendors/webauthn.js index 85a8ac22..5604a41f 100644 --- a/static/assets/js/vendors/webauthn.js +++ b/static/assets/js/vendors/webauthn.js @@ -56,7 +56,7 @@ const transformCredentialRequestOptions = ( const transformCredentialCreateOptions = ( credentialCreateOptionsFromServer ) => { - let { challenge, user } = credentialCreateOptionsFromServer; + let { challenge, user, excludeCredentials } = credentialCreateOptionsFromServer; user.id = Uint8Array.from( atob( credentialCreateOptionsFromServer.user.id @@ -75,10 +75,17 @@ const transformCredentialCreateOptions = ( (c) => c.charCodeAt(0) ); + excludeCredentials = excludeCredentials.map((credentialDescriptor) => { + let { id } = credentialDescriptor; + id = id.replace(/\_/g, "/").replace(/\-/g, "+"); + id = Uint8Array.from(atob(id), (c) => c.charCodeAt(0)); + return Object.assign({}, credentialDescriptor, { id }); + }); + const transformedCredentialCreateOptions = Object.assign( {}, credentialCreateOptionsFromServer, - { challenge, user } + { challenge, user, excludeCredentials } ); return transformedCredentialCreateOptions; From 9fb91c83e7673e5e5957fe14b4938156f13b92de Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 00:01:27 -0700 Subject: [PATCH 02/21] more setup --- app/dashboard/views/fido_setup.py | 23 +++++++++++++++++------ server.py | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/dashboard/views/fido_setup.py b/app/dashboard/views/fido_setup.py index 50ffe3b2..a70bc8ee 100644 --- a/app/dashboard/views/fido_setup.py +++ b/app/dashboard/views/fido_setup.py @@ -29,7 +29,10 @@ def fido_setup(): ) return redirect(url_for("dashboard.index")) - fido_model = FIDO.filter_by(uuid=current_user.fido_uuid).all() + if current_user.fido_uuid is not None: + fido_model = FIDO.filter_by(uuid=current_user.fido_uuid).all() + else: + fido_model = [] fido_token_form = FidoTokenForm() @@ -59,18 +62,25 @@ def fido_setup(): LOG.error(f"An error occurred in WebAuthn registration process: {e}") flash("Key registration failed.", "warning") return redirect(url_for("dashboard.index")) + + if current_user.fido_uuid is None: + current_user.fido_uuid = fido_uuid - current_user.fido_pk = str(fido_credential.public_key, "utf-8") - current_user.fido_uuid = fido_uuid - current_user.fido_sign_count = fido_credential.sign_count - current_user.fido_credential_id = str(fido_credential.credential_id, "utf-8") + FIDO.create( + credential_id = str(fido_credential.credential_id, "utf-8"), + uuid = fido_uuid, + public_key = str(fido_credential.public_key, "utf-8"), + sign_count = fido_credential.sign_count, + ) db.session.commit() + LOG.d(f"credential_id={str(fido_credential.credential_id, 'utf-8')} added for {fido_uuid}") + flash("Security key has been activated", "success") return redirect(url_for("dashboard.recovery_code_route")) # Prepare information for key registration process - fido_uuid = str(uuid.uuid4()) + fido_uuid = str(uuid.uuid4()) if current_user.fido_uuid is None else current_user.fido_uuid challenge = secrets.token_urlsafe(32) credential_create_options = webauthn.WebAuthnMakeCredentialOptions( @@ -90,6 +100,7 @@ def fido_setup(): registration_dict = credential_create_options.registration_dict del registration_dict["extensions"]["webauthn.loc"] + # Prevent user from adding duplicated keys for record in fido_model: registration_dict["excludeCredentials"].append({ 'type': 'public-key', diff --git a/server.py b/server.py index 2576e042..e15fd372 100644 --- a/server.py +++ b/server.py @@ -147,13 +147,13 @@ def fake_data(): ) db.session.commit() - fido = FIDO.create( + FIDO.create( credential_id = "umR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", uuid = "59576167-6c37-4d67-943b-4683b24ff821", public_key = "pQECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", sign_count = 1, ) - fido = FIDO.create( + FIDO.create( credential_id = "1mR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", uuid = "59576167-6c37-4d67-943b-4683b24ff821", public_key = "1QECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", From 2b8febe0b9ab3d7f4049a5e30305e9749fce501b Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 00:06:24 -0700 Subject: [PATCH 03/21] black --- app/dashboard/views/fido_setup.py | 30 ++++++++++++++++++------------ app/models.py | 8 +++++++- server.py | 16 ++++++++-------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/app/dashboard/views/fido_setup.py b/app/dashboard/views/fido_setup.py index a70bc8ee..14c1b471 100644 --- a/app/dashboard/views/fido_setup.py +++ b/app/dashboard/views/fido_setup.py @@ -62,25 +62,29 @@ def fido_setup(): LOG.error(f"An error occurred in WebAuthn registration process: {e}") flash("Key registration failed.", "warning") return redirect(url_for("dashboard.index")) - + if current_user.fido_uuid is None: current_user.fido_uuid = fido_uuid FIDO.create( - credential_id = str(fido_credential.credential_id, "utf-8"), - uuid = fido_uuid, - public_key = str(fido_credential.public_key, "utf-8"), - sign_count = fido_credential.sign_count, + credential_id=str(fido_credential.credential_id, "utf-8"), + uuid=fido_uuid, + public_key=str(fido_credential.public_key, "utf-8"), + sign_count=fido_credential.sign_count, ) db.session.commit() - LOG.d(f"credential_id={str(fido_credential.credential_id, 'utf-8')} added for {fido_uuid}") + LOG.d( + f"credential_id={str(fido_credential.credential_id, 'utf-8')} added for {fido_uuid}" + ) flash("Security key has been activated", "success") return redirect(url_for("dashboard.recovery_code_route")) # Prepare information for key registration process - fido_uuid = str(uuid.uuid4()) if current_user.fido_uuid is None else current_user.fido_uuid + fido_uuid = ( + str(uuid.uuid4()) if current_user.fido_uuid is None else current_user.fido_uuid + ) challenge = secrets.token_urlsafe(32) credential_create_options = webauthn.WebAuthnMakeCredentialOptions( @@ -102,11 +106,13 @@ def fido_setup(): # Prevent user from adding duplicated keys for record in fido_model: - registration_dict["excludeCredentials"].append({ - 'type': 'public-key', - 'id': record.credential_id, - 'transports': ['usb', 'nfc', 'ble', 'internal'], - }) + registration_dict["excludeCredentials"].append( + { + "type": "public-key", + "id": record.credential_id, + "transports": ["usb", "nfc", "ble", "internal"], + } + ) session["fido_uuid"] = fido_uuid session["fido_challenge"] = challenge.rstrip("=") diff --git a/app/models.py b/app/models.py index 72747c50..4d5f57c3 100644 --- a/app/models.py +++ b/app/models.py @@ -119,13 +119,19 @@ class AliasGeneratorEnum(EnumE): word = 1 # aliases are generated based on random words uuid = 2 # aliases are generated based on uuid + class FIDO(db.Model, ModelMixin): __tablename__ = "fido" credential_id = db.Column(db.String(), nullable=False, unique=True, index=True) - uuid = db.Column(db.ForeignKey("users.fido_uuid", ondelete="cascade"), unique=False, nullable=False) + uuid = db.Column( + db.ForeignKey("users.fido_uuid", ondelete="cascade"), + unique=False, + nullable=False, + ) public_key = db.Column(db.String(), nullable=False, unique=True) sign_count = db.Column(db.Integer(), nullable=False) + class User(db.Model, ModelMixin, UserMixin): __tablename__ = "users" email = db.Column(db.String(256), unique=True, nullable=False) diff --git a/server.py b/server.py index e15fd372..3e20335e 100644 --- a/server.py +++ b/server.py @@ -148,16 +148,16 @@ def fake_data(): db.session.commit() FIDO.create( - credential_id = "umR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", - uuid = "59576167-6c37-4d67-943b-4683b24ff821", - public_key = "pQECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", - sign_count = 1, + credential_id="umR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", + uuid="59576167-6c37-4d67-943b-4683b24ff821", + public_key="pQECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", + sign_count=1, ) FIDO.create( - credential_id = "1mR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", - uuid = "59576167-6c37-4d67-943b-4683b24ff821", - public_key = "1QECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", - sign_count = 1, + credential_id="1mR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", + uuid="59576167-6c37-4d67-943b-4683b24ff821", + public_key="1QECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", + sign_count=1, ) db.session.commit() From ec91d280bb2b8891d76b09879eac70ebb65709a4 Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 00:08:06 -0700 Subject: [PATCH 04/21] Verify --- app/auth/views/fido.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/app/auth/views/fido.py b/app/auth/views/fido.py index 472747ac..0b1395ef 100644 --- a/app/auth/views/fido.py +++ b/app/auth/views/fido.py @@ -12,7 +12,7 @@ from app.config import MFA_USER_ID from app.config import RP_ID, URL from app.extensions import db from app.log import LOG -from app.models import User +from app.models import User, FIDO class FidoTokenForm(FlaskForm): @@ -40,16 +40,21 @@ def fido(): next_url = request.args.get("next") - webauthn_user = webauthn.WebAuthnUser( - user.fido_uuid, - user.email, - user.name if user.name else user.email, - False, - user.fido_credential_id, - user.fido_pk, - user.fido_sign_count, - RP_ID, - ) + fido_model = FIDO.filter_by(uuid=user.fido_uuid).all() + webauthn_users = [] + for record in fido_model: + webauthn_users.append( + webauthn.WebAuthnUser( + user.fido_uuid, + user.email, + user.name if user.name else user.email, + False, + record.credential_id, + record.public_key, + record.sign_count, + RP_ID, + ) + ) # Handling POST requests if fido_token_form.validate_on_submit(): @@ -62,7 +67,7 @@ def fido(): challenge = session["fido_challenge"] webauthn_assertion_response = webauthn.WebAuthnAssertionResponse( - webauthn_user, sk_assertion, challenge, URL, uv_required=False + webauthn_users, sk_assertion, challenge, URL, uv_required=False ) try: @@ -94,7 +99,7 @@ def fido(): session["fido_challenge"] = challenge.rstrip("=") webauthn_assertion_options = webauthn.WebAuthnAssertionOptions( - webauthn_user, challenge + webauthn_users, challenge ) webauthn_assertion_options = webauthn_assertion_options.assertion_dict From 419aa95f1f64906abbf8620dd8519e6c808ff4a3 Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 01:02:58 -0700 Subject: [PATCH 05/21] more verify --- app/auth/views/fido.py | 51 ++++++++++++++++++++++++++---------------- server.py | 4 ++-- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/app/auth/views/fido.py b/app/auth/views/fido.py index 0b1395ef..a752e962 100644 --- a/app/auth/views/fido.py +++ b/app/auth/views/fido.py @@ -40,21 +40,6 @@ def fido(): next_url = request.args.get("next") - fido_model = FIDO.filter_by(uuid=user.fido_uuid).all() - webauthn_users = [] - for record in fido_model: - webauthn_users.append( - webauthn.WebAuthnUser( - user.fido_uuid, - user.email, - user.name if user.name else user.email, - False, - record.credential_id, - record.public_key, - record.sign_count, - RP_ID, - ) - ) # Handling POST requests if fido_token_form.validate_on_submit(): @@ -66,11 +51,23 @@ def fido(): challenge = session["fido_challenge"] - webauthn_assertion_response = webauthn.WebAuthnAssertionResponse( - webauthn_users, sk_assertion, challenge, URL, uv_required=False - ) - try: + fido_key = FIDO.get_by( + uuid=user.fido_uuid, credential_id=sk_assertion["id"] + ) + webauthn_user = webauthn.WebAuthnUser( + user.fido_uuid, + user.email, + user.name if user.name else user.email, + False, + fido_key.credential_id, + fido_key.public_key, + fido_key.sign_count, + RP_ID, + ) + webauthn_assertion_response = webauthn.WebAuthnAssertionResponse( + webauthn_user, sk_assertion, challenge, URL, uv_required=False + ) new_sign_count = webauthn_assertion_response.verify() except Exception as e: LOG.error(f"An error occurred in WebAuthn verification process: {e}") @@ -98,6 +95,22 @@ def fido(): session["fido_challenge"] = challenge.rstrip("=") + fido_model = FIDO.filter_by(uuid=user.fido_uuid).all() + webauthn_users = [] + for record in fido_model: + webauthn_users.append( + webauthn.WebAuthnUser( + user.fido_uuid, + user.email, + user.name if user.name else user.email, + False, + record.credential_id, + record.public_key, + record.sign_count, + RP_ID, + ) + ) + webauthn_assertion_options = webauthn.WebAuthnAssertionOptions( webauthn_users, challenge ) diff --git a/server.py b/server.py index 3e20335e..a219b23d 100644 --- a/server.py +++ b/server.py @@ -154,9 +154,9 @@ def fake_data(): sign_count=1, ) FIDO.create( - credential_id="1mR9q5vX61XG7vh7gi8wT0gJ9LkYwHKSzDL5vhtZs3o", + credential_id="4SaUPugJ2sAErSnZil6_5_wXIL-Sk6QdFmNm94IL-_g", uuid="59576167-6c37-4d67-943b-4683b24ff821", - public_key="1QECAyYgASFYIEjQg3TOuUZJxylLE6gJDNHcNyYVW5hOAZ-vGOY9I_TDIlggfJqIh07bj3n6RVmrEsuozsYPYM6VeJKCeduz0DFp8AY", + public_key="pQECAyYgASFYILfse0JIp0a7Gz7n1K8b75_OgV-iliKr52FB-BGzv2R2IlggsPcViY5Dma8XooLWUHtx7X2_px0MsFR_7VRMwT2OHKg", sign_count=1, ) db.session.commit() From 35f0c094fe873d1c3568faa4f70108de40c75532 Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 01:04:45 -0700 Subject: [PATCH 06/21] black --- app/auth/views/fido.py | 3 +-- app/dashboard/templates/dashboard/fido_setup.html | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/auth/views/fido.py b/app/auth/views/fido.py index a752e962..741573af 100644 --- a/app/auth/views/fido.py +++ b/app/auth/views/fido.py @@ -40,7 +40,6 @@ def fido(): next_url = request.args.get("next") - # Handling POST requests if fido_token_form.validate_on_submit(): try: @@ -110,7 +109,7 @@ def fido(): RP_ID, ) ) - + webauthn_assertion_options = webauthn.WebAuthnAssertionOptions( webauthn_users, challenge ) diff --git a/app/dashboard/templates/dashboard/fido_setup.html b/app/dashboard/templates/dashboard/fido_setup.html index 8770fd18..88318034 100644 --- a/app/dashboard/templates/dashboard/fido_setup.html +++ b/app/dashboard/templates/dashboard/fido_setup.html @@ -33,7 +33,6 @@ JSON.parse('{{credential_create_options|tojson|safe}}') ) - console.log(pkCredentialCreateOptions) let credential try { From f79eb90d2a137c74351b60998f556d738463b9c3 Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 02:14:40 -0700 Subject: [PATCH 07/21] sudo mode --- app/dashboard/__init__.py | 1 + .../templates/dashboard/enter_sudo.html | 31 +++++++++++ app/dashboard/views/enter_sudo.py | 55 +++++++++++++++++++ app/dashboard/views/fido_setup.py | 4 +- app/dashboard/views/mfa_cancel.py | 2 + app/dashboard/views/mfa_setup.py | 2 + 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 app/dashboard/templates/dashboard/enter_sudo.html create mode 100644 app/dashboard/views/enter_sudo.py diff --git a/app/dashboard/__init__.py b/app/dashboard/__init__.py index 7a6fcabd..16ca9962 100644 --- a/app/dashboard/__init__.py +++ b/app/dashboard/__init__.py @@ -9,6 +9,7 @@ from .views import ( api_key, custom_domain, alias_contact_manager, + enter_sudo, mfa_setup, mfa_cancel, fido_setup, diff --git a/app/dashboard/templates/dashboard/enter_sudo.html b/app/dashboard/templates/dashboard/enter_sudo.html new file mode 100644 index 00000000..934f7aa3 --- /dev/null +++ b/app/dashboard/templates/dashboard/enter_sudo.html @@ -0,0 +1,31 @@ +{% extends 'default.html' %} +{% set active_page = "setting" %} +{% block title %} + SUDO MODE +{% endblock %} + + +{% block default_content %} +
+ You are trying to change sensitive settings +
++ Please enter the password of your account so that we can ensure it's you. +
+ + + +- Please enter the password of your account so that we can ensure it's you. -
- - - -Delete all keys will also disable WebAuthn 2FA.
+Unlink all keys will also disable WebAuthn 2FA.