diff --git a/app/assets/stylesheets/components/_tooltip.scss b/app/assets/stylesheets/components/_tooltip.scss
index ed7af2c389b..774cb4f0a7d 100644
--- a/app/assets/stylesheets/components/_tooltip.scss
+++ b/app/assets/stylesheets/components/_tooltip.scss
@@ -34,14 +34,14 @@
.hint--no-animate {
&::before,
&::after {
- display: none;
+ visibility: hidden;
}
&:focus::before,
&:focus::after,
&:hover::before,
&:hover::after {
- display: block;
+ visibility: visible;
}
}
diff --git a/app/controllers/concerns/two_factor_authenticatable.rb b/app/controllers/concerns/two_factor_authenticatable.rb
index d84e9fadf46..7632bc11b96 100644
--- a/app/controllers/concerns/two_factor_authenticatable.rb
+++ b/app/controllers/concerns/two_factor_authenticatable.rb
@@ -220,6 +220,6 @@ def presenter_for(otp_code_method)
data = send("#{type}_view_data".to_sym)
- TwoFactorAuthCode.const_get("#{type}_delivery_presenter".classify).new(data)
+ TwoFactorAuthCode.const_get("#{type}_delivery_presenter".classify).new(data, view_context)
end
end
diff --git a/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb b/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb
index 2f60530472e..878ca616b58 100644
--- a/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb
+++ b/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb
@@ -1,13 +1,14 @@
module TwoFactorAuthCode
class AuthenticatorDeliveryPresenter < TwoFactorAuthCode::GenericDeliveryPresenter
def header
- t('devise.two_factor_authentication.header_text')
+ t('devise.two_factor_authentication.totp_header_text')
end
def help_text
t("instructions.2fa.#{delivery_method}.confirm_code_html",
email: content_tag(:strong, user_email),
- app: content_tag(:strong, APP_NAME))
+ app: content_tag(:strong, APP_NAME),
+ tooltip: view.tooltip(t('tooltips.authentication_app')))
end
def fallback_links
diff --git a/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb b/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb
index 44cb711a244..65516f60d21 100644
--- a/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb
+++ b/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb
@@ -5,12 +5,14 @@ class GenericDeliveryPresenter
include Rails.application.routes.url_helpers
attr_reader :phone_number, :code_value, :delivery_method, :reenter_phone_number_path,
- :totp_enabled, :unconfirmed_phone, :recovery_code_unavailable, :user_email
+ :totp_enabled, :unconfirmed_phone, :recovery_code_unavailable, :user_email, :view
- def initialize(data_model)
+ def initialize(data_model, view = nil)
data_model.each do |key, value|
instance_variable_set("@#{key}", value)
end
+
+ @view = view
end
def header
diff --git a/app/views/two_factor_authentication/totp_verification/show.html.slim b/app/views/two_factor_authentication/totp_verification/show.html.slim
index 693d3575034..ef4b0a31d2b 100644
--- a/app/views/two_factor_authentication/totp_verification/show.html.slim
+++ b/app/views/two_factor_authentication/totp_verification/show.html.slim
@@ -1,6 +1,5 @@
- title t('titles.enter_2fa_code')
-
h1.h3.my0 = @presenter.header
p.mt-tiny.mb0#code-instructs = @presenter.help_text
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index 05a378ab007..1d4ef27e093 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -104,6 +104,7 @@ ignore_unused:
- 'links.phone_confirmation.fallback_to_{sms,authenticator,voice}_html'
- 'links.two_factor_authentication.resend_code.{sms,voice}_html'
- 'links.two_factor_authentication.{sms,voice}_html'
+ - 'tooltips.authentication_app'
# - 'simple_form.{yes,no}'
# - 'simple_form.{placeholders,hints,labels}.*'
# - 'simple_form.{error_notification,required}.:'
diff --git a/config/locales/devise/en.yml b/config/locales/devise/en.yml
index dd0e08e9ee0..f40edb4e4de 100644
--- a/config/locales/devise/en.yml
+++ b/config/locales/devise/en.yml
@@ -138,7 +138,7 @@ en:
If you can’t use your authenticator app right now you can %{sms_link}
or %{voice_link}.
voice_link_text: with a phone call
- totp_header_text: Enter your authenticator code
+ totp_header_text: Enter your authentication app code
totp_info: Use any authenticator app to scan the QR code below.
two_factor_setup: Add a phone number
user:
diff --git a/config/locales/instructions/en.yml b/config/locales/instructions/en.yml
index 6d8fa473434..ec6932cb00b 100644
--- a/config/locales/instructions/en.yml
+++ b/config/locales/instructions/en.yml
@@ -5,7 +5,7 @@ en:
authenticator:
confirm_code_html: Enter the code from your authenticator app. If you have several accounts
set up in your app, enter the code corresponding to %{email} at
- %{app}.
+ %{app}.%{tooltip}
sms:
confirm_code_html: We sent it in a text message to %{number}. Need another code?
%{resend_code_link}. Message rates may apply.
@@ -16,10 +16,6 @@ en:
%{resend_code_link}
fallback_html: If you can't take a phone call right now, you can get a passcode
via %{link}
- authenticator:
- confirm_code_html: Enter the code from your authenticator app. If you have several accounts
- set up in your app, enter the code corresponding to %{email} at
- %{app}.
wrong_number_html: Entered the wrong phone number? %{link}
forgot_password:
close_window: You can close this browser window once you have reset your password.
diff --git a/config/locales/instructions/es.yml b/config/locales/instructions/es.yml
index d3ffa4e8720..cb260aa6204 100644
--- a/config/locales/instructions/es.yml
+++ b/config/locales/instructions/es.yml
@@ -5,7 +5,7 @@ es:
authenticator:
confirm_code_html: Ingrese el código de su aplicación de autenticador. Si tiene varias cuentas
configuradas en su aplicación, ingrese el código correspondiente a %{email} en
- %{app}.
+ %{app}.%{tooltip}
sms:
confirm_code_html: Lo enviamos a %{number}. ¿No recibió un código? %{link}.
fallback_html: NOT TRANSLATED YET
diff --git a/config/locales/tooltips/en.yml b/config/locales/tooltips/en.yml
index 6402cf175fa..2c7e8334fa3 100644
--- a/config/locales/tooltips/en.yml
+++ b/config/locales/tooltips/en.yml
@@ -16,3 +16,6 @@ en:
For your security, some government agencies require customer accounts to
be verified using Personally Identifiable Information (PII) such as
Social Security Number and proof of address.
+ authentication_app: An authentication application is a mobile security app
+ that generates security codes even if you don't have an Internet connection
+ or cellular service.
diff --git a/config/locales/tooltips/es.yml b/config/locales/tooltips/es.yml
index 45c0d04b3aa..147a1b90283 100644
--- a/config/locales/tooltips/es.yml
+++ b/config/locales/tooltips/es.yml
@@ -6,3 +6,4 @@ es:
ssn: NOT TRANSLATED YET
two_factor: NOT TRANSLATED YET
verified_account: NOT TRANSLATED YET
+ authentication_app: NOT TRANSLATED YET
diff --git a/spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb b/spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb
index 70c89cdae07..6fab953b933 100644
--- a/spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb
+++ b/spec/presenters/two_factor_auth_code/generic_delivery_presenter_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
-def presenter_with(arguments = {})
- TwoFactorAuthCode::GenericDeliveryPresenter.new(arguments)
+def presenter_with(arguments = {}, view = nil)
+ TwoFactorAuthCode::GenericDeliveryPresenter.new(arguments, view)
end
describe TwoFactorAuthCode::GenericDeliveryPresenter do
@@ -15,6 +15,14 @@ def presenter_with(arguments = {})
end
end
+ describe 'view context' do
+ it 'makes the view context available' do
+ view = ActionController::Base.new.view_context
+ presenter = presenter_with({}, view)
+ expect(presenter.view).to equal(view)
+ end
+ end
+
describe '#recovery_code_link' do
context 'with unconfirmed user' do
presenter = presenter_with(recovery_code_unavailable: true)
diff --git a/spec/views/two_factor_authentication/totp_verification/show.html.slim_spec.rb b/spec/views/two_factor_authentication/totp_verification/show.html.slim_spec.rb
index 1feec822099..5a42338df66 100644
--- a/spec/views/two_factor_authentication/totp_verification/show.html.slim_spec.rb
+++ b/spec/views/two_factor_authentication/totp_verification/show.html.slim_spec.rb
@@ -13,7 +13,8 @@
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:reauthn?).and_return(false)
- @presenter = TwoFactorAuthCode::AuthenticatorDeliveryPresenter.new(presenter_data)
+ @presenter = TwoFactorAuthCode::AuthenticatorDeliveryPresenter.
+ new(presenter_data, ApplicationController.new.view_context)
render
end
@@ -21,15 +22,12 @@
it_behaves_like 'an otp form'
it 'shows the correct header' do
- expect(rendered).to have_content t('devise.two_factor_authentication.header_text')
+ expect(rendered).to have_content t('devise.two_factor_authentication.totp_header_text')
end
it 'shows the correct help text' do
- expect(rendered).to have_content(
- t('instructions.2fa.authenticator.confirm_code_html',
- email: user.email,
- app: APP_NAME)
- )
+ expect(rendered).to have_content 'Enter the code from your authenticator app.'
+ expect(rendered).to have_content "enter the code corresponding to #{user.email}"
end
it 'allows the user to fallback to SMS and voice' do
@@ -47,4 +45,9 @@
href: login_two_factor_recovery_code_path
)
end
+
+ it 'displays a helpful tooltip to the user' do
+ tooltip = t('tooltips.authentication_app')
+ expect(rendered).to have_xpath("//span[@aria-label=\"#{tooltip}\"]")
+ end
end