diff --git a/tildes/tildes/templates/intercooler/two_factor_backup_codes.jinja2 b/tildes/tildes/templates/intercooler/two_factor_backup_codes.jinja2 new file mode 100644 index 0000000..efd4aaa --- /dev/null +++ b/tildes/tildes/templates/intercooler/two_factor_backup_codes.jinja2 @@ -0,0 +1,6 @@ +{# Copyright (c) 2020 Tildes contributors #} +{# SPDX-License-Identifier: AGPL-3.0-or-later #} + +{% from 'macros/user.jinja2' import two_factor_backup_codes with context %} + +{{ two_factor_backup_codes() }} diff --git a/tildes/tildes/templates/intercooler/two_factor_enabled.jinja2 b/tildes/tildes/templates/intercooler/two_factor_enabled.jinja2 index f0da6b9..29eb2b0 100644 --- a/tildes/tildes/templates/intercooler/two_factor_enabled.jinja2 +++ b/tildes/tildes/templates/intercooler/two_factor_enabled.jinja2 @@ -1,14 +1,8 @@ {# Copyright (c) 2018 Tildes contributors #} {# SPDX-License-Identifier: AGPL-3.0-or-later #} -

Congratulations! Two-factor authentication has been enabled.

- -

These are your backup codes. In the event that you lose access to your authenticator device, you will need one of these codes to regain access to your account (or disable two-factor authentication). Each code can only be used once.

+{% from 'macros/user.jinja2' import two_factor_backup_codes with context %} -

Make sure to write them down and store them in a safe place.

+

Congratulations! Two-factor authentication has been enabled.

-
    -{% for code in backup_codes %} -
  1. {{ code }}
  2. -{% endfor %} -
+{{ two_factor_backup_codes() }} diff --git a/tildes/tildes/templates/macros/user.jinja2 b/tildes/tildes/templates/macros/user.jinja2 index 8876ae0..fff9dd1 100644 --- a/tildes/tildes/templates/macros/user.jinja2 +++ b/tildes/tildes/templates/macros/user.jinja2 @@ -31,3 +31,15 @@ {% endif %} {% endmacro %} + +{% macro two_factor_backup_codes() %} +

These are your backup codes. In the event that you lose access to your authenticator device, you will need one of these codes to regain access to your account (or disable two-factor authentication). Each code can only be used once.

+ +

Make sure to write them down and store them in a safe place.

+ +
    + {% for code in backup_codes %} +
  1. {{ code }}
  2. + {% endfor %} +
+{% endmacro %} diff --git a/tildes/tildes/templates/settings.jinja2 b/tildes/tildes/templates/settings.jinja2 index 65964e4..53365ea 100644 --- a/tildes/tildes/templates/settings.jinja2 +++ b/tildes/tildes/templates/settings.jinja2 @@ -217,8 +217,8 @@ Enable two-factor authentication
For extra security, you can enable two-factor authentication.
{% else %} - Disable two-factor authentication -
Disabling two-factor authentication requires a code from your device or a backup code.
+ Two-factor authentication +
View your backup codes or disable two-factor authentication.
{% endif %} diff --git a/tildes/tildes/templates/settings_two_factor.jinja2 b/tildes/tildes/templates/settings_two_factor.jinja2 index 386a1ee..9dbccc0 100644 --- a/tildes/tildes/templates/settings_two_factor.jinja2 +++ b/tildes/tildes/templates/settings_two_factor.jinja2 @@ -9,7 +9,29 @@ {% block settings %} {% if request.user.two_factor_enabled %} -

You already have two-factor authentication enabled. To disable it, enter a code from your authenticator device below and click the button. If you do not have access to your authenticator device, enter a backup code.

+
+

To view your backup codes, enter a code from your authenticator device below and click the button. If you do not have access to your authenticator device, enter a backup code.

+ +
+
+ + +
+ +
+ +
+
+
+ +
+ +

To disable two-factor authentication, enter a code from your authenticator device below and click the button. If you do not have access to your authenticator device, enter a backup code.

Response: return {} +@ic_view_config( + route_name="user", + request_method="POST", + request_param="ic-trigger-name=view-two-factor-backup-codes", + renderer="two_factor_backup_codes.jinja2", + permission="change_two_factor", +) +@use_kwargs({"code": String()}) +def post_view_two_factor_backup_codes(request: Request, code: str) -> Response: + """Show the user their two-factor authentication backup codes.""" + user = request.context + + if not user.is_correct_two_factor_code(code): + raise HTTPUnauthorized(body="Invalid code") + + # format the backup codes to be easier to read for output + backup_codes = [ + separate_string(code, " ", 4) for code in user.two_factor_backup_codes + ] + + return {"backup_codes": backup_codes} + + @ic_view_config( route_name="user", request_method="PATCH",