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
15 changes: 9 additions & 6 deletions app/forms/update_user_password_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,26 @@ def submit(params)

def process_valid_submission
update_user_password
encrypt_user_profile_if_active
encrypt_user_profiles
end

def update_user_password
attributes = { password: password }
UpdateUser.new(user: user, attributes: attributes).call
end

def encrypt_user_profile_if_active
active_profile = user.active_profile
return if active_profile.blank?
def encrypt_user_profiles
return if user.active_or_pending_profile.blank?

encryptor.call
encryptor.encrypt
end

def encryptor
@encryptor ||= ActiveProfileEncryptor.new(user, user_session, password)
@encryptor ||= UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
end

def extra_analytics_attributes
Expand Down
22 changes: 0 additions & 22 deletions app/services/active_profile_encryptor.rb

This file was deleted.

28 changes: 28 additions & 0 deletions app/services/user_profiles_encryptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class UserProfilesEncryptor
attr_reader :personal_key

def initialize(user:, user_session:, password:)
@user = user
@user_session = user_session
@password = password
end

def encrypt
if user.active_profile.present?
encrypt_pii_for_profile(user.active_profile)
end
if user.pending_profile.present?
encrypt_pii_for_profile(user.pending_profile)
end
end

private

attr_reader :user, :password, :user_session

def encrypt_pii_for_profile(profile)
pii = Pii::Cacher.new(user, user_session).fetch(profile.id)
@personal_key = profile.encrypt_pii(pii, password)
profile.save!
end
end
1 change: 1 addition & 0 deletions spec/controllers/users/passwords_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
stub_sign_in(user)
Pii::Cacher.new(user, controller.user_session).save_decrypted_pii(
Pii::Attributes.new(ssn: '111-222-3333'),
user.active_profile.id,
)

params = {
Expand Down
36 changes: 25 additions & 11 deletions spec/forms/update_user_password_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
}

expect(UpdateUser).not_to receive(:new)
expect(ActiveProfileEncryptor).not_to receive(:new)
expect(UserProfilesEncryptor).not_to receive(:new)
expect(subject.submit(params).to_h).to include(
success: false,
errors: errors,
Expand Down Expand Up @@ -70,17 +70,21 @@
context 'when the user has an active profile' do
let(:profile) { create(:profile, :active, :verified, pii: { ssn: '1234' }) }
let(:user) { profile.user }
let(:user_session) { { decrypted_pii: { ssn: '1234' }.to_json } }
let(:user_session) { {} }

before do
Pii::Cacher.new(user, user_session).save_decrypted_pii({ ssn: '1234' }, profile.id)
end

it 'encrypts the active profile' do
encryptor = instance_double(ActiveProfileEncryptor)
allow(ActiveProfileEncryptor).to receive(:new).
with(user, user_session, password).and_return(encryptor)
allow(encryptor).to receive(:call)
encryptor = instance_double(UserProfilesEncryptor)
allow(UserProfilesEncryptor).to receive(:new).
with(user: user, user_session: user_session, password: password).and_return(encryptor)
allow(encryptor).to receive(:encrypt)

subject.submit(params)

expect(encryptor).to have_received(:call)
expect(encryptor).to have_received(:encrypt)
end

it 'logs that the user has an active profile' do
Expand All @@ -96,11 +100,21 @@
context 'the user has a pending profile' do
let(:profile) { create(:profile, :verify_by_mail_pending, :verified, pii: { ssn: '1234' }) }
let(:user) { profile.user }
let(:user_session) { {} }

it 'does not call ActiveProfileEncryptor' do
expect(ActiveProfileEncryptor).to_not receive(:new)
before do
Pii::Cacher.new(user, user_session).save_decrypted_pii({ ssn: '1234' }, profile.id)
end

it 'encrypts the pending profile' do
encryptor = instance_double(UserProfilesEncryptor)
allow(UserProfilesEncryptor).to receive(:new).
with(user: user, user_session: user_session, password: password).and_return(encryptor)
allow(encryptor).to receive(:encrypt)

subject.submit(params)

expect(encryptor).to have_received(:encrypt)
end

it 'logs that the user has a pending profile' do
Expand All @@ -114,8 +128,8 @@
end

context 'when the user does not have a profile' do
it 'does not call ActiveProfileEncryptor' do
expect(ActiveProfileEncryptor).to_not receive(:new)
it 'does not call UserProfilesEncryptor' do
expect(UserProfilesEncryptor).to_not receive(:new)

subject.submit(params)
end
Expand Down
25 changes: 0 additions & 25 deletions spec/services/active_profile_encryptor_spec.rb

This file was deleted.

121 changes: 121 additions & 0 deletions spec/services/user_profiles_encryptor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
require 'rails_helper'

RSpec.describe UserProfilesEncryptor do
describe '#call' do
let(:user_session) { {}.with_indifferent_access }
let(:pii) { Pii::Attributes.new(ssn: '1234') }
let(:profile) { create(:profile, :active, :verified, pii: pii.to_h) }
let(:user) { profile.user }
let(:password) { 'a new and incredibly exciting password' }

before do
Pii::Cacher.new(user, user_session).save_decrypted_pii(pii, profile.id)
end

context 'when the user has an active profile' do
it 'encrypts the PII for the active profile with the password' do
encryptor = UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
encryptor.encrypt

profile.reload

personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)

decrypted_profile_pii = profile.decrypt_pii(password)
decrypted_profile_recovery_pii = profile.recover_pii(personal_key)

expect(pii).to eq(decrypted_profile_pii)
expect(pii).to eq(decrypted_profile_recovery_pii)
expect(user.valid_personal_key?(personal_key)).to eq(true)
end
end

context 'when the user has a pending profile' do
let(:profile) { create(:profile, :verify_by_mail_pending, :verified, pii: pii.to_h) }

it 'encrypts the PII for the pending profile with the password' do
encryptor = UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
encryptor.encrypt

profile.reload

personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)

decrypted_profile_pii = profile.decrypt_pii(password)
decrypted_profile_recovery_pii = profile.recover_pii(personal_key)

expect(pii).to eq(decrypted_profile_pii)
expect(pii).to eq(decrypted_profile_recovery_pii)
expect(user.valid_personal_key?(personal_key)).to eq(true)
end
end

context 'when the user has an active and a pending profile' do
let(:active_pii) { pii }
let(:active_profile) { profile }
let(:pending_pii) { Pii::Attributes.new(ssn: '5555') }
let(:pending_profile) do
create(
:profile,
:verify_by_mail_pending,
:verified,
pii: pending_pii.to_h,
user: user,
)
end

before do
Pii::Cacher.new(user, user_session).save_decrypted_pii(pending_pii, pending_profile.id)
end

it 'encrypts the PII for both profiles with the password' do
encryptor = UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
encryptor.encrypt

active_profile.reload
pending_profile.reload

decrypted_active_profile_pii = active_profile.decrypt_pii(password)
decrypted_pending_profile_pii = pending_profile.decrypt_pii(password)

expect(decrypted_active_profile_pii).to eq(active_pii)
expect(decrypted_pending_profile_pii).to eq(pending_pii)
end

it 'sets the pending profile personal key as the personal key' do
encryptor = UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
encryptor.encrypt

active_profile.reload
pending_profile.reload

personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)

expect do
active_profile.recover_pii(personal_key)
end.to raise_error(Encryption::EncryptionError)

decrypted_pending_profile_recovery_pii = pending_profile.recover_pii(personal_key)
expect(decrypted_pending_profile_recovery_pii).to eq(pending_pii)

expect(user.valid_personal_key?(personal_key)).to eq(true)
end
end
end
end