Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/forms/idv/doc_pii_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def submit

def self.pii_like_keypaths(document_type:)
keypaths = [[:pii]]
document_attrs = document_type&.downcase == 'passport' ?
document_attrs = document_type&.downcase&.include?('passport') ?
DocPiiPassport.pii_like_keypaths :
DocPiiStateId.pii_like_keypaths

Expand Down Expand Up @@ -106,7 +106,7 @@ def id_doc_type_valid?
when *STATE_ID_TYPES
state_id_validation = DocPiiStateId.new(pii: pii_from_doc)
state_id_validation.valid? || errors.merge!(state_id_validation.errors)
when 'passport'
when 'passport', 'passport_card'
passport_validation = DocPiiPassport.new(pii: pii_from_doc)
passport_validation.valid? || errors.merge!(passport_validation.errors)
else
Expand Down
19 changes: 14 additions & 5 deletions app/forms/idv/doc_pii_passport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class DocPiiPassport
in: 'USA', message: proc { I18n.t('doc_auth.errors.general.no_liveness') }
}

validate :passport_expired?
validate :passport_not_expired?
validate :passport_book? # we don't support passport cards

attr_reader :passport_expiration, :issuing_country_code, :mrz

Expand All @@ -35,10 +36,18 @@ def generic_error
I18n.t('doc_auth.errors.general.no_liveness')
end

def passport_expired?
if passport_expiration && DateParser.parse_legacy(passport_expiration).past?
errors.add(:passport_expiration, generic_error, type: :passport_expiration)
end
def passport_not_expired?
return true unless passport_expiration && DateParser.parse_legacy(passport_expiration).past?

errors.add(:passport_expiration, generic_error, type: :passport_expiration)
false
end

def passport_book?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found myself doing a double-take on this method name since it's checking for passport cards but named passport_book?. Would passport_card_not_supported? or validate_not_passport_card be clearer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to not_passport_book? in 9e55565

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, per Amir's comment, I changed it back to passport_book? but fail if id_doc_type is anything but 'passport' in 03a86f2

return true if pii_from_doc[:id_doc_type] == 'passport'

errors.add(:id_doc_type, generic_error, type: :id_doc_type)
false
end
end
end
27 changes: 23 additions & 4 deletions app/services/doc_auth/lexis_nexis/doc_pii_reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ def read_pii(true_id_product)
return nil unless id_auth_field_data.present?

id_doc_type_slug = id_auth_field_data['Fields_DocumentClassName']
@id_doc_type = IdentityConfig.store.doc_auth_passports_enabled ?
DocAuth::Response::ID_TYPE_SLUGS[id_doc_type_slug] :
DocAuth::Response::STATE_ID_TYPE_SLUGS[id_doc_type_slug]
id_doc_issue_type = authentication_result_field_data['DocIssueType']

@id_doc_type = determine_id_doc_type(
doc_class_name: id_doc_type_slug,
doc_issue_type: id_doc_issue_type,
)

if id_doc_type == 'drivers_license' || id_doc_type == 'state_id_card'
generate_state_id_pii
elsif id_doc_type == 'passport'
elsif id_doc_type == 'passport' || id_doc_type == 'passport_card'
generate_passport_pii
end
end
Expand Down Expand Up @@ -179,6 +182,22 @@ def generate_passport_pii
mrz: id_auth_field_data['Fields_MRZ'],
)
end

def determine_id_doc_type(doc_class_name:, doc_issue_type:)
val = if IdentityConfig.store.doc_auth_passports_enabled
DocAuth::Response::ID_TYPE_SLUGS[doc_class_name]
else
DocAuth::Response::STATE_ID_TYPE_SLUGS[doc_class_name]
end

# If the DocIssueType is 'Passport Card',
# LN is returning 'Identification Card' as the DocClassName so we need to differentiate
# between a passport card and a state-issued identification card.
if doc_issue_type == 'Passport Card'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about extracting this to a constant like PASSPORT_CARD_ISSUE_TYPE? Might help if we need to reference this LexisNexis value elsewhere or if it ever changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree - adding this to LG-16371

val = 'passport_card'
end
val
end
end
end
end
27 changes: 25 additions & 2 deletions app/services/doc_auth/lexis_nexis/responses/true_id_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def initialize(http_response, config, liveness_checking_enabled = false,
## returns full check success status, considering all checks:
# vendor (document and selfie if requested)
def successful_result?
return false if passport_detected_but_not_allowed?
return false if passport_card_detected?

doc_auth_success? &&
(@liveness_checking_enabled ? selfie_passed? : true)
end
Expand All @@ -55,7 +58,11 @@ def doc_auth_success?
def error_messages
return {} if successful_result?

if with_authentication_result?
if passport_detected_but_not_allowed?
{ passport: true }
elsif passport_card_detected?
{ passport_card: true }
elsif with_authentication_result?
ErrorGenerator.new(config).generate_doc_auth_errors(response_info)
elsif true_id_product.present?
ErrorGenerator.wrapped_general_error
Expand Down Expand Up @@ -122,7 +129,10 @@ def parsed_response_body
end

def passport_pii?
@passport_pii ||= pii_from_doc&.id_doc_type == 'passport'
@passport_pii ||= begin
pii_from_doc&.id_doc_type == 'passport' ||
pii_from_doc&.id_doc_type == 'passport_card'
end
end

def transaction_status
Expand Down Expand Up @@ -228,6 +238,19 @@ def doc_issuer_type
true_id_product&.dig(:AUTHENTICATION_RESULT, :DocIssuerType)
end

def doc_issue_type
true_id_product&.dig(:AUTHENTICATION_RESULT, :DocIssueType)
end

def passport_detected_but_not_allowed?
passport_detected = doc_class_name == 'Passport' || passport_card_detected?
!IdentityConfig.store.doc_auth_passports_enabled && passport_detected
end

def passport_card_detected?
doc_issue_type == 'Passport Card'
end

def classification_info
# Acuant response has both sides info, here simulate that
doc_class = doc_class_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocIssuerType",
"Values": [{ "Value": "StateProvince" }]
"Values": [{ "Value": "Country" }]
},
{
"Group": "AUTHENTICATION_RESULT",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
{
"Group": "AUTHENTICATION_RESULT",
"Name": "DocIssuerType",
"Values": [{ "Value": "StateProvince" }]
"Values": [{ "Value": "Country" }]
},
{
"Group": "AUTHENTICATION_RESULT",
Expand Down Expand Up @@ -1044,4 +1044,3 @@
}
]
}

Loading