From 477aa3e3e45c6ed740c2dddd2ab124a29abbf4e1 Mon Sep 17 00:00:00 2001 From: Amir Reavis-Bey Date: Tue, 14 Jan 2025 15:34:17 -0500 Subject: [PATCH 1/5] LG-15321: relax vendor redirect in test mode (#11677) * init relax vendor redirect if in test mode [skip changelog] * fix doc cap standard test * fix doc cap socure hybrid test * fix doc cap hybrid test * in test mode do not redirect except if socure and facial match req'd * fix specs to not allow socure to have flow in test mode for selfie capture * update happy path specs to be able to upload links while enforcing doc cap redirects * allow step without forcing doc cap redirect * disable invalid test * fix hybrid mobile spec * create flag for disable redirect_to_correct_vendor * undo spec changes * add redirect spec * when redirect to correct vendor is disabled on hybrid mobile spec * undo spec preconditions change * use default redirect to correct vendor in dev * only bypass redirect correct vendor if disabled * only bypass redirect correct vendor if disabled - remove spec * test disable vendor redirect for socure standard controller * test redirect correct vendor in socure doc auth controllers * test redirect correct vendor in standard doc auth controllers * happy linting * rename env var doc_auth_disable_redirect_to_correct_vendor to doc_auth_redirect_to_correct_vendor_disabled * rename env var doc_auth_disable_redirect_to_correct_vendor to doc_auth_redirect_to_correct_vendor_disabled in specs * lint config file * remove unused variable * fix spec for document request api calls to test hybrid flow * happy linting * add spec to test when socure hybrid mobile when redirect is enforced * update spec desc --- .../concerns/idv/document_capture_concern.rb | 2 + config/application.yml.default | 1 + lib/identity_config.rb | 1 + .../idv/document_capture_controller_spec.rb | 32 +++++---- .../document_capture_controller_spec.rb | 13 ++++ .../document_capture_controller_spec.rb | 24 +++++++ .../document_capture_controller_spec.rb | 23 +++++- .../idv/doc_auth/document_capture_spec.rb | 18 +++-- .../doc_auth/socure_document_capture_spec.rb | 5 ++ .../hybrid_socure_mobile_spec.rb | 70 ++++++++----------- 10 files changed, 132 insertions(+), 57 deletions(-) diff --git a/app/controllers/concerns/idv/document_capture_concern.rb b/app/controllers/concerns/idv/document_capture_concern.rb index 6445a77e82b..5cd9eb2ea57 100644 --- a/app/controllers/concerns/idv/document_capture_concern.rb +++ b/app/controllers/concerns/idv/document_capture_concern.rb @@ -59,6 +59,8 @@ def selfie_requirement_met? end def redirect_to_correct_vendor(vendor, in_hybrid_mobile) + return if IdentityConfig.store.doc_auth_redirect_to_correct_vendor_disabled + expected_doc_auth_vendor = doc_auth_vendor return if vendor == expected_doc_auth_vendor return if vendor == Idp::Constants::Vendors::LEXIS_NEXIS && diff --git a/config/application.yml.default b/config/application.yml.default index af18e673bb8..21ab799da38 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -107,6 +107,7 @@ doc_auth_max_attempts: 5 doc_auth_max_capture_attempts_before_native_camera: 3 doc_auth_max_submission_attempts_before_native_camera: 3 doc_auth_read_additional_pii_attributes_enabled: false +doc_auth_redirect_to_correct_vendor_disabled: false doc_auth_selfie_desktop_test_mode: false doc_auth_socure_wait_polling_refresh_max_seconds: 15 doc_auth_socure_wait_polling_timeout_minutes: 2 diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 5dcc7b7556d..092f25addbc 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -118,6 +118,7 @@ def self.store config.add(:doc_auth_check_failed_image_resubmission_enabled, type: :boolean) config.add(:doc_auth_client_glare_threshold, type: :integer) config.add(:doc_auth_client_sharpness_threshold, type: :integer) + config.add(:doc_auth_redirect_to_correct_vendor_disabled, type: :boolean) config.add(:doc_auth_error_dpi_threshold, type: :integer) config.add(:doc_auth_error_glare_threshold, type: :integer) config.add(:doc_auth_error_sharpness_threshold, type: :integer) diff --git a/spec/controllers/idv/document_capture_controller_spec.rb b/spec/controllers/idv/document_capture_controller_spec.rb index b6592943583..4a0d945b92e 100644 --- a/spec/controllers/idv/document_capture_controller_spec.rb +++ b/spec/controllers/idv/document_capture_controller_spec.rb @@ -20,6 +20,7 @@ # selfie related test flags let(:sp_selfie_enabled) { false } let(:flow_path) { 'standard' } + let(:doc_auth_selfie_desktop_test_mode) { false } before do stub_sign_in(user) @@ -41,6 +42,9 @@ allow(IdentityConfig.store).to receive(:doc_auth_vendor_default).and_return( Idp::Constants::Vendors::LEXIS_NEXIS, ) + + allow(IdentityConfig.store).to receive(:doc_auth_selfie_desktop_test_mode) + .and_return(doc_auth_selfie_desktop_test_mode) end describe '#step_info' do @@ -64,11 +68,6 @@ describe 'with sp selfie enabled' do let(:sp_selfie_enabled) { true } - before do - allow(IdentityConfig.store).to receive(:doc_auth_selfie_desktop_test_mode) - .and_return(false) - end - it 'does satisfy precondition' do expect(Idv::DocumentCaptureController.step_info.preconditions.is_a?(Proc)) expect(subject).not_to receive(:render).with(:show, locals: an_instance_of(Hash)) @@ -172,6 +171,19 @@ expect(response).to redirect_to idv_socure_document_capture_url end + + context 'when redirect to correct vendor is disabled' do + before do + allow(IdentityConfig.store) + .to receive(:doc_auth_redirect_to_correct_vendor_disabled).and_return(true) + end + + it 'redirects to the Socure controller' do + get :show + + expect(response).to render_template :show + end + end end context 'socure is the default vendor but facial match is required' do @@ -193,13 +205,8 @@ context 'when a selfie is requested' do let(:sp_selfie_enabled) { true } - let(:desktop_selfie_enabled) { false } - before do - allow(IdentityConfig.store).to receive(:doc_auth_selfie_desktop_test_mode) - .and_return(desktop_selfie_enabled) - end + describe 'when desktop selfie disabled' do - let(:desktop_selfie_enabled) { false } it 'redirect back to handoff page' do expect(subject).not_to receive(:render).with( :show, @@ -216,7 +223,7 @@ end describe 'when desktop selfie enabled' do - let(:desktop_selfie_enabled) { true } + let(:doc_auth_selfie_desktop_test_mode) { true } it 'allows capture' do expect(subject).to receive(:render).with( :show, @@ -321,7 +328,6 @@ let(:sp_selfie_enabled) { true } before do - allow(IdentityConfig.store).to receive(:doc_auth_selfie_desktop_test_mode).and_return(false) allow(Idv::InPersonConfig).to receive(:enabled_for_issuer?).with(anything).and_return(false) end diff --git a/spec/controllers/idv/hybrid_mobile/document_capture_controller_spec.rb b/spec/controllers/idv/hybrid_mobile/document_capture_controller_spec.rb index d1a52c3b3df..f6d744dbc67 100644 --- a/spec/controllers/idv/hybrid_mobile/document_capture_controller_spec.rb +++ b/spec/controllers/idv/hybrid_mobile/document_capture_controller_spec.rb @@ -67,6 +67,19 @@ expect(response).to redirect_to idv_hybrid_mobile_socure_document_capture_url end + + context 'when redirect to correct vendor is disabled' do + before do + allow(IdentityConfig.store) + .to receive(:doc_auth_redirect_to_correct_vendor_disabled).and_return(true) + end + + it 'allows the user to use this controller' do + get :show + + expect(response).to render_template :show + end + end end it 'renders the show template' do diff --git a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb index de12759de6f..c05ef0408b3 100644 --- a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb @@ -211,6 +211,30 @@ expect(document_capture_session.socure_docv_transaction_token) .to eq(docv_transaction_token) end + + context 'when we try to use this controller but we should be using the LN/mock version' do + let(:idv_vendor) { Idp::Constants::Vendors::LEXIS_NEXIS } + + it 'redirects to the LN/Mock controller' do + get :show + + expect(response).to redirect_to(idv_hybrid_mobile_document_capture_url) + end + + context 'when redirect to correct vendor is disabled' do + before do + allow(IdentityConfig.store) + .to receive(:doc_auth_redirect_to_correct_vendor_disabled).and_return(true) + end + + it 'renders to the Socure controller' do + get :show + + expect(response).to have_http_status 200 + expect(response.body).to have_link(href: socure_capture_app_url) + end + end + end end end diff --git a/spec/controllers/idv/socure/document_capture_controller_spec.rb b/spec/controllers/idv/socure/document_capture_controller_spec.rb index 7557cadd21f..d663103604c 100644 --- a/spec/controllers/idv/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/socure/document_capture_controller_spec.rb @@ -39,7 +39,6 @@ allow(IdentityConfig.store).to receive(:doc_auth_vendor_switching_enabled) .and_return(vendor_switching_enabled) allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) - allow(subject).to receive(:stored_result).and_return(stored_result) user_session = {} @@ -98,6 +97,28 @@ get :show expect(response).to redirect_to idv_document_capture_url end + + context 'when redirect to correct vendor is disabled' do + let(:socure_capture_app_url) { 'https://verify.socure.test/' } + let(:response_body) do + { + data: { + docvTransactionToken: SecureRandom.hex(6), + url: socure_capture_app_url, + }, + } + end + before do + allow(IdentityConfig.store) + .to receive(:doc_auth_redirect_to_correct_vendor_disabled).and_return(true) + end + + it 'redirects to the Socure controller' do + get :show + + expect(response).to have_http_status 200 + end + end end context 'when facial match is required' do diff --git a/spec/features/idv/doc_auth/document_capture_spec.rb b/spec/features/idv/doc_auth/document_capture_spec.rb index 4d7cabfa5ce..825c5a700a8 100644 --- a/spec/features/idv/doc_auth/document_capture_spec.rb +++ b/spec/features/idv/doc_auth/document_capture_spec.rb @@ -96,11 +96,21 @@ expect(page).to have_content(I18n.t('doc_auth.errors.general.network_error')) end - it 'does not track state if state tracking is disabled' do - allow(IdentityConfig.store).to receive(:state_tracking_enabled).and_return(false) - attach_and_submit_images + context 'state tracking is disabled' do + before do + allow(IdentityConfig.store).to receive(:state_tracking_enabled).and_return(false) + allow(IdentityConfig.store).to receive(:socure_docv_enabled).and_return(true) + end + it 'does not track state' do + # Confirm that we end up on the LN / Mock page even if we try to + # go to the Socure one. + visit idv_socure_document_capture_url + expect(page).to have_current_path(idv_document_capture_url) - expect(DocAuthLog.find_by(user_id: @user.id).state).to be_nil + attach_and_submit_images + + expect(DocAuthLog.find_by(user_id: @user.id).state).to be_nil + end end end diff --git a/spec/features/idv/doc_auth/socure_document_capture_spec.rb b/spec/features/idv/doc_auth/socure_document_capture_spec.rb index ed45c95437f..ede7b13c5f5 100644 --- a/spec/features/idv/doc_auth/socure_document_capture_spec.rb +++ b/spec/features/idv/doc_auth/socure_document_capture_spec.rb @@ -293,6 +293,11 @@ docv_transaction_token: @docv_transaction_token, ) + # Confirm that we end up on the Socure page even if we try to + # go to the LN / Mock one. + visit idv_document_capture_url + expect(page).to have_current_path(idv_socure_document_capture_url) + visit idv_socure_document_capture_update_path expect(DocAuthLog.find_by(user_id: @user.id).state).to be_nil end diff --git a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb index 6b61c0887a8..94e870126ee 100644 --- a/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb +++ b/spec/features/idv/hybrid_mobile/hybrid_socure_mobile_spec.rb @@ -68,9 +68,9 @@ visit idv_link_sent_url expect(page).to have_current_path(root_url) - # Confirm that we end up on the LN / Mock page even if we try to - # go to the Socure one. - visit idv_hybrid_mobile_socure_document_capture_url + # Confirm that we end up on the Socure page even if we try to + # go to the LN / Mock one. + visit idv_hybrid_mobile_document_capture_url expect(page).to have_current_path(idv_hybrid_mobile_socure_document_capture_url) # Confirm that clicking cancel and then coming back doesn't cause errors @@ -459,56 +459,48 @@ end context 'with a network error requesting the capture app url' do - before do - allow_any_instance_of(Faraday::Connection).to receive(:post) - .and_raise(Faraday::ConnectionFailed) - end - - it 'shows the network error page on the phone and the link sent page on the desktop', - js: true do - user = nil + shared_examples 'document request API failure' do + it 'shows the network error page on the phone and the link sent page on the desktop', + js: true do + perform_in_browser(:desktop) do + visit_idp_from_sp_with_ial2(sp) + sign_up_and_2fa_ial1_user - perform_in_browser(:desktop) do - visit_idp_from_sp_with_ial2(sp) - user = sign_up_and_2fa_ial1_user + complete_doc_auth_steps_before_hybrid_handoff_step + clear_and_fill_in(:doc_auth_phone, phone_number) + click_send_link + end - complete_doc_auth_steps_before_hybrid_handoff_step - clear_and_fill_in(:doc_auth_phone, phone_number) - click_send_link - end + perform_in_browser(:mobile) do + visit @sms_link - perform_in_browser(:mobile) do - visit @sms_link + expect(page).to have_text(t('doc_auth.headers.general.network_error')) + expect(page).to have_text(t('doc_auth.errors.general.new_network_error')) + expect(@analytics).to have_logged_event(:idv_socure_document_request_submitted) + end - expect(page).to have_text(t('doc_auth.headers.general.network_error')) - expect(page).to have_text(t('doc_auth.errors.general.new_network_error')) - expect(@analytics).to have_logged_event(:idv_socure_document_request_submitted) + perform_in_browser(:desktop) do + expect(page).to have_current_path(idv_link_sent_path) + end end + end - perform_in_browser(:desktop) do - expect(page).to have_current_path(idv_link_sent_path) + context 'Faraday connection error' do + before do + allow_any_instance_of(Faraday::Connection).to receive(:post) + .and_raise(Faraday::ConnectionFailed) end + + it_behaves_like 'document request API failure' end - end - context 'invalid request', allow_browser_log: true do - context 'getting the capture path w wrong api key' do + context 'invalid request (ie: wrong api key)', allow_browser_log: true do before do - user = user_with_2fa - visit_idp_from_oidc_sp_with_ial2 - sign_in_and_2fa_user(user) - complete_doc_auth_steps_before_document_capture_step - click_idv_continue DocAuth::Mock::DocAuthMockClient.reset! stub_docv_document_request(status: 401) end - it 'correctly logs event', js: true do - visit idv_socure_document_capture_path - expect(@analytics).to have_logged_event( - :idv_socure_document_request_submitted, - ) - end + it_behaves_like 'document request API failure' end end end From 2e85e6641196797464cff9fd793a0eb2b5ab7b0b Mon Sep 17 00:00:00 2001 From: Andrew Duthie <1779930+aduth@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:55:41 -0500 Subject: [PATCH 2/5] LG-10965: Extract new controller for backup code reminder (#11738) * LG-10965: Extract new controller for backup code reminder changelog: Internal, Analytics, Log analytics events for backup code reminder * Correct description months for backup code reminder * Alphabetize analytics events * Check account age when considering backup code reminder * Use before? to improve date comparison readability --- .../concerns/backup_code_reminder_concern.rb | 7 +- .../users/backup_code_reminder_controller.rb | 29 +++++++ .../users/backup_code_setup_controller.rb | 6 +- app/models/user.rb | 13 ++- app/services/analytics_events.rb | 13 +++ .../show.html.erb} | 18 ++-- config/routes.rb | 3 +- .../backup_code_reminder_concern_spec.rb | 77 +++++++++++++++++ .../backup_code_reminder_controller_spec.rb | 86 +++++++++++++++++++ .../backup_code_setup_controller_spec.rb | 2 +- .../backup_code_sign_in_spec.rb | 33 +++++++ .../backup_code_sign_up_spec.rb | 15 ---- spec/models/user_spec.rb | 31 +++++-- .../show.html.erb_spec.rb} | 12 ++- 14 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 app/controllers/users/backup_code_reminder_controller.rb rename app/views/users/{backup_code_setup/reminder.html.erb => backup_code_reminder/show.html.erb} (56%) create mode 100644 spec/controllers/concerns/backup_code_reminder_concern_spec.rb create mode 100644 spec/controllers/users/backup_code_reminder_controller_spec.rb rename spec/views/users/{backup_code_setup/reminder.html.erb_spec.rb => backup_code_reminder/show.html.erb_spec.rb} (53%) diff --git a/app/controllers/concerns/backup_code_reminder_concern.rb b/app/controllers/concerns/backup_code_reminder_concern.rb index 8abbe2d568b..b521f6330eb 100644 --- a/app/controllers/concerns/backup_code_reminder_concern.rb +++ b/app/controllers/concerns/backup_code_reminder_concern.rb @@ -2,15 +2,18 @@ module BackupCodeReminderConcern def user_needs_backup_code_reminder? + return false if user_session[:dismissed_backup_code_reminder] user_backup_codes_configured? && user_last_signed_in_more_than_5_months_ago? end + private + def user_backup_codes_configured? MfaContext.new(current_user).backup_code_configurations.present? end def user_last_signed_in_more_than_5_months_ago? - second_last_signed_in_at = current_user.second_last_signed_in_at - second_last_signed_in_at && second_last_signed_in_at < 5.months.ago + current_user.created_at.before?(5.months.ago) && + current_user.second_last_signed_in_at(since: 5.months.ago).blank? end end diff --git a/app/controllers/users/backup_code_reminder_controller.rb b/app/controllers/users/backup_code_reminder_controller.rb new file mode 100644 index 00000000000..174069625da --- /dev/null +++ b/app/controllers/users/backup_code_reminder_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Users + class BackupCodeReminderController < ApplicationController + before_action :confirm_two_factor_authenticated + + def show + flash.now[:success] = t('notices.authenticated_successfully') + analytics.backup_code_reminder_visited + end + + def update + user_session[:dismissed_backup_code_reminder] = true + analytics.backup_code_reminder_submitted(has_codes: has_codes?) + + if has_codes? + redirect_to after_sign_in_path_for(current_user) + else + redirect_to backup_code_regenerate_path + end + end + + private + + def has_codes? + params[:has_codes].present? + end + end +end diff --git a/app/controllers/users/backup_code_setup_controller.rb b/app/controllers/users/backup_code_setup_controller.rb index f0ea7cc2ced..dfc9619b8de 100644 --- a/app/controllers/users/backup_code_setup_controller.rb +++ b/app/controllers/users/backup_code_setup_controller.rb @@ -13,7 +13,7 @@ class BackupCodeSetupController < ApplicationController before_action :set_backup_code_setup_presenter before_action :apply_secure_headers_override before_action :authorize_backup_code_disable, only: [:delete] - before_action :confirm_recently_authenticated_2fa, except: [:reminder, :continue] + before_action :confirm_recently_authenticated_2fa, except: [:continue] before_action :validate_multi_mfa_selection, only: [:index] helper_method :in_multi_mfa_selection_flow? @@ -69,10 +69,6 @@ def delete end end - def reminder - flash.now[:success] = t('notices.authenticated_successfully') - end - def confirm_backup_codes; end private diff --git a/app/models/user.rb b/app/models/user.rb index 2eca557512a..c0528992740 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -446,10 +446,17 @@ def sign_in_count(since:) .count end - def second_last_signed_in_at + # Returns the date of the last fully-authenticated sign-in before the most recent. + # + # A `since` time argument is required, to optimize performance based on database indices for + # querying a user's events. + def second_last_signed_in_at(since:) events - .where(event_type: 'sign_in_after_2fa') - .order(created_at: :desc).limit(2).pluck(:created_at).second + .where(event_type: :sign_in_after_2fa, created_at: since..) + .order(created_at: :desc) + .limit(2) + .pluck(:created_at) + .second end def connected_apps diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 1ae73fc8b8e..cccdd0f6c96 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -390,6 +390,19 @@ def backup_code_regenerate_visit(in_account_creation_flow:, **extra) track_event('Backup Code Regenerate Visited', in_account_creation_flow:, **extra) end + # @param [Boolean] has_codes Whether the user still has access to their backup codes. + # Tracks when the user submits to confirm whether they still have access to their backup codes + # when signing in for the first time in at least 5 months. + def backup_code_reminder_submitted(has_codes:, **extra) + track_event(:backup_code_reminder_submitted, has_codes:, **extra) + end + + # Tracks when the user is prompted to confirm that they still have access to their backup codes + # when signing in for the first time in at least 5 months. + def backup_code_reminder_visited + track_event(:backup_code_reminder_visited) + end + # Track user creating new BackupCodeSetupForm, record form submission Hash # @param [Boolean] success Whether form validation was successful # @param [Hash] mfa_method_counts Hash of MFA method with the number of that method on the account diff --git a/app/views/users/backup_code_setup/reminder.html.erb b/app/views/users/backup_code_reminder/show.html.erb similarity index 56% rename from app/views/users/backup_code_setup/reminder.html.erb rename to app/views/users/backup_code_reminder/show.html.erb index 770ab54031e..fec8fe6e8d1 100644 --- a/app/views/users/backup_code_setup/reminder.html.erb +++ b/app/views/users/backup_code_reminder/show.html.erb @@ -1,19 +1,19 @@ -<% self.title = t('forms.backup_code.title') %> +<% self.title = t('forms.backup_code_reminder.heading') %> <%= image_tag asset_url('user-signup.svg'), width: 107, height: 119, alt: '', class: 'margin-bottom-4', aria: { hidden: true } %> <%= render PageHeadingComponent.new.with_content(t('forms.backup_code_reminder.heading')) %> -

+

<%= t('forms.backup_code_reminder.body_info') %>

-<%= button_to( - account_path, - method: :get, - class: 'usa-button usa-button--wide usa-button--big margin-bottom-3', - ) do %> - <%= t('forms.backup_code_reminder.have_codes') %> -<% end %> +
+ <%= render ButtonComponent.new( + url: account_path, + big: true, + wide: true, + ).with_content(t('forms.backup_code_reminder.have_codes')) %> +
<%= link_to t('forms.backup_code_reminder.need_new_codes'), backup_code_regenerate_path %> diff --git a/config/routes.rb b/config/routes.rb index cfd32ce457d..0cf6cf6027e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -299,7 +299,8 @@ get '/users/two_factor_authentication' => 'users/two_factor_authentication#show', as: :user_two_factor_authentication # route name is used by two_factor_authentication gem get '/backup_code_refreshed' => 'users/backup_code_setup#refreshed' - get '/backup_code_reminder' => 'users/backup_code_setup#reminder' + get '/backup_code_reminder' => 'users/backup_code_reminder#show' + post '/backup_code_reminder' => 'users/backup_code_reminder#update' get '/backup_code_confirm_setup' => 'users/backup_code_setup#new' post '/backup_code_setup' => 'users/backup_code_setup#create' get '/backup_code_setup' => 'users/backup_code_setup#index' diff --git a/spec/controllers/concerns/backup_code_reminder_concern_spec.rb b/spec/controllers/concerns/backup_code_reminder_concern_spec.rb new file mode 100644 index 00000000000..3cd33dfa65e --- /dev/null +++ b/spec/controllers/concerns/backup_code_reminder_concern_spec.rb @@ -0,0 +1,77 @@ +require 'rails_helper' + +RSpec.describe BackupCodeReminderConcern do + let(:user) { create(:user, :fully_registered) } + + controller ApplicationController do + include BackupCodeReminderConcern + end + + before do + stub_sign_in(user) + end + + describe '#user_needs_backup_code_reminder?' do + subject(:user_needs_backup_code_reminder?) { controller.user_needs_backup_code_reminder? } + + context 'if user has dismissed reminder in current session' do + before do + controller.user_session[:dismissed_backup_code_reminder] = true + end + + it { is_expected.to eq(false) } + end + + context 'if the user does not have backup codes' do + let(:user) { create(:user, :fully_registered, :with_phone) } + + it { is_expected.to eq(false) } + end + + context 'if the user has backup codes' do + context 'if the user account is less than 5 months old' do + let(:user) do + create(:user, :fully_registered, :with_phone, :with_backup_code, created_at: 1.day.ago) + end + + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.minute.ago) + end + + it { is_expected.to eq(false) } + end + + context 'if the user account is more than 5 months old' do + let(:user) do + create(:user, :fully_registered, :with_phone, :with_backup_code, created_at: 7.months.ago) + end + + context 'if the user has signed in more recently than 5 months ago' do + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 4.months.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.minute.ago) + end + + it { is_expected.to eq(false) } + end + + context 'if the user not signed in within the past 5 months' do + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 6.months.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.minute.ago) + end + + it { is_expected.to eq(true) } + end + + context 'if the user is fully authenticating for the first time' do + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.minute.ago) + end + + it { is_expected.to eq(true) } + end + end + end + end +end diff --git a/spec/controllers/users/backup_code_reminder_controller_spec.rb b/spec/controllers/users/backup_code_reminder_controller_spec.rb new file mode 100644 index 00000000000..c897f89b470 --- /dev/null +++ b/spec/controllers/users/backup_code_reminder_controller_spec.rb @@ -0,0 +1,86 @@ +require 'rails_helper' + +RSpec.describe Users::BackupCodeReminderController do + let(:user) { create(:user) } + + before do + stub_sign_in(user) if user + end + + describe '#show' do + subject(:response) { get :show } + + it 'flashes successful authentication message' do + response + + expect(flash[:success]).to eq(t('notices.authenticated_successfully')) + end + + it 'logs analytics' do + stub_analytics + + response + + expect(@analytics).to have_logged_event(:backup_code_reminder_visited) + end + + context 'if signed out' do + let(:user) { nil } + + it 'redirects to sign in page' do + expect(response).to redirect_to(new_user_session_path) + end + end + end + + describe '#update' do + subject(:response) { post :update, params: params } + let(:params) { {} } + + it 'assigns user session value acknowledging dismissed reminder' do + response + + expect(controller.user_session[:dismissed_backup_code_reminder]).to eq(true) + end + + context 'if user confirms they have codes' do + let(:params) { { has_codes: 'true' } } + + it 'logs analytics' do + stub_analytics + + response + + expect(@analytics).to have_logged_event(:backup_code_reminder_submitted, has_codes: true) + end + + it 'redirects to after-sign-in path' do + expect(response).to redirect_to(account_path) + end + end + + context 'if user requests new codes' do + let(:params) { {} } + + it 'logs analytics' do + stub_analytics + + response + + expect(@analytics).to have_logged_event(:backup_code_reminder_submitted, has_codes: false) + end + + it 'redirects to backup code regenerate path' do + expect(response).to redirect_to(backup_code_regenerate_path) + end + end + + context 'if signed out' do + let(:user) { nil } + + it 'redirects to sign in page' do + expect(response).to redirect_to(new_user_session_path) + end + end + end +end diff --git a/spec/controllers/users/backup_code_setup_controller_spec.rb b/spec/controllers/users/backup_code_setup_controller_spec.rb index 71b7286c975..5e5051e95c1 100644 --- a/spec/controllers/users/backup_code_setup_controller_spec.rb +++ b/spec/controllers/users/backup_code_setup_controller_spec.rb @@ -8,7 +8,7 @@ :authenticate_user!, :confirm_user_authenticated_for_2fa_setup, :apply_secure_headers_override, - [:confirm_recently_authenticated_2fa, except: ['reminder', 'continue']], + [:confirm_recently_authenticated_2fa, except: ['continue']], :validate_multi_mfa_selection, ) end diff --git a/spec/features/two_factor_authentication/backup_code_sign_in_spec.rb b/spec/features/two_factor_authentication/backup_code_sign_in_spec.rb index 3d049ea6755..0ee7efdc365 100644 --- a/spec/features/two_factor_authentication/backup_code_sign_in_spec.rb +++ b/spec/features/two_factor_authentication/backup_code_sign_in_spec.rb @@ -45,4 +45,37 @@ assert_navigation { click_submit_default } end end + + context 'when the user needs a backup code reminder' do + let(:user) do + create(:user, created_at: 10.months.ago, second_mfa_reminder_dismissed_at: 8.months.ago) + end + + let!(:event) do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 9.months.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 8.months.ago) + end + + it 'redirects the user to the backup code reminder url and allows user to confirm possession' do + fill_in t('forms.two_factor.backup_code'), with: codes.sample + click_submit_default + + expect(page).to have_current_path(backup_code_reminder_path) + + click_on t('forms.backup_code_reminder.have_codes') + + expect(page).to have_current_path(account_path) + end + + it 'redirects the user to the backup code reminder url and allows user to create new codes' do + fill_in t('forms.two_factor.backup_code'), with: codes.sample + click_submit_default + + expect(page).to have_current_path(backup_code_reminder_path) + + click_on t('forms.backup_code_reminder.need_new_codes') + + expect(page).to have_current_path(backup_code_regenerate_path) + end + end end diff --git a/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb b/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb index 659123c2802..f109775f2ff 100644 --- a/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb +++ b/spec/features/two_factor_authentication/backup_code_sign_up_spec.rb @@ -82,21 +82,6 @@ expect(page).to have_current_path(sign_up_completed_path) end - context 'when the user needs a backup code reminder' do - let!(:user) { create(:user, :fully_registered, :with_authentication_app, :with_backup_code) } - let!(:event) do - create(:event, user: user, event_type: :sign_in_after_2fa, created_at: 9.months.ago) - end - - it 'redirects the user to the backup code reminder url' do - sign_in_user(user) - fill_in_code_with_last_totp(user) - click_submit_default - - expect(page).to have_current_path backup_code_reminder_path - end - end - def sign_out_user first(:button, t('links.sign_out')).click end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index af90db40662..8d6a887cd20 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1680,13 +1680,32 @@ def it_should_not_send_survey end describe '#second_last_signed_in_at' do - it 'returns second most recent full authentication event' do - user = create(:user) - _event1 = create(:event, user: user, event_type: 'sign_in_after_2fa') - event2 = create(:event, user: user, event_type: 'sign_in_after_2fa') - _event3 = create(:event, user: user, event_type: 'sign_in_after_2fa') + subject(:second_last_signed_in_at) { user.second_last_signed_in_at(since: 3.months.ago) } + let(:user) { create(:user) } + + around do |example| + freeze_time { example.run } + end + + context 'in timeframe with multiple matched sign-in events' do + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.month.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 2.months.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 4.months.ago) + end + + it 'returns date of second most recent full authentication event' do + expect(second_last_signed_in_at).to eq(2.months.ago) + end + end + + context 'in timeframe with one or fewer matched sign-in events' do + before do + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 1.month.ago) + create(:event, user:, event_type: :sign_in_after_2fa, created_at: 4.months.ago) + end - expect(user.second_last_signed_in_at).to eq(event2.reload.created_at) + it { is_expected.to be_nil } end end diff --git a/spec/views/users/backup_code_setup/reminder.html.erb_spec.rb b/spec/views/users/backup_code_reminder/show.html.erb_spec.rb similarity index 53% rename from spec/views/users/backup_code_setup/reminder.html.erb_spec.rb rename to spec/views/users/backup_code_reminder/show.html.erb_spec.rb index 78882c82b66..bc66a99328b 100644 --- a/spec/views/users/backup_code_setup/reminder.html.erb_spec.rb +++ b/spec/views/users/backup_code_reminder/show.html.erb_spec.rb @@ -1,8 +1,8 @@ require 'rails_helper' -RSpec.describe 'users/backup_code_setup/reminder.html.erb' do +RSpec.describe 'users/backup_code_reminder/show.html.erb' do it 'has a localized title' do - expect(view).to receive(:title=).with(t('forms.backup_code.title')) + expect(view).to receive(:title=).with(t('forms.backup_code_reminder.heading')) render end @@ -10,21 +10,19 @@ it 'has a localized heading' do render - expect(rendered).to have_content \ - t('forms.backup_code_reminder.heading') + expect(rendered).to have_content(t('forms.backup_code_reminder.heading')) end it 'has localized body info' do render - expect(rendered).to have_content \ - t('forms.backup_code_reminder.body_info') + expect(rendered).to have_content(t('forms.backup_code_reminder.body_info')) end it 'has a cancel link to account path' do render - expect(rendered).to have_button(t('forms.backup_code_reminder.have_codes')) + expect(rendered).to have_link(t('forms.backup_code_reminder.have_codes')) end it 'has a regenerate backup code link' do From 21daf9bc5c3ab30b1b9d7830907e3874c55c79d4 Mon Sep 17 00:00:00 2001 From: Jonathan Hooper Date: Wed, 15 Jan 2025 09:50:41 -0500 Subject: [PATCH 3/5] Remove AAMVA attribute related config flags (#11724) We have added logic to conditionally send information to AAMVA. We are not planning to reduce the scope of what we send to AAMVA so these flags are no longer necessary. This commit removes them. changelog: Internal, AAMVA, Feature flags for conditionally sending attributes to AAMVA were removed --- .../doc_auth/lexis_nexis/doc_pii_reader.rb | 18 +--- .../aamva/request/verification_request.rb | 24 ++--- config/application.yml.default | 5 - lib/identity_config.rb | 3 - .../responses/true_id_response_spec.rb | 23 ++--- .../request/verification_request_spec.rb | 98 ++++++------------- 6 files changed, 52 insertions(+), 119 deletions(-) diff --git a/app/services/doc_auth/lexis_nexis/doc_pii_reader.rb b/app/services/doc_auth/lexis_nexis/doc_pii_reader.rb index 26e172491fc..79a46b11d64 100644 --- a/app/services/doc_auth/lexis_nexis/doc_pii_reader.rb +++ b/app/services/doc_auth/lexis_nexis/doc_pii_reader.rb @@ -27,11 +27,11 @@ def read_pii(true_id_product) state_id_type_slug = id_auth_field_data['Fields_DocumentClassName'] state_id_type = DocAuth::Response::ID_TYPE_SLUGS[state_id_type_slug] - state_id_data = Pii::StateId.new( + Pii::StateId.new( first_name: id_auth_field_data['Fields_FirstName'], last_name: id_auth_field_data['Fields_Surname'], middle_name: id_auth_field_data['Fields_MiddleName'], - name_suffix: nil, + name_suffix: id_auth_field_data['Fields_NameSuffix'], address1: id_auth_field_data['Fields_AddressLine1'], address2: id_auth_field_data['Fields_AddressLine2'], city: id_auth_field_data['Fields_City'], @@ -42,8 +42,8 @@ def read_pii(true_id_product) month: id_auth_field_data['Fields_DOB_Month'], day: id_auth_field_data['Fields_DOB_Day'], ), - sex: nil, - height: nil, + sex: parse_sex_value(id_auth_field_data['Fields_Sex']), + height: parse_height_value(id_auth_field_data['Fields_Height']), weight: nil, eye_color: nil, state_id_expiration: parse_date( @@ -61,16 +61,6 @@ def read_pii(true_id_product) state_id_type: state_id_type, issuing_country_code: id_auth_field_data['Fields_CountryCode'], ) - - if IdentityConfig.store.doc_auth_read_additional_pii_attributes_enabled - state_id_data = state_id_data.with( - name_suffix: id_auth_field_data['Fields_NameSuffix'], - sex: parse_sex_value(id_auth_field_data['Fields_Sex']), - height: parse_height_value(id_auth_field_data['Fields_Height']), - ) - end - - state_id_data end def parse_date(year:, month:, day:) diff --git a/app/services/proofing/aamva/request/verification_request.rb b/app/services/proofing/aamva/request/verification_request.rb index 32e440407dc..34dfae42a90 100644 --- a/app/services/proofing/aamva/request/verification_request.rb +++ b/app/services/proofing/aamva/request/verification_request.rb @@ -63,14 +63,12 @@ def add_user_provided_data_to_body REXML::XPath.first(document, xpath).add_text(data) end - if IdentityConfig.store.aamva_send_middle_name - add_optional_element( - 'nc:PersonMiddleName', - value: applicant.middle_name, - document:, - inside: '//nc:PersonName', - ) - end + add_optional_element( + 'nc:PersonMiddleName', + value: applicant.middle_name, + document:, + inside: '//nc:PersonName', + ) add_optional_element( 'nc:PersonNameSuffixText', @@ -123,12 +121,10 @@ def add_user_provided_data_to_body inside: '//dldv:verifyDriverLicenseDataRequest', ) - if IdentityConfig.store.aamva_send_id_type - add_state_id_type( - applicant.state_id_data.state_id_type, - document, - ) - end + add_state_id_type( + applicant.state_id_data.state_id_type, + document, + ) @body = document.to_s end diff --git a/config/application.yml.default b/config/application.yml.default index 21ab799da38..ed4ab839b27 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -19,8 +19,6 @@ aamva_auth_url: 'https://example.org:12345/auth/url' aamva_cert_enabled: true aamva_private_key: '' aamva_public_key: '' -aamva_send_id_type: true -aamva_send_middle_name: true aamva_supported_jurisdictions: '["AL","AR","AZ","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","MA","MD","ME","MI","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","OH","OK","OR","PA","RI","SC","SD","TN","TX","VA","VT","WA","WI","WV","WY"]' aamva_verification_request_timeout: 5.0 aamva_verification_url: https://example.org:12345/verification/url @@ -106,7 +104,6 @@ doc_auth_error_sharpness_threshold: 40 doc_auth_max_attempts: 5 doc_auth_max_capture_attempts_before_native_camera: 3 doc_auth_max_submission_attempts_before_native_camera: 3 -doc_auth_read_additional_pii_attributes_enabled: false doc_auth_redirect_to_correct_vendor_disabled: false doc_auth_selfie_desktop_test_mode: false doc_auth_socure_wait_polling_refresh_max_seconds: 15 @@ -517,8 +514,6 @@ development: # production: aamva_auth_url: 'https://authentication-cert.aamva.org/Authentication/Authenticate.svc' - aamva_send_id_type: false - aamva_send_middle_name: false aamva_verification_url: 'https://verificationservices-cert.aamva.org:18449/dldv/2.1/online' disable_email_sending: false disable_logout_get_request: false diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 092f25addbc..82ebc291ae8 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -34,8 +34,6 @@ def self.store config.add(:aamva_cert_enabled, type: :boolean) config.add(:aamva_private_key, type: :string) config.add(:aamva_public_key, type: :string) - config.add(:aamva_send_id_type, type: :boolean) - config.add(:aamva_send_middle_name, type: :boolean) config.add(:aamva_supported_jurisdictions, type: :json) config.add(:aamva_verification_request_timeout, type: :float) config.add(:aamva_verification_url) @@ -125,7 +123,6 @@ def self.store config.add(:doc_auth_max_attempts, type: :integer) config.add(:doc_auth_max_capture_attempts_before_native_camera, type: :integer) config.add(:doc_auth_max_submission_attempts_before_native_camera, type: :integer) - config.add(:doc_auth_read_additional_pii_attributes_enabled, type: :boolean) config.add(:doc_auth_selfie_desktop_test_mode, type: :boolean) config.add(:doc_auth_socure_wait_polling_refresh_max_seconds, type: :integer) config.add(:doc_auth_socure_wait_polling_timeout_minutes, type: :integer) diff --git a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb index 51d3608784f..4a2e5bb4dec 100644 --- a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb +++ b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb @@ -134,7 +134,7 @@ state: 'MD', dob: '1986-07-01', sex: nil, - height: nil, + height: 69, weight: nil, eye_color: nil, state_id_expiration: '2099-10-15', @@ -146,7 +146,7 @@ issuing_country_code: 'USA', ) - expect(response.pii_from_doc).to eq(expected_state_id_pii) + expect(response.pii_from_doc.to_h).to eq(expected_state_id_pii.to_h) end it 'excludes pii fields from logging' do @@ -250,20 +250,11 @@ end end - context 'when doc_auth_read_additional_pii_attributes_enabled is enabled' do - before do - allow(IdentityConfig.store).to receive(:doc_auth_read_additional_pii_attributes_enabled) - .and_return(true) - end - + context 'when height is present' do let(:success_response_body) { LexisNexisFixtures.true_id_response_success } - it 'reads the additional PII attributes' do + it 'properly converts the height to inches' do pii_from_doc = response.pii_from_doc - - expect(pii_from_doc.first_name).to eq('LICENSE') - expect(pii_from_doc.name_suffix).to eq('JR') - expect(pii_from_doc.sex).to eq('male') expect(pii_from_doc.height).to eq(68) end @@ -366,8 +357,8 @@ def get_decision_product(resp) city: 'ANYTOWN', state: 'MD', dob: '1986-10-13', - sex: nil, - height: nil, + sex: 'male', + height: 70, weight: nil, eye_color: nil, state_id_expiration: '2099-10-15', @@ -379,7 +370,7 @@ def get_decision_product(resp) issuing_country_code: nil, ) - expect(response.pii_from_doc).to eq(expected_state_id_pii) + expect(response.pii_from_doc.to_h).to eq(expected_state_id_pii.to_h) end end diff --git a/spec/services/proofing/aamva/request/verification_request_spec.rb b/spec/services/proofing/aamva/request/verification_request_spec.rb index ff092966c78..1a9a5865bd0 100644 --- a/spec/services/proofing/aamva/request/verification_request_spec.rb +++ b/spec/services/proofing/aamva/request/verification_request_spec.rb @@ -117,6 +117,13 @@ ) end + it 'includes middle_name if it is present' do + applicant.middle_name = 'test_name' + expect(subject.body).to include( + 'test_name', + ) + end + context '#sex' do context 'when the sex is male' do it 'sends a sex code value of 1' do @@ -144,86 +151,43 @@ end end - context '#middle_name' do - context 'when the feature flag is off' do - before do - allow(IdentityConfig.store).to receive(:aamva_send_middle_name).and_return(false) - end - - it 'does not add a PersonMiddleName node' do - applicant.middle_name = 'test_name' - expect(subject.body).to_not include('') + context '#state_id_type' do + context 'when the type is a Drivers License' do + it 'includes DocumentCategoryCode=1' do + applicant.state_id_data.state_id_type = 'drivers_license' + expect(subject.body).to include( + '1', + ) end end - context 'when the feature flag is on' do - before do - allow(IdentityConfig.store).to receive(:aamva_send_middle_name).and_return(true) - end - - it 'does add a PersonMiddleName node' do - applicant.middle_name = 'test_name' + context 'when the type is a learners permit' do + it 'includes DocumentCategoryCode=2' do + applicant.state_id_data.state_id_type = 'drivers_permit' expect(subject.body).to include( - 'test_name', + '2', ) end end - end - context '#state_id_type' do - context 'when the feature flag is off' do - before do - expect(IdentityConfig.store).to receive(:aamva_send_id_type).and_return(false) - end - - it 'does not add a DocumentCategoryCode' do - applicant.state_id_data.state_id_type = 'drivers_license' - expect(subject.body).to_not include('') + context 'when the type is an ID Card' do + it 'includes DocumentCategoryCode=3' do + applicant.state_id_data.state_id_type = 'state_id_card' + expect(subject.body).to include( + '3', + ) end end - context 'when the feature flag is on' do - before do - expect(IdentityConfig.store).to receive(:aamva_send_id_type).and_return(true) - end - - context 'when the type is a Drivers License' do - it 'includes DocumentCategoryCode=1' do - applicant.state_id_data.state_id_type = 'drivers_license' - expect(subject.body).to include( - '1', - ) - end - end - - context 'when the type is a learners permit' do - it 'includes DocumentCategoryCode=2' do - applicant.state_id_data.state_id_type = 'drivers_permit' - expect(subject.body).to include( - '2', - ) - end - end - - context 'when the type is an ID Card' do - it 'includes DocumentCategoryCode=3' do - applicant.state_id_data.state_id_type = 'state_id_card' - expect(subject.body).to include( - '3', - ) - end + context 'when the type is something invalid' do + it 'does not add a DocumentCategoryCode for nil ID type' do + applicant.state_id_data.state_id_type = nil + expect(subject.body).to_not include('') end - context 'when the type is something invalid' do - it 'does not add a DocumentCategoryCode for nil ID type' do - applicant.state_id_data.state_id_type = nil - expect(subject.body).to_not include('') - end - - it 'does not add a DocumentCategoryCode for invalid ID types' do - applicant.state_id_data.state_id_type = 'License to Keep an Alpaca' - expect(subject.body).to_not include('') - end + it 'does not add a DocumentCategoryCode for invalid ID types' do + applicant.state_id_data.state_id_type = 'License to Keep an Alpaca' + expect(subject.body).to_not include('') end end end From a1436452b1829b9d9f952a09d437181866d3f583 Mon Sep 17 00:00:00 2001 From: Jenny Verdeyen Date: Wed, 15 Jan 2025 09:56:45 -0500 Subject: [PATCH 4/5] LG-15379 removes post office closure alerts from barcode page and email (#11733) * LG-15379 removes post office closure alerts from barcode page and email changelog: User-Facing Improvements, In-person proofing, removes post office closure alerts from barcode page and email --- .../in_person/ready_to_verify_controller.rb | 2 - app/mailers/user_mailer.rb | 14 ----- .../in_person/ready_to_verify/show.html.erb | 8 --- .../in_person_post_office_closed.html.erb | 2 - .../_in_person_ready_to_verify.html.erb | 15 ----- config/application.yml.default | 2 - config/locales/en.yml | 5 -- config/locales/es.yml | 5 -- config/locales/fr.yml | 5 -- config/locales/zh.yml | 5 -- lib/identity_config.rb | 1 - .../ready_to_verify_controller_spec.rb | 14 ----- spec/mailers/previews/user_mailer_preview.rb | 4 -- spec/mailers/user_mailer_spec.rb | 63 ------------------- .../ready_to_verify/show.html.erb_spec.rb | 44 ------------- 15 files changed, 189 deletions(-) delete mode 100644 app/views/user_mailer/in_person_post_office_closed.html.erb diff --git a/app/controllers/idv/in_person/ready_to_verify_controller.rb b/app/controllers/idv/in_person/ready_to_verify_controller.rb index 79e7172745d..fbd0aeeee2c 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -18,8 +18,6 @@ class ReadyToVerifyController < ApplicationController def show @is_enhanced_ipp = resolved_authn_context_result.enhanced_ipp? - @show_closed_post_office_banner = - IdentityConfig.store.in_person_proofing_post_office_closed_alert_enabled analytics.idv_in_person_ready_to_verify_visit(**opt_in_analytics_properties) @presenter = ReadyToVerifyPresenter.new( enrollment: enrollment, diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index caed7d1e823..611e4c48d07 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -312,8 +312,6 @@ def in_person_ready_to_verify(enrollment:, is_enhanced_ipp:) is_enhanced_ipp: is_enhanced_ipp, ) @is_enhanced_ipp = is_enhanced_ipp - @show_closed_post_office_banner = - IdentityConfig.store.in_person_proofing_post_office_closed_alert_enabled mail( to: email_address.email, @@ -328,8 +326,6 @@ def in_person_ready_to_verify_reminder(enrollment:) ).image_data @is_enhanced_ipp = enrollment.enhanced_ipp? - @show_closed_post_office_banner = - IdentityConfig.store.in_person_proofing_post_office_closed_alert_enabled with_user_locale(user) do @presenter = Idv::InPerson::ReadyToVerifyPresenter.new( @@ -439,16 +435,6 @@ def account_reinstated end end - def in_person_post_office_closed - with_user_locale(user) do - @hide_title = true - mail( - to: email_address.email, - subject: t('in_person_proofing.post_office_closed.email.subject'), - ) - end - end - private attr_reader :user, :email_address diff --git a/app/views/idv/in_person/ready_to_verify/show.html.erb b/app/views/idv/in_person/ready_to_verify/show.html.erb index 109f9cdd468..6cc213c8a91 100644 --- a/app/views/idv/in_person/ready_to_verify/show.html.erb +++ b/app/views/idv/in_person/ready_to_verify/show.html.erb @@ -228,14 +228,6 @@ <% end %> -<%# Alert %> -<% if @show_closed_post_office_banner %> - <%= render AlertComponent.new(type: :warning, class: 'margin-y-4', text_tag: :div) do %> -

<%= t('in_person_proofing.post_office_closed.heading') %>

-

<%= t('in_person_proofing.post_office_closed.body') %>

- <% end %> -<% end %> - <% if !@is_enhanced_ipp %>

<%= t('in_person_proofing.body.location.change_location_heading') %>

diff --git a/app/views/user_mailer/in_person_post_office_closed.html.erb b/app/views/user_mailer/in_person_post_office_closed.html.erb deleted file mode 100644 index 14abf7ed812..00000000000 --- a/app/views/user_mailer/in_person_post_office_closed.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -

<%= t('in_person_proofing.post_office_closed.email.heading') %>

-

<%= t('in_person_proofing.post_office_closed.email.body_html') %>

diff --git a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb index 3db2200a903..9fcddaa4dbd 100644 --- a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb +++ b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb @@ -275,21 +275,6 @@ <% end %> -<%# alert %> -<% if @show_closed_post_office_banner %> - - - - - -
- <%= image_tag('email/warning.png', width: 16, height: 16, alt: '', style: 'margin-top: 4px;') %> - -

<%= t('in_person_proofing.post_office_closed.heading') %>

-

<%= t('in_person_proofing.post_office_closed.body') %>

-
-<% end %> - <% if !@is_enhanced_ipp %>

<%= t('in_person_proofing.body.location.change_location_heading') %>

diff --git a/config/application.yml.default b/config/application.yml.default index ed4ab839b27..cbcec5b2cc1 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -193,7 +193,6 @@ in_person_outage_message_enabled: false in_person_proofing_enabled: false in_person_proofing_enforce_tmx: false in_person_proofing_opt_in_enabled: false -in_person_proofing_post_office_closed_alert_enabled: true in_person_results_delay_in_hours: 1 in_person_send_proofing_notifications_enabled: false in_person_stop_expiring_enrollments: false @@ -560,7 +559,6 @@ test: hmac_fingerprinter_key: a2c813d4dca919340866ba58063e4072adc459b767a74cf2666d5c1eef3861db26708e7437abde1755eb24f4034386b0fea1850a1cb7e56bff8fae3cc6ade96c hmac_fingerprinter_key_queue: '["old-key-one", "old-key-two"]' identity_pki_disabled: true - in_person_proofing_post_office_closed_alert_enabled: false lexisnexis_trueid_account_id: 'test_account' lockout_period_in_minutes: 5 logins_per_email_and_ip_limit: 2 diff --git a/config/locales/en.yml b/config/locales/en.yml index 332fd7014e1..01413fae31c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1327,11 +1327,6 @@ in_person_proofing.headings.state_id_milestone_2: Enter the information on your in_person_proofing.headings.switch_back: Switch back to your computer to prepare to verify your identity in person in_person_proofing.headings.update_address: Update your current address in_person_proofing.headings.update_state_id: Update the information on your ID -in_person_proofing.post_office_closed.body: Post Office locations will resume regular hours on Friday, January 10, 2025. -in_person_proofing.post_office_closed.email.body_html: You will not be able to visit a Post Office on Thursday, January 9, 2025 to finish verifying your identity. Post Office locations will resume regular hours on Friday, January 10, 2025. -in_person_proofing.post_office_closed.email.heading: All Post Offices will be closed on January 9, 2025 to honor former President Jimmy Carter -in_person_proofing.post_office_closed.email.subject: All Post Offices will be closed on Thursday, January 9, 2025 -in_person_proofing.post_office_closed.heading: All Post Offices will be closed on Thursday, January 9, 2025 to honor former President Jimmy Carter. in_person_proofing.process.barcode.caption_label: Enrollment code in_person_proofing.process.barcode.heading: Show your %{app_name} barcode in_person_proofing.process.barcode.info: The retail associate needs to scan your barcode at the top of this page. You can print this page or show it on your mobile device. diff --git a/config/locales/es.yml b/config/locales/es.yml index 6c3a7ea4a9d..7f915783dcf 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1338,11 +1338,6 @@ in_person_proofing.headings.state_id_milestone_2: Ingrese la información de su in_person_proofing.headings.switch_back: Vuelva a su computadora para preparar la verificación de su identidad en persona in_person_proofing.headings.update_address: Actualice su dirección actual in_person_proofing.headings.update_state_id: Actualice la información de su identificación -in_person_proofing.post_office_closed.body: Las oficinas de correos reanudarán su horario habitual el viernes 10 de enero de 2025. -in_person_proofing.post_office_closed.email.body_html: No podrás visitar una Oficina de Correos el jueves 9 de enero de 2025 para terminar de verificar tu identidad. Las oficinas de correos reanudarán su horario habitual el viernes 10 de enero de 2025. -in_person_proofing.post_office_closed.email.heading: Todas las oficinas de correos estarán cerradas el 9 de enero de 2025 en honor al expresidente Jimmy Carter -in_person_proofing.post_office_closed.email.subject: Todas las oficinas de correos estarán cerradas el jueves 9 de enero de 2025 -in_person_proofing.post_office_closed.heading: Todas las oficinas de correos estarán cerradas el jueves 9 de enero de 2025 en honor al ex presidente Jimmy Carter. in_person_proofing.process.barcode.caption_label: Código de registro in_person_proofing.process.barcode.heading: Muestre su código de barras de %{app_name} in_person_proofing.process.barcode.info: El empleado debe escanear el código de barras que aparece en la parte superior de esta página. Puede imprimir esta página o mostrarla en su dispositivo móvil. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 827f65367ad..df55dd7df15 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1327,11 +1327,6 @@ in_person_proofing.headings.state_id_milestone_2: Saisissez les informations fig in_person_proofing.headings.switch_back: Revenez à votre ordinateur pour vous préparer à confirmer votre identité en personne in_person_proofing.headings.update_address: Mettez à jour votre adresse actuelle in_person_proofing.headings.update_state_id: Mettez à jour les informations figurant sur votre document d’identité -in_person_proofing.post_office_closed.body: Les bureaux de poste reprendront leurs horaires habituels le vendredi 10 janvier 2025. -in_person_proofing.post_office_closed.email.body_html: Vous ne pourrez pas vous rendre dans un bureau de Poste le jeudi 9 janvier 2025 pour terminer la vérification de votre identité. Les bureaux de poste reprendront leurs horaires habituels le vendredi 10 janvier 2025 -in_person_proofing.post_office_closed.email.heading: Tous les bureaux de poste seront fermés le 9 janvier 2025 en l’honneur de l’ancien président Jimmy Carter -in_person_proofing.post_office_closed.email.subject: Tous les bureaux de poste seront fermés le jeudi 9 janvier 2025 -in_person_proofing.post_office_closed.heading: Tous les bureaux de poste seront fermés le jeudi 9 janvier 2025 en l’honneur de l’ancien président Jimmy Carter. in_person_proofing.process.barcode.caption_label: Code d’inscription in_person_proofing.process.barcode.heading: Montrez votre code-barres %{app_name} in_person_proofing.process.barcode.info: Le préposé doit scanner votre code-barres en haut de cette page. Vous pouvez imprimer cette page ou la montrer sur votre appareil mobile. diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 20b499180b1..b4882d157e2 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -1340,11 +1340,6 @@ in_person_proofing.headings.state_id_milestone_2: 输入你州政府颁发身份 in_person_proofing.headings.switch_back: 切换回你的电脑,来准备亲身去验证身份。 in_person_proofing.headings.update_address: 更新你当前地址 in_person_proofing.headings.update_state_id: 更新你身份证件上的信息 -in_person_proofing.post_office_closed.body: 邮局地点将于 2025 年 1 月 10 日星期五恢复正常工作时间。 -in_person_proofing.post_office_closed.email.body_html: 您将无法在 2025 年 1 月 9 日星期四前往邮局完成身份验证。 邮局地点将于 2025 年 1 月 10 日星期五恢复正常工作时间 -in_person_proofing.post_office_closed.email.heading: 所有邮局将于 2025 年 1 月 9 日关闭,以纪念前总统吉米·卡特 -in_person_proofing.post_office_closed.email.subject: 所有邮局将于 2025 年 1 月 9 日星期四关闭 -in_person_proofing.post_office_closed.heading: 所有邮局将于 2025 年 1 月 9 日关闭,以纪念前总统吉米·卡特。 in_person_proofing.process.barcode.caption_label: 注册代码 in_person_proofing.process.barcode.heading: 出示你的 %{app_name} 条形码 in_person_proofing.process.barcode.info: 邮局工作人员需要扫描该页顶部的条形码你可以把该页打印出来,或在你的移动设备上显示。 diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 82ebc291ae8..fef3200fbb7 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -217,7 +217,6 @@ def self.store config.add(:in_person_proofing_enabled, type: :boolean) config.add(:in_person_proofing_enforce_tmx, type: :boolean) config.add(:in_person_proofing_opt_in_enabled, type: :boolean) - config.add(:in_person_proofing_post_office_closed_alert_enabled, type: :boolean) config.add(:in_person_results_delay_in_hours, type: :integer) config.add(:in_person_send_proofing_notifications_enabled, type: :boolean) config.add(:in_person_stop_expiring_enrollments, type: :boolean) diff --git a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb index 86e3f4664c5..cc14296fd92 100644 --- a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb +++ b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb @@ -32,7 +32,6 @@ context 'with in person proofing enabled' do let(:in_person_proofing_enabled) { true } - let(:ipp_post_office_closed_alert_enabled) { false } context 'authenticated' do before do @@ -128,19 +127,6 @@ expect(assigns(:is_enhanced_ipp)).to be true end end - - context 'with in_person_proofing_post_office_closed_alert_enabled' do - let(:ipp_post_office_closed_alert_enabled) { true } - before do - allow(IdentityConfig.store) - .to receive(:in_person_proofing_post_office_closed_alert_enabled) - .and_return(ipp_post_office_closed_alert_enabled) - end - - it 'renders the show template' do - expect(response).to render_template :show - end - end end end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 9f36238d62f..66edf8f05ee 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -286,10 +286,6 @@ def account_reinstated ).account_reinstated end - def in_person_post_office_closed - UserMailer.with(user: user, email_address: email_address_record).in_person_post_office_closed - end - private def user diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 6c182992a74..93e5c9d94c4 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -934,50 +934,6 @@ def expect_email_body_to_have_help_and_contact_links end end - context 'post office closed alert' do - context 'when the post office closed alert flag is disabled' do - before do - allow(IdentityConfig.store) - .to receive(:in_person_proofing_post_office_closed_alert_enabled) - .and_return(false) - end - - it 'does not render the post office closed alert' do - aggregate_failures do - [ - t('in_person_proofing.post_office_closed.heading'), - t('in_person_proofing.post_office_closed.body'), - ].each do |copy| - Array(copy).each do |part| - expect(mail.html_part.body).to_not have_content(part) - end - end - end - end - end - - context 'when the post office closed alert flag is enabled' do - before do - allow(IdentityConfig.store) - .to receive(:in_person_proofing_post_office_closed_alert_enabled) - .and_return(true) - end - - it 'renders the post office closed alert' do - aggregate_failures do - [ - t('in_person_proofing.post_office_closed.heading'), - t('in_person_proofing.post_office_closed.body'), - ].each do |copy| - Array(copy).each do |part| - expect(mail.html_part.body).to have_content(part) - end - end - end - end - end - end - context 'Need to change location section' do context 'when Enhanced IPP is not enabled' do let(:is_enhanced_ipp) { false } @@ -1623,23 +1579,4 @@ def expect_email_body_to_have_help_and_contact_links it_behaves_like 'a system email' it_behaves_like 'an email that respects user email locale preference' end - - describe '#in_person_post_office_closed' do - let(:mail) do - UserMailer.with(user: user, email_address: email_address).in_person_post_office_closed - end - - it_behaves_like 'a system email' - it_behaves_like 'an email that respects user email locale preference' - - it 'includes a translated header' do - expect(mail.html_part.body) - .to include(t('in_person_proofing.post_office_closed.email.heading', locale: :en)) - end - - it 'includes a translated body' do - expect(mail.html_part.body) - .to include(t('in_person_proofing.post_office_closed.email.body_html', locale: :en)) - end - end end diff --git a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb index f5874ffb8a2..04bccd8e056 100644 --- a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -176,50 +176,6 @@ end end - context 'post office warning' do - context 'when the show closed post office banner is disabled' do - before do - @show_closed_post_office_banner = false - end - - it 'does not render the post office closed alert' do - render - - aggregate_failures do - [ - t('in_person_proofing.post_office_closed.heading'), - t('in_person_proofing.post_office_closed.body'), - ].each do |copy| - Array(copy).each do |part| - expect(rendered).to_not have_content(part) - end - end - end - end - end - - context 'when the show closed post office banner is enabled' do - before do - @show_closed_post_office_banner = true - end - - it 'renders the post office closed alert' do - render - - aggregate_failures do - [ - t('in_person_proofing.post_office_closed.heading'), - t('in_person_proofing.post_office_closed.body'), - ].each do |copy| - Array(copy).each do |part| - expect(rendered).to have_content(part) - end - end - end - end - end - end - context 'what to expect section' do context 'when Enhanced IPP is not enabled' do let(:is_enhanced_ipp) { false } From a1584b04ddca58e000a9ad02f82acb560170ef29 Mon Sep 17 00:00:00 2001 From: A Shukla Date: Wed, 15 Jan 2025 09:26:58 -0600 Subject: [PATCH 5/5] changelog: Bug Fixes, screen reader, changing aria label for selfie capture (#11739) --- .../packages/document-capture/components/acuant-capture.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 9f4cc97d979..ec969c0302b 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -764,7 +764,7 @@ function AcuantCapture( >