diff --git a/app/controllers/concerns/idv/document_capture_concern.rb b/app/controllers/concerns/idv/document_capture_concern.rb index 77e07da73d8..a92a523599c 100644 --- a/app/controllers/concerns/idv/document_capture_concern.rb +++ b/app/controllers/concerns/idv/document_capture_concern.rb @@ -6,6 +6,18 @@ module DocumentCaptureConcern include DocAuthVendorConcern + def handle_stored_result(user: current_user, store_in_session: true) + if stored_result&.success? && selfie_requirement_met? + save_proofing_components(user) + extract_pii_from_doc(user, store_in_session: store_in_session) + flash[:success] = t('doc_auth.headings.capture_complete') + successful_response + else + extra = { stored_result_present: stored_result.present? } + failure(I18n.t('doc_auth.errors.general.network_error'), extra) + end + end + def save_proofing_components(user) return unless user @@ -77,5 +89,10 @@ def track_document_issuing_state(user, state) doc_auth_log.state = state doc_auth_log.save! end + + def cancel_establishing_in_person_enrollments(user: current_user) + UspsInPersonProofing::EnrollmentHelper. + cancel_stale_establishing_enrollments_for_user(user) + end end end diff --git a/app/controllers/idv/document_capture_controller.rb b/app/controllers/idv/document_capture_controller.rb index a5e3adbdcfe..77599c271c7 100644 --- a/app/controllers/idv/document_capture_controller.rb +++ b/app/controllers/idv/document_capture_controller.rb @@ -89,11 +89,6 @@ def self.step_info private - def cancel_establishing_in_person_enrollments - UspsInPersonProofing::EnrollmentHelper. - cancel_stale_establishing_enrollments_for_user(current_user) - end - def analytics_arguments { flow_path: flow_path, @@ -106,18 +101,6 @@ def analytics_arguments }.merge(ab_test_analytics_buckets) end - def handle_stored_result - if stored_result&.success? && selfie_requirement_met? - save_proofing_components(current_user) - extract_pii_from_doc(current_user, store_in_session: true) - flash[:success] = t('doc_auth.headings.capture_complete') - successful_response - else - extra = { stored_result_present: stored_result.present? } - failure(I18n.t('doc_auth.errors.general.network_error'), extra) - end - end - def allow_direct_ipp? return false unless idv_session.welcome_visited && idv_session.idv_consent_given? diff --git a/app/controllers/idv/hybrid_mobile/document_capture_controller.rb b/app/controllers/idv/hybrid_mobile/document_capture_controller.rb index d2ea4984f4b..023ce16fa46 100644 --- a/app/controllers/idv/hybrid_mobile/document_capture_controller.rb +++ b/app/controllers/idv/hybrid_mobile/document_capture_controller.rb @@ -24,7 +24,10 @@ def show def update document_capture_session.confirm_ocr - result = handle_stored_result + result = handle_stored_result( + user: document_capture_user, + store_in_session: false, + ) analytics.idv_doc_auth_document_capture_submitted(**result.to_h.merge(analytics_arguments)) @@ -33,7 +36,6 @@ def update # rate limiting redirect is in ImageUploadResponsePresenter if result.success? - flash[:success] = t('doc_auth.headings.capture_complete') redirect_to idv_hybrid_mobile_capture_complete_url else redirect_to idv_hybrid_mobile_document_capture_url @@ -66,17 +68,6 @@ def analytics_arguments ) end - def handle_stored_result - if stored_result&.success? && selfie_requirement_met? - save_proofing_components(document_capture_user) - extract_pii_from_doc(document_capture_user) - successful_response - else - extra = { stored_result_present: stored_result.present? } - failure(I18n.t('doc_auth.errors.general.network_error'), extra) - end - end - def confirm_document_capture_needed return unless stored_result&.success? return if redo_document_capture_pending? diff --git a/app/controllers/idv/socure/document_capture_controller.rb b/app/controllers/idv/socure/document_capture_controller.rb index 824b545e83b..805b92c3851 100644 --- a/app/controllers/idv/socure/document_capture_controller.rb +++ b/app/controllers/idv/socure/document_capture_controller.rb @@ -28,7 +28,7 @@ def show # document request document_request = DocAuth::Socure::Requests::DocumentRequest.new( document_capture_session_uuid: document_capture_session_uuid, - redirect_url: idv_socure_document_capture_url, + redirect_url: idv_socure_document_capture_update_url, language: I18n.locale, ) @@ -61,7 +61,25 @@ def show end def update - render plain: 'stub to ensure Socure callback exists and the route works' + clear_future_steps! + idv_session.redo_document_capture = nil # done with this redo + # Not used in standard flow, here for data consistency with hybrid flow. + document_capture_session.confirm_ocr + + result = handle_stored_result + # TODO: new analytics event? + analytics.idv_doc_auth_document_capture_submitted(**result.to_h.merge(analytics_arguments)) + + Funnel::DocAuth::RegisterStep.new(current_user.id, sp_session[:issuer]). + call('socure_document_capture', :update, true) + + cancel_establishing_in_person_enrollments + + if result.success? + redirect_to idv_ssn_url + else + redirect_to idv_socure_document_capture_url + end end def self.step_info @@ -85,6 +103,20 @@ def self.step_info end, ) end + + private + + def analytics_arguments + { + flow_path: flow_path, + step: 'socure_document_capture', + analytics_id: 'Doc Auth', + redo_document_capture: idv_session.redo_document_capture, + skip_hybrid_handoff: idv_session.skip_hybrid_handoff, + liveness_checking_required: resolved_authn_context_result.facial_match?, + selfie_check_required: resolved_authn_context_result.facial_match?, + }.merge(ab_test_analytics_buckets) + end end end end diff --git a/app/controllers/socure_webhook_controller.rb b/app/controllers/socure_webhook_controller.rb index 4d1ca45a362..a4ba596cae3 100644 --- a/app/controllers/socure_webhook_controller.rb +++ b/app/controllers/socure_webhook_controller.rb @@ -21,11 +21,23 @@ def create private + def process_webhook_event + case event[:eventType] + when 'DOCUMENTS_UPLOADED' + increment_rate_limiter + fetch_results + end + end + def fetch_results dcs = document_capture_session raise 'DocumentCaptureSession not found' if dcs.blank? - SocureDocvResultsJob.perform_later(document_capture_session_uuid: dcs.uuid) + if IdentityConfig.store.ruby_workers_idv_enabled + SocureDocvResultsJob.perform_later(document_capture_session_uuid: dcs.uuid) + else + SocureDocvResultsJob.perform_now(document_capture_session_uuid: dcs.uuid) + end end def check_token @@ -74,14 +86,6 @@ def log_webhook_receipt ) end - def process_webhook_event - case event[:eventType] - when 'DOCUMENTS_UPLOADED' - increment_rate_limiter - fetch_results - end - end - def increment_rate_limiter if document_capture_session.present? rate_limiter.increment! @@ -90,8 +94,9 @@ def increment_rate_limiter end def document_capture_session + token = event[:docvTransactionToken] || event[:docVTransactionToken] @document_capture_session ||= DocumentCaptureSession.find_by( - socure_docv_transaction_token: event[:docvTransactionToken], + socure_docv_transaction_token: token, ) end @@ -109,7 +114,7 @@ def rate_limiter def socure_params params.permit( event: [:created, :customerUserId, :eventType, :referenceId, - :docvTransactionToken], + :docvTransactionToken, :docVTransactionToken], ) end end diff --git a/app/services/doc_auth/socure/requests/document_request.rb b/app/services/doc_auth/socure/requests/document_request.rb index 9062ac1b9be..4a6f5b0920f 100644 --- a/app/services/doc_auth/socure/requests/document_request.rb +++ b/app/services/doc_auth/socure/requests/document_request.rb @@ -27,7 +27,7 @@ def lang(language) def body redirect = { - method: 'POST', + method: 'GET', url: redirect_url, } diff --git a/config/routes.rb b/config/routes.rb index 33df2761750..e9f42f70ac7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -360,7 +360,7 @@ get '/document_capture' => 'document_capture#show' put '/document_capture' => 'document_capture#update' get '/socure/document_capture' => 'socure/document_capture#show' - post '/socure/document_capture' => 'socure/document_capture#update' + get '/socure/document_capture_update' => 'socure/document_capture#update', as: :socure_document_capture_update # This route is included in SMS messages sent to users who start the IdV hybrid flow. It # should be kept short, and should not include underscores ("_"). get '/documents' => 'hybrid_mobile/entry#show', as: :hybrid_mobile_entry diff --git a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb index bdfb814fdbe..d87e5061368 100644 --- a/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/hybrid_mobile/socure/document_capture_controller_spec.rb @@ -120,7 +120,7 @@ config: { documentType: 'license', redirect: { - method: 'POST', + method: 'GET', url: idv_hybrid_mobile_socure_document_capture_url, }, language: expected_language, @@ -143,7 +143,7 @@ config: { documentType: 'license', redirect: { - method: 'POST', + method: 'GET', url: idv_hybrid_mobile_socure_document_capture_url, }, language: 'zh-cn', diff --git a/spec/controllers/idv/socure/document_capture_controller_spec.rb b/spec/controllers/idv/socure/document_capture_controller_spec.rb index 0b7ca0bbf19..6ecf9d88f05 100644 --- a/spec/controllers/idv/socure/document_capture_controller_spec.rb +++ b/spec/controllers/idv/socure/document_capture_controller_spec.rb @@ -6,7 +6,17 @@ let(:idv_vendor) { Idp::Constants::Vendors::SOCURE } let(:fake_socure_endpoint) { 'https://fake-socure.test' } let(:user) { create(:user) } - let(:stored_result) { nil } + let(:doc_auth_success) { true } + let(:stored_result) do + DocumentCaptureSessionResult.new( + id: SecureRandom.uuid, + success: doc_auth_success, + doc_auth_success: doc_auth_success, + selfie_status: :none, + pii: { first_name: 'Testy', last_name: 'Testerson' }, + attention_with_barcode: false, + ) + end let(:socure_enabled) { true } let(:document_capture_session) do @@ -23,6 +33,7 @@ and_return(fake_socure_endpoint) allow(IdentityConfig.store).to receive(:doc_auth_vendor).and_return(idv_vendor) allow(IdentityConfig.store).to receive(:doc_auth_vendor_default).and_return(idv_vendor) + allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) allow(subject).to receive(:stored_result).and_return(stored_result) @@ -101,7 +112,7 @@ expect(request_class).to have_received(:new). with( document_capture_session_uuid: expected_uuid, - redirect_url: idv_socure_document_capture_url, + redirect_url: idv_socure_document_capture_update_url, language: expected_language, ) end @@ -122,8 +133,8 @@ config: { documentType: 'license', redirect: { - method: 'POST', - url: idv_socure_document_capture_url, + method: 'GET', + url: idv_socure_document_capture_update_url, }, language: :en, }, @@ -145,8 +156,8 @@ config: { documentType: 'license', redirect: { - method: 'POST', - url: idv_socure_document_capture_url, + method: 'GET', + url: idv_socure_document_capture_update_url, }, language: 'zh-cn', }, @@ -264,9 +275,19 @@ describe '#update' do it 'returns OK (200)' do - post(:update) + get(:update) + + expect(response).to redirect_to(idv_ssn_path) + end - expect(response).to have_http_status(:ok) + context 'when doc auth fails' do + let(:doc_auth_success) { false } + + it 'redirects to document capture' do + get(:update) + + expect(response).to redirect_to(idv_socure_document_capture_path) + end end context 'when socure is disabled' do diff --git a/spec/services/doc_auth/socure/requests/document_request_spec.rb b/spec/services/doc_auth/socure/requests/document_request_spec.rb index 4ea862c903f..17c8032118b 100644 --- a/spec/services/doc_auth/socure/requests/document_request_spec.rb +++ b/spec/services/doc_auth/socure/requests/document_request_spec.rb @@ -38,7 +38,7 @@ documentType: document_type, redirect: { - method: 'POST', + method: 'GET', url: redirect_url, }, language: language,