diff --git a/.gitignore b/.gitignore index 18d6f95f197..260d1f099d0 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,9 @@ .vagrant .capistrano +# avoid checking in stray files +*.bak + # root files capybara-*.html dump.rdb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 113ee609299..62f6d2243a5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -97,11 +97,11 @@ build-review-image: needs: [] interruptible: true variables: - BRANCH_TAGGING_STRING: "" + BRANCH_TAGGING_STRING: '' rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH variables: - BRANCH_TAGGING_STRING: "--destination ${ECR_REGISTRY}/identity-idp/review:main" + BRANCH_TAGGING_STRING: '--destination ${ECR_REGISTRY}/identity-idp/review:main' - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - if: $CI_PIPELINE_SOURCE != "merge_request_event" when: never @@ -312,14 +312,14 @@ build-ci-image: - build-pool image: name: gcr.io/kaniko-project/executor:debug - entrypoint: [""] + entrypoint: [''] rules: # Build when there are changes to the Dockerfile - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "external_pull_request_event" || $CI_PIPELINE_SOURCE == "web"' changes: compare_to: 'refs/heads/main' paths: - - dockerfiles/idp_ci.Dockerfile + - dockerfiles/idp_ci.Dockerfile script: - mkdir -p /kaniko/.docker - |- @@ -489,25 +489,37 @@ include: secret_detection: allow_failure: false variables: - SECRET_DETECTION_LOG_OPTIONS: origin/${CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME}..HEAD - SECRET_DETECTION_REPORT_FILE: "gl-secret-detection-report.json" + SECRET_DETECTION_EXCLUDED_PATHS: 'keys.example,config/artifacts.example,public/acuant/*/opencv.min.js,tmp/0.0.0.0-3000.key' + SECRET_DETECTION_REPORT_FILE: 'gl-secret-detection-report.json' rules: - if: $SECRET_DETECTION_DISABLED when: never - if: '$CI_COMMIT_BRANCH || $CI_COMMIT_TAG' + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main" + variables: + SECRET_DETECTION_LOG_OPTIONS: origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..HEAD + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "main" && $CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME == "main" + variables: + SECRET_DETECTION_LOG_OPTIONS: origin/${CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME}..HEAD before_script: - apk add --no-cache jq + - git fetch origin --quiet script: - - /analyzer run - # check if '{ "vulnerabilities": [], ..' is empty in the report file if it exists - | - if [ -f "$SECRET_DETECTION_REPORT_FILE" ]; then - if [ "$(jq ".vulnerabilities | length" $SECRET_DETECTION_REPORT_FILE)" -gt 0 ]; then - echo "Vulnerabilities detected. Please analyze the artifact $SECRET_DETECTION_REPORT_FILE produced by the 'secret-detection' job." - exit 80 + if [ -z "$SECRET_DETECTION_LOG_OPTIONS" ]; then + /analyzer run + if [ -f "$SECRET_DETECTION_REPORT_FILE" ]; then + # check if '{ "vulnerabilities": [], ..' is empty in the report file if it exists + if [ "$(jq ".vulnerabilities | length" $SECRET_DETECTION_REPORT_FILE)" -gt 0 ]; then + echo "Vulnerabilities detected. Please analyze the artifact $SECRET_DETECTION_REPORT_FILE produced by the 'secret-detection' job." + exit 80 + fi + else + echo "Artifact $SECRET_DETECTION_REPORT_FILE does not exist. The 'secret-detection' job likely didn't create one. Hence, no evaluation can be performed." fi else - echo "Artifact $SECRET_DETECTION_REPORT_FILE does not exist. The 'secret-detection' job likely didn't create one. Hence, no evaluation can be performed." + echo "Skipping because this is not a PR or is not targeting main" + exit 0 fi .container_scan_template: @@ -517,7 +529,7 @@ secret_detection: - build-pool image: name: amazon/aws-cli - entrypoint: [""] + entrypoint: [''] before_script: - curl -LO https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64 - chmod +x jq-linux64 @@ -636,7 +648,7 @@ secret_detection: } end' > gl-container-scanning-report.json artifacts: - paths: + paths: - gl-container-scanning-report.json reports: container_scanning: gl-container-scanning-report.json @@ -663,7 +675,7 @@ ecr-scan-ci: changes: compare_to: 'refs/heads/main' paths: - - dockerfiles/idp_ci.Dockerfile + - dockerfiles/idp_ci.Dockerfile needs: - job: build-ci-image stage: scan diff --git a/.rubocop.yml b/.rubocop.yml index 4b01c32efb0..de889dd8439 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,6 +6,7 @@ require: - rubocop-rails - rubocop-performance + - ./lib/linters/analytics_event_name_linter.rb - ./lib/linters/localized_validation_message_linter.rb - ./lib/linters/image_size_linter.rb - ./lib/linters/mail_later_linter.rb @@ -43,6 +44,11 @@ Bundler/InsecureProtocolSource: Gemspec/DuplicatedAssignment: Enabled: true +IdentityIdp/AnalyticsEventNameLinter: + Enabled: true + Include: + - app/services/analytics_events.rb + IdentityIdp/LocalizedValidationMessageLinter: Enabled: true diff --git a/app/controllers/concerns/idv/document_capture_concern.rb b/app/controllers/concerns/idv/document_capture_concern.rb index 58038bda659..fc8078c443f 100644 --- a/app/controllers/concerns/idv/document_capture_concern.rb +++ b/app/controllers/concerns/idv/document_capture_concern.rb @@ -30,7 +30,6 @@ def failure(message, extra = nil) end # @param [DocAuth::Response, - # DocumentCaptureSessionAsyncResult, # DocumentCaptureSessionResult] response def extract_pii_from_doc(user, response, store_in_session: false) pii_from_doc = response.pii_from_doc.merge( diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index 3560c6c4224..eeedbf5d82c 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -34,7 +34,7 @@ def shared_update user_id: current_user.id, threatmetrix_session_id: idv_session.threatmetrix_session_id, request_ip: request.remote_ip, - double_address_verification: capture_secondary_id_enabled, + double_address_verification: double_address_verification, ) return true @@ -42,9 +42,11 @@ def shared_update private - def capture_secondary_id_enabled - current_user.establishing_in_person_enrollment&. - capture_secondary_id_enabled || false + def double_address_verification + # If in person return true else return false. This is temporary until we add a feature flag + # to track enrollment was created in the in person flow. + # todo LG-11235 update value based on new feature flag + current_user.has_in_person_enrollment? end def should_use_aamva?(pii) @@ -164,7 +166,7 @@ def process_async_state(current_async_state) return end - return if confirm_not_rate_limited + return if confirm_not_rate_limited_after_doc_auth if current_async_state.none? idv_session.invalidate_verify_info_step! diff --git a/app/controllers/concerns/idv_step_concern.rb b/app/controllers/concerns/idv_step_concern.rb index b643c810ff4..036c841944f 100644 --- a/app/controllers/concerns/idv_step_concern.rb +++ b/app/controllers/concerns/idv_step_concern.rb @@ -9,7 +9,6 @@ module IdvStepConcern included do before_action :confirm_two_factor_authenticated before_action :confirm_idv_needed - before_action :confirm_not_rate_limited before_action :confirm_no_pending_gpo_profile before_action :confirm_no_pending_in_person_enrollment before_action :handle_fraud diff --git a/app/controllers/concerns/rate_limit_concern.rb b/app/controllers/concerns/rate_limit_concern.rb index 8ada2c10913..75d48d0a179 100644 --- a/app/controllers/concerns/rate_limit_concern.rb +++ b/app/controllers/concerns/rate_limit_concern.rb @@ -1,9 +1,11 @@ module RateLimitConcern extend ActiveSupport::Concern - def confirm_not_rate_limited + ALL_IDV_RATE_LIMITTERS = [:idv_resolution, :idv_doc_auth, :proof_address, :proof_ssn].freeze + + def confirm_not_rate_limited(rate_limiters = ALL_IDV_RATE_LIMITTERS) rate_limited = false - %i[idv_resolution idv_doc_auth proof_address proof_ssn].each do |rate_limit_type| + rate_limiters.each do |rate_limit_type| if rate_limit_redirect!(rate_limit_type) rate_limited = true break @@ -12,6 +14,16 @@ def confirm_not_rate_limited rate_limited end + def confirm_not_rate_limited_after_doc_auth + rate_limitters = [:idv_resolution, :proof_ssn, :proof_address] + confirm_not_rate_limited(rate_limitters) + end + + def confirm_not_rate_limited_after_idv_resolution + rate_limitters = [:proof_address] + confirm_not_rate_limited(rate_limitters) + end + def rate_limit_redirect!(rate_limit_type) if idv_attempter_rate_limited?(rate_limit_type) track_rate_limited_event(rate_limit_type) diff --git a/app/controllers/idv/address_controller.rb b/app/controllers/idv/address_controller.rb index 6c7fcf03d9d..8efc1c4679c 100644 --- a/app/controllers/idv/address_controller.rb +++ b/app/controllers/idv/address_controller.rb @@ -2,6 +2,7 @@ module Idv class AddressController < ApplicationController include IdvStepConcern + before_action :confirm_not_rate_limited_after_doc_auth before_action :confirm_document_capture_complete def new diff --git a/app/controllers/idv/agreement_controller.rb b/app/controllers/idv/agreement_controller.rb index d2bf36c5a72..9cd06b3a3e8 100644 --- a/app/controllers/idv/agreement_controller.rb +++ b/app/controllers/idv/agreement_controller.rb @@ -3,6 +3,7 @@ class AgreementController < ApplicationController include IdvStepConcern include StepIndicatorConcern + before_action :confirm_not_rate_limited before_action :confirm_welcome_step_complete before_action :confirm_agreement_needed @@ -53,7 +54,7 @@ def skip_to_capture end def consent_form_params - params.require(:doc_auth).permit([:ial2_consent_given, :idv_consent_given]) + params.require(:doc_auth).permit(:idv_consent_given) end def confirm_welcome_step_complete diff --git a/app/controllers/idv/capture_doc_status_controller.rb b/app/controllers/idv/capture_doc_status_controller.rb index 670721751a6..61e07bcc880 100644 --- a/app/controllers/idv/capture_doc_status_controller.rb +++ b/app/controllers/idv/capture_doc_status_controller.rb @@ -43,8 +43,7 @@ def redirect_url def session_result return @session_result if defined?(@session_result) - @session_result = document_capture_session.load_result || - document_capture_session.load_doc_auth_async_result + @session_result = document_capture_session.load_result end def document_capture_session diff --git a/app/controllers/idv/document_capture_controller.rb b/app/controllers/idv/document_capture_controller.rb index 6f24377a3e6..6d854de756f 100644 --- a/app/controllers/idv/document_capture_controller.rb +++ b/app/controllers/idv/document_capture_controller.rb @@ -5,6 +5,7 @@ class DocumentCaptureController < ApplicationController include IdvStepConcern include StepIndicatorConcern + before_action :confirm_not_rate_limited before_action :confirm_hybrid_handoff_complete before_action :confirm_document_capture_needed before_action :override_csp_to_allow_acuant diff --git a/app/controllers/idv/getting_started_controller.rb b/app/controllers/idv/getting_started_controller.rb index ae515eed8f5..36812b0b31c 100644 --- a/app/controllers/idv/getting_started_controller.rb +++ b/app/controllers/idv/getting_started_controller.rb @@ -2,6 +2,7 @@ module Idv class GettingStartedController < ApplicationController include IdvStepConcern + before_action :confirm_not_rate_limited before_action :confirm_agreement_needed def show @@ -72,7 +73,7 @@ def skip_to_capture end def consent_form_params - params.require(:doc_auth).permit([:ial2_consent_given, :idv_consent_given]) + params.require(:doc_auth).permit(:idv_consent_given) end def confirm_agreement_needed diff --git a/app/controllers/idv/hybrid_handoff_controller.rb b/app/controllers/idv/hybrid_handoff_controller.rb index d060691386b..d05476abff5 100644 --- a/app/controllers/idv/hybrid_handoff_controller.rb +++ b/app/controllers/idv/hybrid_handoff_controller.rb @@ -4,6 +4,7 @@ class HybridHandoffController < ApplicationController include IdvStepConcern include StepIndicatorConcern + before_action :confirm_not_rate_limited before_action :confirm_verify_info_step_needed before_action :confirm_agreement_step_complete before_action :confirm_hybrid_handoff_needed, only: :show diff --git a/app/controllers/idv/in_person/ssn_controller.rb b/app/controllers/idv/in_person/ssn_controller.rb index 6b9dad37590..49ce8c27bb4 100644 --- a/app/controllers/idv/in_person/ssn_controller.rb +++ b/app/controllers/idv/in_person/ssn_controller.rb @@ -6,6 +6,7 @@ class SsnController < ApplicationController include Steps::ThreatMetrixStepHelper include ThreatMetrixConcern + before_action :confirm_not_rate_limited_after_doc_auth before_action :confirm_verify_info_step_needed before_action :confirm_in_person_address_step_complete before_action :confirm_repeat_ssn, only: :show diff --git a/app/controllers/idv/in_person/verify_info_controller.rb b/app/controllers/idv/in_person/verify_info_controller.rb index 6ce2fc38a91..bf9cdac6daa 100644 --- a/app/controllers/idv/in_person/verify_info_controller.rb +++ b/app/controllers/idv/in_person/verify_info_controller.rb @@ -6,14 +6,13 @@ class VerifyInfoController < ApplicationController include Steps::ThreatMetrixStepHelper include VerifyInfoConcern + before_action :confirm_not_rate_limited_after_doc_auth, except: [:show] before_action :confirm_ssn_step_complete before_action :confirm_verify_info_step_needed - skip_before_action :confirm_not_rate_limited, only: :show def show @step_indicator_steps = step_indicator_steps @ssn = idv_session.ssn - @capture_secondary_id_enabled = capture_secondary_id_enabled analytics.idv_doc_auth_verify_visited(**analytics_arguments) Funnel::DocAuth::RegisterStep.new(current_user.id, sp_session[:issuer]). diff --git a/app/controllers/idv/link_sent_controller.rb b/app/controllers/idv/link_sent_controller.rb index 622aec47f95..72c97b97b50 100644 --- a/app/controllers/idv/link_sent_controller.rb +++ b/app/controllers/idv/link_sent_controller.rb @@ -4,6 +4,7 @@ class LinkSentController < ApplicationController include IdvStepConcern include StepIndicatorConcern + before_action :confirm_not_rate_limited before_action :confirm_hybrid_handoff_complete before_action :confirm_document_capture_needed @@ -84,10 +85,7 @@ def take_photo_with_phone_successful? end def document_capture_session_result - @document_capture_session_result ||= begin - document_capture_session&.load_result || - document_capture_session&.load_doc_auth_async_result - end + @document_capture_session_result ||= document_capture_session&.load_result end end end diff --git a/app/controllers/idv/phone_controller.rb b/app/controllers/idv/phone_controller.rb index 9b8ba058049..d30421e17d3 100644 --- a/app/controllers/idv/phone_controller.rb +++ b/app/controllers/idv/phone_controller.rb @@ -7,10 +7,10 @@ class PhoneController < ApplicationController attr_reader :idv_form + before_action :confirm_not_rate_limited_after_idv_resolution, except: [:new] before_action :confirm_verify_info_step_complete before_action :confirm_step_needed before_action :set_idv_form - skip_before_action :confirm_not_rate_limited, only: :new def new flash.keep(:success) if should_keep_flash_success? @@ -24,7 +24,7 @@ def new render 'shared/wait' and return if async_state.in_progress? - return if confirm_not_rate_limited + return if confirm_not_rate_limited_after_idv_resolution if async_state.none? Funnel::DocAuth::RegisterStep.new(current_user.id, current_sp&.issuer). diff --git a/app/controllers/idv/phone_question_controller.rb b/app/controllers/idv/phone_question_controller.rb index 2705fc12170..bb28400a18e 100644 --- a/app/controllers/idv/phone_question_controller.rb +++ b/app/controllers/idv/phone_question_controller.rb @@ -4,6 +4,7 @@ class PhoneQuestionController < ApplicationController include IdvStepConcern include StepIndicatorConcern + before_action :confirm_not_rate_limited before_action :confirm_verify_info_step_needed before_action :confirm_agreement_step_complete before_action :confirm_hybrid_handoff_needed, only: :show diff --git a/app/controllers/idv/review_controller.rb b/app/controllers/idv/review_controller.rb index f72bb72d350..4b3b225bb19 100644 --- a/app/controllers/idv/review_controller.rb +++ b/app/controllers/idv/review_controller.rb @@ -10,7 +10,6 @@ class ReviewController < ApplicationController before_action :confirm_verify_info_step_complete before_action :confirm_address_step_complete before_action :confirm_current_password, only: [:create] - skip_before_action :confirm_not_rate_limited helper_method :step_indicator_step diff --git a/app/controllers/idv/ssn_controller.rb b/app/controllers/idv/ssn_controller.rb index f3b3084a203..8c43dbd65a5 100644 --- a/app/controllers/idv/ssn_controller.rb +++ b/app/controllers/idv/ssn_controller.rb @@ -5,6 +5,7 @@ class SsnController < ApplicationController include Steps::ThreatMetrixStepHelper include ThreatMetrixConcern + before_action :confirm_not_rate_limited_after_doc_auth before_action :confirm_verify_info_step_needed before_action :confirm_document_capture_complete before_action :confirm_repeat_ssn, only: :show diff --git a/app/controllers/idv/verify_info_controller.rb b/app/controllers/idv/verify_info_controller.rb index a892f63ccc2..b30db05794d 100644 --- a/app/controllers/idv/verify_info_controller.rb +++ b/app/controllers/idv/verify_info_controller.rb @@ -5,9 +5,9 @@ class VerifyInfoController < ApplicationController include VerifyInfoConcern include Steps::ThreatMetrixStepHelper + before_action :confirm_not_rate_limited_after_doc_auth, except: [:show] before_action :confirm_ssn_step_complete before_action :confirm_verify_info_step_needed - skip_before_action :confirm_not_rate_limited, only: :show def show @step_indicator_steps = step_indicator_steps diff --git a/app/controllers/idv/welcome_controller.rb b/app/controllers/idv/welcome_controller.rb index 9f3ac24af87..1b515334c08 100644 --- a/app/controllers/idv/welcome_controller.rb +++ b/app/controllers/idv/welcome_controller.rb @@ -4,6 +4,7 @@ class WelcomeController < ApplicationController include StepIndicatorConcern include GettingStartedAbTestConcern + before_action :confirm_not_rate_limited before_action :confirm_welcome_needed before_action :maybe_redirect_for_getting_started_ab_test diff --git a/app/controllers/openid_connect/logout_controller.rb b/app/controllers/openid_connect/logout_controller.rb index b43a72b3b31..c438f3420a2 100644 --- a/app/controllers/openid_connect/logout_controller.rb +++ b/app/controllers/openid_connect/logout_controller.rb @@ -3,7 +3,6 @@ class LogoutController < ApplicationController include SecureHeadersConcern include FullyAuthenticatable - before_action :apply_secure_headers_override, only: [:index, :delete] before_action :confirm_two_factor_authenticated, only: [:delete] def index @@ -41,6 +40,17 @@ def delete private + def apply_logout_secure_headers_override(redirect_uri, service_provider) + return if service_provider.nil? || redirect_uri.nil? + + uris = SecureHeadersAllowList.csp_with_sp_redirect_uris( + redirect_uri, + service_provider.redirect_uris, + ) + + override_form_action_csp(uris) + end + def require_logout_confirmation? (logout_params[:id_token_hint].nil? || IdentityConfig.store.reject_id_token_hint_in_logout) && logout_params[:client_id] && @@ -55,6 +65,7 @@ def build_logout_form end def handle_successful_logout_request(result, redirect_uri) + apply_logout_secure_headers_override(redirect_uri, @logout_form.service_provider) if require_logout_confirmation? analytics.oidc_logout_visited(**result.to_h.except(:redirect_uri)) @params = { diff --git a/app/forms/idv/consent_form.rb b/app/forms/idv/consent_form.rb index 1d4c27eebd1..933733623bc 100644 --- a/app/forms/idv/consent_form.rb +++ b/app/forms/idv/consent_form.rb @@ -6,7 +6,7 @@ class ConsentForm acceptance: { message: proc { I18n.t('errors.doc_auth.consent_form') } } def submit(params) - @idv_consent_given = params[:idv_consent_given] == '1' || params[:ial2_consent_given] == '1' + @idv_consent_given = params[:idv_consent_given] == '1' FormResponse.new(success: valid?, errors: errors) end diff --git a/app/forms/idv/in_person/address_form.rb b/app/forms/idv/in_person/address_form.rb index 43d5b422cca..6bfd7493462 100644 --- a/app/forms/idv/in_person/address_form.rb +++ b/app/forms/idv/in_person/address_form.rb @@ -8,10 +8,6 @@ class AddressForm attr_accessor(*ATTRIBUTES) - def initialize(capture_secondary_id_enabled:) - @capture_secondary_id_enabled = capture_secondary_id_enabled - end - def self.model_name ActiveModel::Name.new(self, nil, 'InPersonAddress') end @@ -33,9 +29,6 @@ def submit(params) private - attr_reader :capture_secondary_id_enabled - alias_method :capture_secondary_id_enabled?, :capture_secondary_id_enabled - def consume_params(params) params.each do |key, value| raise_invalid_address_parameter_error(key) unless ATTRIBUTES.include?(key.to_sym) diff --git a/app/forms/idv/state_id_form.rb b/app/forms/idv/state_id_form.rb index 3f80e517ca3..2225225344a 100644 --- a/app/forms/idv/state_id_form.rb +++ b/app/forms/idv/state_id_form.rb @@ -13,9 +13,8 @@ def self.model_name ActiveModel::Name.new(self, nil, 'StateId') end - def initialize(pii, capture_secondary_id_enabled:) + def initialize(pii) @pii = pii - @capture_secondary_id_enabled = capture_secondary_id_enabled end def submit(params) @@ -36,9 +35,6 @@ def submit(params) private - attr_reader :capture_secondary_id_enabled - alias_method :capture_secondary_id_enabled?, :capture_secondary_id_enabled - def consume_params(params) params.each do |key, value| raise_invalid_state_id_parameter_error(key) unless ATTRIBUTES.include?(key.to_sym) diff --git a/app/javascript/packages/phone-input/package.json b/app/javascript/packages/phone-input/package.json index e6bc8a18a60..e7120294009 100644 --- a/app/javascript/packages/phone-input/package.json +++ b/app/javascript/packages/phone-input/package.json @@ -4,6 +4,6 @@ "version": "1.0.0", "dependencies": { "intl-tel-input": "^17.0.19", - "libphonenumber-js": "^1.10.45" + "libphonenumber-js": "^1.10.47" } } diff --git a/app/jobs/get_usps_proofing_results_job.rb b/app/jobs/get_usps_proofing_results_job.rb index 3690d77acdc..0368a69232a 100644 --- a/app/jobs/get_usps_proofing_results_job.rb +++ b/app/jobs/get_usps_proofing_results_job.rb @@ -120,9 +120,8 @@ def check_enrollment(enrollment) enrollment.update(status_check_attempted_at: status_check_attempted_at) end - def passed_with_unsupported_secondary_id_type?(enrollment, response) - return enrollment.capture_secondary_id_enabled && - response['secondaryIdType'].present? && + def passed_with_unsupported_secondary_id_type?(response) + return response['secondaryIdType'].present? && SUPPORTED_SECONDARY_ID_TYPES.exclude?(response['secondaryIdType']) end @@ -414,7 +413,7 @@ def process_enrollment_response(enrollment, response) case response['status'] when IPP_STATUS_PASSED - if passed_with_unsupported_secondary_id_type?(enrollment, response) + if passed_with_unsupported_secondary_id_type?(response) handle_unsupported_secondary_id(enrollment, response) elsif SUPPORTED_ID_TYPES.include?(response['primaryIdType']) handle_successful_status_update(enrollment, response) diff --git a/app/jobs/multi_region_kms_migration/profile_migration_job.rb b/app/jobs/multi_region_kms_migration/profile_migration_job.rb deleted file mode 100644 index c334aced307..00000000000 --- a/app/jobs/multi_region_kms_migration/profile_migration_job.rb +++ /dev/null @@ -1,62 +0,0 @@ -module MultiRegionKmsMigration - class ProfileMigrationJob < ApplicationJob - queue_as :long_running - - MAXIMUM_ERROR_TOLERANCE = 10 - - include ::NewRelic::Agent::MethodTracer - - def perform(statement_timeout: 120, profile_count: 1000) - return unless IdentityConfig.store.multi_region_kms_migration_jobs_enabled - - error_count = 0 - success_count = 0 - - profiles = find_profiles_to_migrate(statement_timeout:, profile_count:) - profiles.each do |profile| - return if error_count >= MAXIMUM_ERROR_TOLERANCE # rubocop:disable Lint/NonLocalExitFromIterator - - Encryption::MultiRegionKmsMigration::ProfileMigrator.new(profile).migrate! - success_count += 1 - analytics.multi_region_kms_migration_profile_migrated( - success: true, - profile_id: profile.id, - exception: nil, - ) - rescue => err - error_count += 1 - analytics.multi_region_kms_migration_profile_migrated( - success: false, - profile_id: profile.id, - exception: err.inspect, - ) - end - analytics.multi_region_kms_migration_profile_migration_summary( - profile_count: profiles.size, - success_count: success_count, - error_count: error_count, - ) - end - - def find_profiles_to_migrate(statement_timeout:, profile_count:) - Profile.transaction do - quoted_timeout = Profile.connection.quote(statement_timeout * 1000) - Profile.connection.execute("SET LOCAL statement_timeout = #{quoted_timeout}") - - Profile.where( - encrypted_pii_multi_region: nil, - encrypted_pii_recovery_multi_region: nil, - ).where( - 'encrypted_pii IS NOT NULL', - 'encrypted_pii_recovery IS NOT NULL', - ).limit(profile_count).to_a - end - end - - def analytics - @analytics ||= Analytics.new(user: AnonymousUser.new, request: nil, session: {}, sp: nil) - end - - add_method_tracer :find_profiles_to_migrate, "Custom/#{name}/find_profiles_to_migrate" - end -end diff --git a/app/jobs/reports/monthly_key_metrics_report.rb b/app/jobs/reports/monthly_key_metrics_report.rb index 8438089d1b6..31150211f33 100644 --- a/app/jobs/reports/monthly_key_metrics_report.rb +++ b/app/jobs/reports/monthly_key_metrics_report.rb @@ -11,9 +11,11 @@ def perform(date = Time.zone.today) account_reuse_table = account_reuse_report.account_reuse_report total_profiles_table = account_reuse_report.total_identities_report + account_deletion_rate_table = account_deletion_rate_report.account_deletion_report upload_to_s3(account_reuse_table, report_name: 'account_reuse') upload_to_s3(total_profiles_table, report_name: 'total_profiles') + upload_to_s3(account_deletion_rate_table, report_name: 'account_deletion_rate') email_tables = [ [ @@ -28,6 +30,14 @@ def perform(date = Time.zone.today) { title: 'Total proofed identities' }, *total_profiles_table, ], + [ + { + title: 'Account deletion rate (last 30 days)', + float_as_percent: true, + precision: 4, + }, + *account_deletion_rate_table, + ], ] email_message = "Report: #{REPORT_NAME} #{date}" @@ -57,6 +67,10 @@ def account_reuse_report @account_reuse_report ||= Reporting::AccountReuseAndTotalIdentitiesReport.new(report_date) end + def account_deletion_rate_report + @account_deletion_rate_report ||= Reporting::AccountDeletionRateReport.new(report_date) + end + def upload_to_s3(report_body, report_name: nil) _latest, path = generate_s3_paths(REPORT_NAME, 'csv', subname: report_name, now: report_date) diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 43d2f59d80a..4b782de1401 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -397,7 +397,7 @@ def gpo_reminder user.gpo_verification_pending_profile.gpo_verification_pending_at, format: :event_date, ) - mail(to: email_address.email, subject: t('idv.messages.gpo_reminder.subject')) + mail(to: email_address.email, subject: t('user_mailer.letter_reminder_14_days.subject')) end end diff --git a/app/models/document_capture_session.rb b/app/models/document_capture_session.rb index ac9bd7a8215..3536998935f 100644 --- a/app/models/document_capture_session.rb +++ b/app/models/document_capture_session.rb @@ -39,21 +39,6 @@ def store_failed_auth_image_fingerprint(front_image_fingerprint, back_image_fing save! end - def load_doc_auth_async_result - EncryptedRedisStructStorage.load(result_id, type: DocumentCaptureSessionAsyncResult) - end - - def create_doc_auth_session - EncryptedRedisStructStorage.store( - DocumentCaptureSessionAsyncResult.new( - id: generate_result_id, - status: DocumentCaptureSessionAsyncResult::IN_PROGRESS, - ), - expires_in: IdentityConfig.store.async_wait_timeout_seconds, - ) - save! - end - def load_proofing_result EncryptedRedisStructStorage.load(result_id, type: ProofingSessionAsyncResult) end diff --git a/app/models/in_person_enrollment.rb b/app/models/in_person_enrollment.rb index 169b2f16779..313a133d6fa 100644 --- a/app/models/in_person_enrollment.rb +++ b/app/models/in_person_enrollment.rb @@ -32,7 +32,6 @@ class InPersonEnrollment < ApplicationRecord before_save(:on_status_updated, if: :will_save_change_to_status?) before_save(:on_notification_sent_at_updated, if: :will_save_change_to_notification_sent_at?) before_create(:set_unique_id, unless: :unique_id) - before_create(:set_capture_secondary_id) class << self def needs_early_email_reminder(early_benchmark, late_benchmark) @@ -182,10 +181,4 @@ def profile_belongs_to_user type: :in_person_enrollment_user_profile_mismatch end end - - def set_capture_secondary_id - if IdentityConfig.store.in_person_capture_secondary_id_enabled - self.capture_secondary_id_enabled = true - 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 f52a5184137..3398cb572c9 100644 --- a/app/presenters/idv/in_person/ready_to_verify_presenter.rb +++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb @@ -30,10 +30,6 @@ def selected_location_hours(prefix) return localized_hours(hours) if hours end - def needs_proof_of_address? - !(enrollment.current_address_matches_id || enrollment.capture_secondary_id_enabled) - end - def service_provider enrollment.service_provider end diff --git a/app/presenters/idv/in_person/verification_results_email_presenter.rb b/app/presenters/idv/in_person/verification_results_email_presenter.rb index c89838e07c7..98523931bbf 100644 --- a/app/presenters/idv/in_person/verification_results_email_presenter.rb +++ b/app/presenters/idv/in_person/verification_results_email_presenter.rb @@ -47,10 +47,6 @@ def service_provider_homepage_url sp_return_url_resolver.homepage_url if service_provider end - def needs_proof_of_address? - !(enrollment.current_address_matches_id || enrollment.capture_secondary_id_enabled) - end - private def sp_return_url_resolver diff --git a/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb b/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb index 5bb04e1b33c..546d2415e51 100644 --- a/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb +++ b/app/presenters/two_factor_auth_code/generic_delivery_presenter.rb @@ -60,17 +60,6 @@ def url_options private - def service_provider_mfa_policy - @service_provider_mfa_policy ||= ServiceProviderMfaPolicy.new( - user: @view.current_user, - service_provider: @service_provider, - auth_method: @view.user_session[:auth_method], - aal_level_requested: @view.sp_session[:aal_level_requested], - piv_cac_requested: @view.sp_session[:piv_cac_requested], - phishing_resistant_requested: @view.sp_session[:phishing_resistant_requested], - ) - end - attr_reader :view, :user_opted_remember_device_cookie end end diff --git a/app/presenters/two_factor_auth_code/webauthn_authentication_presenter.rb b/app/presenters/two_factor_auth_code/webauthn_authentication_presenter.rb index 392f2a06d91..7c049a2461c 100644 --- a/app/presenters/two_factor_auth_code/webauthn_authentication_presenter.rb +++ b/app/presenters/two_factor_auth_code/webauthn_authentication_presenter.rb @@ -69,10 +69,6 @@ def redirect_location_step :webauthn_verification end - def multiple_factors_enabled? - service_provider_mfa_policy.multiple_factors_enabled? - end - def platform_authenticator? @platform_authenticator end diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index f4357a1a2b5..7be300f33e2 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -14,18 +14,18 @@ module AnalyticsEvents # @param [Boolean] success # When a user submits a form to delete their account def account_delete_submitted(success:, **extra) - track_event('Account Delete submitted', success: success, **extra) + track_event('Account Delete submitted', success: success, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # When a user visits the page to delete their account def account_delete_visited - track_event('Account Delete visited') + track_event('Account Delete visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] request_came_from the controller/action the request came from # When a user deletes their account def account_deletion(request_came_from:, **extra) - track_event('Account Deletion Requested', request_came_from: request_came_from, **extra) + track_event('Account Deletion Requested', request_came_from: request_came_from, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name Account Reset @@ -35,7 +35,7 @@ def account_deletion(request_came_from:, **extra) # An account reset was cancelled def account_reset_cancel(user_id:, message_id: nil, request_id: nil, **extra) track_event( - 'Account Reset: cancel', + 'Account Reset: cancel', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { user_id: user_id, message_id: message_id, @@ -51,7 +51,7 @@ def account_reset_cancel(user_id:, message_id: nil, request_id: nil, **extra) # Validates the token used for cancelling an account reset def account_reset_cancel_token_validation(user_id:, errors: nil, **extra) track_event( - 'Account Reset: cancel token validation', + 'Account Reset: cancel token validation', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter user_id: user_id, errors: errors, **extra, @@ -77,7 +77,7 @@ def account_reset_delete( **extra ) track_event( - 'Account Reset: delete', + 'Account Reset: delete', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, user_id: user_id, account_age_in_days: account_age_in_days, @@ -94,7 +94,7 @@ def account_reset_delete( # Validates the granted token for account reset def account_reset_granted_token_validation(user_id: nil, errors: nil, **extra) track_event( - 'Account Reset: granted token validation', + 'Account Reset: granted token validation', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter user_id: user_id, errors: errors, **extra, @@ -105,12 +105,12 @@ def account_reset_granted_token_validation(user_id: nil, errors: nil, **extra) # @param [Integer] count number of email notifications sent # Account reset was performed, logs the number of email notifications sent def account_reset_notifications(count:, **extra) - track_event('Account Reset: notifications', count: count, **extra) + track_event('Account Reset: notifications', count: count, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks users visiting the recovery options page def account_reset_recovery_options_visit - track_event('Account Reset: Recovery Options Visited') + track_event('Account Reset: Recovery Options Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name Account Reset @@ -133,7 +133,7 @@ def account_reset_request( **extra ) track_event( - 'Account Reset: request', + 'Account Reset: request', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, sms_phone: sms_phone, @@ -149,19 +149,19 @@ def account_reset_request( # User visited the account deletion and reset page def account_reset_visit - track_event('Account deletion and reset visited') + track_event('Account deletion and reset visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # When a user views the account page def account_visit - track_event('Account Page Visited') + track_event('Account Page Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success # @param [String] user_id account the email is linked to # A user has clicked the confirmation link in an email def add_email_confirmation(user_id:, success: nil, **extra) - track_event('Add Email: Email Confirmation', user_id: user_id, success: success, **extra) + track_event('Add Email: Email Confirmation', user_id: user_id, success: success, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -169,7 +169,7 @@ def add_email_confirmation(user_id:, success: nil, **extra) # Tracks request for adding new emails to an account def add_email_request(success:, errors:, **extra) track_event( - 'Add Email Requested', + 'Add Email Requested', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -178,38 +178,38 @@ def add_email_request(success:, errors:, **extra) # When a user views the add email address page def add_email_visit - track_event('Add Email Address Page Visited') + track_event('Add Email Address Page Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks When users visit the add phone page def add_phone_setup_visit track_event( - 'Phone Setup Visited', + 'Phone Setup Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter ) end # When a user views the "you are already signed in with the following email" screen def authentication_confirmation - track_event('Authentication Confirmation') + track_event('Authentication Confirmation') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # When a user views the "you are already signed in with the following email" screen and # continues with their existing logged-in email def authentication_confirmation_continue - track_event('Authentication Confirmation: Continue selected') + track_event('Authentication Confirmation: Continue selected') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # When a user views the "you are already signed in with the following email" screen and # signs out of their current logged in email to choose a different email def authentication_confirmation_reset - track_event('Authentication Confirmation: Reset selected') + track_event('Authentication Confirmation: Reset selected') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [DateTime] fraud_rejection_at Date when profile was rejected # Tracks when a profile is automatically rejected due to being under review for 30 days def automatic_fraud_rejection(fraud_rejection_at:, **extra) track_event( - 'Fraud: Automatic Fraud Rejection', + 'Fraud: Automatic Fraud Rejection', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter fraud_rejection_at: fraud_rejection_at, **extra, ) @@ -219,7 +219,7 @@ def automatic_fraud_rejection(fraud_rejection_at:, **extra) # @param [Integer] enabled_mfa_methods_count number of registered mfa methods for the user def backup_code_created(enabled_mfa_methods_count:, **extra) track_event( - 'Backup Code Created', + 'Backup Code Created', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enabled_mfa_methods_count: enabled_mfa_methods_count, **extra, ) @@ -228,7 +228,7 @@ def backup_code_created(enabled_mfa_methods_count:, **extra) # Tracks when the user visits the Backup Code Regenerate page. # @param [Boolean] in_account_creation_flow whether user is going through creation flow def backup_code_regenerate_visit(in_account_creation_flow:, **extra) - track_event('Backup Code Regenerate Visited', in_account_creation_flow:, **extra) + track_event('Backup Code Regenerate Visited', in_account_creation_flow:, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Track user creating new BackupCodeSetupForm, record form submission Hash @@ -242,7 +242,7 @@ def backup_code_setup_visit( **extra ) track_event( - 'Backup Code Setup Visited', + 'Backup Code Setup Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, error_details: error_details, @@ -253,24 +253,24 @@ def backup_code_setup_visit( # A user that has been banned from an SP has authenticated, they are redirected # to a page showing them that they have been banned def banned_user_redirect - track_event('Banned User redirected') + track_event('Banned User redirected') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # A user that has been banned from an SP has authenticated, they have visited # a page showing them that they have been banned def banned_user_visited - track_event('Banned User visited') + track_event('Banned User visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # A user that had a broken personal key was routed to a page to regenerate their personal key, # so that they no longer have a broken one def broken_personal_key_regenerated - track_event('Broken Personal Key: Regenerated') + track_event('Broken Personal Key: Regenerated') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks users going back or cancelling acoount recovery def cancel_account_reset_recovery - track_event('Account Reset: Cancel Account Recovery Options') + track_event('Account Reset: Cancel Account Recovery Options') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] redirect_url URL user was directed to @@ -280,7 +280,7 @@ def cancel_account_reset_recovery # User was redirected to the login.gov contact page def contact_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra) track_event( - 'Contact Page Redirect', + 'Contact Page Redirect', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_url: redirect_url, step: step, location: location, @@ -289,21 +289,13 @@ def contact_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra ) end - # @param [String, nil] error error message - # @param [String, nil] uuid document capture session uuid - # @param [String, nil] result_id document capture session result id - # When there is an error loading async results during the document authentication flow - def doc_auth_async(error: nil, uuid: nil, result_id: nil, **extra) - track_event('Doc Auth Async', error: error, uuid: uuid, result_id: result_id, **extra) - end - # @param [String] message the warning # @param [String] getting_started_ab_test_bucket Which initial IdV screen the user saw # Logged when there is a non-user-facing error in the doc auth process, such as an unrecognized # field from a vendor def doc_auth_warning(message: nil, getting_started_ab_test_bucket: nil, **extra) track_event( - 'Doc Auth Warning', + 'Doc Auth Warning', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter message: message, getting_started_ab_test_bucket: getting_started_ab_test_bucket, **extra, @@ -312,7 +304,7 @@ def doc_auth_warning(message: nil, getting_started_ab_test_bucket: nil, **extra) # When a user views the edit password page def edit_password_visit - track_event('Edit Password Page Visited') + track_event('Edit Password Page Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -334,7 +326,7 @@ def email_and_password_auth( **extra ) track_event( - 'Email and Password Authentication', + 'Email and Password Authentication', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, user_id: user_id, user_locked_out: user_locked_out, @@ -351,7 +343,7 @@ def email_and_password_auth( # Tracks request for deletion of email address def email_deletion_request(success:, errors:, **extra) track_event( - 'Email Deletion Requested', + 'Email Deletion Requested', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -363,7 +355,7 @@ def email_deletion_request(success:, errors:, **extra) # Tracks if Email Language is updated def email_language_updated(success:, errors:, **extra) track_event( - 'Email Language: Updated', + 'Email Language: Updated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -372,7 +364,7 @@ def email_language_updated(success:, errors:, **extra) # Tracks if Email Language is visited def email_language_visited - track_event('Email Language: Visited') + track_event('Email Language: Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Logs after an email is sent @@ -380,7 +372,7 @@ def email_language_visited # @param [String, nil] ses_message_id AWS SES Message ID def email_sent(action:, ses_message_id:, **extra) track_event( - 'Email Sent', + 'Email Sent', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter action: action, ses_message_id: ses_message_id, **extra, @@ -410,7 +402,7 @@ def event_disavowal( **extra ) track_event( - 'Event disavowal visited', + 'Event disavowal visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, event_created_at: event_created_at, @@ -447,7 +439,7 @@ def event_disavowal_password_reset( **extra ) track_event( - 'Event disavowal password reset', + 'Event disavowal password reset', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, event_created_at: event_created_at, @@ -484,7 +476,7 @@ def event_disavowal_token_invalid( **extra ) track_event( - 'Event disavowal token invalid', + 'Event disavowal token invalid', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, event_created_at: event_created_at, @@ -500,7 +492,7 @@ def event_disavowal_token_invalid( # User visited the events page def events_visit - track_event('Events Page Visited') + track_event('Events Page Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] redirect_url URL user was directed to @@ -510,7 +502,7 @@ def events_visit # User was redirected to a page outside the IDP def external_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra) track_event( - 'External Redirect', + 'External Redirect', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_url: redirect_url, step: step, location: location, @@ -521,12 +513,12 @@ def external_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extr # The user chose to "forget all browsers" def forget_all_browsers_submitted - track_event('Forget All Browsers Submitted') + track_event('Forget All Browsers Submitted') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # The user visited the "forget all browsers" page def forget_all_browsers_visited - track_event('Forget All Browsers Visited') + track_event('Forget All Browsers Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -542,7 +534,7 @@ def fraud_review_passed( **extra ) track_event( - 'Fraud: Profile review passed', + 'Fraud: Profile review passed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, exception: exception, @@ -564,7 +556,7 @@ def fraud_review_rejected( **extra ) track_event( - 'Fraud: Profile review rejected', + 'Fraud: Profile review rejected', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, exception: exception, @@ -578,7 +570,7 @@ def fraud_review_rejected( # @param [String] message # @param [String] stack def frontend_error(name:, message:, stack: nil, **extra) - track_event('Frontend Error', name:, message:, stack:, **extra) + track_event('Frontend Error', name:, message:, stack:, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -596,7 +588,7 @@ def idv_address_submitted( **extra ) track_event( - 'IdV: address submitted', + 'IdV: address submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, address_edited: address_edited, @@ -608,7 +600,7 @@ def idv_address_submitted( # User visited idv address page def idv_address_visit - track_event('IdV: address visited') + track_event('IdV: address visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] step the step that the user was on when they clicked cancel @@ -616,7 +608,7 @@ def idv_address_visit # The user confirmed their choice to cancel going through IDV def idv_cancellation_confirmed(step:, proofing_components: nil, **extra) track_event( - 'IdV: cancellation confirmed', + 'IdV: cancellation confirmed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step: step, proofing_components: proofing_components, **extra, @@ -628,7 +620,7 @@ def idv_cancellation_confirmed(step:, proofing_components: nil, **extra) # The user chose to go back instead of cancel IDV def idv_cancellation_go_back(step:, proofing_components: nil, **extra) track_event( - 'IdV: cancellation go back', + 'IdV: cancellation go back', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step: step, proofing_components: proofing_components, **extra, @@ -647,7 +639,7 @@ def idv_cancellation_visited( **extra ) track_event( - 'IdV: cancellation visited', + 'IdV: cancellation visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step: step, request_came_from: request_came_from, proofing_components: proofing_components, @@ -660,7 +652,7 @@ def idv_cancellation_visited( # @param [Boolean] checked Whether the user checked the checkbox def idv_consent_checkbox_toggled(checked:, **extra) track_event( - 'IdV: consent checkbox toggled', + 'IdV: consent checkbox toggled', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter checked: checked, **extra, ) @@ -669,23 +661,23 @@ def idv_consent_checkbox_toggled(checked:, **extra) # User has consented to share information with document upload and may # view the "hybrid handoff" step next unless "skip_hybrid_handoff" param is true def idv_doc_auth_agreement_submitted(**extra) - track_event('IdV: doc auth agreement submitted', **extra) + track_event('IdV: doc auth agreement submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_agreement_visited(**extra) - track_event('IdV: doc auth agreement visited', **extra) + track_event('IdV: doc auth agreement visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_capture_complete_visited(**extra) - track_event('IdV: doc auth capture_complete visited', **extra) + track_event('IdV: doc auth capture_complete visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_document_capture_submitted(**extra) - track_event('IdV: doc auth document_capture submitted', **extra) + track_event('IdV: doc auth document_capture submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_document_capture_visited(**extra) - track_event('IdV: doc auth document_capture visited', **extra) + track_event('IdV: doc auth document_capture visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] step_name which step the user was on @@ -694,7 +686,7 @@ def idv_doc_auth_document_capture_visited(**extra) # The user visited an error page due to an encountering an exception talking to a proofing vendor def idv_doc_auth_exception_visited(step_name:, remaining_attempts:, **extra) track_event( - 'IdV: doc auth exception visited', + 'IdV: doc auth exception visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step_name: step_name, remaining_attempts: remaining_attempts, **extra, @@ -704,18 +696,18 @@ def idv_doc_auth_exception_visited(step_name:, remaining_attempts:, **extra) # @param [String] side the side of the image submission def idv_doc_auth_failed_image_resubmitted(side:, **extra) track_event( - 'IdV: failed doc image resubmitted', + 'IdV: failed doc image resubmitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter side: side, **extra, ) end def idv_doc_auth_getting_started_submitted(**extra) - track_event('IdV: doc auth getting_started submitted', **extra) + track_event('IdV: doc auth getting_started submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_getting_started_visited(**extra) - track_event('IdV: doc auth getting_started visited', **extra) + track_event('IdV: doc auth getting_started visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # The "hybrid handoff" step: Desktop user has submitted their choice to @@ -723,48 +715,48 @@ def idv_doc_auth_getting_started_visited(**extra) # to mobile phone ("send_link" destination) to perform document upload. # @identity.idp.previous_event_name IdV: doc auth upload submitted def idv_doc_auth_hybrid_handoff_submitted(**extra) - track_event('IdV: doc auth hybrid handoff submitted', **extra) + track_event('IdV: doc auth hybrid handoff submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Desktop user has reached the above "hybrid handoff" view # @identity.idp.previous_event_name IdV: doc auth upload visited def idv_doc_auth_hybrid_handoff_visited(**extra) - track_event('IdV: doc auth hybrid handoff visited', **extra) + track_event('IdV: doc auth hybrid handoff visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name IdV: doc auth send_link submitted def idv_doc_auth_link_sent_submitted(**extra) - track_event('IdV: doc auth link_sent submitted', **extra) + track_event('IdV: doc auth link_sent submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_link_sent_visited(**extra) - track_event('IdV: doc auth link_sent visited', **extra) + track_event('IdV: doc auth link_sent visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_randomizer_defaulted track_event( - 'IdV: doc_auth random vendor error', + 'IdV: doc_auth random vendor error', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter error: 'document_capture_session_uuid_key missing', ) end # @identity.idp.previous_event_name IdV: in person proofing redo_address submitted def idv_doc_auth_redo_address_submitted(**extra) - track_event('IdV: doc auth redo_address submitted', **extra) + track_event('IdV: doc auth redo_address submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_redo_ssn_submitted(**extra) - track_event('IdV: doc auth redo_ssn submitted', **extra) + track_event('IdV: doc auth redo_ssn submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name IdV: in person proofing ssn submitted def idv_doc_auth_ssn_submitted(**extra) - track_event('IdV: doc auth ssn submitted', **extra) + track_event('IdV: doc auth ssn submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name IdV: in person proofing ssn visited def idv_doc_auth_ssn_visited(**extra) - track_event('IdV: doc auth ssn visited', **extra) + track_event('IdV: doc auth ssn visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -790,7 +782,7 @@ def idv_doc_auth_submitted_image_upload_form( **extra ) track_event( - 'IdV: doc auth image upload form submitted', + 'IdV: doc auth image upload form submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, attempts: attempts, @@ -840,7 +832,7 @@ def idv_doc_auth_submitted_image_upload_vendor( **extra ) track_event( - 'IdV: doc auth image upload vendor submitted', + 'IdV: doc auth image upload vendor submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, exception: exception, @@ -884,7 +876,7 @@ def idv_doc_auth_submitted_pii_validation( **extra ) track_event( - 'IdV: doc auth image upload vendor pii validation', + 'IdV: doc auth image upload vendor pii validation', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, user_id: user_id, @@ -899,17 +891,17 @@ def idv_doc_auth_submitted_pii_validation( end def idv_doc_auth_verify_proofing_results(**extra) - track_event('IdV: doc auth verify proofing results', **extra) + track_event('IdV: doc auth verify proofing results', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name IdV: in person proofing verify submitted def idv_doc_auth_verify_submitted(**extra) - track_event('IdV: doc auth verify submitted', **extra) + track_event('IdV: doc auth verify submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name IdV: in person proofing verify visited def idv_doc_auth_verify_visited(**extra) - track_event('IdV: doc auth verify visited', **extra) + track_event('IdV: doc auth verify visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] step_name @@ -921,7 +913,7 @@ def idv_doc_auth_warning_visited( **extra ) track_event( - 'IdV: doc auth warning visited', + 'IdV: doc auth warning visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step_name: step_name, remaining_attempts: remaining_attempts, **extra, @@ -929,11 +921,11 @@ def idv_doc_auth_warning_visited( end def idv_doc_auth_welcome_submitted(**extra) - track_event('IdV: doc auth welcome submitted', **extra) + track_event('IdV: doc auth welcome submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end def idv_doc_auth_welcome_visited(**extra) - track_event('IdV: doc auth welcome visited', **extra) + track_event('IdV: doc auth welcome visited', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -957,7 +949,7 @@ def idv_final( **extra ) track_event( - 'IdV: final resolution', + 'IdV: final resolution', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, fraud_review_pending: fraud_review_pending, fraud_rejection: fraud_rejection, @@ -973,7 +965,7 @@ def idv_final( # User visited forgot password page def idv_forgot_password(proofing_components: nil, **extra) track_event( - 'IdV: forgot password visited', + 'IdV: forgot password visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -983,7 +975,7 @@ def idv_forgot_password(proofing_components: nil, **extra) # User confirmed forgot password def idv_forgot_password_confirmed(proofing_components: nil, **extra) track_event( - 'IdV: forgot password confirmed', + 'IdV: forgot password confirmed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -1007,7 +999,7 @@ def idv_gpo_address_letter_enqueued( **extra ) track_event( - 'IdV: USPS address letter enqueued', + 'IdV: USPS address letter enqueued', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enqueued_at: enqueued_at, resend: resend, first_letter_requested_at: first_letter_requested_at, @@ -1034,7 +1026,7 @@ def idv_gpo_address_letter_requested( **extra ) track_event( - 'IdV: USPS address letter requested', + 'IdV: USPS address letter requested', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter resend: resend, first_letter_requested_at:, hours_since_first_letter:, @@ -1046,13 +1038,13 @@ def idv_gpo_address_letter_requested( # The user visited the gpo confirm cancellation screen def idv_gpo_confirm_start_over_visited - track_event('IdV: gpo confirm start over visited') + track_event('IdV: gpo confirm start over visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # A GPO reminder email was sent to the user # @param [String] user_id UUID of user who we sent a reminder to def idv_gpo_reminder_email_sent(user_id:, **extra) - track_event('IdV: gpo reminder email sent', user_id: user_id, **extra) + track_event('IdV: gpo reminder email sent', user_id: user_id, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks emails that are initiated during InPerson::EmailReminderJob @@ -1064,7 +1056,7 @@ def idv_in_person_email_reminder_job_email_initiated( **extra ) track_event( - 'InPerson::EmailReminderJob: Reminder email initiated', + 'InPerson::EmailReminderJob: Reminder email initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter email_type: email_type, enrollment_id: enrollment_id, **extra, @@ -1082,7 +1074,7 @@ def idv_in_person_email_reminder_job_exception( **extra ) track_event( - 'InPerson::EmailReminderJob: Exception raised when attempting to send reminder email', + 'InPerson::EmailReminderJob: Exception raised when attempting to send reminder email', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_id: enrollment_id, exception_class: exception_class, exception_message: exception_message, @@ -1096,7 +1088,7 @@ def idv_in_person_email_reminder_job_exception( def idv_in_person_location_submitted(selected_location:, flow_path:, **extra) track_event( - 'IdV: in person proofing location submitted', + 'IdV: in person proofing location submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter selected_location: selected_location, flow_path: flow_path, **extra, @@ -1107,7 +1099,7 @@ def idv_in_person_location_submitted(selected_location:, flow_path:, # The user visited the in person proofing location step def idv_in_person_location_visited(flow_path:, **extra) track_event( - 'IdV: in person proofing location visited', + 'IdV: in person proofing location visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, **extra, ) @@ -1128,7 +1120,7 @@ def idv_in_person_locations_request_failure( **extra ) track_event( - 'Request USPS IPP locations: request failed', + 'Request USPS IPP locations: request failed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter exception_class: exception_class, exception_message: exception_message, response_body_present: response_body_present, @@ -1155,7 +1147,7 @@ def idv_in_person_locations_searched( **extra ) track_event( - 'IdV: in person proofing location search submitted', + 'IdV: in person proofing location search submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, result_total: result_total, errors: errors, @@ -1170,7 +1162,7 @@ def idv_in_person_locations_searched( # The user submitted the in person proofing prepare step def idv_in_person_prepare_submitted(flow_path:, **extra) track_event( - 'IdV: in person proofing prepare submitted', + 'IdV: in person proofing prepare submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, **extra, ) @@ -1179,7 +1171,7 @@ def idv_in_person_prepare_submitted(flow_path:, **extra) # @param [String] flow_path Document capture path ("hybrid" or "standard") # The user visited the in person proofing prepare step def idv_in_person_prepare_visited(flow_path:, **extra) - track_event('IdV: in person proofing prepare visited', flow_path: flow_path, **extra) + track_event('IdV: in person proofing prepare visited', flow_path: flow_path, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] flow_path @@ -1203,7 +1195,7 @@ def idv_in_person_proofing_address_submitted( **extra ) track_event( - 'IdV: in person proofing address submitted', + 'IdV: in person proofing address submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1231,7 +1223,7 @@ def idv_in_person_proofing_address_visited( **extra ) track_event( - 'IdV: in person proofing address visited', + 'IdV: in person proofing address visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1262,7 +1254,7 @@ def idv_in_person_proofing_cancel_update_address( **extra ) track_event( - 'IdV: in person proofing cancel_update_address submitted', + 'IdV: in person proofing cancel_update_address submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1296,7 +1288,7 @@ def idv_in_person_proofing_cancel_update_state_id( **extra ) track_event( - 'IdV: in person proofing cancel_update_state_id submitted', + 'IdV: in person proofing cancel_update_state_id submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1328,7 +1320,7 @@ def idv_in_person_proofing_enrollments_ready_for_status_check_job_completed( **extra ) track_event( - 'InPersonEnrollmentsReadyForStatusCheckJob: Job completed', + 'InPersonEnrollmentsReadyForStatusCheckJob: Job completed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter fetched_items:, processed_items:, deleted_items:, @@ -1350,7 +1342,7 @@ def idv_in_person_proofing_enrollments_ready_for_status_check_job_ingestion_erro **extra ) track_event( - 'InPersonEnrollmentsReadyForStatusCheckJob: Ingestion error', + 'InPersonEnrollmentsReadyForStatusCheckJob: Ingestion error', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter exception_class:, exception_message:, **extra, @@ -1360,7 +1352,7 @@ def idv_in_person_proofing_enrollments_ready_for_status_check_job_ingestion_erro # A job to check USPS notifications about in-person enrollment status updates has started def idv_in_person_proofing_enrollments_ready_for_status_check_job_started(**extra) track_event( - 'InPersonEnrollmentsReadyForStatusCheckJob: Job started', + 'InPersonEnrollmentsReadyForStatusCheckJob: Job started', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -1372,7 +1364,7 @@ def idv_in_person_proofing_nontransliterable_characters_submitted( **extra ) track_event( - 'IdV: in person proofing characters submitted could not be transliterated', + 'IdV: in person proofing characters submitted could not be transliterated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter nontransliterable_characters: nontransliterable_characters, **extra, ) @@ -1399,7 +1391,7 @@ def idv_in_person_proofing_redo_state_id_submitted( **extra ) track_event( - 'IdV: in person proofing redo_state_id submitted', + 'IdV: in person proofing redo_state_id submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1413,7 +1405,7 @@ def idv_in_person_proofing_redo_state_id_submitted( end def idv_in_person_proofing_residential_address_submitted(**extra) - track_event('IdV: in person proofing residential address submitted', **extra) + track_event('IdV: in person proofing residential address submitted', **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] flow_path @@ -1437,7 +1429,7 @@ def idv_in_person_proofing_state_id_submitted( **extra ) track_event( - 'IdV: in person proofing state_id submitted', + 'IdV: in person proofing state_id submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1465,7 +1457,7 @@ def idv_in_person_proofing_state_id_visited( **extra ) track_event( - 'IdV: in person proofing state_id visited', + 'IdV: in person proofing state_id visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, step: step, step_count: step_count, @@ -1478,7 +1470,7 @@ def idv_in_person_proofing_state_id_visited( # The user clicked the sp link on the "ready to verify" page def idv_in_person_ready_to_verify_sp_link_clicked(**extra) track_event( - 'IdV: user clicked sp link on ready to verify page', + 'IdV: user clicked sp link on ready to verify page', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -1488,7 +1480,7 @@ def idv_in_person_ready_to_verify_sp_link_clicked(**extra) def idv_in_person_ready_to_verify_visit(proofing_components: nil, **extra) track_event( - 'IdV: in person ready to verify visited', + 'IdV: in person ready to verify visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -1497,7 +1489,7 @@ def idv_in_person_ready_to_verify_visit(proofing_components: nil, # The user clicked the what to bring link on the "ready to verify" page def idv_in_person_ready_to_verify_what_to_bring_link_clicked(**extra) track_event( - 'IdV: user clicked what to bring link on ready to verify page', + 'IdV: user clicked what to bring link on ready to verify page', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -1516,7 +1508,7 @@ def idv_in_person_send_proofing_notification_attempted( **extra ) track_event( - 'SendProofingNotificationJob: in person notification SMS send attempted', + 'SendProofingNotificationJob: in person notification SMS send attempted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, enrollment_code: enrollment_code, enrollment_id: enrollment_id, @@ -1535,7 +1527,7 @@ def idv_in_person_send_proofing_notification_job_completed( **extra ) track_event( - 'SendProofingNotificationJob: job completed', + 'SendProofingNotificationJob: job completed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, **extra, @@ -1556,7 +1548,7 @@ def idv_in_person_send_proofing_notification_job_exception( **extra ) track_event( - 'SendProofingNotificationJob: exception raised', + 'SendProofingNotificationJob: exception raised', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, exception_class: exception_class, @@ -1575,7 +1567,7 @@ def idv_in_person_send_proofing_notification_job_skipped( **extra ) track_event( - 'SendProofingNotificationJob: job skipped', + 'SendProofingNotificationJob: job skipped', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, **extra, @@ -1592,7 +1584,7 @@ def idv_in_person_send_proofing_notification_job_started( **extra ) track_event( - 'SendProofingNotificationJob: job started', + 'SendProofingNotificationJob: job started', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, **extra, @@ -1602,13 +1594,13 @@ def idv_in_person_send_proofing_notification_job_started( # @param [String] flow_path Document capture path ("hybrid" or "standard") # The user submitted the in person proofing switch_back step def idv_in_person_switch_back_submitted(flow_path:, **extra) - track_event('IdV: in person proofing switch_back submitted', flow_path: flow_path, **extra) + track_event('IdV: in person proofing switch_back submitted', flow_path: flow_path, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] flow_path Document capture path ("hybrid" or "standard") # The user visited the in person proofing switch_back step def idv_in_person_switch_back_visited(flow_path:, **extra) - track_event('IdV: in person proofing switch_back visited', flow_path: flow_path, **extra) + track_event('IdV: in person proofing switch_back visited', flow_path: flow_path, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # An email from USPS with an enrollment code has been received, indicating @@ -1622,7 +1614,7 @@ def idv_in_person_usps_proofing_enrollment_code_email_received( **extra ) track_event( - 'IdV: in person usps proofing enrollment code email received', + 'IdV: in person usps proofing enrollment code email received', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter multi_part: multi_part, part_found: part_found, **extra, @@ -1648,7 +1640,7 @@ def idv_in_person_usps_proofing_results_job_completed( **extra ) track_event( - 'GetUspsProofingResultsJob: Job completed', + 'GetUspsProofingResultsJob: Job completed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter duration_seconds: duration_seconds, enrollments_checked: enrollments_checked, enrollments_errored: enrollments_errored, @@ -1671,7 +1663,7 @@ def idv_in_person_usps_proofing_results_job_deadline_passed_email_exception( **extra ) track_event( - 'GetUspsProofingResultsJob: Exception raised when attempting to send deadline passed email', + 'GetUspsProofingResultsJob: Exception raised when attempting to send deadline passed email', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_id: enrollment_id, exception_class: exception_class, exception_message: exception_message, @@ -1686,7 +1678,7 @@ def idv_in_person_usps_proofing_results_job_deadline_passed_email_initiated( **extra ) track_event( - 'GetUspsProofingResultsJob: deadline passed email initiated', + 'GetUspsProofingResultsJob: deadline passed email initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_id: enrollment_id, **extra, ) @@ -1699,7 +1691,7 @@ def idv_in_person_usps_proofing_results_job_email_initiated( **extra ) track_event( - 'GetUspsProofingResultsJob: Success or failure email initiated', + 'GetUspsProofingResultsJob: Success or failure email initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter email_type: email_type, **extra, ) @@ -1718,7 +1710,7 @@ def idv_in_person_usps_proofing_results_job_enrollment_incomplete( **extra ) track_event( - 'GetUspsProofingResultsJob: Enrollment incomplete', + 'GetUspsProofingResultsJob: Enrollment incomplete', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, minutes_since_established: minutes_since_established, @@ -1744,7 +1736,7 @@ def idv_in_person_usps_proofing_results_job_enrollment_updated( **extra ) track_event( - 'GetUspsProofingResultsJob: Enrollment status updated', + 'GetUspsProofingResultsJob: Enrollment status updated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, minutes_since_established: minutes_since_established, @@ -1806,7 +1798,7 @@ def idv_in_person_usps_proofing_results_job_exception( **extra ) track_event( - 'GetUspsProofingResultsJob: Exception raised', + 'GetUspsProofingResultsJob: Exception raised', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter reason: reason, enrollment_id: enrollment_id, exception_class: exception_class, @@ -1843,7 +1835,7 @@ def idv_in_person_usps_proofing_results_job_started( **extra ) track_event( - 'GetUspsProofingResultsJob: Job started', + 'GetUspsProofingResultsJob: Job started', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollments_count: enrollments_count, reprocess_delay_minutes: reprocess_delay_minutes, **extra, @@ -1865,7 +1857,7 @@ def idv_in_person_usps_proofing_results_job_unexpected_response( **extra ) track_event( - 'GetUspsProofingResultsJob: Unexpected response received', + 'GetUspsProofingResultsJob: Unexpected response received', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, minutes_since_established: minutes_since_established, @@ -1890,7 +1882,7 @@ def idv_in_person_usps_request_enroll_exception( **extra ) track_event( - 'USPS IPPaaS enrollment failed', + 'USPS IPPaaS enrollment failed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, enrollment_id: enrollment_id, exception_class: exception_class, @@ -1902,7 +1894,7 @@ def idv_in_person_usps_request_enroll_exception( # User visits IdV def idv_intro_visit - track_event('IdV: intro visited') + track_event('IdV: intro visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # The user visited the "letter enqueued" page shown during the verify by mail flow @@ -1910,7 +1902,7 @@ def idv_intro_visit # @identity.idp.previous_event_name IdV: come back later visited def idv_letter_enqueued_visit(proofing_components: nil, **extra) track_event( - 'IdV: letter enqueued visited', + 'IdV: letter enqueued visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -1919,7 +1911,7 @@ def idv_letter_enqueued_visit(proofing_components: nil, **extra) # Tracks when the user visits Mail only warning when vendor_status_sms is set to full_outage def idv_mail_only_warning_visited(**extra) track_event( - 'IdV: Mail only warning visited', + 'IdV: Mail only warning visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -1937,7 +1929,7 @@ def idv_mobile_device_and_camera_check( **extra ) track_event( - 'IdV: Mobile device and camera check', + 'IdV: Mobile device and camera check', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter is_camera_capable_mobile: is_camera_capable_mobile, camera_present: camera_present, grace_time: grace_time, @@ -1961,7 +1953,7 @@ def idv_native_camera_forced( **extra ) track_event( - 'IdV: Native camera forced after failed attempts', + 'IdV: Native camera forced after failed attempts', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter failed_capture_attempts: failed_capture_attempts, failed_submission_attempts: failed_submission_attempts, field: field, @@ -1972,7 +1964,7 @@ def idv_native_camera_forced( # Tracks when user reaches verify errors due to being rejected due to fraud def idv_not_verified_visited - track_event('IdV: Not verified visited') + track_event('IdV: Not verified visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks if a user clicks the 'acknowledge' checkbox during personal @@ -1982,7 +1974,7 @@ def idv_not_verified_visited # the box with this click def idv_personal_key_acknowledgment_toggled(checked:, proofing_components:, **extra) track_event( - 'IdV: personal key acknowledgment toggled', + 'IdV: personal key acknowledgment toggled', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter checked: checked, proofing_components: proofing_components, **extra, @@ -1994,7 +1986,7 @@ def idv_personal_key_acknowledgment_toggled(checked:, proofing_components:, **ex # @param [Idv::ProofingComponentsLogging] proofing_components User's current proofing components def idv_personal_key_downloaded(proofing_components: nil, **extra) track_event( - 'IdV: personal key downloaded', + 'IdV: personal key downloaded', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2015,7 +2007,7 @@ def idv_personal_key_submitted( **extra ) track_event( - 'IdV: personal key submitted', + 'IdV: personal key submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter in_person_verification_pending: in_person_verification_pending, deactivation_reason: deactivation_reason, fraud_review_pending: fraud_review_pending, @@ -2029,7 +2021,7 @@ def idv_personal_key_submitted( # User visited IDV personal key page def idv_personal_key_visited(proofing_components: nil, **extra) track_event( - 'IdV: personal key visited', + 'IdV: personal key visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2048,7 +2040,7 @@ def idv_phone_confirmation_form_submitted( **extra ) track_event( - 'IdV: phone confirmation form', + 'IdV: phone confirmation form', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, otp_delivery_preference: otp_delivery_preference, @@ -2061,7 +2053,7 @@ def idv_phone_confirmation_form_submitted( # The user was rate limited for submitting too many OTPs during the IDV phone step def idv_phone_confirmation_otp_rate_limit_attempts(proofing_components: nil, **extra) track_event( - 'Idv: Phone OTP attempts rate limited', + 'Idv: Phone OTP attempts rate limited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2071,7 +2063,7 @@ def idv_phone_confirmation_otp_rate_limit_attempts(proofing_components: nil, **e # The user was locked out for hitting the phone OTP rate limit during IDV def idv_phone_confirmation_otp_rate_limit_locked_out(proofing_components: nil, **extra) track_event( - 'Idv: Phone OTP rate limited user', + 'Idv: Phone OTP rate limited user', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2081,7 +2073,7 @@ def idv_phone_confirmation_otp_rate_limit_locked_out(proofing_components: nil, * # The user was rate limited for requesting too many OTPs during the IDV phone step def idv_phone_confirmation_otp_rate_limit_sends(proofing_components: nil, **extra) track_event( - 'Idv: Phone OTP sends rate limited', + 'Idv: Phone OTP sends rate limited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2108,7 +2100,7 @@ def idv_phone_confirmation_otp_resent( **extra ) track_event( - 'IdV: phone confirmation otp resent', + 'IdV: phone confirmation otp resent', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, otp_delivery_preference: otp_delivery_preference, @@ -2146,7 +2138,7 @@ def idv_phone_confirmation_otp_sent( **extra ) track_event( - 'IdV: phone confirmation otp sent', + 'IdV: phone confirmation otp sent', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, otp_delivery_preference: otp_delivery_preference, @@ -2180,7 +2172,7 @@ def idv_phone_confirmation_otp_submitted( **extra ) track_event( - 'IdV: phone confirmation otp submitted', + 'IdV: phone confirmation otp submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, code_expired: code_expired, @@ -2196,7 +2188,7 @@ def idv_phone_confirmation_otp_submitted( # When a user visits the page to confirm posession of a new phone number during the IDV process def idv_phone_confirmation_otp_visit(proofing_components: nil, **extra) track_event( - 'IdV: phone confirmation otp visited', + 'IdV: phone confirmation otp visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2213,7 +2205,7 @@ def idv_phone_confirmation_vendor_submitted( **extra ) track_event( - 'IdV: phone confirmation vendor', + 'IdV: phone confirmation vendor', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, proofing_components: proofing_components, @@ -2234,7 +2226,7 @@ def idv_phone_error_visited( **extra ) track_event( - 'IdV: phone error visited', + 'IdV: phone error visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { type: type, proofing_components: proofing_components, @@ -2249,7 +2241,7 @@ def idv_phone_error_visited( # User visited idv phone of record def idv_phone_of_record_visited(proofing_components: nil, **extra) track_event( - 'IdV: phone of record visited', + 'IdV: phone of record visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2269,7 +2261,7 @@ def idv_phone_otp_delivery_selection_submitted( **extra ) track_event( - 'IdV: Phone OTP Delivery Selection Submitted', + 'IdV: Phone OTP Delivery Selection Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, errors: errors, @@ -2285,7 +2277,7 @@ def idv_phone_otp_delivery_selection_submitted( # User visited idv phone OTP delivery selection def idv_phone_otp_delivery_selection_visit(proofing_components: nil, **extra) track_event( - 'IdV: Phone OTP delivery Selection Visited', + 'IdV: Phone OTP delivery Selection Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2296,7 +2288,7 @@ def idv_phone_otp_delivery_selection_visit(proofing_components: nil, **extra) # User decided to use a different phone number in idv def idv_phone_use_different(step:, proofing_components: nil, **extra) track_event( - 'IdV: use different phone number', + 'IdV: use different phone number', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step: step, proofing_components: proofing_components, **extra, @@ -2308,7 +2300,7 @@ def idv_phone_use_different(step:, proofing_components: nil, **extra) # Tracks when the user reaches the verify please call page after failing proofing def idv_please_call_visited(proofing_components: nil, **extra) track_event( - 'IdV: Verify please call visited', + 'IdV: Verify please call visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2318,7 +2310,7 @@ def idv_please_call_visited(proofing_components: nil, **extra) # The system encountered an error and the proofing results are missing def idv_proofing_resolution_result_missing(proofing_components: nil, **extra) track_event( - 'IdV: proofing resolution result missing', + 'IdV: proofing resolution result missing', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter proofing_components: proofing_components, **extra, ) @@ -2332,7 +2324,7 @@ def idv_request_letter_visited( **extra ) track_event( - 'IdV: request letter visited', + 'IdV: request letter visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter letter_already_sent: letter_already_sent, **extra, ) @@ -2357,7 +2349,7 @@ def idv_review_complete( **extra ) track_event( - 'IdV: review complete', + 'IdV: review complete', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, deactivation_reason: deactivation_reason, fraud_review_pending: fraud_review_pending, @@ -2378,7 +2370,7 @@ def idv_review_info_visited(proofing_components: nil, address_verification_method: nil, **extra) track_event( - 'IdV: review info visited', + 'IdV: review info visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter address_verification_method: address_verification_method, proofing_components: proofing_components, **extra, @@ -2394,7 +2386,7 @@ def idv_session_error_visited( **extra ) track_event( - 'IdV: session error visited', + 'IdV: session error visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter type: type, attempts_remaining: attempts_remaining, **extra, @@ -2412,7 +2404,7 @@ def idv_start_over( **extra ) track_event( - 'IdV: start over', + 'IdV: start over', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter step: step, location: location, proofing_components: proofing_components, @@ -2423,7 +2415,7 @@ def idv_start_over( # Track when USPS auth token refresh job completed def idv_usps_auth_token_refresh_job_completed(**extra) track_event( - 'UspsAuthTokenRefreshJob: Completed', + 'UspsAuthTokenRefreshJob: Completed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -2433,7 +2425,7 @@ def idv_usps_auth_token_refresh_job_completed(**extra) # @param [String] exception_message def idv_usps_auth_token_refresh_job_network_error(exception_class:, exception_message:, **extra) track_event( - 'UspsAuthTokenRefreshJob: Network error', + 'UspsAuthTokenRefreshJob: Network error', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter exception_class: exception_class, exception_message: exception_message, **extra, @@ -2443,7 +2435,7 @@ def idv_usps_auth_token_refresh_job_network_error(exception_class:, exception_me # Track when USPS auth token refresh job started def idv_usps_auth_token_refresh_job_started(**extra) track_event( - 'UspsAuthTokenRefreshJob: Started', + 'UspsAuthTokenRefreshJob: Started', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -2475,7 +2467,7 @@ def idv_verify_by_mail_enter_code_submitted( **extra ) track_event( - 'IdV: enter verify by mail code submitted', + 'IdV: enter verify by mail code submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, pii_like_keypaths: pii_like_keypaths, @@ -2498,7 +2490,7 @@ def idv_verify_by_mail_enter_code_visited( **extra ) track_event( - 'IdV: enter verify by mail code visited', + 'IdV: enter verify by mail code visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter source: source, **extra, ) @@ -2509,7 +2501,7 @@ def idv_verify_by_mail_enter_code_visited( def idv_verify_in_person_troubleshooting_option_clicked(flow_path:, **extra) track_event( - 'IdV: verify in person troubleshooting option clicked', + 'IdV: verify in person troubleshooting option clicked', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flow_path: flow_path, **extra, ) @@ -2524,7 +2516,7 @@ def invalid_authenticity_token( **extra ) track_event( - 'Invalid Authenticity Token', + 'Invalid Authenticity Token', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter controller: controller, user_signed_in: user_signed_in, **extra, @@ -2544,7 +2536,7 @@ def irs_attempts_api_events( **extra ) track_event( - 'IRS Attempt API: Events submitted', + 'IRS Attempt API: Events submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter rendered_event_count: rendered_event_count, authenticated: authenticated, elapsed_time: elapsed_time, @@ -2578,7 +2570,7 @@ def logout_initiated( **extra ) track_event( - 'Logout Initiated', + 'Logout Initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, client_id: client_id, client_id_parameter_present: client_id_parameter_present, @@ -2627,7 +2619,7 @@ def multi_factor_auth( **extra ) track_event( - 'Multi-Factor Authentication', + 'Multi-Factor Authentication', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, context: context, @@ -2651,7 +2643,7 @@ def multi_factor_auth( # @param [Integer] enabled_mfa_methods_count number of registered mfa methods for the user def multi_factor_auth_added_phone(enabled_mfa_methods_count:, **extra) track_event( - 'Multi-Factor Authentication: Added phone', + 'Multi-Factor Authentication: Added phone', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { method_name: :phone, enabled_mfa_methods_count: enabled_mfa_methods_count, @@ -2666,7 +2658,7 @@ def multi_factor_auth_added_phone(enabled_mfa_methods_count:, **extra) def multi_factor_auth_added_piv_cac(enabled_mfa_methods_count:, in_account_creation_flow:, **extra) track_event( - 'Multi-Factor Authentication: Added PIV_CAC', + 'Multi-Factor Authentication: Added PIV_CAC', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { method_name: :piv_cac, enabled_mfa_methods_count:, @@ -2682,7 +2674,7 @@ def multi_factor_auth_added_piv_cac(enabled_mfa_methods_count:, in_account_creat def multi_factor_auth_added_totp(enabled_mfa_methods_count:, in_account_creation_flow:, **extra) track_event( - 'Multi-Factor Authentication: Added TOTP', + 'Multi-Factor Authentication: Added TOTP', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { method_name: :totp, in_account_creation_flow:, @@ -2700,7 +2692,7 @@ def multi_factor_auth_added_webauthn( enabled_mfa_methods_count:, **extra ) track_event( - 'Multi-Factor Authentication: Added webauthn', + 'Multi-Factor Authentication: Added webauthn', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { method_name: :webauthn, platform_authenticator: platform_authenticator, @@ -2712,7 +2704,7 @@ def multi_factor_auth_added_webauthn( # A user has downloaded their backup codes def multi_factor_auth_backup_code_download - track_event('Multi-Factor Authentication: download backup code') + track_event('Multi-Factor Authentication: download backup code') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when the user visits the backup code confirmation setup page @@ -2724,7 +2716,7 @@ def multi_factor_auth_enter_backup_code_confirmation_visit( **extra ) track_event( - 'Multi-Factor Authentication: enter backup code confirmation visited', + 'Multi-Factor Authentication: enter backup code confirmation visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { enabled_mfa_methods_count:, in_account_creation_flow:, @@ -2737,7 +2729,7 @@ def multi_factor_auth_enter_backup_code_confirmation_visit( # User visited the page to enter a backup code as their MFA def multi_factor_auth_enter_backup_code_visit(context:, **extra) track_event( - 'Multi-Factor Authentication: enter backup code visited', + 'Multi-Factor Authentication: enter backup code visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, **extra, ) @@ -2756,7 +2748,7 @@ def multi_factor_auth_enter_otp_visit( **extra ) track_event( - 'Multi-Factor Authentication: enter OTP visited', + 'Multi-Factor Authentication: enter OTP visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, multi_factor_auth_method: multi_factor_auth_method, confirmation_for_add_phone: confirmation_for_add_phone, @@ -2769,7 +2761,7 @@ def multi_factor_auth_enter_otp_visit( # User visited the page to enter a personal key as their mfa (legacy flow) def multi_factor_auth_enter_personal_key_visit(context:, **extra) track_event( - 'Multi-Factor Authentication: enter personal key visited', + 'Multi-Factor Authentication: enter personal key visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, **extra, ) @@ -2786,7 +2778,7 @@ def multi_factor_auth_enter_piv_cac( **extra ) track_event( - 'Multi-Factor Authentication: enter PIV CAC visited', + 'Multi-Factor Authentication: enter PIV CAC visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, multi_factor_auth_method: multi_factor_auth_method, piv_cac_configuration_id: piv_cac_configuration_id, @@ -2797,7 +2789,7 @@ def multi_factor_auth_enter_piv_cac( # @param ["authentication","reauthentication","confirmation"] context user session context # User visited the page to enter a TOTP as their mfa def multi_factor_auth_enter_totp_visit(context:, **extra) - track_event('Multi-Factor Authentication: enter TOTP visited', context: context, **extra) + track_event('Multi-Factor Authentication: enter TOTP visited', context: context, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param ["authentication","reauthentication","confirmation"] context user session context @@ -2813,7 +2805,7 @@ def multi_factor_auth_enter_webauthn_visit( **extra ) track_event( - 'Multi-Factor Authentication: enter webAuthn authentication visited', + 'Multi-Factor Authentication: enter webAuthn authentication visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter context: context, multi_factor_auth_method: multi_factor_auth_method, webauthn_configuration_id: webauthn_configuration_id, @@ -2823,12 +2815,12 @@ def multi_factor_auth_enter_webauthn_visit( # Max multi factor auth attempts met def multi_factor_auth_max_attempts - track_event('Multi-Factor Authentication: max attempts reached') + track_event('Multi-Factor Authentication: max attempts reached') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Max multi factor max otp sends reached def multi_factor_auth_max_sends - track_event('Multi-Factor Authentication: max otp sends reached') + track_event('Multi-Factor Authentication: max otp sends reached') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Multi factor selected from auth options list @@ -2837,7 +2829,7 @@ def multi_factor_auth_max_sends # @param [String] selection def multi_factor_auth_option_list(success:, errors:, selection:, **extra) track_event( - 'Multi-Factor Authentication: option list', + 'Multi-Factor Authentication: option list', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, selection: selection, @@ -2847,7 +2839,7 @@ def multi_factor_auth_option_list(success:, errors:, selection:, **extra) # User visited the list of multi-factor options to use def multi_factor_auth_option_list_visit - track_event('Multi-Factor Authentication: option list visited') + track_event('Multi-Factor Authentication: option list visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Multi factor auth phone setup @@ -2869,7 +2861,7 @@ def multi_factor_auth_phone_setup(success:, types:, **extra) track_event( - 'Multi-Factor Authentication: phone setup', + 'Multi-Factor Authentication: phone setup', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, otp_delivery_preference: otp_delivery_preference, @@ -2897,7 +2889,7 @@ def multi_factor_auth_setup( **extra ) track_event( - 'Multi-Factor Authentication Setup', + 'Multi-Factor Authentication Setup', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, multi_factor_auth_method: multi_factor_auth_method, @@ -2907,44 +2899,6 @@ def multi_factor_auth_setup( ) end - # @param [Boolean] success - # @param [String] exception - # @param [Integer] profile_id - # A profile was migrated from a single-region key to a multi-region key - def multi_region_kms_migration_profile_migrated( - success:, - exception:, - profile_id:, - **extra - ) - track_event( - 'Multi-region KMS migration: Profile migrated', - success: success, - exception: exception, - profile_id: profile_id, - **extra, - ) - end - - # @param [Integer] profile_count - # @param [Integer] success_count - # @param [Integer] error_count - # The profile migration job finished running - def multi_region_kms_migration_profile_migration_summary( - profile_count:, - success_count:, - error_count:, - **extra - ) - track_event( - 'Multi-region KMS migration: Profile migration summary', - profile_count: profile_count, - success_count: success_count, - error_count: error_count, - **extra, - ) - end - # @param [Boolean] success # @param [String] exception # @param [Integer] user_id @@ -2956,7 +2910,7 @@ def multi_region_kms_migration_user_migrated( **extra ) track_event( - 'Multi-region KMS migration: User migrated', + 'Multi-region KMS migration: User migrated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, exception: exception, user_id: user_id, @@ -2975,7 +2929,7 @@ def multi_region_kms_migration_user_migration_summary( **extra ) track_event( - 'Multi-region KMS migration: User migration summary', + 'Multi-region KMS migration: User migration summary', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter user_count: user_count, success_count: success_count, error_count: error_count, @@ -3008,7 +2962,7 @@ def oidc_logout_requested( **extra ) track_event( - 'OIDC Logout Requested', + 'OIDC Logout Requested', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, client_id: client_id, client_id_parameter_present: client_id_parameter_present, @@ -3048,7 +3002,7 @@ def oidc_logout_submitted( **extra ) track_event( - 'OIDC Logout Submitted', + 'OIDC Logout Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, client_id: client_id, client_id_parameter_present: client_id_parameter_present, @@ -3088,7 +3042,7 @@ def oidc_logout_visited( **extra ) track_event( - 'OIDC Logout Page Visited', + 'OIDC Logout Page Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, client_id: client_id, client_id_parameter_present: client_id_parameter_present, @@ -3112,7 +3066,7 @@ def openid_connect_authorization_handoff( **extra ) track_event( - 'OpenID Connect: authorization request handoff', + 'OpenID Connect: authorization request handoff', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter client_id: client_id, code_digest: code_digest, **extra, @@ -3126,7 +3080,7 @@ def openid_connect_authorization_handoff( # @param [Hash] errors def openid_connect_bearer_token(success:, ial:, client_id:, errors:, **extra) track_event( - 'OpenID Connect: bearer token authentication', + 'OpenID Connect: bearer token authentication', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, ial: ial, client_id: client_id, @@ -3150,7 +3104,7 @@ def openid_connect_request_authorization( **extra ) track_event( - 'OpenID Connect: authorization request', + 'OpenID Connect: authorization request', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter client_id: client_id, scope: scope, acr_values: acr_values, @@ -3168,7 +3122,7 @@ def openid_connect_request_authorization( # @param [Integer, nil] ial ial level of identity def openid_connect_token(client_id:, user_id:, code_digest:, expires_in:, ial:, **extra) track_event( - 'OpenID Connect: token', + 'OpenID Connect: token', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter client_id: client_id, user_id: user_id, code_digest: code_digest, @@ -3195,7 +3149,7 @@ def otp_delivery_selection( **extra ) track_event( - 'OTP: Delivery Selection', + 'OTP: Delivery Selection', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter otp_delivery_preference: otp_delivery_preference, resend: resend, country_code: country_code, @@ -3213,7 +3167,7 @@ def otp_delivery_selection( # @param [String] country def otp_phone_validation_failed(error:, context:, country:, **extra) track_event( - 'Vendor Phone Validation failed', + 'Vendor Phone Validation failed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter error: error, context: context, country: country, @@ -3225,19 +3179,19 @@ def otp_phone_validation_failed(error:, context:, country:, **extra) # @param [Hash] errors # The user updated their password def password_changed(success:, errors:, **extra) - track_event('Password Changed', success: success, errors: errors, **extra) + track_event('Password Changed', success: success, errors: errors, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success # @param [Hash] errors # The user added a password after verifying their email for account creation def password_creation(success:, errors:, **extra) - track_event('Password Creation', success: success, errors: errors, **extra) + track_event('Password Creation', success: success, errors: errors, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # The user got their password incorrect the max number of times, their session was terminated def password_max_attempts - track_event('Password Max Attempts Reached') + track_event('Password Max Attempts Reached') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -3249,7 +3203,7 @@ def password_max_attempts # The user entered an email address to request a password reset def password_reset_email(success:, errors:, confirmed:, active_profile:, **extra) track_event( - 'Password Reset: Email Submitted', + 'Password Reset: Email Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, confirmed: confirmed, @@ -3265,7 +3219,7 @@ def password_reset_email(success:, errors:, confirmed:, active_profile:, **extra # The user changed the password for their account via the password reset flow def password_reset_password(success:, errors:, profile_deactivated:, **extra) track_event( - 'Password Reset: Password Submitted', + 'Password Reset: Password Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, profile_deactivated: profile_deactivated, @@ -3279,7 +3233,7 @@ def password_reset_password(success:, errors:, profile_deactivated:, **extra) # A password token has been sent for user def password_reset_token(success:, errors:, user_id:, **extra) track_event( - 'Password Reset: Token Submitted', + 'Password Reset: Token Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, user_id: user_id, @@ -3289,17 +3243,17 @@ def password_reset_token(success:, errors:, user_id:, **extra) # Password reset form has been visited. def password_reset_visit - track_event('Password Reset: Email Form Visited') + track_event('Password Reset: Email Form Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Pending account reset cancelled def pending_account_reset_cancelled - track_event('Pending account reset cancelled') + track_event('Pending account reset cancelled') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Pending account reset visited def pending_account_reset_visited - track_event('Pending account reset visited') + track_event('Pending account reset visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -3307,7 +3261,7 @@ def pending_account_reset_visited # Alert user if a personal key was used to sign in def personal_key_alert_about_sign_in(success:, errors:, **extra) track_event( - 'Personal key: Alert user about sign in', + 'Personal key: Alert user about sign in', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -3316,13 +3270,13 @@ def personal_key_alert_about_sign_in(success:, errors:, **extra) # Account reactivated with personal key def personal_key_reactivation - track_event('Personal key reactivation: Account reactivated with personal key') + track_event('Personal key reactivation: Account reactivated with personal key') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Account reactivated with personal key as MFA def personal_key_reactivation_sign_in track_event( - 'Personal key reactivation: Account reactivated with personal key as MFA', + 'Personal key reactivation: Account reactivated with personal key as MFA', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter ) end @@ -3332,7 +3286,7 @@ def personal_key_reactivation_sign_in # Personal key form submitted def personal_key_reactivation_submitted(success:, errors:, pii_like_keypaths:, **extra) track_event( - 'Personal key reactivation: Personal key form submitted', + 'Personal key reactivation: Personal key form submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, pii_like_keypaths: pii_like_keypaths, @@ -3342,14 +3296,14 @@ def personal_key_reactivation_submitted(success:, errors:, pii_like_keypaths:, * # Personal key reactivation visited def personal_key_reactivation_visited - track_event('Personal key reactivation: Personal key form visited') + track_event('Personal key reactivation: Personal key form visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] personal_key_present if personal key is present # Personal key viewed def personal_key_viewed(personal_key_present:, **extra) track_event( - 'Personal key viewed', + 'Personal key viewed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter personal_key_present: personal_key_present, **extra, ) @@ -3370,7 +3324,7 @@ def phone_change_submitted( **extra ) track_event( - 'Phone Number Change: Form submitted', + 'Phone Number Change: Form submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, delivery_preference: delivery_preference, @@ -3382,7 +3336,7 @@ def phone_change_submitted( # User has viewed the page to change their phone number def phone_change_viewed - track_event('Phone Number Change: Visited') + track_event('Phone Number Change: Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -3390,7 +3344,7 @@ def phone_change_viewed # tracks a phone number deletion event def phone_deletion(success:, phone_configuration_id:, **extra) track_event( - 'Phone Number Deletion: Submitted', + 'Phone Number Deletion: Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, phone_configuration_id: phone_configuration_id, **extra, @@ -3400,7 +3354,7 @@ def phone_deletion(success:, phone_configuration_id:, **extra) # @identity.idp.previous_event_name User Registration: piv cac disabled # Tracks when user's piv cac is disabled def piv_cac_disabled - track_event('PIV CAC disabled') + track_event('PIV CAC disabled') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -3408,7 +3362,7 @@ def piv_cac_disabled # tracks piv cac login event def piv_cac_login(success:, errors:, **extra) track_event( - 'PIV/CAC Login', + 'PIV/CAC Login', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -3420,7 +3374,7 @@ def piv_cac_login(success:, errors:, **extra) # @param [Boolean] in_account_creation_flow def piv_cac_setup_visit(in_account_creation_flow:, **extra) track_event( - 'PIV CAC setup visited', + 'PIV CAC setup visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter in_account_creation_flow:, **extra, ) @@ -3433,7 +3387,7 @@ def piv_cac_setup_visit(in_account_creation_flow:, **extra) # User was redirected to the login.gov policy page def policy_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra) track_event( - 'Policy Page Redirect', + 'Policy Page Redirect', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_url: redirect_url, step: step, location: location, @@ -3445,13 +3399,13 @@ def policy_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra) # @param [String] error # Tracks if a Profile encryption is invalid def profile_encryption_invalid(error:, **extra) - track_event('Profile Encryption: Invalid', error: error, **extra) + track_event('Profile Encryption: Invalid', error: error, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @see #profile_personal_key_create_notifications # User has chosen to receive a new personal key def profile_personal_key_create - track_event('Profile: Created new personal key') + track_event('Profile: Created new personal key') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [true] success this event always succeeds @@ -3462,7 +3416,7 @@ def profile_personal_key_create # were sent to phone numbers and email addresses for the user def profile_personal_key_create_notifications(success:, emails:, sms_message_ids:, **extra) track_event( - 'Profile: Created new personal key notifications', + 'Profile: Created new personal key notifications', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, emails: emails, sms_message_ids: sms_message_ids, @@ -3472,21 +3426,21 @@ def profile_personal_key_create_notifications(success:, emails:, sms_message_ids # User has visited the page that lets them confirm if they want a new personal key def profile_personal_key_visit - track_event('Profile: Visited new personal key') + track_event('Profile: Visited new personal key') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name Proofing Address Timeout # The job for address verification (PhoneFinder) did not record a result in the expected # place during the expected time frame def proofing_address_result_missing - track_event('Proofing Address Result Missing') + track_event('Proofing Address Result Missing') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @identity.idp.previous_event_name Proofing Document Timeout # The job for document authentication did not record a result in the expected # place during the expected time frame def proofing_document_result_missing - track_event('Proofing Document Result Missing') + track_event('Proofing Document Result Missing') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when a user triggered a rate limiter @@ -3494,7 +3448,7 @@ def proofing_document_result_missing # @identity.idp.previous_event_name Throttler Rate Limit Triggered def rate_limit_reached(limiter_type:, **extra) track_event( - 'Rate Limit Reached', + 'Rate Limit Reached', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter limiter_type: limiter_type, **extra, ) @@ -3503,17 +3457,17 @@ def rate_limit_reached(limiter_type:, **extra) # Rate limit triggered # @param [String] type def rate_limit_triggered(type:, **extra) - track_event('Rate Limit Triggered', type: type, **extra) + track_event('Rate Limit Triggered', type: type, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Account profile reactivation submitted def reactivate_account_submit - track_event('Reactivate Account Submitted') + track_event('Reactivate Account Submitted') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Account profile reactivation page visited def reactivate_account_visit - track_event('Reactivate Account Visited') + track_event('Reactivate Account Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # The result of a reCAPTCHA verification request was received @@ -3533,7 +3487,7 @@ def recaptcha_verify_result_received( **extra ) track_event( - 'reCAPTCHA verify result received', + 'reCAPTCHA verify result received', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { recaptcha_result:, score_threshold:, @@ -3555,7 +3509,7 @@ def remembered_device_used_for_authentication( **extra ) track_event( - 'Remembered device used for authentication', + 'Remembered device used for authentication', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter cookie_created_at: cookie_created_at, cookie_age_seconds: cookie_age_seconds, **extra, @@ -3571,7 +3525,7 @@ def remote_logout_completed( **extra ) track_event( - 'Remote Logout completed', + 'Remote Logout completed', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter service_provider: service_provider, user_id: user_id, **extra, @@ -3587,7 +3541,7 @@ def remote_logout_initiated( **extra ) track_event( - 'Remote Logout initiated', + 'Remote Logout initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter service_provider: service_provider, saml_request_valid: saml_request_valid, **extra, @@ -3598,7 +3552,7 @@ def remote_logout_initiated( # Tracks request for resending confirmation for new emails to an account def resend_add_email_request(success:, **extra) track_event( - 'Resend Add Email Requested', + 'Resend Add Email Requested', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, **extra, ) @@ -3615,7 +3569,7 @@ def response_timed_out( **extra ) track_event( - 'Response Timed Out', + 'Response Timed Out', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter backtrace: backtrace, exception_message: exception_message, exception_class: exception_class, @@ -3636,7 +3590,7 @@ def return_to_sp_cancelled( **extra ) track_event( - 'Return to SP: Cancelled', + 'Return to SP: Cancelled', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_url: redirect_url, step: step, location: location, @@ -3652,7 +3606,7 @@ def return_to_sp_cancelled( # @param [String] location def return_to_sp_failure_to_proof(redirect_url:, flow: nil, step: nil, location: nil, **extra) track_event( - 'Return to SP: Failed to proof', + 'Return to SP: Failed to proof', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_url: redirect_url, flow: flow, step: step, @@ -3666,7 +3620,7 @@ def return_to_sp_failure_to_proof(redirect_url:, flow: nil, step: nil, location: # @param [Hash] errors def rules_of_use_submitted(success: nil, errors: nil, **extra) track_event( - 'Rules of Use Submitted', + 'Rules of Use Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, **extra, @@ -3675,7 +3629,7 @@ def rules_of_use_submitted(success: nil, errors: nil, **extra) # Tracks when rules of use is visited def rules_of_use_visit - track_event('Rules of Use Visited') + track_event('Rules of Use Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Record SAML authentication payload Hash @@ -3695,7 +3649,7 @@ def saml_auth( **extra ) track_event( - 'SAML Auth', + 'SAML Auth', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, nameid_format: nameid_format, @@ -3719,7 +3673,7 @@ def saml_auth_request( **extra ) track_event( - 'SAML Auth Request', + 'SAML Auth Request', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { requested_ial: requested_ial, requested_aal_authn_context: requested_aal_authn_context, @@ -3733,12 +3687,12 @@ def saml_auth_request( # User dismissed the second MFA reminder page # @param [Boolean] opted_to_add Whether the user chose to add a method def second_mfa_reminder_dismissed(opted_to_add:, **extra) - track_event('Second MFA Reminder Dismissed', opted_to_add:, **extra) + track_event('Second MFA Reminder Dismissed', opted_to_add:, **extra) # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # User visited the second MFA reminder page def second_mfa_reminder_visit - track_event('Second MFA Reminder Visited') + track_event('Second MFA Reminder Visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when security event is received @@ -3758,7 +3712,7 @@ def security_event_received( **extra ) track_event( - 'RISC: Security event received', + 'RISC: Security event received', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, error_code: error_code, errors: errors, @@ -3771,22 +3725,22 @@ def security_event_received( # tracks if the session is kept alive def session_kept_alive - track_event('Session Kept Alive') + track_event('Session Kept Alive') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # tracks if the session timed out def session_timed_out - track_event('Session Timed Out') + track_event('Session Timed Out') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # tracks when a user's session is timed out def session_total_duration_timeout - track_event('User Maximum Session Length Exceeded') + track_event('User Maximum Session Length Exceeded') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks if a user clicks the "You will also need" accordion on the homepage def sign_in_idv_requirements_accordion_clicked - track_event('Sign In: IdV requirements accordion clicked') + track_event('Sign In: IdV requirements accordion clicked') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] flash @@ -3794,7 +3748,7 @@ def sign_in_idv_requirements_accordion_clicked # tracks when a user visits the sign in page def sign_in_page_visit(flash:, stored_location:, **extra) track_event( - 'Sign in page visited', + 'Sign in page visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter flash: flash, stored_location: stored_location, **extra, @@ -3814,7 +3768,7 @@ def sms_opt_in_submitted( **extra ) track_event( - 'SMS Opt-In: Submitted', + 'SMS Opt-In: Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, new_user: new_user, has_other_auth_methods: has_other_auth_methods, @@ -3834,7 +3788,7 @@ def sms_opt_in_visit( **extra ) track_event( - 'SMS Opt-In: Visited', + 'SMS Opt-In: Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter new_user: new_user, has_other_auth_methods: has_other_auth_methods, phone_configuration_id: phone_configuration_id, @@ -3844,17 +3798,17 @@ def sms_opt_in_visit( # Tracks when a user is bounced back from the service provider due to an integration issue. def sp_handoff_bounced_detected - track_event('SP handoff bounced detected') + track_event('SP handoff bounced detected') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when a user visits the bounced page. def sp_handoff_bounced_visit - track_event('SP handoff bounced visited') + track_event('SP handoff bounced visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when a user visits the "This agency no longer uses Login.gov" page. def sp_inactive_visit - track_event('SP inactive visited') + track_event('SP inactive visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when a user is redirected back to the service provider @@ -3862,7 +3816,7 @@ def sp_inactive_visit # @param [Integer] billed_ial def sp_redirect_initiated(ial:, billed_ial:, **extra) track_event( - 'SP redirect initiated', + 'SP redirect initiated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter ial: ial, billed_ial: billed_ial, **extra, @@ -3873,7 +3827,7 @@ def sp_redirect_initiated(ial:, billed_ial:, **extra) # @param [String] issuer issuer of the service provider consent to be revoked def sp_revoke_consent_revoked(issuer:, **extra) track_event( - 'SP Revoke Consent: Revoked', + 'SP Revoke Consent: Revoked', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter issuer: issuer, **extra, ) @@ -3883,7 +3837,7 @@ def sp_revoke_consent_revoked(issuer:, **extra) # @param [String] issuer which issuer def sp_revoke_consent_visited(issuer:, **extra) track_event( - 'SP Revoke Consent: Visited', + 'SP Revoke Consent: Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter issuer: issuer, **extra, ) @@ -3913,7 +3867,7 @@ def telephony_otp_sent( **extra ) track_event( - 'Telephony: OTP sent', + 'Telephony: OTP sent', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { area_code: area_code, country_code: country_code, @@ -3942,7 +3896,7 @@ def totp_setup_visit( **extra ) track_event( - 'TOTP Setup Visited', + 'TOTP Setup Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter user_signed_up:, totp_secret_present:, enabled_mfa_methods_count:, @@ -3953,7 +3907,7 @@ def totp_setup_visit( # Tracks when a user disabled a TOTP device def totp_user_disabled - track_event('TOTP: User Disabled') + track_event('TOTP: User Disabled') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] controller @@ -3967,7 +3921,7 @@ def unsafe_redirect_error( **extra ) track_event( - 'Unsafe Redirect', + 'Unsafe Redirect', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter controller: controller, referer: referer, user_signed_in: user_signed_in, @@ -3980,7 +3934,7 @@ def unsafe_redirect_error( # @param [String] authenticated_at def user_2fa_reauthentication_required(auth_method:, authenticated_at:, **extra) track_event( - 'User 2FA Reauthentication Required', + 'User 2FA Reauthentication Required', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter auth_method: auth_method, authenticated_at: authenticated_at, **extra, @@ -3991,7 +3945,7 @@ def user_2fa_reauthentication_required(auth_method:, authenticated_at:, **extra) # @param [String] authentication_type def user_marked_authed(authentication_type:, **extra) track_event( - 'User marked authenticated', + 'User marked authenticated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter authentication_type: authentication_type, **extra, ) @@ -4002,7 +3956,7 @@ def user_marked_authed(authentication_type:, **extra) # @param [String] path Path where this event was encountered. def user_prompted_before_navigation(path:, **extra) track_event( - 'User prompted before navigation', + 'User prompted before navigation', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter path: path, **extra, ) @@ -4014,7 +3968,7 @@ def user_prompted_before_navigation(path:, **extra) # @param [Integer] seconds Amount of time user has been on page since prompt. def user_prompted_before_navigation_and_still_on_page(path:, seconds:, **extra) track_event( - 'User prompted before navigation and still on page', + 'User prompted before navigation and still on page', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter path: path, seconds: seconds, **extra, @@ -4036,7 +3990,7 @@ def user_registration_2fa_setup( **extra ) track_event( - 'User Registration: 2FA Setup', + 'User Registration: 2FA Setup', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, errors: errors, @@ -4052,7 +4006,7 @@ def user_registration_2fa_setup( # @param [Integer] enabled_mfa_methods_count Number of MFAs associated with user at time of visit def user_registration_2fa_setup_visit(enabled_mfa_methods_count:, **extra) track_event( - 'User Registration: 2FA Setup visited', + 'User Registration: 2FA Setup visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enabled_mfa_methods_count:, **extra, ) @@ -4077,7 +4031,7 @@ def user_registration_agency_handoff_page_visit( **extra ) track_event( - 'User registration: agency handoff visited', + 'User registration: agency handoff visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter ial2: ial2, ialmax: ialmax, service_provider_name: service_provider_name, @@ -4093,7 +4047,7 @@ def user_registration_agency_handoff_page_visit( # @param [String] request_came_from the controller/action the request came from def user_registration_cancellation(request_came_from:, **extra) track_event( - 'User registration: cancellation visited', + 'User registration: cancellation visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter request_came_from: request_came_from, **extra, ) @@ -4118,7 +4072,7 @@ def user_registration_complete( **extra ) track_event( - 'User registration: complete', + 'User registration: complete', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter ial2: ial2, ialmax: ialmax, service_provider_name: service_provider_name, @@ -4147,7 +4101,7 @@ def user_registration_email( **extra ) track_event( - 'User Registration: Email Submitted', + 'User Registration: Email Submitted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, rate_limited: rate_limited, @@ -4173,7 +4127,7 @@ def user_registration_email_confirmation( **extra ) track_event( - 'User Registration: Email Confirmation', + 'User Registration: Email Confirmation', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, errors: errors, error_details: error_details, @@ -4184,7 +4138,7 @@ def user_registration_email_confirmation( # Tracks when user visits enter email page def user_registration_enter_email_visit - track_event('User Registration: enter email visited') + track_event('User Registration: enter email visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [Boolean] success @@ -4202,7 +4156,7 @@ def user_registration_mfa_setup_complete( **extra ) track_event( - 'User Registration: MFA Setup Complete', + 'User Registration: MFA Setup Complete', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, mfa_method_counts: mfa_method_counts, @@ -4218,7 +4172,7 @@ def user_registration_mfa_setup_complete( # Tracks when user visits the phone setup step during registration def user_registration_phone_setup_visit(enabled_mfa_methods_count:, **extra) track_event( - 'User Registration: phone setup visited', + 'User Registration: phone setup visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enabled_mfa_methods_count: enabled_mfa_methods_count, **extra, ) @@ -4226,12 +4180,12 @@ def user_registration_phone_setup_visit(enabled_mfa_methods_count:, **extra) # Tracks when user skips Suggest Another MFA Page def user_registration_suggest_another_mfa_notice_skipped - track_event('User Registration: Suggest Another MFA Notice Skipped') + track_event('User Registration: Suggest Another MFA Notice Skipped') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # Tracks when user visits Suggest Another MFA Page def user_registration_suggest_another_mfa_notice_visited - track_event('User Registration: Suggest Another MFA Notice visited') + track_event('User Registration: Suggest Another MFA Notice visited') # rubocop:disable IdentityIdp/AnalyticsEventNameLinter end # @param [String] mfa_method @@ -4241,7 +4195,7 @@ def user_registration_user_fully_registered( **extra ) track_event( - 'User Registration: User Fully Registered', + 'User Registration: User Fully Registered', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { mfa_method: mfa_method, **extra, @@ -4258,7 +4212,7 @@ def user_reinstated( **extra ) track_event( - 'User Suspension: Reinstated', + 'User Suspension: Reinstated', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, error_message: error_message, @@ -4276,7 +4230,7 @@ def user_suspended( **extra ) track_event( - 'User Suspension: Suspended', + 'User Suspension: Suspended', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter { success: success, error_message: error_message, @@ -4288,7 +4242,7 @@ def user_suspended( # Tracks when the user is suspended and attempts to sign in, triggering the please call page. def user_suspended_please_call_visited(**extra) track_event( - 'User Suspension: Please call visited', + 'User Suspension: Please call visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter **extra, ) end @@ -4306,7 +4260,7 @@ def usps_ippaas_enrollment_created( **extra ) track_event( - 'USPS IPPaaS enrollment created', + 'USPS IPPaaS enrollment created', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter enrollment_code: enrollment_code, enrollment_id: enrollment_id, second_address_line_present: second_address_line_present, @@ -4324,7 +4278,7 @@ def vendor_outage( **extra ) track_event( - 'Vendor Outage', + 'Vendor Outage', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter redirect_from: redirect_from, vendor_status: vendor_status, **extra, @@ -4336,7 +4290,7 @@ def vendor_outage( # Tracks when WebAuthn is deleted def webauthn_deleted(success:, mfa_method_counts:, pii_like_keypaths:, **extra) track_event( - 'WebAuthn Deleted', + 'WebAuthn Deleted', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter success: success, mfa_method_counts: mfa_method_counts, pii_like_keypaths: pii_like_keypaths, @@ -4352,7 +4306,7 @@ def webauthn_deleted(success:, mfa_method_counts:, pii_like_keypaths:, **extra) def webauthn_setup_visit(platform_authenticator:, errors:, enabled_mfa_methods_count:, success:, **extra) track_event( - 'WebAuthn Setup Visited', + 'WebAuthn Setup Visited', # rubocop:disable IdentityIdp/AnalyticsEventNameLinter # rubocop:disable IdentityIdp/AnalyticsEventNameLinter platform_authenticator: platform_authenticator, errors: errors, enabled_mfa_methods_count: enabled_mfa_methods_count, diff --git a/app/services/document_capture_session_async_result.rb b/app/services/document_capture_session_async_result.rb deleted file mode 100644 index cfaa9d7ac73..00000000000 --- a/app/services/document_capture_session_async_result.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -# Used in async document capture flow by LambdaJobs::Runner/Idv::Proofing.document_job_class -DocumentCaptureSessionAsyncResult = RedactedStruct.new( - :id, - :status, - :result, - :pii, - keyword_init: true, - allowed_members: [:id, :status, :result], -) do - self::IN_PROGRESS = 'in_progress' - self::DONE = 'done' - self::MISSING = 'missing' - - def self.redis_key_prefix - 'dcs-async:result' - end - - def self.missing - new(status: DocumentCaptureSessionAsyncResult::MISSING) - end - - def missing? - status == DocumentCaptureSessionAsyncResult::MISSING - end - - def done? - status == DocumentCaptureSessionAsyncResult::DONE - end - - def success? - done? && result[:success] - end - - def in_progress? - status == DocumentCaptureSessionAsyncResult::IN_PROGRESS - end - - def attention_with_barcode? - done? && result[:attention_with_barcode] - end - - alias_method :pii_from_doc, :pii -end diff --git a/app/services/gpo_reminder_sender.rb b/app/services/gpo_reminder_sender.rb index 32dcf07a20d..867cbd77130 100644 --- a/app/services/gpo_reminder_sender.rb +++ b/app/services/gpo_reminder_sender.rb @@ -7,7 +7,12 @@ def send_emails(for_letters_sent_before) profiles_due_for_reminder(letter_eligible_range).each do |profile| profile.user.send_email_to_all_addresses(:gpo_reminder) - profile.gpo_confirmation_codes.first.update(reminder_sent_at: Time.zone.now) + profile.gpo_confirmation_codes.all.each do |gpo_code| + next if gpo_code.reminder_sent_at + next unless letter_eligible_range.cover?(gpo_code.created_at) + + gpo_code.update(reminder_sent_at: Time.zone.now) + end analytics.idv_gpo_reminder_email_sent(user_id: profile.user.uuid) end end diff --git a/app/services/idv/steps/doc_auth_base_step.rb b/app/services/idv/steps/doc_auth_base_step.rb index 593bb51d77a..64679881331 100644 --- a/app/services/idv/steps/doc_auth_base_step.rb +++ b/app/services/idv/steps/doc_auth_base_step.rb @@ -7,10 +7,6 @@ def initialize(flow) private - def capture_secondary_id_enabled? - current_user.establishing_in_person_enrollment.capture_secondary_id_enabled - end - def save_proofing_components return unless current_user diff --git a/app/services/idv/steps/in_person/address_step.rb b/app/services/idv/steps/in_person/address_step.rb index 7b53f4943f7..7a28e11137b 100644 --- a/app/services/idv/steps/in_person/address_step.rb +++ b/app/services/idv/steps/in_person/address_step.rb @@ -9,20 +9,14 @@ def self.analytics_visited_event end def analytics_submitted_event - if capture_secondary_id_enabled? - :idv_in_person_proofing_residential_address_submitted - else - :idv_in_person_proofing_address_submitted - end + :idv_in_person_proofing_residential_address_submitted end def call attrs = Idv::InPerson::AddressForm::ATTRIBUTES - if capture_secondary_id_enabled? - attrs = attrs.difference([:same_address_as_id]) - flow_session[:pii_from_user][:same_address_as_id] = 'false' if updating_address? - end + attrs = attrs.difference([:same_address_as_id]) + flow_session[:pii_from_user][:same_address_as_id] = 'false' if updating_address? attrs.each do |attr| flow_session[:pii_from_user][attr] = flow_params[attr] @@ -35,7 +29,6 @@ def call def extra_view_variables { - capture_secondary_id_enabled: capture_secondary_id_enabled?, form:, pii:, updating_address: updating_address?, @@ -61,8 +54,7 @@ def flow_params end def form - @form ||= Idv::InPerson::AddressForm. - new(capture_secondary_id_enabled: capture_secondary_id_enabled?) + @form ||= Idv::InPerson::AddressForm.new end def form_submit diff --git a/app/services/idv/steps/in_person/state_id_step.rb b/app/services/idv/steps/in_person/state_id_step.rb index 872387abe32..c3079c55468 100644 --- a/app/services/idv/steps/in_person/state_id_step.rb +++ b/app/services/idv/steps/in_person/state_id_step.rb @@ -23,20 +23,18 @@ def call formatted_dob = MemorableDateComponent.extract_date_param flow_params&.[](:dob) pii_from_user[:dob] = formatted_dob if formatted_dob - if capture_secondary_id_enabled? - if pii_from_user[:same_address_as_id] == 'true' - copy_state_id_address_to_residential_address(pii_from_user) - mark_step_complete(:address) - redirect_to idv_in_person_ssn_url - end - - if initial_state_of_same_address_as_id == 'true' && - pii_from_user[:same_address_as_id] == 'false' - clear_residential_address(pii_from_user) - mark_step_incomplete(:address) - end + if pii_from_user[:same_address_as_id] == 'true' + copy_state_id_address_to_residential_address(pii_from_user) + mark_step_complete(:address) + redirect_to idv_in_person_ssn_url end + if initial_state_of_same_address_as_id == 'true' && + pii_from_user[:same_address_as_id] == 'false' + clear_residential_address(pii_from_user) + mark_step_incomplete(:address) + end + if flow_session['Idv::Steps::InPerson::AddressStep'] redirect_to idv_in_person_verify_info_url end @@ -44,7 +42,6 @@ def call def extra_view_variables { - capture_secondary_id_enabled: capture_secondary_id_enabled?, form:, pii:, parsed_dob:, @@ -104,10 +101,7 @@ def flow_params end def form - @form ||= Idv::StateIdForm.new( - current_user, - capture_secondary_id_enabled: capture_secondary_id_enabled?, - ) + @form ||= Idv::StateIdForm.new(current_user) end def form_submit diff --git a/app/services/reporting/account_deletion_rate_report.rb b/app/services/reporting/account_deletion_rate_report.rb new file mode 100644 index 00000000000..f5c9ed43399 --- /dev/null +++ b/app/services/reporting/account_deletion_rate_report.rb @@ -0,0 +1,42 @@ +module Reporting + class AccountDeletionRateReport + attr_reader :report_date + + def initialize(report_date = Time.zone.today) + @report_date = report_date + end + + def account_deletion_report + table = [] + table << ['Deleted Users', 'Total Users', 'Deletion Rate'] + table << [deleted_user_count, users_and_deleted_for_period, deletion_rate] + table + end + + private + + def deleted_user_count + @deleted_user_count ||= DeletedUser.where(user_created_at: start_date..end_date).count + end + + def user_count + @user_count ||= User.where(created_at: start_date..end_date).count + end + + def users_and_deleted_for_period + deleted_user_count + user_count + end + + def deletion_rate + deleted_user_count.to_f / users_and_deleted_for_period.to_f + end + + def start_date + (report_date - 30.days).beginning_of_day + end + + def end_date + report_date.beginning_of_day + 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 b116838f56d..f2ef64237ec 100644 --- a/app/services/usps_in_person_proofing/enrollment_helper.rb +++ b/app/services/usps_in_person_proofing/enrollment_helper.rb @@ -8,10 +8,9 @@ def schedule_in_person_enrollment(user, pii) enrollment.current_address_matches_id = pii['same_address_as_id'] enrollment.save! - # If we're using secondary ID capture (aka double address verification), - # then send the state ID address to USPS. Otherwise send the residential address. + # Send state ID address to USPS pii = pii.to_h - if enrollment.capture_secondary_id_enabled? && !enrollment.current_address_matches_id? + if !enrollment.current_address_matches_id? pii = pii.except(*SECONDARY_ID_ADDRESS_MAP.values). transform_keys(SECONDARY_ID_ADDRESS_MAP) end diff --git a/app/validators/idv/form_state_id_validator.rb b/app/validators/idv/form_state_id_validator.rb index cb993bae471..62dbe02e3e1 100644 --- a/app/validators/idv/form_state_id_validator.rb +++ b/app/validators/idv/form_state_id_validator.rb @@ -7,15 +7,12 @@ module FormStateIdValidator validates :first_name, :last_name, :dob, + :identity_doc_address1, + :identity_doc_city, :state_id_jurisdiction, :state_id_number, presence: true - validates :identity_doc_address1, - :identity_doc_city, - presence: true, - if: :capture_secondary_id_enabled? - validates_with UspsInPersonProofing::TransliterableValidator, fields: [:first_name, :last_name, :identity_doc_city], reject_chars: /[^A-Za-z\-' ]/, diff --git a/app/validators/idv/in_person/form_address_validator.rb b/app/validators/idv/in_person/form_address_validator.rb index 928b377caff..00a44ca4d36 100644 --- a/app/validators/idv/in_person/form_address_validator.rb +++ b/app/validators/idv/in_person/form_address_validator.rb @@ -5,10 +5,6 @@ module FormAddressValidator include Idv::FormAddressValidator included do - validates :same_address_as_id, - presence: true, - unless: :capture_secondary_id_enabled? - validates_with UspsInPersonProofing::TransliterableValidator, fields: [:city], reject_chars: /[^A-Za-z\-' ]/, diff --git a/app/views/accounts/_password_reset.html.erb b/app/views/accounts/_password_reset.html.erb index 4aaf4b8bd80..4ff48de0c41 100644 --- a/app/views/accounts/_password_reset.html.erb +++ b/app/views/accounts/_password_reset.html.erb @@ -2,7 +2,7 @@
<%= t('account.index.reactivation.instructions') %>
-+
<%= link_to t('account.index.reactivation.link'), reactivate_account_path %>
<% end %> diff --git a/app/views/accounts/_pending_profile_gpo.html.erb b/app/views/accounts/_pending_profile_gpo.html.erb index f613180fda4..5ca40bc2edc 100644 --- a/app/views/accounts/_pending_profile_gpo.html.erb +++ b/app/views/accounts/_pending_profile_gpo.html.erb @@ -2,7 +2,7 @@<%= t('account.index.verification.instructions') %>
-+
<%= link_to t('account.index.verification.reactivate_button'), idv_verify_by_mail_enter_code_path %>
<% end %> diff --git a/app/views/accounts/_service_provider_continue.html.erb b/app/views/accounts/_service_provider_continue.html.erb index 6e3aef58423..cb4f24109fe 100644 --- a/app/views/accounts/_service_provider_continue.html.erb +++ b/app/views/accounts/_service_provider_continue.html.erb @@ -1,3 +1,3 @@ -<%= render AlertComponent.new(type: :info, text_tag: 'div') do %> +<%= render AlertComponent.new(type: :info) do %> <%= link_to(t('account.index.continue_to_service_provider', service_provider: presenter.sp_name), presenter.sp_session_request_url) %> <% end %> diff --git a/app/views/idv/by_mail/enter_code/index.html.erb b/app/views/idv/by_mail/enter_code/index.html.erb index 22c000e0976..e7b5c8c78d1 100644 --- a/app/views/idv/by_mail/enter_code/index.html.erb +++ b/app/views/idv/by_mail/enter_code/index.html.erb @@ -13,6 +13,10 @@ <% title t('idv.gpo.title') %> <% end %> +<%= render AlertComponent.new(type: :warning, class: 'margin-bottom-3') do %> + <%= t('idv.gpo.change_to_verification_code_html') %> +<% end %> + <%= render AlertComponent.new(type: :info, class: 'margin-bottom-4', text_tag: 'div') do %><%= t('idv.gpo.alert_info') %> diff --git a/app/views/idv/in_person/address.html.erb b/app/views/idv/in_person/address.html.erb index f2b02c809a8..bf5a5799ff0 100644 --- a/app/views/idv/in_person/address.html.erb +++ b/app/views/idv/in_person/address.html.erb @@ -6,36 +6,21 @@ <%= render PageHeadingComponent.new.with_content(t('in_person_proofing.headings.address')) %> <% end %> -<% unless capture_secondary_id_enabled %> -
- <%= t('in_person_proofing.body.address.info') %> - <%= new_tab_link_to( - t('in_person_proofing.body.address.learn_more'), - MarketingSite.help_center_article_url( - category: 'verify-your-identity', - article: 'verify-your-identity-in-person', - ), - ) %> -
-<% end %> - <%= simple_form_for( form, url: url_for, method: 'PUT', html: { autocomplete: 'off' } ) do |f| %> - <% if capture_secondary_id_enabled %> - <%= render ValidatedFieldComponent.new( - collection: us_states_territories, - form: f, - input_html: { class: 'address-state-selector' }, - label: t('idv.form.state'), - label_html: { class: 'usa-label' }, - name: :state, - prompt: t('in_person_proofing.form.address.state_prompt'), - required: true, - selected: pii[:state], - ) %> - <% end %> + <%= render ValidatedFieldComponent.new( + collection: us_states_territories, + form: f, + input_html: { class: 'address-state-selector' }, + label: t('idv.form.state'), + label_html: { class: 'usa-label' }, + name: :state, + prompt: t('in_person_proofing.form.address.state_prompt'), + required: true, + selected: pii[:state], + ) %> <%= render ValidatedFieldComponent.new( form: f, hint: t('in_person_proofing.form.state_id.address1_hint'), @@ -52,7 +37,7 @@ hint: t('in_person_proofing.form.state_id.address2_hint'), hint_html: { class: ['display-none', 'puerto-rico-extras'] }, input_html: { value: pii[:address2] }, - label: capture_secondary_id_enabled ? t('idv.form.address2') : t('idv.form.address2_optional'), + label: t('idv.form.address2'), label_html: { class: 'usa-label' }, maxlength: 255, name: :address2, @@ -68,19 +53,6 @@ required: true, ) %> - <% unless capture_secondary_id_enabled %> - <%= render ValidatedFieldComponent.new( - collection: us_states_territories, - form: f, - label: t('idv.form.state'), - label_html: { class: 'usa-label' }, - name: :state, - prompt: t('in_person_proofing.form.address.state_prompt'), - required: true, - selected: pii[:state], - ) %> - <% end %> -<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %>
-<%= t('in_person_proofing.body.barcode.deadline_restart') %>
+<%= t('in_person_proofing.body.barcode.deadline_restart') %>
<% end %><%= t('in_person_proofing.process.state_id.info') %>
<% end %> - <% if @presenter.needs_proof_of_address? %> - <% c.with_item(heading: t('in_person_proofing.process.proof_of_address.heading')) do %> -<%= t('in_person_proofing.process.proof_of_address.info') %>
-<%= t('in_person_proofing.process.proof_of_address.physical_or_digital_copy') %>
- <% end %> - <% end %> <% end %><%= t('in_person_proofing.body.barcode.questions') %> diff --git a/app/views/idv/in_person/state_id.html.erb b/app/views/idv/in_person/state_id.html.erb index fed60a92539..4f1f255aafc 100644 --- a/app/views/idv/in_person/state_id.html.erb +++ b/app/views/idv/in_person/state_id.html.erb @@ -96,21 +96,19 @@ %> - <% if capture_secondary_id_enabled %> -
+ <%= help_link = link_to( t('idv.troubleshooting.options.learn_more_verify_by_mail'), help_center_redirect_url( @@ -9,14 +9,13 @@ ), { style: "text-decoration: 'underline'" }, ) - t( - 'idv.messages.gpo_reminder.body_html', + 'user_mailer.letter_reminder_14_days.body_html', date_letter_was_sent: @gpo_verification_pending_at, app_name: APP_NAME, help_link: help_link, ) %> -
+|
- <%= link_to t('idv.messages.gpo_reminder.finish'),
+ <%= link_to t('user_mailer.letter_reminder_14_days.finish'),
idv_verify_by_mail_enter_code_url,
target: '_blank',
class: 'float-center',
@@ -44,9 +43,9 @@
<%= t( - 'idv.messages.gpo_reminder.did_not_get_a_letter_html', + 'user_mailer.letter_reminder_14_days.did_not_get_a_letter_html', another_letter_link_html: link_to( - t('idv.messages.gpo_reminder.sign_in_and_request_another_letter'), + t('user_mailer.letter_reminder_14_days.sign_in_and_request_another_letter'), idv_verify_by_mail_enter_code_url(did_not_receive_letter: 1), { style: "text-decoration: 'underline'" }, ), diff --git a/app/views/user_mailer/in_person_failed.html.erb b/app/views/user_mailer/in_person_failed.html.erb index bd9117a6f34..4fe54f94d4c 100644 --- a/app/views/user_mailer/in_person_failed.html.erb +++ b/app/views/user_mailer/in_person_failed.html.erb @@ -16,9 +16,6 @@ <%= t('user_mailer.in_person_failed.verifying_identity') %>
<%= t('in_person_proofing.process.state_id.info') %> |
|
4 |
-
- <%= t('in_person_proofing.process.proof_of_address.heading') %>-<%= t('in_person_proofing.process.proof_of_address.info') %> -
<%= t('in_person_proofing.process.proof_of_address.physical_or_digital_copy') %> - |
-
<%= t('in_person_proofing.body.barcode.questions') %> diff --git a/config/application.yml.default b/config/application.yml.default index 4c183ce2dd8..43449f66b72 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -124,7 +124,6 @@ idv_phone_question_a_b_testing: '{"show_phone_question":0}' idv_send_link_attempt_window_in_minutes: 10 idv_send_link_max_attempts: 5 idv_sp_required: false -in_person_capture_secondary_id_enabled: false in_person_public_address_search_enabled: false in_person_doc_auth_button_enabled: true in_person_email_reminder_early_benchmark_in_days: 11 diff --git a/config/initializers/job_configurations.rb b/config/initializers/job_configurations.rb index bdb591d68be..5c76dd70d6f 100644 --- a/config/initializers/job_configurations.rb +++ b/config/initializers/job_configurations.rb @@ -194,15 +194,6 @@ cron: cron_24h, args: -> { [Time.zone.today] }, }, - # Job to backfill encrypted_pii_recovery_multi_region on profiles - multi_region_kms_migration_profile_migration: { - class: 'MultiRegionKmsMigration::ProfileMigrationJob', - cron: cron_12m, - kwargs: { - profile_count: IdentityConfig.store.multi_region_kms_migration_jobs_profile_count, - statement_timeout: IdentityConfig.store.multi_region_kms_migration_jobs_profile_timeout, - }, - }, # Job to backfill encrypted_pii_recovery_multi_region on users multi_region_kms_migration_user_migration: { class: 'MultiRegionKmsMigration::UserMigrationJob', diff --git a/config/locales/account/en.yml b/config/locales/account/en.yml index 9bb8aca31ec..c0899d0f7b7 100644 --- a/config/locales/account/en.yml +++ b/config/locales/account/en.yml @@ -53,7 +53,7 @@ en: totp_confirm_delete: Yes, remove authentication app unknown_location: unknown location verification: - instructions: Your account requires a one-time code to be verified. + instructions: Your account requires a verification code to be verified. reactivate_button: Enter the code you received via US mail success: We verified your information webauthn: Security key diff --git a/config/locales/account/es.yml b/config/locales/account/es.yml index 10cf90cb4c9..df67f19cef6 100644 --- a/config/locales/account/es.yml +++ b/config/locales/account/es.yml @@ -54,7 +54,7 @@ es: totp_confirm_delete: Sí, eliminar la aplicación de autenticación unknown_location: ubicación desconocida verification: - instructions: Su cuenta requiere un código único para ser verificado. + instructions: Su cuenta requiere un código de verificación para ser verificado. reactivate_button: Ingrese el código que recibió por correo postal. success: Verificamos tu información webauthn: Clave de seguridad diff --git a/config/locales/account/fr.yml b/config/locales/account/fr.yml index cdaef8729dc..9257ac30ea3 100644 --- a/config/locales/account/fr.yml +++ b/config/locales/account/fr.yml @@ -57,7 +57,7 @@ fr: totp_confirm_delete: Oui, supprimez l’application d’authentification unknown_location: lieu inconnu verification: - instructions: Votre compte nécessite un code à usage unique pour être vérifié. + instructions: Votre compte nécessite un code de vérification pour être vérifié. reactivate_button: Entrez le code que vous avez reçu par la poste success: Nous avons vérifié vos informations webauthn: Clé de sécurité diff --git a/config/locales/errors/en.yml b/config/locales/errors/en.yml index 7a65c4f71fe..85bcb27e688 100644 --- a/config/locales/errors/en.yml +++ b/config/locales/errors/en.yml @@ -49,8 +49,8 @@ en: confirmation instructions” to get another one. expired: has expired, please request a new one format_mismatch: Please match the requested format. - gpo_otp_expired: Your one-time code has expired. Please request another letter - for a new code. + gpo_otp_expired: Your verification code has expired. Please request another + letter for a new code. improbable_phone: Invalid phone number. Please make sure you enter a valid phone number. inclusion: is not included in the list invalid_calling_area: Calls to that phone number are not supported. Please try diff --git a/config/locales/errors/es.yml b/config/locales/errors/es.yml index 869bea48867..474c0d9f4a8 100644 --- a/config/locales/errors/es.yml +++ b/config/locales/errors/es.yml @@ -52,8 +52,8 @@ es: en “Reenviar instrucciones de confirmación” para obtener otro. expired: ha caducado, por favor solicite uno nuevo format_mismatch: Por favor, use el formato solicitado. - gpo_otp_expired: Tu código único ha caducado. Vuelve a solicitar otra carta para - recibir un nuevo código. + gpo_otp_expired: Tu código de verificación ha caducado. Vuelve a solicitar otra + carta para recibir un nuevo código. improbable_phone: Número de teléfono no válido. Asegúrate de introducir un número de teléfono válido. inclusion: No se incluye en la lista. diff --git a/config/locales/errors/fr.yml b/config/locales/errors/fr.yml index 7d8e5540fc9..d6e9a35538e 100644 --- a/config/locales/errors/fr.yml +++ b/config/locales/errors/fr.yml @@ -58,7 +58,7 @@ fr: obtenir un autre. expired: est expiré, veuillez en demander un nouveau format_mismatch: Veuillez vous assurer de respecter le format requis. - gpo_otp_expired: Votre code à usage unique a expiré. Veuillez solliciter une + gpo_otp_expired: Votre code de vérification a expiré. Veuillez solliciter une autre lettre afin d’obtenir un nouveau code. improbable_phone: Numéro de téléphone non valide. Veillez à saisir un numéro de téléphone valide. diff --git a/config/locales/idv/en.yml b/config/locales/idv/en.yml index f8dc1e77926..0619c1c515d 100644 --- a/config/locales/idv/en.yml +++ b/config/locales/idv/en.yml @@ -33,7 +33,7 @@ en: gpo: start_over: 'If you clear your information and start over:' warnings: - - The one-time code in your letter will no longer work + - The verification code in your letter will no longer work - You will start over verifying your identity from the beginning hybrid: If you cancel now, you will be prompted to switch back to your computer to continue verifying your identity. @@ -155,7 +155,6 @@ en: form: address1: Address line 1 address2: Address line 2 - address2_optional: Address line 2 (optional) city: City dob: Date of birth first_name: First name @@ -172,7 +171,9 @@ en: no_js_intro: '%{sp_name} needs you to verify your identity. You need to enable JavaScript to continue this process.' gpo: - alert_info: 'We sent a letter with your one-time code to:' + alert_info: 'We sent a letter with your verification code to:' + change_to_verification_code_html: 'The one-time code from your + letter is now referred to as verification code.' clear_and_start_over: Clear your information and start over did_not_receive_letter: form: @@ -187,10 +188,10 @@ en: title: Didn’t get your letter? form: instructions: Enter the 10-character code from the letter you received. - otp_label: One-time code + otp_label: Verification code submit: Confirm account title: Confirm your account - intro_html: '
If you have received your letter, please enter your one-time + intro_html: '
If you have received your letter, please enter your verification code below.
If your letter hasn’t arrived yet, please be patient as letters take up to 10 days to arrive. Thank you for your patience.
' @@ -218,15 +219,15 @@ en: clear_and_start_over: Clear my information and start over come_back_later_html:Letters take 5 to 10 days to arrive via USPS First-Class Mail.
Once your letter arrives, sign in to - %{app_name}, and enter your one-time code when prompted.
+ %{app_name}, and enter your verification code when prompted. come_back_later_no_sp_html: You can return to your %{app_name} account for now. come_back_later_password_html: Don’t forget your password.Si ha recibido su carta, introduzca su código único a + intro_html: '
Si ha recibido su carta, introduzca su código de verificación a continuación.
Si su carta aún no ha llegado, tenga paciencia, ya que las cartas tardan hasta 10 días en llegar. Gracias por su paciencia.
' @@ -227,17 +228,18 @@ es: clear_and_start_over: Borrar mi información y empezar de nuevo come_back_later_html:Las cartas tardan entre 5 y 10 días en llegar por USPS First-Class Mail.
Una vez que reciba la carta, - inicie sesión en %{app_name} e introduzca el código único cuando se le - solicite.
+ inicie sesión en %{app_name} e introduzca su código de verificación + cuando se le solicite. come_back_later_no_sp_html: Ahora puedes volver a tu cuenta de %{app_name}. come_back_later_password_html: No olvide su contraseña.Si vous avez reçu votre lettre, veuillez entrer votre code à - usage unique ci-dessous.
Si votre lettre n’est pas encore + intro_html: '
Si vous avez reçu votre lettre, veuillez entrer votre code de + vérification ci-dessous.
Si votre lettre n’est pas encore arrivée, veuillez être patient car les lettres mettent jusqu’à 10 jours pour arriver. Nous vous remercions de votre patience.
' @@ -236,19 +238,19 @@ fr: clear_and_start_over: Supprimer mes données et recommencer come_back_later_html:Les lettres mettent 5 à 10 jours pour arriver par le courrier de première classe d’USPS.
Une fois votre - lettre arrivée, connectez-vous à %{app_name} et entrez votre code à - usage unique lorsque vous y êtes invité.
+ lettre arrivée, connectez-vous à %{app_name} et entrez votre code de + vérification lorsque vous y êtes invité. come_back_later_no_sp_html: Vous pouvez revenir à votre compte %{app_name} pour le moment. come_back_later_password_html: N’oubliez pas votre mot de passe.You requested a letter with a verification code on + %{date_letter_was_sent}.
Sign back in to + %{app_name} and enter the verification code to finish verifying your + identity. %{help_link}.
+ did_not_get_a_letter_html: If you didn’t get this letter, %{another_letter_link_html}. + finish: Finish verifying your identity + sign_in_and_request_another_letter: sign in to request another letter + subject: Finish verifying your identity new_device_sign_in: disavowal_link: reset your password help_html: If you did not make this change, %{disavowal_link_html}. For more @@ -269,8 +276,8 @@ en: subject: Unusual activity — reset your %{app_name} password reset_password_instructions: footer: This link expires in %{expires} hours. - gpo_letter_description: If you reset your password, the one-time code in your - letter will no longer work and you’ll have to verify your identity + gpo_letter_description: If you reset your password, the verification code in + your letter will no longer work and you’ll have to verify your identity again. gpo_letter_header: Your letter is on the way header: To finish resetting your password, please click the link below or copy diff --git a/config/locales/user_mailer/es.yml b/config/locales/user_mailer/es.yml index 6c5fd8a80ad..f25a7ca2698 100644 --- a/config/locales/user_mailer/es.yml +++ b/config/locales/user_mailer/es.yml @@ -137,10 +137,6 @@ es: verifying_step_not_expired: Su documento de identidad o permiso de conducir emitido por el estado debe estar vigente. Por el momento, no aceptamos otras formas de identificación, como pasaportes o cartillas militares. - verifying_step_proof_of_address: Si vuelve a intentar verificar su identidad en - persona, deberá llevar un comprobante de domicilio vigente si su - dirección actual es distinta de la que aparece en su documento de - identidad. in_person_failed_suspected_fraud: body: help_center_html: Si necesita ayuda adicional, puede . Para informar de esto, póngase en contacto con el soporte de %{app_name}. letter_reminder: - info_html: La carta que está a punto de recibir contendrá un código único que - nos ayudará a verificar su dirección. Puede completar el proceso de - verificación de identidad iniciando sesión en %{link_html} e ingresando - el código único. + info_html: La carta que está a punto de recibir contendrá un código de + verificación que nos ayudará a verificar su dirección. Puede completar + el proceso de verificación de identidad iniciando sesión en %{link_html} + e ingresando el código de verificación. subject: Le enviamos una carta a la dirección que tiene archivada + letter_reminder_14_days: + body_html:Solicitó una carta con un código de verificación el + %{date_letter_was_sent}.
Inicie sesión de nuevo + en %{app_name} e ingrese el código de verificación para terminar de + verificar su identidad. %{help_link}.
+ did_not_get_a_letter_html: Si no recibiste dicha carta, %{another_letter_link_html}. + finish: Termina de verificar tu identidad + sign_in_and_request_another_letter: inicia sesión para solicitar otra + subject: Termina de verificar tu identidad new_device_sign_in: disavowal_link: restablecer su contraseña help_html: Si no realizó este cambio, %{disavowal_link_html}. Para más ayuda, @@ -288,9 +293,9 @@ es: subject: Actividad inusual — restablezca su contraseña de %{app_name} reset_password_instructions: footer: Este enlace expira en %{expires} horas. - gpo_letter_description: Si restablece su contraseña, el código único que figura - en su carta dejará de funcionar y tendrá que volver a verificar su - identidad. + gpo_letter_description: Si restablece su contraseña, el código de verificación + que figura en su carta dejará de funcionar y tendrá que volver a + verificar su identidad. gpo_letter_header: Su carta está en camino header: Para terminar de restablecer su contraseña, haga clic en el enlace de abajo o copie y pegue el enlace completo en su navegador. diff --git a/config/locales/user_mailer/fr.yml b/config/locales/user_mailer/fr.yml index 0841255d471..3bd4b728c2a 100644 --- a/config/locales/user_mailer/fr.yml +++ b/config/locales/user_mailer/fr.yml @@ -142,10 +142,6 @@ fr: délivré par l’État ne doit pas être périmé. Nous n’acceptons actuellement aucune autre forme d’identification, comme les passeports et les cartes d’identité militaires. - verifying_step_proof_of_address: Si vous tentez à nouveau de vérifier votre - identité en personne, vous devez apporter un justificatif de domicile - valable si votre adresse actuelle est différente de celle figurant sur - votre pièce d’identité. in_person_failed_suspected_fraud: body: help_center_html: Si vous avez besoin d’aide supplémentaire, vous pouvez contactez l’assistance de %{app_name}. letter_reminder: - info_html: La lettre que vous êtes sur le point de recevoir contiendra un code à - usage unique nous permettant de vérifier votre adresse. Vous pouvez + info_html: La lettre que vous êtes sur le point de recevoir contiendra un code + de vérification nous permettant de vérifier votre adresse. Vous pouvez terminer le processus de vérification d’identité en vous connectant à - %{link_html} et en entrant le code à usage unique. + %{link_html} et en entrant le code de vérification. subject: Nous avons envoyé une lettre à l’adresse que vous avez en dossier + letter_reminder_14_days: + body_html:Vous avez demandé une lettre avec un code de vérification le + %{date_letter_was_sent}.
Reconnectez-vous à + %{app_name} et saisissez le code de vérification pour terminer la + vérification de votre identité. %{help_link}.
+ did_not_get_a_letter_html: Si vous n’avez pas reçu cette lettre, %{another_letter_link_html}. + finish: Terminer la vérification de votre identité + sign_in_and_request_another_letter: connectez-vous pour en demander une autre + subject: Terminer la vérification de votre identité new_device_sign_in: disavowal_link: réinitialiser votre mot de passe help_html: Si vous n’avez pas effectué ce changement, %{disavowal_link_html}. @@ -298,8 +303,8 @@ fr: subject: Activité inhabituelle — réinitialisez votre mot de passe %{app_name} reset_password_instructions: footer: Ce lien expire dans %{expires} heures. - gpo_letter_description: Si vous réinitialisez votre mot de passe, le code à - usage unique contenu dans votre lettre ne correspondra plus et vous + gpo_letter_description: Si vous réinitialisez votre mot de passe, le code de + vérification contenu dans votre lettre ne correspondra plus et vous devrez de vérifier à nouveau votre identité. gpo_letter_header: Votre lettre est en route header: Pour terminer la réinitialisation de votre mot de passe, veuillez diff --git a/docs/backend.md b/docs/backend.md index 65997aa7ff3..c456dc18e8d 100644 --- a/docs/backend.md +++ b/docs/backend.md @@ -80,10 +80,15 @@ properties to the Form object that get written during `#submit` At the end of the day, analytics events get dumped into `events.log` and contain information like user ID, service provider, user agent, etc. -Event names are strings. Events correspond to methods in the +Event names correspond to methods in the [AnalyticsEvents](../app/services/analytics_events.rb) mixin. We document these with YARD so that we can auto-generate -[documentation on them in our handbook][analytics-handbook] +[documentation on them in our handbook][analytics-handbook]. + +> [!NOTE] +> The convention to name events to match the method name is expected for all new analytics events, +> but you will find a number of exceptions for analytics which had existed prior to this convention +> being established. [analytics-handbook]: https://handbook.login.gov/articles/analytics-events.html diff --git a/docs/frontend.md b/docs/frontend.md index bde03ebc4f3..65531a3a3b7 100644 --- a/docs/frontend.md +++ b/docs/frontend.md @@ -320,19 +320,37 @@ is a wrapper component for Simple Form's `f.input` helper. It enhances the behav ### Production Errors -JavaScript errors that occur in production environments are automatically logged to NewRelic. -Because JavaScript is transpiled and minified in production, these files can be difficult to debug. -Fortunately, [NewRelic supports source maps](https://docs.newrelic.com/docs/browser/browser-monitoring/browser-pro-features/upload-source-maps-un-minify-js-errors/) -to produce a readable stack trace of the original code. +JavaScript errors that occur in production environments are automatically logged to NewRelic. They are logged as an expected Ruby error with the class `FrontendLoggerError::FrontendError`. -When viewing an instance of a JavaScript error, NewRelic will prompt for a sourcemap corresponding -to a specific JavaScript file URL. +There are two ways you can view these errors: - +- [In the production APM "Errors" inbox, removing the filter which hides "expected" errors](https://onenr.io/0OQMVbbB9wG) +- [In the query builder, selecting from `TransactionError` with an error class of `FrontendErrorLogger::FrontendLogger`](https://onenr.io/0kjnpGG4awo) -To retrieve the sourcemap for this URL, simply copy the URL into your browser URL bar and append -`.map`. Navigating to this URL should download the `.map` file to your computer, which you can then -drag-and-drop onto the NewRelic web interface to reveal the decompiled stack trace. +Each error includes a few details to help you debug: + +- `message`: Corresponds to [`Error#message`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/message), and is usually a good summary to group by +- `name`: The subclass of the error (e.g. `TypeError`) +- `stack`: A stacktrace of the individual error instance + +Note that NewRelic creates links in stack traces which are invalid, since they include the line and column number. If you encounter an "AccessDenied" error when clicking a stacktrace link, make sure to remove those details after the `.js` in your browser URL. + +Debugging these stack traces can be difficult, since files in production are minified, and the stack traces include line numbers and columns for minified files. With the following steps, you can find a reference to the original code: + +1. Download the minified JavaScript file referenced in the stack trace + - Example: https://secure.login.gov/packs/js/document-capture-e41c853e.digested.js +2. Download the sourcemap file for the JavaScript by appending `.map` to the previous URL + - Example: https://secure.login.gov/packs/js/document-capture-e41c853e.digested.js.map +3. Install the [`sourcemap-lookup` npm package](https://www.npmjs.com/package/sourcemap-lookup) + - `npm i -g sourcemap-lookup` +4. Open a terminal window to the directory where you downloaded the files in steps 1 and 2 + - Example: `cd ~/Downloads` +5. Clean the sourcemap file to remove Webpack protocol details + - Example: `sed -i '' 's/webpack:\/\/@18f\/identity-idp\///g' document-capture-e41c853e.digested.js.map` +6. Run the `sourcemap-lookup` command with a reference to the JavaScript file, line and column number, and specifying the source path to your local copy of `identity-idp` + - Example: `sourcemap-lookup document-capture-e41c853e.digested.js:2:172098 --source-path=/path/to/identity-idp/` + +The output of the `sourcemap-lookup` command should include "Original Position" and "Code Section" of the code which triggered the error. ## Devices diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 5b47c4c8ac9..c7bdbbb4ec5 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -236,7 +236,6 @@ def self.build_store(config_map) config.add(:idv_send_link_attempt_window_in_minutes, type: :integer) config.add(:idv_send_link_max_attempts, type: :integer) config.add(:idv_sp_required, type: :boolean) - config.add(:in_person_capture_secondary_id_enabled, type: :boolean) config.add(:in_person_completion_survey_url, type: :string) config.add(:in_person_doc_auth_button_enabled, type: :boolean) config.add(:in_person_email_reminder_early_benchmark_in_days, type: :integer) diff --git a/lib/idp/constants.rb b/lib/idp/constants.rb index 478f183b338..ea123d5b9e6 100644 --- a/lib/idp/constants.rb +++ b/lib/idp/constants.rb @@ -113,6 +113,7 @@ module Vendors same_address_as_id: 'false', ).freeze + # Use this as the default applicant for in person proofing MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID = MOCK_IDV_APPLICANT_WITH_SSN.merge( identity_doc_address1: MOCK_IDV_APPLICANT_WITH_SSN[:address1], identity_doc_address2: MOCK_IDV_APPLICANT_WITH_SSN[:address2], @@ -133,6 +134,9 @@ module Vendors MOCK_IDV_APPLICANT_WITH_PHONE = MOCK_IDV_APPLICANT_WITH_SSN.merge(phone: '12025551212').freeze + MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID_WITH_PHONE = + MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID.merge(phone: '12025551212').freeze + MOCK_IDV_APPLICANT_FULL_STATE_ID_JURISDICTION = 'North Dakota' MOCK_IDV_APPLICANT_FULL_STATE = 'Montana' MOCK_IDV_APPLICANT_FULL_IDENTITY_DOC_ADDRESS_STATE = 'Virginia' diff --git a/lib/linters/analytics_event_name_linter.rb b/lib/linters/analytics_event_name_linter.rb new file mode 100644 index 00000000000..f6a9db0f4de --- /dev/null +++ b/lib/linters/analytics_event_name_linter.rb @@ -0,0 +1,27 @@ +module RuboCop + module Cop + module IdentityIdp + class AnalyticsEventNameLinter < RuboCop::Cop::Cop + RESTRICT_ON_SEND = [:track_event] + + def on_send(node) + first_argument, = node.arguments + expected_name = ancestor_method_name(node) + if first_argument.type != :sym || first_argument.value != expected_name + add_offense( + first_argument, + location: :expression, + message: "Event name must match the method name, expected `:#{expected_name}`", + ) + end + end + + private + + def ancestor_method_name(node) + node.each_ancestor(:def).first.method_name + end + end + end + end +end diff --git a/package.json b/package.json index 41ddb6f1302..4546dd9abc0 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@testing-library/react": "^11.2.2", "@testing-library/react-hooks": "^3.7.0", "@testing-library/user-event": "^14.4.3", - "@types/chai": "^4.3.3", + "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", "@types/cleave.js": "^1.4.7", "@types/dirty-chai": "^2.0.2", @@ -63,7 +63,7 @@ "@types/sinon-chai": "^3.2.8", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^6.7.4", - "chai": "^4.3.6", + "chai": "^4.3.10", "chai-as-promised": "^7.1.1", "clipboard-polyfill": "^3.0.3", "dirty-chai": "^2.0.1", @@ -78,8 +78,7 @@ "jsdom": "^22.1.0", "mocha": "^10.0.0", "mq-polyfill": "^1.1.8", - "msw": "^1.2.1", - "postcss": "^8.4.22", + "msw": "^1.3.2", "prettier": "^3.0.3", "quibble": "^0.6.17", "react-test-renderer": "^17.0.2", @@ -92,6 +91,7 @@ "webpack-dev-server": "^4.11.1" }, "resolutions": { - "minimist": "1.2.6" + "minimist": "1.2.6", + "postcss": "8.4.31" } } diff --git a/spec/controllers/concerns/idv_step_concern_spec.rb b/spec/controllers/concerns/idv_step_concern_spec.rb index 1c126c279ac..f9c8d2351de 100644 --- a/spec/controllers/concerns/idv_step_concern_spec.rb +++ b/spec/controllers/concerns/idv_step_concern_spec.rb @@ -17,13 +17,6 @@ def show end describe 'before_actions' do - it 'includes confirm_not_rate_limited before_action' do - expect(Idv::StepController).to have_actions( - :before, - :confirm_not_rate_limited, - ) - end - it 'includes handle_fraud' do expect(Idv::StepController).to have_actions( :before, diff --git a/spec/controllers/concerns/rate_limit_concern_spec.rb b/spec/controllers/concerns/rate_limit_concern_spec.rb index f48ecaa4659..6edf7982bdf 100644 --- a/spec/controllers/concerns/rate_limit_concern_spec.rb +++ b/spec/controllers/concerns/rate_limit_concern_spec.rb @@ -98,4 +98,69 @@ def update end end end + + describe '#confirm_not_rate_limited_after_doc_auth' do + controller Idv::StepController do + before_action :confirm_not_rate_limited_after_doc_auth + end + + before(:each) do + sign_in(user) + allow(subject).to receive(:current_user).and_return(user) + routes.draw do + get 'show' => 'idv/step#show' + put 'update' => 'idv/step#update' + end + end + + it 'redirects if the user is rate limited for a step after doc auth' do + RateLimiter.new(user: user, rate_limit_type: :idv_resolution).increment_to_limited! + + get :show + + expect(response).to redirect_to(idv_session_errors_failure_url) + end + + it 'does not redirect if the user is rate limited for doc auth' do + RateLimiter.new(user: user, rate_limit_type: :idv_doc_auth).increment_to_limited! + + get :show + + expect(response.body).to eq 'Hello' + expect(response.status).to eq 200 + end + end + + describe '#confirm_not_rate_limited_after_idv_resolution' do + controller Idv::StepController do + before_action :confirm_not_rate_limited_after_idv_resolution + end + + before(:each) do + sign_in(user) + allow(subject).to receive(:current_user).and_return(user) + routes.draw do + get 'show' => 'idv/step#show' + put 'update' => 'idv/step#update' + end + end + + it 'redirects if the user is rate limited for a step after idv resolution' do + RateLimiter.new(user: user, rate_limit_type: :proof_address).increment_to_limited! + + get :show + + expect(response).to redirect_to(idv_phone_errors_failure_url) + end + + it 'does not redirect if the user is rate limited for idv resolution' do + RateLimiter.new(user: user, rate_limit_type: :idv_doc_auth).increment_to_limited! + RateLimiter.new(user: user, rate_limit_type: :idv_resolution).increment_to_limited! + + get :show + + expect(response.body).to eq 'Hello' + expect(response.status).to eq 200 + end + end end diff --git a/spec/controllers/idv/agreement_controller_spec.rb b/spec/controllers/idv/agreement_controller_spec.rb index 68a276b9296..38068894fae 100644 --- a/spec/controllers/idv/agreement_controller_spec.rb +++ b/spec/controllers/idv/agreement_controller_spec.rb @@ -145,20 +145,5 @@ expect(response).to redirect_to(idv_hybrid_handoff_url) end end - - context 'ial2_consent_given param present' do - let(:params) do - { - doc_auth: { - ial2_consent_given: 1, - }, - skip_hybrid_handoff: skip_hybrid_handoff, - }.compact - end - it 'succeeds' do - put :update, params: params - expect(response).to redirect_to(idv_hybrid_handoff_url) - end - end end end diff --git a/spec/controllers/idv/capture_doc_status_controller_spec.rb b/spec/controllers/idv/capture_doc_status_controller_spec.rb index eca9b333668..f263b3f0680 100644 --- a/spec/controllers/idv/capture_doc_status_controller_spec.rb +++ b/spec/controllers/idv/capture_doc_status_controller_spec.rb @@ -3,6 +3,33 @@ RSpec.describe Idv::CaptureDocStatusController do let(:user) { build(:user) } + let(:doc_auth_response) do + DocAuth::Response.new( + success: true, + pii_from_doc: { + first_name: 'Testy', + last_name: 'Testerson', + }, + ) + end + + let(:failed_doc_auth_response) do + DocAuth::Response.new( + success: false, + ) + end + + let(:barcode_attention_auth_response) do + DocAuth::Response.new( + success: true, + pii_from_doc: { + first_name: 'Testy', + last_name: 'Testerson', + }, + attention_with_barcode: true, + ) + end + before do stub_sign_in(user) if user end @@ -69,33 +96,9 @@ end end - context 'when capture failed' do - before do - allow(EncryptedRedisStructStorage).to receive(:load).and_return( - DocumentCaptureSessionResult.new( - id: SecureRandom.uuid, - success: false, - pii: {}, - ), - ) - end - - it 'returns unauthorized' do - get :show - - expect(response.status).to eq(401) - end - end - context 'when capture succeeded' do before do - allow(EncryptedRedisStructStorage).to receive(:load).and_return( - DocumentCaptureSessionResult.new( - id: SecureRandom.uuid, - success: true, - pii: {}, - ), - ) + document_capture_session.store_result_from_response(doc_auth_response) end it 'returns success' do @@ -106,17 +109,8 @@ end context 'when capture succeeded with barcode attention' do - let(:result) do - DocumentCaptureSessionResult.new( - id: SecureRandom.uuid, - success: true, - pii: {}, - attention_with_barcode: true, - ) - end - before do - allow(EncryptedRedisStructStorage).to receive(:load).and_return(result) + document_capture_session.store_result_from_response(barcode_attention_auth_response) end context 'when barcode attention result is pending confirmation' do @@ -156,18 +150,11 @@ end context 'when user receives a second result that is not the attention result' do - let(:result) do - DocumentCaptureSessionResult.new( - id: SecureRandom.uuid, - success: true, - pii: {}, - attention_with_barcode: false, - ) - end - before do idv_session[:had_barcode_attention_error] = true document_capture_session.update(ocr_confirmation_pending: false) + + document_capture_session.store_result_from_response(doc_auth_response) end it 'assigns idv session values as not having received attention result' do diff --git a/spec/controllers/idv/getting_started_controller_spec.rb b/spec/controllers/idv/getting_started_controller_spec.rb index f23a7d0b274..d66c21ea9f1 100644 --- a/spec/controllers/idv/getting_started_controller_spec.rb +++ b/spec/controllers/idv/getting_started_controller_spec.rb @@ -155,21 +155,6 @@ expect(response).to redirect_to(idv_hybrid_handoff_url) end - context 'ial2_consent_given param present' do - let(:params) do - { - doc_auth: { - ial2_consent_given: 1, - }, - skip_hybrid_handoff: skip_hybrid_handoff, - }.compact - end - it 'succeeds' do - put :update, params: params - expect(response).to redirect_to(idv_hybrid_handoff_url) - end - end - context 'skip_hybrid_handoff present in params' do let(:skip_hybrid_handoff) { '' } it 'sets flow_path to standard' do diff --git a/spec/controllers/idv/in_person/verify_info_controller_spec.rb b/spec/controllers/idv/in_person/verify_info_controller_spec.rb index f5fc53dd0a1..66200e5d465 100644 --- a/spec/controllers/idv/in_person/verify_info_controller_spec.rb +++ b/spec/controllers/idv/in_person/verify_info_controller_spec.rb @@ -128,47 +128,30 @@ expect(response).to redirect_to idv_in_person_verify_info_url end - context 'double address verification is not enabled' do - let(:capture_secondary_id_enabled) { false } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } - before do - allow(user).to receive(:establishing_in_person_enrollment).and_return(enrollment) - end + let(:pii_from_user) { Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS.dup } + let(:enrollment) { InPersonEnrollment.new } + before do + allow(user).to receive(:establishing_in_person_enrollment).and_return(enrollment) + end - it 'sets uuid_prefix and state_id_type on pii_from_user' do - expect(Idv::Agent).to receive(:new). - with(hash_including(uuid_prefix: service_provider.app_id)).and_call_original - # our test data already has the expected value by default - flow_session[:pii_from_user].delete(:state_id_type) + it 'sets uuid_prefix and state_id_type on pii_from_user' do + expect(Idv::Agent).to receive(:new). + with(hash_including(uuid_prefix: service_provider.app_id)).and_call_original + # our test data already has the expected value by default + flow_session[:pii_from_user].delete(:state_id_type) - put :update + put :update - expect(flow_session[:pii_from_user][:state_id_type]).to eq 'drivers_license' - expect(flow_session[:pii_from_user][:uuid_prefix]).to eq service_provider.app_id - end + expect(flow_session[:pii_from_user][:state_id_type]).to eq 'drivers_license' + expect(flow_session[:pii_from_user][:uuid_prefix]).to eq service_provider.app_id + end - context 'a user does not have an establishing in person enrollment associated with them' do - before do - allow(user).to receive(:establishing_in_person_enrollment).and_return(nil) - end - - it 'disables double address verification for the user' do - expect_any_instance_of(Idv::Agent).to receive(:proof_resolution). - with( - kind_of(DocumentCaptureSession), - should_proof_state_id: anything, - trace_id: subject.send(:amzn_trace_id), - threatmetrix_session_id: nil, - user_id: anything, - request_ip: request.remote_ip, - double_address_verification: false, - ) - - put :update - end + context 'a user does not have an establishing in person enrollment associated with them' do + before do + allow(user).to receive(:establishing_in_person_enrollment).and_return(nil) end - it 'passes the X-Amzn-Trace-Id to the proofer' do + it 'disables double address verification for the user' do expect_any_instance_of(Idv::Agent).to receive(:proof_resolution). with( kind_of(DocumentCaptureSession), @@ -182,76 +165,85 @@ put :update end + end - it 'only enqueues a job once' do - put :update - expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) + context 'a user does have an establishing in person enrollment associated with them' do + it 'indicates to the IDV agent that double_address_verification is enabled' do + expect_any_instance_of(Idv::Agent).to receive(:proof_resolution).with( + kind_of(DocumentCaptureSession), + should_proof_state_id: anything, + trace_id: anything, + threatmetrix_session_id: anything, + user_id: anything, + request_ip: anything, + double_address_verification: true, + ) put :update end - context 'when pii_from_user is blank' do - it 'redirects' do - flow_session[:pii_from_user] = {} - put :update - expect(response.status).to eq 302 - end - end - - context 'when different users use the same SSN within the same timeframe' do - let(:user2) { create(:user) } - - before do - allow(IdentityConfig.store).to receive(:proof_ssn_max_attempts).and_return(3) - allow(IdentityConfig.store).to receive(:proof_ssn_max_attempt_window_in_minutes). - and_return(10) - end - - it 'rate limits them all' do - put :update - subject.idv_session.verify_info_step_document_capture_session_uuid = nil - put :update - subject.idv_session.verify_info_step_document_capture_session_uuid = nil - put :update - put :update - expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) - expect(response).to redirect_to(idv_session_errors_ssn_failure_url) - subject.idv_session.verify_info_step_document_capture_session_uuid = nil - - stub_sign_in(user2) - put :update - expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) - expect(response).to redirect_to(idv_session_errors_ssn_failure_url) - end - end - end - - context 'double address verification is enabled' do - let(:pii_from_user) { Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS.dup } - let(:capture_secondary_id_enabled) { true } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } - before do - allow(user).to receive(:establishing_in_person_enrollment).and_return(enrollment) - end it 'captures state id address fields in the pii' do expect(Idv::Agent).to receive(:new). with(Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS.merge(uuid_prefix: nil)). and_call_original put :update end + end - it 'indicates to the IDV agent that double_address_verification is enabled' do - expect_any_instance_of(Idv::Agent).to receive(:proof_resolution).with( + it 'passes the X-Amzn-Trace-Id to the proofer' do + expect_any_instance_of(Idv::Agent).to receive(:proof_resolution). + with( kind_of(DocumentCaptureSession), should_proof_state_id: anything, - trace_id: anything, - threatmetrix_session_id: anything, + trace_id: subject.send(:amzn_trace_id), + threatmetrix_session_id: nil, user_id: anything, - request_ip: anything, + request_ip: request.remote_ip, double_address_verification: true, ) + put :update + end + + it 'only enqueues a job once' do + put :update + expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) + + put :update + end + + context 'when pii_from_user is blank' do + it 'redirects' do + flow_session[:pii_from_user] = {} put :update + expect(response.status).to eq 302 + end + end + + context 'when different users use the same SSN within the same timeframe' do + let(:user2) { create(:user) } + + before do + allow(IdentityConfig.store).to receive(:proof_ssn_max_attempts).and_return(3) + allow(IdentityConfig.store).to receive(:proof_ssn_max_attempt_window_in_minutes). + and_return(10) + end + + it 'rate limits them all' do + put :update + subject.idv_session.verify_info_step_document_capture_session_uuid = nil + put :update + subject.idv_session.verify_info_step_document_capture_session_uuid = nil + put :update + put :update + expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) + expect(response).to redirect_to(idv_session_errors_ssn_failure_url) + subject.idv_session.verify_info_step_document_capture_session_uuid = nil + + stub_sign_in(user2) + put :update + expect_any_instance_of(Idv::Agent).to_not receive(:proof_resolution) + expect(response).to redirect_to(idv_session_errors_ssn_failure_url) end end end diff --git a/spec/controllers/idv/review_controller_spec.rb b/spec/controllers/idv/review_controller_spec.rb index f1fa8747afa..b63de98cbdd 100644 --- a/spec/controllers/idv/review_controller_spec.rb +++ b/spec/controllers/idv/review_controller_spec.rb @@ -391,7 +391,7 @@ def show stub_request_enroll end let(:applicant) do - Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE + Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID_WITH_PHONE end before do @@ -587,12 +587,13 @@ def show end context 'when user enters an address2 value' do - let(:applicant) { Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE.merge(address2: '3b') } + let(:applicant) do + Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID_WITH_PHONE.merge(address2: '3b') + end it 'does not include address2' do proofer = UspsInPersonProofing::Proofer.new mock = double - expect(UspsInPersonProofing::Proofer).to receive(:new).and_return(mock) expect(mock).to receive(:request_enroll) do |applicant| expect(applicant.address). diff --git a/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb index 20052aa7760..402677ee9bc 100644 --- a/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb +++ b/spec/controllers/two_factor_authentication/webauthn_verification_controller_spec.rb @@ -246,12 +246,6 @@ create(:webauthn_configuration, :platform_authenticator, user:, created_at: 1.day.ago) end - before do - allow_any_instance_of(TwoFactorAuthCode::WebauthnAuthenticationPresenter). - to receive(:multiple_factors_enabled?). - and_return(true) - end - it 'redirects to webauthn show page' do patch :confirm, params: params expect(response).to redirect_to login_two_factor_webauthn_url(platform: true) diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index 77634db5a82..aa608d6931f 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -283,29 +283,29 @@ step: 'state_id', flow_path: 'standard', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false }, 'IdV: in person proofing state_id submitted' => { - success: true, flow_path: 'standard', step: 'state_id', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false, errors: {}, same_address_as_id: nil + success: true, flow_path: 'standard', step: 'state_id', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false, errors: {}, same_address_as_id: false }, 'IdV: in person proofing address visited' => { - step: 'address', flow_path: 'standard', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false + step: 'address', flow_path: 'standard', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false, same_address_as_id: false }, - 'IdV: in person proofing address submitted' => { - success: true, step: 'address', flow_path: 'standard', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false, errors: {}, same_address_as_id: true + 'IdV: in person proofing residential address submitted' => { + success: true, step: 'address', flow_path: 'standard', step_count: 1, analytics_id: 'In Person Proofing', irs_reproofing: false, errors: {}, same_address_as_id: false }, 'IdV: doc auth ssn visited' => { - analytics_id: 'In Person Proofing', step: 'ssn', flow_path: 'standard', irs_reproofing: false, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, same_address_as_id: true + analytics_id: 'In Person Proofing', step: 'ssn', flow_path: 'standard', irs_reproofing: false, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, same_address_as_id: false }, 'IdV: doc auth ssn submitted' => { - analytics_id: 'In Person Proofing', success: true, step: 'ssn', flow_path: 'standard', irs_reproofing: false, errors: {}, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, same_address_as_id: true + analytics_id: 'In Person Proofing', success: true, step: 'ssn', flow_path: 'standard', irs_reproofing: false, errors: {}, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, same_address_as_id: false }, 'IdV: doc auth verify visited' => { - analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', irs_reproofing: false, same_address_as_id: true, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil + analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', irs_reproofing: false, same_address_as_id: false, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil }, 'IdV: doc auth verify submitted' => { - analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', irs_reproofing: false, same_address_as_id: true, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil + analytics_id: 'In Person Proofing', step: 'verify', flow_path: 'standard', irs_reproofing: false, same_address_as_id: false, getting_started_ab_test_bucket: :welcome_default, acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'In Person Proofing', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, irs_reproofing: false, skip_hybrid_handoff: nil, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', double_address_verification: false, resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { errors: {}, exception: nil, reference: '', success: true, timed_out: false, transaction_id: '', vendor_name: 'ResidentialAddressNotRequired' }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', double_address_verification: true, resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { errors: {}, exception: nil, reference: 'aaa-bbb-ccc', success: true, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } }, 'IdV: phone confirmation form' => { success: true, errors: {}, phone_type: :mobile, types: [:fixed_or_mobile], carrier: 'Test Mobile Carrier', country_code: 'US', area_code: '202', acuant_sdk_upgrade_ab_test_bucket: :default, getting_started_ab_test_bucket: :welcome_default, skip_hybrid_handoff: nil, otp_delivery_preference: 'sms', @@ -482,8 +482,6 @@ before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) allow(Idv::InPersonConfig).to receive(:enabled_for_issuer?).and_return(true) allow_any_instance_of(Idv::InPerson::ReadyToVerifyPresenter). to receive(:service_provider_homepage_url).and_return(return_sp_url) @@ -493,7 +491,7 @@ start_idv_from_sp(:saml) sign_in_and_2fa_user(user) begin_in_person_proofing(user) - complete_all_in_person_proofing_steps(user) + complete_all_in_person_proofing_steps(user, same_address_as_id: false) complete_phone_step(user) complete_review_step(user) acknowledge_and_confirm_personal_key diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 14fe80b0713..d73385ebc91 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -8,8 +8,6 @@ before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) end context 'ThreatMetrix review pending' do @@ -32,9 +30,6 @@ # state ID page complete_state_id_step(user) - # address page - complete_address_step(user) - # ssn page select 'Reject', from: :mock_profiling_result complete_ssn_step(user) @@ -47,10 +42,14 @@ expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) - expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) - expect(page).to have_text(InPersonHelper::GOOD_CITY) - expect(page).to have_text(InPersonHelper::GOOD_ZIPCODE) - expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state]) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_CITY).twice + expect(page).to have_text( + Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction], + count: 3, + ) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ZIPCODE).twice expect(page).to have_text(DocAuthHelper::GOOD_SSN_MASKED) complete_verify_step(user) @@ -138,12 +137,6 @@ ) complete_state_id_step(user) - # address page - expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) - expect(page).to have_content(t('in_person_proofing.headings.address')) - expect(page).to have_content(t('in_person_proofing.form.address.same_address').tr(' ', ' ')) - complete_address_step(user) - # ssn page expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) expect(page).to have_content(t('doc_auth.headings.ssn')) @@ -157,15 +150,17 @@ expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) - expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) - expect(page).to have_text(InPersonHelper::GOOD_CITY) - expect(page).to have_text(InPersonHelper::GOOD_ZIPCODE) - expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state]) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_CITY).twice + expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction], count: 3) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ZIPCODE).twice expect(page).to have_text(DocAuthHelper::GOOD_SSN_MASKED) # click update state ID button click_button t('idv.buttons.change_state_id_label') expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + choose t('in_person_proofing.form.state_id.same_address_as_id_yes') click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) expect(page).to have_current_path(idv_in_person_verify_info_path) @@ -173,7 +168,6 @@ # click update address button click_button t('idv.buttons.change_address_label') expect(page).to have_content(t('in_person_proofing.headings.update_address')) - choose t('in_person_proofing.form.address.same_address_choice_yes') click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) expect(page).to have_current_path(idv_in_person_verify_info_path) @@ -324,7 +318,8 @@ end end - it 'resumes desktop session with in-person proofing', allow_browser_log: true do + it 'resumes desktop session with in-person proofing when same_address_as_id is true', + allow_browser_log: true do user = nil perform_in_browser(:desktop) do @@ -338,38 +333,27 @@ expect(@sms_link).to be_present - perform_in_browser(:mobile) do - # doc auth page - visit @sms_link - mock_doc_auth_attention_with_barcode - attach_and_submit_images - - # error page - click_button t('in_person_proofing.body.cta.button') - # prepare page - expect(page).to(have_content(t('in_person_proofing.body.prepare.verify_step_about'))) - click_idv_continue - # location page - expect(page).to have_content(t('in_person_proofing.headings.po_search.location')) - complete_location_step - - # switch back page - expect(page).to have_content(t('in_person_proofing.headings.switch_back')) - end + perform_mobile_hybrid_steps + perform_desktop_hybrid_steps(user) + end + + it 'resumes desktop session with in-person proofing when same_address_as_id is false', + allow_browser_log: true do + user = nil perform_in_browser(:desktop) do - expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - - complete_state_id_step(user) - complete_address_step(user) - complete_ssn_step(user) - complete_verify_step(user) - complete_phone_step(user) - complete_review_step(user) - acknowledge_and_confirm_personal_key + user = sign_in_and_2fa_user + complete_doc_auth_steps_before_hybrid_handoff_step + clear_and_fill_in(:doc_auth_phone, '415-555-0199') + click_send_link - expect(page).to have_content('MILWAUKEE') + expect(page).to have_content(t('doc_auth.headings.text_message')) end + + expect(@sms_link).to be_present + + perform_mobile_hybrid_steps + perform_desktop_hybrid_steps(user, same_address_as_id: false) end end @@ -435,333 +419,213 @@ and_return(true) end - context 'with double address verification' do - let(:capture_secondary_id_enabled) { true } - let(:double_address_verification) { true } - let(:user) { user_with_2fa } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } - - before do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(true) - allow(user).to receive(:establishing_in_person_enrollment). - and_return(enrollment) - end - - it 'shows validation errors when double address verification is true', - allow_browser_log: true do - sign_in_and_2fa_user - begin_in_person_proofing - complete_prepare_step - complete_location_step - expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - - fill_out_state_id_form_ok(capture_secondary_id_enabled: capture_secondary_id_enabled) - fill_in t('in_person_proofing.form.state_id.first_name'), with: 'T0mmy "Lee"' - fill_in t('in_person_proofing.form.state_id.last_name'), with: 'Джейкоб' - fill_in t('in_person_proofing.form.state_id.address1'), with: '#1 $treet' - fill_in t('in_person_proofing.form.state_id.address2'), with: 'Gr@nd Lañe^' - fill_in t('in_person_proofing.form.state_id.city'), with: 'B3st C!ty' - click_idv_continue - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: '", 0', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: 'Д, б, е, ж, й, к, о', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: '$', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: '@, ^', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: '!, 3', - ), - ) - - # re-fill state id form with good inputs - fill_in t('in_person_proofing.form.state_id.first_name'), - with: InPersonHelper::GOOD_FIRST_NAME - fill_in t('in_person_proofing.form.state_id.last_name'), - with: InPersonHelper::GOOD_LAST_NAME - fill_in t('in_person_proofing.form.state_id.address1'), - with: InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1 - fill_in t('in_person_proofing.form.state_id.address2'), - with: InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2 - fill_in t('in_person_proofing.form.state_id.city'), - with: InPersonHelper::GOOD_IDENTITY_DOC_CITY - click_idv_continue - - expect(page).to have_current_path(idv_in_person_step_path(step: :address), wait: 10) - end + let(:user) { user_with_2fa } + let(:enrollment) { InPersonEnrollment.new } - it 'shows hints when user selects Puerto Rico as state', - allow_browser_log: true do - sign_in_and_2fa_user - begin_in_person_proofing - complete_prepare_step - complete_location_step - expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - - # state id page - select 'Puerto Rico', - from: t('in_person_proofing.form.state_id.identity_doc_address_state') - - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - - # change state selection - fill_out_state_id_form_ok(capture_secondary_id_enabled: true) - expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - - # re-select puerto rico - select 'Puerto Rico', - from: t('in_person_proofing.form.state_id.identity_doc_address_state') - click_idv_continue - - expect(page).to have_current_path(idv_in_person_step_path(step: :address)) - - # address form - select 'Puerto Rico', - from: t('idv.form.state') - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - - # change selection - fill_out_address_form_ok(double_address_verification: true) - expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - - # re-select puerto rico - select 'Puerto Rico', - from: t('idv.form.state') - click_idv_continue - - # ssn page - expect(page).to have_current_path(idv_in_person_ssn_url) - complete_ssn_step - - # verify page - expect(page).to have_current_path(idv_in_person_verify_info_path) - expect(page).to have_text('PR').twice - - # update state ID - click_button t('idv.buttons.change_state_id_label') - - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - click_button t('forms.buttons.submit.update') - - # update address - click_button t('idv.buttons.change_address_label') - - expect(page).to have_content(t('in_person_proofing.headings.update_address')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) - expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) - end + before do + allow(user).to receive(:establishing_in_person_enrollment). + and_return(enrollment) end - context 'without double address verification' do - it 'shows validation errors when double address verification is false', - allow_browser_log: true do - sign_in_and_2fa_user - begin_in_person_proofing - complete_prepare_step - complete_location_step - expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - - fill_out_state_id_form_ok - fill_in t('in_person_proofing.form.state_id.first_name'), with: 'T0mmy "Lee"' - fill_in t('in_person_proofing.form.state_id.last_name'), with: 'Джейкоб' - click_idv_continue - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: '", 0', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.state_id.errors.unsupported_chars', - char_list: 'Д, б, е, ж, й, к, о', - ), - ) - - # re-fill form with good inputs - fill_in t('in_person_proofing.form.state_id.first_name'), - with: InPersonHelper::GOOD_FIRST_NAME - fill_in t('in_person_proofing.form.state_id.last_name'), - with: InPersonHelper::GOOD_LAST_NAME - click_idv_continue - - expect(page).to have_current_path(idv_in_person_step_path(step: :address), wait: 10) - fill_out_address_form_ok - - fill_in t('idv.form.address1'), with: 'Джордж' - fill_in t('idv.form.address2_optional'), with: '(Nope) = %' - fill_in t('idv.form.city'), with: 'Елена' - click_idv_continue - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.address.errors.unsupported_chars', - char_list: 'Д, д, ж, о, р', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.address.errors.unsupported_chars', - char_list: '%, (, ), =', - ), - ) - - expect(page).to have_content( - I18n.t( - 'in_person_proofing.form.address.errors.unsupported_chars', - char_list: 'Е, а, е, л, н', - ), - ) - - # re-fill form with good inputs - fill_in t('idv.form.address1'), with: InPersonHelper::GOOD_ADDRESS1 - fill_in t('idv.form.address2_optional'), with: InPersonHelper::GOOD_ADDRESS2 - fill_in t('idv.form.city'), with: InPersonHelper::GOOD_CITY - click_idv_continue - expect(page).to have_current_path(idv_in_person_ssn_url, wait: 10) - end - end - end + it 'shows validation errors', + allow_browser_log: true do + sign_in_and_2fa_user + begin_in_person_proofing + complete_prepare_step + complete_location_step + expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) + + fill_out_state_id_form_ok + fill_in t('in_person_proofing.form.state_id.first_name'), with: 'T0mmy "Lee"' + fill_in t('in_person_proofing.form.state_id.last_name'), with: 'Джейкоб' + fill_in t('in_person_proofing.form.state_id.address1'), with: '#1 $treet' + fill_in t('in_person_proofing.form.state_id.address2'), with: 'Gr@nd Lañe^' + fill_in t('in_person_proofing.form.state_id.city'), with: 'B3st C!ty' + click_idv_continue - context 'in_person_capture_secondary_id_enabled feature flag disabled, then enabled during flow', - allow_browser_log: true do - let(:user) { user_with_2fa } + expect(page).to have_content( + I18n.t( + 'in_person_proofing.form.state_id.errors.unsupported_chars', + char_list: '", 0', + ), + ) - before(:each) do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) + expect(page).to have_content( + I18n.t( + 'in_person_proofing.form.state_id.errors.unsupported_chars', + char_list: 'Д, б, е, ж, й, к, о', + ), + ) - sign_in_and_2fa_user(user) - begin_in_person_proofing(user) - complete_prepare_step(user) - complete_location_step(user) + expect(page).to have_content( + I18n.t( + 'in_person_proofing.form.state_id.errors.unsupported_chars', + char_list: '$', + ), + ) + + expect(page).to have_content( + I18n.t( + 'in_person_proofing.form.state_id.errors.unsupported_chars', + char_list: '@, ^', + ), + ) + + expect(page).to have_content( + I18n.t( + 'in_person_proofing.form.state_id.errors.unsupported_chars', + char_list: '!, 3', + ), + ) + + # re-fill state id form with good inputs + fill_in t('in_person_proofing.form.state_id.first_name'), + with: InPersonHelper::GOOD_FIRST_NAME + fill_in t('in_person_proofing.form.state_id.last_name'), + with: InPersonHelper::GOOD_LAST_NAME + fill_in t('in_person_proofing.form.state_id.address1'), + with: InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1 + fill_in t('in_person_proofing.form.state_id.address2'), + with: InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2 + fill_in t('in_person_proofing.form.state_id.city'), + with: InPersonHelper::GOOD_IDENTITY_DOC_CITY + click_idv_continue + + expect(page).to have_current_path(idv_in_person_step_path(step: :address), wait: 10) end - it 'does not capture separate state id address from residential address' do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(true) - complete_state_id_step(user) - complete_address_step(user) - complete_ssn_step(user) + it 'shows hints when user selects Puerto Rico as state', + allow_browser_log: true do + sign_in_and_2fa_user + begin_in_person_proofing + complete_prepare_step + complete_location_step + expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) + + # state id page + select 'Puerto Rico', + from: t('in_person_proofing.form.state_id.identity_doc_address_state') + + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) + + # change state selection + fill_out_state_id_form_ok + expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) + + # re-select puerto rico + select 'Puerto Rico', + from: t('in_person_proofing.form.state_id.identity_doc_address_state') + click_idv_continue + + expect(page).to have_current_path(idv_in_person_step_path(step: :address)) + + # address form + select 'Puerto Rico', + from: t('idv.form.state') + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) + + # change selection + fill_out_address_form_ok + expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).not_to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) + + # re-select puerto rico + select 'Puerto Rico', + from: t('idv.form.state') + click_idv_continue + + # ssn page + expect(page).to have_current_path(idv_in_person_ssn_url) + complete_ssn_step + + # verify page + expect(page).to have_current_path(idv_in_person_verify_info_path) + expect(page).to have_text('PR').twice + + # update state ID + click_button t('idv.buttons.change_state_id_label') + + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) + click_button t('forms.buttons.submit.update') + + # update address + click_button t('idv.buttons.change_address_label') + + expect(page).to have_content(t('in_person_proofing.headings.update_address')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address1_hint')) + expect(page).to have_content(I18n.t('in_person_proofing.form.state_id.address2_hint')) end end - shared_examples 'captures address with state id' do + context 'same address as id is false', + allow_browser_log: true do let(:user) { user_with_2fa } before(:each) do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(true) - sign_in_and_2fa_user(user) begin_in_person_proofing(user) complete_prepare_step(user) complete_location_step(user) end - it 'successfully proceeds through the flow' do - complete_state_id_step( - user, same_address_as_id: false, capture_secondary_id_enabled: true - ) - complete_address_step(user, double_address_verification: true) + it 'shows the address page' do + complete_state_id_step(user, same_address_as_id: false) + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) + expect(page).to have_content(t('in_person_proofing.headings.address')) + + # arrive at address step + complete_address_step(user, same_address_as_id: false) + complete_ssn_step(user) # Ensure the page submitted successfully expect(page).to have_content(t('idv.form.ssn_label')) end - end - - context 'in_person_capture_secondary_id_enabled feature flag enabled', allow_browser_log: true do - context 'flag remains enabled' do - it_behaves_like 'captures address with state id' - end - - context 'flag is then disabled' do - before(:each) do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) - end - it_behaves_like 'captures address with state id' + it 'can update the address page form' do + complete_state_id_step(user, same_address_as_id: false) + complete_address_step(user, same_address_as_id: false) + complete_ssn_step(user) + # click update address button on the verify page + click_button t('idv.buttons.change_address_label') + expect(page).to have_content(t('in_person_proofing.headings.update_address')) + fill_out_address_form_ok(same_address_as_id: true) + click_button t('forms.buttons.submit.update') + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) end end - context 'in_person_capture_secondary_id_enabled feature flag enabled and same address as id', + context 'same address as id is true then update is selected on verify info pg', allow_browser_log: true do let(:user) { user_with_2fa } before(:each) do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(true) - sign_in_and_2fa_user(user) begin_in_person_proofing(user) complete_prepare_step(user) complete_location_step(user) end - it 'skips the address page' do - complete_state_id_step( - user, same_address_as_id: true, capture_secondary_id_enabled: true - ) - # skip address step - complete_ssn_step(user) - # Ensure the page submitted successfully - expect(page).to have_content(t('idv.form.ssn_label')) - end - - it 'can redo the address page form even if that page is skipped' do - complete_state_id_step( - user, same_address_as_id: true, capture_secondary_id_enabled: true - ) + it 'can redo the address page form after it is skipped' do + complete_state_id_step(user, same_address_as_id: true) # skip address step complete_ssn_step(user) # click update address button on the verify page click_button t('idv.buttons.change_address_label') expect(page).to have_content(t('in_person_proofing.headings.update_address')) - fill_out_address_form_ok(double_address_verification: true, same_address_as_id: true) + fill_out_address_form_ok(same_address_as_id: true) click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) expect(page).to have_current_path(idv_in_person_verify_info_path) end it 'allows user to update their residential address as different from their state id' do - complete_state_id_step( - user, same_address_as_id: true, capture_secondary_id_enabled: true - ) + complete_state_id_step(user, same_address_as_id: true) complete_ssn_step(user) # click "update residential address" @@ -788,167 +652,155 @@ end end - context 'in_person_capture_secondary_id_enabled feature flag enabled and' do - context 'when updates are made on state ID page starting from Verify Your Information', - allow_browser_log: true do - let(:user) { user_with_2fa } - - before(:each) do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(true) + context 'Updates are made on state ID page starting from Verify Your Information', + allow_browser_log: true do + let(:user) { user_with_2fa } - sign_in_and_2fa_user(user) - begin_in_person_proofing(user) - complete_prepare_step(user) - complete_location_step(user) - end + before(:each) do + sign_in_and_2fa_user(user) + begin_in_person_proofing(user) + complete_prepare_step(user) + complete_location_step(user) + end - it 'does not update their previous selection of "Yes, + it 'does not update their previous selection of "Yes, I live at the address on my state-issued ID"' do - complete_state_id_step( - user, same_address_as_id: true, capture_secondary_id_enabled: true - ) - # skip address step - complete_ssn_step(user) - # expect to be on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - # click update state ID button on the verify page - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # change address - fill_in t('in_person_proofing.form.state_id.address1'), with: '' - fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' - click_button t('forms.buttons.submit.update') - # expect to be back on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - expect(page).to have_content(t('headings.verify')) - # expect to see state ID address update on verify twice - expect(page).to have_text('test update address').twice # for state id addr and addr update - # click update state id address - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # expect "Yes, I live at a different address" is checked" - expect(page).to have_checked_field( - t('in_person_proofing.form.state_id.same_address_as_id_yes'), - visible: false, - ) - end + complete_state_id_step(user, same_address_as_id: true) + # skip address step + complete_ssn_step(user) + # expect to be on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + # click update state ID button on the verify page + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # change address + fill_in t('in_person_proofing.form.state_id.address1'), with: '' + fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' + click_button t('forms.buttons.submit.update') + # expect to be back on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + expect(page).to have_content(t('headings.verify')) + # expect to see state ID address update on verify twice + expect(page).to have_text('test update address').twice # for state id addr and addr update + # click update state id address + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # expect "Yes, I live at a different address" is checked" + expect(page).to have_checked_field( + t('in_person_proofing.form.state_id.same_address_as_id_yes'), + visible: false, + ) + end - it 'does not update their previous selection of "No, I live at a different address"' do - complete_state_id_step( - user, same_address_as_id: false, capture_secondary_id_enabled: true - ) - # expect to be on address page - expect(page).to have_content(t('in_person_proofing.headings.address')) - # complete address step - complete_address_step(user, double_address_verification: true) - complete_ssn_step(user) - # expect to be back on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - # click update state ID button on the verify page - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # change address - fill_in t('in_person_proofing.form.state_id.address1'), with: '' - fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' - click_button t('forms.buttons.submit.update') - # expect to be back on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - expect(page).to have_content(t('headings.verify')) - # expect to see state ID address update on verify - expect(page).to have_text('test update address').once # only state id address update - # click update state id address - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - expect(page).to have_checked_field( - t('in_person_proofing.form.state_id.same_address_as_id_no'), - visible: false, - ) - end + it 'does not update their previous selection of "No, I live at a different address"' do + complete_state_id_step(user, same_address_as_id: false) + # expect to be on address page + expect(page).to have_content(t('in_person_proofing.headings.address')) + # complete address step + complete_address_step(user) + complete_ssn_step(user) + # expect to be back on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + # click update state ID button on the verify page + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # change address + fill_in t('in_person_proofing.form.state_id.address1'), with: '' + fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' + click_button t('forms.buttons.submit.update') + # expect to be back on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + expect(page).to have_content(t('headings.verify')) + # expect to see state ID address update on verify + expect(page).to have_text('test update address').once # only state id address update + # click update state id address + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + expect(page).to have_checked_field( + t('in_person_proofing.form.state_id.same_address_as_id_no'), + visible: false, + ) + end - it 'updates their previous selection from "Yes" TO "No, I live at a different address"' do - complete_state_id_step( - user, same_address_as_id: true, capture_secondary_id_enabled: true - ) - # skip address step - complete_ssn_step(user) - # click update state ID button on the verify page - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # change address - fill_in t('in_person_proofing.form.state_id.address1'), with: '' - fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' - # change response to No - choose t('in_person_proofing.form.state_id.same_address_as_id_no') - click_button t('forms.buttons.submit.update') - # expect to be on address page - expect(page).to have_content(t('in_person_proofing.headings.address')) - # complete address step - complete_address_step(user, double_address_verification: true) - # expect to be on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - # expect to see state ID address update on verify - expect(page).to have_text('test update address').once # only state id address update - # click update state id address - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # check that the "No, I live at a different address" is checked" - expect(page).to have_checked_field( - t('in_person_proofing.form.state_id.same_address_as_id_no'), - visible: false, - ) - end + it 'updates their previous selection from "Yes" TO "No, I live at a different address"' do + complete_state_id_step(user, same_address_as_id: true) + # skip address step + complete_ssn_step(user) + # click update state ID button on the verify page + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # change address + fill_in t('in_person_proofing.form.state_id.address1'), with: '' + fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' + # change response to No + choose t('in_person_proofing.form.state_id.same_address_as_id_no') + click_button t('forms.buttons.submit.update') + # expect to be on address page + expect(page).to have_content(t('in_person_proofing.headings.address')) + # complete address step + complete_address_step(user) + # expect to be on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + # expect to see state ID address update on verify + expect(page).to have_text('test update address').once # only state id address update + # click update state id address + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # check that the "No, I live at a different address" is checked" + expect(page).to have_checked_field( + t('in_person_proofing.form.state_id.same_address_as_id_no'), + visible: false, + ) + end - it 'updates their previous selection from "No" TO "Yes, + it 'updates their previous selection from "No" TO "Yes, I live at the address on my state-issued ID"' do - complete_state_id_step( - user, same_address_as_id: false, capture_secondary_id_enabled: true - ) - # expect to be on address page - expect(page).to have_content(t('in_person_proofing.headings.address')) - # complete address step - complete_address_step(user, double_address_verification: true) - complete_ssn_step(user) - # expect to be on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - # click update state ID button on the verify page - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - # change address - fill_in t('in_person_proofing.form.state_id.address1'), with: '' - fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' - # change response to Yes - choose t('in_person_proofing.form.state_id.same_address_as_id_yes') - click_button t('forms.buttons.submit.update') - # expect to be back on verify page - expect(page).to have_content(t('headings.verify')) - expect(page).to have_current_path(idv_in_person_verify_info_path) - # expect to see state ID address update on verify twice - expect(page).to have_text('test update address').twice # for state id addr and addr update - # click update state ID button on the verify page - click_button t('idv.buttons.change_state_id_label') - # expect to be on the state ID page - expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) - expect(page).to have_checked_field( - t('in_person_proofing.form.state_id.same_address_as_id_yes'), - visible: false, - ) - end + complete_state_id_step(user, same_address_as_id: false) + # expect to be on address page + expect(page).to have_content(t('in_person_proofing.headings.address')) + # complete address step + complete_address_step(user) + complete_ssn_step(user) + # expect to be on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + # click update state ID button on the verify page + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + # change address + fill_in t('in_person_proofing.form.state_id.address1'), with: '' + fill_in t('in_person_proofing.form.state_id.address1'), with: 'test update address' + # change response to Yes + choose t('in_person_proofing.form.state_id.same_address_as_id_yes') + click_button t('forms.buttons.submit.update') + # expect to be back on verify page + expect(page).to have_content(t('headings.verify')) + expect(page).to have_current_path(idv_in_person_verify_info_path) + # expect to see state ID address update on verify twice + expect(page).to have_text('test update address').twice # for state id addr and addr update + # click update state ID button on the verify page + click_button t('idv.buttons.change_state_id_label') + # expect to be on the state ID page + expect(page).to have_content(t('in_person_proofing.headings.update_state_id')) + expect(page).to have_checked_field( + t('in_person_proofing.form.state_id.same_address_as_id_yes'), + visible: false, + ) end end + context 'when manual address entry is enabled for post office search' do let(:user) { user_with_2fa } @@ -966,10 +818,10 @@ complete_location_step # state ID page - complete_state_id_step(user) + complete_state_id_step(user, same_address_as_id: false) # address page - complete_address_step(user) + complete_address_step(user, same_address_as_id: false) # ssn page select 'Reject', from: :mock_profiling_result @@ -983,6 +835,11 @@ expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_CITY) + expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction]).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ZIPCODE) expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) expect(page).to have_text(InPersonHelper::GOOD_CITY) expect(page).to have_text(InPersonHelper::GOOD_ZIPCODE) diff --git a/spec/features/idv/steps/gpo_otp_verification_step_spec.rb b/spec/features/idv/steps/gpo_otp_verification_step_spec.rb index 52916a4d67d..dc5f0560a3b 100644 --- a/spec/features/idv/steps/gpo_otp_verification_step_spec.rb +++ b/spec/features/idv/steps/gpo_otp_verification_step_spec.rb @@ -147,6 +147,7 @@ expect(current_path).to eq idv_verify_by_mail_enter_code_path expect(page).to have_content t('idv.gpo.alert_info') + expect(page).to have_content strip_tags(t('idv.gpo.change_to_verification_code_html')) expect(page).to have_content t('idv.gpo.wrong_address') expect(page).to have_content Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE[:address1] diff --git a/spec/features/idv/steps/in_person/ssn_spec.rb b/spec/features/idv/steps/in_person/ssn_spec.rb index 011f4ed029e..31e35137481 100644 --- a/spec/features/idv/steps/in_person/ssn_spec.rb +++ b/spec/features/idv/steps/in_person/ssn_spec.rb @@ -6,7 +6,6 @@ before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled).and_return(true) end context 'when visiting ssn for the first time' do @@ -101,7 +100,7 @@ end end - context 'when in_person_capture_secondary_id_enabled is true, ssn step is accessible from' do + context 'when same_address_as_id is false, ssn step is accessible from' do it 'address step', allow_browser_log: true do user = user_with_2fa sign_in_and_2fa_user(user) @@ -111,25 +110,27 @@ # location page complete_location_step(user) # state ID page - fill_out_state_id_form_ok(same_address_as_id: false, capture_secondary_id_enabled: true) + fill_out_state_id_form_ok(same_address_as_id: false) click_idv_continue - fill_out_address_form_ok(double_address_verification: true, same_address_as_id: false) + fill_out_address_form_ok(same_address_as_id: false) click_idv_continue # ssn page expect(page).to have_content(t('doc_auth.headings.ssn')) end - it 'state_id step (when state id address matches residential address)', - allow_browser_log: true do - user = user_with_2fa - complete_idv_steps_before_ssn(user) - # ssn page - expect(page).to have_content(t('doc_auth.headings.ssn')) - end - it 'verify info step', allow_browser_log: true do user = user_with_2fa - complete_idv_steps_before_ssn(user) + sign_in_and_2fa_user(user) + begin_in_person_proofing(user) + # prepare page + complete_prepare_step(user) + # location page + complete_location_step(user) + # state ID page + fill_out_state_id_form_ok(same_address_as_id: false) + click_idv_continue + fill_out_address_form_ok(same_address_as_id: false) + click_idv_continue # ssn page (first visit) complete_ssn_step(user) # verify page (next page) diff --git a/spec/features/idv/steps/in_person/state_id_step_spec.rb b/spec/features/idv/steps/in_person/state_id_step_spec.rb index a265174d37f..aa774a0477a 100644 --- a/spec/features/idv/steps/in_person/state_id_step_spec.rb +++ b/spec/features/idv/steps/in_person/state_id_step_spec.rb @@ -8,36 +8,28 @@ allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) end - context 'capture secondary id is enabled' do - before do - allow(IdentityConfig.store). - to(receive(:in_person_capture_secondary_id_enabled)). - and_return(true) - end + it 'validates zip code input', allow_browser_log: true do + user = user_with_2fa - it 'validates zip code input', allow_browser_log: true do - user = user_with_2fa - - sign_in_and_2fa_user(user) - begin_in_person_proofing(user) - complete_prepare_step(user) - complete_location_step(user) - expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - fill_out_state_id_form_ok(same_address_as_id: true, capture_secondary_id_enabled: true) - # blank out the zip code field - fill_in t('in_person_proofing.form.state_id.zipcode'), with: '' - # try to enter invalid input into the zip code field - fill_in t('in_person_proofing.form.state_id.zipcode'), with: 'invalid input' - expect(page).to have_field(t('in_person_proofing.form.state_id.zipcode'), with: '') - # enter valid characters, but invalid length - fill_in t('in_person_proofing.form.state_id.zipcode'), with: '123' - click_idv_continue - expect(page).to have_css('.usa-error-message', text: t('idv.errors.pattern_mismatch.zipcode')) - # enter a valid zip and make sure we can continue - fill_in t('in_person_proofing.form.state_id.zipcode'), with: '123456789' - expect(page).to have_field(t('in_person_proofing.form.state_id.zipcode'), with: '12345-6789') - click_idv_continue - expect(page).to have_current_path(idv_in_person_ssn_url) - end + sign_in_and_2fa_user(user) + begin_in_person_proofing(user) + complete_prepare_step(user) + complete_location_step(user) + expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) + fill_out_state_id_form_ok(same_address_as_id: true) + # blank out the zip code field + fill_in t('in_person_proofing.form.state_id.zipcode'), with: '' + # try to enter invalid input into the zip code field + fill_in t('in_person_proofing.form.state_id.zipcode'), with: 'invalid input' + expect(page).to have_field(t('in_person_proofing.form.state_id.zipcode'), with: '') + # enter valid characters, but invalid length + fill_in t('in_person_proofing.form.state_id.zipcode'), with: '123' + click_idv_continue + expect(page).to have_css('.usa-error-message', text: t('idv.errors.pattern_mismatch.zipcode')) + # enter a valid zip and make sure we can continue + fill_in t('in_person_proofing.form.state_id.zipcode'), with: '123456789' + expect(page).to have_field(t('in_person_proofing.form.state_id.zipcode'), with: '12345-6789') + click_idv_continue + expect(page).to have_current_path(idv_in_person_ssn_url) end end diff --git a/spec/features/idv/steps/in_person/verify_info_spec.rb b/spec/features/idv/steps/in_person/verify_info_spec.rb index c4a4be66b56..f7172c6a70a 100644 --- a/spec/features/idv/steps/in_person/verify_info_spec.rb +++ b/spec/features/idv/steps/in_person/verify_info_spec.rb @@ -7,8 +7,7 @@ let(:user) { user_with_2fa } let(:fake_analytics) { FakeAnalytics.new(user: user) } - let(:capture_secondary_id_enabled) { false } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } + let(:enrollment) { InPersonEnrollment.new } before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) @@ -24,7 +23,6 @@ complete_prepare_step(user) complete_location_step(user) complete_state_id_step(user) - complete_address_step(user) complete_ssn_step(user) # verify page @@ -35,10 +33,11 @@ expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) - expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) - expect(page).to have_text(InPersonHelper::GOOD_CITY) - expect(page).to have_text(InPersonHelper::GOOD_ZIPCODE) - expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state]) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_CITY).twice + expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction], count: 3) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ZIPCODE).twice expect(page).to have_text(DocAuthHelper::GOOD_SSN_MASKED) # click update state ID button @@ -58,7 +57,7 @@ click_doc_auth_back_link expect(page).to have_content(t('headings.verify')) expect(page).to have_current_path(idv_in_person_verify_info_path) - expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1) expect(page).not_to have_text('bad address') # click update ssn button @@ -83,7 +82,6 @@ complete_prepare_step(user) complete_location_step(user) complete_state_id_step(user) - complete_address_step(user) complete_ssn_step(user) # verify page @@ -95,10 +93,11 @@ expect(page).to have_text(InPersonHelper::GOOD_LAST_NAME) expect(page).to have_text(InPersonHelper::GOOD_DOB_FORMATTED_EVENT) expect(page).to have_text(InPersonHelper::GOOD_STATE_ID_NUMBER) - expect(page).to have_text(InPersonHelper::GOOD_ADDRESS1) - expect(page).to have_text(InPersonHelper::GOOD_CITY) - expect(page).to have_text(InPersonHelper::GOOD_ZIPCODE) - expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state]) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS1).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ADDRESS2).twice + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_CITY).twice + expect(page).to have_text(Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction], count: 3) + expect(page).to have_text(InPersonHelper::GOOD_IDENTITY_DOC_ZIPCODE).twice expect(page).to have_text(DocAuthHelper::GOOD_SSN_MASKED) # click update state ID button @@ -115,7 +114,6 @@ click_button t('idv.buttons.change_address_label') expect(page).to have_content(t('in_person_proofing.headings.update_address')) fill_in t('idv.form.address1'), with: '987 Fake St.' - choose t('in_person_proofing.form.address.same_address_choice_yes') click_button t('forms.buttons.submit.update') expect(page).to have_content(t('headings.verify')) expect(page).to have_current_path(idv_in_person_verify_info_path) @@ -145,7 +143,6 @@ complete_prepare_step(user) complete_location_step(user) complete_state_id_step(user) - complete_address_step(user) fill_out_ssn_form_with_ssn_that_fails_resolution click_idv_continue click_idv_continue @@ -163,7 +160,6 @@ complete_prepare_step(user) complete_location_step(user) complete_state_id_step(user) - complete_address_step(user) complete_ssn_step(user) click_idv_continue diff --git a/spec/features/openid_connect/openid_connect_spec.rb b/spec/features/openid_connect/openid_connect_spec.rb index ffe97872183..2fe438b58df 100644 --- a/spec/features/openid_connect/openid_connect_spec.rb +++ b/spec/features/openid_connect/openid_connect_spec.rb @@ -290,6 +290,8 @@ post_logout_redirect_uri: 'gov.gsa.openidconnect.test://result/signout', state: state, ) + expect(page.response_headers['Content-Security-Policy']). + to(include('form-action \'self\' gov.gsa.openidconnect.test:')) expect(page).to have_content( t( 'openid_connect.logout.heading_with_sp', diff --git a/spec/forms/idv/in_person/address_form_spec.rb b/spec/forms/idv/in_person/address_form_spec.rb index f51daf033e3..fc6d284c5df 100644 --- a/spec/forms/idv/in_person/address_form_spec.rb +++ b/spec/forms/idv/in_person/address_form_spec.rb @@ -23,7 +23,7 @@ } end context 'when usps_ipp_transliteration_enabled is false' do - let(:subject) { described_class.new(capture_secondary_id_enabled: true) } + let(:subject) { described_class.new } before(:each) do allow(IdentityConfig.store).to receive(:usps_ipp_transliteration_enabled).and_return(false) end @@ -52,7 +52,7 @@ end end context 'when usps_ipp_transliteration_enabled is enabled ' do - let(:subject) { described_class.new(capture_secondary_id_enabled: true) } + let(:subject) { described_class.new } before(:each) do allow(IdentityConfig.store).to receive(:usps_ipp_transliteration_enabled).and_return(true) end @@ -77,26 +77,13 @@ before(:each) do allow(IdentityConfig.store).to receive(:usps_ipp_transliteration_enabled).and_return(true) end - context 'when capture_secondary_id_enabled is true' do - let(:subject) { described_class.new(capture_secondary_id_enabled: true) } - it 'submit with missing same_address_as_id should be successful' do - missing_required_params = good_params.except(:same_address_as_id) - result = subject.submit(missing_required_params) - expect(subject.errors.empty?).to be(true) - expect(result).to be_kind_of(FormResponse) - expect(result.success?).to be(true) - end - end - context 'when capture_secondary_id_enabled is false' do - let(:subject) { described_class.new(capture_secondary_id_enabled: false) } - it 'submit with missing same_address_as_id will fail' do - missing_required_params = good_params.except(:same_address_as_id) - result = subject.submit(missing_required_params) - expect(subject.errors.empty?).to be(false) - expect(result).to be_kind_of(FormResponse) - expect(result.success?).to be(false) - expect(result.errors.keys).to include(:same_address_as_id) - end + let(:subject) { described_class.new } + it 'submit with missing same_address_as_id should be successful' do + missing_required_params = good_params.except(:same_address_as_id) + result = subject.submit(missing_required_params) + expect(subject.errors.empty?).to be(true) + expect(result).to be_kind_of(FormResponse) + expect(result.success?).to be(true) end end end diff --git a/spec/forms/idv/state_id_form_spec.rb b/spec/forms/idv/state_id_form_spec.rb index a2d371c481d..7e2fadb21a5 100644 --- a/spec/forms/idv/state_id_form_spec.rb +++ b/spec/forms/idv/state_id_form_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' RSpec.describe Idv::StateIdForm do - let(:subject) { Idv::StateIdForm.new(pii, capture_secondary_id_enabled:) } + let(:subject) { Idv::StateIdForm.new(pii) } let(:valid_dob) do valid_d = Time.zone.today - IdentityConfig.store.idv_min_age_years.years - 1.day ActionController::Parameters.new( @@ -62,7 +62,6 @@ } end let(:pii) { nil } - let(:capture_secondary_id_enabled) { true } describe '#submit' do context 'when the form is valid' do it 'returns a successful form response' do diff --git a/spec/jobs/get_usps_proofing_results_job_spec.rb b/spec/jobs/get_usps_proofing_results_job_spec.rb index defb960d05f..8b517ec960d 100644 --- a/spec/jobs/get_usps_proofing_results_job_spec.rb +++ b/spec/jobs/get_usps_proofing_results_job_spec.rb @@ -218,7 +218,7 @@ describe '#perform' do describe 'IPP enabled' do - describe 'DAV not enabled' do + describe 'Proofed without secondary id' do let!(:pending_enrollments) do ['BALTIMORE', 'FRIENDSHIP', 'WASHINGTON', 'ARLINGTON', 'DEANWOOD'].map do |name| create( @@ -1149,19 +1149,17 @@ end end - describe 'DAV enabled' do - let(:capture_secondary_id_enabled) { true } + describe 'Proofed with secondary id' do let(:pending_enrollment) do create( - :in_person_enrollment, :pending, - capture_secondary_id_enabled: capture_secondary_id_enabled + :in_person_enrollment, :pending ) end before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) end - context 'when an enrollment passes proofing with an secondary ID and DAV enabled' do + context 'when an enrollment passes proofing with a secondary ID' do before do stub_request_passed_proofing_secondary_id_type_results end @@ -1212,85 +1210,82 @@ ) end end + end - context 'sms notifications enabled' do - let(:pending_enrollment) do - create( - :in_person_enrollment, - :pending, - :with_notification_phone_configuration, - capture_secondary_id_enabled: true, - ) - end - - before do - allow(IdentityConfig.store).to receive(:in_person_send_proofing_notifications_enabled). - and_return(true) - end + describe 'sms notifications enabled' do + let(:pending_enrollment) do + create( + :in_person_enrollment, :pending, :with_notification_phone_configuration + ) + end + before do + allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) + allow(IdentityConfig.store).to receive(:in_person_send_proofing_notifications_enabled). + and_return(true) + end - context 'enrollment is expired' do - it 'deletes the notification phone configuration without sending an sms' do - stub_request_expired_proofing_results + context 'enrollment is expired' do + it 'deletes the notification phone configuration without sending an sms' do + stub_request_expired_proofing_results - expect(pending_enrollment.notification_phone_configuration).to_not be_nil + expect(pending_enrollment.notification_phone_configuration).to_not be_nil - job.perform(Time.zone.now) + job.perform(Time.zone.now) - expect(pending_enrollment.reload.notification_phone_configuration).to be_nil - expect(pending_enrollment.notification_sent_at).to be_nil - end + expect(pending_enrollment.reload.notification_phone_configuration).to be_nil + expect(pending_enrollment.notification_sent_at).to be_nil end + end - context 'enrollment has passed proofing' do - it 'invokes the SendProofingNotificationJob for the enrollment' do - stub_request_passed_proofing_results + context 'enrollment has passed proofing' do + it 'invokes the SendProofingNotificationJob for the enrollment' do + stub_request_passed_proofing_results - expect(pending_enrollment.notification_phone_configuration).to_not be_nil - expect(pending_enrollment.notification_sent_at).to be_nil + expect(pending_enrollment.notification_phone_configuration).to_not be_nil + expect(pending_enrollment.notification_sent_at).to be_nil - expect { job.perform(Time.zone.now) }. - to have_enqueued_job(InPerson::SendProofingNotificationJob). - with(pending_enrollment.id) - end + expect { job.perform(Time.zone.now) }. + to have_enqueued_job(InPerson::SendProofingNotificationJob). + with(pending_enrollment.id) end + end - context 'enrollment has failed proofing' do - it 'invokes the SendProofingNotificationJob for the enrollment' do - stub_request_failed_proofing_results + context 'enrollment has failed proofing' do + it 'invokes the SendProofingNotificationJob for the enrollment' do + stub_request_failed_proofing_results - expect(pending_enrollment.notification_phone_configuration).to_not be_nil - expect(pending_enrollment.notification_sent_at).to be_nil + expect(pending_enrollment.notification_phone_configuration).to_not be_nil + expect(pending_enrollment.notification_sent_at).to be_nil - expect { job.perform(Time.zone.now) }. - to have_enqueued_job(InPerson::SendProofingNotificationJob). - with(pending_enrollment.id) - end + expect { job.perform(Time.zone.now) }. + to have_enqueued_job(InPerson::SendProofingNotificationJob). + with(pending_enrollment.id) end + end - context 'enrollment has failed proofing due to unsupported secondary ID' do - it 'invokes the SendProofingNotificationJob for the enrollment' do - stub_request_passed_proofing_secondary_id_type_results + context 'enrollment has failed proofing due to unsupported secondary ID' do + it 'invokes the SendProofingNotificationJob for the enrollment' do + stub_request_passed_proofing_secondary_id_type_results - expect(pending_enrollment.notification_phone_configuration).to_not be_nil - expect(pending_enrollment.notification_sent_at).to be_nil + expect(pending_enrollment.notification_phone_configuration).to_not be_nil + expect(pending_enrollment.notification_sent_at).to be_nil - expect { job.perform(Time.zone.now) }. - to have_enqueued_job(InPerson::SendProofingNotificationJob). - with(pending_enrollment.id) - end + expect { job.perform(Time.zone.now) }. + to have_enqueued_job(InPerson::SendProofingNotificationJob). + with(pending_enrollment.id) end + end - context 'enrollment has failed proofing due to unsupported ID type' do - it 'invokes the SendProofingNotificationJob for the enrollment' do - stub_request_passed_proofing_unsupported_id_results + context 'enrollment has failed proofing due to unsupported ID type' do + it 'invokes the SendProofingNotificationJob for the enrollment' do + stub_request_passed_proofing_unsupported_id_results - expect(pending_enrollment.notification_phone_configuration).to_not be_nil - expect(pending_enrollment.notification_sent_at).to be_nil + expect(pending_enrollment.notification_phone_configuration).to_not be_nil + expect(pending_enrollment.notification_sent_at).to be_nil - expect { job.perform(Time.zone.now) }. - to have_enqueued_job(InPerson::SendProofingNotificationJob). - with(pending_enrollment.id) - end + expect { job.perform(Time.zone.now) }. + to have_enqueued_job(InPerson::SendProofingNotificationJob). + with(pending_enrollment.id) end end end diff --git a/spec/jobs/multi_region_kms_migration/profile_migration_job_spec.rb b/spec/jobs/multi_region_kms_migration/profile_migration_job_spec.rb deleted file mode 100644 index aa7880b5c0b..00000000000 --- a/spec/jobs/multi_region_kms_migration/profile_migration_job_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -require 'rails_helper' - -RSpec.describe MultiRegionKmsMigration::ProfileMigrationJob do - let!(:profiles) { create_list(:profile, 4, :with_pii) } - let!(:single_region_ciphertext_profiles) do - single_region_profiles = profiles[2..3] - single_region_profiles.each do |profile| - profile.update!( - encrypted_pii_multi_region: nil, - encrypted_pii_recovery_multi_region: nil, - ) - end - single_region_profiles - end - let!(:multi_region_ciphertext_profiles) { profiles[0..1] } - - describe '#perform' do - it 'does not modify records that do have multi-region ciphertexts' do - profile = multi_region_ciphertext_profiles.first - - original_encrypted_pii_multi_region = profile.encrypted_pii_multi_region - original_encrypted_pii_recovery_multi_region = profile.encrypted_pii_recovery_multi_region - - described_class.perform_now - - expect(profile.reload.encrypted_pii_multi_region).to eq( - original_encrypted_pii_multi_region, - ) - expect(profile.encrypted_pii_recovery_multi_region).to eq( - original_encrypted_pii_recovery_multi_region, - ) - end - - it 'migrates records that do not have multi-region ciphertexts' do - described_class.perform_now - - aggregate_failures do - single_region_ciphertext_profiles.each do |profile| - expect(profile.reload.encrypted_pii_multi_region).to_not be_blank - expect(profile.encrypted_pii_recovery_multi_region).to_not be_blank - end - end - end - - context 'when errors occur' do - let(:profile_migrator) { double(Encryption::MultiRegionKmsMigration::ProfileMigrator) } - - before do - allow(profile_migrator).to receive(:migrate!).and_raise(RuntimeError, 'test error') - allow( - Encryption::MultiRegionKmsMigration::ProfileMigrator, - ).to receive(:new).and_return(profile_migrator) - end - - it 'logs the error' do - analytics = subject.analytics - - expect(analytics).to receive(:track_event).twice.with( - 'Multi-region KMS migration: Profile migrated', - success: false, - profile_id: instance_of(Integer), - exception: instance_of(String), - ) - expect(analytics).to receive(:track_event).with( - 'Multi-region KMS migration: Profile migration summary', - profile_count: 2, - success_count: 0, - error_count: 2, - ) - - subject.perform_now - end - - it 'aborts after it encounters too many errors' do - # rubocop:disable Rails/SkipsModelValidations - create_list(:profile, 11, :with_pii) - Profile.update_all( - encrypted_pii_multi_region: nil, - encrypted_pii_recovery_multi_region: nil, - ) - # rubocop:enable Rails/SkipsModelValidations - - subject.perform_now - - expect(profile_migrator).to have_received(:migrate!).exactly(10).times - end - end - end - - describe '#find_profiles_to_migrate' do - it 'returns the profiles that need to be migrated' do - results = subject.find_profiles_to_migrate(statement_timeout: 120, profile_count: 2) - - expect(results).to match_array(single_region_ciphertext_profiles) - end - - context 'when a profile does not include PII' do - let(:profiles) { create_list(:profile, 4) } - - it 'does not return the profile' do - results = subject.find_profiles_to_migrate(statement_timeout: 120, profile_count: 2) - - expect(results).to be_empty - end - end - end -end diff --git a/spec/jobs/reports/monthly_key_metrics_report_spec.rb b/spec/jobs/reports/monthly_key_metrics_report_spec.rb index bc0298d6ccd..ae244517381 100644 --- a/spec/jobs/reports/monthly_key_metrics_report_spec.rb +++ b/spec/jobs/reports/monthly_key_metrics_report_spec.rb @@ -8,11 +8,17 @@ let(:agnes_email) { 'fake@agnes_email.com' } let(:feds_email) { 'fake@feds_email.com' } let(:s3_report_bucket_prefix) { 'reports-bucket' } + let(:report_folder) do + 'int/monthly-key-metrics-report/2021/2021-03-02.monthly-key-metrics-report' + end let(:account_reuse_s3_path) do - 'int/monthly-key-metrics-report/2021/2021-03-02.monthly-key-metrics-report/account_reuse.csv' + "#{report_folder}/account_reuse.csv" end let(:total_profiles_s3_path) do - 'int/monthly-key-metrics-report/2021/2021-03-02.monthly-key-metrics-report/total_profiles.csv' + "#{report_folder}/total_profiles.csv" + end + let(:account_deletion_rate_s3_path) do + "#{report_folder}/account_deletion_rate.csv" end before do @@ -86,6 +92,13 @@ bucket: 'reports-bucket.1234-us-west-1', ).exactly(1).time.and_call_original + expect(subject).to receive(:upload_file_to_s3_bucket).with( + path: account_deletion_rate_s3_path, + body: anything, + content_type: 'text/csv', + bucket: 'reports-bucket.1234-us-west-1', + ).exactly(1).time.and_call_original + subject.perform(report_date) end end diff --git a/spec/jobs/resolution_proofing_job_spec.rb b/spec/jobs/resolution_proofing_job_spec.rb index 84fc0c97232..a581637b608 100644 --- a/spec/jobs/resolution_proofing_job_spec.rb +++ b/spec/jobs/resolution_proofing_job_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' RSpec.describe ResolutionProofingJob, type: :job do - let(:pii) { Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN } + let(:pii) { Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID } let(:encrypted_arguments) do Encryption::Encryptors::BackgroundProofingArgEncryptor.new.encrypt( { applicant_pii: pii }.to_json, diff --git a/spec/lib/linters/analytics_event_name_linter_spec.rb b/spec/lib/linters/analytics_event_name_linter_spec.rb new file mode 100644 index 00000000000..adc2f3c9c59 --- /dev/null +++ b/spec/lib/linters/analytics_event_name_linter_spec.rb @@ -0,0 +1,32 @@ +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../lib/linters/analytics_event_name_linter' + +RSpec.describe RuboCop::Cop::IdentityIdp::AnalyticsEventNameLinter do + include CopHelper + include RuboCop::RSpec::ExpectOffense + + let(:config) { RuboCop::Config.new } + let(:cop) { RuboCop::Cop::IdentityIdp::AnalyticsEventNameLinter.new(config) } + + it 'registers an offense when event name does not match method name' do + expect_offense(<<~RUBY) + module AnalyticsEvents + def my_method + track_event(:not_my_method) + ^^^^^^^^^^^^^^ IdentityIdp/AnalyticsEventNameLinter: Event name must match the method name, expected `:my_method` + end + end + RUBY + end + + it 'does not register an offense when event name matches method name' do + expect_no_offenses(<<~RUBY) + module AnalyticsEvents + def my_method + track_event(:my_method) + end + end + RUBY + end +end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 2da146b5174..a85d3df8ba1 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -234,7 +234,6 @@ def in_person_enrollment ), status_updated_at: Time.zone.now - 1.hour, current_address_matches_id: params['current_address_matches_id'] == 'true', - capture_secondary_id_enabled: IdentityConfig.store.in_person_capture_secondary_id_enabled, selected_location_details: { 'name' => 'BALTIMORE', 'street_address' => '900 E FAYETTE ST RM 118', diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 344f2db5be1..91c41f04c8f 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -534,7 +534,6 @@ def expect_email_body_to_have_help_and_contact_links end context 'in person emails' do - let(:capture_secondary_id_enabled) { false } let(:current_address_matches_id) { false } let!(:enrollment) do create( @@ -542,7 +541,6 @@ def expect_email_body_to_have_help_and_contact_links :pending, selected_location_details: { name: 'FRIENDSHIP' }, status_updated_at: Time.zone.now - 2.hours, - capture_secondary_id_enabled: capture_secondary_id_enabled, current_address_matches_id: current_address_matches_id, ) end @@ -557,25 +555,6 @@ def expect_email_body_to_have_help_and_contact_links it_behaves_like 'a system email' it_behaves_like 'an email that respects user email locale preference' - context 'double address verification is not enabled' do - it 'renders the body' do - expect(mail.html_part.body). - to have_content( - t('in_person_proofing.process.proof_of_address.heading'), - ) - end - end - - context 'double address verification is enabled' do - let(:capture_secondary_id_enabled) { true } - it 'renders the body' do - expect(mail.html_part.body). - to_not have_content( - t('in_person_proofing.process.proof_of_address.heading'), - ) - end - end - context 'Outage message' do let(:formatted_date) { 'Tuesday, October 31' } let(:in_person_outage_emailed_by_date) { 'November 1, 2023' } @@ -646,25 +625,6 @@ def expect_email_body_to_have_help_and_contact_links it_behaves_like 'a system email' it_behaves_like 'an email that respects user email locale preference' - context 'double address verification is not enabled' do - it 'renders the body' do - expect(mail.html_part.body). - to have_content( - t('in_person_proofing.process.proof_of_address.heading'), - ) - end - end - - context 'double address verification is enabled' do - let(:capture_secondary_id_enabled) { true } - it 'renders the body' do - expect(mail.html_part.body). - to_not have_content( - t('in_person_proofing.process.proof_of_address.heading'), - ) - end - end - it 'renders the body' do expect(mail.html_part.body). to have_content( @@ -699,7 +659,6 @@ def expect_email_body_to_have_help_and_contact_links selected_location_details: { name: 'FRIENDSHIP' }, status_updated_at: Time.zone.now - 2.hours, current_address_matches_id: current_address_matches_id, - capture_secondary_id_enabled: capture_secondary_id_enabled, ) end @@ -711,25 +670,6 @@ def expect_email_body_to_have_help_and_contact_links it_behaves_like 'a system email' it_behaves_like 'an email that respects user email locale preference' - - context 'double address verification is not enabled' do - it 'renders the body' do - expect(mail.html_part.body). - to have_content( - t('user_mailer.in_person_failed.verifying_step_proof_of_address'), - ) - end - end - - context 'double address verification is enabled' do - let(:capture_secondary_id_enabled) { true } - it 'renders the body' do - expect(mail.html_part.body). - to_not have_content( - t('user_mailer.in_person_failed.verifying_step_proof_of_address'), - ) - end - end end describe '#in_person_failed_fraud' do @@ -894,7 +834,7 @@ def expect_email_body_to_have_help_and_contact_links end it 'renders the subject' do - expect(mail.subject).to eq t('idv.messages.gpo_reminder.subject') + expect(mail.subject).to eq t('user_mailer.letter_reminder_14_days.subject') end it 'renders the body' do @@ -911,7 +851,7 @@ def expect_email_body_to_have_help_and_contact_links expected_body = strip_tags( t( - 'idv.messages.gpo_reminder.body_html', + 'user_mailer.letter_reminder_14_days.body_html', date_letter_was_sent: date_letter_was_sent.strftime(t('time.formats.event_date')), app_name: APP_NAME, help_link: expected_help_link, @@ -923,14 +863,14 @@ def expect_email_body_to_have_help_and_contact_links it 'renders the finish link' do expect(mail.html_part.body).to have_link( - t('idv.messages.gpo_reminder.finish'), + t('user_mailer.letter_reminder_14_days.finish'), href: idv_verify_by_mail_enter_code_url, ) end it 'renders the did not get it link' do expect(mail.html_part.body).to have_link( - t('idv.messages.gpo_reminder.sign_in_and_request_another_letter'), + t('user_mailer.letter_reminder_14_days.sign_in_and_request_another_letter'), href: idv_verify_by_mail_enter_code_url(did_not_receive_letter: 1), ) end diff --git a/spec/models/in_person_enrollment_spec.rb b/spec/models/in_person_enrollment_spec.rb index 35848e6d5ab..1d2bd5ac76b 100644 --- a/spec/models/in_person_enrollment_spec.rb +++ b/spec/models/in_person_enrollment_spec.rb @@ -144,34 +144,6 @@ expect(enrollment.unique_id).to eq('1234') end - - describe 'setting capture_secondary_id_enabled on creation' do - let(:capture_enabled) { nil } - - before do - allow(IdentityConfig.store). - to( - receive(:in_person_capture_secondary_id_enabled). - and_return(capture_enabled), - ) - end - - context 'feature flag is enabled' do - let(:capture_enabled) { true } - it 'sets capture_secondary_id_enabled to true on the enrollment' do - enrollment = create(:in_person_enrollment, :pending) - expect(enrollment.capture_secondary_id_enabled).to eq(true) - end - end - - context 'feature flag is not enabled' do - let(:capture_enabled) { false } - it 'does not set capture_secondary_id_enabled to true on the enrollment' do - enrollment = create(:in_person_enrollment, :pending) - expect(enrollment.capture_secondary_id_enabled).to eq(false) - end - end - end end describe 'enrollments that need email reminders' do diff --git a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb index ee9db5e0668..4c66d801dae 100644 --- a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb +++ b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb @@ -11,7 +11,6 @@ let(:enrollment_selected_location_details) do JSON.parse(UspsInPersonProofing::Mock::Fixtures.enrollment_selected_location_details) end - let(:capture_secondary_id_enabled) { false } let(:enrollment) do create( :in_person_enrollment, :with_service_provider, :pending, @@ -20,8 +19,7 @@ created_at: created_at, enrollment_established_at: enrollment_established_at, current_address_matches_id: current_address_matches_id, - selected_location_details: enrollment_selected_location_details, - capture_secondary_id_enabled: capture_secondary_id_enabled + selected_location_details: enrollment_selected_location_details ) end subject(:presenter) { described_class.new(enrollment: enrollment) } @@ -102,42 +100,6 @@ end end - describe '#needs_proof_of_address?' do - subject(:needs_proof_of_address) { presenter.needs_proof_of_address? } - - context 'with double address verification disabled' do - let(:capture_secondary_id_enabled) { false } - - context 'with current address matching id' do - let(:current_address_matches_id) { true } - - it { expect(needs_proof_of_address).to eq false } - end - - context 'with current address not matching id' do - let(:current_address_matches_id) { false } - - it { expect(needs_proof_of_address).to eq true } - end - end - - context 'with double address verification enabled' do - let(:capture_secondary_id_enabled) { true } - - context 'with current address matching id' do - let(:current_address_matches_id) { true } - - it { expect(needs_proof_of_address).to eq false } - end - - context 'with current address not matching id' do - let(:current_address_matches_id) { false } - - it { expect(needs_proof_of_address).to eq false } - end - end - end - describe '#sp_name' do subject(:sp_name) { presenter.sp_name } diff --git a/spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb b/spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb index 05f241b5bb5..4b53c3ae6da 100644 --- a/spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb +++ b/spec/presenters/idv/in_person/verification_results_email_presenter_spec.rb @@ -7,7 +7,6 @@ let(:status_updated_at) { described_class::USPS_SERVER_TIMEZONE.parse('2022-07-14T00:00:00Z') } let(:sp) { nil } let(:current_address_matches_id) { true } - let(:capture_secondary_id_enabled) { false } let(:enrollment) do create( :in_person_enrollment, @@ -15,7 +14,6 @@ service_provider: sp, selected_location_details: { name: location_name }, current_address_matches_id: current_address_matches_id, - capture_secondary_id_enabled: capture_secondary_id_enabled, ) end @@ -185,40 +183,4 @@ end end end - - describe '#needs_proof_of_address?' do - subject(:needs_proof_of_address) { presenter.needs_proof_of_address? } - - context 'with double address verification disabled' do - let(:capture_secondary_id_enabled) { false } - - context 'with current address matching id' do - let(:current_address_matches_id) { true } - - it { expect(needs_proof_of_address).to eq false } - end - - context 'with current address not matching id' do - let(:current_address_matches_id) { false } - - it { expect(needs_proof_of_address).to eq true } - end - end - - context 'with double address verification enabled' do - let(:capture_secondary_id_enabled) { true } - - context 'with current address matching id' do - let(:current_address_matches_id) { true } - - it { expect(needs_proof_of_address).to eq false } - end - - context 'with current address not matching id' do - let(:current_address_matches_id) { false } - - it { expect(needs_proof_of_address).to eq false } - end - end - end end diff --git a/spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb b/spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb index 2f73a7e8da2..ffd92ae97c7 100644 --- a/spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb +++ b/spec/presenters/two_factor_auth_code/piv_cac_authentication_presenter_spec.rb @@ -10,19 +10,6 @@ let(:phishing_resistant_required) { true } let(:piv_cac_required) { false } - let(:service_provider_mfa_policy) do - instance_double( - ServiceProviderMfaPolicy, - phishing_resistant_required?: phishing_resistant_required, - piv_cac_required?: piv_cac_required, - ) - end - - before do - allow(presenter).to receive( - :service_provider_mfa_policy, - ).and_return(service_provider_mfa_policy) - end describe '#header' do let(:expected_header) { t('two_factor_authentication.piv_cac_header_text') } diff --git a/spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb b/spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb index c5bc98967cf..48bb1a3b0e1 100644 --- a/spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb +++ b/spec/presenters/two_factor_auth_code/webauthn_authentication_presenter_spec.rb @@ -17,18 +17,6 @@ let(:phishing_resistant_required) { false } let(:platform_authenticator) { false } - let(:multiple_factors_enabled) { false } - let(:service_provider_mfa_policy) do - instance_double( - ServiceProviderMfaPolicy, - phishing_resistant_required?: phishing_resistant_required, - multiple_factors_enabled?: multiple_factors_enabled, - ) - end - - before do - allow(presenter).to receive(:service_provider_mfa_policy).and_return service_provider_mfa_policy - end describe '#webauthn_help' do let(:phishing_resistant_required) { false } @@ -71,22 +59,6 @@ end end - describe '#multiple_factors_enabled?' do - context 'with multiple factors enabled in user policy' do - let(:multiple_factors_enabled) { true } - - it 'returns true' do - expect(presenter.multiple_factors_enabled?).to be_truthy - end - end - - context 'with multiple factors not enabled for user policy' do - it 'returns false' do - expect(presenter.multiple_factors_enabled?).to be_falsey - end - end - end - describe '#header' do context 'with a roaming authenticator' do it 'renders the roaming authenticator header' do diff --git a/spec/requests/csp_spec.rb b/spec/requests/csp_spec.rb index 54e6305809f..5cfd4a927e9 100644 --- a/spec/requests/csp_spec.rb +++ b/spec/requests/csp_spec.rb @@ -26,6 +26,17 @@ ) expect(content_security_policy['style-src']).to eq("'self'") end + + it 'uses logout SP to override CSP form action that will allow a redirect to the CSP' do + visit_password_form_with_sp + visit_logout_form_with_sp + + content_security_policy = parse_content_security_policy + + expect(content_security_policy['form-action']).to eq( + "'self' gov.gsa.openidconnect.test:", + ) + end end context 'on endpoints that will not redirect to an SP' do @@ -78,4 +89,17 @@ def visit_password_form_with_sp headers: { 'Accept' => '*/*' }, ) end + + def visit_logout_form_with_sp + params = { + client_id: 'urn:gov:gsa:openidconnect:test', + post_logout_redirect_uri: 'gov.gsa.openidconnect.test://result/signout', + state: 'a' * 22, + } + + get( + openid_connect_logout_path, + params: params, + ) + end end diff --git a/spec/services/document_capture_session_async_result_spec.rb b/spec/services/document_capture_session_async_result_spec.rb deleted file mode 100644 index 6e82fc0d57e..00000000000 --- a/spec/services/document_capture_session_async_result_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'rails_helper' - -RSpec.describe DocumentCaptureSessionAsyncResult do - let(:id) { SecureRandom.uuid } - let(:status) { DocumentCaptureSessionAsyncResult::IN_PROGRESS } - let(:idv_result) { nil } - - subject do - result = DocumentCaptureSessionAsyncResult.new(id: id, status: status, result: idv_result) - EncryptedRedisStructStorage.store(result) - EncryptedRedisStructStorage.load(id, type: DocumentCaptureSessionAsyncResult) - end - - describe 'success?' do - context 'with incomplete result' do - it 'is false' do - expect(subject.success?).to eq false - end - end - - context 'with complete result' do - let(:status) { DocumentCaptureSessionAsyncResult::DONE } - - context 'with unsuccessful result' do - let(:idv_result) { { success: false, errors: {} } } - - it 'is false' do - expect(subject.success?).to eq false - end - end - - context 'with successful result' do - let(:idv_result) { { success: true, errors: {} } } - - it 'is true' do - expect(subject.success?).to eq true - end - end - end - end - - describe 'attention_with_barcode?' do - it { expect(subject.attention_with_barcode?).to eq false } - - context 'with complete result' do - let(:status) { DocumentCaptureSessionAsyncResult::DONE } - let(:idv_result) { { success: true, attention_with_barcode: false } } - - it { expect(subject.attention_with_barcode?).to eq false } - - context 'with attention with barcode result' do - let(:idv_result) { { success: true, attention_with_barcode: true } } - - it { expect(subject.attention_with_barcode?).to eq true } - end - end - end -end diff --git a/spec/services/gpo_reminder_sender_spec.rb b/spec/services/gpo_reminder_sender_spec.rb index 4d8fbd89d28..4b8f866842d 100644 --- a/spec/services/gpo_reminder_sender_spec.rb +++ b/spec/services/gpo_reminder_sender_spec.rb @@ -54,11 +54,19 @@ def set_gpo_verification_pending_at(user, to_time) user. gpo_verification_pending_profile. update(gpo_verification_pending_at: to_time) + + user. + gpo_verification_pending_profile. + gpo_confirmation_codes.each do |code| + code.update(code_sent_at: to_time, created_at: to_time, updated_at: to_time) + end end def set_reminder_sent_at(to_time) gpo_confirmation_code.update( reminder_sent_at: to_time, + created_at: to_time, + updated_at: to_time, ) end @@ -72,17 +80,22 @@ def set_reminder_sent_at(to_time) context 'when a user has requested two letters' do before do - set_gpo_verification_pending_at(user, time_due_for_reminder - 2.days) - new_confirmation_code = create(:gpo_confirmation_code) + timestamp = time_due_for_reminder - 2.days + set_gpo_verification_pending_at(user, timestamp) + new_confirmation_code = create(:gpo_confirmation_code, created_at: timestamp) user.gpo_verification_pending_profile.gpo_confirmation_codes << new_confirmation_code end include_examples 'sends emails', expected_number_of_emails: 2 - it 'updates the GPO verification code `reminder_sent_at`' do + it 'updates the GPO verification code `reminder_sent_at` for both codes' do subject.send_emails(time_due_for_reminder) + user.gpo_verification_pending_profile.gpo_confirmation_codes.each(&:reload) - expect(gpo_confirmation_code.reminder_sent_at).to be_within(1.second).of(Time.zone.now) + expect(user.gpo_verification_pending_profile.gpo_confirmation_codes[0].reminder_sent_at). + to be_within(1.second).of(Time.zone.now) + expect(user.gpo_verification_pending_profile.gpo_confirmation_codes[1].reminder_sent_at). + to be_within(1.second).of(Time.zone.now) end end @@ -93,6 +106,7 @@ def set_reminder_sent_at(to_time) it 'updates the GPO verification code `reminder_sent_at`' do subject.send_emails(time_due_for_reminder) + gpo_confirmation_code.reload expect(gpo_confirmation_code.reminder_sent_at).to be_within(1.second).of(Time.zone.now) end @@ -106,6 +120,7 @@ def set_reminder_sent_at(to_time) it 'updates the GPO verification code `reminder_sent_at`' do subject.send_emails(time_due_for_reminder) + gpo_confirmation_code.reload expect(gpo_confirmation_code.reminder_sent_at).to be_within(1.second).of(Time.zone.now) end diff --git a/spec/services/idv/steps/in_person/address_step_spec.rb b/spec/services/idv/steps/in_person/address_step_spec.rb index d635d33b526..7a3cf969a1f 100644 --- a/spec/services/idv/steps/in_person/address_step_spec.rb +++ b/spec/services/idv/steps/in_person/address_step_spec.rb @@ -5,8 +5,7 @@ let(:submitted_values) { {} } let(:pii_from_user) { flow.flow_session[:pii_from_user] } let(:params) { ActionController::Parameters.new({ in_person_address: submitted_values }) } - let(:capture_secondary_id_enabled) { false } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } + let(:enrollment) { InPersonEnrollment.new } let(:user) { build(:user) } let(:service_provider) { create(:service_provider) } let(:controller) do @@ -35,10 +34,6 @@ end describe '#call' do - before do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) - end context 'with values submitted' do let(:address1) { '1 FAKE RD' } let(:address2) { 'APT 1B' } @@ -63,67 +58,51 @@ end end - it 'sets values in flow session' do + it 'sets the values in flow session' do step.call + expect(flow.flow_session[:pii_from_user]).to include( address1:, address2:, city:, zipcode:, state:, - same_address_as_id:, ) end - context 'with secondary capture enabled' do - let(:capture_secondary_id_enabled) { true } - - it 'sets the values in flow session' do + context 'when initially entering the residential address' do + it 'leaves the "same_address_as_id" attr as false' do + flow.flow_session[:pii_from_user][:same_address_as_id] = 'false' step.call - expect(flow.flow_session[:pii_from_user]).to include( - address1:, - address2:, - city:, - zipcode:, - state:, - ) + expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') end + end - context 'when initially entering the residential address' do - it 'leaves the "same_address_as_id" attr as false' do - flow.flow_session[:pii_from_user][:same_address_as_id] = 'false' - step.call - - expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') - end + context 'when updating the residential address' do + before(:each) do + flow.flow_session[:pii_from_user][:address1] = '123 New Residential Ave' end - context 'when updating the residential address' do + context 'user previously selected that the residential address matched state ID' do before(:each) do - flow.flow_session[:pii_from_user][:address1] = '123 New Residential Ave' + flow.flow_session[:pii_from_user][:same_address_as_id] = 'true' end - context 'user previously selected that the residential address matched state ID' do - before(:each) do - flow.flow_session[:pii_from_user][:same_address_as_id] = 'true' - end - - it 'infers and sets the "same_address_as_id" in the flow session to false' do - step.call - expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') - end + it 'infers and sets the "same_address_as_id" in the flow session to false' do + step.call + expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') end + end - context 'user previously selected that the residential address did not match state ID' do - before(:each) do - flow.flow_session[:pii_from_user][:same_address_as_id] = 'false' - end + context 'user previously selected that the residential address did not match state ID' do + before(:each) do + flow.flow_session[:pii_from_user][:same_address_as_id] = 'false' + end - it 'leaves the "same_address_as_id" in the flow session as false' do - step.call - expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') - end + it 'leaves the "same_address_as_id" in the flow session as false' do + step.call + expect(flow.flow_session[:pii_from_user][:same_address_as_id]).to eq('false') end end end @@ -131,17 +110,10 @@ end describe '#analytics_submitted_event' do - it 'logs idv_in_person_proofing_address_submitted' do - expect(step.analytics_submitted_event).to be(:idv_in_person_proofing_address_submitted) - end - - context 'with secondary capture enabled' do - let(:capture_secondary_id_enabled) { true } - it 'logs idv_in_person_proofing_residential_address_submitted' do - expect(step.analytics_submitted_event).to be( - :idv_in_person_proofing_residential_address_submitted, - ) - end + it 'logs idv_in_person_proofing_residential_address_submitted' do + expect(step.analytics_submitted_event).to be( + :idv_in_person_proofing_residential_address_submitted, + ) end end @@ -173,20 +145,5 @@ ) end end - - it 'returns capture enabled = false' do - expect(step.extra_view_variables).to include( - capture_secondary_id_enabled: false, - ) - end - - context 'with secondary capture enabled' do - let(:capture_secondary_id_enabled) { true } - it 'returns capture enabled = true' do - expect(step.extra_view_variables).to include( - capture_secondary_id_enabled: true, - ) - end - end end end diff --git a/spec/services/idv/steps/in_person/state_id_step_spec.rb b/spec/services/idv/steps/in_person/state_id_step_spec.rb index c9a279529b1..270a32b6117 100644 --- a/spec/services/idv/steps/in_person/state_id_step_spec.rb +++ b/spec/services/idv/steps/in_person/state_id_step_spec.rb @@ -5,8 +5,7 @@ let(:submitted_values) { {} } let(:params) { ActionController::Parameters.new({ state_id: submitted_values }) } let(:user) { build(:user) } - let(:capture_secondary_id_enabled) { false } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } + let(:enrollment) { InPersonEnrollment.new } let(:service_provider) { create(:service_provider) } let(:controller) do instance_double( @@ -44,8 +43,6 @@ end before do - allow(IdentityConfig.store).to receive(:in_person_capture_secondary_id_enabled). - and_return(false) allow(user).to receive(:establishing_in_person_enrollment). and_return(enrollment) end @@ -84,10 +81,9 @@ end end - context 'when capture_secondary_id_enabled is...' do + context 'when same_address_as_id is...' do let(:pii_from_user) { flow.flow_session[:pii_from_user] } let(:params) { ActionController::Parameters.new({ state_id: submitted_values }) } - let(:capture_secondary_id_enabled) { true } let(:dob) { InPersonHelper::GOOD_DOB } # residential let(:address1) { InPersonHelper::GOOD_ADDRESS1 } @@ -107,8 +103,7 @@ and_return(enrollment) end - context 'enabled, and - same_address_as_id changed from "true" to "false"' do + context 'changed from "true" to "false"' do let(:submitted_values) do { dob:, @@ -125,6 +120,7 @@ identity_doc_zipcode:, } end + it 'marks address step as incomplete, retains identity_doc_ attrs/value but removes addr attr in flow session' do Idv::StateIdForm::ATTRIBUTES.each do |attr| @@ -161,8 +157,7 @@ end end - context 'enabled, and - same_address_as_id changed from "false" to "true"' do + context 'changed from "false" to "true"' do let(:submitted_values) do { dob:, @@ -200,8 +195,7 @@ end end - context 'enabled, and - same_address_as_id does not change from from "false"' do + context 'not changed from "false"' do let(:submitted_values) do { dob:, @@ -252,47 +246,6 @@ expect(pii_from_user[:zipcode]).to_not eq identity_doc_zipcode end end - - context 'not enabled' do - let(:capture_secondary_id_enabled) { false } - let(:submitted_values) do - { - dob:, - address1:, - address2:, - city:, - state:, - zipcode:, - identity_doc_address1:, - identity_doc_address2:, - identity_doc_city:, - identity_doc_address_state:, - identity_doc_zipcode:, - } - end - - it 'retains identity_doc_ attr/values in flow session' do - Idv::StateIdForm::ATTRIBUTES.each do |attr| - expect(flow.flow_session[:pii_from_user]).to_not have_key attr - end - - pii_from_user[:identity_doc_address1] = identity_doc_address1 - pii_from_user[:identity_doc_address2] = identity_doc_address2 - pii_from_user[:identity_doc_city] = identity_doc_city - pii_from_user[:identity_doc_address_state] = identity_doc_address_state - pii_from_user[:identity_doc_zipcode] = identity_doc_zipcode - - step.call - - expect(flow.flow_session[:pii_from_user]).to include( - identity_doc_address1:, - identity_doc_address2:, - identity_doc_city:, - identity_doc_address_state:, - identity_doc_zipcode:, - ) - end - end end end @@ -301,8 +254,7 @@ let(:first_name) { 'First name' } let(:pii_from_user) { flow.flow_session[:pii_from_user] } let(:params) { ActionController::Parameters.new } - let(:capture_secondary_id_enabled) { true } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } + let(:enrollment) { InPersonEnrollment.new } before(:each) do allow(step).to receive(:current_user). @@ -354,30 +306,12 @@ ) end end - - context 'with secondary capture enabled' do - it 'returns capture enabled = true' do - expect(step.extra_view_variables).to include( - capture_secondary_id_enabled: true, - ) - end - end - - context 'with secondary capture disabled' do - let(:capture_secondary_id_enabled) { false } - it 'returns capture enabled = false' do - expect(step.extra_view_variables).to include( - capture_secondary_id_enabled: false, - ) - end - end end describe 'skip address step?' do let(:pii_from_user) { flow.flow_session[:pii_from_user] } let(:params) { ActionController::Parameters.new({ state_id: submitted_values }) } - let(:capture_secondary_id_enabled) { true } - let(:enrollment) { InPersonEnrollment.new(capture_secondary_id_enabled:) } + let(:enrollment) { InPersonEnrollment.new } let(:dob) { '1980-01-01' } let(:identity_doc_address_state) { 'Nevada' } let(:identity_doc_city) { 'Twin Peaks' } @@ -437,19 +371,5 @@ expect(pii_from_user[:zipcode]).to_not eq identity_doc_zipcode end end - - context 'capture secondary id is disabled' do - let(:capture_secondary_id_enabled) { false } - it 'does not add state id values to address values in pii' do - step.call - - pii_from_user = flow.flow_session[:pii_from_user] - expect(pii_from_user[:address1]).to_not eq identity_doc_address1 - expect(pii_from_user[:address2]).to_not eq identity_doc_address2 - expect(pii_from_user[:city]).to_not eq identity_doc_city - expect(pii_from_user[:state]).to_not eq identity_doc_address_state - expect(pii_from_user[:zipcode]).to_not eq identity_doc_zipcode - end - end end end diff --git a/spec/services/proofing/resolution/progressive_proofer_spec.rb b/spec/services/proofing/resolution/progressive_proofer_spec.rb index 58e9624c7e1..374292918b8 100644 --- a/spec/services/proofing/resolution/progressive_proofer_spec.rb +++ b/spec/services/proofing/resolution/progressive_proofer_spec.rb @@ -3,7 +3,7 @@ RSpec.describe Proofing::Resolution::ProgressiveProofer do let(:applicant_pii) { Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS } let(:should_proof_state_id) { true } - let(:double_address_verification) { false } + let(:double_address_verification) { true } let(:request_ip) { Faker::Internet.ip_v4_address } let(:threatmetrix_session_id) { SecureRandom.uuid } let(:timer) { JobHelpers::Timer.new } @@ -55,57 +55,33 @@ expect(proofing_result.same_address_as_id).to eq(applicant_pii[:same_address_as_id]) end - context 'when double address verification is enabled' do - let(:double_address_verification) { true } - let(:resolution_result) do - instance_double(Proofing::Resolution::Result) + let(:resolution_result) do + instance_double(Proofing::Resolution::Result) + end + context 'ThreatMetrix is enabled' do + let(:threatmetrix_proofer) { instance_double(Proofing::LexisNexis::Ddp::Proofer) } + + before do + allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?). + and_return(true) + allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_mock_enabled). + and_return(false) + allow(instance).to receive(:lexisnexis_ddp_proofer).and_return(threatmetrix_proofer) + + allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). + and_return(resolution_result) + allow(resolution_result).to receive(:success?).and_return(true) + allow(instant_verify_proofer).to receive(:proof) end - context 'ThreatMetrix is enabled' do - let(:threatmetrix_proofer) { instance_double(Proofing::LexisNexis::Ddp::Proofer) } - - before do - allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?). - and_return(true) - allow(IdentityConfig.store).to receive(:lexisnexis_threatmetrix_mock_enabled). - and_return(false) - allow(instance).to receive(:lexisnexis_ddp_proofer).and_return(threatmetrix_proofer) - - allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). - and_return(resolution_result) - allow(resolution_result).to receive(:success?).and_return(true) - allow(instant_verify_proofer).to receive(:proof) - end - - it 'makes a request to the ThreatMetrix proofer' do - expect(threatmetrix_proofer).to receive(:proof) - subject - end - - context 'it lacks a session id' do - let(:threatmetrix_session_id) { nil } - it 'returns a disabled result' do - result = subject + it 'makes a request to the ThreatMetrix proofer' do + expect(threatmetrix_proofer).to receive(:proof) - device_profiling_result = result.device_profiling_result - - expect(device_profiling_result.success).to be(true) - expect(device_profiling_result.client).to eq('tmx_disabled') - expect(device_profiling_result.review_status).to eq('pass') - end - end + subject end - context 'ThreatMetrix is disabled' do - before do - allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?). - and_return(false) - - allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). - and_return(resolution_result) - allow(resolution_result).to receive(:success?).and_return(true) - allow(instant_verify_proofer).to receive(:proof) - end + context 'it lacks a session id' do + let(:threatmetrix_session_id) { nil } it 'returns a disabled result' do result = subject @@ -116,155 +92,177 @@ expect(device_profiling_result.review_status).to eq('pass') end end + end - context 'residential address and id address are the same' do - let(:applicant_pii) { Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID } - let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } - let(:residential_instant_verify_proof) do + context 'ThreatMetrix is disabled' do + before do + allow(FeatureManagement).to receive(:proofing_device_profiling_collecting_enabled?). + and_return(false) + + allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). + and_return(resolution_result) + allow(resolution_result).to receive(:success?).and_return(true) + allow(instant_verify_proofer).to receive(:proof) + end + it 'returns a disabled result' do + result = subject + + device_profiling_result = result.device_profiling_result + + expect(device_profiling_result.success).to be(true) + expect(device_profiling_result.client).to eq('tmx_disabled') + expect(device_profiling_result.review_status).to eq('pass') + end + end + + context 'residential address and id address are the same' do + let(:applicant_pii) { Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID } + let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } + let(:residential_instant_verify_proof) do + instance_double(Proofing::Resolution::Result) + end + before do + allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) + allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) + allow(instant_verify_proofer).to receive(:proof). + and_return(residential_instant_verify_proof) + allow(residential_instant_verify_proof).to receive(:success?).and_return(true) + end + + it 'only makes one request to LexisNexis InstantVerify' do + expect(instant_verify_proofer).to receive(:proof).exactly(:once) + expect(aamva_proofer).to receive(:proof) + + subject + end + + it 'produces a result adjudicator with correct information' do + expect(aamva_proofer).to receive(:proof) + + result = subject + + expect(result.same_address_as_id).to eq('true') + expect(result.double_address_verification).to eq(true) + expect(result.resolution_result).to eq(result.residential_resolution_result) + end + + context 'LexisNexis InstantVerify fails' do + let(:result_that_failed_instant_verify) do instance_double(Proofing::Resolution::Result) end before do - allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) - allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) - allow(instant_verify_proofer).to receive(:proof). - and_return(residential_instant_verify_proof) - allow(residential_instant_verify_proof).to receive(:success?).and_return(true) + allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). + and_return(result_that_failed_instant_verify) + allow(instant_verify_proofer).to receive(:proof).with(hash_including(state_id_address)). + and_return(result_that_failed_instant_verify) + allow(instance).to receive(:user_can_pass_after_state_id_check?). + with(result_that_failed_instant_verify). + and_return(true) + allow(result_that_failed_instant_verify).to receive(:success?). + and_return(false) end - it 'only makes one request to LexisNexis InstantVerify' do - expect(instant_verify_proofer).to receive(:proof).exactly(:once) - expect(aamva_proofer).to receive(:proof) + context 'the failure can be covered by AAMVA' do + before do + allow(result_that_failed_instant_verify). + to receive(:attributes_requiring_additional_verification). + and_return([:address]) + end - subject - end + context 'it is not covered by AAMVA' do + let(:failed_aamva_proof) { instance_double(Proofing::StateIdResult) } + before do + allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) + allow(failed_aamva_proof).to receive(:verified_attributes).and_return([]) + allow(failed_aamva_proof).to receive(:success?).and_return(false) + end + it 'indicates the aamva check did not pass' do + result = subject - it 'produces a result adjudicator with correct information' do - expect(aamva_proofer).to receive(:proof) + expect(result.state_id_result.success?).to eq(false) + end + end - result = subject + context 'it is covered by AAMVA' do + let(:successful_aamva_proof) { instance_double(Proofing::StateIdResult) } + before do + allow(aamva_proofer).to receive(:proof).and_return(successful_aamva_proof) + allow(successful_aamva_proof).to receive(:verified_attributes). + and_return([:address]) + allow(successful_aamva_proof).to receive(:success?).and_return(true) + end + it 'indicates aamva did pass' do + result = subject - expect(result.same_address_as_id).to eq('true') - expect(result.double_address_verification).to eq(true) - expect(result.resolution_result).to eq(result.residential_resolution_result) + expect(result.state_id_result.success?).to eq(true) + end + end end + end - context 'LexisNexis InstantVerify fails' do - let(:result_that_failed_instant_verify) do + context 'LexisNexis InstantVerify passes for residential address and id address' do + context 'should proof with AAMVA' do + let(:id_resolution_that_passed_instant_verify) do instance_double(Proofing::Resolution::Result) end + let(:residential_resolution_that_passed_instant_verify) do + instance_double(Proofing::Resolution::Result) + end + before do + allow(instance).to receive(:proof_residential_address_if_needed). + and_return(residential_resolution_that_passed_instant_verify) allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). - and_return(result_that_failed_instant_verify) - allow(instant_verify_proofer).to receive(:proof).with(hash_including(state_id_address)). - and_return(result_that_failed_instant_verify) + and_return(id_resolution_that_passed_instant_verify) + allow(instant_verify_proofer).to receive(:proof). + with(hash_including(state_id_address)). + and_return(id_resolution_that_passed_instant_verify) allow(instance).to receive(:user_can_pass_after_state_id_check?). - with(result_that_failed_instant_verify). + with(id_resolution_that_passed_instant_verify). + and_return(true) + allow(id_resolution_that_passed_instant_verify).to receive(:success?). + and_return(true) + allow(residential_resolution_that_passed_instant_verify).to receive(:success?). and_return(true) - allow(result_that_failed_instant_verify).to receive(:success?). - and_return(false) end - context 'the failure can be covered by AAMVA' do - before do - allow(result_that_failed_instant_verify). - to receive(:attributes_requiring_additional_verification). - and_return([:address]) - end - - context 'it is not covered by AAMVA' do - let(:failed_aamva_proof) { instance_double(Proofing::StateIdResult) } - before do - allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) - allow(failed_aamva_proof).to receive(:verified_attributes).and_return([]) - allow(failed_aamva_proof).to receive(:success?).and_return(false) - end - it 'indicates the aamva check did not pass' do - result = subject - - expect(result.state_id_result.success?).to eq(false) - end - end + it 'makes a request to the AAMVA proofer' do + expect(aamva_proofer).to receive(:proof) - context 'it is covered by AAMVA' do - let(:successful_aamva_proof) { instance_double(Proofing::StateIdResult) } - before do - allow(aamva_proofer).to receive(:proof).and_return(successful_aamva_proof) - allow(successful_aamva_proof).to receive(:verified_attributes). - and_return([:address]) - allow(successful_aamva_proof).to receive(:success?).and_return(true) - end - it 'indicates aamva did pass' do - result = subject - - expect(result.state_id_result.success?).to eq(true) - end - end + subject end - end - context 'LexisNexis InstantVerify passes for residential address and id address' do - context 'should proof with AAMVA' do - let(:id_resolution_that_passed_instant_verify) do - instance_double(Proofing::Resolution::Result) - end - let(:residential_resolution_that_passed_instant_verify) do - instance_double(Proofing::Resolution::Result) + context 'AAMVA proofing fails' do + let(:aamva_client) { instance_double(Proofing::Aamva::VerificationClient) } + let(:failed_aamva_proof) do + instance_double(Proofing::StateIdResult) end - before do - allow(instance).to receive(:proof_residential_address_if_needed). - and_return(residential_resolution_that_passed_instant_verify) - allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). - and_return(id_resolution_that_passed_instant_verify) - allow(instant_verify_proofer).to receive(:proof). - with(hash_including(state_id_address)). - and_return(id_resolution_that_passed_instant_verify) - allow(instance).to receive(:user_can_pass_after_state_id_check?). - with(id_resolution_that_passed_instant_verify). - and_return(true) - allow(id_resolution_that_passed_instant_verify).to receive(:success?). - and_return(true) - allow(residential_resolution_that_passed_instant_verify).to receive(:success?). - and_return(true) + allow(Proofing::Aamva::VerificationClient).to receive(:new).and_return(aamva_client) + allow(failed_aamva_proof).to receive(:success?).and_return(false) end + it 'returns a result adjudicator that indicates the aamva proofing failed' do + allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) - it 'makes a request to the AAMVA proofer' do - expect(aamva_proofer).to receive(:proof) - - subject - end + result = subject - context 'AAMVA proofing fails' do - let(:aamva_client) { instance_double(Proofing::Aamva::VerificationClient) } - let(:failed_aamva_proof) do - instance_double(Proofing::StateIdResult) - end - before do - allow(Proofing::Aamva::VerificationClient).to receive(:new).and_return(aamva_client) - allow(failed_aamva_proof).to receive(:success?).and_return(false) - end - it 'returns a result adjudicator that indicates the aamva proofing failed' do - allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) - - result = subject - - expect(result.state_id_result.success?).to eq(false) - end + expect(result.state_id_result.success?).to eq(false) end end end end + end - context 'residential address and id address are different' do - let(:residential_address_proof) do - instance_double(Proofing::Resolution::Result) - end - let(:resolution_result) do - instance_double(Proofing::Resolution::Result) - end - let(:double_address_verification) { true } - let(:applicant_pii) do - JSON.parse(<<-STR, symbolize_names: true) + context 'residential address and id address are different' do + let(:residential_address_proof) do + instance_double(Proofing::Resolution::Result) + end + let(:resolution_result) do + instance_double(Proofing::Resolution::Result) + end + let(:double_address_verification) { true } + let(:applicant_pii) do + JSON.parse(<<-STR, symbolize_names: true) { "uuid": "3e8db152-4d35-4207-b828-3eee8c52c50f", "middle_name": "", @@ -291,164 +289,130 @@ "state_id_type": "drivers_license", "uuid_prefix": null } - STR - end - let(:residential_address) do - { - address1: applicant_pii[:address1], - address2: applicant_pii[:address2], - city: applicant_pii[:city], - state: applicant_pii[:state], - state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], - zipcode: applicant_pii[:zipcode], - } - end - let(:state_id_address) do - { - address1: applicant_pii[:identity_doc_address1], - address2: applicant_pii[:identity_doc_address2], - city: applicant_pii[:identity_doc_city], - state: applicant_pii[:identity_doc_address_state], - state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], - zipcode: applicant_pii[:identity_doc_zipcode], - } - end - - context 'LexisNexis InstantVerify passes for residential address' do - before do - allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) - allow(instant_verify_proofer).to receive(:proof).and_return(residential_address_proof) - allow(residential_address_proof).to receive(:success?).and_return(true) - end - context 'LexisNexis InstantVerify passes for id address' do - it 'makes two requests to the InstantVerify Proofer' do - expect(instant_verify_proofer).to receive(:proof). - with(hash_including(residential_address)). - ordered - expect(instant_verify_proofer).to receive(:proof). - with(hash_including(state_id_address)). - ordered - - subject - end + STR + end + let(:residential_address) do + { + address1: applicant_pii[:address1], + address2: applicant_pii[:address2], + city: applicant_pii[:city], + state: applicant_pii[:state], + state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], + zipcode: applicant_pii[:zipcode], + } + end + let(:state_id_address) do + { + address1: applicant_pii[:identity_doc_address1], + address2: applicant_pii[:identity_doc_address2], + city: applicant_pii[:identity_doc_city], + state: applicant_pii[:identity_doc_address_state], + state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], + zipcode: applicant_pii[:identity_doc_zipcode], + } + end - context 'AAMVA fails' do - let(:failed_aamva_proof) { instance_double(Proofing::StateIdResult) } - let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } - before do - allow(instance).to receive(:proof_id_with_aamva_if_needed). - and_return(failed_aamva_proof) - allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) - allow(failed_aamva_proof).to receive(:success?).and_return(false) - allow(resolution_result).to receive(:errors) - end - - it 'returns the correct resolution results' do - result_adjudicator = subject - - expect(result_adjudicator.residential_resolution_result.success?).to be(true) - expect(result_adjudicator.resolution_result.success?).to be(true) - expect(result_adjudicator.state_id_result.success?).to be(false) - end - end - end + context 'LexisNexis InstantVerify passes for residential address' do + before do + allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) + allow(instant_verify_proofer).to receive(:proof).and_return(residential_address_proof) + allow(residential_address_proof).to receive(:success?).and_return(true) end - context 'LexisNexis InstantVerify fails for residential address' do - let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } - - before do - allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) - allow(instance).to receive(:proof_residential_address_if_needed). - and_return(residential_address_proof) - allow(instant_verify_proofer).to receive(:proof). + context 'LexisNexis InstantVerify passes for id address' do + it 'makes two requests to the InstantVerify Proofer' do + expect(instant_verify_proofer).to receive(:proof). with(hash_including(residential_address)). - and_return(residential_address_proof) - allow(instance).to receive(:user_can_pass_after_state_id_check?). - with(residential_address_proof). - and_return(false) - allow(residential_address_proof).to receive(:success?). - and_return(false) - end - - it 'does not make unnecessary calls' do - expect(aamva_proofer).to_not receive(:proof) - expect(instant_verify_proofer).to_not receive(:proof). - with(hash_including(state_id_address)) + ordered + expect(instant_verify_proofer).to receive(:proof). + with(hash_including(state_id_address)). + ordered subject end - end - - context 'LexisNexis InstantVerify fails for id address & passes for residential address' do - let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } - let(:result_that_failed_instant_verify) do - instance_double(Proofing::Resolution::Result) - end - - before do - allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) - allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). - and_return(result_that_failed_instant_verify) - allow(instant_verify_proofer).to receive(:proof).with(hash_including(state_id_address)). - and_return(result_that_failed_instant_verify) - end - context 'the failure can be covered by AAMVA' do + context 'AAMVA fails' do let(:failed_aamva_proof) { instance_double(Proofing::StateIdResult) } let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } before do - allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) - allow(instant_verify_proofer).to receive(:proof).and_return(residential_address_proof) - allow(residential_address_proof).to receive(:success?).and_return(true) - - allow(instance).to receive(:user_can_pass_after_state_id_check?). - with(result_that_failed_instant_verify). - and_return(true) - allow(result_that_failed_instant_verify). - to receive(:attributes_requiring_additional_verification). - and_return([:address]) - allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) + allow(instance).to receive(:proof_id_with_aamva_if_needed). + and_return(failed_aamva_proof) + allow(aamva_proofer).to receive(:proof).and_return(failed_aamva_proof) + allow(failed_aamva_proof).to receive(:success?).and_return(false) + allow(resolution_result).to receive(:errors) end - it 'calls AAMVA' do - expect(aamva_proofer).to receive(:proof) - subject + it 'returns the correct resolution results' do + result_adjudicator = subject + + expect(result_adjudicator.residential_resolution_result.success?).to be(true) + expect(result_adjudicator.resolution_result.success?).to be(true) + expect(result_adjudicator.state_id_result.success?).to be(false) end end end end - end + context 'LexisNexis InstantVerify fails for residential address' do + let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } - context 'when double address verification is not enabled' do - let(:double_address_verification) { false } - let(:applicant_pii) do - # test ensures same_address_as_id value has no effect - Idp::Constants::MOCK_IDV_APPLICANT.merge(same_address_as_id: 'true') - end - let(:residential_instant_verify_proof) do - instance_double(Proofing::Resolution::Result) + before do + allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) + allow(instance).to receive(:proof_residential_address_if_needed). + and_return(residential_address_proof) + allow(instant_verify_proofer).to receive(:proof). + with(hash_including(residential_address)). + and_return(residential_address_proof) + allow(instance).to receive(:user_can_pass_after_state_id_check?). + with(residential_address_proof). + and_return(false) + allow(residential_address_proof).to receive(:success?). + and_return(false) + end + + it 'does not make unnecessary calls' do + expect(aamva_proofer).to_not receive(:proof) + expect(instant_verify_proofer).to_not receive(:proof). + with(hash_including(state_id_address)) + + subject + end end - it 'makes one request to LexisNexis InstantVerify' do - allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) - allow(instant_verify_proofer).to receive(:proof). - and_return(residential_instant_verify_proof) - allow(residential_instant_verify_proof).to receive(:success?).and_return(true) + context 'LexisNexis InstantVerify fails for id address & passes for residential address' do + let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } + let(:result_that_failed_instant_verify) do + instance_double(Proofing::Resolution::Result) + end - expect(instant_verify_proofer).to receive(:proof).exactly(:once) + before do + allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) + allow(instance).to receive(:proof_id_address_with_lexis_nexis_if_needed). + and_return(result_that_failed_instant_verify) + allow(instant_verify_proofer).to receive(:proof).with(hash_including(state_id_address)). + and_return(result_that_failed_instant_verify) + end - subject - end + context 'the failure can be covered by AAMVA' do + let(:failed_aamva_proof) { instance_double(Proofing::StateIdResult) } + let(:aamva_proofer) { instance_double(Proofing::Aamva::Proofer) } + before do + allow(instance).to receive(:resolution_proofer).and_return(instant_verify_proofer) + allow(instant_verify_proofer).to receive(:proof).and_return(residential_address_proof) + allow(residential_address_proof).to receive(:success?).and_return(true) - it 'returns distinct objects for the resolution result and residential resolution result' do - result = subject + allow(instance).to receive(:user_can_pass_after_state_id_check?). + with(result_that_failed_instant_verify). + and_return(true) + allow(result_that_failed_instant_verify). + to receive(:attributes_requiring_additional_verification). + and_return([:address]) + allow(instance).to receive(:state_id_proofer).and_return(aamva_proofer) + end + it 'calls AAMVA' do + expect(aamva_proofer).to receive(:proof) - expect(result.residential_resolution_result).to_not eq(result.resolution_result) - expect( - result.residential_resolution_result. - vendor_name, - ).to eq('ResidentialAddressNotRequired') - expect(result.resolution_result.vendor_name).to eq('lexisnexis:instant_verify') + subject + end + end end end end diff --git a/spec/services/proofing/resolution/result_adjudicator_spec.rb b/spec/services/proofing/resolution/result_adjudicator_spec.rb index f517f735617..b3bfd220133 100644 --- a/spec/services/proofing/resolution/result_adjudicator_spec.rb +++ b/spec/services/proofing/resolution/result_adjudicator_spec.rb @@ -29,8 +29,8 @@ end let(:should_proof_state_id) { true } - let(:double_address_verification) { false } - let(:same_address_as_id) { 'true' } + let(:double_address_verification) { true } + let(:same_address_as_id) { 'false' } let(:device_profiling_success) { true } let(:device_profiling_exception) { nil } @@ -57,130 +57,38 @@ end describe '#adjudicated_result' do - context 'double address verification is disabled' do - context 'AAMVA and LexisNexis both pass' do - it 'returns a successful response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(true) - end - end - context 'LexisNexis fails with attributes covered by AAMVA response' do + context 'residential address and id address are different' do + context 'LexisNexis fails for the residential address' do let(:resolution_success) { false } - let(:can_pass_with_additional_verification) { true } - let(:attributes_requiring_additional_verification) { [:dob] } - let(:state_id_verified_attributes) { [:dob, :address] } - - it 'returns a successful response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(true) + let(:residential_resolution_result) do + Proofing::Resolution::Result.new( + success: resolution_success, + errors: {}, + exception: nil, + vendor_name: 'test-resolution-vendor', + failed_result_can_pass_with_additional_verification: + can_pass_with_additional_verification, + attributes_requiring_additional_verification: + attributes_requiring_additional_verification, + ) end - end - - context 'LexisNexis fails with attributes not covered by AAMVA response' do - let(:resolution_success) { false } - let(:can_pass_with_additional_verification) { true } - let(:attributes_requiring_additional_verification) { [:address] } - let(:state_id_verified_attributes) { [:dob] } - it 'returns a failed response' do result = subject.adjudicated_result expect(result.success?).to eq(false) + resolution_adjudication_reason = result.extra[:context][:resolution_adjudication_reason] + expect(resolution_adjudication_reason).to eq(:fail_resolution_skip_state_id) end end - context 'LexisNexis fails and AAMVA state is unsupported' do - let(:should_proof_state_id) { false } - let(:resolution_success) { false } - - it 'returns a failed response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(false) - end - end - - context 'LexisNexis passes and AAMVA fails' do - let(:resolution_success) { true } + context 'AAMVA fails for the id address' do let(:state_id_success) { false } - it 'returns a failed response' do result = subject.adjudicated_result expect(result.success?).to eq(false) - end - end - - context 'Device profiling fails and everything else passes' do - let(:device_profiling_success) { false } - let(:device_profiling_review_status) { 'fail' } - - it 'returns a successful response including the review status' do - result = subject.adjudicated_result - - expect(result.success?).to eq(true) - - threatmetrix_context = result.extra[:context][:stages][:threatmetrix] - expect(threatmetrix_context[:success]).to eq(false) - expect(threatmetrix_context[:review_status]).to eq('fail') - end - end - - context 'Device profiling experiences an exception' do - let(:device_profiling_success) { false } - let(:device_profiling_exception) { 'this is a test value' } - - it 'returns a failed response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(false) - - threatmetrix_context = result.extra[:context][:stages][:threatmetrix] - expect(threatmetrix_context[:success]).to eq(false) - expect(threatmetrix_context[:exception]).to eq('this is a test value') - end - end - end - - context 'double address verification is enabled' do - let(:double_address_verification) { true } - let(:should_proof_state_id) { true } - context 'residential address and id address are different' do - let(:same_address_as_id) { 'false' } - context 'LexisNexis fails for the residential address' do - let(:resolution_success) { false } - let(:residential_resolution_result) do - Proofing::Resolution::Result.new( - success: resolution_success, - errors: {}, - exception: nil, - vendor_name: 'test-resolution-vendor', - failed_result_can_pass_with_additional_verification: - can_pass_with_additional_verification, - attributes_requiring_additional_verification: - attributes_requiring_additional_verification, - ) - end - it 'returns a failed response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(false) - resolution_adjudication_reason = result.extra[:context][:resolution_adjudication_reason] - expect(resolution_adjudication_reason).to eq(:fail_resolution_skip_state_id) - end - end - - context 'AAMVA fails for the id address' do - let(:state_id_success) { false } - it 'returns a failed response' do - result = subject.adjudicated_result - - expect(result.success?).to eq(false) - resolution_adjudication_reason = result.extra[:context][:resolution_adjudication_reason] - expect(resolution_adjudication_reason).to eq(:fail_state_id) - end + resolution_adjudication_reason = result.extra[:context][:resolution_adjudication_reason] + expect(resolution_adjudication_reason).to eq(:fail_state_id) end end end diff --git a/spec/services/reporting/account_deletion_rate_report_spec.rb b/spec/services/reporting/account_deletion_rate_report_spec.rb new file mode 100644 index 00000000000..82952ddab9b --- /dev/null +++ b/spec/services/reporting/account_deletion_rate_report_spec.rb @@ -0,0 +1,41 @@ +require 'rails_helper' + +RSpec.describe Reporting::AccountDeletionRateReport do + let(:report_date) { Date.new(2021, 3, 1) } + + subject(:report) { Reporting::AccountDeletionRateReport.new(report_date) } + + before do + travel_to report_date + end + + describe '#account_deletion_report' do + before do + travel_to(report_date - 2.months) do + create_and_delete_accounts + end + travel_to(report_date - 1.month) do + create_and_delete_accounts + end + travel_to(report_date - 1.week) do + create_and_delete_accounts + end + end + + it 'returns a report for account deletion rate (last 30 days)' do + account_deletion_table = report.account_deletion_report + expected_table = [['Deleted Users', 'Total Users', 'Deletion Rate'], [2, 8, 0.25]] + + expect(account_deletion_table).to eq(expected_table) + end + end + + def create_and_delete_accounts + create(:user, :proofed) + create_list(:user, 2) + + user = create(:user) + DeletedUser.create_from_user(user) + user.destroy! + 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 449e313ede8..c822c491bad 100644 --- a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb +++ b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb @@ -8,7 +8,7 @@ let(:current_address_matches_id) { false } let(:pii) do Pii::Attributes.new_from_hash( - Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE. + Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID_WITH_PHONE. merge(same_address_as_id: current_address_matches_id ? 'true' : 'false'). transform_keys(&:to_s), ) @@ -18,7 +18,6 @@ let(:transliterator) { UspsInPersonProofing::Transliterator.new } let(:service_provider) { nil } let(:usps_ipp_transliteration_enabled) { true } - let(:in_person_capture_secondary_id_enabled) { false } let(:usps_ipp_enrollment_status_update_email_address) do 'registration@usps.local.identitysandbox.gov' end @@ -38,8 +37,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(:in_person_capture_secondary_id_enabled). - and_return(in_person_capture_secondary_id_enabled) end describe '#schedule_in_person_enrollment' do @@ -102,7 +99,7 @@ subject.schedule_in_person_enrollment(user, pii) end - describe 'double address verification' do + context 'same address as id is false' do let(:pii) do Pii::Attributes.new_from_hash( Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE. @@ -112,46 +109,24 @@ ) end - context 'feature enabled' do - let(:in_person_capture_secondary_id_enabled) { true } - - it 'maps enrollment address fields' do - expect(proofer).to receive(:request_enroll) do |applicant| - ADDR = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS - expect(applicant).to have_attributes( - address: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[ - :identity_doc_address1 - ], - city: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_city], - state: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[ - :identity_doc_address_state - ], - zip_code: - Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_zipcode], - ) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) - end - - subject.schedule_in_person_enrollment(user, pii) + it 'maps enrollment address fields' do + expect(proofer).to receive(:request_enroll) do |applicant| + ADDR = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS + expect(applicant).to have_attributes( + address: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[ + :identity_doc_address1 + ], + city: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_city], + state: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[ + :identity_doc_address_state + ], + zip_code: + Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_zipcode], + ) + UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) end - end - - context 'feature disabled' do - let(:in_person_capture_secondary_id_enabled) { false } - - it 'does not map enrollment address fields' do - expect(proofer).to receive(:request_enroll) do |applicant| - expect(applicant).to have_attributes( - address: Idp::Constants::MOCK_IDV_APPLICANT[:address1], - city: Idp::Constants::MOCK_IDV_APPLICANT[:city], - state: Idp::Constants::MOCK_IDV_APPLICANT[:state], - zip_code: Idp::Constants::MOCK_IDV_APPLICANT[:zipcode], - ) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) - end - subject.schedule_in_person_enrollment(user, pii) - end + subject.schedule_in_person_enrollment(user, pii) end end end @@ -247,29 +222,33 @@ context 'with address line 2 present' do before { pii['address2'] = 'Apartment 227' } - it 'logs the presence of address line 2' do + # this is a pii bundle that adds identity_doc_* values + let(:pii) do + Pii::Attributes.new_from_hash( + Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS.transform_keys(&:to_s), + ) + end + + it 'does not log the presence of address line 2 only in residential address' do + pii['identity_doc_address2'] = nil + subject.schedule_in_person_enrollment(user, pii) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', enrollment_code: user.in_person_enrollments.first.enrollment_code, enrollment_id: user.in_person_enrollments.first.id, - second_address_line_present: true, + second_address_line_present: false, service_provider: nil, ) end - context 'double address verification active' do - let(:in_person_capture_secondary_id_enabled) { true } - # this is a pii bundle that adds identity_doc_* values - let(:pii) do - Pii::Attributes.new_from_hash( - Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS.transform_keys(&:to_s), - ) - end + context 'with address line 2 present in state ID address' do + it 'logs the presence of address line 2' do + expect(pii['identity_doc_address2'].present?).to eq(true) - it 'does not log the presence of address line 2 only in residential address' do - pii['identity_doc_address2'] = nil + pii['same_address_as_id'] = false + pii['address2'] = nil subject.schedule_in_person_enrollment(user, pii) @@ -277,29 +256,10 @@ 'USPS IPPaaS enrollment created', enrollment_code: user.in_person_enrollments.first.enrollment_code, enrollment_id: user.in_person_enrollments.first.id, - second_address_line_present: false, + second_address_line_present: true, service_provider: nil, ) end - - context 'with address line 2 present in state ID address' do - it 'logs the presence of address line 2' do - expect(pii['identity_doc_address2'].present?).to eq(true) - - pii['same_address_as_id'] = false - pii['address2'] = nil - - subject.schedule_in_person_enrollment(user, pii) - - expect(subject_analytics).to have_logged_event( - 'USPS IPPaaS enrollment created', - enrollment_code: user.in_person_enrollments.first.enrollment_code, - enrollment_id: user.in_person_enrollments.first.id, - second_address_line_present: true, - service_provider: nil, - ) - end - end end end end diff --git a/spec/support/features/idv_step_helper.rb b/spec/support/features/idv_step_helper.rb index 86b3b700e40..f6150c1ba6d 100644 --- a/spec/support/features/idv_step_helper.rb +++ b/spec/support/features/idv_step_helper.rb @@ -134,7 +134,7 @@ def complete_idv_steps_before_ssn(user = user_with_2fa) # location page complete_location_step(user) # state ID page - fill_out_state_id_form_ok(same_address_as_id: true, capture_secondary_id_enabled: true) + fill_out_state_id_form_ok(same_address_as_id: true) click_idv_continue end diff --git a/spec/support/features/in_person_helper.rb b/spec/support/features/in_person_helper.rb index 8f856af732e..9ae6de8b41e 100644 --- a/spec/support/features/in_person_helper.rb +++ b/spec/support/features/in_person_helper.rb @@ -31,7 +31,7 @@ module InPersonHelper GOOD_IDENTITY_DOC_ZIPCODE = Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_zipcode] - def fill_out_state_id_form_ok(same_address_as_id: false, capture_secondary_id_enabled: false) + def fill_out_state_id_form_ok(same_address_as_id: false) fill_in t('in_person_proofing.form.state_id.first_name'), with: GOOD_FIRST_NAME fill_in t('in_person_proofing.form.state_id.last_name'), with: GOOD_LAST_NAME year, month, day = GOOD_DOB.split('-') @@ -42,40 +42,32 @@ def fill_out_state_id_form_ok(same_address_as_id: false, capture_secondary_id_en from: t('in_person_proofing.form.state_id.state_id_jurisdiction') fill_in t('in_person_proofing.form.state_id.state_id_number'), with: GOOD_STATE_ID_NUMBER - if capture_secondary_id_enabled - fill_in t('in_person_proofing.form.state_id.address1'), with: GOOD_IDENTITY_DOC_ADDRESS1 - fill_in t('in_person_proofing.form.state_id.address2'), with: GOOD_IDENTITY_DOC_ADDRESS2 - fill_in t('in_person_proofing.form.state_id.city'), with: GOOD_IDENTITY_DOC_CITY - fill_in t('in_person_proofing.form.state_id.zipcode'), with: GOOD_IDENTITY_DOC_ZIPCODE - if same_address_as_id - select GOOD_IDENTITY_DOC_ADDRESS_STATE, - from: t('in_person_proofing.form.state_id.identity_doc_address_state') - choose t('in_person_proofing.form.state_id.same_address_as_id_yes') - else - select GOOD_STATE, from: t('in_person_proofing.form.state_id.identity_doc_address_state') - choose t('in_person_proofing.form.state_id.same_address_as_id_no') - end + fill_in t('in_person_proofing.form.state_id.address1'), with: GOOD_IDENTITY_DOC_ADDRESS1 + fill_in t('in_person_proofing.form.state_id.address2'), with: GOOD_IDENTITY_DOC_ADDRESS2 + fill_in t('in_person_proofing.form.state_id.city'), with: GOOD_IDENTITY_DOC_CITY + fill_in t('in_person_proofing.form.state_id.zipcode'), with: GOOD_IDENTITY_DOC_ZIPCODE + select GOOD_STATE_ID_JURISDICTION, + from: t('in_person_proofing.form.state_id.identity_doc_address_state') + if same_address_as_id + choose t('in_person_proofing.form.state_id.same_address_as_id_yes') + else + choose t('in_person_proofing.form.state_id.same_address_as_id_no') end end - def fill_out_address_form_ok(double_address_verification: false, same_address_as_id: false) + def fill_out_address_form_ok(same_address_as_id: false) fill_in t('idv.form.address1'), with: same_address_as_id ? GOOD_IDENTITY_DOC_ADDRESS1 : GOOD_ADDRESS1 - fill_in t('idv.form.address2_optional'), with: GOOD_ADDRESS2 unless double_address_verification fill_in t('idv.form.address2'), with: same_address_as_id ? GOOD_IDENTITY_DOC_ADDRESS2 : GOOD_ADDRESS2 fill_in t('idv.form.city'), with: same_address_as_id ? GOOD_IDENTITY_DOC_CITY : GOOD_CITY fill_in t('idv.form.zipcode'), with: same_address_as_id ? GOOD_IDENTITY_DOC_ZIPCODE : GOOD_ZIPCODE if same_address_as_id - select GOOD_IDENTITY_DOC_ADDRESS_STATE, from: t('idv.form.state') + select GOOD_STATE_ID_JURISDICTION, from: t('idv.form.state') else select GOOD_STATE, from: t('idv.form.state') end - - unless double_address_verification - choose t('in_person_proofing.form.address.same_address_choice_yes') - end end def begin_in_person_proofing(_user = nil) @@ -122,23 +114,19 @@ def complete_prepare_step(_user = nil) click_on t('forms.buttons.continue') end - def complete_state_id_step(_user = nil, same_address_as_id: true, - capture_secondary_id_enabled: false) + def complete_state_id_step(_user = nil, same_address_as_id: true) # Wait for page to load before attempting to fill out form expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - fill_out_state_id_form_ok( - same_address_as_id: same_address_as_id, - capture_secondary_id_enabled: capture_secondary_id_enabled, - ) + fill_out_state_id_form_ok(same_address_as_id: same_address_as_id) click_idv_continue - unless capture_secondary_id_enabled && same_address_as_id + unless same_address_as_id expect(page).to have_current_path(idv_in_person_step_path(step: :address), wait: 10) expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.verify_info')) end end - def complete_address_step(_user = nil, double_address_verification: false) - fill_out_address_form_ok(double_address_verification: double_address_verification) + def complete_address_step(_user = nil, same_address_as_id: true) + fill_out_address_form_ok(same_address_as_id: same_address_as_id) click_idv_continue end @@ -151,11 +139,11 @@ def complete_verify_step(_user = nil) click_idv_continue end - def complete_all_in_person_proofing_steps(user = user_with_2fa) + def complete_all_in_person_proofing_steps(user = user_with_2fa, same_address_as_id: true) complete_prepare_step(user) complete_location_step(user) - complete_state_id_step(user) - complete_address_step(user) + complete_state_id_step(user, same_address_as_id: same_address_as_id) + complete_address_step(user, same_address_as_id: same_address_as_id) unless same_address_as_id complete_ssn_step(user) complete_verify_step(user) end @@ -202,4 +190,41 @@ def mark_in_person_enrollment_passed(user) enrollment.profile.activate_after_passing_in_person enrollment.update(status: :passed) end + + def perform_mobile_hybrid_steps + perform_in_browser(:mobile) do + # doc auth page + visit @sms_link + mock_doc_auth_attention_with_barcode + attach_and_submit_images + + # error page + click_button t('in_person_proofing.body.cta.button') + # prepare page + expect(page).to(have_content(t('in_person_proofing.body.prepare.verify_step_about'))) + click_idv_continue + # location page + expect(page).to have_content(t('in_person_proofing.headings.po_search.location')) + complete_location_step + + # switch back page + expect(page).to have_content(t('in_person_proofing.headings.switch_back')) + end + end + + def perform_desktop_hybrid_steps(user = user_with_2fa, same_address_as_id: true) + perform_in_browser(:desktop) do + expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) + + complete_state_id_step(user, same_address_as_id: same_address_as_id) + complete_address_step(user, same_address_as_id: same_address_as_id) unless same_address_as_id + complete_ssn_step(user) + complete_verify_step(user) + complete_phone_step(user) + complete_review_step(user) + acknowledge_and_confirm_personal_key + + expect(page).to have_content('MILWAUKEE') + end + end end diff --git a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb index 76583e5bacb..ef12a9aa5a8 100644 --- a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -65,26 +65,6 @@ ) end - context 'with enrollment where current address matches id' do - let(:current_address_matches_id) { true } - - it 'renders without proof of address instructions' do - render - - expect(rendered).not_to have_content(t('in_person_proofing.process.proof_of_address.heading')) - end - end - - context 'with enrollment where current address does not match id' do - let(:current_address_matches_id) { false } - - it 'renders with proof of address instructions' do - render - - expect(rendered).to have_content(t('in_person_proofing.process.proof_of_address.heading')) - end - end - context 'with enrollment where selected_location_details is present' do it 'renders a location' do render diff --git a/spec/views/two_factor_authentication/webauthn_verification/show.html.erb_spec.rb b/spec/views/two_factor_authentication/webauthn_verification/show.html.erb_spec.rb index 56ffa23f8d9..a837e4920a9 100644 --- a/spec/views/two_factor_authentication/webauthn_verification/show.html.erb_spec.rb +++ b/spec/views/two_factor_authentication/webauthn_verification/show.html.erb_spec.rb @@ -3,17 +3,6 @@ RSpec.describe 'two_factor_authentication/webauthn_verification/show.html.erb' do let(:user) { build_stubbed(:user) } let(:platform_authenticator) { false } - let(:phishing_resistant_required) { false } - let(:service_provider_mfa_policy) do - ServiceProviderMfaPolicy.new( - user:, - service_provider: nil, - auth_method: :webauthn, - aal_level_requested: nil, - piv_cac_requested: false, - phishing_resistant_requested: phishing_resistant_required, - ) - end subject(:rendered) { render } @@ -27,9 +16,6 @@ service_provider: nil, platform_authenticator:, ) - allow(@presenter).to receive( - :service_provider_mfa_policy, - ).and_return(service_provider_mfa_policy) end it 'includes hidden platform form input with value false' do diff --git a/yarn.lock b/yarn.lock index 1524e115352..48f47699c08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1175,16 +1175,16 @@ "@types/set-cookie-parser" "^2.4.0" set-cookie-parser "^2.4.6" -"@mswjs/interceptors@^0.17.5": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.6.tgz#7f7900f4cd26f70d9f698685e4485b2f4101d26a" - integrity sha512-201pBIWehTURb6q8Gheu4Zhvd3Ox1U4BJq5KiOQsYzkWyfiOG4pwcz5hPZIEryztgrf8/sdwABpvY757xMmfrQ== +"@mswjs/interceptors@^0.17.10": + version "0.17.10" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.10.tgz#857b41f30e2b92345ed9a4e2b1d0a08b8b6fcad4" + integrity sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw== dependencies: "@open-draft/until" "^1.0.3" "@types/debug" "^4.1.7" "@xmldom/xmldom" "^0.8.3" debug "^4.3.3" - headers-polyfill "^3.1.0" + headers-polyfill "3.2.5" outvariant "^1.2.1" strict-event-emitter "^0.2.4" web-encoding "^1.1.5" @@ -1351,10 +1351,10 @@ dependencies: "@types/chai" "*" -"@types/chai@*", "@types/chai@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.3.tgz#3c90752792660c4b562ad73b3fbd68bf3bc7ae07" - integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== +"@types/chai@*", "@types/chai@^4.3.7": + version "4.3.7" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.7.tgz#5457bc3dce72f20ae533366682a6298471d1c610" + integrity sha512-/k+vesl92vMvMygmQrFe9Aimxi6oQXFUX9mA5HanTrKUSAMoLauSi6PNFOdRw0oeqilaW600GNx2vSaT2f8aIQ== "@types/cleave.js@^1.4.7": version "1.4.7" @@ -2422,26 +2422,18 @@ chai-as-promised@^7.1.1: dependencies: check-error "^1.0.2" -chai@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== +chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== dependencies: assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - loupe "^2.3.1" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" pathval "^1.1.1" - type-detect "^4.0.5" - -chalk@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" + type-detect "^4.0.8" chalk@^2.0.0: version "2.4.2" @@ -2465,10 +2457,12 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.4.2, chokidar@^3.5.3: version "3.5.3" @@ -2847,10 +2841,10 @@ decimal.js@^10.4.3: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" @@ -3743,10 +3737,10 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-func-name@^2.0.0, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.0" @@ -3887,10 +3881,10 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -"graphql@^15.0.0 || ^16.0.0": - version "16.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb" - integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw== +graphql@^16.8.1: + version "16.8.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" + integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== handle-thing@^2.0.0: version "2.0.1" @@ -3953,10 +3947,10 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -headers-polyfill@^3.1.0, headers-polyfill@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.1.2.tgz#9a4dcb545c5b95d9569592ef7ec0708aab763fbe" - integrity sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA== +headers-polyfill@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.2.5.tgz#6e67d392c9d113d37448fe45014e0afdd168faed" + integrity sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA== hosted-git-info@^4.0.1: version "4.1.0" @@ -4605,10 +4599,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libphonenumber-js@^1.10.45: - version "1.10.45" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.45.tgz#cbaebe6bfae746dbfb42730cd043fcb8c472ca00" - integrity sha512-eeHcvGafEYCaKB4fo2uBINfG7j7PcGwBHUaTVfbwl/6KcjCgIKNlIOsSXVRp9BH10NQwmvvk+nQ1e/Yp4BGB7w== +libphonenumber-js@^1.10.47: + version "1.10.47" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.47.tgz#1efdf08306960a222703e575e78eb76458944012" + integrity sha512-b4t7VQDV29xx/ni+58yl9KWPGjnDLDXCeCTLrD4V8vDpObXZRZBrg7uX/HWZ7YXiJKqdBDGgc+barUUTNB6Slw== lightningcss-darwin-arm64@1.16.1: version "1.16.1" @@ -4750,10 +4744,10 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== +loupe@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== dependencies: get-func-name "^2.0.0" @@ -4992,21 +4986,21 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -msw@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/msw/-/msw-1.2.1.tgz#9dd347583eeba5e5c7f33b54be5600a899dc61bd" - integrity sha512-bF7qWJQSmKn6bwGYVPXOxhexTCGD5oJSZg8yt8IBClxvo3Dx/1W0zqE1nX9BSWmzRsCKWfeGWcB/vpqV6aclpw== +msw@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/msw/-/msw-1.3.2.tgz#35e0271293e893fc3c55116e90aad5d955c66899" + integrity sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA== dependencies: "@mswjs/cookies" "^0.2.2" - "@mswjs/interceptors" "^0.17.5" + "@mswjs/interceptors" "^0.17.10" "@open-draft/until" "^1.0.3" "@types/cookie" "^0.4.1" "@types/js-levenshtein" "^1.1.1" - chalk "4.1.1" + chalk "^4.1.1" chokidar "^3.4.2" cookie "^0.4.2" - graphql "^15.0.0 || ^16.0.0" - headers-polyfill "^3.1.2" + graphql "^16.8.1" + headers-polyfill "3.2.5" inquirer "^8.2.0" is-node-process "^1.2.0" js-levenshtein "^1.1.6" @@ -5486,10 +5480,10 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.22, postcss@^8.4.24: - version "8.4.25" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.25.tgz#4a133f5e379eda7f61e906c3b1aaa9b81292726f" - integrity sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw== +postcss@8.4.31, postcss@^8.4.24: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -6716,7 +6710,7 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==