From b19754a45ff6e6b784fc698dcac19a7f588b66e9 Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Thu, 2 Nov 2023 16:16:41 -0400 Subject: [PATCH 1/6] upgrade django-two-factor-auth to v1.15.5 --- requirements/dev-requirements.txt | 2 +- requirements/docs-requirements.txt | 2 +- requirements/prod-requirements.txt | 2 +- requirements/requirements.txt | 2 +- requirements/test-requirements.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements/dev-requirements.txt b/requirements/dev-requirements.txt index 42444a9b7443..e7151c546d62 100644 --- a/requirements/dev-requirements.txt +++ b/requirements/dev-requirements.txt @@ -214,7 +214,7 @@ django-tastypie==0.14.4 # via -r base-requirements.in django-transfer==0.4 # via -r base-requirements.in -django-two-factor-auth==1.13.2 +django-two-factor-auth==1.15.5 # via -r base-requirements.in django-user-agents==0.4.0 # via -r base-requirements.in diff --git a/requirements/docs-requirements.txt b/requirements/docs-requirements.txt index e5b2fbb0c727..d579e709cd4d 100644 --- a/requirements/docs-requirements.txt +++ b/requirements/docs-requirements.txt @@ -188,7 +188,7 @@ django-tastypie==0.14.4 # via -r base-requirements.in django-transfer==0.4 # via -r base-requirements.in -django-two-factor-auth==1.13.2 +django-two-factor-auth==1.15.5 # via -r base-requirements.in django-user-agents==0.4.0 # via -r base-requirements.in diff --git a/requirements/prod-requirements.txt b/requirements/prod-requirements.txt index b7b2f8d24815..b7867e841932 100644 --- a/requirements/prod-requirements.txt +++ b/requirements/prod-requirements.txt @@ -189,7 +189,7 @@ django-tastypie==0.14.4 # via -r base-requirements.in django-transfer==0.4 # via -r base-requirements.in -django-two-factor-auth==1.13.2 +django-two-factor-auth==1.15.5 # via -r base-requirements.in django-user-agents==0.4.0 # via -r base-requirements.in diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 975d3ace355c..29a43e618a0e 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -181,7 +181,7 @@ django-tastypie==0.14.4 # via -r base-requirements.in django-transfer==0.4 # via -r base-requirements.in -django-two-factor-auth==1.13.2 +django-two-factor-auth==1.15.5 # via -r base-requirements.in django-user-agents==0.4.0 # via -r base-requirements.in diff --git a/requirements/test-requirements.txt b/requirements/test-requirements.txt index 13b5a88940ac..ac7e9ec80b0d 100644 --- a/requirements/test-requirements.txt +++ b/requirements/test-requirements.txt @@ -192,7 +192,7 @@ django-tastypie==0.14.4 # via -r base-requirements.in django-transfer==0.4 # via -r base-requirements.in -django-two-factor-auth==1.13.2 +django-two-factor-auth==1.15.5 # via -r base-requirements.in django-user-agents==0.4.0 # via -r base-requirements.in From 2af62e5974de463cb5d37bb95c497e354197c041 Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Thu, 2 Nov 2023 16:17:17 -0400 Subject: [PATCH 2/6] resolve breaking changes in v1.14.0 - add two_factor.plugins.phonenumber to INSTALLED_APPS - phone specific logic was moved to two_factor.plugins.phonenumber - the two_factor template tag was renamed to phonenumber see https://github.com/jazzband/django-two-factor-auth/blob/master/CHANGELOG.md#changed-3 --- .../login_and_password/two_factor/core/login.html | 2 +- .../two_factor/core/login_form.html | 2 +- .../two_factor/profile/profile.html | 2 +- corehq/apps/hqwebapp/two_factor_gateways.py | 2 +- corehq/apps/settings/forms.py | 6 ++++-- corehq/apps/settings/tests/test_views.py | 3 ++- corehq/apps/settings/views.py | 11 +++++++---- settings.py | 1 + 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/corehq/apps/domain/templates/login_and_password/two_factor/core/login.html b/corehq/apps/domain/templates/login_and_password/two_factor/core/login.html index 61887c4d673a..102481acf529 100644 --- a/corehq/apps/domain/templates/login_and_password/two_factor/core/login.html +++ b/corehq/apps/domain/templates/login_and_password/two_factor/core/login.html @@ -1,4 +1,4 @@ -{% load i18n two_factor %} +{% load i18n phonenumber %} {% block focus-content %}

diff --git a/corehq/apps/domain/templates/login_and_password/two_factor/core/login_form.html b/corehq/apps/domain/templates/login_and_password/two_factor/core/login_form.html index 92beadb3c119..81967ba38d24 100644 --- a/corehq/apps/domain/templates/login_and_password/two_factor/core/login_form.html +++ b/corehq/apps/domain/templates/login_and_password/two_factor/core/login_form.html @@ -1,4 +1,4 @@ -{% load i18n two_factor %} +{% load i18n phonenumber %}
{% csrf_token %} {% include "two_factor/_wizard_forms.html" %} diff --git a/corehq/apps/domain/templates/login_and_password/two_factor/profile/profile.html b/corehq/apps/domain/templates/login_and_password/two_factor/profile/profile.html index 7f246170a6cb..8b9d41233528 100644 --- a/corehq/apps/domain/templates/login_and_password/two_factor/profile/profile.html +++ b/corehq/apps/domain/templates/login_and_password/two_factor/profile/profile.html @@ -1,5 +1,5 @@ {% extends "hqwebapp/bootstrap3/base_section.html" %} -{% load i18n two_factor %} +{% load i18n phonenumber %} {% block page_content %} {% if is_using_sso %} diff --git a/corehq/apps/hqwebapp/two_factor_gateways.py b/corehq/apps/hqwebapp/two_factor_gateways.py index 2891f444dc00..69ff68b8d28b 100644 --- a/corehq/apps/hqwebapp/two_factor_gateways.py +++ b/corehq/apps/hqwebapp/two_factor_gateways.py @@ -13,7 +13,7 @@ from twilio.base.exceptions import TwilioRestException from twilio.http.http_client import TwilioHttpClient from twilio.rest import Client -from two_factor.models import PhoneDevice +from two_factor.plugins.phonenumber.models import PhoneDevice import settings from corehq.apps.users.models import CouchUser diff --git a/corehq/apps/settings/forms.py b/corehq/apps/settings/forms.py index ac3c27845daa..47883a864a70 100644 --- a/corehq/apps/settings/forms.py +++ b/corehq/apps/settings/forms.py @@ -15,11 +15,13 @@ from two_factor.forms import ( DeviceValidationForm, MethodForm, + TOTPDeviceForm, +) +from two_factor.plugins.phonenumber.utils import get_available_phone_methods +from two_factor.plugins.phonenumber.forms import ( PhoneNumberForm, PhoneNumberMethodForm, - TOTPDeviceForm, ) -from two_factor.models import get_available_phone_methods from two_factor.utils import totp_digits from corehq.apps.hqwebapp import crispy as hqcrispy diff --git a/corehq/apps/settings/tests/test_views.py b/corehq/apps/settings/tests/test_views.py index b5b999d8d321..9bad5746cdeb 100644 --- a/corehq/apps/settings/tests/test_views.py +++ b/corehq/apps/settings/tests/test_views.py @@ -7,7 +7,8 @@ from django.test.client import RequestFactory from django.urls import reverse -from two_factor.views import PhoneSetupView, ProfileView, SetupView +from two_factor.views import ProfileView, SetupView +from two_factor.plugins.phonenumber.views import PhoneSetupView from corehq.apps.domain.shortcuts import create_domain from corehq.apps.users.audit.change_messages import UserChangeMessage diff --git a/corehq/apps/settings/views.py b/corehq/apps/settings/views.py index e9f72ca537b2..38b90cf53870 100644 --- a/corehq/apps/settings/views.py +++ b/corehq/apps/settings/views.py @@ -20,17 +20,20 @@ import langcodes import qrcode from memoized import memoized -from two_factor.models import PhoneDevice -from two_factor.utils import backup_phones, default_device +from two_factor.plugins.phonenumber.models import PhoneDevice +from two_factor.utils import default_device +from two_factor.plugins.phonenumber.utils import backup_phones from two_factor.views import ( BackupTokensView, DisableView, - PhoneDeleteView, - PhoneSetupView, ProfileView, SetupCompleteView, SetupView, ) +from two_factor.plugins.phonenumber.views import ( + PhoneDeleteView, + PhoneSetupView +) from dimagi.utils.web import json_response diff --git a/settings.py b/settings.py index 43e1e9c67c7e..f51f72560b71 100755 --- a/settings.py +++ b/settings.py @@ -231,6 +231,7 @@ 'django_otp.plugins.otp_static', 'django_otp.plugins.otp_totp', 'two_factor', + 'two_factor.plugins.phonenumber', 'ws4redis', 'statici18n', 'django_user_agents', From 7a74469627818af2e8cc5d45183db5de3612f202 Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Thu, 2 Nov 2023 17:32:25 -0400 Subject: [PATCH 3/6] fix failing tests - corehq.apps.dump_reload.tests.test_dump_models.test_domain_dump_sql_models - corehq.apps.domain.tests.test_deletion_models:test_deletion_sql_models --- corehq/apps/domain/deletion.py | 2 +- corehq/apps/dump_reload/tests/test_dump_models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/corehq/apps/domain/deletion.py b/corehq/apps/domain/deletion.py index da957c6258e5..b381451bd6a6 100644 --- a/corehq/apps/domain/deletion.py +++ b/corehq/apps/domain/deletion.py @@ -301,7 +301,7 @@ def _delete_demo_user_restores(domain_name): DOMAIN_DELETE_OPERATIONS = [ DjangoUserRelatedModelDeletion('otp_static', 'StaticDevice', 'user__username', ['StaticToken']), DjangoUserRelatedModelDeletion('otp_totp', 'TOTPDevice', 'user__username'), - DjangoUserRelatedModelDeletion('two_factor', 'PhoneDevice', 'user__username'), + DjangoUserRelatedModelDeletion('phonenumber', 'PhoneDevice', 'user__username'), DjangoUserRelatedModelDeletion('users', 'HQApiKey', 'user__username'), CustomDeletion('auth', _delete_django_users, ['User']), ModelDeletion('products', 'SQLProduct', 'domain'), diff --git a/corehq/apps/dump_reload/tests/test_dump_models.py b/corehq/apps/dump_reload/tests/test_dump_models.py index 0ad058f3b104..c202c25b09fb 100644 --- a/corehq/apps/dump_reload/tests/test_dump_models.py +++ b/corehq/apps/dump_reload/tests/test_dump_models.py @@ -92,7 +92,7 @@ "tastypie.ApiAccess", # not tagged by domain "tastypie.ApiKey", # not domain-specific "toggle_ui.ToggleAudit", - "two_factor.PhoneDevice", + "phonenumber.PhoneDevice", "users.Permission", "util.BouncedEmail", "util.ComplaintBounceMeta", From 6ba6fec220a32a2262f77551a068209f2fc7e31f Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Thu, 2 Nov 2023 18:07:23 -0400 Subject: [PATCH 4/6] run makemigrations --lock-update --- migrations.lock | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/migrations.lock b/migrations.lock index f11d81ac78e3..de661424d464 100644 --- a/migrations.lock +++ b/migrations.lock @@ -733,6 +733,8 @@ phonelog 0012_server_date_not_null 0013_delete_olddevicereportentry 0014_auto_20170718_2039 +phonenumber + 0001_squashed_0001_initial (10 squashed migrations) pillow_retry 0001_initial 0002_pillowerror_queued @@ -1088,13 +1090,7 @@ translations 0008_remove_couch_id 0009_auto_20200924_1753 two_factor - 0001_initial - 0002_auto_20150110_0810 - 0003_auto_20150817_1733 - 0004_auto_20160205_1827 - 0005_auto_20160224_0450 - 0006_phonedevice_key_default - 0007_auto_20201201_1019 + (no migrations) user_importer 0001_initial userreports From 024f23d7b12dbbfed60aa4bc1395d3e996368795 Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Fri, 22 Dec 2023 13:39:16 -0500 Subject: [PATCH 5/6] Register custom HQ 2FA forms with django-two-factor-auth's registry Includes other changes to get 2FA setup working on the new version of django-two-factor-auth, like clearing the cached device on the user object after deletion, and receiving appropriate parameters. --- .../two_factor/core/setup.html | 60 ++++++++++++------- corehq/apps/settings/forms.py | 19 ++---- corehq/apps/settings/method.py | 28 +++++++++ corehq/apps/settings/views.py | 37 ++++-------- 4 files changed, 83 insertions(+), 61 deletions(-) create mode 100644 corehq/apps/settings/method.py diff --git a/corehq/apps/domain/templates/login_and_password/two_factor/core/setup.html b/corehq/apps/domain/templates/login_and_password/two_factor/core/setup.html index 0e7c716d3352..118cce81901e 100644 --- a/corehq/apps/domain/templates/login_and_password/two_factor/core/setup.html +++ b/corehq/apps/domain/templates/login_and_password/two_factor/core/setup.html @@ -1,41 +1,55 @@ +{# lightly modified version of two_factor/core/setup.html #} {% extends "hqwebapp/bootstrap3/base_section.html" %} {% load i18n %} {% load crispy_forms_tags %} +{% block extra_media %} + {{ form.media }} +{% endblock %} + {% block page_content %}

{% block title %}{% trans "Enable Two-Factor Authentication" %}{% endblock %}

- {% if wizard.steps.current == 'welcome_setup' %} -

{% blocktrans %}Follow the steps in this wizard to enable two-factor - authentication.{% endblocktrans %}

- {% elif wizard.steps.current == 'welcome_reset' %} -

{% blocktrans %}Follow the steps in this wizard to reset two-factor - authentication.{% endblocktrans %}

+ {% if wizard.steps.current == 'welcome' %} +

{% blocktrans trimmed %}Follow the steps in this wizard to enable two-factor + authentication.{% endblocktrans %}

{% elif wizard.steps.current == 'method' %} -

{% blocktrans %}Please select which authentication method you would - like to use.{% endblocktrans %}

+

{% blocktrans trimmed %}Please select which authentication method you would + like to use.{% endblocktrans %}

{% elif wizard.steps.current == 'generator' %} -

{% blocktrans %}To start using a token generator, please use your - smartphone to scan the QR code below. For example, use Google - Authenticator. Then, enter the token generated by the app. - {% endblocktrans %}

-

QR Code

+

{% blocktrans trimmed %}To start using a token generator, please use your + smartphone to scan the QR code below. For example, use Google + Authenticator.{% endblocktrans %}

+

QR Code

+

{% blocktrans trimmed %}Alternatively you can use the following secret to + setup TOTP in your authenticator or password manager manually.{% endblocktrans %}

+

{% translate "TOTP Secret:" %} {{ secret_key }}

+

{% blocktrans %}Then, enter the token generated by the app.{% endblocktrans %}

+ {% elif wizard.steps.current == 'sms' %} -

{% blocktrans %}Please enter the phone number you wish to receive the +

{% blocktrans trimmed %}Please enter the phone number you wish to receive the text messages on. This number will be validated in the next step. - {% endblocktrans %}

+ {% endblocktrans %}

{% elif wizard.steps.current == 'call' %} -

{% blocktrans %}Please enter the phone number you wish to be called on. +

{% blocktrans trimmed %}Please enter the phone number you wish to be called on. This number will be validated in the next step. {% endblocktrans %}

{% elif wizard.steps.current == 'validation' %} - {% if device.method == 'call' %} -

{% blocktrans %}We are calling your phone right now, please enter the - digits you hear.{% endblocktrans %}

- {% elif device.method == 'sms' %} -

{% blocktrans %}We sent you a text message, please enter the tokens we - sent.{% endblocktrans %}

+ {% if challenge_succeeded %} + {% if device.method == 'call' %} +

{% blocktrans trimmed %}We are calling your phone right now, please enter the + digits you hear.{% endblocktrans %}

+ {% elif device.method == 'sms' %} +

{% blocktrans trimmed %}We sent you a text message, please enter the tokens we + sent.{% endblocktrans %}

+ {% endif %} + {% else %} + {% endif %} {% elif wizard.steps.current == 'yubikey' %} -

{% blocktrans %}To identify and verify your YubiKey, please insert a +

{% blocktrans trimmed %}To identify and verify your YubiKey, please insert a token in the field below. Your YubiKey will be linked to your account.{% endblocktrans %}

{% endif %} diff --git a/corehq/apps/settings/forms.py b/corehq/apps/settings/forms.py index 47883a864a70..5c86e3371321 100644 --- a/corehq/apps/settings/forms.py +++ b/corehq/apps/settings/forms.py @@ -17,7 +17,6 @@ MethodForm, TOTPDeviceForm, ) -from two_factor.plugins.phonenumber.utils import get_available_phone_methods from two_factor.plugins.phonenumber.forms import ( PhoneNumberForm, PhoneNumberMethodForm, @@ -142,16 +141,8 @@ def clean_token(self): class HQTwoFactorMethodForm(MethodForm): - def __init__(self, *, allow_phone_2fa, **kwargs): - super().__init__(**kwargs) - if not allow_phone_2fa: - # Block people from setting up the phone method as their default - phone_methods = [method for method, _ in get_available_phone_methods()] - self.fields['method'].choices = [ - (method, display_name) - for method, display_name in self.fields['method'].choices - if method not in phone_methods - ] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_class = 'form form-horizontal' self.helper.label_class = 'col-sm-3 col-md-4 col-lg-2' @@ -172,7 +163,7 @@ def __init__(self, *, allow_phone_2fa, **kwargs): _("Back"), css_class='btn-default', type='submit', - value='welcome_setup', + value='welcome', name="wizard_goto_step", ), ) @@ -182,8 +173,8 @@ def __init__(self, *, allow_phone_2fa, **kwargs): class HQTOTPDeviceForm(TOTPDeviceForm): token = forms.IntegerField(required=False, label=_("Token"), min_value=1, max_value=int('9' * totp_digits())) - def __init__(self, **kwargs): - super(HQTOTPDeviceForm, self).__init__(**kwargs) + def __init__(self, key, user, **kwargs): + super(HQTOTPDeviceForm, self).__init__(key, user, **kwargs) self.helper = FormHelper() self.helper.form_class = 'form form-horizontal' self.helper.label_class = 'col-sm-3 col-md-4 col-lg-2' diff --git a/corehq/apps/settings/method.py b/corehq/apps/settings/method.py new file mode 100644 index 000000000000..8ea82ee9515e --- /dev/null +++ b/corehq/apps/settings/method.py @@ -0,0 +1,28 @@ +from two_factor.plugins.phonenumber.method import PhoneCallMethod, SMSMethod +from two_factor.plugins.registry import GeneratorMethod + +from corehq.apps.settings.forms import HQPhoneNumberForm, HQTOTPDeviceForm + + +class HQGeneratorMethod(GeneratorMethod): + + form_path = 'corehq.apps.settings.forms.HQTOTPDeviceForm' + + def get_setup_forms(self, *args): + return {self.code: HQTOTPDeviceForm} + + +class HQPhoneCallMethod(PhoneCallMethod): + + form_path = 'corehq.apps.settings.forms.HQPhoneNumberForm' + + def get_setup_forms(self, *args): + return {self.code: HQPhoneNumberForm} + + +class HQSMSMethod(SMSMethod): + + form_path = 'corehq.apps.settings.forms.HQPhoneNumberForm' + + def get_setup_forms(self, *args): + return {self.code: HQPhoneNumberForm} diff --git a/corehq/apps/settings/views.py b/corehq/apps/settings/views.py index 38b90cf53870..742af46b7e16 100644 --- a/corehq/apps/settings/views.py +++ b/corehq/apps/settings/views.py @@ -34,6 +34,7 @@ PhoneDeleteView, PhoneSetupView ) +from two_factor.plugins.registry import registry from dimagi.utils.web import json_response @@ -57,14 +58,13 @@ not_found, ) from corehq.apps.settings.exceptions import DuplicateApiKeyName +from corehq.apps.settings.method import HQGeneratorMethod, HQPhoneCallMethod, HQSMSMethod from corehq.apps.settings.forms import ( HQApiKeyForm, HQDeviceValidationForm, HQEmptyForm, HQPasswordChangeForm, - HQPhoneNumberForm, HQPhoneNumberMethodForm, - HQTOTPDeviceForm, HQTwoFactorMethodForm, ) from corehq.apps.sso.models import IdentityProvider @@ -409,26 +409,21 @@ class TwoFactorSetupView(BaseMyAccountView, SetupView): page_title = gettext_lazy("Two Factor Authentication Setup") form_list = ( - ('welcome_setup', HQEmptyForm), + ('welcome', HQEmptyForm), ('method', HQTwoFactorMethodForm), - ('generator', HQTOTPDeviceForm), - ('sms', HQPhoneNumberForm), - ('call', HQPhoneNumberForm), - ('validation', HQDeviceValidationForm), + # other forms are dynamically added ) @method_decorator(active_domains_required) @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): - # this is only here to add the login_required decorator - return super(TwoFactorSetupView, self).dispatch(request, *args, **kwargs) + registry.unregister('generator') + registry.register(HQGeneratorMethod()) + if _user_can_use_phone(request.user): + registry.register(HQSMSMethod()) + registry.register(HQPhoneCallMethod()) - def get_form_kwargs(self, step=None): - kwargs = super().get_form_kwargs(step) - if step == 'method': - kwargs.setdefault('allow_phone_2fa', _user_can_use_phone(self.request.couch_user)) - - return kwargs + return super(TwoFactorSetupView, self).dispatch(request, *args, **kwargs) class TwoFactorSetupCompleteView(BaseMyAccountView, SetupCompleteView): @@ -544,17 +539,11 @@ def dispatch(self, request, *args, **kwargs): class TwoFactorResetView(TwoFactorSetupView): urlname = 'reset' - form_list = ( - ('welcome_reset', HQEmptyForm), - ('method', HQTwoFactorMethodForm), - ('generator', HQTOTPDeviceForm), - ('sms', HQPhoneNumberForm), - ('call', HQPhoneNumberForm), - ('validation', HQDeviceValidationForm), - ) - def get(self, request, *args, **kwargs): default_device(request.user).delete() + # django-two-factor-auth caches the default device on the user so clear that too + from two_factor.utils import USER_DEFAULT_DEVICE_ATTR_NAME + delattr(request.user, USER_DEFAULT_DEVICE_ATTR_NAME) return super(TwoFactorResetView, self).get(request, *args, **kwargs) From 6d10fa8a94014c7cf9871ed25c9c44d10ec136b0 Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Tue, 26 Dec 2023 13:44:42 -0500 Subject: [PATCH 6/6] Fix TwoFactorPhoneSetupView - two_factor:phone_create and phone_delete urls were updated in 1.15.5 (removed backup) - PhoneSetupView changed key 'method' to 'setup' --- .../login_and_password/two_factor/core/phone_register.html | 7 ++++--- corehq/apps/hqwebapp/urls.py | 4 ++-- corehq/apps/settings/views.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/corehq/apps/domain/templates/login_and_password/two_factor/core/phone_register.html b/corehq/apps/domain/templates/login_and_password/two_factor/core/phone_register.html index dd334433ebac..8739ecf73720 100644 --- a/corehq/apps/domain/templates/login_and_password/two_factor/core/phone_register.html +++ b/corehq/apps/domain/templates/login_and_password/two_factor/core/phone_register.html @@ -1,3 +1,4 @@ +{# lightly modified version of two_factor/core/phone_register.html #} {% extends "hqwebapp/bootstrap3/base_section.html" %} {% load i18n %} {% load crispy_forms_tags %} @@ -5,11 +6,11 @@ {% block page_content %}

{% block title %}{% trans "Add Backup Phone" %}{% endblock %}

- {% if wizard.steps.current == 'method' %} -

{% blocktrans %}Your backup phone number will be used if your primary method of + {% if wizard.steps.current == 'setup' %} +

{% blocktrans trimmed %}Your backup phone number will be used if your primary method of registration is not available. Please enter a valid phone number.{% endblocktrans %}

{% elif wizard.steps.current == 'validation' %} -

{% blocktrans %}We've sent a token to your phone number. Please +

{% blocktrans trimmed %}We've sent a token to your phone number. Please enter the token you've received.{% endblocktrans %}

{% endif %} diff --git a/corehq/apps/hqwebapp/urls.py b/corehq/apps/hqwebapp/urls.py index 0c08e098b96d..98153e0f2662 100644 --- a/corehq/apps/hqwebapp/urls.py +++ b/corehq/apps/hqwebapp/urls.py @@ -76,9 +76,9 @@ url(r'^account/two_factor/backup/tokens/$', TwoFactorBackupTokensView.as_view(), name=TwoFactorBackupTokensView.urlname), url(r'^account/two_factor/disable/$', TwoFactorDisableView.as_view(), name=TwoFactorDisableView.urlname), - url(r'^account/two_factor/backup/phone/register/$', TwoFactorPhoneSetupView.as_view(), + url(r'^account/two_factor/phone/register/$', TwoFactorPhoneSetupView.as_view(), name=TwoFactorPhoneSetupView.urlname), - url(r'^account/two_factor/backup/phone/unregister/(?P\d+)/$', TwoFactorPhoneDeleteView.as_view(), + url(r'^account/two_factor/phone/unregister/(?P\d+)/$', TwoFactorPhoneDeleteView.as_view(), name=TwoFactorPhoneDeleteView.urlname), url(r'', include(tf_urls)), url(r'', include(tf_twilio_urls)), diff --git a/corehq/apps/settings/views.py b/corehq/apps/settings/views.py index 742af46b7e16..2a1318931829 100644 --- a/corehq/apps/settings/views.py +++ b/corehq/apps/settings/views.py @@ -490,7 +490,7 @@ class TwoFactorPhoneSetupView(BaseMyAccountView, PhoneSetupView): page_title = gettext_lazy("Two Factor Authentication Phone Setup") form_list = ( - ('method', HQPhoneNumberMethodForm), + ('setup', HQPhoneNumberMethodForm), ('validation', HQDeviceValidationForm), )