Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
962e046
Add doc_auth_ssn_controller_enabled flag
soniaconnolly Jan 26, 2023
7838580
Initial SsnController, template, specs
soniaconnolly Jan 26, 2023
2cdf5f7
Pull common code into VerifyInfoConcern
soniaconnolly Jan 27, 2023
328dbea
Add IdvSession and stub user in specs
soniaconnolly Feb 1, 2023
221f6ac
Add pii_from_doc before action
soniaconnolly Feb 4, 2023
2999769
Add analytics to ssn_controller
soniaconnolly Feb 6, 2023
5c2752f
Add update and specs
soniaconnolly Feb 7, 2023
5022ed8
Rename verify_info_step_spec.rb to verify_info_spec.rb
soniaconnolly Feb 7, 2023
c319d38
Divert from document capture step to ssn controller
soniaconnolly Feb 7, 2023
89be067
Local params for :show
soniaconnolly Feb 8, 2023
dc1ae96
Show and update don't blow up
soniaconnolly Feb 8, 2023
37edc7e
Correct step_count key
soniaconnolly Feb 8, 2023
59a429b
Get ssn from correct form param, fix spec, update works
soniaconnolly Feb 8, 2023
5168368
Get SsnController#update tests working
soniaconnolly Feb 9, 2023
c9ed143
Add second feature spec
soniaconnolly Feb 9, 2023
cdc8b36
Add document_capture feature spec for new ssn controller redirect
soniaconnolly Feb 10, 2023
4d0e34d
Undo rename verify_info_step_spec.rb to avoid merge conflicts with ve…
soniaconnolly Feb 10, 2023
2a91e58
Add submitted analytics and redo action
soniaconnolly Feb 10, 2023
69ba274
Use get, not put, to edit SSN from verify_info
soniaconnolly Feb 10, 2023
53d4fb8
Add changelog
soniaconnolly Feb 10, 2023
0c02dd4
Update idv_session when ssn is updated
soniaconnolly Feb 10, 2023
acf2b8f
If no ssn in pii, VerifyInfo checks ssn feature flag
soniaconnolly Feb 10, 2023
cc94219
Merge branch 'main' into sonia-lg-8733-init-ssn-controller
jmhooper Feb 13, 2023
092a685
remove the old verify info contorller feature flag
jmhooper Feb 13, 2023
f0a4912
Merge branch 'main' into sonia-lg-8733-init-ssn-controller
jmhooper Feb 15, 2023
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
41 changes: 41 additions & 0 deletions app/controllers/concerns/idv/step_utilities_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module Idv
module StepUtilitiesConcern
extend ActiveSupport::Concern

def flow_session
user_session['idv/doc_auth']
end

# copied from doc_auth_controller
def flow_path
flow_session[:flow_path]
end

def confirm_pii_from_doc
@pii = flow_session['pii_from_doc'] # hash with indifferent access
return if @pii.present?
flow_session.delete('Idv::Steps::DocumentCaptureStep')
redirect_to idv_doc_auth_url
end

# Copied from capture_doc_flow.rb
# and from doc_auth_flow.rb
def acuant_sdk_ab_test_analytics_args
capture_session_uuid = flow_session[:document_capture_session_uuid]
if capture_session_uuid
{
acuant_sdk_upgrade_ab_test_bucket:
AbTests::ACUANT_SDK.bucket(capture_session_uuid),
Comment on lines +27 to +28
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.

style nit, I'd indent this for clarity

Suggested change
acuant_sdk_upgrade_ab_test_bucket:
AbTests::ACUANT_SDK.bucket(capture_session_uuid),
acuant_sdk_upgrade_ab_test_bucket:
AbTests::ACUANT_SDK.bucket(capture_session_uuid),

}
else
{}
end
end

def irs_reproofing?
effective_user&.decorate&.reproof_for_irs?(
service_provider: current_sp,
).present?
end
end
end
88 changes: 88 additions & 0 deletions app/controllers/idv/ssn_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
module Idv
class SsnController < ApplicationController
include IdvSession
include StepIndicatorConcern
include StepUtilitiesConcern
include Steps::ThreatMetrixStepHelper

before_action :render_404_if_ssn_controller_disabled
before_action :confirm_two_factor_authenticated
before_action :confirm_pii_from_doc

attr_accessor :error_message

def show
increment_step_counts

analytics.idv_doc_auth_redo_ssn_submitted(**analytics_arguments) if updating_ssn

analytics.idv_doc_auth_ssn_visited(**analytics_arguments)

render :show, locals: extra_view_variables
end

def update
@error_message = nil
form_response = form_submit

unless form_response.success?
@error_message = form_response.first_error_message
redirect_to idv_ssn_url
end

flow_session['pii_from_doc'][:ssn] = params[:doc_auth][:ssn]

analytics.idv_doc_auth_ssn_submitted(**analytics_arguments)

irs_attempts_api_tracker.idv_ssn_submitted(
ssn: params[:doc_auth][:ssn],
)

idv_session.ssn_updated!

redirect_to idv_verify_info_url
end

def extra_view_variables
{
updating_ssn: updating_ssn,
success_alert_enabled: !updating_ssn,
**threatmetrix_view_variables,
}
end

private

def render_404_if_ssn_controller_disabled
render_not_found unless IdentityConfig.store.doc_auth_ssn_controller_enabled
end

def analytics_arguments
{
flow_path: flow_path,
step: 'ssn',
step_count: current_flow_step_counts['Idv::Steps::SsnStep'],
analytics_id: 'Doc Auth',
irs_reproofing: irs_reproofing?,
}.merge(**acuant_sdk_ab_test_analytics_args)
end

def current_flow_step_counts
user_session['idv/doc_auth_flow_step_counts'] ||= {}
user_session['idv/doc_auth_flow_step_counts'].default = 0
user_session['idv/doc_auth_flow_step_counts']
end

def increment_step_counts
current_flow_step_counts['Idv::Steps::SsnStep'] += 1
end

def form_submit
Idv::SsnFormatForm.new(current_user).submit(params.require(:doc_auth).permit(:ssn))
end

def updating_ssn
flow_session.dig('pii_from_doc', :ssn).present?
end
end
end
36 changes: 6 additions & 30 deletions app/controllers/idv/verify_info_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Idv
class VerifyInfoController < ApplicationController
include IdvSession
include StepUtilitiesConcern

before_action :confirm_two_factor_authenticated
before_action :confirm_ssn_step_complete
Expand Down Expand Up @@ -73,21 +74,6 @@ def update

private

# copied from doc_auth_controller
def flow_session
user_session['idv/doc_auth']
end

def flow_path
flow_session[:flow_path]
end

def irs_reproofing?
effective_user&.decorate&.reproof_for_irs?(
service_provider: current_sp,
).present?
end

def analytics_arguments
{
flow_path: flow_path,
Expand All @@ -98,20 +84,6 @@ def analytics_arguments
}.merge(**acuant_sdk_ab_test_analytics_args)
end

# Copied from capture_doc_flow.rb
# and from doc_auth_flow.rb
def acuant_sdk_ab_test_analytics_args
capture_session_uuid = flow_session[:document_capture_session_uuid]
if capture_session_uuid
{
acuant_sdk_upgrade_ab_test_bucket:
AbTests::ACUANT_SDK.bucket(capture_session_uuid),
}
else
{}
end
end

# copied from verify_step
def pii
@pii = flow_session[:pii_from_doc] if flow_session
Expand All @@ -125,7 +97,11 @@ def delete_pii
# copied from address_controller
def confirm_ssn_step_complete
return if pii.present? && pii[:ssn].present?
redirect_to idv_doc_auth_url
if IdentityConfig.store.doc_auth_ssn_controller_enabled
redirect_to idv_ssn_url
else
redirect_to idv_doc_auth_url
end
end

def confirm_profile_not_already_confirmed
Expand Down
18 changes: 18 additions & 0 deletions app/services/idv/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ def user_phone_confirmation_session=(new_user_phone_confirmation_session)
session[:user_phone_confirmation_session] = new_user_phone_confirmation_session.to_h
end

def ssn_updated!
# Guard against unvalidated attributes from in-person flow in review controller
session[:applicant] = nil

invalidate_verify_info_step!
invalidate_phone_step!
end
Comment on lines +139 to +145
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.

to me, the name was confusing here compared to what the method does, WDYT about invalidate_steps_before_ssn!?

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.

I can change it to invalidate_steps_after_ssn!


def invalidate_verify_info_step!
session[:resolution_successful] = nil
session[:profile_confirmation] = nil
end

def invalidate_phone_step!
session[:vendor_phone_confirmation] = nil
session[:user_phone_confirmation] = nil
end

private

attr_accessor :user_session
Expand Down
7 changes: 7 additions & 0 deletions app/services/idv/steps/document_capture_step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def self.analytics_submitted_event

def call
handle_stored_result if !FeatureManagement.document_capture_async_uploads_enabled?

exit_flow_state_machine if IdentityConfig.store.doc_auth_ssn_controller_enabled
end

def extra_view_variables
Expand All @@ -38,6 +40,11 @@ def extra_view_variables

private

def exit_flow_state_machine
flow_session[:flow_path] = @flow.flow_path
redirect_to idv_ssn_url
end

def native_camera_ab_testing_variables
{
acuant_sdk_upgrade_ab_test_bucket:
Expand Down
91 changes: 91 additions & 0 deletions app/views/idv/ssn/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<%#
Renders a page asking the user to enter their SSN or update their SSN if they had previously entered it.

locals:
* success_alert_enabled: whether or not to display a "We've successfully verified your ID" success alert
* updating_ssn: true if the user is updating their SSN instead of providing it for the first time. This
will render a different page heading and different navigation buttons in the page footer
%>
<% content_for(:pre_flash_content) do %>
<%= render StepIndicatorComponent.new(
steps: Idv::Flows::DocAuthFlow::STEP_INDICATOR_STEPS,
current_step: :verify_info,
locale_scope: 'idv',
class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4',
) %>
<% end %>

<% title t('titles.doc_auth.ssn') %>

<% if success_alert_enabled %>
<%= render AlertComponent.new(
type: :success,
class: 'margin-bottom-4',
) do %>
<%= t('doc_auth.headings.capture_complete') %>
<% end %>
<% end %>

<% if updating_ssn %>
<%= render PageHeadingComponent.new.with_content(t('doc_auth.headings.ssn_update')) %>
<% else %>
<%= render PageHeadingComponent.new.with_content(t('doc_auth.headings.ssn')) %>
<% end %>

<p>
<%= t('doc_auth.info.ssn') %>
<%= new_window_link_to(t('doc_auth.instructions.learn_more'), MarketingSite.security_and_privacy_practices_url) %>
</p>

<% if FeatureManagement.proofing_device_profiling_collecting_enabled? %>
<% if threatmetrix_session_id.present? %>
<% threatmetrix_javascript_urls.each do |threatmetrix_javascript_url| %>
<%= javascript_include_tag threatmetrix_javascript_url, nonce: true %>
<% end %>
<noscript>
<%= content_tag(
:iframe,
'',
src: threatmetrix_iframe_url,
style: 'width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;',
) %>
</noscript>
<% end %>
<% end %>

<% if IdentityConfig.store.proofer_mock_fallback %>
<div class="usa-alert usa-alert--info margin-bottom-4" role="status">
<div class="usa-alert__body">
<p class="usa-alert__text">
<%= t('doc_auth.instructions.test_ssn') %>
</p>
</div>
</div>
<% end %>

<%= simple_form_for(
:doc_auth,
url: idv_ssn_url,
method: :put,
html: { autocomplete: 'off' },
) do |f| %>
<div class="tablet:grid-col-8">
<%= render 'shared/ssn_field', f: f %>
</div>

<p><%= @error_message %></p>

<%= f.submit class: 'display-block margin-y-5' do %>
<% if updating_ssn %>
<%= t('forms.buttons.submit.update') %>
<% else %>
<%= t('forms.buttons.continue') %>
<% end %>
<% end %>
<% end %>

<% if updating_ssn %>
<%= render 'idv/shared/back', action: 'cancel_update_ssn' %>
<% else %>
<%= render 'idv/doc_auth/cancel', step: 'ssn' %>
<% end %>
11 changes: 11 additions & 0 deletions app/views/idv/verify_info/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ locals:
toggle_label: t('forms.ssn.show'),
) %>
</div>
<% if IdentityConfig.store.doc_auth_ssn_controller_enabled %>
Comment on lines 104 to +105
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 would indent this whole block and line it up with the </div> above? If the worry was about diff noise, we can always suggest reviews hide whitespace

Suggested change
</div>
<% if IdentityConfig.store.doc_auth_ssn_controller_enabled %>
</div>
<% if IdentityConfig.store.doc_auth_ssn_controller_enabled %>

<div class='grid-auto'>
<%= button_to(
idv_ssn_url,
method: :get,
class: 'usa-button usa-button--unstyled',
'aria-label': t('idv.buttons.change_ssn_label'),
) { t('idv.buttons.change_label') } %>
</div>
<% else %>
<div class='grid-auto'>
<%= button_to(
idv_doc_auth_step_url(step: :redo_ssn),
Expand All @@ -110,6 +120,7 @@ locals:
'aria-label': t('idv.buttons.change_ssn_label'),
) { t('idv.buttons.change_label') } %>
</div>
<% end %>
</div>
<div class="margin-top-5">
<%= render SpinnerButtonComponent.new(
Expand Down
1 change: 1 addition & 0 deletions config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ country_phone_number_overrides: '{}'
doc_auth_error_dpi_threshold: 290
doc_auth_error_sharpness_threshold: 40
doc_auth_error_glare_threshold: 40
doc_auth_ssn_controller_enabled: false
database_pool_extra_connections_for_worker: 4
database_pool_idp: 5
database_statement_timeout: 2_500
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@
post '/forgot_password' => 'forgot_password#update'
get '/otp_delivery_method' => 'otp_delivery_method#new'
put '/otp_delivery_method' => 'otp_delivery_method#create'
get '/ssn' => 'ssn#show'
put '/ssn' => 'ssn#update'
get '/verify_info' => 'verify_info#show'
put '/verify_info' => 'verify_info#update'
get '/phone' => 'phone#new'
Expand Down
1 change: 1 addition & 0 deletions lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def self.build_store(config_map)
config.add(:doc_auth_max_submission_attempts_before_native_camera, type: :integer)
config.add(:doc_auth_max_capture_attempts_before_tips, type: :integer)
config.add(:doc_auth_s3_request_timeout, type: :integer)
config.add(:doc_auth_ssn_controller_enabled, type: :boolean)
config.add(:doc_auth_vendor, type: :string)
config.add(:doc_auth_vendor_randomize, type: :boolean)
config.add(:doc_auth_vendor_randomize_percent, type: :integer)
Expand Down
Loading