Skip to content

Commit

Permalink
Merge pull request #11436 from 18F/stages/rc-2024-10-31
Browse files Browse the repository at this point in the history
Deploy RC 427 to Production
  • Loading branch information
solipet authored Oct 31, 2024
2 parents 34fe0d9 + 268e1c2 commit 31cd191
Show file tree
Hide file tree
Showing 16 changed files with 655 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ GEM
actionpack (>= 5.0)
railties (>= 5.0)
retries (0.0.5)
rexml (3.3.7)
rexml (3.3.9)
rotp (6.3.0)
rouge (4.2.0)
rqrcode (2.1.0)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/idv/phone_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def frontend_request?
end

def verify_step_request?
request.referer == idv_verify_info_url
[idv_verify_info_url, idv_in_person_verify_info_url].include?(request.referer)
end

def should_keep_flash_success?
Expand Down
56 changes: 51 additions & 5 deletions app/controllers/socure_webhook_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ class SocureWebhookController < ApplicationController
before_action :check_socure_event

def create
log_webhook_receipt
render json: { message: 'Secret token is valid.' }
begin
log_webhook_receipt
process_webhook_event
rescue StandardError => e
NewRelic::Agent.notice_error(e)
ensure
render json: { message: 'Secret token is valid.' }, status: :ok
end
end

private

def fetch_results
dcs = document_capture_session
raise 'DocumentCaptureSession not found' if dcs.blank?

SocureDocvResultsJob.perform_later(document_capture_session_uuid: dcs.uuid)
end

def check_token
if !token_valid?
render status: :unauthorized, json: { message: 'Invalid secret token.' }
Expand Down Expand Up @@ -52,8 +65,6 @@ def verify_queue(authorization_header:)
end

def log_webhook_receipt
event = socure_params[:event]

analytics.idv_doc_auth_socure_webhook_received(
created_at: event[:created],
customer_user_id: event[:customerUserId],
Expand All @@ -63,7 +74,42 @@ 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!
end
# Logic to throw an error when no DocumentCaptureSession found will be done in ticket LG-14905
end

def document_capture_session
@document_capture_session ||= DocumentCaptureSession.find_by(
socure_docv_transaction_token: event[:docvTransactionToken],
)
end

def event
@event ||= socure_params[:event]
end

def rate_limiter
@rate_limiter ||= RateLimiter.new(
user: document_capture_session.user,
rate_limit_type: :idv_doc_auth,
)
end

def socure_params
params.permit(event: [:created, :customerUserId, :eventType, :referenceId])
params.permit(
event: [:created, :customerUserId, :eventType, :referenceId,
:docvTransactionToken],
)
end
end
9 changes: 2 additions & 7 deletions app/jobs/reports/protocols_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@ class ProtocolsReport < BaseReport

attr_accessor :report_date

def initialize(report_date = nil, *args, **rest)
@report_date = report_date
super(*args, **rest)
end

def perform(report_date)
def perform(date = Time.zone.yesterday.end_of_day)
return unless IdentityConfig.store.s3_reports_enabled

self.report_date = report_date
@report_date = date
message = "Report: #{REPORT_NAME} #{report_date}"
subject = "Weekly Protocols Report - #{report_date}"

Expand Down
43 changes: 43 additions & 0 deletions app/jobs/socure_docv_results_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

class SocureDocvResultsJob < ApplicationJob
queue_as :default

attr_reader :document_capture_session_uuid

# @param [String] document_capture_session_uuid
def perform(document_capture_session_uuid:)
@document_capture_session_uuid = document_capture_session_uuid

dcs = DocumentCaptureSession.find_by(uuid: document_capture_session_uuid)
raise "DocumentCaptureSession not found: #{document_capture_session_uuid}" if !dcs

# analytics = create_analytics(
# user: dcs.user,
# service_provider_issuer: dcs.issuer,
# )

result = socure_document_verification_result
dcs.store_result_from_response(result)
end

private

def create_analytics(
user:,
service_provider_issuer:
)
Analytics.new(
user:,
request: nil,
sp: service_provider_issuer,
session: {},
)
end

def socure_document_verification_result
DocAuth::Socure::Requests::DocvResultRequest.new(
document_capture_session_uuid:,
).fetch
end
end
52 changes: 52 additions & 0 deletions app/services/doc_auth/socure/requests/docv_result_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

module DocAuth
module Socure
module Requests
class DocvResultRequest < DocAuth::Socure::Request
attr_reader :document_capture_session_uuid, :biometric_comparison_required

def initialize(document_capture_session_uuid:, biometric_comparison_required: false)
@document_capture_session_uuid = document_capture_session_uuid
@biometric_comparison_required = biometric_comparison_required
end

private

def body
{
modules: ['documentverification'],
docvTransactionToken: document_capture_session.socure_docv_transaction_token,
}.to_json
end

def handle_http_response(http_response)
DocAuth::Socure::Responses::DocvResultResponse.new(
http_response: http_response,
biometric_comparison_required: biometric_comparison_required,
)
end

def document_capture_session
@document_capture_session ||=
DocumentCaptureSession.find_by!(uuid: document_capture_session_uuid)
end

def method
:post
end

def endpoint
@endpoint ||= URI.join(
IdentityConfig.store.socure_idplus_base_url,
'/api/3.0/EmailAuthScore',
).to_s
end

def metric_name
'socure_id_plus_document_verification'
end
end
end
end
end
133 changes: 133 additions & 0 deletions app/services/doc_auth/socure/responses/docv_result_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# frozen_string_literal: true

module DocAuth
module Socure
module Responses
class DocvResultResponse < DocAuth::Response
attr_reader :http_response, :biometric_comparison_required

DATA_PATHS = {
reference_id: %w[referenceId],
document_verification: %w[documentVerification],
reason_codes: %w[documentVerification reasonCodes],
document_type: %w[documentVerification documentType],
id_type: %w[documentVerification documentType type],
issuing_state: %w[documentVerification documentType state],
issuing_country: %w[documentVerification documentType country],
decision: %w[documentVerification decision],
decision_name: %w[documentVerification decision name],
decision_value: %w[documentVerification decision value],
document_data: %w[documentVerification documentData],
first_name: %w[documentVerification documentData firstName],
middle_name: %w[documentVerification documentData middleName],
last_name: %w[documentVerification documentData surName],
address1: %w[documentVerification documentData parsedAddress physicalAddress],
address2: %w[documentVerification documentData parsedAddress physicalAddress2],
city: %w[documentVerification documentData parsedAddress city],
state: %w[documentVerification documentData parsedAddress state],
zipcode: %w[documentVerification documentData parsedAddress zip],
dob: %w[documentVerification documentData dob],
document_number: %w[documentVerification documentData documentNumber],
issue_date: %w[documentVerification documentData issueDate],
expiration_date: %w[documentVerification documentData expirationDate],
}.freeze

def initialize(http_response: nil, biometric_comparison_required: false)
@http_response = http_response
@biometric_comparison_required = biometric_comparison_required
@pii_from_doc = read_pii

super(
success: successful_result?,
errors: error_messages,
extra: extra_attributes,
pii_from_doc: @pii_from_doc,
)
rescue StandardError => e
NewRelic::Agent.notice_error(e)
super(
success: false,
errors: { network: true },
exception: e,
extra: {
backtrace: e.backtrace,
},
)
end

def doc_auth_success?
success?
end

def selfie_status
:not_processed
end

private

def successful_result?
get_data(DATA_PATHS[:decision_value]) == 'accept'
end

def error_messages
return {} if successful_result?

{
reason_codes: get_data(DATA_PATHS[:reason_codes]),
}
end

def extra_attributes
{
reference_id: get_data(DATA_PATHS[:reference_id]),
decision: get_data(DATA_PATHS[:decision]),
biometric_comparison_required: biometric_comparison_required,
}
end

def read_pii
Pii::StateId.new(
first_name: get_data(DATA_PATHS[:first_name]),
middle_name: get_data(DATA_PATHS[:middle_name]),
last_name: get_data(DATA_PATHS[:last_name]),
address1: get_data(DATA_PATHS[:address1]),
address2: get_data(DATA_PATHS[:address2]),
city: get_data(DATA_PATHS[:city]),
state: get_data(DATA_PATHS[:state]),
zipcode: get_data(DATA_PATHS[:zipcode]),
dob: parse_date(get_data(DATA_PATHS[:dob])),
state_id_number: get_data(DATA_PATHS[:document_number]),
state_id_issued: parse_date(get_data(DATA_PATHS[:issue_date])),
state_id_expiration: parse_date(get_data(DATA_PATHS[:expiration_date])),
state_id_type: state_id_type,
state_id_jurisdiction: get_data(DATA_PATHS[:issuing_state]),
issuing_country_code: get_data(DATA_PATHS[:issuing_country]),
)
end

def get_data(path)
parsed_response_body.dig(*path)
end

def parsed_response_body
@parsed_response_body ||= JSON.parse(http_response.body).with_indifferent_access
end

def state_id_type
type = get_data(DATA_PATHS[:id_type])
type.gsub(/\W/, '').underscore
end

def parse_date(date_string)
Date.parse(date_string)
rescue ArgumentError
message = {
event: 'Failure to parse Socure ID+ date',
}.to_json
Rails.logger.info(message)
nil
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class IndexSocureDocVTransactionToken < ActiveRecord::Migration[7.2]
disable_ddl_transaction!
def up
add_index :document_capture_sessions, %i[socure_docv_transaction_token], name: "index_socure_docv_transaction_token", unique: true, algorithm: :concurrently
end
def down
remove_index :document_capture_sessions, %i[socure_docv_transaction_token]
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_10_23_191918) do
ActiveRecord::Schema[7.2].define(version: 2024_10_29_152408) do
# These are extensions that must be enabled in order to support this database
enable_extension "citext"
enable_extension "pg_stat_statements"
Expand Down Expand Up @@ -194,6 +194,7 @@
t.string "socure_docv_transaction_token", comment: "sensitive=false"
t.string "socure_docv_capture_app_url", comment: "sensitive=false"
t.index ["result_id"], name: "index_document_capture_sessions_on_result_id"
t.index ["socure_docv_transaction_token"], name: "index_socure_docv_transaction_token", unique: true
t.index ["user_id"], name: "index_document_capture_sessions_on_user_id"
t.index ["uuid"], name: "index_document_capture_sessions_on_uuid"
end
Expand Down
Loading

0 comments on commit 31cd191

Please sign in to comment.