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