Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 0 additions & 53 deletions .codeclimate.yml

This file was deleted.

23 changes: 22 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ApplicationController < ActionController::Base
rescue_from error, with: :render_timeout
end

helper_method :decorated_sp_session, :user_fully_authenticated?
helper_method :decorated_sp_session, :current_sp, :user_fully_authenticated?

prepend_before_action :add_new_relic_trace_attributes
prepend_before_action :session_expires_at
Expand Down Expand Up @@ -77,6 +77,19 @@ def analytics_user
current_user || AnonymousUser.new
end

def attempts_api_tracker
@attempts_api_tracker ||= AttemptsApi::Tracker.new(
session_id: attempts_api_session_id,
request:,
user: current_user,
sp: current_sp,
cookie_device_uuid: cookies[:device],
# this only works for oidc
sp_request_uri: decorated_sp_session.request_url_params[:redirect_uri],
enabled_for_session: attempts_api_enabled_for_session?,
)
end

def user_event_creator
@user_event_creator ||= UserEventCreator.new(request: request, current_user: current_user)
end
Expand Down Expand Up @@ -127,6 +140,14 @@ def current_sp

private

def attempts_api_enabled_for_session?
current_sp&.attempts_api_enabled? && attempts_api_session_id.present?
end

def attempts_api_session_id
@attempts_api_session_id ||= decorated_sp_session.attempts_api_session_id
end

# These attributes show up in New Relic traces for all requests.
# https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/collect-custom-attributes
def add_new_relic_trace_attributes
Expand Down
6 changes: 6 additions & 0 deletions app/controllers/sign_up/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ def forbidden_passwords

def track_analytics(result)
analytics.password_creation(**result)

failure_reason = attempts_api_tracker.parse_failure_reason(result)
attempts_api_tracker.user_registration_password_submitted(
success: result.success?,
failure_reason:,
)
end

def permitted_params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def confirm_voice_capability
return if params[:otp_delivery_preference] == 'sms'

phone_is_confirmed = UserSessionContext.authentication_or_reauthentication_context?(context)

capabilities = PhoneNumberCapabilities.new(phone, phone_confirmed: phone_is_confirmed)

return if capabilities.supports_voice?
Expand Down Expand Up @@ -233,6 +234,7 @@ def update_phone_attributes
user: current_user,
attributes: { phone_id: user_session[:phone_id],
phone: user_session[:unconfirmed_phone],
phone_confirmed_at: Time.zone.now,
otp_make_default_number: selected_otp_make_default_number },
)
end
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/users/backup_code_setup_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def index
result = BackupCodeSetupForm.new(current_user).submit
visit_result = result.to_h.merge(analytics_properties_for_visit)
analytics.backup_code_setup_visit(**visit_result)
attempts_api_tracker.mfa_enroll_backup_code(success: result.success?)

generate_codes
track_backup_codes_created
Expand All @@ -35,6 +36,7 @@ def create
result = BackupCodeSetupForm.new(current_user).submit
visit_result = result.to_h.merge(analytics_properties_for_visit)
analytics.backup_code_setup_visit(**visit_result)
attempts_api_tracker.mfa_enroll_backup_code(success: result.success?)

generate_codes
track_backup_codes_created
Expand Down
1 change: 1 addition & 0 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def track_authentication_attempt
remember_device: remember_device_cookie.present?,
new_device: success ? new_device? : nil,
)
attempts_api_tracker.email_and_password_auth(success:)
end

def user_locked_out?(user)
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/users/totp_setup_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def confirm
properties = result.to_h.merge(analytics_properties)
analytics.multi_factor_auth_setup(**properties)

attempts_api_tracker.mfa_enroll_totp(success: result.success?)

if result.success?
process_valid_code
user_session.delete(:mfa_attempts)
Expand Down
6 changes: 2 additions & 4 deletions app/decorators/null_service_provider_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ def sp_name; end

def sp_issuer; end

def sp_logo; end

def sp_logo_url; end

def sp_redirect_uris; end

def requested_attributes; end
Expand All @@ -47,6 +43,8 @@ def current_user
view_context&.current_user
end

def attempts_api_session_id; end

private

attr_reader :view_context
Expand Down
33 changes: 4 additions & 29 deletions app/decorators/service_provider_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ class ServiceProviderSession
include ActionView::Helpers::TranslationHelper
include Rails.application.routes.url_helpers

DEFAULT_LOGO = 'generic.svg'

def initialize(sp:, view_context:, sp_session:, service_provider_request:)
@sp = sp
@view_context = view_context
@sp_session = sp_session
@service_provider_request = service_provider_request
end

def attempts_api_session_id
request_url_params['attempts_api_session_id']
end

def remember_device_default
sp_aal < 2
end
Expand All @@ -21,33 +23,6 @@ def sp_redirect_uris
@sp.redirect_uris
end

def sp_logo
sp.logo.presence || DEFAULT_LOGO
end

def sp_logo_url
if FeatureManagement.logo_upload_enabled? && sp.remote_logo_key.present?
s3_logo_url(sp)
else
legacy_logo_url
end
end

def s3_logo_url(service_provider)
region = IdentityConfig.store.aws_region
bucket = IdentityConfig.store.aws_logo_bucket
key = service_provider.remote_logo_key

"https://s3.#{region}.amazonaws.com/#{bucket}/#{key}"
end

def legacy_logo_url
logo = sp_logo
ActionController::Base.helpers.image_path("sp-logos/#{logo}")
rescue Propshaft::MissingAssetError
''
end

def new_session_heading
I18n.t('headings.sign_in_with_sp', sp: sp_name)
end
Expand Down
2 changes: 1 addition & 1 deletion app/forms/idv/api_image_upload_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def extra_attributes
submit_attempts: submit_attempts,
remaining_submit_attempts: remaining_submit_attempts,
user_id: user_uuid,
pii_like_keypaths: DocPiiForm.pii_like_keypaths,
pii_like_keypaths: DocPiiForm.pii_like_keypaths(document_type: document_type),
flow_path: params[:flow_path],
}

Expand Down
62 changes: 25 additions & 37 deletions app/forms/idv/doc_pii_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,17 @@ class DocPiiForm

validate :name_valid?
validate :dob_valid?
validates_presence_of :address1, { message: proc {
I18n.t('doc_auth.errors.alerts.address_check')
} }
validate :zipcode_valid?
validates :jurisdiction, :state, inclusion: { in: Idp::Constants::STATE_AND_TERRITORY_CODES,
message: proc {
I18n.t('doc_auth.errors.general.no_liveness')
} }

validates_presence_of :state_id_number, { message: proc {
I18n.t('doc_auth.errors.general.no_liveness')
} }
validate :state_id_expired?
validate :state_id_or_passport

attr_reader :first_name, :last_name, :dob, :address1, :state, :zipcode, :attention_with_barcode,
:jurisdiction, :state_id_number, :state_id_expiration
attr_reader :first_name, :last_name, :dob, :state_id_type, :attention_with_barcode
alias_method :attention_with_barcode?, :attention_with_barcode

def initialize(pii:, attention_with_barcode: false)
@pii_from_doc = pii
@first_name = pii[:first_name]
@last_name = pii[:last_name]
@dob = pii[:dob]
@address1 = pii[:address1]
@state = pii[:state]
@zipcode = pii[:zipcode]
@jurisdiction = pii[:state_id_jurisdiction]
@state_id_number = pii[:state_id_number]
@state_id_expiration = pii[:state_id_expiration]
@state_id_type = pii[:state_id_type]
@attention_with_barcode = attention_with_barcode
end

Expand All @@ -43,19 +25,27 @@ def submit
success: valid?,
errors: errors,
extra: {
pii_like_keypaths: self.class.pii_like_keypaths,
pii_like_keypaths: self.class.pii_like_keypaths(document_type: state_id_type),
attention_with_barcode: attention_with_barcode?,
id_issued_status: pii_from_doc[:state_id_issued].present? ? 'present' : 'missing',
id_expiration_status: pii_from_doc[:state_id_expiration].present? ? 'present' : 'missing',
passport_issued_status: pii_from_doc[:passport_issued].present? ? 'present' : 'missing',
passport_expiration_status: pii_from_doc[:passport_expiration].present? ?
'present' : 'missing',
},
)
response.pii_from_doc = pii_from_doc
response
end

def self.pii_like_keypaths
def self.pii_like_keypaths(document_type:)
keypaths = [[:pii]]
attrs = %i[name dob dob_min_age address1 state zipcode jurisdiction state_id_number]
document_attrs = document_type&.downcase == 'passport' ?
DocPiiPassport.pii_like_keypaths :
DocPiiStateId.pii_like_keypaths

attrs = %i[name dob dob_min_age] + document_attrs

attrs.each do |k|
keypaths << [:errors, k]
keypaths << [:error_details, k]
Expand Down Expand Up @@ -84,6 +74,7 @@ def self.present_error(existing_errors)

PII_ERROR_KEYS = %i[name dob address1 state zipcode jurisdiction state_id_number
dob_min_age].freeze
STATE_ID_TYPES = ['drivers_license', 'state_id_card', 'identification_card'].freeze

attr_reader :pii_from_doc

Expand All @@ -108,22 +99,19 @@ def dob_valid?
end
end

def state_id_expired?
# temporary fix, tracked for removal in LG-15600
return if IdentityConfig.store.socure_docv_verification_data_test_mode &&
DateParser.parse_legacy(state_id_expiration) == Date.parse('2020-01-01')

if state_id_expiration && DateParser.parse_legacy(state_id_expiration).past?
errors.add(:state_id_expiration, generic_error, type: :state_id_expiration)
def state_id_or_passport
case state_id_type
when *STATE_ID_TYPES
state_id_validation = DocPiiStateId.new(pii: pii_from_doc)
state_id_validation.valid? || errors.merge!(state_id_validation.errors)
when 'passport'
passport_validation = DocPiiPassport.new(pii: pii_from_doc)
passport_validation.valid? || errors.merge!(passport_validation.errors)
else
errors.add(:no_document, generic_error, type: :no_document)
end
end

def zipcode_valid?
return if zipcode.is_a?(String) && zipcode.present?

errors.add(:zipcode, generic_error, type: :zipcode)
end

def generic_error
I18n.t('doc_auth.errors.general.no_liveness')
end
Expand Down
Loading