18F/identity-idp

View on GitHub
app/controllers/concerns/rate_limit_concern.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module RateLimitConcern
  extend ActiveSupport::Concern

  ALL_IDV_RATE_LIMITERS = [:idv_resolution, :idv_doc_auth, :proof_ssn].freeze

  def confirm_not_rate_limited(rate_limiters = ALL_IDV_RATE_LIMITERS)
    exceeded_rate_limits = check_for_exceeded_rate_limits(rate_limiters)
    if exceeded_rate_limits.any?
      rate_limit_redirect!(exceeded_rate_limits.first)
      return true
    end
    confirm_not_rate_limited_for_phone_and_letter_address_verification
  end

  def confirm_not_rate_limited_after_doc_auth
    rate_limiters = [:idv_resolution, :proof_ssn]
    confirm_not_rate_limited(rate_limiters)
  end

  def confirm_not_rate_limited_for_phone_address_verification
    if idv_attempter_rate_limited?(:proof_address)
      rate_limit_redirect!(:proof_address)
      return true
    end
  end

  private

  def confirm_not_rate_limited_for_phone_and_letter_address_verification
    if idv_attempter_rate_limited?(:proof_address) && gpo_verify_by_mail_policy.rate_limited?
      rate_limit_redirect!(:proof_address)
      return true
    end
  end

  def rate_limit_redirect!(rate_limit_type)
    if idv_attempter_rate_limited?(rate_limit_type)
      analytics.rate_limit_reached(limiter_type: rate_limit_type)
      rate_limited_redirect(rate_limit_type)
      return true
    end
  end

  def rate_limited_redirect(rate_limit_type)
    case rate_limit_type
    when :idv_resolution
      redirect_to idv_session_errors_failure_url
    when :idv_doc_auth
      redirect_to idv_session_errors_rate_limited_url
    when :proof_address
      redirect_to idv_phone_errors_failure_url
    when :proof_ssn
      redirect_to idv_session_errors_ssn_failure_url
    end
  end

  def check_for_exceeded_rate_limits(rate_limit_types)
    rate_limit_types.select do |rate_limit_type|
      idv_attempter_rate_limited?(rate_limit_type)
    end
  end

  def idv_attempter_rate_limited?(rate_limit_type)
    if rate_limit_type == :proof_ssn
      return unless pii_ssn
      RateLimiter.new(
        target: Pii::Fingerprinter.fingerprint(pii_ssn),
        rate_limit_type: :proof_ssn,
      ).limited?
    else
      RateLimiter.new(
        user: idv_session_user,
        rate_limit_type: rate_limit_type,
      ).limited?
    end
  end

  def pii_ssn
    return unless defined?(idv_session) && user_session
    idv_session&.ssn
  end
end