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 0a513410e6e..72125da9073 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2363,6 +2363,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