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
1 change: 1 addition & 0 deletions app/controllers/idv/otp_verification_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def phone_confirmation_otp_verification_form
@phone_confirmation_otp_verification_form ||= PhoneConfirmationOtpVerificationForm.new(
user: current_user,
user_phone_confirmation_session: idv_session.user_phone_confirmation_session,
irs_attempts_api_tracker: irs_attempts_api_tracker,
)
end
end
Expand Down
14 changes: 11 additions & 3 deletions app/forms/idv/phone_confirmation_otp_verification_form.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module Idv
class PhoneConfirmationOtpVerificationForm
attr_reader :user, :user_phone_confirmation_session, :code
attr_reader :user, :user_phone_confirmation_session, :irs_attempts_api_tracker, :code

def initialize(user:, user_phone_confirmation_session:)
def initialize(user:, user_phone_confirmation_session:, irs_attempts_api_tracker:)
@user = user
@user_phone_confirmation_session = user_phone_confirmation_session
@irs_attempts_api_tracker = irs_attempts_api_tracker
end

def submit(code:)
Expand Down Expand Up @@ -32,11 +33,18 @@ def clear_second_factor_attempts
def increment_second_factor_attempts
user.second_factor_attempts_count += 1
attributes = {}
attributes[:second_factor_locked_at] = Time.zone.now if user.max_login_attempts?
if user.max_login_attempts?
attributes[:second_factor_locked_at] = Time.zone.now
irs_attempts_api_tracker.idv_phone_otp_submitted_rate_limited(phone: user_phone)
end

UpdateUser.new(user: user, attributes: attributes).call
end

def user_phone
user_phone_confirmation_session.phone
end

def extra_analytics_attributes
{
code_expired: user_phone_confirmation_session.expired?,
Expand Down
9 changes: 9 additions & 0 deletions app/services/irs_attempts_api/tracker_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ def forgot_password_email_confirmed(success:, failure_reason: nil)
)
end

# The user reached the rate limit for Idv phone OTP submitted
# @param [String] phone
def idv_phone_otp_submitted_rate_limited(phone:)
track_event(
:idv_phone_otp_submitted_rate_limited,
phone: phone,
)
end

# @param [Boolean] success
# @param [String] phone_number
# The phone upload link was sent during the IDV process
Expand Down
15 changes: 14 additions & 1 deletion spec/forms/idv/phone_confirmation_otp_verification_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@
delivery_method: :sms,
)
end
let(:irs_attempts_api_tracker) do
instance_double(
IrsAttemptsApi::Tracker,
idv_phone_otp_submitted_rate_limited: true,
)
end

describe '#submit' do
def try_submit(code)
described_class.new(
user: user, user_phone_confirmation_session: user_phone_confirmation_session,
user: user,
user_phone_confirmation_session: user_phone_confirmation_session,
irs_attempts_api_tracker: irs_attempts_api_tracker,
).submit(code: code)
end

Expand Down Expand Up @@ -64,6 +72,10 @@ def try_submit(code)
context 'when the code is expired' do
let(:phone_confirmation_otp_sent_at) { 11.minutes.ago }

before do
allow(IrsAttemptsApi::Tracker).to receive(:new).and_return(irs_attempts_api_tracker)
end

it 'returns an unsuccessful result' do
result = try_submit(phone_confirmation_otp_code)

Expand All @@ -84,6 +96,7 @@ def try_submit(code)

expect(user.second_factor_attempts_count).to eq(3)
expect(user.second_factor_locked_at).to be_within(1.second).of(Time.zone.now)
expect(irs_attempts_api_tracker).to have_received(:idv_phone_otp_submitted_rate_limited)
end
end

Expand Down