diff --git a/.eslintrc b/.eslintrc
index 015b41f4bdf..0c776ec027a 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -18,8 +18,8 @@
"no-restricted-syntax": [
"error",
{
- "selector": "AssignmentExpression[left.property.name='href'][right.type=/(Template)?Literal/],NewExpression[callee.name=URL][arguments.0.type=/(Template)?Literal/]",
- "message": "Avoid hard-coded string URLs, since they will not include the current locale"
+ "selector": "AssignmentExpression[left.property.name='href'][right.type=/(Template)?Literal/]",
+ "message": "Do not assign window.location.href to a string or string template to avoid losing i18n parameters"
}
],
"react-hooks/exhaustive-deps": "error"
@@ -42,7 +42,6 @@
"packageDir": "."
}
],
- "no-restricted-syntax": "off",
"testing-library/await-async-events": "error",
"testing-library/await-async-queries": "error",
"testing-library/await-async-utils": "error",
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ed0580e2514..0e36154b270 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -67,7 +67,9 @@ stages:
workflow:
rules:
- - if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "external_pull_request_event" || $CI_PIPELINE_SOURCE == "schedule"'
+ - if: '$CI_PIPELINE_SOURCE == "schedule"'
+ when: never
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "external_pull_request_event"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "external_pull_request_event" || $CI_PIPELINE_SOURCE == "web"'
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "stages/prod"'
- if: '$CI_MERGE_REQUEST_IID || $CI_EXTERNAL_PULL_REQUEST_IID'
@@ -339,6 +341,30 @@ js_tests:
- *yarn_install
- yarn test
+pinpoint-check:
+ needs:
+ - job: install
+ stage: test
+ cache:
+ - <<: *ruby_cache
+ - <<: *yarn_cache
+ script:
+ - *bundle_install
+ - *yarn_install
+ - make lint_country_dialing_codes
+
+audit_packages:
+ needs:
+ - job: install
+ stage: test
+ cache:
+ - <<: *ruby_cache
+ - <<: *yarn_cache
+ script:
+ - *bundle_install
+ - *yarn_install
+ - make audit
+
prepare_deploy:
# Runs in parallel with tests so we can deploy more quickly after passing
stage: test
@@ -812,51 +838,3 @@ ecr-scan-ci:
stage: scan
variables:
ecr_repo: idp/ci
-
-pinpoint_check_scheduled:
- needs:
- - job: install
- cache:
- - <<: *ruby_cache
- - <<: *yarn_cache
- script:
- - *bundle_install
- - *yarn_install
- - make lint_country_dialing_codes
- after_script:
- - |-
- if [ "$CI_JOB_STATUS" != "success" ]; then
- ./scripts/notify-slack \
- --icon ":gitlab:" \
- --username "gitlab-notify" \
- --channel "#login-appdev" \
- --webhook "${SLACK_WEBHOOK}" \
- --raise \
- --text "Pinpoint supported countries check in GitLab failed.\nBuild Results: ${CI_JOB_URL}.\nCheck results locally with 'make lint_country_dialing_codes'"
- fi
- rules:
- - if: $CI_PIPELINE_SOURCE == "schedule"
-
-audit_packages_scheduled:
- needs:
- - job: install
- cache:
- - <<: *ruby_cache
- - <<: *yarn_cache
- script:
- - *bundle_install
- - *yarn_install
- - make audit
- after_script:
- - |-
- if [ "$CI_JOB_STATUS" != "success" ]; then
- ./scripts/notify-slack \
- --icon ":gitlab:" \
- --username "gitlab-notify" \
- --channel "#login-appdev" \
- --webhook "${SLACK_WEBHOOK}" \
- --raise \
- --text "Dependencies audit in GitLab failed.\nBuild Results: ${CI_JOB_URL}\nCheck results locally with 'make audit'"
- fi
- rules:
- - if: $CI_PIPELINE_SOURCE == "schedule"
diff --git a/app/controllers/concerns/idv/verify_by_mail_concern.rb b/app/controllers/concerns/idv/verify_by_mail_concern.rb
deleted file mode 100644
index 6907db67cc9..00000000000
--- a/app/controllers/concerns/idv/verify_by_mail_concern.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-module Idv
- module VerifyByMailConcern
- def gpo_verify_by_mail_policy
- @gpo_verify_by_mail_policy ||= Idv::GpoVerifyByMailPolicy.new(
- current_user,
- resolved_authn_context_result,
- )
- end
-
- def log_letter_requested_analytics(resend:)
- analytics.idv_gpo_address_letter_requested(
- resend: resend,
- first_letter_requested_at: first_letter_requested_at,
- hours_since_first_letter: hours_since_first_letter,
- phone_step_attempts: phone_step_attempt_count,
- **ab_test_analytics_buckets,
- )
- end
-
- def log_letter_enqueued_analytics(resend:)
- analytics.idv_gpo_address_letter_enqueued(
- enqueued_at: Time.zone.now,
- resend: resend,
- phone_step_attempts: phone_step_attempt_count,
- first_letter_requested_at: first_letter_requested_at,
- hours_since_first_letter: hours_since_first_letter,
- **ab_test_analytics_buckets,
- )
- end
-
- def phone_step_attempt_count
- @phone_step_attempt_count ||= RateLimiter.new(
- user: current_user,
- rate_limit_type: :proof_address,
- ).attempts
- end
-
- def first_letter_requested_at
- current_user.gpo_verification_pending_profile&.gpo_verification_pending_at
- end
-
- def hours_since_first_letter
- if first_letter_requested_at.present?
- (Time.zone.now - first_letter_requested_at).to_i.seconds.in_hours.to_i
- else
- 0
- end
- end
- end
-end
diff --git a/app/controllers/concerns/idv_step_concern.rb b/app/controllers/concerns/idv_step_concern.rb
index fccc07a6f34..82a08bace1d 100644
--- a/app/controllers/concerns/idv_step_concern.rb
+++ b/app/controllers/concerns/idv_step_concern.rb
@@ -7,7 +7,6 @@ module IdvStepConcern
include RateLimitConcern
include FraudReviewConcern
include Idv::AbTestAnalyticsConcern
- include Idv::VerifyByMailConcern
included do
before_action :confirm_two_factor_authenticated
@@ -51,7 +50,8 @@ def check_for_mail_only_outage
end
def redirect_for_mail_only
- if gpo_verify_by_mail_policy.send_letter_available?
+ policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ if policy.send_letter_available?
redirect_to idv_mail_only_warning_url
else
redirect_to vendor_outage_url
diff --git a/app/controllers/concerns/rate_limit_concern.rb b/app/controllers/concerns/rate_limit_concern.rb
index e49ab0e6bc8..db5ecd55aa4 100644
--- a/app/controllers/concerns/rate_limit_concern.rb
+++ b/app/controllers/concerns/rate_limit_concern.rb
@@ -29,7 +29,8 @@ def confirm_not_rate_limited_for_phone_address_verification
private
def confirm_not_rate_limited_for_phone_and_letter_address_verification
- if idv_attempter_rate_limited?(:proof_address) && gpo_verify_by_mail_policy.rate_limited?
+ gpo_policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ if idv_attempter_rate_limited?(:proof_address) && gpo_policy.rate_limited?
rate_limit_redirect!(:proof_address)
return true
end
diff --git a/app/controllers/idv/by_mail/enter_code_controller.rb b/app/controllers/idv/by_mail/enter_code_controller.rb
index 53a2821182f..c4c34d1ba2c 100644
--- a/app/controllers/idv/by_mail/enter_code_controller.rb
+++ b/app/controllers/idv/by_mail/enter_code_controller.rb
@@ -7,8 +7,6 @@ class EnterCodeController < ApplicationController
include IdvSessionConcern
include Idv::StepIndicatorConcern
include FraudReviewConcern
- include AbTestAnalyticsConcern
- include VerifyByMailConcern
prepend_before_action :note_if_user_did_not_receive_letter
before_action :confirm_two_factor_authenticated
@@ -18,7 +16,7 @@ def index
analytics.idv_verify_by_mail_enter_code_visited(
source: user_did_not_receive_letter? ? 'gpo_reminder_email' : nil,
otp_rate_limited: rate_limiter.limited?,
- user_can_request_another_letter: gpo_verify_by_mail_policy.resend_letter_available?,
+ user_can_request_another_letter: user_can_request_another_letter?,
)
if rate_limiter.limited?
@@ -28,12 +26,7 @@ def index
end
prefilled_code = session[:last_gpo_confirmation_code] if FeatureManagement.reveal_gpo_code?
- @gpo_verify_form = GpoVerifyForm.new(
- user: current_user,
- pii: pii,
- resolved_authn_context_result: resolved_authn_context_result,
- otp: prefilled_code,
- )
+ @gpo_verify_form = GpoVerifyForm.new(user: current_user, pii: pii, otp: prefilled_code)
render_enter_code_form
end
@@ -70,7 +63,7 @@ def create
private
def render_enter_code_form
- @can_request_another_letter = gpo_verify_by_mail_policy.resend_letter_available?
+ @can_request_another_letter = user_can_request_another_letter?
@user_did_not_receive_letter = user_did_not_receive_letter?
@last_date_letter_was_sent = last_date_letter_was_sent
render :index
@@ -126,7 +119,6 @@ def build_gpo_verify_form
GpoVerifyForm.new(
user: current_user,
pii: pii,
- resolved_authn_context_result: resolved_authn_context_result,
otp: params_otp,
)
end
@@ -154,6 +146,12 @@ def user_did_not_receive_letter?
params[:did_not_receive_letter].present?
end
+ def user_can_request_another_letter?
+ return @user_can_request_another_letter if defined?(@user_can_request_another_letter)
+ policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ @user_can_request_another_letter = policy.resend_letter_available?
+ end
+
def last_date_letter_was_sent
return @last_date_letter_was_sent if defined?(@last_date_letter_was_sent)
diff --git a/app/controllers/idv/by_mail/request_letter_controller.rb b/app/controllers/idv/by_mail/request_letter_controller.rb
index b071093cf9c..eae902c80d4 100644
--- a/app/controllers/idv/by_mail/request_letter_controller.rb
+++ b/app/controllers/idv/by_mail/request_letter_controller.rb
@@ -5,25 +5,42 @@ module ByMail
class RequestLetterController < ApplicationController
include Idv::AvailabilityConcern
include IdvStepConcern
+ skip_before_action :confirm_no_pending_gpo_profile
include Idv::StepIndicatorConcern
- include VerifyByMailConcern
before_action :confirm_mail_not_rate_limited
before_action :confirm_step_allowed
+ before_action :confirm_profile_not_too_old
def index
@applicant = idv_session.applicant
+ @presenter = RequestLetterPresenter.new(current_user, url_options)
Funnel::DocAuth::RegisterStep.new(current_user.id, current_sp&.issuer).
call(:usps_address, :view, true)
- analytics.idv_request_letter_visited
+ analytics.idv_request_letter_visited(
+ letter_already_sent: @presenter.resend_requested?,
+ )
end
def create
clear_future_steps!
update_tracking
idv_session.address_verification_mechanism = :gpo
- redirect_to idv_enter_password_url
+
+ if resend_requested? && pii_locked?
+ redirect_to capture_password_url
+ elsif resend_requested?
+ resend_letter
+ flash[:success] = t('idv.messages.gpo.another_letter_on_the_way')
+ redirect_to idv_letter_enqueued_url
+ else
+ redirect_to idv_enter_password_url
+ end
+ end
+
+ def gpo_mail_policy
+ @gpo_mail_policy ||= Idv::GpoVerifyByMailPolicy.new(current_user)
end
def self.step_info
@@ -41,18 +58,87 @@ def self.step_info
private
+ def confirm_profile_not_too_old
+ redirect_to idv_path if gpo_mail_policy.profile_too_old?
+ end
+
def update_tracking
Funnel::DocAuth::RegisterStep.new(current_user.id, current_sp&.issuer).
call(:usps_letter_sent, :update, true)
- log_letter_requested_analytics(resend: false)
+ analytics.idv_gpo_address_letter_requested(
+ resend: resend_requested?,
+ first_letter_requested_at: first_letter_requested_at,
+ hours_since_first_letter:
+ hours_since_first_letter(first_letter_requested_at),
+ phone_step_attempts: RateLimiter.new(
+ user: current_user,
+ rate_limit_type: :proof_address,
+ ).attempts,
+ **ab_test_analytics_buckets,
+ )
create_user_event(:gpo_mail_sent, current_user)
ProofingComponent.find_or_create_by(user: current_user).update(address_check: 'gpo_letter')
end
+ def resend_requested?
+ current_user.gpo_verification_pending_profile?
+ end
+
+ def first_letter_requested_at
+ current_user.gpo_verification_pending_profile&.gpo_verification_pending_at
+ end
+
+ def hours_since_first_letter(first_letter_requested_at)
+ first_letter_requested_at ?
+ (Time.zone.now - first_letter_requested_at).to_i.seconds.in_hours.to_i : 0
+ end
+
def confirm_mail_not_rate_limited
- redirect_to idv_enter_password_url if gpo_verify_by_mail_policy.rate_limited?
+ redirect_to idv_enter_password_url if gpo_mail_policy.rate_limited?
+ end
+
+ def resend_letter
+ analytics.idv_gpo_address_letter_enqueued(
+ enqueued_at: Time.zone.now,
+ resend: true,
+ first_letter_requested_at: first_letter_requested_at,
+ hours_since_first_letter:
+ hours_since_first_letter(first_letter_requested_at),
+ phone_step_attempts: RateLimiter.new(
+ user: current_user,
+ rate_limit_type: :proof_address,
+ ).attempts,
+ **ab_test_analytics_buckets,
+ )
+ confirmation_maker = confirmation_maker_perform
+ send_reminder
+ return unless FeatureManagement.reveal_gpo_code?
+ session[:last_gpo_confirmation_code] = confirmation_maker.otp
+ end
+
+ def confirmation_maker_perform
+ confirmation_maker = GpoConfirmationMaker.new(
+ pii: pii,
+ service_provider: current_sp,
+ profile: current_user.pending_profile,
+ )
+ confirmation_maker.perform
+ confirmation_maker
+ end
+
+ def pii
+ Pii::Cacher.new(current_user, user_session).
+ fetch(current_user.gpo_verification_pending_profile.id)
+ end
+
+ def send_reminder
+ current_user.send_email_to_all_addresses(:verify_by_mail_letter_requested)
+ end
+
+ def pii_locked?
+ !Pii::Cacher.new(current_user, user_session).exists_in_session?
end
def step_indicator_steps
diff --git a/app/controllers/idv/by_mail/resend_letter_controller.rb b/app/controllers/idv/by_mail/resend_letter_controller.rb
index 10f81cb71b1..86efadac256 100644
--- a/app/controllers/idv/by_mail/resend_letter_controller.rb
+++ b/app/controllers/idv/by_mail/resend_letter_controller.rb
@@ -3,11 +3,9 @@
module Idv
module ByMail
class ResendLetterController < ApplicationController
- include AvailabilityConcern
+ include Idv::AvailabilityConcern
include IdvSessionConcern
- include StepIndicatorConcern
- include VerifyByMailConcern
- include AbTestAnalyticsConcern
+ include Idv::StepIndicatorConcern
before_action :confirm_two_factor_authenticated
before_action :confirm_verification_needed
@@ -29,6 +27,10 @@ def create
end
end
+ def gpo_mail_policy
+ @gpo_mail_policy ||= Idv::GpoVerifyByMailPolicy.new(current_user)
+ end
+
private
def confirm_verification_needed
@@ -37,13 +39,22 @@ def confirm_verification_needed
end
def confirm_resend_letter_available
- unless gpo_verify_by_mail_policy.resend_letter_available?
+ unless gpo_mail_policy.resend_letter_available?
redirect_to idv_verify_by_mail_enter_code_path
end
end
def update_tracking
- log_letter_requested_analytics(resend: true)
+ analytics.idv_gpo_address_letter_requested(
+ resend: true,
+ first_letter_requested_at: first_letter_requested_at,
+ hours_since_first_letter:
+ hours_since_first_letter(first_letter_requested_at),
+ phone_step_attempts: RateLimiter.new(
+ user: current_user,
+ rate_limit_type: :proof_address,
+ ).attempts,
+ )
create_user_event(:gpo_mail_sent, current_user)
end
@@ -51,8 +62,27 @@ def resend_requested?
current_user.gpo_verification_pending_profile?
end
+ def first_letter_requested_at
+ current_user.gpo_verification_pending_profile&.gpo_verification_pending_at
+ end
+
+ def hours_since_first_letter(first_letter_requested_at)
+ first_letter_requested_at ?
+ (Time.zone.now - first_letter_requested_at).to_i.seconds.in_hours.to_i : 0
+ end
+
def resend_letter
- log_letter_enqueued_analytics(resend: true)
+ analytics.idv_gpo_address_letter_enqueued(
+ enqueued_at: Time.zone.now,
+ resend: true,
+ first_letter_requested_at: first_letter_requested_at,
+ hours_since_first_letter:
+ hours_since_first_letter(first_letter_requested_at),
+ phone_step_attempts: RateLimiter.new(
+ user: current_user,
+ rate_limit_type: :proof_address,
+ ).attempts,
+ )
confirmation_maker = confirmation_maker_perform
send_reminder
return unless FeatureManagement.reveal_gpo_code?
diff --git a/app/controllers/idv/enter_password_controller.rb b/app/controllers/idv/enter_password_controller.rb
index 2ca053235a1..6b22e0fedcd 100644
--- a/app/controllers/idv/enter_password_controller.rb
+++ b/app/controllers/idv/enter_password_controller.rb
@@ -5,7 +5,6 @@ class EnterPasswordController < ApplicationController
include Idv::AvailabilityConcern
include IdvStepConcern
include StepIndicatorConcern
- include VerifyByMailConcern
before_action :confirm_step_allowed
before_action :confirm_no_profile_yet
@@ -127,7 +126,17 @@ def init_profile
)
if idv_session.verify_by_mail?
current_user.send_email_to_all_addresses(:verify_by_mail_letter_requested)
- log_letter_enqueued_analytics(resend: false)
+ analytics.idv_gpo_address_letter_enqueued(
+ enqueued_at: Time.zone.now,
+ resend: false,
+ phone_step_attempts: RateLimiter.new(
+ user: current_user,
+ rate_limit_type: :proof_address,
+ ).attempts,
+ first_letter_requested_at: first_letter_requested_at,
+ hours_since_first_letter: hours_since_first_letter(first_letter_requested_at),
+ **ab_test_analytics_buckets,
+ )
end
if idv_session.profile.active?
@@ -144,6 +153,11 @@ def first_letter_requested_at
idv_session.profile.gpo_verification_pending_at
end
+ def hours_since_first_letter(first_letter_requested_at)
+ first_letter_requested_at ?
+ (Time.zone.now - first_letter_requested_at).to_i.seconds.in_hours.to_i : 0
+ end
+
def valid_password?
current_user.valid_password?(password)
end
diff --git a/app/controllers/idv/in_person/public/usps_locations_controller.rb b/app/controllers/idv/in_person/public/usps_locations_controller.rb
index eafddf1924a..5ecb9c28ae1 100644
--- a/app/controllers/idv/in_person/public/usps_locations_controller.rb
+++ b/app/controllers/idv/in_person/public/usps_locations_controller.rb
@@ -18,26 +18,19 @@ def index
)
locations = proofer.request_facilities(candidate, false)
- render json: localized_locations(locations).to_json
+ render json: locations.to_json
end
def options
head :ok
end
- private
+ protected
def proofer
@proofer ||= UspsInPersonProofing::EnrollmentHelper.usps_proofer
end
- def localized_locations(locations)
- return nil if locations.nil?
- locations.map do |location|
- UspsInPersonProofing::EnrollmentHelper.localized_location(location)
- end
- end
-
def enabled?
IdentityConfig.store.in_person_public_address_search_enabled
end
diff --git a/app/controllers/idv/in_person/ready_to_verify_controller.rb b/app/controllers/idv/in_person/ready_to_verify_controller.rb
index fbd0aeeee2c..ab70eeb3f32 100644
--- a/app/controllers/idv/in_person/ready_to_verify_controller.rb
+++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb
@@ -12,8 +12,8 @@ class ReadyToVerifyController < ApplicationController
check_or_render_not_found -> { IdentityConfig.store.in_person_proofing_enabled }
- before_action :confirm_two_factor_authenticated
before_action :handle_fraud
+ before_action :confirm_two_factor_authenticated
before_action :confirm_in_person_session
def show
diff --git a/app/controllers/idv/in_person/usps_locations_controller.rb b/app/controllers/idv/in_person/usps_locations_controller.rb
index 45cac7ac484..4367b795ba3 100644
--- a/app/controllers/idv/in_person/usps_locations_controller.rb
+++ b/app/controllers/idv/in_person/usps_locations_controller.rb
@@ -27,18 +27,18 @@ def index
zip_code: search_params['zip_code']
)
is_enhanced_ipp = resolved_authn_context_result.enhanced_ipp?
- locations = proofer.request_facilities(candidate, is_enhanced_ipp)
- if locations.length > 0
+ response = proofer.request_facilities(candidate, is_enhanced_ipp)
+ if response.length > 0
analytics.idv_in_person_locations_searched(
success: true,
- result_total: locations.length,
+ result_total: response.length,
)
else
analytics.idv_in_person_locations_searched(
success: false, errors: 'No USPS locations found',
)
end
- render json: localized_locations(locations).to_json
+ render json: response.to_json
end
# save the Post Office location the user selected to an enrollment
@@ -64,13 +64,6 @@ def add_proofing_component
update(document_check: Idp::Constants::Vendors::USPS)
end
- def localized_locations(locations)
- return nil if locations.nil?
- locations.map do |location|
- EnrollmentHelper.localized_location(location)
- end
- end
-
def handle_error(err)
remapped_error = case err
when ActionController::InvalidAuthenticityToken,
diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb
index ed676b6ad94..97db1d19f08 100644
--- a/app/controllers/idv/phone_controller.rb
+++ b/app/controllers/idv/phone_controller.rb
@@ -7,7 +7,6 @@ class PhoneController < ApplicationController
include StepIndicatorConcern
include PhoneOtpRateLimitable
include PhoneOtpSendable
- include Idv::VerifyByMailConcern
attr_reader :idv_form
@@ -36,15 +35,11 @@ def new
analytics.idv_phone_of_record_visited(
**ab_test_analytics_buckets,
)
- render(
- :new, locals: { gpo_letter_available: gpo_verify_by_mail_policy.send_letter_available? }
- )
+ render :new, locals: { gpo_letter_available: gpo_letter_available }
elsif async_state.missing?
analytics.proofing_address_result_missing
flash.now[:error] = I18n.t('idv.failure.timeout')
- render(
- :new, locals: { gpo_letter_available: gpo_verify_by_mail_policy.send_letter_available? }
- )
+ render :new, locals: { gpo_letter_available: gpo_letter_available }
end
end
@@ -61,9 +56,7 @@ def create
redirect_to idv_phone_path
else
flash.now[:error] = result.first_error_message
- render(
- :new, locals: { gpo_letter_available: gpo_verify_by_mail_policy.send_letter_available? }
- )
+ render :new, locals: { gpo_letter_available: gpo_letter_available }
end
end
@@ -230,6 +223,12 @@ def formatted_previous_phone_step_params_phone
)
end
+ def gpo_letter_available
+ return @gpo_letter_available if defined?(@gpo_letter_available)
+ policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ @gpo_letter_available = policy.send_letter_available?
+ end
+
# Migrated from otp_delivery_method_controller
def otp_sent_tracker_error(result)
if send_phone_confirmation_otp_rate_limited?
diff --git a/app/controllers/idv/phone_errors_controller.rb b/app/controllers/idv/phone_errors_controller.rb
index 770be4cbe47..57670946238 100644
--- a/app/controllers/idv/phone_errors_controller.rb
+++ b/app/controllers/idv/phone_errors_controller.rb
@@ -6,7 +6,6 @@ class PhoneErrorsController < ApplicationController
include IdvStepConcern
include StepIndicatorConcern
include Idv::AbTestAnalyticsConcern
- include Idv::VerifyByMailConcern
before_action :confirm_step_allowed, except: [:failure]
before_action :set_gpo_letter_available
@@ -72,8 +71,12 @@ def track_event(type:)
analytics.idv_phone_error_visited(**attributes)
end
+ # rubocop:disable Naming/MemoizedInstanceVariableName
def set_gpo_letter_available
- @gpo_letter_available = gpo_verify_by_mail_policy.send_letter_available?
+ return @gpo_letter_available if defined?(@gpo_letter_available)
+ policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ @gpo_letter_available = policy.send_letter_available?
end
+ # rubocop:enable Naming/MemoizedInstanceVariableName
end
end
diff --git a/app/controllers/idv/sessions_controller.rb b/app/controllers/idv/sessions_controller.rb
index 50bdc27ac86..37d98075582 100644
--- a/app/controllers/idv/sessions_controller.rb
+++ b/app/controllers/idv/sessions_controller.rb
@@ -9,8 +9,8 @@ class SessionsController < ApplicationController
def destroy
cancel_processing
- log_analytics
clear_session
+ log_analytics
redirect_to idv_url
end
diff --git a/app/controllers/idv_controller.rb b/app/controllers/idv_controller.rb
index 7d58f23a72a..bef3b246b29 100644
--- a/app/controllers/idv_controller.rb
+++ b/app/controllers/idv_controller.rb
@@ -5,7 +5,6 @@ class IdvController < ApplicationController
include AccountReactivationConcern
include VerifyProfileConcern
include RateLimitConcern
- include Idv::VerifyByMailConcern
before_action :confirm_two_factor_authenticated
before_action :profile_needs_reactivation?, only: [:index]
diff --git a/app/controllers/openid_connect/logout_controller.rb b/app/controllers/openid_connect/logout_controller.rb
index ada39ed341e..16f042142d2 100644
--- a/app/controllers/openid_connect/logout_controller.rb
+++ b/app/controllers/openid_connect/logout_controller.rb
@@ -133,9 +133,9 @@ def handle_successful_logout_request(result, redirect_uri)
def handle_logout(result, redirect_uri)
analytics.logout_initiated(**to_event(result))
- redirect_user(redirect_uri, @logout_form.service_provider&.issuer, current_user&.uuid)
-
sign_out
+
+ redirect_user(redirect_uri, @logout_form.service_provider&.issuer, current_user&.uuid)
end
# Convert FormResponse into loggable analytics event
diff --git a/app/controllers/users/delete_controller.rb b/app/controllers/users/delete_controller.rb
index c76d65b904a..a58e6cbb72f 100644
--- a/app/controllers/users/delete_controller.rb
+++ b/app/controllers/users/delete_controller.rb
@@ -16,10 +16,10 @@ def delete
send_push_notifications
notify_user_via_email_of_deletion
notify_user_via_sms_of_deletion
- analytics.account_delete_submitted(success: true)
delete_user
sign_out
flash[:success] = t('devise.registrations.destroyed')
+ analytics.account_delete_submitted(success: true)
redirect_to root_url
end
diff --git a/app/controllers/vendor_outage_controller.rb b/app/controllers/vendor_outage_controller.rb
index 411d735f899..76b22c2447f 100644
--- a/app/controllers/vendor_outage_controller.rb
+++ b/app/controllers/vendor_outage_controller.rb
@@ -1,15 +1,11 @@
# frozen_string_literal: true
class VendorOutageController < ApplicationController
- include Idv::VerifyByMailConcern
-
def show
outage_status = OutageStatus.new
@specific_message = outage_status.outage_message
- @show_gpo_option = from_idv_phone? &&
- user_signed_in? &&
- gpo_verify_by_mail_policy.send_letter_available?
+ @show_gpo_option = from_idv_phone? && gpo_letter_available?
outage_status.track_event(analytics)
end
@@ -18,4 +14,10 @@ def show
def from_idv_phone?
params[:from] == 'idv_phone'
end
+
+ def gpo_letter_available?
+ return false unless current_user
+ policy = Idv::GpoVerifyByMailPolicy.new(current_user)
+ policy.send_letter_available?
+ end
end
diff --git a/app/forms/gpo_verify_form.rb b/app/forms/gpo_verify_form.rb
index 497bb79678c..e9ca623efc9 100644
--- a/app/forms/gpo_verify_form.rb
+++ b/app/forms/gpo_verify_form.rb
@@ -9,12 +9,11 @@ class GpoVerifyForm
validate :validate_pending_profile
attr_accessor :otp, :pii, :pii_attributes
- attr_reader :user, :resolved_authn_context_result
+ attr_reader :user
- def initialize(user:, pii:, resolved_authn_context_result:, otp: nil)
+ def initialize(user:, pii:, otp: nil)
@user = user
@pii = pii
- @resolved_authn_context_result = resolved_authn_context_result
@otp = otp
end
@@ -128,7 +127,7 @@ def activate_profile
end
def user_can_request_another_letter?
- policy = Idv::GpoVerifyByMailPolicy.new(user, resolved_authn_context_result)
+ policy = Idv::GpoVerifyByMailPolicy.new(user)
policy.resend_letter_available?
end
end
diff --git a/app/forms/recaptcha_form.rb b/app/forms/recaptcha_form.rb
index 1ddd6fa9ee9..4d49437d65b 100644
--- a/app/forms/recaptcha_form.rb
+++ b/app/forms/recaptcha_form.rb
@@ -6,7 +6,6 @@ class RecaptchaForm
VERIFICATION_ENDPOINT = 'https://www.google.com/recaptcha/api/siteverify'
RESULT_ERRORS = ['missing-input-secret', 'invalid-input-secret'].freeze
- EXEMPT_RESULT_REASONS = ['LOW_CONFIDENCE_SCORE'].freeze
attr_reader :recaptcha_action,
:recaptcha_token,
@@ -96,7 +95,6 @@ def faraday
def recaptcha_result_valid?(result)
return true if result.blank?
- return true if result_reason_exempt?(result)
if result.success?
result.score >= score_threshold
@@ -109,10 +107,6 @@ def is_result_error?(error_code)
RESULT_ERRORS.include?(error_code)
end
- def result_reason_exempt?(result)
- (EXEMPT_RESULT_REASONS & result.reasons).any?
- end
-
def log_analytics(result: nil, error: nil)
analytics&.recaptcha_verify_result_received(
recaptcha_result: result.to_h.presence,
diff --git a/app/javascript/packages/session/requests.spec.ts b/app/javascript/packages/session/requests.spec.ts
index 24607acb2c3..2793584b50a 100644
--- a/app/javascript/packages/session/requests.spec.ts
+++ b/app/javascript/packages/session/requests.spec.ts
@@ -1,11 +1,9 @@
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import type { SetupServer } from 'msw/node';
-import { requestSessionStatus, extendSession } from './requests';
+import { SESSIONS_URL, requestSessionStatus, extendSession } from './requests';
import type { SessionLiveStatusResponse, SessionTimedOutStatusResponse } from './requests';
-const SESSIONS_URL = '/api/internal/sessions';
-
describe('requestSessionStatus', () => {
let server: SetupServer;
@@ -24,7 +22,7 @@ describe('requestSessionStatus', () => {
});
it('resolves to the status', async () => {
- const result = await requestSessionStatus(SESSIONS_URL);
+ const result = await requestSessionStatus();
expect(result).to.deep.equal({ isLive: false });
});
@@ -48,7 +46,7 @@ describe('requestSessionStatus', () => {
});
it('resolves to the status', async () => {
- const result = await requestSessionStatus(SESSIONS_URL);
+ const result = await requestSessionStatus();
expect(result).to.deep.equal({ isLive: true, timeout: new Date(timeout) });
});
@@ -67,7 +65,7 @@ describe('requestSessionStatus', () => {
});
it('resolves to the status', async () => {
- const result = await requestSessionStatus(SESSIONS_URL);
+ const result = await requestSessionStatus();
expect(result).to.deep.equal({ isLive: false });
});
@@ -86,7 +84,7 @@ describe('requestSessionStatus', () => {
});
it('throws an error', async () => {
- await expect(requestSessionStatus(SESSIONS_URL)).to.be.rejected();
+ await expect(requestSessionStatus()).to.be.rejected();
});
});
});
@@ -111,7 +109,7 @@ describe('extendSession', () => {
});
it('resolves to the status', async () => {
- const result = await extendSession(SESSIONS_URL);
+ const result = await extendSession();
expect(result).to.deep.equal({ isLive: true, timeout: new Date(timeout) });
});
@@ -130,7 +128,7 @@ describe('extendSession', () => {
});
it('resolves to the status', async () => {
- const result = await extendSession(SESSIONS_URL);
+ const result = await extendSession();
expect(result).to.deep.equal({ isLive: false });
});
@@ -149,7 +147,7 @@ describe('extendSession', () => {
});
it('throws an error', async () => {
- await expect(extendSession(SESSIONS_URL)).to.be.rejected();
+ await expect(extendSession()).to.be.rejected();
});
});
});
diff --git a/app/javascript/packages/session/requests.ts b/app/javascript/packages/session/requests.ts
index a04e2cc213f..048834b6ca5 100644
--- a/app/javascript/packages/session/requests.ts
+++ b/app/javascript/packages/session/requests.ts
@@ -52,6 +52,8 @@ interface SessionTimedOutStatus {
export type SessionStatus = SessionLiveStatus | SessionTimedOutStatus;
+export const SESSIONS_URL = new URL('/api/internal/sessions', window.location.href).toString();
+
function mapSessionStatusResponse(
response: R,
): SessionLiveStatus;
@@ -81,11 +83,10 @@ function handleUnauthorizedStatusResponse(error: ResponseError) {
/**
* Request the current session status. Returns a promise resolving to the current session status.
*
- * @param sessionsURL The URL for the session API
* @return A promise resolving to the current session status
*/
-export const requestSessionStatus = (sessionsURL: string): Promise =>
- request(sessionsURL)
+export const requestSessionStatus = (): Promise =>
+ request(SESSIONS_URL)
.catch(handleUnauthorizedStatusResponse)
.then(mapSessionStatusResponse);
@@ -93,10 +94,9 @@ export const requestSessionStatus = (sessionsURL: string): Promise =>
- request(sessionsURL, { method: 'PUT' })
+export const extendSession = (): Promise =>
+ request(SESSIONS_URL, { method: 'PUT' })
.catch(handleUnauthorizedStatusResponse)
.then(mapSessionStatusResponse);
diff --git a/app/javascript/packs/document-capture.tsx b/app/javascript/packs/document-capture.tsx
index 2cf4b4bafeb..be9c15bd19b 100644
--- a/app/javascript/packs/document-capture.tsx
+++ b/app/javascript/packs/document-capture.tsx
@@ -39,8 +39,6 @@ interface AppRootData {
howToVerifyURL: string;
previousStepUrl: string;
docAuthSelfieDesktopTestMode: string;
- locationsUrl: string;
- addressSearchUrl: string;
}
const appRoot = document.getElementById('document-capture-form')!;
@@ -109,8 +107,6 @@ const {
howToVerifyUrl,
previousStepUrl,
docAuthSelfieDesktopTestMode,
- locationsUrl: locationsURL,
- addressSearchUrl: addressSearchURL,
} = appRoot.dataset as DOMStringMap & AppRootData;
let parsedUsStatesTerritories = [];
@@ -126,8 +122,8 @@ const App = composeComponents(
{
value: {
inPersonURL,
- locationsURL,
- addressSearchURL,
+ locationsURL: new URL('/verify/in_person/usps_locations', window.location.href).toString(),
+ addressSearchURL: new URL('/api/addresses', window.location.href).toString(),
inPersonOutageMessageEnabled: inPersonOutageMessageEnabled === 'true',
inPersonOutageExpectedUpdateDate,
inPersonFullAddressEntryEnabled: inPersonFullAddressEntryEnabled === 'true',
diff --git a/app/javascript/packs/session-timeout-ping.ts b/app/javascript/packs/session-timeout-ping.ts
index a86f60254b5..339ce097c86 100644
--- a/app/javascript/packs/session-timeout-ping.ts
+++ b/app/javascript/packs/session-timeout-ping.ts
@@ -11,8 +11,7 @@ const defaultTime = '60';
const frequency = parseInt(warningEl?.dataset.frequency || defaultTime, 10) * 1000;
const warning = parseInt(warningEl?.dataset.warning || defaultTime, 10) * 1000;
const start = parseInt(warningEl?.dataset.start || defaultTime, 10) * 1000;
-const timeoutURL = warningEl?.dataset.timeoutUrl!;
-const sessionsURL = warningEl?.dataset.sessionsUrl!;
+const timeoutUrl = warningEl?.dataset.timeoutUrl!;
const modal = document.querySelector('lg-modal.session-timeout-modal')!;
const keepaliveEl = document.getElementById('session-keepalive-btn');
@@ -20,8 +19,8 @@ const countdownEls: NodeListOf = modal.querySelectorAll('lg-co
function success({ isLive, timeout }: SessionStatus) {
if (!isLive) {
- if (timeoutURL) {
- forceRedirect(timeoutURL);
+ if (timeoutUrl) {
+ forceRedirect(timeoutUrl);
}
return;
}
@@ -44,12 +43,12 @@ function success({ isLive, timeout }: SessionStatus) {
setTimeout(ping, nextPingTimeout);
}
-const ping = () => requestSessionStatus(sessionsURL).then(success);
+const ping = () => requestSessionStatus().then(success);
function keepalive() {
modal.hide();
countdownEls.forEach((countdownEl) => countdownEl.stop());
- extendSession(sessionsURL);
+ extendSession();
}
keepaliveEl?.addEventListener('click', keepalive, false);
diff --git a/app/models/anonymous_user.rb b/app/models/anonymous_user.rb
index f3b22485419..b871d1a74be 100644
--- a/app/models/anonymous_user.rb
+++ b/app/models/anonymous_user.rb
@@ -5,10 +5,6 @@ def uuid
'anonymous-uuid'
end
- def establishing_in_person_enrollment; end
-
- def pending_in_person_enrollment; end
-
def second_factor_locked_at
nil
end
diff --git a/app/policies/idv/gpo_verify_by_mail_policy.rb b/app/policies/idv/gpo_verify_by_mail_policy.rb
index e0a0f9247d6..6f2fd464dd9 100644
--- a/app/policies/idv/gpo_verify_by_mail_policy.rb
+++ b/app/policies/idv/gpo_verify_by_mail_policy.rb
@@ -2,23 +2,21 @@
module Idv
class GpoVerifyByMailPolicy
- attr_reader :user, :resolved_authn_context_result
+ attr_reader :user
- def initialize(user, resolved_authn_context_result)
+ def initialize(user)
@user = user
- @resolved_authn_context_result = resolved_authn_context_result
end
def resend_letter_available?
- @resend_letter_available ||= FeatureManagement.gpo_verification_enabled? &&
- !rate_limited? &&
- !profile_too_old?
+ FeatureManagement.gpo_verification_enabled? &&
+ !rate_limited? &&
+ !profile_too_old?
end
def send_letter_available?
- @send_letter_available ||= FeatureManagement.gpo_verification_enabled? &&
- !disabled_for_biometric_comparison? &&
- !rate_limited?
+ FeatureManagement.gpo_verification_enabled? &&
+ !rate_limited?
end
def rate_limited?
@@ -36,12 +34,6 @@ def profile_too_old?
private
- def disabled_for_biometric_comparison?
- return false unless IdentityConfig.store.no_verify_by_mail_for_biometric_comparison_enabled
-
- resolved_authn_context_result.two_pieces_of_fair_evidence?
- end
-
def window_limit_enabled?
IdentityConfig.store.max_mail_events != 0 &&
IdentityConfig.store.max_mail_events_window_in_days != 0
diff --git a/app/presenters/idv/by_mail/request_letter_presenter.rb b/app/presenters/idv/by_mail/request_letter_presenter.rb
new file mode 100644
index 00000000000..349e7554619
--- /dev/null
+++ b/app/presenters/idv/by_mail/request_letter_presenter.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Idv
+ module ByMail
+ class RequestLetterPresenter
+ include Rails.application.routes.url_helpers
+
+ attr_reader :current_user, :url_options
+
+ def initialize(current_user, url_options)
+ @current_user = current_user
+ @url_options = url_options
+ end
+
+ def title
+ resend_requested? ?
+ I18n.t('idv.gpo.request_another_letter.title') :
+ I18n.t('idv.titles.mail.verify')
+ end
+
+ def button
+ resend_requested? ?
+ I18n.t('idv.gpo.request_another_letter.button') :
+ I18n.t('idv.buttons.mail.send')
+ end
+
+ def fallback_back_path
+ return idv_verify_info_path if OutageStatus.new.any_phone_vendor_outage?
+ user_needs_address_otp_verification? ? idv_verify_by_mail_enter_code_path : idv_phone_path
+ end
+
+ def resend_requested?
+ current_user.gpo_verification_pending_profile?
+ end
+
+ def back_or_cancel_partial
+ if FeatureManagement.idv_by_mail_only?
+ 'idv/doc_auth/cancel'
+ else
+ 'idv/shared/back'
+ end
+ end
+
+ def back_or_cancel_parameters
+ if FeatureManagement.idv_by_mail_only?
+ { step: 'gpo' }
+ else
+ { fallback_path: fallback_back_path }
+ end
+ end
+
+ private
+
+ def user_needs_address_otp_verification?
+ current_user.pending_profile?
+ end
+ end
+ end
+end
diff --git a/app/presenters/idv/in_person/ready_to_verify_presenter.rb b/app/presenters/idv/in_person/ready_to_verify_presenter.rb
index 61caeca8b5a..a5f8462f742 100644
--- a/app/presenters/idv/in_person/ready_to_verify_presenter.rb
+++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb
@@ -31,7 +31,7 @@ def formatted_due_date
def selected_location_hours(prefix)
return unless selected_location_details
hours = selected_location_details["#{prefix}_hours"]
- UspsInPersonProofing::EnrollmentHelper.localized_hours(hours) if hours
+ return localized_hours(hours) if hours
end
def service_provider
@@ -107,6 +107,18 @@ def format_outage_date(date)
I18n.l(date.to_date, format: :short)
end
+ def localized_hours(hours)
+ case hours
+ when 'Closed'
+ I18n.t('in_person_proofing.body.barcode.retail_hours_closed')
+ else
+ hours.
+ split(' - '). # Hyphen
+ map { |time| Time.zone.parse(time).strftime(I18n.t('time.formats.event_time')) }.
+ join(' – ') # Endash
+ end
+ end
+
def sp_return_url_resolver
SpReturnUrlResolver.new(service_provider: service_provider)
end
diff --git a/app/services/access_token_verifier.rb b/app/services/access_token_verifier.rb
index d203a25b22a..02f55ed401a 100644
--- a/app/services/access_token_verifier.rb
+++ b/app/services/access_token_verifier.rb
@@ -59,7 +59,7 @@ def extract_access_token(header)
end
bearer, access_token = header.split(' ', 2)
- if bearer != 'Bearer' || access_token.blank?
+ if bearer != 'Bearer'
errors.add(
:access_token, t('openid_connect.user_info.errors.malformed_authorization'),
type: :malformed_authorization
diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb
index 3177bb11df2..699e56d39c0 100644
--- a/app/services/analytics_events.rb
+++ b/app/services/analytics_events.rb
@@ -887,14 +887,7 @@ def idv_camera_info_logged(flow_path:, camera_info:, **_extra)
end
# @param [String] step the step that the user was on when they clicked cancel
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user confirmed their choice to cancel going through IDV
@@ -916,14 +909,7 @@ def idv_cancellation_confirmed(
end
# @param [String] step the step that the user was on when they clicked cancel
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [boolean,nil] cancelled_enrollment Whether the user's IPP enrollment has been canceled
# @param [String,nil] enrollment_code IPP enrollment code
# @param [Integer,nil] enrollment_id ID of the associated IPP enrollment record
@@ -956,14 +942,7 @@ def idv_cancellation_go_back(
# @param [String] step the step that the user was on when they clicked cancel
# @param [String] request_came_from the controller and action from the
# source such as "users/sessions#new"
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user clicked cancel during IDV (presented with an option to go back or confirm)
@@ -1474,14 +1453,7 @@ def idv_doc_auth_welcome_visited(**extra)
# @param [Boolean] fraud_rejection
# @param [Boolean] gpo_verification_pending
# @param [Boolean] in_person_verification_pending
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String, nil] deactivation_reason Reason user's profile was deactivated, if any.
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
@@ -1513,14 +1485,8 @@ def idv_enter_password_submitted(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's
+ # current proofing components
# @param [String] address_verification_method The method (phone or gpo) being
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
@@ -1550,14 +1516,7 @@ def idv_enter_password_visited(
# @param [Boolean] fraud_rejection Profile is rejected due to fraud
# @param [Boolean] gpo_verification_pending Profile is awaiting gpo verification
# @param [Boolean] in_person_verification_pending Profile is awaiting in person verification
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# @param [Array,nil] profile_history Array of user's profiles (oldest to newest).
@@ -1593,14 +1552,7 @@ def idv_final(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# User visited forgot password page
@@ -1619,14 +1571,7 @@ def idv_forgot_password(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# User confirmed forgot password
@@ -1772,14 +1717,7 @@ def idv_front_image_clicked(
# @param [Integer] hours_since_first_letter Difference between first_letter_requested_at
# and now in hours
# @param [Integer] phone_step_attempts Number of attempts at phone step before requesting letter
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# GPO letter was enqueued and the time at which it was enqueued
@@ -1813,14 +1751,7 @@ def idv_gpo_address_letter_enqueued(
# @param [Integer] hours_since_first_letter Difference between first_letter_requested_at
# and now in hours
# @param [Integer] phone_step_attempts Number of attempts at phone step before requesting letter
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# GPO letter was requested
@@ -2281,14 +2212,7 @@ def idv_in_person_ready_to_verify_sp_link_clicked(**extra)
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user visited the "ready to verify" page for the in person proofing flow
@@ -2770,14 +2694,7 @@ def idv_ipp_deactivated_for_never_visiting_post_office(
end
# The user visited the "letter enqueued" page shown during the verify by mail flow
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# @identity.idp.previous_event_name IdV: come back later visited
@@ -2860,14 +2777,7 @@ def idv_not_verified_visited(**extra)
# Tracks if a user clicks the 'acknowledge' checkbox during personal
# key creation
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [boolean] checked whether the user checked or un-checked
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
@@ -2891,14 +2801,7 @@ def idv_personal_key_acknowledgment_toggled(
# A user has downloaded their personal key. This event is no longer emitted.
# @identity.idp.previous_event_name IdV: download personal key
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
def idv_personal_key_downloaded(
@@ -2916,14 +2819,7 @@ def idv_personal_key_downloaded(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String, nil] deactivation_reason Reason profile was deactivated.
# @param [Boolean] fraud_review_pending Profile is under review for fraud
# @param [Boolean] fraud_rejection Profile is rejected due to fraud
@@ -2957,14 +2853,7 @@ def idv_personal_key_submitted(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String] address_verification_method "phone" or "gpo"
# @param [Boolean,nil] in_person_verification_pending
# @param [Boolean] encrypted_profiles_missing True if user's session had no encrypted pii
@@ -2996,14 +2885,7 @@ def idv_personal_key_visited(
# @param [Hash] errors Errors resulting from form validation
# @param [Hash] error_details Details for errors that occurred in unsuccessful submission
# @param ["sms", "voice"] otp_delivery_preference
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user submitted their phone on the phone confirmation page
@@ -3030,14 +2912,7 @@ def idv_phone_confirmation_form_submitted(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user was rate limited for submitting too many OTPs during the IDV phone step
@@ -3056,14 +2931,7 @@ def idv_phone_confirmation_otp_rate_limit_attempts(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user was locked out for hitting the phone OTP rate limit during IDV
@@ -3082,14 +2950,7 @@ def idv_phone_confirmation_otp_rate_limit_locked_out(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The user was rate limited for requesting too many OTPs during the IDV phone step
@@ -3117,14 +2978,7 @@ def idv_phone_confirmation_otp_rate_limit_sends(
# @param [Boolean] rate_limit_exceeded whether or not the rate limit was exceeded by this attempt
# @param [Hash] telephony_response response from Telephony gem
# @param [String] phone_fingerprint Fingerprint string identifying phone number
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# @param [Hash, nil] ab_tests data for ongoing A/B tests
@@ -3173,14 +3027,7 @@ def idv_phone_confirmation_otp_resent(
# @param [Boolean] rate_limit_exceeded whether or not the rate limit was exceeded by this attempt
# @param [String] phone_fingerprint the hmac fingerprint of the phone number formatted as e164
# @param [Hash] telephony_response response from Telephony gem
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [:test, :pinpoint] adapter which adapter the OTP was delivered with
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
@@ -3228,14 +3075,7 @@ def idv_phone_confirmation_otp_sent(
# @param [:sms,:voice] otp_delivery_preference
# @param [Integer] second_factor_attempts_count number of attempts to confirm this phone
# @param [Time, nil] second_factor_locked_at timestamp when the phone was locked out
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# When a user attempts to confirm posession of a new phone number during the IDV process
@@ -3270,14 +3110,7 @@ def idv_phone_confirmation_otp_submitted(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# When a user visits the page to confirm posession of a new phone number during the IDV process
@@ -3299,14 +3132,7 @@ def idv_phone_confirmation_otp_visit(
# @param [Boolean] success Whether form validation was successful
# @param [Hash] errors Errors resulting from form validation
# @param [Hash] error_details Details for errors that occurred in unsuccessful submission
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The vendor finished the process of confirming the users phone
@@ -3335,14 +3161,7 @@ def idv_phone_confirmation_vendor_submitted(
# @param [Time] limiter_expires_at when the rate limit expires
# @param [Integer] remaining_submit_attempts number of submit attempts remaining
# (previously called "remaining_attempts")
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# When a user gets an error during the phone finder flow of IDV
@@ -3369,14 +3188,7 @@ def idv_phone_error_visited(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# User visited idv phone of record
@@ -3395,14 +3207,7 @@ def idv_phone_of_record_visited(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String] step the step the user was on when they clicked use a different phone number
# User decided to use a different phone number in idv
def idv_phone_use_different(step:, proofing_components: nil, **extra)
@@ -3415,14 +3220,7 @@ def idv_phone_use_different(step:, proofing_components: nil, **extra)
end
# @identity.idp.previous_event_name IdV: Verify setup errors visited
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# @param [Array,nil] profile_history Array of user's profiles (oldest to newest).
@@ -3444,14 +3242,7 @@ def idv_please_call_visited(
)
end
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [String,nil] active_profile_idv_level ID verification level of user's active profile.
# @param [String,nil] pending_profile_idv_level ID verification level of user's pending profile.
# The system encountered an error and the proofing results are missing
@@ -3470,13 +3261,16 @@ def idv_proofing_resolution_result_missing(
)
end
+ # @param [Boolean] letter_already_sent
# GPO "request letter" page visited
# @identity.idp.previous_event_name IdV: USPS address visited
def idv_request_letter_visited(
+ letter_already_sent:,
**extra
)
track_event(
'IdV: request letter visited',
+ letter_already_sent: letter_already_sent,
**extra,
)
end
@@ -3758,14 +3552,7 @@ def idv_session_error_visited(
# @param [String] step
# @param [String] location
- # @param [Hash,nil] proofing_components User's current proofing components
- # @option proofing_components [String,nil] 'document_check' Vendor that verified the user's ID
- # @option proofing_components [String,nil] 'document_type' Type of ID used to verify
- # @option proofing_components [String,nil] 'source_check' Source used to verify user's PII
- # @option proofing_components [String,nil] 'resolution_check' Vendor for identity resolution check
- # @option proofing_components [String,nil] 'address_check' Method used to verify user's address
- # @option proofing_components [Boolean,nil] 'threatmetrix' Whether ThreatMetrix check was done
- # @option proofing_components [String,nil] 'threatmetrix_review_status' TMX decision on the user
+ # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components
# @param [boolean,nil] cancelled_enrollment Whether the user's IPP enrollment has been canceled
# @param [String,nil] enrollment_code IPP enrollment code
# @param [Integer,nil] enrollment_id ID of the associated IPP enrollment record
diff --git a/app/services/gpo_confirmation_uploader.rb b/app/services/gpo_confirmation_uploader.rb
index 54422aba58c..315c649a244 100644
--- a/app/services/gpo_confirmation_uploader.rb
+++ b/app/services/gpo_confirmation_uploader.rb
@@ -43,14 +43,8 @@ def generate_export(confirmations)
def upload_export(export)
return unless FeatureManagement.gpo_upload_enabled?
io = StringIO.new(export)
-
- with_retries(
- max_tries: 5,
- rescue: [Net::SFTP::Exception, Net::SSH::Exception],
- ) do
- Net::SFTP.start(*sftp_config) do |sftp|
- sftp.upload!(io, remote_path)
- end
+ Net::SFTP.start(*sftp_config) do |sftp|
+ sftp.upload!(io, remote_path)
end
end
diff --git a/app/services/idv/analytics_events_enhancer.rb b/app/services/idv/analytics_events_enhancer.rb
index f75fd52f412..5645c1f3320 100644
--- a/app/services/idv/analytics_events_enhancer.rb
+++ b/app/services/idv/analytics_events_enhancer.rb
@@ -183,20 +183,8 @@ def profile_history
end
def proofing_components
- return if !user
-
- idv_session = Idv::Session.new(
- user_session: session&.dig('warden.user.user.session') || {},
- current_user: user,
- service_provider: sp,
- )
-
- proofing_components_hash = ProofingComponents.new(
- user:,
- idv_session:,
- ).to_h
-
- proofing_components_hash.empty? ? nil : proofing_components_hash
+ return if !user&.respond_to?(:proofing_component) || !user.proofing_component
+ ProofingComponentsLogging.new(user.proofing_component)
end
end
end
diff --git a/app/services/idv/proofing_components.rb b/app/services/idv/proofing_components.rb
deleted file mode 100644
index 6300bfd8ff3..00000000000
--- a/app/services/idv/proofing_components.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-module Idv
- class ProofingComponents
- def initialize(
- user:,
- idv_session:
- )
- @user = user
- @idv_session = idv_session
- end
-
- def document_check
- if user.establishing_in_person_enrollment || user.pending_in_person_enrollment
- Idp::Constants::Vendors::USPS
- elsif idv_session.remote_document_capture_complete?
- DocAuthRouter.doc_auth_vendor(
- discriminator: idv_session.document_capture_session_uuid,
- )
- end
- end
-
- def document_type
- return 'state_id' if idv_session.remote_document_capture_complete?
- end
-
- def source_check
- Idp::Constants::Vendors::AAMVA if idv_session.verify_info_step_complete?
- end
-
- def resolution_check
- Idp::Constants::Vendors::LEXIS_NEXIS if idv_session.verify_info_step_complete?
- end
-
- def address_check
- if idv_session.verify_by_mail?
- 'gpo_letter'
- elsif idv_session.address_verification_mechanism == 'phone'
- 'lexis_nexis_address'
- end
- end
-
- def threatmetrix
- if idv_session.threatmetrix_review_status.present?
- FeatureManagement.proofing_device_profiling_collecting_enabled?
- end
- end
-
- def threatmetrix_review_status
- idv_session.threatmetrix_review_status
- end
-
- def to_h
- {
- document_check:,
- document_type:,
- source_check:,
- resolution_check:,
- address_check:,
- threatmetrix:,
- threatmetrix_review_status:,
-
- }.compact
- end
-
- private
-
- attr_reader :user, :idv_session
- end
-end
diff --git a/app/services/idv/proofing_components_logging.rb b/app/services/idv/proofing_components_logging.rb
new file mode 100644
index 00000000000..d6f31ced71c
--- /dev/null
+++ b/app/services/idv/proofing_components_logging.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Idv
+ ProofingComponentsLogging = Struct.new(:proofing_components) do
+ def as_json(*)
+ proofing_components.slice(
+ :document_check,
+ :document_type,
+ :source_check,
+ :resolution_check,
+ :address_check,
+ :liveness_check,
+ :device_fingerprinting_vendor,
+ :threatmetrix,
+ :threatmetrix_review_status,
+ :threatmetrix_risk_rating,
+ :threatmetrix_policy_score,
+ ).compact
+ end
+ end
+end
diff --git a/app/services/usps_in_person_proofing/enrollment_helper.rb b/app/services/usps_in_person_proofing/enrollment_helper.rb
index cb8cc789c9f..1a500465f57 100644
--- a/app/services/usps_in_person_proofing/enrollment_helper.rb
+++ b/app/services/usps_in_person_proofing/enrollment_helper.rb
@@ -20,12 +20,6 @@ def schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:, opt_in: nil)
enrollment_code = create_usps_enrollment(enrollment, pii, is_enhanced_ipp)
return unless enrollment_code
- if is_enhanced_ipp
- enrollment.sponsor_id = IdentityConfig.store.usps_eipp_sponsor_id
- else
- enrollment.sponsor_id = IdentityConfig.store.usps_ipp_sponsor_id
- end
-
# update the enrollment to status pending
enrollment.enrollment_code = enrollment_code
enrollment.status = :pending
@@ -101,40 +95,6 @@ def usps_proofer
end
end
- def localized_location(location)
- {
- address: location.address,
- city: location.city,
- distance: location.distance,
- name: location.name,
- saturday_hours: EnrollmentHelper.localized_hours(location.saturday_hours),
- state: location.state,
- sunday_hours: EnrollmentHelper.localized_hours(location.sunday_hours),
- weekday_hours: EnrollmentHelper.localized_hours(location.weekday_hours),
- zip_code_4: location.zip_code_4,
- zip_code_5: location.zip_code_5,
- is_pilot: location.is_pilot,
- }
- end
-
- def localized_hours(hours)
- if hours == 'Closed'
- I18n.t('in_person_proofing.body.barcode.retail_hours_closed')
- elsif hours.include?(' - ') # Hyphen
- hours.
- split(' - '). # Hyphen
- map { |time| Time.zone.parse(time).strftime(I18n.t('time.formats.event_time')) }.
- join(' – ') # Endash
- elsif hours.include?(' – ') # Endash
- hours.
- split(' – '). # Endash
- map { |time| Time.zone.parse(time).strftime(I18n.t('time.formats.event_time')) }.
- join(' – ') # Endash
- else
- hours
- end
- end
-
private
SECONDARY_ID_ADDRESS_MAP = {
diff --git a/app/views/idv/by_mail/request_letter/index.html.erb b/app/views/idv/by_mail/request_letter/index.html.erb
index 730c829806c..99a2f06e42b 100644
--- a/app/views/idv/by_mail/request_letter/index.html.erb
+++ b/app/views/idv/by_mail/request_letter/index.html.erb
@@ -9,58 +9,77 @@
) %>
<% end %>
-<%= render AlertComponent.new(
- type: :info,
- message: t('idv.messages.gpo.info_alert'),
- class: 'margin-bottom-4',
- ) %>
-
-<%= render PageHeadingComponent.new.with_content(t('idv.titles.mail.verify')) %>
-
-
- <%= t('idv.messages.gpo.timeframe_html') %>
-
- <%= new_tab_link_to(
- t('idv.messages.gpo.learn_more_verify_by_mail'),
- help_center_redirect_url(
- category: 'verify-your-identity',
- article: 'verify-your-address-by-mail',
- flow: :idv,
- step: :gpo_send_letter,
- ),
- )
- %>
-
-
- <%= t('idv.messages.gpo.address_on_file') %>
-
+<% if @presenter.resend_requested? %>
+ <%= render PageHeadingComponent.new.with_content(@presenter.title) %>
+
+ <%= t('idv.gpo.request_another_letter.instructions_html') %>
+
+
+ <%= new_tab_link_to(
+ t('idv.gpo.request_another_letter.learn_more_link'),
+ help_center_redirect_url(
+ category: 'verify-your-identity',
+ article: 'verify-your-address-by-mail',
+ flow: :idv,
+ step: :gpo_send_letter,
+ ),
+ ) %>
+
+<% else %>
+ <%= render AlertComponent.new(
+ type: :info,
+ message: t('idv.messages.gpo.info_alert'),
+ class: 'margin-bottom-4',
+ ) %>
+ <%= render PageHeadingComponent.new.with_content(@presenter.title) %>
+
+ <%= t('idv.messages.gpo.timeframe_html') %>
+
+ <%= new_tab_link_to(
+ t('idv.messages.gpo.learn_more_verify_by_mail'),
+ help_center_redirect_url(
+ category: 'verify-your-identity',
+ article: 'verify-your-address-by-mail',
+ flow: :idv,
+ step: :gpo_send_letter,
+ ),
+ )
+ %>
+
+
+ <%= t('idv.messages.gpo.address_on_file') %>
+
-
- <%= render 'shared/address',
- address: @applicant.slice(:address1, :address2, :city, :state, :zipcode)
- %>
-
+
+ <%= @applicant[:address1] %>
+
+ <% if @applicant[:address2] %>
+ <%= @applicant[:address2] %>
+
+ <% end %>
+ <%= @applicant[:city] %>, <%= @applicant[:state] %> <%= @applicant[:zipcode] %>
+
+
-
- <%= t(
- 'idv.messages.gpo.start_over_html',
- start_over_link_html: link_to(
+
+ <%= start_over_link_html = link_to(
t('idv.messages.gpo.start_over_link_text'),
idv_confirm_start_over_before_letter_path,
- ),
- )
- %>
-
+ )
+ t(
+ 'idv.messages.gpo.start_over_html',
+ start_over_link_html: start_over_link_html,
+ )
+ %>
+
+
+<% end %>
- <%= button_to t('idv.buttons.mail.send'),
+ <%= button_to @presenter.button,
idv_request_letter_path,
method: 'put',
class: 'usa-button usa-button--big usa-button--wide' %>
-<% if FeatureManagement.idv_by_mail_only? %>
- <%= render 'idv/doc_auth/cancel', step: 'gpo' %>
-<% else %>
- <%= render 'idv/shared/back', fallback_path: idv_phone_path %>
-<% end %>
+<%= render @presenter.back_or_cancel_partial, @presenter.back_or_cancel_parameters %>
diff --git a/app/views/idv/shared/_document_capture.html.erb b/app/views/idv/shared/_document_capture.html.erb
index 424ffac95ff..72000e65e8b 100644
--- a/app/views/idv/shared/_document_capture.html.erb
+++ b/app/views/idv/shared/_document_capture.html.erb
@@ -42,8 +42,6 @@
skip_doc_auth_from_handoff: skip_doc_auth_from_handoff,
how_to_verify_url: idv_how_to_verify_url,
previous_step_url: @previous_step_url,
- locations_url: idv_in_person_usps_locations_url,
- address_search_url: '',
} %>
<%= simple_form_for(
:doc_auth,
diff --git a/app/views/session_timeout/_ping.html.erb b/app/views/session_timeout/_ping.html.erb
index 4a8aaa1b8fb..9c600645c3d 100644
--- a/app/views/session_timeout/_ping.html.erb
+++ b/app/views/session_timeout/_ping.html.erb
@@ -1,7 +1,6 @@
<%= tag.div id: 'session-timeout-cntnr',
data: {
timeout_url: new_user_session_url(timeout: :session, request_id: sp_session[:request_id]),
- sessions_url: api_internal_sessions_path,
warning: warning,
start: start,
frequency: frequency,
diff --git a/config/application.yml.default b/config/application.yml.default
index 0ab878f88cc..24e0c0ecfb4 100644
--- a/config/application.yml.default
+++ b/config/application.yml.default
@@ -199,7 +199,6 @@ min_password_score: 3
minimum_wait_before_another_usps_letter_in_hours: 24
mx_timeout: 3
new_device_alert_delay_in_minutes: 5
-no_verify_by_mail_for_biometric_comparison_enabled: true
openid_connect_redirect: client_side_js
openid_connect_content_security_form_action_enabled: false
openid_connect_redirect_uuid_override_map: '{}'
@@ -282,7 +281,7 @@ risc_notifications_rate_limit_max_requests: 1_000
risc_notifications_rate_limit_overrides: '{"https://example.com/push":{"interval":120,"max_requests":10000}}'
risc_notifications_request_timeout: 3
ruby_workers_idv_enabled: true
-rules_of_use_horizon_years: 5
+rules_of_use_horizon_years: 6
rules_of_use_updated_at: '2022-01-19T00:00:00Z' # Production has a newer timestamp than this, update directly in S3
s3_public_reports_enabled: false
s3_reports_enabled: false
@@ -468,7 +467,6 @@ production:
logins_per_ip_period: 20
logins_per_ip_track_only_mode: true
newrelic_license_key: ''
- no_verify_by_mail_for_biometric_comparison_enabled: false
openid_connect_redirect: server_side
openid_connect_content_security_form_action_enabled: true
otp_delivery_blocklist_findtime: 5
diff --git a/lib/identity_config.rb b/lib/identity_config.rb
index 5584cdc6549..773018ff91a 100644
--- a/lib/identity_config.rb
+++ b/lib/identity_config.rb
@@ -239,7 +239,6 @@ def self.store
config.add(:mx_timeout, type: :integer)
config.add(:new_device_alert_delay_in_minutes, type: :integer)
config.add(:newrelic_license_key, type: :string)
- config.add(:no_verify_by_mail_for_biometric_comparison_enabled, type: :boolean)
config.add(
:openid_connect_redirect,
type: :string,
diff --git a/lib/tasks/data_requests.rake b/lib/tasks/data_requests.rake
index 79fd6bbaaff..8727246f4b2 100644
--- a/lib/tasks/data_requests.rake
+++ b/lib/tasks/data_requests.rake
@@ -33,11 +33,6 @@ namespace :data_requests do
# export USERS_REPORT=/tmp/query-2020-11-17/user_report.json
# export OUTPUT_DIR=/tmp/query-2020-11-17/results/
- #
- # Optionally filter by start and/or end date
- # export START_DATE=2024-01-01
- # export END_DATE=2025-01-01
- #
# rake data_requests:process_users_report
desc 'Take a JSON user report, download logs from cloud watch, and write user data'
task process_users_report: :environment do
@@ -45,8 +40,6 @@ namespace :data_requests do
users_report = JSON.parse(File.read(ENV['USERS_REPORT']), symbolize_names: true)
output_dir = ENV['OUTPUT_DIR']
- start_date = Time.zone.parse(ENV['START_DATE']).to_date if ENV['START_DATE']
- end_date = Time.zone.parse(ENV['END_DATE']).to_date if ENV['END_DATE']
users_csv = CSV.open(File.join(output_dir, 'users.csv'), 'w')
user_events_csv = CSV.open(File.join(output_dir, 'user_events.csv'), 'w')
@@ -70,25 +63,12 @@ namespace :data_requests do
cloudwatch_dates = user_report[:user_events].pluck(:date_time).map do |date_time|
Time.zone.parse(date_time).to_date
- end.uniq.filter do |date|
- if start_date && date < start_date
- false
- elsif end_date && date > end_date
- false
- else
- true
- end
- end
-
- cloudwatch_results =
- if cloudwatch_dates.empty?
- []
- else
- DataRequests::Local::FetchCloudwatchLogs.new(
- user_report[:login_uuid],
- cloudwatch_dates,
- ).call
- end
+ end.uniq
+
+ cloudwatch_results = DataRequests::Local::FetchCloudwatchLogs.new(
+ user_report[:login_uuid],
+ cloudwatch_dates,
+ ).call
DataRequests::Local::WriteCloudwatchLogs.new(
cloudwatch_results:,
diff --git a/scripts/notify-slack b/scripts/notify-slack
deleted file mode 100755
index 52066f45598..00000000000
--- a/scripts/notify-slack
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'json'
-require 'net/http'
-require 'optparse'
-
-# Posts a message to Slack via webhook
-class NotifySlack
- def run(argv:, stdin:, stdout:)
- channel = nil
- username = nil
- text = nil
- webhook = nil
- icon = ':login-gov:'
- raise_on_failure = false
-
- program_name = File.basename($PROGRAM_NAME)
-
- parser = OptionParser.new do |opts|
- opts.banner = <<~STR
- #{program_name} [options]
-
- Usage:
-
- * Using arguments
-
- #{program_name} --text "my *message*" \\
- --channel "#some-channel" \\
- --webhook https://example.com/webhook
-
- * Passing text over STDIN
-
- echo "my *message*" | #{program_name} --text - \\
- --channel "#some-channel" \\
- --webhook https://example.com/webhook
-
- Options:
- STR
-
- opts.on('--channel CHANNEL', 'which channel to notify') do |channel_v|
- channel = channel_v
- end
-
- opts.on('--webhook WEBHOOK', 'Slack webhook URL') do |webhook_v|
- webhook = webhook_v
- end
-
- opts.on('--username USERNAME', 'which username to notify as') do |username_v|
- username = username_v
- end
-
- opts.on('--text TEXT', 'text of notification, pass - to read from STDIN') do |text_v|
- if text_v == '-'
- if stdin.tty?
- stdout.print 'please enter text of message: '
- text = stdin.gets
- else
- text = stdin.read
- end
- else
- text = text_v
- end
- end
-
- opts.on('--icon ICON', 'slack emoji to use as icon (optional)') do |icon_v|
- icon = icon_v
- end
-
- opts.on('--[no-]raise', <<~EOS) do |raise_v|
- raise errors/exit uncleanly if the webhook fails. defaults to not raising
- EOS
- raise_on_failure = raise_v
- end
-
- opts.on('--help') do
- puts opts
- exit 0
- end
- end
-
- parser.parse!(argv)
-
- if !channel || !username || !text || !webhook
- stdout.puts parser
- exit 1
- end
-
- notify(
- webhook: webhook,
- channel: channel,
- username: username,
- text: text,
- icon: format_icon(icon),
- )
- stdout.puts 'OK'
- rescue Net::HTTPClientException => err
- stdout.puts "#{program_name} HTTP ERROR: #{err.response.code}"
- raise err if raise_on_failure
- rescue => err
- stdout.puts "#{program_name} ERROR: #{err.message}"
- raise err if raise_on_failure
- end
-
- # @raise [Net::HTTPClientException] throws an error for non-successful response
- # @return [Net::HTTPResponse]
- def notify(webhook:, channel:, username:, text:, icon:)
- url = URI(webhook)
-
- req = Net::HTTP::Post.new(url)
- req.form_data = {
- 'payload' => {
- channel: channel,
- username: username,
- text: text,
- icon_emoji: icon,
- }.to_json,
- }
-
- Net::HTTP.start(
- url.hostname,
- url.port,
- use_ssl: url.scheme == 'https',
- open_timeout: 1,
- read_timeout: 1,
- write_timeout: 1,
- ssl_timeout: 1,
- ) do |http|
- http.request(req)
- end.value
- end
-
- def format_icon(icon)
- if icon.start_with?(':') && icon.end_with?(':')
- icon
- else
- ":#{icon}:"
- end
- end
-end
-
-if $PROGRAM_NAME == __FILE__
- NotifySlack.new.run(argv: ARGV, stdin: STDIN, stdout: STDOUT)
-end
diff --git a/spec/controllers/concerns/rate_limit_concern_spec.rb b/spec/controllers/concerns/rate_limit_concern_spec.rb
index 09ab0b02f16..9c324bb8f00 100644
--- a/spec/controllers/concerns/rate_limit_concern_spec.rb
+++ b/spec/controllers/concerns/rate_limit_concern_spec.rb
@@ -10,7 +10,6 @@ def self.name
include RateLimitConcern
include IdvSessionConcern
- include Idv::VerifyByMailConcern
def show
render plain: 'Hello'
diff --git a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
index d62f9818e8d..199513694a8 100644
--- a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
+++ b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb
@@ -453,14 +453,7 @@
end
let(:is_enhanced_ipp) { true }
let(:user) { create(:user, :with_pending_gpo_profile, created_at: 2.days.ago) }
- let(:gpo_verify_form) do
- GpoVerifyForm.new(
- user: user,
- pii: {},
- resolved_authn_context_result: Vot::Parser::Result.no_sp_result,
- otp: good_otp,
- )
- end
+ let(:gpo_verify_form) { GpoVerifyForm.new(user: user, pii: {}, otp: good_otp) }
before do
authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse
allow(controller).to(
diff --git a/spec/controllers/idv/by_mail/request_letter_controller_spec.rb b/spec/controllers/idv/by_mail/request_letter_controller_spec.rb
index bcee2c46ed0..8a5b0170dc8 100644
--- a/spec/controllers/idv/by_mail/request_letter_controller_spec.rb
+++ b/spec/controllers/idv/by_mail/request_letter_controller_spec.rb
@@ -26,6 +26,7 @@
:confirm_two_factor_authenticated,
:confirm_idv_needed,
:confirm_mail_not_rate_limited,
+ :confirm_profile_not_too_old,
)
end
@@ -43,7 +44,10 @@
get :index
expect(response).to have_http_status(200)
- expect(@analytics).to have_logged_event('IdV: request letter visited')
+ expect(@analytics).to have_logged_event(
+ 'IdV: request letter visited',
+ letter_already_sent: false,
+ )
end
it 'updates the doc auth log for the user for the usps_address_view event' do
@@ -56,58 +60,197 @@
end
it 'redirects if the user has sent too much mail' do
- allow(controller.gpo_verify_by_mail_policy).to receive(:rate_limited?).and_return(true)
+ allow(controller.gpo_mail_policy).to receive(:rate_limited?).and_return(true)
allow(subject.idv_session).to receive(:address_mechanism_chosen?).
and_return(true)
get :index
expect(response).to redirect_to idv_enter_password_path
end
- end
- describe '#create' do
- before do
- stub_verify_steps_one_and_two(user)
+ it 'allows a user to request another letter' do
+ allow(controller.gpo_mail_policy).to receive(:rate_limited?).and_return(false)
+ get :index
+
+ expect(response).to be_ok
end
- it 'invalidates future steps' do
- expect(subject).to receive(:clear_future_steps!)
+ context 'with letter already sent' do
+ before do
+ allow_any_instance_of(Idv::ByMail::RequestLetterPresenter).
+ to receive(:resend_requested?).and_return(true)
+ end
- put :create
+ it 'logs visited event' do
+ get :index
+
+ expect(@analytics).to have_logged_event(
+ 'IdV: request letter visited',
+ letter_already_sent: true,
+ )
+ end
end
- it 'sets session to :gpo and redirects' do
- expect(subject.idv_session.address_verification_mechanism).to be_nil
+ context 'user has a pending profile' do
+ let(:profile_created_at) { Time.zone.now }
+ let(:pending_profile) do
+ create(
+ :profile,
+ :with_pii,
+ user: user,
+ created_at: profile_created_at,
+ )
+ end
+ before do
+ allow(user).to receive(:pending_profile).and_return(pending_profile)
+ end
- put :create
+ it 'renders ok' do
+ get :index
+ expect(response).to be_ok
+ end
- expect(response).to redirect_to idv_enter_password_path
- expect(subject.idv_session.address_verification_mechanism).to eq :gpo
+ context 'but pending profile is too old to send another letter' do
+ let(:profile_created_at) { Time.zone.now - 31.days }
+ it 'redirects back to /verify' do
+ get :index
+ expect(response).to redirect_to(idv_path)
+ end
+ end
end
+ end
- it 'logs USPS address letter requested analytics event with phone step attempts' do
- RateLimiter.new(user: user, rate_limit_type: :proof_address).increment!
- put :create
+ describe '#create' do
+ context 'first time through the idv process' do
+ before do
+ stub_verify_steps_one_and_two(user)
+ end
- expect(@analytics).to have_logged_event(
- 'IdV: USPS address letter requested',
- hash_including(
- resend: false,
- phone_step_attempts: 1,
- first_letter_requested_at: nil,
- hours_since_first_letter: 0,
- **ab_test_args,
- ),
- )
+ it 'invalidates future steps' do
+ expect(subject).to receive(:clear_future_steps!)
+
+ put :create
+ end
+
+ it 'sets session to :gpo and redirects' do
+ expect(subject.idv_session.address_verification_mechanism).to be_nil
+
+ put :create
+
+ expect(response).to redirect_to idv_enter_password_path
+ expect(subject.idv_session.address_verification_mechanism).to eq :gpo
+ end
+
+ it 'logs USPS address letter requested analytics event with phone step attempts' do
+ RateLimiter.new(user: user, rate_limit_type: :proof_address).increment!
+ put :create
+
+ expect(@analytics).to have_logged_event(
+ 'IdV: USPS address letter requested',
+ hash_including(
+ resend: false,
+ phone_step_attempts: 1,
+ first_letter_requested_at: nil,
+ hours_since_first_letter: 0,
+ **ab_test_args,
+ ),
+ )
+ end
+
+ it 'updates the doc auth log for the user for the usps_letter_sent event' do
+ unstub_analytics
+ doc_auth_log = DocAuthLog.create(user_id: user.id)
+
+ expect { put :create }.to(
+ change { doc_auth_log.reload.usps_letter_sent_submit_count }.from(0).to(1),
+ )
+ end
end
- it 'updates the doc auth log for the user for the usps_letter_sent event' do
- unstub_analytics
- doc_auth_log = DocAuthLog.create(user_id: user.id)
+ context 'resending a letter' do
+ let(:has_pending_profile) { true }
+ let(:pending_profile) { create(:profile, :with_pii, :verify_by_mail_pending) }
- expect { put :create }.to(
- change { doc_auth_log.reload.usps_letter_sent_submit_count }.from(0).to(1),
- )
+ before do
+ stub_sign_in(user)
+ stub_user_with_pending_profile(user)
+ allow(user).to receive(:gpo_verification_pending_profile?).and_return(true)
+ subject.idv_session.welcome_visited = true
+ subject.idv_session.idv_consent_given = true
+ subject.idv_session.flow_path = 'standard'
+ subject.idv_session.resolution_successful = true
+ subject.idv_session.applicant = Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN
+ end
+
+ it 'calls the GpoConfirmationMaker to send another letter and redirects' do
+ expect_resend_letter_to_send_letter_and_redirect(otp: false)
+ end
+
+ it 'calls GpoConfirmationMaker to send another letter with reveal_gpo_code on' do
+ allow(FeatureManagement).to receive(:reveal_gpo_code?).and_return(true)
+ expect_resend_letter_to_send_letter_and_redirect(otp: true)
+ end
+
+ it 'logs USPS address letter analytics events with phone step attempts', :freeze_time do
+ RateLimiter.new(user: user, rate_limit_type: :proof_address).increment!
+ expect_resend_letter_to_send_letter_and_redirect(otp: false)
+
+ expect(@analytics).to have_logged_event(
+ 'IdV: USPS address letter requested',
+ hash_including(
+ resend: true,
+ phone_step_attempts: 1,
+ first_letter_requested_at: pending_profile.gpo_verification_pending_at,
+ hours_since_first_letter: 24,
+ **ab_test_args,
+ ),
+ )
+
+ expect(@analytics).to have_logged_event(
+ 'IdV: USPS address letter enqueued',
+ hash_including(
+ resend: true,
+ first_letter_requested_at: pending_profile.gpo_verification_pending_at,
+ hours_since_first_letter: 24,
+ enqueued_at: Time.zone.now,
+ phone_step_attempts: 1,
+ proofing_components: nil,
+ **ab_test_args,
+ ),
+ )
+ end
+
+ it 'redirects to capture password if pii is locked' do
+ pii_cacher = instance_double(Pii::Cacher)
+ allow(pii_cacher).to receive(:fetch).and_return(nil)
+ allow(pii_cacher).to receive(:exists_in_session?).and_return(false)
+ allow(Pii::Cacher).to receive(:new).and_return(pii_cacher)
+
+ put :create
+
+ expect(response).to redirect_to capture_password_path
+ end
end
end
+
+ def expect_resend_letter_to_send_letter_and_redirect(otp:)
+ pii = pending_profile.decrypt_pii(user.password).to_h
+ pii_cacher = instance_double(Pii::Cacher)
+ allow(pii_cacher).to receive(:fetch).with(pending_profile.id).and_return(pii)
+ allow(pii_cacher).to receive(:exists_in_session?).and_return(true)
+ allow(Pii::Cacher).to receive(:new).and_return(pii_cacher)
+
+ service_provider = create(:service_provider, issuer: '123abc')
+ session[:sp] = { issuer: service_provider.issuer, vtr: ['C1'] }
+
+ gpo_confirmation_maker = instance_double(GpoConfirmationMaker)
+ allow(GpoConfirmationMaker).to receive(:new).
+ with(pii: pii, service_provider: service_provider, profile: pending_profile).
+ and_return(gpo_confirmation_maker)
+
+ expect(gpo_confirmation_maker).to receive(:perform)
+ expect(gpo_confirmation_maker).to receive(:otp) if otp
+ expect { put :create }.to change { ActionMailer::Base.deliveries.count }.by(1)
+ expect(response).to redirect_to idv_letter_enqueued_path
+ end
end
diff --git a/spec/controllers/idv/by_mail/resend_letter_controller_spec.rb b/spec/controllers/idv/by_mail/resend_letter_controller_spec.rb
index 88d5bad68c8..15670d3f2f6 100644
--- a/spec/controllers/idv/by_mail/resend_letter_controller_spec.rb
+++ b/spec/controllers/idv/by_mail/resend_letter_controller_spec.rb
@@ -1,17 +1,11 @@
require 'rails_helper'
-RSpec.describe Idv::ByMail::ResendLetterController,
- allowed_extra_analytics: [:sample_bucket1, :sample_bucket2] do
+RSpec.describe Idv::ByMail::ResendLetterController do
let(:user) { create(:user) }
- let(:ab_test_args) do
- { sample_bucket1: :sample_value1, sample_bucket2: :sample_value2 }
- end
-
before do
stub_sign_in(user)
stub_analytics
- allow(subject).to receive(:ab_test_analytics_buckets).and_return(ab_test_args)
end
describe '#new' do
diff --git a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb
index 88f77fd2e31..17f4be87a7c 100644
--- a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb
+++ b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb
@@ -7,6 +7,7 @@
before do
stub_analytics
+ stub_sign_in(user)
allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).
and_return(in_person_proofing_enabled)
allow(IdentityConfig.store).to receive(:in_person_proofing_enforce_tmx).
@@ -26,117 +27,97 @@
subject(:response) { get :show }
it 'renders not found' do
- stub_sign_in(user)
expect(response.status).to eq 404
end
context 'with in person proofing enabled' do
let(:in_person_proofing_enabled) { true }
- context 'authenticated' do
- before do
- stub_sign_in(user)
- end
+ it 'redirects to account page' do
+ expect(response).to redirect_to account_url
+ end
+
+ context 'with enrollment' do
+ let(:user) { create(:user, :with_pending_in_person_enrollment) }
+ let(:profile) { create(:profile, :with_pii, user: user) }
- it 'redirects to account page' do
- expect(response).to redirect_to account_url
+ it 'renders show template' do
+ expect(response).to render_template :show
end
- context 'with enrollment' do
- let(:user) { create(:user, :with_pending_in_person_enrollment) }
- let(:profile) { create(:profile, :with_pii, user: user) }
+ it 'logs analytics' do
+ response
- it 'renders show template' do
- expect(response).to render_template :show
- end
+ expect(@analytics).to have_logged_event('IdV: in person ready to verify visited')
+ end
- it 'logs analytics' do
+ context 'with in_person_proofing_enforce_tmx disabled and pending fraud review' do
+ let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
+ let!(:enrollment) { create(:in_person_enrollment, :passed, user: user, profile: profile) }
+ it 'redirects to please call page' do
response
- expect(@analytics).to have_logged_event('IdV: in person ready to verify visited')
- end
-
- context 'with in_person_proofing_enforce_tmx disabled and pending fraud review' do
- let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
- let!(:enrollment) do
- create(:in_person_enrollment, :passed, user: user, profile: profile)
- end
- it 'redirects to please call page' do
- response
-
- expect(response).not_to render_template :show
- expect(response).to redirect_to idv_please_call_url
- end
+ expect(response).not_to render_template :show
+ expect(response).to redirect_to idv_please_call_url
end
+ end
- context 'in_person_proofing_enforce_tmx enabled, pending fraud review, enrollment pass' do
- let(:in_person_proofing_enforce_tmx) { true }
- let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
- let!(:enrollment) do
- create(:in_person_enrollment, :passed, user: user, profile: profile)
- end
+ context 'in_person_proofing_enforce_tmx enabled, pending fraud review, enrollment passed' do
+ let(:in_person_proofing_enforce_tmx) { true }
+ let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
+ let!(:enrollment) { create(:in_person_enrollment, :passed, user: user, profile: profile) }
- it 'redirects to please call' do
- response
+ it 'redirects to please call' do
+ response
- expect(response).to redirect_to idv_please_call_url
- end
+ expect(response).to redirect_to idv_please_call_url
end
+ end
- context 'in_person_proofing_enforce_tmx enabled, pending fraud review,
+ context 'in_person_proofing_enforce_tmx enabled, pending fraud review,
enrollment not passed' do
- let(:in_person_proofing_enforce_tmx) { true }
- let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
- let!(:enrollment) do
- create(:in_person_enrollment, :establishing, user: user, profile: profile)
- end
-
- it 'does not redirect to please call' do
- response
-
- expect(response).to render_template :show
- expect(response).not_to redirect_to idv_please_call_url
- end
+ let(:in_person_proofing_enforce_tmx) { true }
+ let!(:profile) { create(:profile, fraud_review_pending_at: 1.day.ago, user: user) }
+ let!(:enrollment) do
+ create(:in_person_enrollment, :establishing, user: user, profile: profile)
end
- context 'when vtr (vector of trust) does not include Enhanced Proofing (Pe)' do
- before do
- resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pb').parse
+ it 'does not redirect to please call' do
+ response
- allow(controller).to receive(:resolved_authn_context_result).
- and_return(resolved_authn_context_result)
- end
+ expect(response).to render_template :show
+ expect(response).not_to redirect_to idv_please_call_url
+ end
+ end
- it 'evaluates to In Person Proofing' do
- response
+ context 'when vtr (vector of trust) does not include Enhanced Proofing (Pe)' do
+ before do
+ resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pb').parse
- expect(assigns(:is_enhanced_ipp)).to be false
- end
+ allow(controller).to receive(:resolved_authn_context_result).
+ and_return(resolved_authn_context_result)
end
- context 'when vtr (vector of trust) includes Enhanced Proofing (Pe)' do
- before do
- resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse
+ it 'evaluates to In Person Proofing' do
+ response
- allow(controller).to receive(:resolved_authn_context_result).
- and_return(resolved_authn_context_result)
- end
+ expect(assigns(:is_enhanced_ipp)).to be false
+ end
+ end
- it 'evaluates to Enhanced IPP' do
- response
+ context 'when vtr (vector of trust) includes Enhanced Proofing (Pe)' do
+ before do
+ resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse
- expect(assigns(:is_enhanced_ipp)).to be true
- end
+ allow(controller).to receive(:resolved_authn_context_result).
+ and_return(resolved_authn_context_result)
end
- end
- end
- context 'with hybrid session' do
- let(:in_person_proofing_enforce_tmx) { true }
- it 'redirects to root' do
- controller.session[:doc_capture_user_id] = user.id
+ it 'evaluates to Enhanced IPP' do
+ response
- expect(response).to redirect_to(new_user_session_url)
+ expect(assigns(:is_enhanced_ipp)).to be true
+ end
end
end
end
diff --git a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb
index aed47ea128e..8d0a7228a43 100644
--- a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb
+++ b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb
@@ -4,6 +4,7 @@
let(:user) { create(:user) }
let(:sp) { nil }
let(:in_person_proofing_enabled) { true }
+ let(:empty_locations) { [] }
let(:address) do
UspsInPersonProofing::Applicant.new(
address: '1600 Pennsylvania Ave',
@@ -38,12 +39,10 @@
end
describe '#index' do
- let(:locale) { nil }
let(:proofer) { double('Proofer') }
let(:locations) do
[
- UspsInPersonProofing::PostOffice.new(
- address: '3118 WASHINGTON BLVD',
+ { address: '3118 WASHINGTON BLVD',
city: 'ARLINGTON',
distance: '6.02 mi',
name: 'ARLINGTON',
@@ -52,10 +51,8 @@
sunday_hours: 'Closed',
weekday_hours: '9:00 AM - 5:00 PM',
zip_code_4: '9998',
- zip_code_5: '22201',
- ),
- UspsInPersonProofing::PostOffice.new(
- address: '4005 WISCONSIN AVE NW',
+ zip_code_5: '22201' },
+ { address: '4005 WISCONSIN AVE NW',
city: 'WASHINGTON',
distance: '6.59 mi',
name: 'FRIENDSHIP',
@@ -64,10 +61,8 @@
sunday_hours: '10:00 AM - 4:00 PM',
weekday_hours: '8:00 AM - 6:00 PM',
zip_code_4: '9997',
- zip_code_5: '20016',
- ),
- UspsInPersonProofing::PostOffice.new(
- address: '6900 WISCONSIN AVE STE 100',
+ zip_code_5: '20016' },
+ { address: '6900 WISCONSIN AVE STE 100',
city: 'CHEVY CHASE',
distance: '8.99 mi',
name: 'BETHESDA',
@@ -76,13 +71,11 @@
sunday_hours: 'Closed',
weekday_hours: '9:00 AM - 5:00 PM',
zip_code_4: '9996',
- zip_code_5: '20815',
- ),
+ zip_code_5: '20815' },
]
end
subject(:response) do
- post :index, params: { locale: locale,
- address: { street_address: '1600 Pennsylvania Ave',
+ post :index, params: { address: { street_address: '1600 Pennsylvania Ave',
city: 'Washington',
state: 'DC',
zip_code: '20500' } }
@@ -136,7 +129,7 @@
context 'no addresses found by usps' do
before do
allow(proofer).to receive(:request_facilities).with(address, false).
- and_return([])
+ and_return(empty_locations)
end
it 'logs analytics with error when successful response is empty' do
@@ -172,32 +165,6 @@
response_status_code: nil,
)
end
-
- context 'with non-English locale' do
- let(:locale) { 'fr' }
-
- it 'returns content in selected locale' do
- json = response.body
-
- expect(json).to include(
- I18n.t('in_person_proofing.body.barcode.retail_hours_closed', locale: locale),
- )
- I18n.locale = locale
- facilities = JSON.parse(json)
-
- facilities.zip(locations).each do |facility, location|
- expect(facility['weekday_hours']).to eq(
- UspsInPersonProofing::EnrollmentHelper.localized_hours(location[:weekday_hours]),
- )
- expect(facility['saturday_hours']).to eq(
- UspsInPersonProofing::EnrollmentHelper.localized_hours(location[:saturday_hours]),
- )
- expect(facility['sunday_hours']).to eq(
- UspsInPersonProofing::EnrollmentHelper.localized_hours(location[:sunday_hours]),
- )
- end
- end
- end
end
context 'with a timeout from Faraday' do
diff --git a/spec/controllers/users/delete_controller_spec.rb b/spec/controllers/users/delete_controller_spec.rb
index e5afa1f93d9..c5c4d113907 100644
--- a/spec/controllers/users/delete_controller_spec.rb
+++ b/spec/controllers/users/delete_controller_spec.rb
@@ -44,12 +44,13 @@
end
it 'logs a failed submit' do
- user = stub_signed_in_user
- stub_analytics(user:)
+ stub_analytics
+ stub_signed_in_user
- delete
+ expect(@analytics).to receive(:track_event).
+ with('Account Delete submitted', success: false)
- expect(@analytics).to have_logged_event('Account Delete submitted', success: false)
+ delete
end
end
@@ -81,12 +82,13 @@
end
it 'logs a succesful submit' do
- user = stub_signed_in_user
- stub_analytics(user:)
+ stub_analytics
+ stub_signed_in_user
- delete
+ expect(@analytics).to receive(:track_event).
+ with('Account Delete submitted', success: true)
- expect(@analytics).to have_logged_event('Account Delete submitted', success: true)
+ delete
end
it 'does not delete identities to prevent uuid reuse' do
diff --git a/spec/controllers/users/piv_cac_login_controller_spec.rb b/spec/controllers/users/piv_cac_login_controller_spec.rb
index 3853a61b023..75c99da9d05 100644
--- a/spec/controllers/users/piv_cac_login_controller_spec.rb
+++ b/spec/controllers/users/piv_cac_login_controller_spec.rb
@@ -2,10 +2,8 @@
RSpec.describe Users::PivCacLoginController do
describe 'GET new' do
- let(:user) {}
-
before do
- stub_analytics(user:)
+ stub_analytics
end
context 'without a token' do
@@ -49,6 +47,7 @@
end
context 'with a valid token' do
+ let(:user) {}
let(:service_provider) { create(:service_provider) }
let(:sp_session) { { ial: 1, issuer: service_provider.issuer, vtr: vtr } }
let(:nonce) { SecureRandom.base64(20) }
@@ -69,6 +68,7 @@
controller.session[:sp] = sp_session
allow(PivCacService).to receive(:decode_token).with(token) { data }
+ stub_analytics(user:)
end
context 'without a valid user' do
diff --git a/spec/controllers/vendor_outage_controller_spec.rb b/spec/controllers/vendor_outage_controller_spec.rb
index 3ceb6600733..07d879161ac 100644
--- a/spec/controllers/vendor_outage_controller_spec.rb
+++ b/spec/controllers/vendor_outage_controller_spec.rb
@@ -21,11 +21,7 @@
before { allow(controller).to receive(:from_idv_phone?).and_return(true) }
context 'gpo letter available' do
- before do
- stub_sign_in
- allow(controller.gpo_verify_by_mail_policy).to receive(:send_letter_available?).
- and_return(true)
- end
+ before { allow(controller).to receive(:gpo_letter_available?).and_return(true) }
it 'sets show_gpo_option as true' do
get :show
diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb
index f3a70efe348..2da550bb912 100644
--- a/spec/features/idv/analytics_spec.rb
+++ b/spec/features/idv/analytics_spec.rb
@@ -460,7 +460,9 @@
active_profile_idv_level: nil, pending_profile_idv_level: nil,
proofing_components: base_proofing_components
},
- 'IdV: request letter visited' => {},
+ 'IdV: request letter visited' => {
+ letter_already_sent: false,
+ },
:idv_enter_password_visited => {
address_verification_method: 'gpo', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil,
active_profile_idv_level: nil, pending_profile_idv_level: nil,
@@ -673,7 +675,7 @@
'IdV: doc auth image upload form submitted' => {
success: true, errors: {}, error_details: nil, submit_attempts: 1, remaining_submit_attempts: 3, user_id: user.uuid, flow_path: 'standard', front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), selfie_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: false, doc_auth_result: 'Passed'),
+ 'IdV: doc auth image upload vendor submitted' => hash_including(success: true, flow_path: 'standard', attention_with_barcode: false, doc_auth_result: 'Passed', liveness_checking_required: boolean),
'IdV: doc auth image upload vendor pii validation' => {
success: true, errors: {}, error_details: nil, user_id: user.uuid, submit_attempts: 1, remaining_submit_attempts: 3, flow_path: 'standard', attention_with_barcode: false, front_image_fingerprint: an_instance_of(String), back_image_fingerprint: an_instance_of(String), selfie_image_fingerprint: an_instance_of(String), liveness_checking_required: boolean, classification_info: {}, id_issued_status: 'present', id_expiration_status: 'present'
},
@@ -774,7 +776,6 @@
and_return(proofing_device_profiling)
allow_any_instance_of(ApplicationController).to receive(:analytics) do |controller|
fake_analytics.user = controller.analytics_user
- fake_analytics.session = controller.session
fake_analytics
end
allow(IdentityConfig.store).to receive(:idv_acuant_sdk_upgrade_a_b_testing_enabled).
diff --git a/spec/features/idv/cancel_spec.rb b/spec/features/idv/cancel_spec.rb
index 0eddb6e18d0..9f2592914be 100644
--- a/spec/features/idv/cancel_spec.rb
+++ b/spec/features/idv/cancel_spec.rb
@@ -13,11 +13,7 @@
start_idv_from_sp(sp)
sign_in_and_2fa_user(user)
complete_doc_auth_steps_before_agreement_step
-
- allow_any_instance_of(ApplicationController).to receive(:analytics) do |controller|
- fake_analytics.session = controller.session
- fake_analytics
- end
+ allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
end
it 'shows the user a cancellation message with the option to go back to the step' do
diff --git a/spec/features/idv/steps/request_letter_step_spec.rb b/spec/features/idv/steps/request_letter_step_spec.rb
index 1c144b7473e..6c32f38a1de 100644
--- a/spec/features/idv/steps/request_letter_step_spec.rb
+++ b/spec/features/idv/steps/request_letter_step_spec.rb
@@ -4,6 +4,19 @@
include IdvStepHelper
include OidcAuthHelper
+ let(:minimum_wait_for_letter) { 24 }
+ let(:days_passed) { max_days_before_resend_disabled + 1 }
+ let(:max_days_before_resend_disabled) { 30 }
+
+ before do
+ allow(IdentityConfig.store).to receive(:minimum_wait_before_another_usps_letter_in_hours).
+ and_return(minimum_wait_for_letter)
+ allow(IdentityConfig.store).to receive(:gpo_max_profile_age_to_send_letter_in_days).
+ and_return(max_days_before_resend_disabled)
+ allow(IdentityConfig.store).to receive(:second_mfa_reminder_account_age_in_days).
+ and_return(days_passed + 1)
+ end
+
it 'visits and completes the enter password step when the user chooses verify by letter', :js do
start_idv_from_sp
complete_idv_steps_before_gpo_step
@@ -16,6 +29,142 @@
expect(page).to have_content(t('idv.messages.gpo.letter_on_the_way'))
end
+ context 'the user has sent a letter but not verified an OTP' do
+ let(:user) { user_with_2fa }
+
+ before do
+ # Without this, the check for GPO expiration leaves an expired
+ # OTP rate limiter laying around.
+ allow(IdentityConfig.store).to receive(:otp_delivery_blocklist_maxretry).and_return(3)
+ end
+
+ it 'if not rate limited, allow user to resend letter & redirect to letter enqueued step', :js do
+ complete_idv_by_mail_and_sign_out
+
+ # rate-limited because too little time has passed
+ sign_in_live_with_2fa(user)
+ confirm_rate_limited
+ sign_out
+
+ # still rate-limited because too little time has passed
+ travel_to((minimum_wait_for_letter - 1).hours.from_now) do
+ sign_in_live_with_2fa(user)
+ confirm_rate_limited
+ sign_out
+ end
+
+ # will be rate-limted after expiration
+ travel_to(days_passed.days.from_now) do
+ sign_in_live_with_2fa(user)
+ confirm_rate_limited
+ sign_out
+ # Clear MFA SMS message from the future to allow re-logging in with test helper
+ Telephony::Test::Message.clear_messages
+ end
+
+ # can re-request after the waiting period
+ travel_to((minimum_wait_for_letter + 1).hours.from_now) do
+ sign_in_live_with_2fa(user)
+ click_on t('idv.messages.gpo.resend')
+
+ # Confirm that we show the correct content on
+ # the GPO page for users requesting re-send
+ expect(page).to have_content(t('idv.gpo.request_another_letter.title'))
+ expect(page).to have_content(
+ strip_tags(t('idv.gpo.request_another_letter.instructions_html')),
+ )
+ expect(page).to have_content(t('idv.gpo.request_another_letter.button'))
+ expect(page).to_not have_content(t('idv.messages.gpo.info_alert'))
+
+ # Ensure user can go back from this page
+ click_doc_auth_back_link
+ expect(page).to have_content(t('idv.gpo.title'))
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+ expect_user_to_be_unverified(user)
+ click_on t('idv.messages.gpo.resend')
+
+ # And then actually ask for a resend
+ expect { click_on t('idv.gpo.request_another_letter.button') }.
+ to change { GpoConfirmation.count }.from(1).to(2)
+ expect_user_to_be_unverified(user)
+ expect(page).to have_content(t('idv.messages.gpo.another_letter_on_the_way'))
+ expect(page).to have_content(t('idv.titles.come_back_later'))
+ expect(page).to have_current_path(idv_letter_enqueued_path)
+
+ # Confirm that user cannot visit other IdV pages while unverified
+ visit idv_agreement_path
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+ visit idv_ssn_url
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+ visit idv_verify_info_url
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+
+ # complete verification: end to end gpo test
+ sign_out
+ sign_in_live_with_2fa(user)
+
+ complete_gpo_verification(user)
+ expect(user.identity_verified?).to be(true)
+ expect(page).to_not have_content(t('account.index.verification.reactivate_button'))
+ end
+ end
+
+ context 'logged in with PIV/CAC and no password' do
+ it 'does not 500' do
+ create(:profile, :with_pii, user: user, gpo_verification_pending_at: 1.day.ago)
+ create(:gpo_confirmation_code, profile: user.pending_profile)
+ create(:piv_cac_configuration, user: user, x509_dn_uuid: 'helloworld', name: 'My PIV Card')
+
+ signin_with_piv(user)
+ fill_in t('account.index.password'), with: user.password
+ click_button t('forms.buttons.submit.default')
+
+ complete_gpo_verification(user)
+
+ expect(user.identity_verified?).to be(true)
+
+ expect(page).to_not have_content(t('account.index.verification.reactivate_button'))
+ end
+ end
+
+ def complete_idv_by_mail_and_sign_out
+ start_idv_from_sp
+ complete_idv_steps_before_gpo_step(user)
+ click_on t('idv.buttons.mail.send')
+ fill_in 'Password', with: user_password
+ click_continue
+ sign_out
+ end
+
+ def expect_user_to_be_unverified(user)
+ expect(user.events.account_verified.size).to be(0)
+ expect(user.profiles.count).to eq 1
+
+ profile = user.profiles.first
+
+ expect(profile.active?).to eq false
+ expect(profile.gpo_verification_pending?).to eq true
+ end
+
+ def sign_out
+ visit sign_out_url
+ end
+
+ def confirm_rate_limited
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+ expect(page).not_to have_link(
+ t('idv.messages.gpo.resend'),
+ )
+ # does not allow the user to go to the resend page manually
+ visit idv_request_letter_path
+
+ expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
+ expect(page).not_to have_link(
+ t('idv.messages.gpo.resend'),
+ )
+ end
+ end
+
context 'GPO verified user has reset their password and needs to re-verify with GPO again', :js do
let(:user) { user_verified_with_gpo }
diff --git a/spec/features/idv/steps/resend_letter_step_spec.rb b/spec/features/idv/steps/resend_letter_step_spec.rb
deleted file mode 100644
index ab10aae5d6c..00000000000
--- a/spec/features/idv/steps/resend_letter_step_spec.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-require 'rails_helper'
-
-RSpec.feature 'idv resend letter step', allowed_extra_analytics: [:*] do
- include IdvStepHelper
- include OidcAuthHelper
-
- let(:minimum_wait_for_letter) { 24 }
- let(:days_passed) { max_days_before_resend_disabled + 1 }
- let(:max_days_before_resend_disabled) { 30 }
-
- before do
- allow(IdentityConfig.store).to receive(:minimum_wait_before_another_usps_letter_in_hours).
- and_return(minimum_wait_for_letter)
- allow(IdentityConfig.store).to receive(:gpo_max_profile_age_to_send_letter_in_days).
- and_return(max_days_before_resend_disabled)
- allow(IdentityConfig.store).to receive(:second_mfa_reminder_account_age_in_days).
- and_return(days_passed + 1)
- end
-
- let(:user) { user_with_2fa }
-
- before do
- # Without this, the check for GPO expiration leaves an expired
- # OTP rate limiter laying around.
- allow(IdentityConfig.store).to receive(:otp_delivery_blocklist_maxretry).and_return(3)
- end
-
- it 'if not rate limited, allow user to resend letter & redirect to letter enqueued step', :js do
- complete_idv_by_mail_and_sign_out
-
- # rate-limited because too little time has passed
- sign_in_live_with_2fa(user)
- confirm_rate_limited
- sign_out
-
- # still rate-limited because too little time has passed
- travel_to((minimum_wait_for_letter - 1).hours.from_now) do
- sign_in_live_with_2fa(user)
- confirm_rate_limited
- sign_out
- end
-
- # will be rate-limted after expiration
- travel_to(days_passed.days.from_now) do
- sign_in_live_with_2fa(user)
- confirm_rate_limited
- sign_out
- # Clear MFA SMS message from the future to allow re-logging in with test helper
- Telephony::Test::Message.clear_messages
- end
-
- # can re-request after the waiting period
- travel_to((minimum_wait_for_letter + 1).hours.from_now) do
- sign_in_live_with_2fa(user)
- click_on t('idv.messages.gpo.resend')
-
- # Confirm that we show the correct content on
- # the GPO page for users requesting re-send
- expect(page).to have_content(t('idv.gpo.request_another_letter.title'))
- expect(page).to have_content(
- strip_tags(t('idv.gpo.request_another_letter.instructions_html')),
- )
- expect(page).to have_content(t('idv.gpo.request_another_letter.button'))
- expect(page).to_not have_content(t('idv.messages.gpo.info_alert'))
-
- # Ensure user can go back from this page
- click_doc_auth_back_link
- expect(page).to have_content(t('idv.gpo.title'))
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
- expect_user_to_be_unverified(user)
- click_on t('idv.messages.gpo.resend')
-
- # And then actually ask for a resend
- expect { click_on t('idv.gpo.request_another_letter.button') }.
- to change { GpoConfirmation.count }.from(1).to(2)
- expect_user_to_be_unverified(user)
- expect(page).to have_content(t('idv.messages.gpo.another_letter_on_the_way'))
- expect(page).to have_content(t('idv.titles.come_back_later'))
- expect(page).to have_current_path(idv_letter_enqueued_path)
-
- # Confirm that user cannot visit other IdV pages while unverified
- visit idv_agreement_path
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
- visit idv_ssn_url
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
- visit idv_verify_info_url
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
-
- # complete verification: end to end gpo test
- sign_out
- sign_in_live_with_2fa(user)
-
- complete_gpo_verification(user)
- expect(user.identity_verified?).to be(true)
- expect(page).to_not have_content(t('account.index.verification.reactivate_button'))
- end
- end
-
- context 'logged in with PIV/CAC and no password' do
- it 'does not 500' do
- create(:profile, :with_pii, user: user, gpo_verification_pending_at: 1.day.ago)
- create(:gpo_confirmation_code, profile: user.pending_profile)
- create(:piv_cac_configuration, user: user, x509_dn_uuid: 'helloworld', name: 'My PIV Card')
-
- signin_with_piv(user)
- fill_in t('account.index.password'), with: user.password
- click_button t('forms.buttons.submit.default')
-
- complete_gpo_verification(user)
-
- expect(user.identity_verified?).to be(true)
-
- expect(page).to_not have_content(t('account.index.verification.reactivate_button'))
- end
- end
-
- def complete_idv_by_mail_and_sign_out
- start_idv_from_sp
- complete_idv_steps_before_gpo_step(user)
- click_on t('idv.buttons.mail.send')
- fill_in 'Password', with: user_password
- click_continue
- sign_out
- end
-
- def expect_user_to_be_unverified(user)
- expect(user.events.account_verified.size).to be(0)
- expect(user.profiles.count).to eq 1
-
- profile = user.profiles.first
-
- expect(profile.active?).to eq false
- expect(profile.gpo_verification_pending?).to eq true
- end
-
- def sign_out
- visit sign_out_url
- end
-
- def confirm_rate_limited
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
- expect(page).not_to have_link(
- t('idv.messages.gpo.resend'),
- )
- # does not allow the user to go to the resend page manually
- visit idv_request_letter_path
-
- expect(page).to have_current_path(idv_verify_by_mail_enter_code_path)
- expect(page).not_to have_link(
- t('idv.messages.gpo.resend'),
- )
- end
-end
diff --git a/spec/forms/gpo_verify_form_spec.rb b/spec/forms/gpo_verify_form_spec.rb
index 5960098c39b..774213f7805 100644
--- a/spec/forms/gpo_verify_form_spec.rb
+++ b/spec/forms/gpo_verify_form_spec.rb
@@ -2,12 +2,7 @@
RSpec.describe GpoVerifyForm, allowed_extra_analytics: [:*] do
subject(:form) do
- GpoVerifyForm.new(
- user: user,
- pii: applicant,
- resolved_authn_context_result: Vot::Parser::Result.no_sp_result,
- otp: entered_otp,
- )
+ GpoVerifyForm.new(user: user, pii: applicant, otp: entered_otp)
end
let(:user) { create(:user, :fully_registered) }
diff --git a/spec/forms/recaptcha_enterprise_form_spec.rb b/spec/forms/recaptcha_enterprise_form_spec.rb
index 1d9858d8b2e..2e32736c455 100644
--- a/spec/forms/recaptcha_enterprise_form_spec.rb
+++ b/spec/forms/recaptcha_enterprise_form_spec.rb
@@ -270,46 +270,6 @@
form_class: 'RecaptchaEnterpriseForm',
)
end
-
- context 'with low confidence score as one of the reasons for failure' do
- before do
- stub_recaptcha_response(
- body: {
- tokenProperties: { valid: true, action: },
- riskAnalysis: { score:, reasons: ['LOW_CONFIDENCE_SCORE'] },
- event: {},
- name:,
- },
- action:,
- token:,
- )
- end
-
- it 'is successful with assessment id' do
- response, assessment_id = result
-
- expect(response.to_h).to eq(success: true)
- expect(assessment_id).to eq(name)
- end
-
- it 'logs analytics of the body' do
- result
-
- expect(analytics).to have_logged_event(
- 'reCAPTCHA verify result received',
- recaptcha_result: {
- success: true,
- score:,
- reasons: ['LOW_CONFIDENCE_SCORE'],
- errors: [],
- assessment_id: name,
- },
- evaluated_as_valid: true,
- score_threshold: score_threshold,
- form_class: 'RecaptchaEnterpriseForm',
- )
- end
- end
end
context 'with successful score from validation service' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a84e0a83bad..fa8143236da 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -567,7 +567,7 @@
end
describe '#accepted_rules_of_use_still_valid?' do
- let(:rules_of_use_horizon_years) { 5 }
+ let(:rules_of_use_horizon_years) { 6 }
let(:rules_of_use_updated_at) { 1.day.ago }
let(:accepted_terms_at) { nil }
let(:user) { create(:user, :fully_registered, accepted_terms_at: accepted_terms_at) }
@@ -601,9 +601,9 @@
end
context 'with a user who accepted the rules of use more than 6 years ago' do
- let(:rules_of_use_horizon_years) { 5 }
- let(:rules_of_use_updated_at) { 6.years.ago }
- let(:accepted_terms_at) { 5.years.ago - 1.day }
+ let(:rules_of_use_horizon_years) { 6 }
+ let(:rules_of_use_updated_at) { 7.years.ago }
+ let(:accepted_terms_at) { 6.years.ago - 1.day }
it 'should return a falsey value' do
expect(user.accepted_rules_of_use_still_valid?).to be_falsey
diff --git a/spec/policies/idv/gpo_verify_by_mail_policy_spec.rb b/spec/policies/idv/gpo_verify_by_mail_policy_spec.rb
index 02c2062e361..179c321b6a8 100644
--- a/spec/policies/idv/gpo_verify_by_mail_policy_spec.rb
+++ b/spec/policies/idv/gpo_verify_by_mail_policy_spec.rb
@@ -3,14 +3,8 @@
require 'rails_helper'
RSpec.describe Idv::GpoVerifyByMailPolicy do
- let(:subject) { described_class.new(user, resolved_authn_context_result) }
+ let(:subject) { described_class.new(user) }
let(:user) { create(:user) }
- let(:two_pieces_of_fair_evidence) { false }
- let(:resolved_authn_context_result) do
- Vot::Parser::Result.no_sp_result.with(
- two_pieces_of_fair_evidence?: two_pieces_of_fair_evidence,
- )
- end
describe '#resend_letter_available?' do
context 'when the feature flag is off' do
@@ -70,10 +64,6 @@
and_return true
end
- it 'returns true when the user is not rate-limited' do
- expect(subject.send_letter_available?).to eq true
- end
-
it 'returns false when the user is rate-limited' do
enqueue_gpo_letter_for(user, at_time: 4.days.ago)
enqueue_gpo_letter_for(user, at_time: 3.days.ago)
@@ -86,26 +76,6 @@
create(:profile, :verify_by_mail_pending, user: user, created_at: 90.days.ago)
expect(subject.send_letter_available?).to eq true
end
-
- context 'the 2 pieces of fair evidence requirement is present' do
- let(:two_pieces_of_fair_evidence) { true }
-
- it 'returns false when the feature flag is enabled' do
- allow(IdentityConfig.store).to receive(
- :no_verify_by_mail_for_biometric_comparison_enabled,
- ).and_return(true)
-
- expect(subject.send_letter_available?).to eq(false)
- end
-
- it 'returns true when the feature flag is disabled' do
- allow(IdentityConfig.store).to receive(
- :no_verify_by_mail_for_biometric_comparison_enabled,
- ).and_return(false)
-
- expect(subject.send_letter_available?).to eq(true)
- end
- end
end
end
diff --git a/spec/presenters/idv/by_mail/request_letter_presenter_spec.rb b/spec/presenters/idv/by_mail/request_letter_presenter_spec.rb
new file mode 100644
index 00000000000..629b02c76d0
--- /dev/null
+++ b/spec/presenters/idv/by_mail/request_letter_presenter_spec.rb
@@ -0,0 +1,91 @@
+require 'rails_helper'
+
+RSpec.describe Idv::ByMail::RequestLetterPresenter do
+ include Rails.application.routes.url_helpers
+
+ let(:user) { create(:user) }
+
+ subject(:decorator) do
+ described_class.new(user, {})
+ end
+
+ describe '#title' do
+ context 'a letter has not been sent' do
+ it 'provides text to send' do
+ expect(subject.title).to eq(
+ I18n.t('idv.titles.mail.verify'),
+ )
+ end
+ end
+
+ context 'a letter has been sent' do
+ before do
+ allow(user).to receive(:gpo_verification_pending_profile).and_return(true)
+ end
+ it 'provides text to resend' do
+ create_letter_send_event
+
+ expect(subject.title).to eq(
+ I18n.t('idv.gpo.request_another_letter.title'),
+ )
+ end
+ end
+
+ context 'the user has verified with GPO before, but is re-proofing' do
+ let(:user) { user_verified_with_gpo }
+ it 'provides text to send' do
+ create_letter_send_event
+ expect(subject.title).to eq(
+ I18n.t('idv.titles.mail.verify'),
+ )
+ end
+ end
+ end
+
+ describe '#button' do
+ let(:user) { create(:user) }
+ context 'a letter has not been sent' do
+ it 'provides text to send' do
+ expect(subject.button).to eq(
+ I18n.t('idv.buttons.mail.send'),
+ )
+ end
+ end
+
+ context 'a letter has been sent' do
+ before do
+ allow(user).to receive(:gpo_verification_pending_profile).and_return(true)
+ end
+ it 'provides text to resend' do
+ create_letter_send_event
+ expect(subject.button).to eq(
+ I18n.t('idv.gpo.request_another_letter.button'),
+ )
+ end
+ end
+ end
+
+ describe '#fallback_back_path' do
+ context 'when the user has a pending profile' do
+ it 'returns the verify account path' do
+ create(:profile, user: user, gpo_verification_pending_at: 1.day.ago)
+ expect(subject.fallback_back_path).to eq(idv_verify_by_mail_enter_code_path)
+ end
+ end
+
+ context 'when the user does not have a pending profile' do
+ it 'returns the idv phone path' do
+ expect(subject.fallback_back_path).to eq(idv_phone_path)
+ end
+ end
+ end
+
+ def create_letter_send_event
+ device = create(:device, user: user)
+ create(:event, user: user, device: device, event_type: :gpo_mail_sent)
+ end
+
+ def user_verified_with_gpo
+ create(:user, :proofed_with_gpo)
+ end
+end
diff --git a/spec/requests/openid_connect_userinfo_spec.rb b/spec/requests/openid_connect_userinfo_spec.rb
index b09f4e61294..8d28b4bbbd3 100644
--- a/spec/requests/openid_connect_userinfo_spec.rb
+++ b/spec/requests/openid_connect_userinfo_spec.rb
@@ -16,19 +16,5 @@
headers: { 'HTTP_AUTHORIZATION' => authorization_header }
expect(response.headers['Set-Cookie']).to_not include(APPLICATION_SESSION_COOKIE_KEY)
end
-
- it 'returns error with blank Bearer Token' do
- identity = create(
- :service_provider_identity,
- rails_session_id: SecureRandom.hex,
- access_token: nil,
- user: create(:user),
- )
- authorization_header = 'Bearer'
- OutOfBandSessionAccessor.new(identity.rails_session_id).put_empty_user_session(50)
- get api_openid_connect_userinfo_path,
- headers: { 'HTTP_AUTHORIZATION' => authorization_header }
- expect(response).to be_unauthorized
- end
end
end
diff --git a/spec/scripts/notify-slack_spec.rb b/spec/scripts/notify-slack_spec.rb
deleted file mode 100644
index 6ddf1903e4a..00000000000
--- a/spec/scripts/notify-slack_spec.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'spec_helper'
-require 'rack/utils'
-load File.expand_path('../../scripts/notify-slack', __dir__)
-
-RSpec.describe NotifySlack do
- subject(:notifier) { described_class.new }
-
- let(:webhook) { 'https://slack.example.com/abcdef/ghijkl' }
- let(:channel) { '#fun-channel' }
- let(:username) { 'notifier-bot' }
- let(:text) { 'my message' }
- let(:icon) { ':red_circle:' }
-
- describe '#run' do
- let(:argv) do
- [
- '--webhook',
- webhook,
- '--channel',
- channel,
- '--username',
- username,
- '--text',
- text,
- '--icon', icon
- ]
- end
- let(:stdin) { StringIO.new }
- let(:stdout) { StringIO.new }
-
- subject(:run) do
- notifier.run(argv:, stdin:, stdout:)
- end
-
- before do
- allow(notifier).to receive(:exit)
- end
-
- context 'missing required argument' do
- before do
- argv.delete('--webhook')
- argv.delete(webhook)
- end
-
- it 'prints help and exits uncleanly' do
- expect(notifier).to receive(:exit).with(1)
-
- run
-
- expect(stdout.string).to include('Usage')
- end
- end
-
- it 'notifies' do
- post_request = stub_request(:post, webhook)
-
- run
-
- expect(post_request).to have_been_made
- end
-
- context 'network error' do
- before do
- stub_request(:post, webhook).to_return(status: 500)
- end
-
- it 'prints an error and exits cleanly' do
- expect(notifier).to_not receive(:exit)
-
- run
-
- expect(stdout.string).to include('ERROR: 500')
- end
-
- context 'with --raise' do
- before { argv << '--raise' }
-
- it 'raises an error' do
- expect { run }.to raise_error(Net::HTTPExceptions)
- end
- end
- end
- end
-
- describe '#notify' do
- subject(:notify) do
- notifier.notify(webhook:, channel:, username:, text:, icon:)
- end
-
- it 'POSTs JSON inside of form encoding to the webhook' do
- post_request = stub_request(:post, webhook).with(
- headers: {
- content_type: 'application/x-www-form-urlencoded',
- },
- ) do |req|
- form = Rack::Utils.parse_query(req.body)
- expect(JSON.parse(form['payload'], symbolize_names: true)).to eq(
- channel:,
- username:,
- text:,
- icon_emoji: icon,
- )
- end
-
- notify
-
- expect(post_request).to have_been_made
- end
- end
-
- describe '#format_icon' do
- it 'adds colons around icon names if missing' do
- expect(notifier.format_icon('joy')).to eq(':joy:')
- end
-
- it 'leaves colons around icon names if present' do
- expect(notifier.format_icon(':sob:')).to eq(':sob:')
- end
- end
-end
diff --git a/spec/services/gpo_confirmation_uploader_spec.rb b/spec/services/gpo_confirmation_uploader_spec.rb
index 8b95c27fb22..4612d1882fc 100644
--- a/spec/services/gpo_confirmation_uploader_spec.rb
+++ b/spec/services/gpo_confirmation_uploader_spec.rb
@@ -71,28 +71,6 @@
subject
end
-
- context 'when an SSH error occurs' do
- it 'retries the upload' do
- expect(Net::SFTP).to receive(:start).twice.with(*sftp_options).and_yield(sftp_connection)
- expect(sftp_connection).to receive(:upload!).once.and_raise(Net::SSH::ConnectionTimeout)
- expect(sftp_connection).to receive(:upload!).once
-
- subject
- end
-
- it 'raises after 5 unsuccessful retries' do
- expect(Net::SFTP).to receive(:start).
- exactly(5).times.
- with(*sftp_options).
- and_yield(sftp_connection)
- expect(sftp_connection).to receive(:upload!).
- exactly(5).times.
- and_raise(Net::SSH::ConnectionTimeout)
-
- expect { subject }.to raise_error(Net::SSH::ConnectionTimeout)
- end
- end
end
describe '#run' do
diff --git a/spec/services/gpo_reminder_sender_spec.rb b/spec/services/gpo_reminder_sender_spec.rb
index a8ce6708be2..797937626b7 100644
--- a/spec/services/gpo_reminder_sender_spec.rb
+++ b/spec/services/gpo_reminder_sender_spec.rb
@@ -175,9 +175,6 @@ def set_reminder_sent_at(to_time)
GpoVerifyForm.new(
user: user,
pii: Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE,
- resolved_authn_context_result: Vot::Parser::Result.no_sp_result.with(
- enhanced_ipp?: is_enhanced_ipp,
- ),
otp: otp,
).submit(is_enhanced_ipp)
end
diff --git a/spec/services/idv/analytics_events_enhancer_spec.rb b/spec/services/idv/analytics_events_enhancer_spec.rb
index a553f623b4e..874e23f4069 100644
--- a/spec/services/idv/analytics_events_enhancer_spec.rb
+++ b/spec/services/idv/analytics_events_enhancer_spec.rb
@@ -3,15 +3,7 @@
RSpec.describe Idv::AnalyticsEventsEnhancer do
let(:user) { build(:user) }
let(:sp) { nil }
- let(:user_session) { nil }
- let(:session) do
- if user_session.present?
- {
- 'warden.user.user.session' => user_session,
- }
- end
- end
-
+ let(:session) { nil }
let(:analytics_class) do
Class.new(FakeAnalytics) do
include AnalyticsEvents
@@ -71,7 +63,11 @@ def track_event(_event, **kwargs)
end
describe 'proofing_components' do
- let(:user_session) { {} }
+ let(:proofing_components) { nil }
+
+ before do
+ user.proofing_component = proofing_components
+ end
context 'without proofing component' do
it 'calls analytics method with original attributes' do
@@ -83,26 +79,17 @@ def track_event(_event, **kwargs)
end
end
- context 'with proofing components' do
- before do
- # Set up the user_session so it looks like the user's been through doc auth
- idv_session = Idv::Session.new(
- user_session:,
- current_user: user,
- service_provider: sp,
- )
- idv_session.pii_from_doc = Idp::Constants::MOCK_IDV_APPLICANT
+ context 'with proofing component' do
+ let(:proofing_components) do
+ ProofingComponent.new(source_check: Idp::Constants::Vendors::AAMVA)
end
it 'calls analytics method with original attributes and proofing_components' do
analytics.idv_test_method(extra: true)
- expect(analytics.called_kwargs).to eql(
+ expect(analytics.called_kwargs).to match(
extra: true,
- proofing_components: {
- document_check: 'mock',
- document_type: 'state_id',
- },
+ proofing_components: kind_of(Idv::ProofingComponentsLogging),
)
end
end
diff --git a/spec/services/idv/proofing_components_logging_spec.rb b/spec/services/idv/proofing_components_logging_spec.rb
new file mode 100644
index 00000000000..b270a722c8d
--- /dev/null
+++ b/spec/services/idv/proofing_components_logging_spec.rb
@@ -0,0 +1,12 @@
+require 'rails_helper'
+
+RSpec.describe Idv::ProofingComponentsLogging do
+ describe '#as_json' do
+ it 'returns hash with nil values omitted' do
+ proofing_components = ProofingComponent.new(document_check: Idp::Constants::Vendors::AAMVA)
+ logging = described_class.new(proofing_components)
+
+ expect(logging.as_json).to eq('document_check' => Idp::Constants::Vendors::AAMVA)
+ end
+ end
+end
diff --git a/spec/services/idv/proofing_components_spec.rb b/spec/services/idv/proofing_components_spec.rb
deleted file mode 100644
index d6bd1b81b73..00000000000
--- a/spec/services/idv/proofing_components_spec.rb
+++ /dev/null
@@ -1,243 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Idv::ProofingComponents do
- let(:user) { create(:user) }
-
- let(:user_session) { {} }
-
- let(:idv_session) do
- Idv::Session.new(
- current_user: user,
- user_session:,
- service_provider: nil,
- ).tap do |idv_session|
- idv_session.pii_from_doc = pii_from_doc
- end
- end
-
- let(:pii_from_doc) { nil }
-
- subject do
- described_class.new(
- user:,
- idv_session:,
- )
- end
-
- describe '#to_h' do
- let(:pii_from_doc) { Idp::Constants::MOCK_IDV_APPLICANT }
-
- before do
- allow(IdentityConfig.store).to receive(:doc_auth_vendor).and_return('test_vendor')
- idv_session.mark_verify_info_step_complete!
- idv_session.address_verification_mechanism = 'gpo'
- allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?).
- and_return(true)
- idv_session.threatmetrix_review_status = 'pass'
- end
-
- it 'returns expected result' do
- expect(subject.to_h).to eql(
- {
- document_check: 'test_vendor',
- document_type: 'state_id',
- source_check: 'aamva',
- resolution_check: 'lexis_nexis',
- address_check: 'gpo_letter',
- threatmetrix: true,
- threatmetrix_review_status: 'pass',
- },
- )
- end
- end
-
- describe '#document_check' do
- it 'returns nil by default' do
- expect(subject.document_check).to be_nil
- end
-
- context 'in-person proofing' do
- context 'establishing' do
- let!(:enrollment) { create(:in_person_enrollment, :establishing, user:) }
- it 'returns USPS' do
- expect(subject.document_check).to eql(Idp::Constants::Vendors::USPS)
- end
- end
-
- context 'pending' do
- let!(:enrollment) { create(:in_person_enrollment, :pending, user:) }
- it 'returns USPS' do
- expect(subject.document_check).to eql(Idp::Constants::Vendors::USPS)
- end
- end
- end
-
- context 'doc auth' do
- before do
- allow(IdentityConfig.store).to receive(:doc_auth_vendor).and_return('test_vendor')
- end
- context 'before doc auth complete' do
- it 'returns nil' do
- expect(subject.document_check).to be_nil
- end
- end
- context 'after doc auth completed successfully' do
- let(:pii_from_doc) { Idp::Constants::MOCK_IDV_APPLICANT }
- it 'returns doc auth vendor' do
- expect(subject.document_check).to eql('test_vendor')
- end
- end
- end
- end
-
- describe '#document_type' do
- context 'in-person proofing' do
- context 'establishing' do
- let!(:enrollment) { create(:in_person_enrollment, :establishing, user:) }
- it 'returns nil' do
- expect(subject.document_type).to be_nil
- end
- end
-
- context 'pending' do
- let!(:enrollment) { create(:in_person_enrollment, :pending, user:) }
- it 'returns nil' do
- expect(subject.document_type).to be_nil
- end
- end
- end
-
- context 'doc auth' do
- context 'before doc auth complete' do
- it 'returns nil' do
- expect(subject.document_type).to be_nil
- end
- end
- context 'after doc auth completed successfully' do
- let(:pii_from_doc) { Idp::Constants::MOCK_IDV_APPLICANT }
- it 'returns doc auth vendor' do
- expect(subject.document_type).to eql('state_id')
- end
- end
- end
- end
-
- describe '#source_check' do
- it 'returns nil by default' do
- expect(subject.source_check).to be_nil
- end
-
- context 'after verification' do
- before do
- idv_session.mark_verify_info_step_complete!
- end
-
- it 'returns aamva' do
- expect(subject.source_check).to eql(Idp::Constants::Vendors::AAMVA)
- end
- end
- end
-
- describe '#resolution_check' do
- it 'returns nil by default' do
- expect(subject.resolution_check).to be_nil
- end
-
- context 'after verification' do
- before do
- idv_session.mark_verify_info_step_complete!
- end
-
- it 'returns LexisNexis' do
- expect(subject.resolution_check).to eql(Idp::Constants::Vendors::LEXIS_NEXIS)
- end
- end
- end
-
- describe '#address_check' do
- it 'returns nil by default' do
- expect(subject.address_check).to be_nil
- end
-
- context 'in GPO flow' do
- before do
- idv_session.address_verification_mechanism = 'gpo'
- end
-
- it 'returns gpo_letter' do
- expect(subject.address_check).to eql('gpo_letter')
- end
- end
-
- context 'using phone verification' do
- before do
- idv_session.mark_phone_step_started!
- end
-
- it 'returns lexis_nexis_address' do
- expect(subject.address_check).to eql('lexis_nexis_address')
- end
- end
- end
-
- describe '#threatmetrix' do
- context 'device profiling collecting enabled' do
- before do
- allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?).
- and_return(true)
- end
-
- context 'threatmetrix_review_status present' do
- before do
- idv_session.threatmetrix_review_status = 'pass'
- end
- it 'returns true' do
- expect(subject.threatmetrix).to be_truthy
- end
- end
- context 'threatmetrix_review_status not present' do
- it 'returns nil' do
- expect(subject.threatmetrix).to be_nil
- end
- end
- end
-
- context 'device profiling collecting disabled' do
- before do
- allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?).
- and_return(false)
- end
-
- context 'threatmetrix_review_status present' do
- before do
- idv_session.threatmetrix_review_status = 'pass'
- end
- it 'returns false' do
- expect(subject.threatmetrix).to eql(false)
- end
- end
-
- context 'threatmetrix_review_status not present' do
- it 'returns nil' do
- expect(subject.threatmetrix).to be_nil
- end
- end
- end
- end
-
- describe '#threatmetrix_review_status' do
- context 'threatmetrix_review_status present in idv_session' do
- before do
- idv_session.threatmetrix_review_status = 'pass'
- end
- it 'returns value' do
- expect(subject.threatmetrix_review_status).to eql('pass')
- end
- end
- context 'threatmetrix_review_status not present in idv_session' do
- it 'returns nil' do
- expect(subject.threatmetrix_review_status).to be_nil
- end
- end
- end
-end
diff --git a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb
index 03575d66993..91c905eaf1d 100644
--- a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb
+++ b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb
@@ -23,7 +23,6 @@
end
let(:proofer) { UspsInPersonProofing::Mock::Proofer.new }
let(:is_enhanced_ipp) { false }
- let(:usps_ipp_sponsor_id) { '2718281828' }
before(:each) do
stub_request_token
@@ -39,7 +38,6 @@
allow(subject).to receive(:analytics).and_return(subject_analytics)
allow(IdentityConfig.store).to receive(:usps_ipp_transliteration_enabled).
and_return(usps_ipp_transliteration_enabled)
- allow(IdentityConfig.store).to receive(:usps_ipp_sponsor_id).and_return(usps_ipp_sponsor_id)
end
describe '#schedule_in_person_enrollment' do
@@ -181,14 +179,10 @@
end
end
- it <<~STR.squish do
- sets enrollment status to pending, sponsor_id to usps_ipp_sponsor_id,
- and sets established at date and unique id
- STR
+ it 'sets enrollment status to pending and sets established at date and unique id' do
subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:)
expect(user.in_person_enrollments.first.status).to eq(InPersonEnrollment::STATUS_PENDING)
- expect(user.in_person_enrollments.first.sponsor_id).to eq(usps_ipp_sponsor_id)
expect(user.in_person_enrollments.first.enrollment_established_at).to_not be_nil
expect(user.in_person_enrollments.first.unique_id).to_not be_nil
end
@@ -337,26 +331,10 @@
allow(proofer).to receive(:request_enroll).and_call_original
end
context 'when the user is going through enhanced ipp' do
- let!(:enrollment) do
- create(
- :in_person_enrollment,
- user: user,
- service_provider: service_provider,
- status: :establishing,
- profile: nil,
- )
- end
-
it 'creates an enhanced ipp enrollment' do
expect(proofer).to receive(:request_enroll).with(applicant, is_enhanced_ipp)
subject.create_usps_enrollment(enrollment, pii, is_enhanced_ipp)
end
-
- it 'saves sponsor_id on the enrollment to the usps_eipp_sponsor_id' do
- subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:)
-
- expect(user.in_person_enrollments.first.sponsor_id).to eq(usps_eipp_sponsor_id)
- end
end
end
diff --git a/spec/support/analytics_helper.rb b/spec/support/analytics_helper.rb
index 1c2ae7fe23a..0f7e125a0c3 100644
--- a/spec/support/analytics_helper.rb
+++ b/spec/support/analytics_helper.rb
@@ -3,8 +3,8 @@ def stub_analytics(user: nil)
analytics = FakeAnalytics.new
if user
- allow(controller).to receive(:analytics).and_wrap_original do |original|
- expect(original.call.user).to eq(user)
+ allow(controller).to receive(:analytics) do
+ expect(controller.analytics_user).to eq(user)
analytics
end
else
diff --git a/spec/support/controller_helper.rb b/spec/support/controller_helper.rb
index 7e8b1f15d10..d8c33b1c171 100644
--- a/spec/support/controller_helper.rb
+++ b/spec/support/controller_helper.rb
@@ -19,9 +19,6 @@ def stub_sign_in(user = build(:user, password: VALID_PASSWORD))
allow(controller).to receive(:user_session).and_return({}.with_indifferent_access)
controller.auth_methods_session.authenticate!(TwoFactorAuthenticatable::AuthMethod::SMS)
allow(controller).to receive(:current_user).and_return(user)
- allow(controller).to receive(:sign_out) do
- allow(controller).to receive(:current_user).and_return(nil)
- end
allow(controller).to receive(:confirm_two_factor_authenticated).and_return(true)
allow(controller).to receive(:user_fully_authenticated?).and_return(true)
allow(controller).to receive(:remember_device_expired_for_sp?).and_return(false)
diff --git a/spec/support/fake_analytics.rb b/spec/support/fake_analytics.rb
index a8dbe00ca24..e456e629275 100644
--- a/spec/support/fake_analytics.rb
+++ b/spec/support/fake_analytics.rb
@@ -150,7 +150,6 @@ def option_param_names(instance_method)
attr_reader :events
attr_accessor :user
- attr_accessor :session
def initialize(user: AnonymousUser.new, sp: nil, session: nil)
@events = Hash.new
@@ -160,7 +159,7 @@ def initialize(user: AnonymousUser.new, sp: nil, session: nil)
end
def track_event(event, attributes = {})
- if attributes[:proofing_components].instance_of?(Idv::ProofingComponents)
+ if attributes[:proofing_components].instance_of?(Idv::ProofingComponentsLogging)
attributes[:proofing_components] = attributes[:proofing_components].as_json.symbolize_keys
end
events[event] ||= []
diff --git a/spec/views/accounts/show.html.erb_spec.rb b/spec/views/accounts/show.html.erb_spec.rb
index 7e0cf6fbd3e..0734dc6c0f5 100644
--- a/spec/views/accounts/show.html.erb_spec.rb
+++ b/spec/views/accounts/show.html.erb_spec.rb
@@ -5,7 +5,6 @@
before do
allow(view).to receive(:current_user).and_return(user)
- allow(view).to receive(:user_session).and_return({})
assign(
:presenter,
AccountShowPresenter.new(
@@ -90,8 +89,6 @@
end
it 'does not render phone' do
- render
-
expect(view).to_not render_template(partial: '_phone')
end
end
@@ -119,8 +116,6 @@
let(:user) { create(:user, :fully_registered, :with_authentication_app) }
it 'does not render piv/cac' do
- render
-
expect(view).to_not render_template(partial: '_piv_cac')
end
end
@@ -128,6 +123,10 @@
context 'user has a piv/cac' do
let(:user) { create(:user, :fully_registered, :with_piv_or_cac) }
+ before do
+ allow(view).to receive(:user_session).and_return({})
+ end
+
it 'renders the piv/cac section' do
render
diff --git a/spec/views/idv/by_mail/enter_code/index.html.erb_spec.rb b/spec/views/idv/by_mail/enter_code/index.html.erb_spec.rb
index a855c021384..7ec1c4d16f8 100644
--- a/spec/views/idv/by_mail/enter_code/index.html.erb_spec.rb
+++ b/spec/views/idv/by_mail/enter_code/index.html.erb_spec.rb
@@ -21,7 +21,6 @@
@gpo_verify_form = GpoVerifyForm.new(
user: user,
pii: pii,
- resolved_authn_context_result: Vot::Parser::Result.no_sp_result,
otp: '1234',
)
diff --git a/spec/views/idv/by_mail/request_letter/index.html.erb_spec.rb b/spec/views/idv/by_mail/request_letter/index.html.erb_spec.rb
index b01459d71a9..6c581ad775c 100644
--- a/spec/views/idv/by_mail/request_letter/index.html.erb_spec.rb
+++ b/spec/views/idv/by_mail/request_letter/index.html.erb_spec.rb
@@ -1,10 +1,14 @@
require 'rails_helper'
RSpec.describe 'idv/by_mail/request_letter/index.html.erb' do
- let(:user) { build(:user) }
+ let(:resend_requested) { false }
+ let(:user_needs_address_otp_verification) { false }
let(:go_back_path) { nil }
let(:step_indicator_steps) { Idv::StepIndicatorConcern::STEP_INDICATOR_STEPS }
- let(:idv_by_mail_only) { false }
+ let(:presenter) do
+ user = build_stubbed(:user, :fully_registered)
+ Idv::ByMail::RequestLetterPresenter.new(user, {})
+ end
let(:address1) { 'applicant address 1' }
let(:address2) { nil }
@@ -13,11 +17,14 @@
let(:zipcode) { 'applicant zipcode' }
before do
- allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:go_back_path).and_return(go_back_path)
allow(view).to receive(:step_indicator_steps).and_return(step_indicator_steps)
- allow(FeatureManagement).to receive(:idv_by_mail_only?).and_return(idv_by_mail_only)
+ allow(presenter).to receive(:resend_requested?).and_return(resend_requested)
+ allow(presenter).to receive(:user_needs_address_otp_verification?).
+ and_return(user_needs_address_otp_verification)
+
+ @presenter = presenter
@applicant = {
address1: 'applicant address 1',
city: 'applicant city',
@@ -60,11 +67,44 @@
end
end
- context 'idv_by_mail_only is enabled' do
- let(:idv_by_mail_only) { true }
+ context 'letter already sent' do
+ let(:resend_requested) { true }
+
+ it 'has the right title' do
+ expect(rendered).to have_css('h1', text: t('idv.gpo.request_another_letter.title'))
+ end
+
+ it 'has the right body' do
+ expect(rendered).to have_text(
+ strip_tags(t('idv.gpo.request_another_letter.instructions_html')),
+ )
+ end
+
+ it 'includes link to help' do
+ expect(rendered).to have_link(
+ t('idv.gpo.request_another_letter.learn_more_link'),
+ href: help_center_redirect_url(
+ category: 'verify-your-identity',
+ article: 'verify-your-address-by-mail',
+ flow: :idv,
+ step: :gpo_send_letter,
+ ),
+ )
+ end
+
+ it 'does not include troubleshooting options' do
+ expect(rendered).not_to have_css('.troubleshooting-options')
+ end
+ end
+
+ context 'user needs address otp verification' do
+ let(:user_needs_address_otp_verification) { true }
- it 'returns a cancel link' do
- expect(rendered).to have_link(t('links.cancel'), href: idv_cancel_path(step: 'gpo'))
+ it 'renders fallback link to return to verify path' do
+ expect(rendered).to have_link(
+ '‹ ' + t('forms.buttons.back'),
+ href: idv_verify_by_mail_enter_code_path,
+ )
end
end
end