From a781ad6fd7df4caf0d930b18c85c82e0224ab9cd Mon Sep 17 00:00:00 2001 From: Adam Biagianti Date: Wed, 21 Dec 2016 21:03:09 -0500 Subject: [PATCH 1/2] Adds authenticator app tooltip **Why**: To ensure users understand what the app is, and how they can use it --- app/assets/stylesheets/components/_tooltip.scss | 1 + .../authenticator_delivery_presenter.rb | 3 ++- .../totp_verification/show.html.slim | 1 - config/locales/devise/en.yml | 2 +- config/locales/tooltips/en.yml | 3 +++ config/locales/tooltips/es.yml | 1 + .../totp_verification/show.html.slim_spec.rb | 10 ++++++++++ 7 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/components/_tooltip.scss b/app/assets/stylesheets/components/_tooltip.scss index ed7af2c389b..d3d4489c10f 100644 --- a/app/assets/stylesheets/components/_tooltip.scss +++ b/app/assets/stylesheets/components/_tooltip.scss @@ -48,3 +48,4 @@ .img-tooltip { vertical-align: middle; } + 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..4950112daba 100644 --- a/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb +++ b/app/presenters/two_factor_auth_code/authenticator_delivery_presenter.rb @@ -7,7 +7,8 @@ def header 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: tooltip(t('tooltips.authentication_app'))) end def fallback_links 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/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/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/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..79a2bdc9f91 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 @@ -32,6 +32,11 @@ ) end + it 'prompts to enter code from app' do + expect(rendered).to have_content t('devise.two_factor_authentication.totp_header_text') + expect(rendered).to have_content "enter the code corresponding to #{user.email}" + end + it 'allows the user to fallback to SMS and voice' do expect(rendered). to have_link(t('devise.two_factor_authentication.totp_fallback.sms_link_text'), @@ -47,4 +52,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 From 03746f38daaa4478318fca5c16954442348a4157 Mon Sep 17 00:00:00 2001 From: Adam Biagianti Date: Thu, 26 Jan 2017 15:00:12 -0800 Subject: [PATCH 2/2] Pass optional explicit view context to presenter **Why**: It is the easiest way to allow the presenter to have access to mehtods inside view helpers --- app/assets/stylesheets/components/_tooltip.scss | 5 ++--- .../concerns/two_factor_authenticatable.rb | 2 +- .../authenticator_delivery_presenter.rb | 4 ++-- .../generic_delivery_presenter.rb | 6 ++++-- config/i18n-tasks.yml | 1 + config/locales/instructions/en.yml | 6 +----- config/locales/instructions/es.yml | 2 +- .../generic_delivery_presenter_spec.rb | 12 ++++++++++-- .../totp_verification/show.html.slim_spec.rb | 15 ++++----------- 9 files changed, 26 insertions(+), 27 deletions(-) diff --git a/app/assets/stylesheets/components/_tooltip.scss b/app/assets/stylesheets/components/_tooltip.scss index d3d4489c10f..774cb4f0a7d 100644 --- a/app/assets/stylesheets/components/_tooltip.scss +++ b/app/assets/stylesheets/components/_tooltip.scss @@ -34,18 +34,17 @@ .hint--no-animate { &::before, &::after { - display: none; + visibility: hidden; } &:focus::before, &:focus::after, &:hover::before, &:hover::after { - display: block; + visibility: visible; } } .img-tooltip { vertical-align: middle; } - 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 4950112daba..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,14 +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), - tooltip: tooltip(t('tooltips.authentication_app'))) + 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/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/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/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 79a2bdc9f91..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,19 +22,11 @@ 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) - ) - end - - it 'prompts to enter code from app' do - expect(rendered).to have_content t('devise.two_factor_authentication.totp_header_text') + 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