Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
004f4f2
changelog: Internal, tech debt, Break up MFA presenter class for phone
kevinsmaster5 Nov 3, 2023
a05eee9
split phone, voice, and sms presenter classes up
kevinsmaster5 Nov 6, 2023
a5ac190
add tests cases for sign_in and set_up phone presenter class
kevinsmaster5 Nov 6, 2023
fa1eb1c
split setup signin presenter spec for voice and sms
kevinsmaster5 Nov 7, 2023
473c08e
lint fix
kevinsmaster5 Nov 7, 2023
23c0ad2
remove old phone selection presenter spec
kevinsmaster5 Nov 7, 2023
8c5a20f
rename phone presenter in spec
kevinsmaster5 Nov 7, 2023
a77d9e6
remove unneeded configuration variable, leverage user for type method
kevinsmaster5 Nov 7, 2023
761176e
remove info method from phone sub classes
kevinsmaster5 Nov 7, 2023
f1ffce1
update options presenter spec with newly split classes
kevinsmaster5 Nov 7, 2023
5c39c4a
merge sms and voice presenters
kevinsmaster5 Nov 8, 2023
28b47f2
revise specs according to merged classes
kevinsmaster5 Nov 9, 2023
07e563d
remove deprecated spec and lint fix
kevinsmaster5 Nov 9, 2023
620c7e8
change info to switch and fix regression with disabled? method
kevinsmaster5 Nov 9, 2023
365f8fe
lint fix
kevinsmaster5 Nov 9, 2023
c218120
fix spec
kevinsmaster5 Nov 9, 2023
b4f693d
remove deprecated translations from setup presenter
kevinsmaster5 Nov 9, 2023
931b8f0
move reader :method to phone sign in presenter
kevinsmaster5 Nov 14, 2023
cb5a3c4
fix lint
kevinsmaster5 Nov 14, 2023
ad0955b
fix lint
kevinsmaster5 Nov 14, 2023
5e14f17
clean up selection presenter class
kevinsmaster5 Nov 15, 2023
d7b8914
remove unneeded configuration setting
kevinsmaster5 Nov 16, 2023
fd859d4
remove configuration from set up presenter spec
kevinsmaster5 Nov 16, 2023
c72de0d
add sms and voice outage spec, standardize spec syntax
kevinsmaster5 Nov 16, 2023
5591554
clarify some syntax
kevinsmaster5 Nov 16, 2023
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
6 changes: 4 additions & 2 deletions app/models/phone_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ def selection_presenters
capabilities = PhoneNumberCapabilities.new(phone, phone_confirmed: !!confirmed_at?)

if capabilities.supports_sms?
options << TwoFactorAuthentication::SmsSelectionPresenter.new(user:, configuration: self)
options << TwoFactorAuthentication::SignInPhoneSelectionPresenter.
new(user:, configuration: self, method: :sms)
end

if capabilities.supports_voice?
options << TwoFactorAuthentication::VoiceSelectionPresenter.new(user:, configuration: self)
options << TwoFactorAuthentication::SignInPhoneSelectionPresenter.
new(user:, configuration: self, method: :voice)
end

options
Expand Down
20 changes: 2 additions & 18 deletions app/presenters/two_factor_authentication/selection_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,11 @@ def disabled?
private

def login_label(type)
case type
when 'sms'
t('two_factor_authentication.login_options.sms')
when 'voice'
t('two_factor_authentication.login_options.voice')
else
raise "Unsupported login method: #{type}"
end
raise "Unsupported login method: #{type}"
end

def setup_label(type)
case type
when 'phone'
t('two_factor_authentication.two_factor_choice_options.phone')
when 'sms'
t('two_factor_authentication.two_factor_choice_options.sms')
when 'voice'
t('two_factor_authentication.two_factor_choice_options.voice')
else
raise "Unsupported setup method: #{type}"
end
raise "Unsupported setup method: #{type}"
end

def login_info(type)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
module TwoFactorAuthentication
class PhoneSelectionPresenter < SelectionPresenter
class SetUpPhoneSelectionPresenter < SetUpSelectionPresenter
def method
:phone
end

def type
if MfaContext.new(configuration&.user).phone_configurations.many?
"#{super}_#{configuration.id}"
else
super
end
def label
t('two_factor_authentication.two_factor_choice_options.phone')
end

def info
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module TwoFactorAuthentication
class SignInPhoneSelectionPresenter < SignInSelectionPresenter
attr_reader :configuration, :user, :method
Copy link
Contributor

@zachmargolis zachmargolis Nov 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method is a ruby built-in method so I feel like it would be good to avoid overriding that if we can? Could we name the attribute something else? like delivery_method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point. It would have to be changed on all of the MFA presenters if so.

Copy link
Contributor

@aduth aduth Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea, though in this case we're porting over an existing pair of methods:

It's also already used throughout every other 2FA presenter:

That being said, the only place I see it actually being used is in the presenter type method, and the only purpose that seemed to serve was for the label method's switches, which should all be effectively removed as of this pull request. I could probably clean this up as part of the follow-on work I mentioned at #9560 (comment) .


def initialize(user:, configuration:, method:)
@user = user
@configuration = configuration
@method = method
end

def type
if MfaContext.new(configuration&.user).phone_configurations.many?
"#{super}_#{configuration.id}"
else
super
end
end

def label
if method.to_s == 'sms'
t('two_factor_authentication.login_options.sms')
elsif method.to_s == 'voice'
t('two_factor_authentication.login_options.voice')
end
end

def info
case method
when :sms
t(
'two_factor_authentication.login_options.sms_info_html',
phone: configuration.masked_phone,
)
when :voice
t(
'two_factor_authentication.login_options.voice_info_html',
phone: configuration.masked_phone,
)
else
t('two_factor_authentication.two_factor_choice_options.phone_info')
end
end

def disabled?
case method
when :sms
OutageStatus.new.vendor_outage?(:sms)
when :voice
OutageStatus.new.vendor_outage?(:voice)
else
OutageStatus.new.all_phone_vendor_outage?
end
end
end
end

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions app/presenters/two_factor_options_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def all_user_selected_options
[
TwoFactorAuthentication::SetUpWebauthnPlatformSelectionPresenter.new(user: user),
TwoFactorAuthentication::SetUpAuthAppSelectionPresenter.new(user: user),
TwoFactorAuthentication::PhoneSelectionPresenter.new(user: user),
TwoFactorAuthentication::SetUpPhoneSelectionPresenter.new(user: user),
TwoFactorAuthentication::SetUpBackupCodeSelectionPresenter.new(user: user),
TwoFactorAuthentication::SetUpWebauthnSelectionPresenter.new(user: user),
TwoFactorAuthentication::SetUpPivCacSelectionPresenter.new(user: user),
Expand Down Expand Up @@ -116,7 +116,7 @@ def phone_options
if piv_cac_required? || phishing_resistant_only? || IdentityConfig.store.hide_phone_mfa_signup
return []
else
[TwoFactorAuthentication::PhoneSelectionPresenter.new(user: user)]
[TwoFactorAuthentication::SetUpPhoneSelectionPresenter.new(user: user)]
end
end

Expand Down
2 changes: 0 additions & 2 deletions config/locales/two_factor_authentication/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,6 @@ en:
(toll) phone numbers.
piv_cac: Government employee ID
piv_cac_info: PIV/CAC cards for government and military employees. Desktop only.
sms: Text message / SMS
voice: Phone call
webauthn: Security key
webauthn_info: A physical device, often shaped like a USB drive, that you plug
in to your device.
Expand Down
2 changes: 0 additions & 2 deletions config/locales/two_factor_authentication/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,6 @@ es:
piv_cac: Identificación de empleado gubernamental
piv_cac_info: Credenciales PIV/CAC para empleados gubernamentales y del
ejército. Únicamente versión de escritorio.
sms: Mensaje de texto / SMS
voice: Llamada telefónica
webauthn: Clave de seguridad
webauthn_info: Un dispositivo físico que suele tener la forma de una unidad USB
y se conecta a su dispositivo.
Expand Down
2 changes: 0 additions & 2 deletions config/locales/two_factor_authentication/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,6 @@ fr:
piv_cac: Carte d’identification des employés du gouvernement
piv_cac_info: Cartes PIV/CAC pour les fonctionnaires et les militaires. Bureau
uniquement.
sms: SMS
voice: Appel téléphonique
webauthn: Clef de sécurité
webauthn_info: Un appareil physique, souvent en forme de clé USB, que vous
branchez sur votre appareil.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::PhoneSelectionPresenter do
RSpec.describe TwoFactorAuthentication::SetUpPhoneSelectionPresenter do
let(:user_without_mfa) { create(:user) }
let(:user_with_mfa) { create(:user, :with_phone) }
let(:presenter_with_mfa) { described_class.new(configuration: phone, user: user_with_mfa) }
let(:presenter_without_mfa) { described_class.new(configuration: phone, user: user_without_mfa) }
let(:presenter_with_mfa) { described_class.new(user: user_with_mfa) }
let(:presenter_without_mfa) { described_class.new(user: user_without_mfa) }

describe '#info' do
context 'when a user does not have a phone configuration (first time)' do
let(:phone) { nil }

it 'includes a note about choosing voice or sms' do
expect(presenter_without_mfa.info).
to include(t('two_factor_authentication.two_factor_choice_options.phone_info'))
Expand All @@ -28,8 +26,6 @@
end

describe '#disabled?' do
let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }

it { expect(presenter_without_mfa.disabled?).to eq(false) }

context 'all phone vendor outage' do
Expand All @@ -42,7 +38,6 @@
end

describe '#mfa_configuration' do
let(:phone) { nil }
it 'returns an empty string when user has not configured this authenticator' do
expect(presenter_without_mfa.mfa_configuration_description).to eq('')
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::SignInPhoneSelectionPresenter do
let(:user) { create(:user, :with_phone) }
let(:configuration) { create(:phone_configuration, user: user) }

let(:presenter) do
described_class.new(user: user, configuration: configuration, method: 'phone')
end

describe '#type' do
it 'returns phone appended with configuration id' do
expect(presenter.type).to eq "phone_#{configuration.id}"
end
end

describe '#info' do
it 'raises with missing translation' do
expect(presenter.info).to eq(
t('two_factor_authentication.two_factor_choice_options.phone_info'),
)
end
context 'with sms method' do
let(:presenter) do
described_class.new(user: user, configuration: configuration, method: :sms)
end
it 'returns the correct translation for sms' do
expect(presenter.info).to eq(
t(
'two_factor_authentication.login_options.sms_info_html',
phone: configuration.masked_phone,
),
)
end
end
context 'with voice method' do
let(:presenter) do
described_class.new(user: user, configuration: configuration, method: :voice)
end
it 'returns the correct translation for voice' do
expect(presenter.info).to eq(
t(
'two_factor_authentication.login_options.voice_info_html',
phone: configuration.masked_phone,
),
)
end
end
end

describe '#disabled?' do
let(:user_without_mfa) { create(:user) }
let(:phone) { build(:phone_configuration, phone: '+1 888 867-5309') }
let(:presenter_without_mfa) do
described_class.new(configuration: phone, user: user_without_mfa, method: 'phone')
end
it { expect(presenter_without_mfa.disabled?).to eq(false) }

context 'all phone vendor outage' do
before do
allow_any_instance_of(OutageStatus).to receive(:all_phone_vendor_outage?).and_return(true)
end

it { expect(presenter_without_mfa.disabled?).to eq(true) }
end

context 'voice vendor outage' do
let(:presenter_without_mfa) do
described_class.new(configuration: phone, user: user, method: method)
end
let(:method) { :voice }
before do
allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:voice).
and_return(true)
end

it { expect(presenter_without_mfa.disabled?).to eq(true) }
end

context 'sms vendor outage' do
let(:presenter_without_mfa) do
described_class.new(configuration: phone, user: user, method: method)
end
let(:method) { :sms }
before do
allow_any_instance_of(OutageStatus).to receive(:vendor_outage?).with(:sms).and_return(true)
end

it { expect(presenter_without_mfa.disabled?).to eq(true) }
end
end
end

This file was deleted.

Loading