From 0183bdd15e669fd043dc4dc1bbf32c01921b1495 Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 12:35:09 -0500 Subject: [PATCH 01/30] Refactor in preparation for allowing more errors --- app/services/doc_auth/error_generator.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index ded26d8915d..59a7e316dfd 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -189,14 +189,20 @@ def get_error_messages(liveness_enabled, response_info) end end - portrait_match_results = response_info[:portrait_match_results] || {} - if liveness_enabled && portrait_match_results.dig(:FaceMatchResult) != 'Pass' - errors[SELFIE] << Errors::SELFIE_FAILURE + selfie_error = get_selfie_error(liveness_enabled, response_info) + if liveness_enabled && selfie_error + errors[SELFIE] << selfie_error end errors end + def get_selfie_error(liveness_enabled, response_info) + if liveness_enabled && portrait_match_results.dig(:FaceMatchResult) == 'Fail' + errors[SELFIE] << get_selfie_error(response_info) + end + end + def scan_for_unknown_alerts(response_info) all_alerts = [ *response_info[:processed_alerts][:failed], From b36be98ffef93405a51dcd9a30a84216e8b973e8 Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 12:51:28 -0500 Subject: [PATCH 02/30] Draft in error reporting --- app/services/doc_auth/error_generator.rb | 17 +++++++++++++++-- app/services/doc_auth/errors.rb | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 59a7e316dfd..928bfc355f8 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -198,9 +198,22 @@ def get_error_messages(liveness_enabled, response_info) end def get_selfie_error(liveness_enabled, response_info) - if liveness_enabled && portrait_match_results.dig(:FaceMatchResult) == 'Fail' - errors[SELFIE] << get_selfie_error(response_info) + # No error if liveness is not enabled + if not liveness_enabled + return nil end + # Error when the image on the id does not match the selfie image + if portrait_match_results.dig(:FaceMatchResult) == 'Fail' + return Errors::SELFIE_FAILURE + end + # Error when the image on the id is poor quality + if # TODO condition + return Errors::SELFIE_NOT_LIVE + end + if # TODO condition + return Errors::SELFIE_POOR_QUALITY + end + # Error when the image on the id is not live end def scan_for_unknown_alerts(response_info) diff --git a/app/services/doc_auth/errors.rb b/app/services/doc_auth/errors.rb index cdd8e79bdc7..e67de97d54c 100644 --- a/app/services/doc_auth/errors.rb +++ b/app/services/doc_auth/errors.rb @@ -27,6 +27,8 @@ module Errors MULTIPLE_FRONT_ID_FAILURES = 'multiple_front_id_failures' REF_CONTROL_NUMBER_CHECK = 'ref_control_number_check' SELFIE_FAILURE = 'selfie_failure' + SELFIE_NOT_LIVE = 'selfie_not_live' + SELFIE_POOR_QUALITY = 'selfie_poor_quality' SEX_CHECK = 'sex_check' VISIBLE_COLOR_CHECK = 'visible_color_check' VISIBLE_PHOTO_CHECK = 'visible_photo_check' From 02a46a8c9c2d36dc7823c3bd7aa91f0ee4cc964f Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 14:40:06 -0500 Subject: [PATCH 03/30] Fill in selfie error generator --- app/services/doc_auth/error_generator.rb | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 928bfc355f8..77937559cc3 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -198,22 +198,31 @@ def get_error_messages(liveness_enabled, response_info) end def get_selfie_error(liveness_enabled, response_info) - # No error if liveness is not enabled - if not liveness_enabled + # The part of the response that contains information about the selfie + portrait_match_results = response_info[:portrait_match_results] || {} + # The overall result of the selfie, 'Pass' or 'Fail' + face_match_result = portrait_match_results.dig(:FaceMatchResult) + # The reason for failure (if it failed), also sometimes contains success info + face_match_error = portrait_match_results.dig(:FaceErrorMessage) + + # No error if liveness is not enabled or if there's no failure + if !liveness_enabled || face_match_result == 'Pass' return nil end - # Error when the image on the id does not match the selfie image - if portrait_match_results.dig(:FaceMatchResult) == 'Fail' + + # Error when the image on the id does not match the selfie image, but the image was acceptable + if face_match_result == 'Fail' && + face_match_error == "FaceErrorMessage: 'Successful. Liveness: Live'" return Errors::SELFIE_FAILURE end - # Error when the image on the id is poor quality - if # TODO condition + # Error when the image on the id is poor quality + if face_match_result == 'Fail' && face_match_error == 'Liveness: PoorQuality' return Errors::SELFIE_NOT_LIVE end - if # TODO condition + # Error when the image on the id is not live + if face_match_result == 'Fail' && face_match_error == 'Liveness: NotLive' return Errors::SELFIE_POOR_QUALITY end - # Error when the image on the id is not live end def scan_for_unknown_alerts(response_info) From dada67c04373d860ea9f4a645c253d0866272a55 Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 15:20:06 -0500 Subject: [PATCH 04/30] Add comments --- app/services/doc_auth/error_generator.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 77937559cc3..fa2df32894e 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -58,9 +58,13 @@ def generate_doc_auth_errors(response_info) unknown_fail_count = scan_for_unknown_alerts(response_info) alert_error_count -= unknown_fail_count + # If we have document type errors (Ex: passport was uploaded) return only + # those errors for both the "FRONT" and "BACK" fields (but not "SELFIE") doc_type_errors = get_id_type_errors(response_info[:classification_info]) return doc_type_errors.to_h unless doc_type_errors.nil? || doc_type_errors.empty? + # If we have image metric errors (Ex: DPI too low) return only + # those errors for both the "FRONT" and "BACK" fields (but not "SELFIE") image_metric_errors = get_image_metric_errors(response_info[:image_metrics]) return image_metric_errors.to_h unless image_metric_errors.empty? @@ -71,6 +75,13 @@ def generate_doc_auth_errors(response_info) error = '' side = nil + # If we don't have document type or image metric errors then sort out which + # errors to return. This can return errors for only these combinations of fields: + # - "Front" + # - "Back" + # - "Front, Back" + # - "Selfie" + # You'll note we're missing some "Selfie" combinations like: "Front", "Selfie" if alert_error_count < 1 config.warn_notifier&.call( message: 'DocAuth failure escaped without useful errors', From 1396c89389fad7c0c5526608a18c31d354c09b4f Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 15:38:37 -0500 Subject: [PATCH 05/30] Add comments to mark broken tests --- spec/services/doc_auth/error_generator_spec.rb | 9 +++++++-- spec/services/doc_auth/mock/doc_auth_mock_client_spec.rb | 4 ++++ spec/services/doc_auth/mock/result_response_spec.rb | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/services/doc_auth/error_generator_spec.rb b/spec/services/doc_auth/error_generator_spec.rb index 84f1ff11e39..a067435b461 100644 --- a/spec/services/doc_auth/error_generator_spec.rb +++ b/spec/services/doc_auth/error_generator_spec.rb @@ -525,9 +525,12 @@ def build_error_info( }, } end + + # TODO fix this set of tests context 'when liveness is enabled' do let(:liveness_enabled) { true } context 'when liveness check passed' do + # TODO:👇🏻 This line does nothing right now, fix this test let(:face_match_result) { 'Pass' } it 'DocAuthResult is Passed with no other error' do error_info = build_error_info(doc_result: 'Passed', image_metrics: metrics) @@ -541,9 +544,11 @@ def build_error_info( end context 'when liveness check failed' do - let(:face_match_result) { 'Failure' } + # TODO:👇🏻 This line does nothing right now, fix this test + let(:face_match_result) { 'Fail' } + # This test doesn't have a selfie error as far as I can tell it 'DocAuthResult is failed with selfie error' do - error_info = build_error_info(doc_result: 'Failed', image_metrics: metrics) + error_info = build_error_info(doc_result: 'Passed', image_metrics: metrics) errors = described_class.new(config).generate_doc_auth_errors(error_info) expect(errors.keys).to contain_exactly(:general, :selfie, :hints) end diff --git a/spec/services/doc_auth/mock/doc_auth_mock_client_spec.rb b/spec/services/doc_auth/mock/doc_auth_mock_client_spec.rb index b10f21671ac..c39d2435a1d 100644 --- a/spec/services/doc_auth/mock/doc_auth_mock_client_spec.rb +++ b/spec/services/doc_auth/mock/doc_auth_mock_client_spec.rb @@ -312,6 +312,10 @@ end end + # TODO fix this set of tests, this looks like something broken with error generation? + # NoMethodError: + # undefined method `empty?' for nil + # ./app/services/doc_auth/error_result.rb:33:in `to_h' describe 'when sending a failing selfie yml' do context 'liveness check fails due to being determined to not be live' do it 'returns a failure response' do diff --git a/spec/services/doc_auth/mock/result_response_spec.rb b/spec/services/doc_auth/mock/result_response_spec.rb index e3296ca83c0..8e1448a8a45 100644 --- a/spec/services/doc_auth/mock/result_response_spec.rb +++ b/spec/services/doc_auth/mock/result_response_spec.rb @@ -676,6 +676,7 @@ end end + # TODO update this test, looks like the same problem as in error_generator_spec.rb describe 'and it is not successful' do let(:input) do <<~YAML From 165a36d11efccdb885971ca07211f5496db18320 Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 15:40:18 -0500 Subject: [PATCH 06/30] Fix comment --- app/services/doc_auth/error_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index fa2df32894e..240c6d9ccbc 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -79,7 +79,7 @@ def generate_doc_auth_errors(response_info) # errors to return. This can return errors for only these combinations of fields: # - "Front" # - "Back" - # - "Front, Back" + # - "ID" (AKA "Front", "Back" I think) # - "Selfie" # You'll note we're missing some "Selfie" combinations like: "Front", "Selfie" if alert_error_count < 1 From d2dcb1ebdbef6f5c79c3075acc9490c33f71a1ef Mon Sep 17 00:00:00 2001 From: charleyf Date: Thu, 18 Jan 2024 16:09:50 -0500 Subject: [PATCH 07/30] Fix mixed up error names --- app/services/doc_auth/error_generator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 240c6d9ccbc..8da253db3b0 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -228,11 +228,11 @@ def get_selfie_error(liveness_enabled, response_info) end # Error when the image on the id is poor quality if face_match_result == 'Fail' && face_match_error == 'Liveness: PoorQuality' - return Errors::SELFIE_NOT_LIVE + return Errors::SELFIE_POOR_QUALITY end # Error when the image on the id is not live if face_match_result == 'Fail' && face_match_error == 'Liveness: NotLive' - return Errors::SELFIE_POOR_QUALITY + return Errors::SELFIE_NOT_LIVE end end From ee025ced8cd8932d0f75b426b3c9e8890c652dc3 Mon Sep 17 00:00:00 2001 From: charleyf Date: Fri, 19 Jan 2024 10:30:50 -0500 Subject: [PATCH 08/30] Use a case (switch) statement instead of ifs --- app/services/doc_auth/error_generator.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 8da253db3b0..2e24ac3f686 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -217,23 +217,23 @@ def get_selfie_error(liveness_enabled, response_info) face_match_error = portrait_match_results.dig(:FaceErrorMessage) # No error if liveness is not enabled or if there's no failure - if !liveness_enabled || face_match_result == 'Pass' + if !liveness_enabled || face_match_result != 'Fail' return nil end + case face_match_error # Error when the image on the id does not match the selfie image, but the image was acceptable - if face_match_result == 'Fail' && - face_match_error == "FaceErrorMessage: 'Successful. Liveness: Live'" + when "FaceErrorMessage: 'Successful. Liveness: Live'" return Errors::SELFIE_FAILURE - end # Error when the image on the id is poor quality - if face_match_result == 'Fail' && face_match_error == 'Liveness: PoorQuality' + when 'Liveness: PoorQuality' return Errors::SELFIE_POOR_QUALITY - end # Error when the image on the id is not live - if face_match_result == 'Fail' && face_match_error == 'Liveness: NotLive' + when 'Liveness: NotLive' return Errors::SELFIE_NOT_LIVE - end + # Fallback, we don't expect this to happen + else + return Errors::SELFIE_FAILURE end def scan_for_unknown_alerts(response_info) From 504276677dd1c26a68ef2b1fdf3e7ad7c580a510 Mon Sep 17 00:00:00 2001 From: charleyf Date: Fri, 19 Jan 2024 11:03:54 -0500 Subject: [PATCH 09/30] Revise comments --- app/services/doc_auth/error_generator.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 2e24ac3f686..993b6610cff 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -59,12 +59,14 @@ def generate_doc_auth_errors(response_info) alert_error_count -= unknown_fail_count # If we have document type errors (Ex: passport was uploaded) return only - # those errors for both the "FRONT" and "BACK" fields (but not "SELFIE") + # document type errors for both the "FRONT" and "BACK" fields (but not "SELFIE") + # this return will never include any selfie errors at the moment. doc_type_errors = get_id_type_errors(response_info[:classification_info]) return doc_type_errors.to_h unless doc_type_errors.nil? || doc_type_errors.empty? # If we have image metric errors (Ex: DPI too low) return only - # those errors for both the "FRONT" and "BACK" fields (but not "SELFIE") + # image metric errors for both the "FRONT" and "BACK" fields (but not "SELFIE") + # this return will never include any selfie errors at the moment. image_metric_errors = get_image_metric_errors(response_info[:image_metrics]) return image_metric_errors.to_h unless image_metric_errors.empty? @@ -76,12 +78,8 @@ def generate_doc_auth_errors(response_info) side = nil # If we don't have document type or image metric errors then sort out which - # errors to return. This can return errors for only these combinations of fields: - # - "Front" - # - "Back" - # - "ID" (AKA "Front", "Back" I think) - # - "Selfie" - # You'll note we're missing some "Selfie" combinations like: "Front", "Selfie" + # errors to return. Note that there's a :general error added in the + # `to_h` method of error_result if alert_error_count < 1 config.warn_notifier&.call( message: 'DocAuth failure escaped without useful errors', From cea16b8a0439181244756732a8ce273482165839 Mon Sep 17 00:00:00 2001 From: charleyf Date: Fri, 19 Jan 2024 11:21:41 -0500 Subject: [PATCH 10/30] Add comment to mark message --- app/services/doc_auth/errors.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/doc_auth/errors.rb b/app/services/doc_auth/errors.rb index e67de97d54c..5306fb0cab8 100644 --- a/app/services/doc_auth/errors.rb +++ b/app/services/doc_auth/errors.rb @@ -118,6 +118,7 @@ module Errors MULTIPLE_BACK_ID_FAILURES => { long_msg: MULTIPLE_BACK_ID_FAILURES, field_msg: FALLBACK_FIELD_LEVEL, hints: true }, GENERAL_ERROR => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: true }, # Liveness, use general error for now + # TODO, this is one of the messages to modify SELFIE_FAILURE => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: false }, } # rubocop:enable Layout/LineLength From 23ff4d93fa868c62a585ea647c9178e067794c62 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 09:33:18 -0500 Subject: [PATCH 11/30] Fix missing `end` --- app/services/doc_auth/error_generator.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index 993b6610cff..a1fe9604d11 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -199,7 +199,7 @@ def get_error_messages(liveness_enabled, response_info) end selfie_error = get_selfie_error(liveness_enabled, response_info) - if liveness_enabled && selfie_error + if liveness_enabled && !!selfie_error errors[SELFIE] << selfie_error end @@ -215,7 +215,7 @@ def get_selfie_error(liveness_enabled, response_info) face_match_error = portrait_match_results.dig(:FaceErrorMessage) # No error if liveness is not enabled or if there's no failure - if !liveness_enabled || face_match_result != 'Fail' + if !liveness_enabled || !face_match_result || face_match_result == 'Pass' return nil end @@ -232,6 +232,7 @@ def get_selfie_error(liveness_enabled, response_info) # Fallback, we don't expect this to happen else return Errors::SELFIE_FAILURE + end end def scan_for_unknown_alerts(response_info) From 20934da47910f5dffa91edb40862250c2eacaeb0 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 09:58:57 -0500 Subject: [PATCH 12/30] Add missing error keys --- app/services/doc_auth/errors.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/doc_auth/errors.rb b/app/services/doc_auth/errors.rb index 5306fb0cab8..98068b64158 100644 --- a/app/services/doc_auth/errors.rb +++ b/app/services/doc_auth/errors.rb @@ -117,9 +117,11 @@ module Errors MULTIPLE_FRONT_ID_FAILURES => { long_msg: MULTIPLE_FRONT_ID_FAILURES, field_msg: FALLBACK_FIELD_LEVEL, hints: true }, MULTIPLE_BACK_ID_FAILURES => { long_msg: MULTIPLE_BACK_ID_FAILURES, field_msg: FALLBACK_FIELD_LEVEL, hints: true }, GENERAL_ERROR => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: true }, + # TODO, theses messages need modifying # Liveness, use general error for now - # TODO, this is one of the messages to modify SELFIE_FAILURE => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: false }, + SELFIE_NOT_LIVE => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: false }, + SELFIE_POOR_QUALITY => { long_msg: GENERAL_ERROR, field_msg: FALLBACK_FIELD_LEVEL, hints: false }, } # rubocop:enable Layout/LineLength end From 69a2cede2e9d68063643fa66800f1f0b049b23e9 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 10:09:13 -0500 Subject: [PATCH 13/30] User Facing Improvements, In-Person Proofing, add error messages behind feature flag for new liveness checks From 005821dd8b9baef58dc2f3c330ca113f616e2c19 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 10:14:05 -0500 Subject: [PATCH 14/30] changelog: User Facing Improvements, In-Person Proofing, add error messages behind feature flag for new liveness checks From e061f6cbcc360111b2af35b997691768121dccc8 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 12:56:29 -0500 Subject: [PATCH 15/30] Draft in selfie error check fields --- .../image_upload_response_presenter.rb | 13 ++++++++++-- app/services/doc_auth/response.rb | 21 +++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/app/presenters/image_upload_response_presenter.rb b/app/presenters/image_upload_response_presenter.rb index 0b927115812..305d0deb7af 100644 --- a/app/presenters/image_upload_response_presenter.rb +++ b/app/presenters/image_upload_response_presenter.rb @@ -41,7 +41,9 @@ def as_json(*) json = { success: false, errors: errors, remaining_attempts: remaining_attempts, - doc_type_supported: doc_type_supported? } + doc_type_supported: doc_type_supported?, + selfie_live: selfie_live?, + selfie_quality_good: selfie_quality_good? } if remaining_attempts&.zero? if @form_response.extra[:flow_path] == 'standard' json[:redirect] = idv_session_errors_rate_limited_url @@ -54,7 +56,6 @@ def as_json(*) json[:result_failed] = doc_auth_result_failed? json[:doc_type_supported] = doc_type_supported? json[:failed_image_fingerprints] = failed_fingerprints - json end end @@ -89,4 +90,12 @@ def doc_type_supported? def failed_fingerprints @form_response.extra[:failed_image_fingerprints] || { front: [], back: [] } end + + def selfie_live? + return true + end + + def selfie_quality_good? + return true + end end diff --git a/app/services/doc_auth/response.rb b/app/services/doc_auth/response.rb index f002df6c97f..c14323f8a05 100644 --- a/app/services/doc_auth/response.rb +++ b/app/services/doc_auth/response.rb @@ -1,6 +1,7 @@ module DocAuth class Response - attr_reader :errors, :exception, :extra, :pii_from_doc, :doc_type_supported + attr_reader :errors, :exception, :extra, :pii_from_doc, :doc_type_supported, :selfie_live, + :selfie_quality_good ID_TYPE_SLUGS = { 'Identification Card' => 'state_id_card', @@ -15,7 +16,9 @@ def initialize( pii_from_doc: {}, attention_with_barcode: false, doc_type_supported: true, - selfie_check_performed: false + selfie_check_performed: false, + selfie_live: true, + selfie_quality_good: true ) @success = success @errors = errors.to_h @@ -25,6 +28,8 @@ def initialize( @attention_with_barcode = attention_with_barcode @doc_type_supported = doc_type_supported @selfie_check_performed = selfie_check_performed + @selfie_live = selfie_live + @selfie_quality_good = selfie_quality_good end def merge(other) @@ -36,6 +41,8 @@ def merge(other) pii_from_doc: pii_from_doc.merge(other.pii_from_doc), attention_with_barcode: attention_with_barcode? || other.attention_with_barcode?, doc_type_supported: doc_type_supported? || other.doc_type_supported?, + selfie_live: selfie_live?, + selfie_quality_good: selfie_quality_good?, ) end @@ -47,6 +54,14 @@ def doc_type_supported? @doc_type_supported end + def selfie_live? + @selfie_live + end + + def selfie_quality_good? + @selfie_quality_good + end + # We use `#to_h` to serialize this for logging. Make certain not to include # the `#pii` value here. def to_h @@ -56,6 +71,8 @@ def to_h exception: exception, attention_with_barcode: attention_with_barcode?, doc_type_supported: doc_type_supported?, + selfie_live: selfie_live?, + selfie_quality_good: selfie_quality_good?, doc_auth_success: doc_auth_success?, selfie_success: selfie_success, }.merge(extra) From 08a2bdc0c5f5ca8e5c9a1399beb47281cd8940c4 Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 15:17:33 -0500 Subject: [PATCH 16/30] Update the two selfie error booleans --- .../image_upload_response_presenter.rb | 4 ++-- .../acuant/responses/get_results_response.rb | 1 + .../lexis_nexis/responses/true_id_response.rb | 7 ++++++- app/services/doc_auth/mock/result_response.rb | 3 +++ app/services/doc_auth/selfie_concern.rb | 21 +++++++++++++++++++ 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 app/services/doc_auth/selfie_concern.rb diff --git a/app/presenters/image_upload_response_presenter.rb b/app/presenters/image_upload_response_presenter.rb index 305d0deb7af..5412fe5edae 100644 --- a/app/presenters/image_upload_response_presenter.rb +++ b/app/presenters/image_upload_response_presenter.rb @@ -92,10 +92,10 @@ def failed_fingerprints end def selfie_live? - return true + @form_response.respond_to?(:selfie_live?) ? @form_response.selfie_live? : true end def selfie_quality_good? - return true + @form_response.respond_to?(:selfie_quality_good?) ? @form_response.selfie_quality_good? : true end end diff --git a/app/services/doc_auth/acuant/responses/get_results_response.rb b/app/services/doc_auth/acuant/responses/get_results_response.rb index eb6ca35d34b..2cbbb5a0b7e 100644 --- a/app/services/doc_auth/acuant/responses/get_results_response.rb +++ b/app/services/doc_auth/acuant/responses/get_results_response.rb @@ -3,6 +3,7 @@ module Acuant module Responses class GetResultsResponse < DocAuth::Response include ClassificationConcern + include SelfieConcern attr_reader :config BARCODE_COULD_NOT_BE_READ_ERROR = '2D Barcode Read'.freeze diff --git a/app/services/doc_auth/lexis_nexis/responses/true_id_response.rb b/app/services/doc_auth/lexis_nexis/responses/true_id_response.rb index 0bdf08488c2..31ad0b721ec 100644 --- a/app/services/doc_auth/lexis_nexis/responses/true_id_response.rb +++ b/app/services/doc_auth/lexis_nexis/responses/true_id_response.rb @@ -5,6 +5,7 @@ module LexisNexis module Responses class TrueIdResponse < DocAuth::Response include ClassificationConcern + include SelfieConcern PII_EXCLUDES = %w[ Age DocSize @@ -226,7 +227,7 @@ def create_response_info processed_alerts: alerts, alert_failure_count: alerts[:failed]&.count.to_i, log_alert_results: log_alert_formatter.log_alerts(alerts), - portrait_match_results: true_id_product&.dig(:PORTRAIT_MATCH_RESULT), + portrait_match_results: portrait_match_results, image_metrics: parse_image_metrics, address_line2_present: !pii_from_doc[:address2].blank?, classification_info: classification_info, @@ -291,6 +292,10 @@ def classification_info } end + def portrait_match_results + true_id_product&.dig(:PORTRAIT_MATCH_RESULT) + end + def doc_auth_result true_id_product&.dig(:AUTHENTICATION_RESULT, :DocAuthResult) end diff --git a/app/services/doc_auth/mock/result_response.rb b/app/services/doc_auth/mock/result_response.rb index fd3d6524655..4dd91adbd73 100644 --- a/app/services/doc_auth/mock/result_response.rb +++ b/app/services/doc_auth/mock/result_response.rb @@ -2,6 +2,7 @@ module DocAuth module Mock class ResultResponse < DocAuth::Response include DocAuth::ClassificationConcern + include DocAuth::SelfieConcern include DocAuth::Mock::YmlLoaderConcern attr_reader :uploaded_file, :config @@ -16,6 +17,8 @@ def initialize(uploaded_file, selfie_check_performed, config) pii_from_doc: pii_from_doc, doc_type_supported: id_type_supported?, selfie_check_performed: selfie_check_performed, + selfie_live: selfie_live?, + selfie_quality_good: selfie_quality_good?, extra: { doc_auth_result: doc_auth_result, portrait_match_results: portrait_match_results, diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb new file mode 100644 index 00000000000..cad3362fd8f --- /dev/null +++ b/app/services/doc_auth/selfie_concern.rb @@ -0,0 +1,21 @@ +module DocAuth + module SelfieConcern + extend ActiveSupport::Concern + def selfie_live? + portait_error = get_portrait_error(portrait_match_results) + return portait_error != 'Liveness: NotLive' + end + + def selfie_quality_good? + portait_error = get_portrait_error(portrait_match_results) + return portait_error != 'Liveness: PoorQuality' + end + + private + + # @param [Object] portrait_match_results trueid portait match info + def get_portrait_error(portrait_match_results) + portrait_match_results&.with_indifferent_access&.dig(:FaceErrorMessage) + end +end +end From bd061f44db34e6170db6b0bcb6cbfdcfde813c9a Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 15:30:06 -0500 Subject: [PATCH 17/30] Add tests for the concern --- spec/services/doc_auth/selfie_concern_spec.rb | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 spec/services/doc_auth/selfie_concern_spec.rb diff --git a/spec/services/doc_auth/selfie_concern_spec.rb b/spec/services/doc_auth/selfie_concern_spec.rb new file mode 100644 index 00000000000..ada2618a17a --- /dev/null +++ b/spec/services/doc_auth/selfie_concern_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +RSpec.describe DocAuth::SelfieConcern do + let(:face_error_message) { '' } + let(:portait_info) do + { + FaceErrorMessage: face_error_message, + } + end + + subject do + Class.new do + include DocAuth::SelfieConcern + attr_reader :portrait_match_results + def initialize(portrait_match_results) + @portrait_match_results = portrait_match_results + end + end.new(portait_info) + end + + describe '#selfie_live?' do + context 'no liveness error message' do + it 'returns true' do + expect(subject.selfie_live?).to eq(true) + end + end + + context 'a non-live error message' do + let(:face_error_message) { 'Liveness: NotLive' } + it 'returns false' do + expect(subject.selfie_live?).to eq(false) + end + end + end + + describe '#selfie_quality_good?' do + context 'no liveness error message' do + it 'returns true' do + expect(subject.selfie_quality_good?).to eq(true) + end + end + + context 'a poor quality error message' do + let(:face_error_message) { 'Liveness: PoorQuality' } + it 'returns false' do + expect(subject.selfie_quality_good?).to eq(false) + end + end + end +end From 815802d19ce61a370f650d5e96069f38d63b231b Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 15:35:36 -0500 Subject: [PATCH 18/30] Re-add accidentally deleted return value --- app/presenters/image_upload_response_presenter.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/presenters/image_upload_response_presenter.rb b/app/presenters/image_upload_response_presenter.rb index 5412fe5edae..56317d9549c 100644 --- a/app/presenters/image_upload_response_presenter.rb +++ b/app/presenters/image_upload_response_presenter.rb @@ -56,6 +56,7 @@ def as_json(*) json[:result_failed] = doc_auth_result_failed? json[:doc_type_supported] = doc_type_supported? json[:failed_image_fingerprints] = failed_fingerprints + json end end From d153145d57b3511719a019f959b53f835023156b Mon Sep 17 00:00:00 2001 From: charleyf Date: Mon, 22 Jan 2024 15:37:52 -0500 Subject: [PATCH 19/30] Fix upload presenter tests --- .../image_upload_response_presenter_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/presenters/image_upload_response_presenter_spec.rb b/spec/presenters/image_upload_response_presenter_spec.rb index 03e81f90681..ae73ad2ab2a 100644 --- a/spec/presenters/image_upload_response_presenter_spec.rb +++ b/spec/presenters/image_upload_response_presenter_spec.rb @@ -130,6 +130,8 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: ['12345'] }, } @@ -152,6 +154,8 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: ['12345'] }, } @@ -181,6 +185,8 @@ remaining_attempts: 3, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -208,6 +214,8 @@ remaining_attempts: 3, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { front: [], back: [] }, } @@ -245,6 +253,8 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { front: [], back: [] }, } @@ -262,6 +272,8 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -290,6 +302,8 @@ remaining_attempts: 3, ocr_pii: Idp::Constants::MOCK_IDV_APPLICANT.slice(:first_name, :last_name, :dob), doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -316,6 +330,8 @@ remaining_attempts: 3, ocr_pii: Idp::Constants::MOCK_IDV_APPLICANT.slice(:first_name, :last_name, :dob), doc_type_supported: true, + selfie_live: true, + selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } From 6a3ef4fff3b9ea1c82aa9a376f60177491de1313 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 09:57:16 -0500 Subject: [PATCH 20/30] Get tests passing --- app/services/doc_auth/selfie_concern.rb | 2 ++ .../idv/image_uploads_controller_spec.rb | 18 ++++++++++++++++++ .../responses/get_results_response_spec.rb | 6 ++++++ .../responses/true_id_response_spec.rb | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index cad3362fd8f..f369698397e 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -2,11 +2,13 @@ module DocAuth module SelfieConcern extend ActiveSupport::Concern def selfie_live? + portrait_match_results ||= {} portait_error = get_portrait_error(portrait_match_results) return portait_error != 'Liveness: NotLive' end def selfie_quality_good? + portrait_match_results ||= {} portait_error = get_portrait_error(portrait_match_results) return portait_error != 'Liveness: PoorQuality' end diff --git a/spec/controllers/idv/image_uploads_controller_spec.rb b/spec/controllers/idv/image_uploads_controller_spec.rb index d762b5fc16e..00dde28d49f 100644 --- a/spec/controllers/idv/image_uploads_controller_spec.rb +++ b/spec/controllers/idv/image_uploads_controller_spec.rb @@ -203,6 +203,8 @@ ocr_pii: nil, doc_type_supported: true, failed_image_fingerprints: { front: [], back: [] }, + selfie_live: true, + selfie_quality_good: true, }, ) end @@ -219,6 +221,8 @@ ocr_pii: nil, doc_type_supported: true, failed_image_fingerprints: { front: [], back: [] }, + selfie_live: true, + selfie_quality_good: true, } end @@ -436,6 +440,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) expect(@analytics).to receive(:track_event).with( @@ -614,6 +620,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) expect(@analytics).to receive(:track_event).with( @@ -705,6 +713,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) expect(@analytics).to receive(:track_event).with( @@ -796,6 +806,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) expect(@analytics).to receive(:track_event).with( @@ -884,6 +896,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) expect(@analytics).to receive(:track_event).with( @@ -997,6 +1011,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) action @@ -1069,6 +1085,8 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) action diff --git a/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb b/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb index 29e071d13a3..66890bdf77c 100644 --- a/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb +++ b/spec/services/doc_auth/acuant/responses/get_results_response_spec.rb @@ -64,6 +64,8 @@ doc_type_supported: true, doc_auth_success: true, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, } processed_alerts = response_hash[:processed_alerts] @@ -422,6 +424,8 @@ doc_type_supported: false, doc_auth_success: true, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, } processed_alerts = response_hash[:processed_alerts] @@ -505,6 +509,8 @@ doc_type_supported: false, doc_auth_success: true, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, } expect(response_hash).to match(expected_hash) diff --git a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb index 838d010d97b..178d7f5e5aa 100644 --- a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb +++ b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb @@ -148,6 +148,8 @@ }, doc_auth_success: true, selfie_success: nil, + selfie_live: true, + selfie_quality_good: true, ) passed_alerts = response_hash.dig(:processed_alerts, :passed) passed_alerts.each do |alert| @@ -389,6 +391,8 @@ def get_decision_product(resp) }, doc_auth_success: false, selfie_success: false, + selfie_live: true, + selfie_quality_good: false, ) end it 'produces appropriate errors with document tampering' do From 343a2db54269e956edd290ecfcc814a0508e50bf Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 09:58:47 -0500 Subject: [PATCH 21/30] Fix string for success error message --- app/services/doc_auth/error_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index a1fe9604d11..de6c49cc24f 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -221,7 +221,7 @@ def get_selfie_error(liveness_enabled, response_info) case face_match_error # Error when the image on the id does not match the selfie image, but the image was acceptable - when "FaceErrorMessage: 'Successful. Liveness: Live'" + when 'Successful. Liveness: Live' return Errors::SELFIE_FAILURE # Error when the image on the id is poor quality when 'Liveness: PoorQuality' From 05f274f85df7de07a3250f4981aa902003568b79 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 10:32:05 -0500 Subject: [PATCH 22/30] Update presenter to only send selfie fail info if it's relevant --- app/forms/idv/api_image_upload_form.rb | 1 + .../image_upload_response_presenter.rb | 10 +++++++--- .../image_upload_response_presenter_spec.rb | 16 ---------------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/app/forms/idv/api_image_upload_form.rb b/app/forms/idv/api_image_upload_form.rb index 2eb3c2536d2..1013d36387d 100644 --- a/app/forms/idv/api_image_upload_form.rb +++ b/app/forms/idv/api_image_upload_form.rb @@ -154,6 +154,7 @@ def extra_attributes @extra_attributes[:front_image_fingerprint] = front_image_fingerprint @extra_attributes[:back_image_fingerprint] = back_image_fingerprint + @extra_attributes[:liveness_checking_required] = liveness_checking_required @extra_attributes end diff --git a/app/presenters/image_upload_response_presenter.rb b/app/presenters/image_upload_response_presenter.rb index 56317d9549c..cc1b8d9f7ca 100644 --- a/app/presenters/image_upload_response_presenter.rb +++ b/app/presenters/image_upload_response_presenter.rb @@ -41,9 +41,7 @@ def as_json(*) json = { success: false, errors: errors, remaining_attempts: remaining_attempts, - doc_type_supported: doc_type_supported?, - selfie_live: selfie_live?, - selfie_quality_good: selfie_quality_good? } + doc_type_supported: doc_type_supported? } if remaining_attempts&.zero? if @form_response.extra[:flow_path] == 'standard' json[:redirect] = idv_session_errors_rate_limited_url @@ -55,6 +53,8 @@ def as_json(*) json[:ocr_pii] = ocr_pii json[:result_failed] = doc_auth_result_failed? json[:doc_type_supported] = doc_type_supported? + json[:selfie_live] = selfie_live? if show_selfie_failures + json[:selfie_quality_good] = selfie_quality_good? if show_selfie_failures json[:failed_image_fingerprints] = failed_fingerprints json end @@ -92,6 +92,10 @@ def failed_fingerprints @form_response.extra[:failed_image_fingerprints] || { front: [], back: [] } end + def show_selfie_failures + @form_response.extra[:liveness_checking_required] == true + end + def selfie_live? @form_response.respond_to?(:selfie_live?) ? @form_response.selfie_live? : true end diff --git a/spec/presenters/image_upload_response_presenter_spec.rb b/spec/presenters/image_upload_response_presenter_spec.rb index ae73ad2ab2a..03e81f90681 100644 --- a/spec/presenters/image_upload_response_presenter_spec.rb +++ b/spec/presenters/image_upload_response_presenter_spec.rb @@ -130,8 +130,6 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: ['12345'] }, } @@ -154,8 +152,6 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: ['12345'] }, } @@ -185,8 +181,6 @@ remaining_attempts: 3, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -214,8 +208,6 @@ remaining_attempts: 3, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { front: [], back: [] }, } @@ -253,8 +245,6 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { front: [], back: [] }, } @@ -272,8 +262,6 @@ remaining_attempts: 0, ocr_pii: nil, doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -302,8 +290,6 @@ remaining_attempts: 3, ocr_pii: Idp::Constants::MOCK_IDV_APPLICANT.slice(:first_name, :last_name, :dob), doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } @@ -330,8 +316,6 @@ remaining_attempts: 3, ocr_pii: Idp::Constants::MOCK_IDV_APPLICANT.slice(:first_name, :last_name, :dob), doc_type_supported: true, - selfie_live: true, - selfie_quality_good: true, failed_image_fingerprints: { back: [], front: [] }, } From f3dc0b2fb918f9e96349f075453cbeb3b5f181aa Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 10:52:59 -0500 Subject: [PATCH 23/30] Fix test with new response params --- spec/forms/idv/api_image_upload_form_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/forms/idv/api_image_upload_form_spec.rb b/spec/forms/idv/api_image_upload_form_spec.rb index 3316727a368..c7f1e1006b7 100644 --- a/spec/forms/idv/api_image_upload_form_spec.rb +++ b/spec/forms/idv/api_image_upload_form_spec.rb @@ -124,6 +124,7 @@ flow_path: anything, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(fake_analytics).to have_logged_event( @@ -159,6 +160,9 @@ front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), doc_type_supported: boolean, + liveness_checking_required: boolean, + selfie_live: boolean, + selfie_quality_good: boolean, doc_auth_success: boolean, selfie_success: anything, ) @@ -222,6 +226,7 @@ flow_path: anything, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) end @@ -354,6 +359,7 @@ flow_path: anything, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, side: 'both', ) end From eeca6563ae9bec3d5b14bd3262f5235586f6ec79 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 11:03:33 -0500 Subject: [PATCH 24/30] Fix selfie concern tests --- app/services/doc_auth/selfie_concern.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index f369698397e..cad3362fd8f 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -2,13 +2,11 @@ module DocAuth module SelfieConcern extend ActiveSupport::Concern def selfie_live? - portrait_match_results ||= {} portait_error = get_portrait_error(portrait_match_results) return portait_error != 'Liveness: NotLive' end def selfie_quality_good? - portrait_match_results ||= {} portait_error = get_portrait_error(portrait_match_results) return portait_error != 'Liveness: PoorQuality' end From 0870619dc04ba62954c5885f703467b0300cdc07 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 11:05:47 -0500 Subject: [PATCH 25/30] Fix acuant api tests --- .../doc_auth/acuant/responses/get_results_response.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/services/doc_auth/acuant/responses/get_results_response.rb b/app/services/doc_auth/acuant/responses/get_results_response.rb index 2cbbb5a0b7e..e6b64f3ebaf 100644 --- a/app/services/doc_auth/acuant/responses/get_results_response.rb +++ b/app/services/doc_auth/acuant/responses/get_results_response.rb @@ -145,6 +145,11 @@ def passed_result? result_code == DocAuth::Acuant::ResultCodes::PASSED end + # This is not implemented for the acuant call since that is currently not in use + def portrait_match_results + return {} + end + def get_image_side_name(side_number) side_number == 0 ? :front : :back end From 453cdc4f79372335a58e3fe9513543f73ebd8c47 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 11:49:11 -0500 Subject: [PATCH 26/30] Fix tests --- .../idv/image_uploads_controller_spec.rb | 33 ++++++++++++++----- spec/features/idv/analytics_spec.rb | 18 +++++----- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/spec/controllers/idv/image_uploads_controller_spec.rb b/spec/controllers/idv/image_uploads_controller_spec.rb index 00dde28d49f..cc6bed5f6c1 100644 --- a/spec/controllers/idv/image_uploads_controller_spec.rb +++ b/spec/controllers/idv/image_uploads_controller_spec.rb @@ -132,6 +132,7 @@ flow_path: 'standard', front_image_fingerprint: nil, back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@irs_attempts_api_tracker).to receive(:track_event).with( @@ -203,8 +204,6 @@ ocr_pii: nil, doc_type_supported: true, failed_image_fingerprints: { front: [], back: [] }, - selfie_live: true, - selfie_quality_good: true, }, ) end @@ -221,8 +220,6 @@ ocr_pii: nil, doc_type_supported: true, failed_image_fingerprints: { front: [], back: [] }, - selfie_live: true, - selfie_quality_good: true, } end @@ -270,6 +267,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@irs_attempts_api_tracker).to receive(:track_event).with( @@ -412,6 +410,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -440,8 +439,9 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, - selfie_live: true, - selfie_quality_good: true, + liveness_checking_required: boolean, + selfie_live: boolean, + selfie_quality_good: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -456,6 +456,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, classification_info: a_kind_of(Hash), ) @@ -592,6 +593,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -620,6 +622,7 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + liveness_checking_required: boolean, selfie_live: true, selfie_quality_good: true, ) @@ -641,6 +644,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, classification_info: hash_including( Front: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'), Back: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'), @@ -685,6 +689,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -713,6 +718,7 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + liveness_checking_required: boolean, selfie_live: true, selfie_quality_good: true, ) @@ -734,6 +740,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, classification_info: hash_including( Front: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'), Back: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'), @@ -778,6 +785,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -806,6 +814,7 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + liveness_checking_required: boolean, selfie_live: true, selfie_quality_good: true, ) @@ -827,6 +836,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, classification_info: hash_including(:Front, :Back), ) @@ -868,6 +878,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -896,6 +907,7 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, + liveness_checking_required: boolean, selfie_live: true, selfie_quality_good: true, ) @@ -917,6 +929,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, classification_info: hash_including(:Front, :Back), ) @@ -981,6 +994,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -1010,6 +1024,7 @@ back_image_fingerprint: an_instance_of(String), doc_type_supported: boolean, doc_auth_success: boolean, + liveness_checking_required: boolean, selfie_success: nil, selfie_live: true, selfie_quality_good: true, @@ -1053,6 +1068,7 @@ flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), + liveness_checking_required: boolean, ) expect(@analytics).to receive(:track_event).with( @@ -1085,8 +1101,9 @@ doc_type_supported: boolean, doc_auth_success: boolean, selfie_success: nil, - selfie_live: true, - selfie_quality_good: true, + liveness_checking_required: boolean, + selfie_live: boolean, + selfie_quality_good: boolean, ) action diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index 81b09b4dc22..a551fe2c066 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -69,10 +69,10 @@ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil }, 'IdV: doc auth image upload form submitted' => { - success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String) + success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean }, 'IdV: doc auth image upload vendor pii validation' => { - success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), classification_info: {} + success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {} }, 'IdV: doc auth document_capture submitted' => { success: true, errors: {}, flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, acuant_sdk_upgrade_ab_test_bucket: :default, lexisnexis_instant_verify_workflow_ab_test_bucket: :default, analytics_id: 'Doc Auth', skip_hybrid_handoff: nil, irs_reproofing: false @@ -177,10 +177,10 @@ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'hybrid', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil }, 'IdV: doc auth image upload form submitted' => { - success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'hybrid', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String) + success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'hybrid', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean }, 'IdV: doc auth image upload vendor pii validation' => { - success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'hybrid', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), classification_info: {} + success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'hybrid', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {} }, 'IdV: doc auth document_capture submitted' => { success: true, errors: {}, flow_path: 'hybrid', step: 'document_capture', acuant_sdk_upgrade_ab_test_bucket: :default, lexisnexis_instant_verify_workflow_ab_test_bucket: :default, analytics_id: 'Doc Auth', irs_reproofing: false @@ -282,10 +282,10 @@ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil }, 'IdV: doc auth image upload form submitted' => { - success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String) + success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean }, 'IdV: doc auth image upload vendor pii validation' => { - success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), classification_info: {} + success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {} }, 'IdV: doc auth document_capture submitted' => { success: true, errors: {}, flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, acuant_sdk_upgrade_ab_test_bucket: :default, lexisnexis_instant_verify_workflow_ab_test_bucket: :default, skip_hybrid_handoff: nil, analytics_id: 'Doc Auth', irs_reproofing: false @@ -369,7 +369,7 @@ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil }, 'IdV: doc auth image upload form submitted' => { - success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String) + success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean }, 'IdV: doc auth image upload vendor submitted' => hash_including(success: true, flow_path: 'standard', attention_with_barcode: true, doc_auth_result: 'Attention'), 'IdV: verify in person troubleshooting option clicked' => { @@ -500,10 +500,10 @@ width: 284, height: 38, mimeType: 'image/png', source: 'upload', size: 3694, attempt: 1, flow_path: 'standard', acuant_sdk_upgrade_a_b_testing_enabled: 'false', use_alternate_sdk: anything, acuant_version: anything, acuantCaptureMode: nil, fingerprint: anything, failedImageResubmission: boolean, documentType: nil, dpi: nil, glare: nil, glareScoreThreshold: nil, isAssessedAsBlurry: nil, isAssessedAsGlare: nil, isAssessedAsUnsupported: nil, moire: nil, sharpness: nil, sharpnessScoreThreshold: nil, assessment: nil }, 'IdV: doc auth image upload form submitted' => { - success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String) + success: true, errors: {}, attempts: 1, remaining_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean }, 'IdV: doc auth image upload vendor pii validation' => { - success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), classification_info: {} + success: true, errors: {}, user_id: user.uuid, attempts: 1, remaining_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {} }, 'IdV: doc auth document_capture submitted' => { success: true, errors: {}, flow_path: 'standard', step: 'document_capture', redo_document_capture: nil, skip_hybrid_handoff: nil, acuant_sdk_upgrade_ab_test_bucket: :default, lexisnexis_instant_verify_workflow_ab_test_bucket: :default, analytics_id: 'Doc Auth', irs_reproofing: false From b86e5f89d2d371c48673318dd7447ba5531c0c27 Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 14:31:12 -0500 Subject: [PATCH 27/30] Centralize facematcherror text comparisons into the concern --- app/services/doc_auth/error_generator.rb | 15 ++++++++------- app/services/doc_auth/selfie_concern.rb | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/app/services/doc_auth/error_generator.rb b/app/services/doc_auth/error_generator.rb index de6c49cc24f..5b931b3324c 100644 --- a/app/services/doc_auth/error_generator.rb +++ b/app/services/doc_auth/error_generator.rb @@ -2,6 +2,7 @@ module DocAuth class ErrorGenerator + include SelfieConcern attr_reader :config def initialize(config) @@ -219,20 +220,20 @@ def get_selfie_error(liveness_enabled, response_info) return nil end - case face_match_error # Error when the image on the id does not match the selfie image, but the image was acceptable - when 'Successful. Liveness: Live' + if error_is_success(face_match_error) return Errors::SELFIE_FAILURE + end # Error when the image on the id is poor quality - when 'Liveness: PoorQuality' + if error_is_poor_quality(face_match_error) return Errors::SELFIE_POOR_QUALITY + end # Error when the image on the id is not live - when 'Liveness: NotLive' + if error_is_not_live(face_match_error) return Errors::SELFIE_NOT_LIVE - # Fallback, we don't expect this to happen - else - return Errors::SELFIE_FAILURE end + # Fallback, we don't expect this to happen + return Errors::SELFIE_FAILURE end def scan_for_unknown_alerts(response_info) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index cad3362fd8f..d19dc544c47 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -3,16 +3,36 @@ module SelfieConcern extend ActiveSupport::Concern def selfie_live? portait_error = get_portrait_error(portrait_match_results) - return portait_error != 'Liveness: NotLive' + return true if portait_error.empty? + return error_is_not_live(portait_error) end def selfie_quality_good? portait_error = get_portrait_error(portrait_match_results) - return portait_error != 'Liveness: PoorQuality' + return true if portait_error.empty? + return error_is_poor_quality(portait_error) + end + + def error_is_success(error_message) + return error_message == ERROR_TEXTS['success'] + end + + def error_is_not_live(error_message) + return error_message == ERROR_TEXTS['not_live'] + end + + def error_is_poor_quality(error_message) + return error_message == ERROR_TEXTS['poor_quality'] end private + ERROR_TEXTS = { + success: 'Successful. Liveness: Live', + not_live: 'Liveness: NotLive', + poor_quality: 'Liveness: PoorQuality', + } + # @param [Object] portrait_match_results trueid portait match info def get_portrait_error(portrait_match_results) portrait_match_results&.with_indifferent_access&.dig(:FaceErrorMessage) From a563e82f3bf37543bf02c4b2f573b261f93c54bc Mon Sep 17 00:00:00 2001 From: charleyf Date: Tue, 23 Jan 2024 14:50:43 -0500 Subject: [PATCH 28/30] Fix testing problem --- app/services/doc_auth/selfie_concern.rb | 4 ++-- .../doc_auth/lexis_nexis/responses/true_id_response_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index d19dc544c47..69f901a2fdc 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -3,13 +3,13 @@ module SelfieConcern extend ActiveSupport::Concern def selfie_live? portait_error = get_portrait_error(portrait_match_results) - return true if portait_error.empty? + return true if portait_error.nil? || portait_error.empty? return error_is_not_live(portait_error) end def selfie_quality_good? portait_error = get_portrait_error(portrait_match_results) - return true if portait_error.empty? + return true if portait_error.nil? || portait_error.empty? return error_is_poor_quality(portait_error) end diff --git a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb index 7aa64c144c7..89deea017de 100644 --- a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb +++ b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb @@ -378,7 +378,7 @@ def get_decision_product(resp) }, doc_auth_success: false, selfie_success: false, - selfie_live: true, + selfie_live: false, selfie_quality_good: false, ) end From 30aab53fe81eec043a3bb8e39b6ce32d742bf000 Mon Sep 17 00:00:00 2001 From: charleyf Date: Wed, 24 Jan 2024 14:52:45 -0500 Subject: [PATCH 29/30] Use `blank` instead of `empty` --- app/services/doc_auth/selfie_concern.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index 69f901a2fdc..72225538e3f 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -3,13 +3,13 @@ module SelfieConcern extend ActiveSupport::Concern def selfie_live? portait_error = get_portrait_error(portrait_match_results) - return true if portait_error.nil? || portait_error.empty? + return true if portait_error.nil? || portait_error.blank? return error_is_not_live(portait_error) end def selfie_quality_good? portait_error = get_portrait_error(portrait_match_results) - return true if portait_error.nil? || portait_error.empty? + return true if portait_error.nil? || portait_error.blank? return error_is_poor_quality(portait_error) end From 94aa1d672c375a9e66f06cb9ea3050f2e1c62041 Mon Sep 17 00:00:00 2001 From: charleyf Date: Wed, 24 Jan 2024 15:21:50 -0500 Subject: [PATCH 30/30] Fix two bugs that compounded each other --- app/services/doc_auth/selfie_concern.rb | 6 +++--- .../responses/true_id_response_spec.rb | 2 +- spec/services/doc_auth/selfie_concern_spec.rb | 18 ++++++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/services/doc_auth/selfie_concern.rb b/app/services/doc_auth/selfie_concern.rb index 72225538e3f..43f29dec079 100644 --- a/app/services/doc_auth/selfie_concern.rb +++ b/app/services/doc_auth/selfie_concern.rb @@ -14,15 +14,15 @@ def selfie_quality_good? end def error_is_success(error_message) - return error_message == ERROR_TEXTS['success'] + return error_message != ERROR_TEXTS[:success] end def error_is_not_live(error_message) - return error_message == ERROR_TEXTS['not_live'] + return error_message != ERROR_TEXTS[:not_live] end def error_is_poor_quality(error_message) - return error_message == ERROR_TEXTS['poor_quality'] + return error_message != ERROR_TEXTS[:poor_quality] end private diff --git a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb index 89deea017de..7aa64c144c7 100644 --- a/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb +++ b/spec/services/doc_auth/lexis_nexis/responses/true_id_response_spec.rb @@ -378,7 +378,7 @@ def get_decision_product(resp) }, doc_auth_success: false, selfie_success: false, - selfie_live: false, + selfie_live: true, selfie_quality_good: false, ) end diff --git a/spec/services/doc_auth/selfie_concern_spec.rb b/spec/services/doc_auth/selfie_concern_spec.rb index ada2618a17a..8516c2e9587 100644 --- a/spec/services/doc_auth/selfie_concern_spec.rb +++ b/spec/services/doc_auth/selfie_concern_spec.rb @@ -19,7 +19,14 @@ def initialize(portrait_match_results) end describe '#selfie_live?' do - context 'no liveness error message' do + context 'no error message' do + it 'returns true' do + expect(subject.selfie_live?).to eq(true) + end + end + + context 'an error message other than liveness' do + let(:face_error_message) { 'Another error message' } it 'returns true' do expect(subject.selfie_live?).to eq(true) end @@ -34,12 +41,19 @@ def initialize(portrait_match_results) end describe '#selfie_quality_good?' do - context 'no liveness error message' do + context 'no error message' do it 'returns true' do expect(subject.selfie_quality_good?).to eq(true) end end + context 'an error message other than quality' do + let(:face_error_message) { 'Another error message' } + it 'returns true' do + expect(subject.selfie_live?).to eq(true) + end + end + context 'a poor quality error message' do let(:face_error_message) { 'Liveness: PoorQuality' } it 'returns false' do