Skip to content

Commit

Permalink
Jmax/lg 12239 Pii re-encryption edge case (#9995)
Browse files Browse the repository at this point in the history
We weren't gracefully handling the case where a user has a pending profile but no PII attached to it.
(This can happen for historical reasons)

changelog: Bug Fixes,PII re-encryption,fix edge-case bug.
  • Loading branch information
jmax-gsa authored Jan 30, 2024
1 parent da1311e commit 05bf73e
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 12 deletions.
15 changes: 13 additions & 2 deletions app/services/user_profiles_encryptor.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
class UserProfilesEncryptor
class MissingPiiError < StandardError
end

attr_reader :personal_key

def initialize(user:, user_session:, password:)
Expand All @@ -11,8 +14,13 @@ 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)
begin
encrypt_pii_for_profile(user.pending_profile)
rescue MissingPiiError
user.pending_profile.deactivate(:encryption_error)
end
end
end

Expand All @@ -21,7 +29,10 @@ def encrypt
attr_reader :user, :password, :user_session

def encrypt_pii_for_profile(profile)
pii = Pii::Cacher.new(user, user_session).fetch(profile.id)
pii_cache = Pii::Cacher.new(user, user_session)
pii = pii_cache.fetch(profile.id)
raise MissingPiiError unless pii

@personal_key = profile.encrypt_pii(pii, password)
profile.save!
end
Expand Down
30 changes: 20 additions & 10 deletions spec/services/user_profiles_encryptor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,35 @@

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(
let(:encryptor) do
UserProfilesEncryptor.new(
user: user,
user_session: user_session,
password: password,
)
encryptor.encrypt
end
let(:personal_key) { PersonalKeyGenerator.new(user).normalize(encryptor.personal_key) }
let(:decrypted_profile_pii) { profile.decrypt_pii(password) }
let(:decrypted_profile_recovery_pii) { profile.recover_pii(personal_key) }

it 'encrypts the PII for the pending profile with the password' do
encryptor.encrypt
profile.reload

personal_key = PersonalKeyGenerator.new(user).normalize(encryptor.personal_key)
expect(decrypted_profile_pii).to eq(pii)
expect(decrypted_profile_recovery_pii).to eq(pii)
expect(user.valid_personal_key?(personal_key)).to eq(true)
end

decrypted_profile_pii = profile.decrypt_pii(password)
decrypted_profile_recovery_pii = profile.recover_pii(personal_key)
context 'but the pending profile has no PII associated with it' do
before { user_session.delete(:encrypted_profiles) }

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)
it 'deactivates the profile with an encryption error' do
encryptor.encrypt
profile.reload

expect(profile.deactivation_reason).to eq('encryption_error')
end
end
end

Expand Down

0 comments on commit 05bf73e

Please sign in to comment.