From 769cc46b7dd0d743d678187f3809f5582195e1f0 Mon Sep 17 00:00:00 2001 From: "Davi (she/they)" Date: Thu, 3 Apr 2025 12:21:18 -0400 Subject: [PATCH 1/8] Login completed and initiated events (#12047) * changelog: Upcoming Features, Attempts API, Add login and logout events --- .../concerns/saml_idp_logout_concern.rb | 2 ++ .../authorization_controller.rb | 2 ++ .../openid_connect/logout_controller.rb | 7 ++++ app/controllers/saml_idp_controller.rb | 2 ++ app/controllers/sign_out_controller.rb | 2 ++ app/controllers/users/sessions_controller.rb | 1 + app/services/attempts_api/tracker_events.rb | 16 ++++++++- .../events/sign-in/LogoutInitiated.yml | 5 +++ .../authorization_controller_spec.rb | 36 +++++++++++++++++++ .../openid_connect/logout_controller_spec.rb | 6 ++++ spec/controllers/saml_idp_controller_spec.rb | 24 +++++++++++++ spec/controllers/sign_out_controller_spec.rb | 3 ++ .../users/sessions_controller_spec.rb | 8 +++++ spec/features/users/sign_up_spec.rb | 5 +++ spec/support/shared_examples/sign_in.rb | 5 +++ 15 files changed, 123 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/saml_idp_logout_concern.rb b/app/controllers/concerns/saml_idp_logout_concern.rb index 343f00e4934..a6c4d7b0970 100644 --- a/app/controllers/concerns/saml_idp_logout_concern.rb +++ b/app/controllers/concerns/saml_idp_logout_concern.rb @@ -62,6 +62,8 @@ def logout_response def track_logout_event sp_initiated = saml_request.present? + attempts_api_tracker.logout_initiated(success: true) + analytics.logout_initiated( sp_initiated: sp_initiated, oidc: false, diff --git a/app/controllers/openid_connect/authorization_controller.rb b/app/controllers/openid_connect/authorization_controller.rb index 2c07e98e1f1..38416870267 100644 --- a/app/controllers/openid_connect/authorization_controller.rb +++ b/app/controllers/openid_connect/authorization_controller.rb @@ -236,6 +236,8 @@ def track_events acr_values: sp_session[:acr_values], sign_in_duration_seconds:, ) + + attempts_api_tracker.login_completed track_billing_events end diff --git a/app/controllers/openid_connect/logout_controller.rb b/app/controllers/openid_connect/logout_controller.rb index 2db0f22cf3b..ad21471dc3e 100644 --- a/app/controllers/openid_connect/logout_controller.rb +++ b/app/controllers/openid_connect/logout_controller.rb @@ -23,6 +23,10 @@ def show original_method: session[:original_method], ) + attempts_api_tracker.logout_initiated( + success: result.success?, + ) + if result.success? && redirect_uri handle_successful_logout_request(result, redirect_uri) else @@ -46,6 +50,9 @@ def delete redirect_uri = result.extra[:redirect_uri] analytics.oidc_logout_submitted(**to_event(result)) + attempts_api_tracker.logout_initiated( + success: result.success?, + ) if result.success? && redirect_uri handle_logout(result, redirect_uri) diff --git a/app/controllers/saml_idp_controller.rb b/app/controllers/saml_idp_controller.rb index 63d9689e650..4ec6e563e61 100644 --- a/app/controllers/saml_idp_controller.rb +++ b/app/controllers/saml_idp_controller.rb @@ -222,6 +222,8 @@ def track_events acr_values: sp_session[:acr_values], sign_in_duration_seconds:, ) + + attempts_api_tracker.login_completed track_billing_events end diff --git a/app/controllers/sign_out_controller.rb b/app/controllers/sign_out_controller.rb index 038f7a7a924..a0655b75833 100644 --- a/app/controllers/sign_out_controller.rb +++ b/app/controllers/sign_out_controller.rb @@ -5,6 +5,8 @@ class SignOutController < ApplicationController def destroy analytics.logout_initiated(method: 'cancel link') + attempts_api_tracker.logout_initiated(success: true) + url_after_cancellation = decorated_sp_session.cancel_link_url sign_out flash[:success] = t('devise.sessions.signed_out') diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index cef07f24ee2..2b3e408da2b 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -57,6 +57,7 @@ def destroy redirect_to root_path else analytics.logout_initiated(sp_initiated: false, oidc: false) + attempts_api_tracker.logout_initiated(success: true) super end end diff --git a/app/services/attempts_api/tracker_events.rb b/app/services/attempts_api/tracker_events.rb index 789304a155f..12600474f91 100644 --- a/app/services/attempts_api/tracker_events.rb +++ b/app/services/attempts_api/tracker_events.rb @@ -25,12 +25,26 @@ def logged_in_account_purged(success:) # A logged-in user has attempted to change their password def logged_in_password_change(success:, failure_reason: nil) track_event( - :logged_in_password_change, + 'logged-in-password-change', success: success, failure_reason:, ) end + # A user has successfully logged in and is being handed off to integration + def login_completed + track_event('login-completed') + end + + # @param [Boolean] success + # A user has initiated a logout event + def logout_initiated(success:) + track_event( + 'logout-initiated', + success:, + ) + end + # @param [Boolean] success # A user has attempted to enroll the Backup Codes MFA method to their account def mfa_enroll_backup_code(success:) diff --git a/docs/attempts-api/schemas/events/sign-in/LogoutInitiated.yml b/docs/attempts-api/schemas/events/sign-in/LogoutInitiated.yml index 73d5e5692ca..15153f3b125 100644 --- a/docs/attempts-api/schemas/events/sign-in/LogoutInitiated.yml +++ b/docs/attempts-api/schemas/events/sign-in/LogoutInitiated.yml @@ -2,3 +2,8 @@ description: The user has logged out of their account. allOf: - $ref: '../shared/EventProperties.yml' - type: object + properties: + success: + type: boolean + description: | + Indicates whether the logout was successfully initiated \ No newline at end of file diff --git a/spec/controllers/openid_connect/authorization_controller_spec.rb b/spec/controllers/openid_connect/authorization_controller_spec.rb index eeeef7aec9c..abb5a3d337b 100644 --- a/spec/controllers/openid_connect/authorization_controller_spec.rb +++ b/spec/controllers/openid_connect/authorization_controller_spec.rb @@ -112,6 +112,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!(verified_attributes: %w[given_name family_name birthdate]) @@ -166,6 +169,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!(verified_attributes: %w[given_name family_name birthdate]) @@ -261,6 +267,9 @@ it 'tracks IAL2 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 2) user.identities.last.update!( @@ -577,6 +586,9 @@ it 'tracks IAL2 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 2) user.identities.last.update!( @@ -651,6 +663,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!( @@ -727,6 +742,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!( @@ -860,6 +878,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!(verified_attributes: %w[given_name family_name birthdate]) @@ -911,6 +932,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!(verified_attributes: %w[given_name family_name birthdate]) @@ -1007,6 +1031,9 @@ it 'tracks IAL2 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 2) user.identities.last.update!( @@ -1363,6 +1390,9 @@ it 'tracks IAL2 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 2) user.identities.last.update!( @@ -1437,6 +1467,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!( @@ -1513,6 +1546,9 @@ it 'tracks IAL1 authentication event' do travel_to now + 15.seconds stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) IdentityLinker.new(user, service_provider).link_identity(ial: 1) user.identities.last.update!( diff --git a/spec/controllers/openid_connect/logout_controller_spec.rb b/spec/controllers/openid_connect/logout_controller_spec.rb index 86fa260d6c1..8a95ca2e02a 100644 --- a/spec/controllers/openid_connect/logout_controller_spec.rb +++ b/spec/controllers/openid_connect/logout_controller_spec.rb @@ -84,6 +84,9 @@ it 'tracks events' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) action @@ -661,6 +664,9 @@ it 'tracks events' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) action diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb index 23e472fda2b..a5af8ae2b59 100644 --- a/spec/controllers/saml_idp_controller_spec.rb +++ b/spec/controllers/saml_idp_controller_spec.rb @@ -46,6 +46,9 @@ it 'tracks the event when idp initiated' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) delete :logout, params: { path_year: path_year } @@ -71,6 +74,9 @@ it 'tracks the event when sp initiated' do allow(controller).to receive(:saml_request).and_return(FakeSamlLogoutRequest.new) stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) delete :logout, params: { SAMLRequest: 'foo', path_year: path_year } @@ -84,6 +90,9 @@ it 'tracks the event when the saml request is invalid' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) delete :logout, params: { SAMLRequest: 'foo', path_year: path_year } @@ -147,6 +156,9 @@ it 'tracks the request' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) delete :logout, params: UriService.params( OneLogin::RubySaml::Logoutrequest.new.create(wrong_cert_settings), @@ -870,6 +882,9 @@ def name_id_version(format_urn) it 'tracks IAL2 authentication events' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) allow(controller).to receive(:identity_needs_verification?).and_return(false) saml_get_auth(ial2_settings) @@ -1027,6 +1042,9 @@ def name_id_version(format_urn) it 'tracks IAL2 authentication events' do stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) allow(controller).to receive(:identity_needs_verification?).and_return(false) saml_get_auth(ialmax_settings) @@ -2734,6 +2752,9 @@ def stub_requested_attributes it 'tracks the authentication without IdV redirection event' do user = create(:user, :fully_registered) stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) session[:sign_in_flow] = :sign_in allow(controller).to receive(:identity_needs_verification?).and_return(false) @@ -2784,6 +2805,9 @@ def stub_requested_attributes it 'tracks the authentication with finish_profile==true' do user = create(:user, :fully_registered) stub_analytics + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:login_completed) session[:sign_in_flow] = :sign_in allow(controller).to receive(:identity_needs_verification?).and_return(false) allow(controller).to receive(:user_has_pending_profile?).and_return(true) diff --git a/spec/controllers/sign_out_controller_spec.rb b/spec/controllers/sign_out_controller_spec.rb index c53b2c6ce42..5ed8f6b8596 100644 --- a/spec/controllers/sign_out_controller_spec.rb +++ b/spec/controllers/sign_out_controller_spec.rb @@ -22,6 +22,9 @@ it 'tracks the event' do stub_sign_in_before_2fa stub_analytics + stub_attempts_tracker + + allow(@attempts_api_tracker).to receive(:logout_initiated).with(success: true) allow(controller.decorated_sp_session).to receive(:cancel_link_url).and_return('foo') get :destroy diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 192ee61a742..8be313f0c97 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -52,6 +52,9 @@ describe 'GET /logout' do it 'does not log user out and redirects to root' do sign_in_as_user + stub_attempts_tracker + + expect(@attempts_api_tracker).to_not receive(:logout_initiated) get :destroy expect(controller.current_user).to_not be nil expect(response).to redirect_to root_url @@ -62,6 +65,11 @@ it 'tracks a logout event' do stub_analytics sign_in_as_user + stub_attempts_tracker + + expect(@attempts_api_tracker).to receive(:logout_initiated).with( + success: true, + ) delete :destroy diff --git a/spec/features/users/sign_up_spec.rb b/spec/features/users/sign_up_spec.rb index a61e54b7f5c..a33a36d7b86 100644 --- a/spec/features/users/sign_up_spec.rb +++ b/spec/features/users/sign_up_spec.rb @@ -467,6 +467,11 @@ def clipboard_text freeze_time do analytics = FakeAnalytics.new allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(analytics) + attempts_api_tracker = AttemptsApiTrackingHelper::FakeAttemptsTracker.new + allow_any_instance_of(ApplicationController).to receive(:attempts_api_tracker).and_return( + attempts_api_tracker, + ) + expect(attempts_api_tracker).to receive(:login_completed) visit_idp_from_sp_with_ial1(:oidc) travel_to Time.zone.now + 15.seconds diff --git a/spec/support/shared_examples/sign_in.rb b/spec/support/shared_examples/sign_in.rb index 61809a45c63..9c0867a4f7f 100644 --- a/spec/support/shared_examples/sign_in.rb +++ b/spec/support/shared_examples/sign_in.rb @@ -36,6 +36,11 @@ user = create(:user, :fully_registered) analytics = FakeAnalytics.new(user:) allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(analytics) + attempts_api_tracker = AttemptsApiTrackingHelper::FakeAttemptsTracker.new + allow_any_instance_of(ApplicationController).to receive(:attempts_api_tracker).and_return( + attempts_api_tracker, + ) + expect(attempts_api_tracker).to receive(:login_completed) visit_idp_from_sp_with_ial1(sp) travel_to Time.zone.now + 15.seconds From 7df4c1f58bdc40e00887a148aa4ee89c710a6d3c Mon Sep 17 00:00:00 2001 From: Doug Price Date: Thu, 3 Apr 2025 14:47:40 -0400 Subject: [PATCH 2/8] LG-15435: Conditionally show passport as option if available on Welcome and How to Verify (#12034) * LG-15435: Conditionally show passport as option if available Updates to IdV Welcome page. Updates to IdV How to Verify page. Updated translations with new copy. changelog: Upcoming Features, Passport Support, Update front IdV pages to inform user about passport option if available. * remove obsolete precondition for WelcomeController * move the referenced id to the h1 * review comments. log `doc_auth_vendor` and `passport_allowed` * create dcs before logging event * fix analytics_spec --------- Co-authored-by: Amir Reavis-Bey --- .../idv/how_to_verify_controller.rb | 15 +- app/controllers/idv/welcome_controller.rb | 23 ++- app/presenters/idv/how_to_verify_presenter.rb | 59 ++++--- app/presenters/idv/welcome_presenter.rb | 13 +- app/services/analytics_events.rb | 12 ++ app/views/idv/how_to_verify/show.html.erb | 165 +++++++++--------- config/locales/en.yml | 29 ++- config/locales/es.yml | 27 ++- config/locales/fr.yml | 27 ++- config/locales/zh.yml | 29 ++- .../idv/welcome_controller_spec.rb | 21 ++- spec/features/idv/analytics_spec.rb | 20 +-- .../idv/doc_auth/how_to_verify_spec.rb | 6 +- .../idv/doc_auth/hybrid_handoff_spec.rb | 4 +- spec/features/idv/in_person_spec.rb | 8 +- .../idv/steps/in_person_opt_in_ipp_spec.rb | 2 +- spec/presenters/idv/welcome_presenter_spec.rb | 23 ++- spec/support/features/doc_auth_helper.rb | 6 +- .../idv/how_to_verify/show.html.erb_spec.rb | 72 +++++--- spec/views/idv/welcome/show.html.erb_spec.rb | 13 +- 20 files changed, 320 insertions(+), 254 deletions(-) diff --git a/app/controllers/idv/how_to_verify_controller.rb b/app/controllers/idv/how_to_verify_controller.rb index e25963eedc7..07657d6eb9e 100644 --- a/app/controllers/idv/how_to_verify_controller.rb +++ b/app/controllers/idv/how_to_verify_controller.rb @@ -5,6 +5,7 @@ class HowToVerifyController < ApplicationController include Idv::AvailabilityConcern include IdvStepConcern include RenderConditionConcern + include DocAuthVendorConcern before_action :confirm_step_allowed before_action :set_how_to_verify_presenter @@ -64,9 +65,9 @@ def self.step_info idv_session.service_provider&.in_person_proofing_enabled end, undo_step: ->(idv_session:, user:) { - idv_session.skip_doc_auth_from_how_to_verify = nil - idv_session.opted_in_to_in_person_proofing = nil - }, + idv_session.skip_doc_auth_from_how_to_verify = nil + idv_session.opted_in_to_in_person_proofing = nil + }, ) end @@ -96,6 +97,7 @@ def set_how_to_verify_presenter @presenter = Idv::HowToVerifyPresenter.new( mobile_required: @mobile_required, selfie_check_required: @selfie_required, + passport_allowed: idv_session.passport_allowed, ) end @@ -103,12 +105,5 @@ def mobile_required? idv_session.selfie_check_required || document_capture_session.doc_auth_vendor == Idp::Constants::Vendors::SOCURE end - - def document_capture_session - return @document_capture_session if defined?(@document_capture_session) - @document_capture_session = DocumentCaptureSession.find_by( - uuid: idv_session.document_capture_session_uuid, - ) - end end end diff --git a/app/controllers/idv/welcome_controller.rb b/app/controllers/idv/welcome_controller.rb index dd07247868b..6a8dab40406 100644 --- a/app/controllers/idv/welcome_controller.rb +++ b/app/controllers/idv/welcome_controller.rb @@ -7,8 +7,10 @@ class WelcomeController < ApplicationController include StepIndicatorConcern include DocAuthVendorConcern + before_action :confirm_step_allowed before_action :confirm_not_rate_limited before_action :cancel_previous_in_person_enrollments, only: :show + before_action :update_doc_auth_vendor before_action :update_passport_allowed, only: :show, if: -> { IdentityConfig.store.doc_auth_passports_enabled } @@ -20,15 +22,16 @@ def show Funnel::DocAuth::RegisterStep.new(current_user.id, sp_session[:issuer]) .call('welcome', :view, true) - @presenter = Idv::WelcomePresenter.new(decorated_sp_session) + @presenter = Idv::WelcomePresenter.new( + decorated_sp_session:, + passport_allowed: idv_session.passport_allowed, + ) end def update clear_future_steps! - analytics.idv_doc_auth_welcome_submitted(**analytics_arguments) - create_document_capture_session - + analytics.idv_doc_auth_welcome_submitted(**analytics_arguments) idv_session.welcome_visited = true redirect_to idv_agreement_url @@ -39,10 +42,12 @@ def self.step_info key: :welcome, controller: self, next_steps: [:agreement], - preconditions: ->(idv_session:, user:) { !user.gpo_verification_pending_profile? }, + preconditions: ->(idv_session:, user:) { true }, undo_step: ->(idv_session:, user:) do idv_session.welcome_visited = nil idv_session.document_capture_session_uuid = nil + idv_session.bucketed_doc_auth_vendor = nil + idv_session.passport_allowed = nil end, ) end @@ -53,6 +58,8 @@ def analytics_arguments { step: 'welcome', analytics_id: 'Doc Auth', + doc_auth_vendor: idv_session.bucketed_doc_auth_vendor, + passport_allowed: idv_session.passport_allowed, }.merge(ab_test_analytics_buckets) end @@ -72,10 +79,14 @@ def cancel_previous_in_person_enrollments ) end + def update_doc_auth_vendor + doc_auth_vendor + end + def update_passport_allowed + return if !IdentityConfig.store.doc_auth_passports_enabled return if resolved_authn_context_result.facial_match? return if doc_auth_vendor == Idp::Constants::Vendors::SOCURE - idv_session.passport_allowed ||= begin if dos_passport_api_healthy?(analytics:) (ab_test_bucket(:DOC_AUTH_PASSPORT) == :passport_allowed) diff --git a/app/presenters/idv/how_to_verify_presenter.rb b/app/presenters/idv/how_to_verify_presenter.rb index ee161ca8284..827b2a1e27e 100644 --- a/app/presenters/idv/how_to_verify_presenter.rb +++ b/app/presenters/idv/how_to_verify_presenter.rb @@ -4,22 +4,23 @@ class Idv::HowToVerifyPresenter include ActionView::Helpers::TagHelper include ActionView::Helpers::TranslationHelper - attr_reader :mobile_required, :selfie_required + attr_reader :mobile_required, :selfie_required, :passport_allowed - def initialize(mobile_required:, selfie_check_required:) + def initialize(mobile_required:, selfie_check_required:, passport_allowed:) @mobile_required = mobile_required @selfie_required = selfie_check_required + @passport_allowed = passport_allowed end def how_to_verify_info - if mobile_required - t('doc_auth.info.how_to_verify_mobile') - else - t('doc_auth.info.how_to_verify') - end + t('doc_auth.headings.how_to_verify') + end + + def header_text + t('doc_auth.headings.how_to_verify') end - def asset_url + def online_asset_url if mobile_required 'idv/mobile-phone-icon.svg' else @@ -27,7 +28,7 @@ def asset_url end end - def alt_text + def online_asset_alt_text if mobile_required t('image_description.phone_icon') else @@ -51,34 +52,46 @@ def verify_online_instruction end def verify_online_description - if mobile_required - t('doc_auth.info.verify_online_description_mobile') + if passport_allowed + t('doc_auth.info.verify_online_description_passport') else - t('doc_auth.info.verify_online_description') + '' end end - def submit + def online_submit if mobile_required - t('forms.buttons.continue_remote_mobile') + t('forms.buttons.continue_online_mobile') else - t('forms.buttons.continue_remote') + t('forms.buttons.continue_online') end end + def post_office_asset_url + 'idv/in-person.svg' + end + + def post_office_asset_alt_text + t('image_description.post_office') + end + + def verify_at_post_office_text + t('doc_auth.headings.verify_at_post_office') + end + def post_office_instruction - if selfie_required - t('doc_auth.info.verify_at_post_office_instruction_selfie') - else - t('doc_auth.info.verify_at_post_office_instruction') - end + t('doc_auth.info.verify_at_post_office_instruction') end def post_office_description - if mobile_required - t('doc_auth.info.verify_at_post_office_description_mobile') + if passport_allowed + t('doc_auth.info.verify_at_post_office_description_passport_html') else - t('doc_auth.info.verify_at_post_office_description') + '' end end + + def post_office_submit + t('forms.buttons.continue_ipp') + end end diff --git a/app/presenters/idv/welcome_presenter.rb b/app/presenters/idv/welcome_presenter.rb index d2a1fc3f7af..60eadae56d0 100644 --- a/app/presenters/idv/welcome_presenter.rb +++ b/app/presenters/idv/welcome_presenter.rb @@ -14,8 +14,9 @@ class WelcomePresenter attr_accessor :url_options - def initialize(decorated_sp_session) + def initialize(decorated_sp_session:, passport_allowed:) @decorated_sp_session = decorated_sp_session + @passport_allowed = passport_allowed @url_options = {} end @@ -45,7 +46,7 @@ def explanation_text(help_link) def bullet_points [ bullet_point( - t('doc_auth.instructions.bullet1'), + id_type_copy, t('doc_auth.instructions.text1'), ), @@ -68,12 +69,18 @@ def bullet_points private - attr_accessor :decorated_sp_session + attr_reader :decorated_sp_session, :passport_allowed def current_user decorated_sp_session&.current_user end + def id_type_copy + return t('doc_auth.instructions.bullet1b') if passport_allowed + + t('doc_auth.instructions.bullet1a') + end + def bullet_point(bullet, text) BulletPoint.new(bullet: bullet, text: text) end diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 2804a6da92c..6aa1ecea9b1 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2322,11 +2322,15 @@ def idv_doc_auth_warning_visited(step_name:, remaining_submit_attempts:, **extra # User submits IdV welcome screen # @param [String] step Current IdV step # @param [String] analytics_id Current IdV flow identifier + # @param [String] doc_auth_vendor Vendor used for document capture + # @param [Boolean] passport_allowed Whether passport is allowed for document capture # @param [Boolean] skip_hybrid_handoff Whether skipped hybrid handoff A/B test is active # @param [Boolean] opted_in_to_in_person_proofing User opted into in person proofing def idv_doc_auth_welcome_submitted( step:, analytics_id:, + doc_auth_vendor:, + passport_allowed:, opted_in_to_in_person_proofing: nil, skip_hybrid_handoff: nil, **extra @@ -2335,6 +2339,8 @@ def idv_doc_auth_welcome_submitted( 'IdV: doc auth welcome submitted', step:, analytics_id:, + doc_auth_vendor:, + passport_allowed:, opted_in_to_in_person_proofing:, skip_hybrid_handoff:, **extra, @@ -2344,11 +2350,15 @@ def idv_doc_auth_welcome_submitted( # User visits IdV welcome screen # @param [String] step Current IdV step # @param [String] analytics_id Current IdV flow identifier + # @param [String] doc_auth_vendor Vendor used for document capture + # @param [Boolean] passport_allowed Whether passport is allowed for document capture # @param [Boolean] skip_hybrid_handoff Whether skipped hybrid handoff A/B test is active # @param [Boolean] opted_in_to_in_person_proofing User opted into in person proofing def idv_doc_auth_welcome_visited( step:, analytics_id:, + doc_auth_vendor:, + passport_allowed:, opted_in_to_in_person_proofing: nil, skip_hybrid_handoff: nil, **extra @@ -2357,6 +2367,8 @@ def idv_doc_auth_welcome_visited( 'IdV: doc auth welcome visited', step:, analytics_id:, + doc_auth_vendor:, + passport_allowed:, skip_hybrid_handoff:, opted_in_to_in_person_proofing:, **extra, diff --git a/app/views/idv/how_to_verify/show.html.erb b/app/views/idv/how_to_verify/show.html.erb index 4c1ee1f7fa8..9573e4e29d8 100644 --- a/app/views/idv/how_to_verify/show.html.erb +++ b/app/views/idv/how_to_verify/show.html.erb @@ -7,9 +7,9 @@ ) %> <% end %> -<% self.title = t('doc_auth.headings.how_to_verify') %> +<% self.title = @presenter.header_text %> -<%= render PageHeadingComponent.new.with_content(t('doc_auth.headings.how_to_verify')) %> +<%= render PageHeadingComponent.new(id: 'how-to-verify-info').with_content(@presenter.header_text) %> <% if defined?(error) %> <%= render AlertComponent.new( @@ -21,67 +21,79 @@ <% end %> <% end %> -

<%= @presenter.how_to_verify_info %>

-
-
- <%= image_tag( - asset_url(@presenter.asset_url), - width: 88, - height: 88, - alt: @presenter.alt_text, - ) %> -
-
- <%= simple_form_for( - @idv_how_to_verify_form, - html: { - id: nil, - aria: { label: @presenter.submit }, - class: 'margin-top-3', - }, - method: :put, - url: idv_how_to_verify_url, - ) do |f| - %> - <%= f.hidden_field( - :selection, - value: Idv::HowToVerifyForm::REMOTE, +
+
+ <%= image_tag( + asset_url(@presenter.online_asset_url), + width: 88, + height: 88, + alt: @presenter.online_asset_alt_text, ) %> - <%= f.label( - :selection_remote, - ) do %> - <% if @mobile_required %> - - <%= t('doc_auth.tips.mobile_phone_required') %> - - <% end %> -

<%= @presenter.verify_online_text %>

-
-

<%= @presenter.verify_online_instruction %>

-

<%= @presenter.verify_online_description %>

-
- <% end %> - <%= f.submit @presenter.submit, class: 'display-block margin-top-3 margin-bottom-5' %> - <% end %> -
-
-
- <%= image_tag( - asset_url('idv/in-person.svg'), - width: 88, - height: 88, - class: 'margin-right-1 margin-top-3', - alt: t('image_description.post_office'), +
+ <%= simple_form_for( + @idv_how_to_verify_form, + html: { + id: nil, + aria: { label: @presenter.online_submit }, + class: 'margin-top-3', + }, + method: :put, + url: idv_how_to_verify_url, + ) do |f| + %> + <%= f.hidden_field( + :selection, + value: Idv::HowToVerifyForm::REMOTE, ) %> + <%= f.label( + :selection_remote, + ) do %> + <% if @mobile_required %> + + <%= t('doc_auth.tips.mobile_phone_required') %> + + <% end %> +

<%= @presenter.verify_online_text %>

+
+

<%= @presenter.verify_online_instruction %> + <%= @presenter.verify_online_description %>

+

+ <%= new_tab_link_to( + t('doc_auth.info.verify_online_link_text'), + help_center_redirect_path( + category: 'verify-your-identity', + article: 'overview', + flow: :idv, + step: :how_to_verify, + location: 'troubleshooting_options', + ), + ) %> +

+
+ <% end %> + <%= f.submit @presenter.online_submit, class: 'display-block margin-top-3 margin-bottom-5' %> + <% end %> +
+ +
+
+ <%= image_tag( + asset_url(@presenter.post_office_asset_url), + width: 88, + height: 88, + class: 'margin-right-1 margin-top-3', + alt: @presenter.post_office_asset_alt_text, + ) %> +
<%= simple_form_for( @idv_how_to_verify_form, html: { id: nil, class: 'margin-top-3', - aria: { label: t('forms.buttons.continue_ipp') }, + aria: { label: @presenter.post_office_submit }, }, method: :put, url: idv_how_to_verify_url, @@ -94,10 +106,22 @@ <%= f.label( :selection_ipp, ) do %> -

<%= t('doc_auth.headings.verify_at_post_office') %>

+

<%= @presenter.verify_at_post_office_text %>

-

<%= @presenter.post_office_instruction %>

-

<%= @presenter.post_office_description %>

+

<%= @presenter.post_office_instruction %> + <%= @presenter.post_office_description %>

+

+ <%= new_tab_link_to( + t('doc_auth.info.verify_at_post_office_link_text'), + help_center_redirect_path( + category: 'verify-your-identity', + article: 'verify-your-identity-in-person', + flow: :idv, + step: :how_to_verify, + location: 'troubleshooting_options', + ), + ) %> +

<% end %> <%= f.submit t('forms.buttons.continue_ipp'), class: 'display-block margin-top-3 margin-bottom-5', outline: true %> @@ -105,33 +129,4 @@
-<%= render( - 'shared/troubleshooting_options', - heading_tag: :h3, - heading: t('doc_auth.info.how_to_verify_troubleshooting_options_header'), - options: [ - { - url: help_center_redirect_path( - category: 'verify-your-identity', - article: 'overview', - flow: :idv, - step: :how_to_verify, - location: 'troubleshooting_options', - ), - text: t('doc_auth.info.verify_online_link_text'), - new_tab: true, - }, - { - url: help_center_redirect_path( - category: 'verify-your-identity', - article: 'verify-your-identity-in-person', - flow: :idv, - step: :how_to_verify, - location: 'troubleshooting_options', - ), - text: t('doc_auth.info.verify_at_post_office_link_text'), - new_tab: true, - }, - ], - ) %> <%= render 'idv/doc_auth/cancel', step: 'how_to_verify' %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 4525adfc6e5..74d8f8ad935 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -604,7 +604,7 @@ doc_auth.headings.document_capture_front: Front of your ID doc_auth.headings.document_capture_selfie: Photo of your face doc_auth.headings.document_capture_subheader_selfie: Add a photo of your face doc_auth.headings.front: Front of your driver’s license or state ID -doc_auth.headings.how_to_verify: Choose how you want to verify your identity +doc_auth.headings.how_to_verify: Choose how to verify your ID doc_auth.headings.hybrid_handoff: How would you like to add your ID? doc_auth.headings.hybrid_handoff_selfie: Enter your phone number to switch devices doc_auth.headings.interstitial: We are processing your images @@ -620,7 +620,7 @@ doc_auth.headings.ssn_update: Update your Social Security number doc_auth.headings.text_message: We sent a message to your phone doc_auth.headings.upload_from_computer: Continue on this computer doc_auth.headings.upload_from_phone: Use your phone to take photos -doc_auth.headings.verify_at_post_office: Verify your identity at a Post Office +doc_auth.headings.verify_at_post_office: Go to a participating Post Office doc_auth.headings.verify_identity: Verify your identity doc_auth.headings.verify_online: Verify your identity online doc_auth.headings.verify_online_mobile: Verify your identity online using your phone @@ -645,9 +645,6 @@ doc_auth.info.exit.with_sp: Exit %{app_name} and return to %{sp_name} doc_auth.info.exit.without_sp: Exit identity verification and go to your account page doc_auth.info.getting_started_html: '%{sp_name} needs to make sure you are you — not someone pretending to be you. %{link_html}' doc_auth.info.getting_started_learn_more: Learn more about verifying your identity -doc_auth.info.how_to_verify: You have the option to verify your identity online, or in person at a participating Post Office. -doc_auth.info.how_to_verify_mobile: You have the option to verify your identity online with your phone, or in person at a participating Post Office. -doc_auth.info.how_to_verify_troubleshooting_options_header: Want to learn more about how to verify your identity? doc_auth.info.hybrid_handoff: We’ll collect information about you by reading your state‑issued ID. doc_auth.info.hybrid_handoff_ipp_html: 'Don’t have a mobile phone? You can verify your identity at a United States Post Office instead.' doc_auth.info.id_types_learn_more: Learn more about which ID types you can use @@ -683,20 +680,18 @@ doc_auth.info.stepping_up_html: Verify your identity again to access this servic doc_auth.info.tag: Recommended doc_auth.info.upload_from_computer: Don’t have a phone? Upload photos of your ID from this computer. doc_auth.info.upload_from_phone: You won’t have to sign in again, and you’ll switch back to this computer after you take photos. Your mobile phone must have a camera and a web browser. -doc_auth.info.verify_at_post_office_description: This option is better if you don’t have a phone to take photos of your ID. -doc_auth.info.verify_at_post_office_description_mobile: Choose this option if you don’t have a phone to take pictures. -doc_auth.info.verify_at_post_office_instruction: You’ll enter your ID information online, and verify your identity in person at a participating Post Office. -doc_auth.info.verify_at_post_office_instruction_selfie: You’ll enter your ID information online, and verify your identity in person at a participating Post Office. +doc_auth.info.verify_at_post_office_description_passport_html: You can only use a U.S. driver’s license or state ID. You cannot use a U.S. passport book for this option. +doc_auth.info.verify_at_post_office_instruction: Enter your information online, then verify your identity in person at a participating Post Office. doc_auth.info.verify_at_post_office_link_text: Learn more about verifying in person doc_auth.info.verify_identity: We’ll ask for your ID, phone number, and other personal information to verify your identity against public records. -doc_auth.info.verify_online_description: This option is better if you have a phone to take photos of your ID. -doc_auth.info.verify_online_description_mobile: Choose this option if you have a phone to take pictures. -doc_auth.info.verify_online_instruction: You’ll take photos of your ID to verify your identity fully online. Most users finish this process in one sitting. -doc_auth.info.verify_online_instruction_mobile_no_selfie: You’ll take photos of your ID using a phone. Most users finish this process in one sitting. -doc_auth.info.verify_online_instruction_selfie: You’ll take photos of your ID and a photo of yourself using a phone. Most users finish this process in one sitting. +doc_auth.info.verify_online_description_passport: You can use a U.S. passport book, U.S. driver’s license or state ID. +doc_auth.info.verify_online_instruction: You’ll add photos of your ID and verify your identity fully online. +doc_auth.info.verify_online_instruction_mobile_no_selfie: You’ll take photos of your ID using a phone. +doc_auth.info.verify_online_instruction_selfie: You’ll take photos of your ID and yourself using a phone. doc_auth.info.verify_online_link_text: Learn more about verifying online doc_auth.info.you_entered: 'You entered:' -doc_auth.instructions.bullet1: Have a driver’s license or state ID +doc_auth.instructions.bullet1a: Have a driver’s license or state ID +doc_auth.instructions.bullet1b: Have a U.S. passport book, U.S. driver’s license or state ID doc_auth.instructions.bullet2: Enter your Social Security number doc_auth.instructions.bullet3: Match to your phone number doc_auth.instructions.bullet4: Re-enter your %{app_name} password @@ -876,8 +871,8 @@ forms.buttons.cancel: Yes, cancel forms.buttons.confirm: Confirm forms.buttons.continue: Continue forms.buttons.continue_ipp: Continue in person -forms.buttons.continue_remote: Continue online -forms.buttons.continue_remote_mobile: Continue on your phone +forms.buttons.continue_online: Continue online +forms.buttons.continue_online_mobile: Continue on your phone forms.buttons.delete: Delete forms.buttons.disable: Delete forms.buttons.edit: Edit diff --git a/config/locales/es.yml b/config/locales/es.yml index 78a46750568..bd763c97e41 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -631,7 +631,7 @@ doc_auth.headings.ssn_update: Actualice su número de Seguro Social doc_auth.headings.text_message: Enviamos un mensaje a su teléfono doc_auth.headings.upload_from_computer: Continúe en esta computadora doc_auth.headings.upload_from_phone: Utilice su teléfono para tomar fotos -doc_auth.headings.verify_at_post_office: Verifique su identidad en una oficina de correos +doc_auth.headings.verify_at_post_office: Vaya a una oficina de correos participante doc_auth.headings.verify_identity: Verifique su identidad doc_auth.headings.verify_online: Verifique su identidad en línea doc_auth.headings.verify_online_mobile: Verifique su identidad en línea con su teléfono @@ -656,9 +656,6 @@ doc_auth.info.exit.with_sp: Salir de %{app_name} y volver a %{sp_name} doc_auth.info.exit.without_sp: Salga de la verificación de identidad y vaya a la página de su cuenta doc_auth.info.getting_started_html: '%{sp_name} necesita asegurarse de que se trata de usted y no de alguien que se hace pasar por usted. %{link_html}' doc_auth.info.getting_started_learn_more: Obtenga más información sobre la verificación de su identidad -doc_auth.info.how_to_verify: Tiene la opción de verificar su identidad en línea, o en persona en una oficina de correos participante. -doc_auth.info.how_to_verify_mobile: Tiene la opción de verificar su identidad en línea con su teléfono, o en persona en una oficina de correos participante. -doc_auth.info.how_to_verify_troubleshooting_options_header: ¿Desea obtener más información sobre cómo verificar su identidad? doc_auth.info.hybrid_handoff: Recopilaremos información sobre usted leyendo su identificación emitida por el estado. doc_auth.info.hybrid_handoff_ipp_html: '¿No tiene un teléfono móvil? Puede verificar su identidad en una oficina de correos de los Estados Unidos.' doc_auth.info.id_types_learn_more: Obtenga más información acerca de los tipos de identificación que puede usar @@ -694,20 +691,18 @@ doc_auth.info.stepping_up_html: Verifique de nuevo su identidad para acceder a e doc_auth.info.tag: Recomendado doc_auth.info.upload_from_computer: '¿No tiene un teléfono? Cargue fotos de su identificación desde esta computadora.' doc_auth.info.upload_from_phone: No tendrá que volver a iniciar sesión y volverá a esta computadora después de tomar las fotos. Su teléfono móvil debe tener una cámara y un navegador web. -doc_auth.info.verify_at_post_office_description: Esta opción es mejor si no tiene un teléfono para tomar fotografías de su identificación. -doc_auth.info.verify_at_post_office_description_mobile: Elija esta opción si no tiene un teléfono para tomar fotografías. -doc_auth.info.verify_at_post_office_instruction: Ingresará la información de su identificación en línea, y verificará su identidad en persona en una oficina de correos participante. -doc_auth.info.verify_at_post_office_instruction_selfie: Ingresará la información de su identificación en línea, y verificará su identidad en persona en una oficina de correos participante. +doc_auth.info.verify_at_post_office_description_passport_html: Solo puede usar una licencia de conducir de los EE. UU. o una identificación estatal. Para esta opción, no puede usar un pasaporte estadounidense. +doc_auth.info.verify_at_post_office_instruction: Ingrese su información en línea, y verifique su identidad en persona en una oficina de correos participante. doc_auth.info.verify_at_post_office_link_text: Obtenga más información sobre la verificación en persona doc_auth.info.verify_identity: Le pediremos su identificación, número de teléfono y otros datos personales para verificar su identidad comparándola con los registros públicos. -doc_auth.info.verify_online_description: Esta opción es mejor si tiene un teléfono para tomar fotografías de su identificación. -doc_auth.info.verify_online_description_mobile: Elija esta opción si tiene un teléfono para tomar fotografías. -doc_auth.info.verify_online_instruction: Tomará fotografías de su identificación para verificar su identidad por completo en línea. La mayoría de los usuarios logran terminar este proceso en una sola sesión. -doc_auth.info.verify_online_instruction_mobile_no_selfie: Tomará fotografías de su identificación con un teléfono. La mayoría de los usuarios logran terminar este proceso en una sola sesión. -doc_auth.info.verify_online_instruction_selfie: Tomará con un teléfono fotos de su identificación y una foto de usted. La mayoría de los usuarios logran terminar este proceso en una sola sesión. +doc_auth.info.verify_online_description_passport: Puede usar un pasaporte estadounidense, una licencia de conducir de los EE. UU. o una identificación estatal. +doc_auth.info.verify_online_instruction: Agregará fotografías de su identificación y verificará su identidad por completo en línea. +doc_auth.info.verify_online_instruction_mobile_no_selfie: Tomará fotografías de su identificación con un teléfono. +doc_auth.info.verify_online_instruction_selfie: Tomará fotografías de su identificación y de usted con un teléfono. doc_auth.info.verify_online_link_text: Obtenga más información sobre la verificación en línea doc_auth.info.you_entered: 'Usted ingresó:' -doc_auth.instructions.bullet1: Tener una licencia de conducir o una tarjeta de identificación estatal +doc_auth.instructions.bullet1a: Tener una licencia de conducir o una tarjeta de identificación estatal +doc_auth.instructions.bullet1b: Tener un pasaporte estadounidense, una licencia de conducir de los EE. UU. o una identificación estatal doc_auth.instructions.bullet2: Ingresar su número de Seguro Social doc_auth.instructions.bullet3: Hacer coincidir su número de teléfono doc_auth.instructions.bullet4: Volver a ingresar su contraseña de %{app_name} @@ -887,8 +882,8 @@ forms.buttons.cancel: Sí, cancelar forms.buttons.confirm: Confirmar forms.buttons.continue: Continuar forms.buttons.continue_ipp: Continúe en persona -forms.buttons.continue_remote: Continúe en línea -forms.buttons.continue_remote_mobile: Continúe en su teléfono +forms.buttons.continue_online: Continúe en línea +forms.buttons.continue_online_mobile: Continúe en su teléfono forms.buttons.delete: Eliminar forms.buttons.disable: Eliminar forms.buttons.edit: Editar diff --git a/config/locales/fr.yml b/config/locales/fr.yml index bf205ac8262..bf65f6f2de5 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -620,7 +620,7 @@ doc_auth.headings.ssn_update: Mettre à jour votre numéro de sécurité sociale doc_auth.headings.text_message: Nous avons envoyé un message à votre téléphone doc_auth.headings.upload_from_computer: Continuer sur cet ordinateur doc_auth.headings.upload_from_phone: Utiliser votre téléphone pour prendre des photos -doc_auth.headings.verify_at_post_office: Confirmer votre identité en personne dans un bureau de poste +doc_auth.headings.verify_at_post_office: Vous rendre à un bureau de poste participant doc_auth.headings.verify_identity: Confirmer votre identité doc_auth.headings.verify_online: Confirmer votre identité en ligne doc_auth.headings.verify_online_mobile: Confirmer votre identité en ligne à l’aide de votre téléphone @@ -645,9 +645,6 @@ doc_auth.info.exit.with_sp: Quitter %{app_name} et revenir à %{sp_name} doc_auth.info.exit.without_sp: Quitter la vérification d’identité et accéder à la page de votre compte doc_auth.info.getting_started_html: '%{sp_name} doit s’assurer qu’il s’agit bien de vous et non de quelqu’un qui se fait passer pour vous. %{link_html}' doc_auth.info.getting_started_learn_more: En savoir plus sur la vérification de votre identité -doc_auth.info.how_to_verify: Vous pouvez confirmer votre identité en ligne ou en personne dans un bureau de poste participant. -doc_auth.info.how_to_verify_mobile: Vous avez la possibilité de confirmer votre identité en ligne avec votre téléphone ou en personne dans un bureau de poste participant. -doc_auth.info.how_to_verify_troubleshooting_options_header: Vous voulez en savoir plus sur la façon de confirmer votre identité? doc_auth.info.hybrid_handoff: Nous recueillerons des informations vous concernant en lisant votre pièce d’identité délivrée par un État. doc_auth.info.hybrid_handoff_ipp_html: 'Vous n’avez pas de téléphone portable? Vous pouvez confirmer votre identité dans un bureau de poste américain participant.' doc_auth.info.id_types_learn_more: En savoir plus sur les types de pièces d’identité que vous pouvez utiliser @@ -683,20 +680,18 @@ doc_auth.info.stepping_up_html: Veuillez confirmer à nouveau votre identité po doc_auth.info.tag: Recommandation doc_auth.info.upload_from_computer: Vous n’avez pas de téléphone ? Téléchargez les photos de votre pièce d’identité depuis cet ordinateur. doc_auth.info.upload_from_phone: Vous n’aurez pas à vous reconnecter. Vous reviendrez sur cet ordinateur après avoir pris des photos. Votre téléphone portable doit être équipé d’un appareil photo et d’un navigateur web. -doc_auth.info.verify_at_post_office_description: Cette option est préférable si vous n’avez pas de téléphone permettant de prendre des photos de votre pièce d’identité. -doc_auth.info.verify_at_post_office_description_mobile: Choisissez cette option si vous ne disposez pas d’un téléphone permettant de prendre des photos. -doc_auth.info.verify_at_post_office_instruction: Vous saisirez vos données d’identification en ligne et confirmerez votre identité en personne dans un bureau de poste participant. -doc_auth.info.verify_at_post_office_instruction_selfie: Vous saisirez vos données d’identification en ligne et confirmez votre identité en personne dans un bureau de poste participant. +doc_auth.info.verify_at_post_office_description_passport_html: Vous pouvez seulement utiliser un permis de conduire ou une carte d’identité d’un État des États-Unis. Le passeport des États-Unis n’est pas accepté dans ce cas. +doc_auth.info.verify_at_post_office_instruction: Saisissez vos renseignements en ligne puis confirmez votre identité en personne dans un bureau de poste participant. doc_auth.info.verify_at_post_office_link_text: En savoir plus sur la vérification en personne doc_auth.info.verify_identity: Nous vous demanderons votre pièce d’identité, numéro de téléphone et d’autres renseignements personnels afin de confirmer votre identité par rapport aux registres publics. -doc_auth.info.verify_online_description: Cette option est préférable si vous disposez d’un téléphone permettant de prendre des photos de votre pièce d’identité. -doc_auth.info.verify_online_description_mobile: Choisissez cette option si vous disposez d’un téléphone permettant de prendre des photos. -doc_auth.info.verify_online_instruction: Vous prendrez des photos de votre pièce d’identité pour confirmer votre identité entièrement en ligne. La plupart des utilisateurs y parviennent en une seule prise. -doc_auth.info.verify_online_instruction_mobile_no_selfie: Vous prendrez des photos de votre pièce d’identité à l’aide d’un téléphone. La plupart des utilisateurs effectuent l’ensemble du processus en une seule fois. -doc_auth.info.verify_online_instruction_selfie: Vous prendrez des photos de votre pièce d’identité et une photo de vous-même avec un téléphone. La plupart des utilisateurs y parviennent en une seule prise. +doc_auth.info.verify_online_description_passport: Vous pouvez utiliser un passeport, un permis de conduire une carte d’identité d’un État des États-Unis. +doc_auth.info.verify_online_instruction: Vous téléverserez des photos de votre pièce d’identité pour confirmer votre identité entièrement en ligne. +doc_auth.info.verify_online_instruction_mobile_no_selfie: Vous prendrez des photos de votre pièce d’identité à l’aide d’un téléphone. +doc_auth.info.verify_online_instruction_selfie: Vous prendrez des photos de votre pièce d’identité et une photo de vous-même avec un téléphone. doc_auth.info.verify_online_link_text: En savoir plus sur la vérification en ligne doc_auth.info.you_entered: 'Vous avez saisi :' -doc_auth.instructions.bullet1: Présenter votre permis de conduire ou votre carte d’identité d’un État +doc_auth.instructions.bullet1a: Présenter votre permis de conduire ou votre carte d’identité d’un État +doc_auth.instructions.bullet1b: Munissez-vous d’un passeport, d’un permis de conduire ou d’une carte d’identité d’un État des États-Unis doc_auth.instructions.bullet2: Saisir votre numéro de sécurité sociale doc_auth.instructions.bullet3: Vérifier la correspondance avec votre numéro de téléphone doc_auth.instructions.bullet4: Saisir à nouveau votre mot de passe %{app_name} @@ -876,8 +871,8 @@ forms.buttons.cancel: Oui, annuler forms.buttons.confirm: Confirmer forms.buttons.continue: Suite forms.buttons.continue_ipp: Continuer en personne -forms.buttons.continue_remote: Continuer en ligne -forms.buttons.continue_remote_mobile: Continuer sur votre téléphone +forms.buttons.continue_online: Continuer en ligne +forms.buttons.continue_online_mobile: Continuer sur votre téléphone forms.buttons.delete: Supprimer forms.buttons.disable: Supprimer forms.buttons.edit: Modifier diff --git a/config/locales/zh.yml b/config/locales/zh.yml index dd475a5ea24..d20712c525f 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -615,7 +615,7 @@ doc_auth.headings.document_capture_front: 你身份证件的正面 doc_auth.headings.document_capture_selfie: 你面部照片 doc_auth.headings.document_capture_subheader_selfie: 添加您面部照片 doc_auth.headings.front: 驾照或州政府颁发身份证件的正面 -doc_auth.headings.how_to_verify: 选择你想如何验证身份 +doc_auth.headings.how_to_verify: 选择如何验证你的身份证件 doc_auth.headings.hybrid_handoff: 你想怎么添加身份证件? doc_auth.headings.hybrid_handoff_selfie: 输入电话号码来切换设备 doc_auth.headings.interstitial: 我们正在处理你的图像 @@ -631,7 +631,7 @@ doc_auth.headings.ssn_update: 更新你的社会保障号码 doc_auth.headings.text_message: 我们给你的手机发了短信 doc_auth.headings.upload_from_computer: 在这台电脑上继续 doc_auth.headings.upload_from_phone: 使用手机拍照 -doc_auth.headings.verify_at_post_office: 去邮局验证身份 +doc_auth.headings.verify_at_post_office: 到一个参与本项目的邮局去 doc_auth.headings.verify_identity: 验证你的身份 doc_auth.headings.verify_online: 在网上验证身份 doc_auth.headings.verify_online_mobile: 使用手机在网上验证你的身份 @@ -656,9 +656,6 @@ doc_auth.info.exit.with_sp: 退出 %{app_name} 并返回 %{sp_name} doc_auth.info.exit.without_sp: 退出身份验证并到你的账户页面 doc_auth.info.getting_started_html: '%{sp_name} 需要确保你是你,而不是别人冒充你。 了解更多有关验证你身份的信息 %{link_html}' doc_auth.info.getting_started_learn_more: 了解有关验证你身份的更多信息 -doc_auth.info.how_to_verify: 你可以选择在网上验证身份或者到参与本项目的邮局亲身验证身份。 -doc_auth.info.how_to_verify_mobile: 你可以选择用你的手机在网上验证身份或者到参与本项目的邮局亲身验证身份。 -doc_auth.info.how_to_verify_troubleshooting_options_header: 想对验证身份获得更多了解吗? doc_auth.info.hybrid_handoff: 我们将通过读取州政府颁发给你的身份证件来收集你的信息。 doc_auth.info.hybrid_handoff_ipp_html: '没有手机?你可以去一个美国邮局验证身份。' doc_auth.info.id_types_learn_more: 了解有关你能使用的身份证件类型的更多信息 @@ -694,20 +691,18 @@ doc_auth.info.stepping_up_html: 再次验证你的身份以使用这项服务。 doc_auth.info.tag: 建议 doc_auth.info.upload_from_computer: 没有手机?从该电脑上传你身份证件的照片。 doc_auth.info.upload_from_phone: 你不必重新登录,而且拍完照后可以转回到该电脑。你的手机必须带有相机和网络浏览器。 -doc_auth.info.verify_at_post_office_description: 如果你没有手机拍身份证件照片,这一选项更好。 -doc_auth.info.verify_at_post_office_description_mobile: 如果你没有手机可以拍照,请选择该选项 -doc_auth.info.verify_at_post_office_instruction: 你在网上输入身份证件信息,然后到一个参与本项目的邮局去亲身验证身份。 -doc_auth.info.verify_at_post_office_instruction_selfie: 你在网上输入身份证件信息,然后到一个参与本项目的邮局去亲身验证身份。 +doc_auth.info.verify_at_post_office_description_passport_html: 你只能使用美国驾照或州身份证件。就这一选项你不能使用美国护照。 +doc_auth.info.verify_at_post_office_instruction: 在网上输入你的信息,然后到一个参与本项目的邮局去亲身验证你的身份。 doc_auth.info.verify_at_post_office_link_text: 对亲身验证获得更多了解 doc_auth.info.verify_identity: 我们会要求获得你的身份识别、电话号码和其他个人信息并通过与公共记录核对来验证你的身份。 -doc_auth.info.verify_online_description: 如果你没有移动设备或者无法轻松拍身份证件照片,这一选项更好。 -doc_auth.info.verify_online_description_mobile: 如果你有手机可以拍照,请选择该选项。 -doc_auth.info.verify_online_instruction: 你将拍身份证件的照片来完全在网上验证身份。大多数用户都能轻松完成这样流程。 -doc_auth.info.verify_online_instruction_mobile_no_selfie: 你将使用手机拍摄你的身份证件照片。大多数用户一次就能完成这个流程。 -doc_auth.info.verify_online_instruction_selfie: 你将用手机拍摄身份证件和本人的照片。大多数用户都能轻松完成这一流程。 +doc_auth.info.verify_online_description_passport: 你可以使用美国护照本、美国驾照或州身份证件。 +doc_auth.info.verify_online_instruction: 你将添加自己身份证件的照片来完全在网上验证身份。 +doc_auth.info.verify_online_instruction_mobile_no_selfie: 你将用手机拍摄你的身份证件照片。 +doc_auth.info.verify_online_instruction_selfie: 你将用手机拍摄自己身份证件和你本人的照片。 doc_auth.info.verify_online_link_text: 对网上验证获得更多了解 doc_auth.info.you_entered: 你输入了: -doc_auth.instructions.bullet1: 带上驾照或州身份证件 +doc_auth.instructions.bullet1a: 带上驾照或州身份证件 +doc_auth.instructions.bullet1b: 拥有美国护照本、美国驾照或州身份证件 doc_auth.instructions.bullet2: 输入你的社会保障号码 doc_auth.instructions.bullet3: 与你电话号码匹配 doc_auth.instructions.bullet4: 重新输入你 %{app_name} 密码 @@ -887,8 +882,8 @@ forms.buttons.cancel: 是的,取消 forms.buttons.confirm: 确认 forms.buttons.continue: 继续 forms.buttons.continue_ipp: 继续亲身验证 -forms.buttons.continue_remote: 继续在网上验证 -forms.buttons.continue_remote_mobile: 在手机上继续 +forms.buttons.continue_online: 继续在网上验证 +forms.buttons.continue_online_mobile: 在手机上继续 forms.buttons.delete: 删除 forms.buttons.disable: 删除 forms.buttons.edit: 编辑 diff --git a/spec/controllers/idv/welcome_controller_spec.rb b/spec/controllers/idv/welcome_controller_spec.rb index 5dfa145dd3d..5dee18480fb 100644 --- a/spec/controllers/idv/welcome_controller_spec.rb +++ b/spec/controllers/idv/welcome_controller_spec.rb @@ -2,10 +2,13 @@ RSpec.describe Idv::WelcomeController do let(:user) { create(:user) } + let(:dos_api_status) { nil } before do stub_sign_in(user) stub_analytics + stub_request(:get, IdentityConfig.store.dos_passport_composite_healthcheck_endpoint) + .to_return({ status: 200, body: { status: dos_api_status }.to_json }) end describe '#step_info' do @@ -71,6 +74,7 @@ { step: 'welcome', analytics_id: 'Doc Auth', + doc_auth_vendor: 'mock', } end @@ -158,11 +162,8 @@ end context 'passports enabled' do - let(:dos_api_status) { nil } before do allow(IdentityConfig.store).to receive(:doc_auth_passports_enabled).and_return(true) - stub_request(:get, IdentityConfig.store.dos_passport_composite_healthcheck_endpoint) - .to_return({ status: 200, body: { status: dos_api_status }.to_json }) end context 'passport api is down' do @@ -179,6 +180,13 @@ context 'passport api is up and running' do let(:dos_api_status) { 'UP' } + let(:passport_bucket) { :default } + + before do + allow(subject).to receive(:ab_test_bucket).and_call_original + allow(subject).to receive(:ab_test_bucket).with(:DOC_AUTH_PASSPORT) + .and_return(passport_bucket) + end it 'passport allowed is false in idv session' do get :show @@ -187,11 +195,7 @@ end context 'user is AB bucketed to allow passports' do - before do - allow(subject).to receive(:ab_test_bucket).and_call_original - allow(subject).to receive(:ab_test_bucket).with(:DOC_AUTH_PASSPORT) - .and_return(:passport_allowed) - end + let(:passport_bucket) { :passport_allowed } it 'passport allowed is true in idv session' do get :show @@ -225,6 +229,7 @@ { step: 'welcome', analytics_id: 'Doc Auth', + doc_auth_vendor: 'mock', } end diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index d6681bf0236..65be952d77a 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -209,10 +209,10 @@ { 'IdV: intro visited' => {}, 'IdV: doc auth welcome visited' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth welcome submitted' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth agreement visited' => { step: 'agreement', analytics_id: 'Doc Auth' @@ -330,10 +330,10 @@ { 'IdV: intro visited' => {}, 'IdV: doc auth welcome visited' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth welcome submitted' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth agreement visited' => { step: 'agreement', analytics_id: 'Doc Auth' @@ -455,10 +455,10 @@ { 'IdV: intro visited' => {}, 'IdV: doc auth welcome visited' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth welcome submitted' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth agreement visited' => { step: 'agreement', analytics_id: 'Doc Auth' @@ -557,10 +557,10 @@ let(:in_person_path_events) do { 'IdV: doc auth welcome visited' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth welcome submitted' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth agreement visited' => { step: 'agreement', analytics_id: 'Doc Auth' @@ -696,10 +696,10 @@ { 'IdV: intro visited' => {}, 'IdV: doc auth welcome visited' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth welcome submitted' => { - step: 'welcome', analytics_id: 'Doc Auth' + step: 'welcome', analytics_id: 'Doc Auth', doc_auth_vendor: 'mock' }, 'IdV: doc auth agreement visited' => { step: 'agreement', analytics_id: 'Doc Auth' diff --git a/spec/features/idv/doc_auth/how_to_verify_spec.rb b/spec/features/idv/doc_auth/how_to_verify_spec.rb index 28c87202c24..43a6b285300 100644 --- a/spec/features/idv/doc_auth/how_to_verify_spec.rb +++ b/spec/features/idv/doc_auth/how_to_verify_spec.rb @@ -96,7 +96,7 @@ expect(page).to have_current_path(idv_how_to_verify_path) # Choose remote option - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') expect(page).to have_current_path(idv_hybrid_handoff_url) # go back and choose in person option @@ -198,7 +198,7 @@ context 'Going back from Hybrid Handoff with opt in disabled midstream' do let(:in_person_proofing_opt_in_enabled) { true } before do - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') end it 'should not be bounced back to How to Verify with opt in disabled midstream' do @@ -223,7 +223,7 @@ context 'Going back from Hybrid Handoff with opt in enabled the whole time' do let(:in_person_proofing_opt_in_enabled) { true } before do - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') end it 'should be bounced back to How to Verify' do diff --git a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb index 29b3865b839..ca4905381a2 100644 --- a/spec/features/idv/doc_auth/hybrid_handoff_spec.rb +++ b/spec/features/idv/doc_auth/hybrid_handoff_spec.rb @@ -385,7 +385,7 @@ def verify_no_upload_photos_section_and_link(page) end describe 'when selfie is required by sp' do before do - click_on t('forms.buttons.continue_remote_mobile') + click_on t('forms.buttons.continue_online_mobile') end it 'shows selfie version of top content and ipp option section' do verify_handoff_page_selfie_version_content(page) @@ -396,7 +396,7 @@ def verify_no_upload_photos_section_and_link(page) describe 'when selfie is not required by sp' do let(:facial_match_required) { false } before do - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') end it 'shows non selfie version of top content and upload section, no ipp option section' do diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index a625b6bf9ed..e7405eb21a3 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -263,7 +263,7 @@ visit idv_how_to_verify_url # choose remote - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') complete_hybrid_handoff_step complete_document_capture_step(with_selfie: false) @@ -292,7 +292,7 @@ it 'allows the user to successfully complete remote identity verification' do # choose remote - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') complete_hybrid_handoff_step complete_document_capture_step(with_selfie: false) @@ -357,7 +357,7 @@ complete_doc_auth_steps_before_hybrid_handoff_step # choose remote - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') click_send_link expect(page).to have_content(t('doc_auth.headings.text_message')) @@ -374,7 +374,7 @@ visit idv_how_to_verify_url # choose remote - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') complete_hybrid_handoff_step successful_response = instance_double( Faraday::Response, diff --git a/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb b/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb index 5eb11e2e7d3..fff00d1140c 100644 --- a/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb +++ b/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb @@ -487,7 +487,7 @@ sign_in_via_branded_page(user) complete_welcome_step complete_agreement_step - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') expect(page).to have_current_path(idv_hybrid_handoff_url) complete_hybrid_handoff_step complete_document_capture_step diff --git a/spec/presenters/idv/welcome_presenter_spec.rb b/spec/presenters/idv/welcome_presenter_spec.rb index d8f49e3c1b5..e4cd8e69224 100644 --- a/spec/presenters/idv/welcome_presenter_spec.rb +++ b/spec/presenters/idv/welcome_presenter_spec.rb @@ -1,14 +1,12 @@ require 'rails_helper' RSpec.describe Idv::WelcomePresenter do - subject(:presenter) { Idv::WelcomePresenter.new(decorated_sp_session) } + subject(:presenter) { Idv::WelcomePresenter.new(decorated_sp_session:, passport_allowed:) } let(:sp) { build(:service_provider) } - let(:sp_session) { {} } - let(:view_context) { ActionController::Base.new.view_context } - + let(:user) { build(:user) } let(:decorated_sp_session) do ServiceProviderSession.new( sp: sp, @@ -17,8 +15,7 @@ service_provider_request: nil, ) end - - let(:user) { build(:user) } + let(:passport_allowed) { false } before do allow(view_context).to receive(:current_user).and_return(user) @@ -63,9 +60,9 @@ end describe 'the bullet points' do - it 'uses the bullet point 1 header' do + it 'uses the bullet point 1a header' do expect(presenter.bullet_points[0].bullet).to eq( - t('doc_auth.instructions.bullet1'), + t('doc_auth.instructions.bullet1a'), ) end @@ -110,5 +107,15 @@ t('doc_auth.instructions.text4'), ) end + + context 'when the user is allowed to use a passport' do + let(:passport_allowed) { true } + + it 'uses the bullet point 1b header' do + expect(presenter.bullet_points[0].bullet).to eq( + t('doc_auth.instructions.bullet1b'), + ) + end + end end end diff --git a/spec/support/features/doc_auth_helper.rb b/spec/support/features/doc_auth_helper.rb index 9fc4318a822..1700a60648b 100644 --- a/spec/support/features/doc_auth_helper.rb +++ b/spec/support/features/doc_auth_helper.rb @@ -85,7 +85,7 @@ def complete_doc_auth_steps_before_document_capture_step(expect_accessible: fals # JavaScript-enabled mobile devices will skip directly to document capture, so stop as complete. return if page.current_path == idv_document_capture_path if IdentityConfig.store.in_person_proofing_opt_in_enabled - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') end complete_hybrid_handoff_step expect_page_to_have_no_accessibility_violations(page) if expect_accessible @@ -98,9 +98,9 @@ def complete_up_to_how_to_verify_step_for_opt_in_ipp(remote: true, complete_agreement_step if remote if facial_match_required - click_on t('forms.buttons.continue_remote_mobile') + click_on t('forms.buttons.continue_online_mobile') else - click_on t('forms.buttons.continue_remote') + click_on t('forms.buttons.continue_online') end else click_on t('forms.buttons.continue_ipp') diff --git a/spec/views/idv/how_to_verify/show.html.erb_spec.rb b/spec/views/idv/how_to_verify/show.html.erb_spec.rb index 1a3d6ec7d42..97e62f50554 100644 --- a/spec/views/idv/how_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/how_to_verify/show.html.erb_spec.rb @@ -4,10 +4,12 @@ selection = Idv::HowToVerifyForm::IPP let(:mobile_required) { false } let(:selfie_check_required) { false } + let(:passport_allowed) { false } let(:presenter) do Idv::HowToVerifyPresenter.new( mobile_required: mobile_required, selfie_check_required: selfie_check_required, + passport_allowed:, ) end let(:idv_how_to_verify_form) { Idv::HowToVerifyForm.new(selection: selection) } @@ -41,14 +43,11 @@ end it 'renders a button for remote and ipp' do - expect(rendered).to have_button(t('forms.buttons.continue_remote')) + expect(rendered).to have_button(t('forms.buttons.continue_online')) expect(rendered).to have_button(t('forms.buttons.continue_ipp')) end - it 'renders a troubleshooting section' do - expect(rendered).to have_content( - t('doc_auth.info.how_to_verify_troubleshooting_options_header'), - ) + it 'renders troubleshooting links' do expect(rendered).to have_link(t('doc_auth.info.verify_online_link_text')) expect(rendered).to have_link(t('doc_auth.info.verify_at_post_office_link_text')) end @@ -58,13 +57,26 @@ end it 'renders non-selfie specific content' do - expect(rendered).to have_content(t('doc_auth.info.how_to_verify')) expect(rendered).not_to have_content(t('doc_auth.tips.mobile_phone_required')) expect(rendered).to have_content(t('doc_auth.headings.verify_online')) expect(rendered).to have_content(t('doc_auth.info.verify_online_instruction')) - expect(rendered).to have_content(t('doc_auth.info.verify_online_description')) + expect(rendered).not_to have_content(t('doc_auth.info.verify_online_description_passport')) expect(rendered).to have_content(t('doc_auth.info.verify_at_post_office_instruction')) - expect(rendered).to have_content(t('doc_auth.info.verify_at_post_office_description')) + expect(rendered).not_to have_content( + strip_tags(t('doc_auth.info.verify_at_post_office_description_passport_html')), + ) + end + + context 'when passport is allowed' do + let(:passport_allowed) { true } + + it 'renders passport specific content' do + expect(rendered).to have_content(t('doc_auth.info.verify_online_instruction')) + expect(rendered).to have_content(t('doc_auth.info.verify_online_description_passport')) + expect(rendered).to have_content( + strip_tags(t('doc_auth.info.verify_at_post_office_description_passport_html')), + ) + end end end @@ -95,14 +107,11 @@ end it 'renders a button for remote and ipp' do - expect(rendered).to have_button(t('forms.buttons.continue_remote_mobile')) + expect(rendered).to have_button(t('forms.buttons.continue_online_mobile')) expect(rendered).to have_button(t('forms.buttons.continue_ipp')) end - it 'renders a troubleshooting section' do - expect(rendered).to have_content( - t('doc_auth.info.how_to_verify_troubleshooting_options_header'), - ) + it 'renders troubleshooting links' do expect(rendered).to have_link(t('doc_auth.info.verify_online_link_text')) expect(rendered).to have_link(t('doc_auth.info.verify_at_post_office_link_text')) end @@ -117,21 +126,44 @@ ) end + context 'when passport is allowed' do + let(:passport_allowed) { true } + + it 'renders passport specific content' do + expect(rendered).to have_content( + t('doc_auth.info.verify_online_instruction_mobile_no_selfie'), + ) + expect(rendered).to have_content(t('doc_auth.info.verify_online_description_passport')) + expect(rendered).to have_content( + strip_tags(t('doc_auth.info.verify_at_post_office_description_passport_html')), + ) + end + end + context 'when selfie is required' do let(:selfie_check_required) { true } it 'renders selfie specific content' do - expect(rendered).to have_content(t('doc_auth.info.how_to_verify_mobile')) expect(rendered).to have_content(t('doc_auth.tips.mobile_phone_required')) expect(rendered).to have_content(t('doc_auth.info.verify_online_instruction_selfie')) - expect(rendered).to have_content(t('doc_auth.info.verify_online_description_mobile')) - expect(rendered).to have_content( - t('doc_auth.info.verify_at_post_office_instruction_selfie'), - ) - expect(rendered).to have_content( - t('doc_auth.info.verify_at_post_office_description_mobile'), + expect(rendered).not_to have_content(t('doc_auth.info.verify_online_description_passport')) + expect(rendered).to have_content(t('doc_auth.info.verify_at_post_office_instruction')) + expect(rendered).not_to have_content( + strip_tags(t('doc_auth.info.verify_at_post_office_description_passport_html')), ) end + + context 'when passport is allowed' do + let(:passport_allowed) { true } + + it 'renders passport specific content' do + expect(rendered).to have_content(t('doc_auth.info.verify_online_instruction_selfie')) + expect(rendered).to have_content(t('doc_auth.info.verify_online_description_passport')) + expect(rendered).to have_content( + strip_tags(t('doc_auth.info.verify_at_post_office_description_passport_html')), + ) + end + end end end end diff --git a/spec/views/idv/welcome/show.html.erb_spec.rb b/spec/views/idv/welcome/show.html.erb_spec.rb index 6a4d16303d2..686d982da2e 100644 --- a/spec/views/idv/welcome/show.html.erb_spec.rb +++ b/spec/views/idv/welcome/show.html.erb_spec.rb @@ -7,6 +7,7 @@ let(:sp_session) { {} } let(:view_context) { ActionController::Base.new.view_context } let(:sp) { build(:service_provider) } + let(:passport_allowed) { false } before do allow(view_context).to receive(:current_user).and_return(user) @@ -17,7 +18,7 @@ sp_session: sp_session, service_provider_request: nil, ) - presenter = Idv::WelcomePresenter.new(decorated_sp_session) + presenter = Idv::WelcomePresenter.new(decorated_sp_session:, passport_allowed:) assign(:presenter, presenter) assign(:current_user, user) render @@ -40,7 +41,7 @@ link_html: '', ), ) - expect(rendered).to have_content(t('doc_auth.instructions.bullet1')) + expect(rendered).to have_content(t('doc_auth.instructions.bullet1a')) expect(rendered).to have_link( t('doc_auth.info.getting_started_learn_more'), href: help_center_redirect_path( @@ -54,6 +55,14 @@ end end + context 'when a user has the passport option' do + let(:passport_allowed) { true } + + it 'renders the modified bullet point' do + expect(rendered).to have_content(t('doc_auth.instructions.bullet1b')) + end + end + context 'in doc auth with a step-up user' do let(:user) { create(:user, :proofed) } From 077e8746c313265425fad1e610feaea78a798891 Mon Sep 17 00:00:00 2001 From: Mitchell Henke Date: Thu, 3 Apr 2025 16:35:15 -0500 Subject: [PATCH 3/8] Always require confirmation of user logout in OIDC Logout (#12048) changelog: Bug Fixes, OpenID Connect, Always require confirmation of user logout --- .../openid_connect/logout_controller.rb | 9 +---- .../openid_connect/logout_controller_spec.rb | 30 +++------------ .../openid_connect/openid_connect_spec.rb | 38 +++++++++++++++++-- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/app/controllers/openid_connect/logout_controller.rb b/app/controllers/openid_connect/logout_controller.rb index ad21471dc3e..955bdecd73a 100644 --- a/app/controllers/openid_connect/logout_controller.rb +++ b/app/controllers/openid_connect/logout_controller.rb @@ -97,12 +97,6 @@ def apply_logout_secure_headers_override(redirect_uri, service_provider) override_form_action_csp(uris) end - def require_logout_confirmation? - (logout_params[:id_token_hint].nil? || IdentityConfig.store.reject_id_token_hint_in_logout) && - logout_params[:client_id] && - current_user - end - # @return [OpenidConnectLogoutForm] def build_logout_form OpenidConnectLogoutForm.new( @@ -115,12 +109,13 @@ def build_logout_form # @param redirect_uri [String] The URL to redirect the user to after logout def handle_successful_logout_request(result, redirect_uri) apply_logout_secure_headers_override(redirect_uri, @logout_form.service_provider) - if require_logout_confirmation? + if current_user.present? analytics.oidc_logout_visited(**to_event(result)) @params = { client_id: logout_params[:client_id], post_logout_redirect_uri: logout_params[:post_logout_redirect_uri], + id_token_hint: logout_params[:id_token_hint], } @params[:state] = logout_params[:state] if !logout_params[:state].nil? @service_provider_name = @logout_form.service_provider&.friendly_name diff --git a/spec/controllers/openid_connect/logout_controller_spec.rb b/spec/controllers/openid_connect/logout_controller_spec.rb index 8a95ca2e02a..2e39352ccc1 100644 --- a/spec/controllers/openid_connect/logout_controller_spec.rb +++ b/spec/controllers/openid_connect/logout_controller_spec.rb @@ -59,30 +59,9 @@ before { stub_sign_in(user) } context 'with valid params' do - it 'destroys the session' do - expect(controller).to receive(:sign_out).and_call_original - - action - end - - it 'redirects back to the client if server-side redirect is enabled' do - allow(IdentityConfig.store).to receive(:openid_connect_redirect) - .and_return('server_side') - action - - expect(response).to redirect_to(/^#{post_logout_redirect_uri}/) - end - - it 'renders JS client-side redirect if client-side JS redirect is enabled' do - allow(IdentityConfig.store).to receive(:openid_connect_redirect) - .and_return('client_side_js') - action - - expect(controller).to render_template('openid_connect/shared/redirect_js') - expect(assigns(:oidc_redirect_uri)).to start_with(post_logout_redirect_uri) - end + render_views - it 'tracks events' do + it 'renders logout confirmation page' do stub_analytics stub_attempts_tracker @@ -102,7 +81,7 @@ ), ) expect(@analytics).to have_logged_event( - 'Logout Initiated', + 'OIDC Logout Page Visited', success: true, client_id: service_provider.issuer, client_id_parameter_present: false, @@ -110,10 +89,11 @@ sp_initiated: true, oidc: true, ) - expect(@analytics).to_not have_logged_event( :sp_integration_errors_present, ) + expect(response).to render_template(:confirm_logout) + expect(response.body).to include service_provider.friendly_name end end diff --git a/spec/features/openid_connect/openid_connect_spec.rb b/spec/features/openid_connect/openid_connect_spec.rb index f743a6227a8..d20abd1a87b 100644 --- a/spec/features/openid_connect/openid_connect_spec.rb +++ b/spec/features/openid_connect/openid_connect_spec.rb @@ -312,8 +312,9 @@ end context 'when sending id_token_hint' do - it 'logout destroys the session' do - id_token = sign_in_get_id_token + it 'logout destroys the session when confirming logout' do + service_provider = ServiceProvider.find_by(issuer: 'urn:gov:gsa:openidconnect:test') + id_token = sign_in_get_id_token(client_id: service_provider.issuer) state = SecureRandom.hex @@ -323,19 +324,38 @@ id_token_hint: id_token, ) + expect(page).to have_content( + t( + 'openid_connect.logout.heading_with_sp', + app_name: APP_NAME, + service_provider_name: service_provider.friendly_name, + ), + ) + click_button t('openid_connect.logout.confirm', app_name: APP_NAME) + visit account_path expect(page).to_not have_content(t('headings.account.login_info')) expect(page).to have_content(t('headings.sign_in_without_sp')) end it 'logout does not require state' do - id_token = sign_in_get_id_token + service_provider = ServiceProvider.find_by(issuer: 'urn:gov:gsa:openidconnect:test') + id_token = sign_in_get_id_token(client_id: service_provider.issuer) visit openid_connect_logout_path( post_logout_redirect_uri: 'gov.gsa.openidconnect.test://result/signout', id_token_hint: id_token, ) + expect(page).to have_content( + t( + 'openid_connect.logout.heading_with_sp', + app_name: APP_NAME, + service_provider_name: service_provider.friendly_name, + ), + ) + click_button t('openid_connect.logout.confirm', app_name: APP_NAME) + visit account_path expect(page).to_not have_content(t('headings.account.login_info')) expect(page).to have_content(t('headings.sign_in_without_sp')) @@ -956,7 +976,8 @@ context 'signing out' do it 'redirects back to the client app and destroys the session' do - id_token = sign_in_get_id_token + service_provider = ServiceProvider.find_by(issuer: 'urn:gov:gsa:openidconnect:test') + id_token = sign_in_get_id_token(client_id: service_provider.issuer) state = SecureRandom.hex @@ -966,6 +987,15 @@ id_token_hint: id_token, ) + expect(page).to have_content( + t( + 'openid_connect.logout.heading_with_sp', + app_name: APP_NAME, + service_provider_name: service_provider.friendly_name, + ), + ) + click_button t('openid_connect.logout.confirm', app_name: APP_NAME) + expect(oidc_redirect_url).to eq( UriService.add_params('gov.gsa.openidconnect.test://result/signout', state:), ) From a82e785c9f7cbeb4b813b799531daa99a4f66920 Mon Sep 17 00:00:00 2001 From: Amir Reavis-Bey Date: Fri, 4 Apr 2025 14:08:57 -0400 Subject: [PATCH 4/8] LG-16031: Send only first part of last name to AAMVA (#12054) * Send only first part of last name to AAMVA for DC, WV (#12045) * Send only first part of last name to AAMVA for DC, WV **Why**: Apparently the backend processors for DC and WV only process matches up to the first "word" of a last name * fixup: use correct let() * Update reference to last_name * make split last name opt-in configurable by state changelog: Bug Fixes, Identity Proofing, Split last names with space configurable opt-in by AAMVA state * add last_name_spaced to analytics for proofing results * add last_name_spaced to signatur of profing analytics event * happy linting * update last_name in spec --------- Co-authored-by: Zach Margolis --- .../concerns/idv/verify_info_concern.rb | 1 + app/services/analytics_events.rb | 3 ++ .../aamva/request/verification_request.rb | 13 ++++++-- config/application.yml.default | 1 + lib/identity_config.rb | 1 + spec/features/idv/analytics_spec.rb | 10 +++---- .../request/verification_request_spec.rb | 30 +++++++++++++++++-- 7 files changed, 50 insertions(+), 9 deletions(-) diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index f5e0afbdc04..c942a596823 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -208,6 +208,7 @@ def async_state_done(current_async_state) extra: { address_edited: !!idv_session.address_edited, address_line2_present: !pii[:address2].blank?, + last_name_spaced: pii[:last_name].split(' ').many?, previous_ssn_edit_distance: previous_ssn_edit_distance, pii_like_keypaths: [ [:errors, :ssn], diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 6aa1ecea9b1..990337b3d69 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2151,6 +2151,7 @@ def idv_doc_auth_verify_polling_wait_visited(**extra) # @param analytics_id [String] "Doc Auth" for remote unsupervised, "In Person Proofing" for IPP # @param errors [Hash] Details about vendor-specific errors encountered during the stages of the identity resolution process # @param flow_path [String] "hybrid" for hybrid handoff, "standard" otherwise + # @param last_name_spaced [Boolean] Whether the user's last name includes an empty space # @param lexisnexis_instant_verify_workflow_ab_test_bucket [String] A/B test bucket for Lexis Nexis InstantVerify workflow testing # @param opted_in_to_in_person_proofing [Boolean] Whether this user explicitly opted into in-person proofing # @param proofing_results [Hash] @@ -2217,6 +2218,7 @@ def idv_doc_auth_verify_proofing_results( analytics_id: nil, errors: nil, flow_path: nil, + last_name_spaced: nil, lexisnexis_instant_verify_workflow_ab_test_bucket: nil, opted_in_to_in_person_proofing: nil, proofing_results: nil, @@ -2237,6 +2239,7 @@ def idv_doc_auth_verify_proofing_results( errors:, flow_path:, lexisnexis_instant_verify_workflow_ab_test_bucket:, + last_name_spaced:, opted_in_to_in_person_proofing:, proofing_results:, skip_hybrid_handoff:, diff --git a/app/services/proofing/aamva/request/verification_request.rb b/app/services/proofing/aamva/request/verification_request.rb index 30dc750dc6c..7cf9c623267 100644 --- a/app/services/proofing/aamva/request/verification_request.rb +++ b/app/services/proofing/aamva/request/verification_request.rb @@ -274,10 +274,10 @@ def transaction_locator_id def user_provided_data_map { - state_id_number: state_id_number, + state_id_number:, state_id_jurisdiction: message_destination_id, first_name: applicant.first_name, - last_name: applicant.last_name, + last_name:, dob: applicant.dob, address1: applicant.address1, city: applicant.city, @@ -295,6 +295,15 @@ def state_id_number end end + def last_name + if IdentityConfig.store.idv_aamva_split_last_name_states + .include? applicant.state_id_data.state_id_jurisdiction + applicant.last_name.split(' ').first + else + applicant.last_name + end + end + def timeout (config.verification_request_timeout || 5).to_f end diff --git a/config/application.yml.default b/config/application.yml.default index e5c7dc8b244..df6928ce03f 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -164,6 +164,7 @@ hmac_fingerprinter_key: hmac_fingerprinter_key_queue: '[]' identity_pki_disabled: false identity_pki_local_dev: false +idv_aamva_split_last_name_states: '[]' idv_account_verified_email_campaign_id: '20241028' idv_acuant_sdk_upgrade_a_b_testing_enabled: false idv_acuant_sdk_upgrade_a_b_testing_percent: 50 diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 25d7549af81..e148ccf800b 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -209,6 +209,7 @@ def self.store config.add(:idv_socure_shadow_mode_enabled, type: :boolean) config.add(:idv_socure_shadow_mode_enabled_for_docv_users, type: :boolean) config.add(:idv_sp_required, type: :boolean) + config.add(:idv_aamva_split_last_name_states, type: :json) config.add(:in_person_completion_survey_delivery_enabled, type: :boolean) config.add(:in_person_completion_survey_url, type: :string) config.add(:in_person_doc_auth_button_enabled, type: :boolean) diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index 65be952d77a..bb556f10bf7 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -266,7 +266,7 @@ end ), 'IdV: doc auth verify proofing results' => { - success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', + success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, last_name_spaced: false, analytics_id: 'Doc Auth', step: 'verify', proofing_results: doc_auth_verify_proofing_results, proofing_components: base_proofing_components }, @@ -391,7 +391,7 @@ end ), 'IdV: doc auth verify proofing results' => { - success: true, flow_path: 'hybrid', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', + success: true, flow_path: 'hybrid', address_edited: false, address_line2_present: false, last_name_spaced: false, analytics_id: 'Doc Auth', step: 'verify', proofing_results: doc_auth_verify_proofing_results, proofing_components: base_proofing_components }, @@ -514,7 +514,7 @@ end ), 'IdV: doc auth verify proofing results' => { - success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', + success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, last_name_spaced: false, analytics_id: 'Doc Auth', step: 'verify', proofing_results: doc_auth_verify_proofing_results, proofing_components: base_proofing_components }, @@ -632,7 +632,7 @@ end ), 'IdV: doc auth verify proofing results' => { - success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'In Person Proofing', step: 'verify', + success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, last_name_spaced: false, analytics_id: 'In Person Proofing', step: 'verify', proofing_results: in_person_path_proofing_results, proofing_components: { document_check: 'usps', resolution_check: 'ResolutionMock', residential_resolution_check: 'ResolutionMock', source_check: 'StateIdMock', threatmetrix: threatmetrix, threatmetrix_review_status: 'pass' } }, @@ -761,7 +761,7 @@ end ), 'IdV: doc auth verify proofing results' => { - success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', step: 'verify', + success: true, flow_path: 'standard', address_edited: false, address_line2_present: false, last_name_spaced: false, analytics_id: 'Doc Auth', step: 'verify', proofing_results: doc_auth_verify_proofing_results, proofing_components: base_proofing_components }, diff --git a/spec/services/proofing/aamva/request/verification_request_spec.rb b/spec/services/proofing/aamva/request/verification_request_spec.rb index 3a24ee8a7cd..33ca99db23a 100644 --- a/spec/services/proofing/aamva/request/verification_request_spec.rb +++ b/spec/services/proofing/aamva/request/verification_request_spec.rb @@ -6,13 +6,14 @@ let(:config) { AamvaFixtures.example_config } let(:state_id_jurisdiction) { 'CA' } let(:state_id_number) { '123456789' } + let(:last_name) { 'McTesterson' } let(:applicant_data) do { uuid: '1234-abcd-efgh', first_name: 'Testy', middle_name: nil, - last_name: 'McTesterson', + last_name:, name_suffix: nil, dob: '10/29/1942', address1: '123 Sunnyside way', @@ -36,7 +37,7 @@ Proofing::Aamva::Applicant.from_proofer_applicant(**applicant_data.compact_blank) end - subject do + subject(:request) do described_class.new( applicant: applicant, session_id: transaction_id, @@ -356,4 +357,29 @@ end end end + + describe 'compound last names' do + let(:last_name) { 'McFirst McSecond' } + + subject(:rendered_last_name) do + body = REXML::Document.new(request.body) + REXML::XPath.first(body, '//nc:PersonSurName')&.text + end + + before do + allow(IdentityConfig.store).to receive(:idv_aamva_split_last_name_states) + .and_return(['DC']) + end + it 'sends the full last name' do + expect(rendered_last_name).to eq('McFirst McSecond') + end + + context 'in state configured for last name split' do + let(:state_id_jurisdiction) { 'DC' } + + it 'only sends the first part of the last name' do + expect(rendered_last_name).to eq('McFirst') + end + end + end end From 0af9d7eb21d95bda6bd8da5b2fb9c41af6f5b2fe Mon Sep 17 00:00:00 2001 From: eileen-nava <80347702+eileen-nava@users.noreply.github.com> Date: Fri, 4 Apr 2025 14:25:11 -0400 Subject: [PATCH 5/8] LG-15960: IPP Passport Feature Flag (#12053) * add feature flag for id-ipp passport support * Changelog: Internal, In-Person Proofing, add feature flag for id-ipp passport support * change in_person_passports_enabled value for default and production --- config/application.yml.default | 2 ++ lib/identity_config.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/config/application.yml.default b/config/application.yml.default index df6928ce03f..bac792958ab 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -206,6 +206,7 @@ in_person_outage_emailed_by_date: 'November 1, 2024' # are strings in the format 'Month day, year' in_person_outage_expected_update_date: 'October 31, 2024' in_person_outage_message_enabled: false +in_person_passports_enabled: true in_person_proofing_enabled: false in_person_proofing_enforce_tmx: false in_person_proofing_opt_in_enabled: false @@ -540,6 +541,7 @@ production: facial_match_general_availability_enabled: false feature_pending_in_person_password_reset_enabled: false idv_sp_required: true + in_person_passports_enabled: false invalid_gpo_confirmation_zipcode: '' lexisnexis_threatmetrix_mock_enabled: false logins_per_ip_period: 20 diff --git a/lib/identity_config.rb b/lib/identity_config.rb index e148ccf800b..2b69f5fed15 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -230,6 +230,7 @@ def self.store config.add(:in_person_outage_emailed_by_date, type: :string) config.add(:in_person_outage_expected_update_date, type: :string) config.add(:in_person_outage_message_enabled, type: :boolean) + config.add(:in_person_passports_enabled, type: :boolean) 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) From aaf691faea2fdcdf1bffc06a8ff231f9ed260ee5 Mon Sep 17 00:00:00 2001 From: Shane Chesnutt Date: Fri, 4 Apr 2025 16:07:22 -0400 Subject: [PATCH 6/8] LG-15859 Add service provider name to barcode deadline alert (#12051) changelog: User-Facing Improvments, In-Person Proofing, Add the service provider name to the barcode page deadline alert --- .../in_person/ready_to_verify/show.html.erb | 10 ++--- .../_in_person_ready_to_verify.html.erb | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/zh.yml | 2 +- spec/features/idv/in_person_spec.rb | 16 ++++++- .../idv/in_person_threatmetrix_spec.rb | 11 +++-- .../idv/steps/in_person_opt_in_ipp_spec.rb | 8 +++- spec/mailers/user_mailer_spec.rb | 44 +++++++++++++++++++ .../ready_to_verify/show.html.erb_spec.rb | 13 ++++++ 11 files changed, 96 insertions(+), 16 deletions(-) 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 6cc213c8a91..dbab09167b8 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 @@ -44,7 +44,7 @@ <%# Alert %> <%= render AlertComponent.new(type: :info, class: 'margin-y-4', text_tag: :div) do %> -

<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %>

+

<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date, sp_name: @presenter.sp_name) %>

<%= t('in_person_proofing.body.barcode.deadline_restart') %>

<% end %> @@ -89,7 +89,7 @@

<%= t('in_person_proofing.process.real_id_and_supporting_docs.info') %>

    <% t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |doc| %> -
  • <%= doc %>
  • +
  • <%= doc %>
  • <% end %>
@@ -130,7 +130,7 @@

<%= t('in_person_proofing.process.eipp_state_id_military_id.heading') %>

<%= t('in_person_proofing.process.eipp_state_id_military_id.info') %>

-
+

@@ -149,7 +149,7 @@

<%= t('in_person_proofing.process.eipp_state_id_supporting_docs.info') %>

    <% t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |doc| %> -
  • <%= doc %>
  • +
  • <%= doc %>
  • <% end %>
@@ -248,7 +248,7 @@

<%= t('in_person_proofing.body.expect.info') %>

- <% if @presenter.service_provider_homepage_url.blank? %> + <% if @presenter.service_provider_homepage_url.blank? %> <%= t('in_person_proofing.body.barcode.close_window') %> <% end %>

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 679959c85da..3b8f2db026d 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 @@ -41,7 +41,7 @@ <%= image_tag('email/info@4x.png', width: 16, height: 16, alt: '', style: 'margin-top: 4px;') %> -

<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %>

+

<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date, sp_name: @presenter.sp_name) %>

<%= t('in_person_proofing.body.barcode.deadline_restart') %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index 74d8f8ad935..5d024794682 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1228,7 +1228,7 @@ image_description.us_flag: US flag image_description.warning: Yellow caution sign in_person_proofing.body.barcode.cancel_link_text: Cancel your barcode in_person_proofing.body.barcode.close_window: You may now close this window. -in_person_proofing.body.barcode.deadline: You must visit any participating Post Office by %{deadline}. +in_person_proofing.body.barcode.deadline: You must visit any participating Post Office by %{deadline}. Complete this step to access %{sp_name}. in_person_proofing.body.barcode.deadline_restart: If you go after this deadline, your barcode will not work. You will need to restart the process. in_person_proofing.body.barcode.eipp_tag: GSA Enhanced Pilot Barcode in_person_proofing.body.barcode.eipp_what_to_bring: 'Depending on your ID, you may need to show supporting documents. Review the following options carefully:' diff --git a/config/locales/es.yml b/config/locales/es.yml index bd763c97e41..6439f0ab3d2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1239,7 +1239,7 @@ image_description.us_flag: Bandera de los EE. UU. image_description.warning: Señal amarilla de precaución in_person_proofing.body.barcode.cancel_link_text: Cancele su código de barras in_person_proofing.body.barcode.close_window: Ya puede cerrar esta ventana. -in_person_proofing.body.barcode.deadline: Debe acudir a cualquier oficina de correos participante antes del %{deadline}. +in_person_proofing.body.barcode.deadline: Debe acudir a cualquier oficina de correos participante antes del %{deadline}. Siga este paso para acceder a %{sp_name}. in_person_proofing.body.barcode.deadline_restart: Si acude después de esta fecha límite, su código de barras ya no funcionará y tendrá que reiniciar el proceso. in_person_proofing.body.barcode.eipp_tag: Código de barras piloto mejorado GSA in_person_proofing.body.barcode.eipp_what_to_bring: 'Según el tipo de identificación que tenga, es posible que deba presentar documentos comprobatorios. Lea con atención las opciones siguientes:' diff --git a/config/locales/fr.yml b/config/locales/fr.yml index bf65f6f2de5..1980fe11d91 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1228,7 +1228,7 @@ image_description.us_flag: Drapeau des États-Unis image_description.warning: Panneau d’avertissement jaune in_person_proofing.body.barcode.cancel_link_text: Annuler votre code-barres in_person_proofing.body.barcode.close_window: Vous pouvez maintenant fermer cette fenêtre -in_person_proofing.body.barcode.deadline: Vous devez vous rendre dans un bureau de poste participant avant le %{deadline}. +in_person_proofing.body.barcode.deadline: Vous devez vous rendre dans un bureau de poste participant avant le %{deadline}. Effectuez cette étape pour accéder à %{sp_name}. in_person_proofing.body.barcode.deadline_restart: Si vous laissez passer la date limite, votre code-barres ne fonctionnera pas. Vous devrez recommencer toute la procédure. in_person_proofing.body.barcode.eipp_tag: Code-barres pilote amélioré de la GSA in_person_proofing.body.barcode.eipp_what_to_bring: 'Selon la pièce d’identité dont vous disposez, il pourra vous être demandé de présenter des documents complémentaires. Étudiez attentivement les options suivantes:' diff --git a/config/locales/zh.yml b/config/locales/zh.yml index d20712c525f..7223f45db96 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -1241,7 +1241,7 @@ image_description.us_flag: 美国国旗 image_description.warning: 黄色警告标志 in_person_proofing.body.barcode.cancel_link_text: 取消你的条形码 in_person_proofing.body.barcode.close_window: 你现在可以关闭这一窗口。 -in_person_proofing.body.barcode.deadline: 你必须在 %{deadline}之前去任何参与邮局。 +in_person_proofing.body.barcode.deadline: 你必须在 %{deadline}之前去任何参与邮局。完成这个步骤以访问%{sp_name}。 in_person_proofing.body.barcode.deadline_restart: 如果你过了截止日期才去邮局,那你的条形码将无法使用。你将需要重新开始这一流程。 in_person_proofing.body.barcode.eipp_tag: GSA 增强型试行条形码 in_person_proofing.body.barcode.eipp_what_to_bring: 取决于您身份证件类型,您也许需要显示支持文件。请仔细阅读以下选项: diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index e7405eb21a3..06144cbae0a 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -19,6 +19,7 @@ it 'works for a happy path', allow_browser_log: true do user = user_with_2fa + visit_idp_from_sp_with_ial2(:oidc, **{ client_id: ipp_service_provider.issuer }) sign_in_and_2fa_user(user) begin_in_person_proofing(user) @@ -138,7 +139,13 @@ expect(page).to have_css("img[alt='#{APP_NAME}']") expect(page).to have_content(strip_nbsp(t('in_person_proofing.headings.barcode'))) expect(page).to have_content(Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code)) - expect(page).to have_content(t('in_person_proofing.body.barcode.deadline', deadline: deadline)) + expect(page).to have_content( + t( + 'in_person_proofing.body.barcode.deadline', + deadline: deadline, + sp_name: ipp_service_provider.friendly_name, + ), + ) expect(page).to have_content('MILWAUKEE') expect(page).to have_content('Sunday: Closed') @@ -579,6 +586,7 @@ let(:user) { user_with_2fa } it 'allows the user to search by full address', allow_browser_log: true do + visit_idp_from_sp_with_ial2(:oidc, **{ client_id: ipp_service_provider.issuer }) sign_in_and_2fa_user(user) begin_in_person_proofing(user) # prepare page @@ -664,7 +672,11 @@ expect(page).to have_content(strip_nbsp(t('in_person_proofing.headings.barcode'))) expect(page).to have_content(Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code)) expect(page).to have_content( - t('in_person_proofing.body.barcode.deadline', deadline: deadline), + t( + 'in_person_proofing.body.barcode.deadline', + deadline: deadline, + sp_name: ipp_service_provider.friendly_name, + ), ) expect(page).to have_content('MILWAUKEE') expect(page).to have_content('Sunday: Closed') diff --git a/spec/features/idv/in_person_threatmetrix_spec.rb b/spec/features/idv/in_person_threatmetrix_spec.rb index 2e3ec70ce93..e201f38f660 100644 --- a/spec/features/idv/in_person_threatmetrix_spec.rb +++ b/spec/features/idv/in_person_threatmetrix_spec.rb @@ -22,12 +22,12 @@ let(:config) { ScriptBase::Config.new(include_missing:, reason: 'INV1234') } let(:enrollment) { InPersonEnrollment.last } let(:profile) { enrollment.profile } + let(:service_provider) { ServiceProvider.find_by(issuer: service_provider_issuer(sp)) } before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) allow(IdentityConfig.store).to receive(:in_person_proofing_enforce_tmx).and_return(true) - ServiceProvider.find_by(issuer: service_provider_issuer(sp)) - .update(in_person_proofing_enabled: true) + service_provider.update(in_person_proofing_enabled: true) end def deactivate_profile_update_enrollment(status:) @@ -73,6 +73,7 @@ def deactivate_profile_update_enrollment(status:) let(:tmx_status) { 'Review' } it 'allows the user to continue down the happy path', allow_browser_log: true do + visit_idp_from_sp_with_ial2(:oidc, **{ client_id: service_provider.issuer }) sign_in_and_2fa_user(user) begin_in_person_proofing(user) # prepare page @@ -157,7 +158,11 @@ def deactivate_profile_update_enrollment(status:) expect(page).to have_content(strip_nbsp(t('in_person_proofing.headings.barcode'))) expect(page).to have_content(Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code)) expect(page).to have_content( - t('in_person_proofing.body.barcode.deadline', deadline: deadline), + t( + 'in_person_proofing.body.barcode.deadline', + deadline: deadline, + sp_name: service_provider.friendly_name, + ), ) expect(page).to have_content('MILWAUKEE') expect(page).to have_content('Sunday: Closed') diff --git a/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb b/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb index fff00d1140c..d782ec3b2ce 100644 --- a/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb +++ b/spec/features/idv/steps/in_person_opt_in_ipp_spec.rb @@ -118,7 +118,11 @@ expect(page).to have_content(strip_nbsp(t('in_person_proofing.headings.barcode'))) expect(page).to have_content(Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code)) expect(page).to have_content( - t('in_person_proofing.body.barcode.deadline', deadline: deadline), + t( + 'in_person_proofing.body.barcode.deadline', + deadline: deadline, + sp_name: ipp_service_provider.friendly_name, + ), ) expect(page).to have_content('MILWAUKEE') expect(page).to have_content('Sunday: Closed') @@ -264,6 +268,7 @@ t( 'in_person_proofing.body.barcode.deadline', deadline: deadline, + sp_name: ipp_service_provider.friendly_name, ), ) expect(page).to have_content('MILWAUKEE') @@ -430,6 +435,7 @@ t( 'in_person_proofing.body.barcode.deadline', deadline: deadline, + sp_name: ipp_service_provider.friendly_name, ), ) expect(page).to have_content('MILWAUKEE') diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 9e22363362e..4bb24bcbe0b 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -938,6 +938,7 @@ def expect_email_body_to_have_help_and_contact_links ) end end + context 'when Enhanced IPP is enabled' do let(:is_enhanced_ipp) { true } let(:mail) do @@ -966,6 +967,15 @@ def expect_email_body_to_have_help_and_contact_links end context 'For Informed Delivery In-Person Proofing (ID-IPP)' do + let(:usps_time_zone) { ActiveSupport::TimeZone['America/New_York'].dup.freeze } + let(:formatted_date) do + I18n.l( + enrollment.due_date.in_time_zone(usps_time_zone), + format: :event_date, + ) + end + let(:sp_name) { enrollment.service_provider.friendly_name } + context 'template displays modified content' do it 'conditionally renders content in the what to expect section applicable to IPP' do aggregate_failures do @@ -982,6 +992,19 @@ def expect_email_body_to_have_help_and_contact_links end end + it 'renders the barcode deadline banner' do + expect(mail.html_part.body).to have_content( + t( + 'in_person_proofing.body.barcode.deadline', + deadline: formatted_date, + sp_name: sp_name, + ), + ) + expect(mail.html_part.body).to have_content( + t('in_person_proofing.body.barcode.deadline_restart'), + ) + end + it 'renders Questions? and Learn more link only once' do expect(mail.html_part.body).to have_content( t('in_person_proofing.body.barcode.questions'), @@ -1031,6 +1054,14 @@ def expect_email_body_to_have_help_and_contact_links end context 'For Enhanced In-Person Proofing (Enhanced IPP)' do + let(:usps_time_zone) { ActiveSupport::TimeZone['America/New_York'].dup.freeze } + let(:formatted_date) do + I18n.l( + enhanced_ipp_enrollment.due_date.in_time_zone(usps_time_zone), + format: :event_date, + ) + end + let(:sp_name) { enhanced_ipp_enrollment.service_provider.friendly_name } let(:is_enhanced_ipp) { true } let(:mail) do UserMailer.with(user: user, email_address: email_address).in_person_ready_to_verify( @@ -1056,6 +1087,19 @@ def expect_email_body_to_have_help_and_contact_links end end + it 'renders the barcode deadline banner' do + expect(mail.html_part.body).to have_content( + t( + 'in_person_proofing.body.barcode.deadline', + deadline: formatted_date, + sp_name: sp_name, + ), + ) + expect(mail.html_part.body).to have_content( + t('in_person_proofing.body.barcode.deadline_restart'), + ) + end + it 'renders Questions? and Learn more link only once' do expect(mail.html_part.body).to have_content( t('in_person_proofing.body.barcode.questions'), 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 04bccd8e056..9dc6b5057bf 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 @@ -52,6 +52,19 @@ ) end + it 'renders the barcode deadline banner' do + render + + expect(rendered).to have_content( + t( + 'in_person_proofing.body.barcode.deadline', + deadline: presenter.formatted_due_date, + sp_name: presenter.sp_name, + ), + ) + expect(rendered).to have_content(t('in_person_proofing.body.barcode.deadline_restart')) + end + it 'renders a cancel link' do render From 74b2a7af14d81083e28f2da80027976f9a707c91 Mon Sep 17 00:00:00 2001 From: Mitchell Henke Date: Fri, 4 Apr 2025 16:02:24 -0500 Subject: [PATCH 7/8] Remove GET /logout path (#12055) * Remove GET /logout path changelog: Internal, Maintenance, Remove GET /logout path * address sometimes flaky spec --- app/controllers/users/sessions_controller.rb | 10 +++------- config/application.yml.default | 2 -- config/routes.rb | 1 - lib/identity_config.rb | 1 - spec/controllers/users/sessions_controller_spec.rb | 12 ------------ spec/features/ialmax/saml_sign_in_spec.rb | 1 + 6 files changed, 4 insertions(+), 23 deletions(-) diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 2b3e408da2b..b058709710a 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -53,13 +53,9 @@ def create end def destroy - if request.method == 'GET' && IdentityConfig.store.disable_logout_get_request - redirect_to root_path - else - analytics.logout_initiated(sp_initiated: false, oidc: false) - attempts_api_tracker.logout_initiated(success: true) - super - end + analytics.logout_initiated(sp_initiated: false, oidc: false) + attempts_api_tracker.logout_initiated(success: true) + super end def analytics_user diff --git a/config/application.yml.default b/config/application.yml.default index bac792958ab..900c0d3ce1e 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -95,7 +95,6 @@ deliver_mail_async: false desktop_ft_unlock_setup_option_percent_tested: 0 development_mailer_deliver_method: letter_opener disable_email_sending: true -disable_logout_get_request: true disposable_email_services: '[]' doc_auth_attempt_window_in_minutes: 360 doc_auth_check_failed_image_resubmission_enabled: true @@ -533,7 +532,6 @@ production: aamva_auth_url: 'https://authentication-cert.aamva.org/Authentication/Authenticate.svc' aamva_verification_url: 'https://verificationservices-cert.aamva.org:18449/dldv/2.1/online' disable_email_sending: false - disable_logout_get_request: false email_registrations_per_ip_track_only_mode: true enable_test_routes: false enable_usps_verification: false diff --git a/config/routes.rb b/config/routes.rb index 8d902318366..7ed8e829b5a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -100,7 +100,6 @@ get '/' => 'users/sessions#new', as: :new_user_session get '/bounced' => 'users/sp_handoff_bounced#bounced' post '/' => 'users/sessions#create', as: :user_session - get '/logout' => 'users/sessions#destroy', as: :destroy_user_session delete '/logout' => 'users/sessions#destroy' get '/login/piv_cac' => 'users/piv_cac_login#new' diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 2b69f5fed15..c23357494cf 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -113,7 +113,6 @@ def self.store config.add(:desktop_ft_unlock_setup_option_percent_tested, type: :integer) config.add(:development_mailer_deliver_method, type: :symbol, enum: [:file, :letter_opener]) config.add(:disable_email_sending, type: :boolean) - config.add(:disable_logout_get_request, type: :boolean) config.add(:disposable_email_services, type: :json) config.add(:doc_auth_attempt_window_in_minutes, type: :integer) config.add(:doc_auth_check_failed_image_resubmission_enabled, type: :boolean) diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index 8be313f0c97..a08726603cd 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -49,18 +49,6 @@ end end - describe 'GET /logout' do - it 'does not log user out and redirects to root' do - sign_in_as_user - stub_attempts_tracker - - expect(@attempts_api_tracker).to_not receive(:logout_initiated) - get :destroy - expect(controller.current_user).to_not be nil - expect(response).to redirect_to root_url - end - end - describe 'DELETE /logout' do it 'tracks a logout event' do stub_analytics diff --git a/spec/features/ialmax/saml_sign_in_spec.rb b/spec/features/ialmax/saml_sign_in_spec.rb index abcfa30f48e..e3f9c262034 100644 --- a/spec/features/ialmax/saml_sign_in_spec.rb +++ b/spec/features/ialmax/saml_sign_in_spec.rb @@ -52,6 +52,7 @@ visit_idp_from_saml_sp_with_ialmax signin_with_piv(user) click_submit_default + expect(page).to have_current_path(capture_password_path) fill_in 'user[password]', with: user.password click_submit_default_twice click_agree_and_continue From 85dbaae654656cf7ea927871c33cc9553ff01282 Mon Sep 17 00:00:00 2001 From: John Maxwell Date: Mon, 7 Apr 2025 10:31:58 -0400 Subject: [PATCH 8/8] LG-15691 Validate passport mrz (#11978) * Added new passport request to the doc auth flow * [skip changelog] Co-authored-by: Amir Reavis-Bey --- app/forms/idv/api_image_upload_form.rb | 33 ++++- app/forms/idv/doc_pii_form.rb | 3 +- app/services/analytics_events.rb | 29 +++++ .../doc_auth/dos/requests/mrz_request.rb | 1 + lib/idp/constants.rb | 14 +++ .../true_id_response_success_passport.json | 2 +- spec/forms/idv/api_image_upload_form_spec.rb | 116 ++++++++++++++++++ 7 files changed, 192 insertions(+), 6 deletions(-) diff --git a/app/forms/idv/api_image_upload_form.rb b/app/forms/idv/api_image_upload_form.rb index d56dd51de67..0fc2b2de5c0 100644 --- a/app/forms/idv/api_image_upload_form.rb +++ b/app/forms/idv/api_image_upload_form.rb @@ -36,6 +36,7 @@ def submit client_response = nil doc_pii_response = nil + passport_response = nil if form_response.success? client_response = post_images_to_client @@ -46,13 +47,19 @@ def submit if client_response.success? doc_pii_response = validate_pii_from_doc(client_response) + + if doc_pii_response.success? && + doc_pii_response.pii_from_doc[:state_id_type] == 'passport' + passport_response = validate_mrz(client_response) + end end end response = determine_response( - form_response: form_response, - client_response: client_response, - doc_pii_response: doc_pii_response, + form_response:, + client_response:, + doc_pii_response:, + passport_response:, ) failed_fingerprints = store_failed_images(client_response, doc_pii_response) @@ -157,6 +164,22 @@ def validate_pii_from_doc(client_response) response end + def validate_mrz(client_response) + response = DocAuth::Dos::Requests::MrzRequest.new(mrz: client_response.pii_from_doc.mrz).fetch + + analytics.idv_dos_passport_verification( + document_type:, + remaining_submit_attempts:, + submit_attempts:, + user_id: user_uuid, + response: response.extra[:response], + success: response.success?, + ) + + response.extra.merge!(extra_attributes) + response + end + def doc_side_classification(client_response) side_info = {}.merge(client_response&.extra&.[](:classification_info) || {}) side_info.transform_keys(&:downcase).symbolize_keys @@ -227,13 +250,15 @@ def processed_selfie_attempts_data { selfie_attempts: past_selfie_count + processed_selfie_count } end - def determine_response(form_response:, client_response:, doc_pii_response:) + def determine_response(form_response:, client_response:, doc_pii_response:, passport_response:) # image validation failed return form_response unless form_response.success? # doc_pii validation failed return doc_pii_response if doc_pii_response.present? && !doc_pii_response.success? + return passport_response if passport_response.present? && !passport_response.success? + client_response end diff --git a/app/forms/idv/doc_pii_form.rb b/app/forms/idv/doc_pii_form.rb index d9afff38fe9..15fe0c266c7 100644 --- a/app/forms/idv/doc_pii_form.rb +++ b/app/forms/idv/doc_pii_form.rb @@ -8,7 +8,8 @@ class DocPiiForm validate :dob_valid? validate :state_id_or_passport - attr_reader :first_name, :last_name, :dob, :state_id_type, :attention_with_barcode + attr_reader :first_name, :last_name, :dob, :attention_with_barcode, + :jurisdiction, :state_id_number, :state_id_expiration, :state_id_type alias_method :attention_with_barcode?, :attention_with_barcode def initialize(pii:, attention_with_barcode: false) diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 990337b3d69..46ea3c81a8b 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2378,6 +2378,35 @@ def idv_doc_auth_welcome_visited( ) end + # User's passport information submitted to DoS for validation + # @param [Boolean] success Whether the validation succeeded + # @param [String] response The raw verdict from DoS + # @param [Integer] submit_attempts Times that user has tried submitting document capture + # @param [Integer] remaining_submit_attempts how many attempts the user has left before + # we rate limit them. + # @param [String] user_id + # @param [String] document_type The document type (should always be 'Passport' here) + def idv_dos_passport_verification( + success:, + response:, + submit_attempts:, + remaining_submit_attempts:, + user_id:, + document_type:, + **extra + ) + track_event( + :idv_dos_passport_verification, + success:, + response:, + submit_attempts:, + remaining_submit_attempts:, + user_id:, + document_type:, + **extra, + ) + end + # User submitted IDV password confirm page # @param [Boolean] success # @param [Boolean] fraud_review_pending diff --git a/app/services/doc_auth/dos/requests/mrz_request.rb b/app/services/doc_auth/dos/requests/mrz_request.rb index 3fcde4ab778..f911684459b 100644 --- a/app/services/doc_auth/dos/requests/mrz_request.rb +++ b/app/services/doc_auth/dos/requests/mrz_request.rb @@ -30,6 +30,7 @@ def handle_http_response(response) vendor: 'DoS', correlation_id_sent: correlation_id, correlation_id_received: response.headers['X-Correlation-ID'], + response: result[:response], }.compact case result[:response] when 'YES' diff --git a/lib/idp/constants.rb b/lib/idp/constants.rb index 0ee3902d31a..758ec95a3dd 100644 --- a/lib/idp/constants.rb +++ b/lib/idp/constants.rb @@ -136,6 +136,20 @@ module Vendors same_address_as_id: 'true', }.freeze + MOCK_IDV_APPLICANT_WITH_PASSPORT = MOCK_IDV_APPLICANT.select do |field, _value| + %i[first_name middle_name last_name dob sex].include?(field) + end.merge( + state_id_type: 'passport', + mrz: + 'P