From 9fe3af940218068ad4ebeda5040719ad4a98777d Mon Sep 17 00:00:00 2001 From: Ahmet Date: Mon, 29 Apr 2019 11:56:04 +0100 Subject: [PATCH 1/2] Override .attributes method on legacy EncryptedModel and adds .unencrypted_attributes method --- lib/vault/latest/encrypted_model.rb | 4 ++ lib/vault/legacy/encrypted_model.rb | 13 +++++ spec/unit/encrypted_model_spec.rb | 78 +++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/lib/vault/latest/encrypted_model.rb b/lib/vault/latest/encrypted_model.rb index 4a82e239..0d91cc87 100644 --- a/lib/vault/latest/encrypted_model.rb +++ b/lib/vault/latest/encrypted_model.rb @@ -390,6 +390,10 @@ def __vault_encrypt_attribute!(attribute, options, in_after_save: false) { column => ciphertext } end + def unencrypted_attributes + attributes.delete_if { |attr| attr.ends_with?('_encrypted') } + end + # Override the reload method to reload the Vault attributes. This will # ensure that we always have the most recent data from Vault when we # reload a record from the database. diff --git a/lib/vault/legacy/encrypted_model.rb b/lib/vault/legacy/encrypted_model.rb index ea40060d..34b8e0e2 100644 --- a/lib/vault/legacy/encrypted_model.rb +++ b/lib/vault/legacy/encrypted_model.rb @@ -286,6 +286,15 @@ def __vault_load_attributes! end end + def attributes + super.tap do |attrs| + missing_keys = self.class.__vault_attributes.keys.map(&:to_s) - attrs.keys + missing_keys.each do |key| + attrs.store(key, public_send(key)) + end + end + end + # Decrypt and load a single attribute from Vault. def __vault_load_attribute!(attribute, options) key = options[:key] @@ -370,6 +379,10 @@ def __vault_encrypt_attribute!(attribute, options) { column => ciphertext } end + def unencrypted_attributes + attributes.delete_if { |attr| attr.ends_with?('_encrypted') } + end + # Override the reload method to reload the Vault attributes. This will # ensure that we always have the most recent data from Vault when we # reload a record from the database. diff --git a/spec/unit/encrypted_model_spec.rb b/spec/unit/encrypted_model_spec.rb index dc5eb723..853f2b84 100644 --- a/spec/unit/encrypted_model_spec.rb +++ b/spec/unit/encrypted_model_spec.rb @@ -134,6 +134,84 @@ end end + describe '#attributes' do + let(:person) { Person.new } + + it 'returns all attributes' do + expect(person.attributes).to eq( + "business_card" => nil, + "business_card_encrypted" => nil, + "cc_encrypted" => nil, + "county" => nil, + "county_encrypted" => nil, + "county_plaintext" => nil, + "created_at" => nil, + "credit_card" => nil, + "date_of_birth" => nil, + "date_of_birth_encrypted" => nil, + "date_of_birth_plaintext" => nil, + "details" => nil, + "details_encrypted" => nil, + "driving_licence_number" => nil, + "driving_licence_number_encrypted" => nil, + "email" => nil, + "email_encrypted" => nil, + "favorite_color" => nil, + "favorite_color_encrypted" => nil, + "float_data" => nil, + "float_data_encrypted" => nil, + "id" => nil, + "integer_data" => nil, + "integer_data_encrypted" => nil, + "ip_address" => nil, + "ip_address_encrypted" => nil, + "name" => nil, + "non_ascii" => nil, + "non_ascii_encrypted" => nil, + "passport_number_encrypted" => nil, + "ssn" => nil, + "ssn_encrypted" => nil, + "state" => nil, + "state_encrypted" => nil, + "state_plaintext" => nil, + "time_data" => nil, + "time_data_encrypted" => nil, + "updated_at" => nil + ) + end + end + + describe '#unencrypted_attributes' do + let(:person) { Person.new } + + it 'returns all attributes apart from encrypted fields' do + expect(person.unencrypted_attributes).to eq( + 'business_card' => nil, + 'county' => nil, + 'county_plaintext' => nil, + 'created_at' => nil, + 'credit_card' => nil, + 'date_of_birth' => nil, + 'date_of_birth_plaintext' => nil, + 'details' => nil, + 'driving_licence_number' => nil, + 'email' => nil, + 'favorite_color' => nil, + 'float_data' => nil, + 'id' => nil, + 'integer_data' => nil, + 'ip_address' => nil, + 'name' => nil, + 'non_ascii' => nil, + 'ssn' => nil, + 'state' => nil, + 'state_plaintext' => nil, + 'time_data' => nil, + 'updated_at' => nil + ) + end + end + describe '#vault_persist_before_save!' do context "when not used" do # Person hasn't had `vault_persist_before_save!` called on it From 2263c4b41d3a80e8af2eb83c692ffd976037e467 Mon Sep 17 00:00:00 2001 From: Ahmet Abdi Date: Tue, 30 Apr 2019 09:37:38 +0100 Subject: [PATCH 2/2] Update unencrypted_attributes method to use vault_attributes for retrieving encryted_column --- lib/vault/latest/encrypted_model.rb | 3 ++- lib/vault/legacy/encrypted_model.rb | 3 ++- spec/dummy/app/models/person.rb | 4 +++- spec/unit/encrypted_model_spec.rb | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/vault/latest/encrypted_model.rb b/lib/vault/latest/encrypted_model.rb index 0d91cc87..8e884543 100644 --- a/lib/vault/latest/encrypted_model.rb +++ b/lib/vault/latest/encrypted_model.rb @@ -391,7 +391,8 @@ def __vault_encrypt_attribute!(attribute, options, in_after_save: false) end def unencrypted_attributes - attributes.delete_if { |attr| attr.ends_with?('_encrypted') } + encrypted_attributes = self.class.__vault_attributes.values.map {|x| x[:encrypted_column].to_s } + attributes.delete_if { |attribute| encrypted_attributes.include?(attribute) } end # Override the reload method to reload the Vault attributes. This will diff --git a/lib/vault/legacy/encrypted_model.rb b/lib/vault/legacy/encrypted_model.rb index 34b8e0e2..05b579f5 100644 --- a/lib/vault/legacy/encrypted_model.rb +++ b/lib/vault/legacy/encrypted_model.rb @@ -380,7 +380,8 @@ def __vault_encrypt_attribute!(attribute, options) end def unencrypted_attributes - attributes.delete_if { |attr| attr.ends_with?('_encrypted') } + encrypted_attributes = self.class.__vault_attributes.values.map {|x| x[:encrypted_column].to_s } + attributes.delete_if { |attribute| encrypted_attributes.include?(attribute) } end # Override the reload method to reload the Vault attributes. This will diff --git a/spec/dummy/app/models/person.rb b/spec/dummy/app/models/person.rb index ecfc720f..cfdc9567 100644 --- a/spec/dummy/app/models/person.rb +++ b/spec/dummy/app/models/person.rb @@ -3,9 +3,11 @@ class Person < ActiveRecord::Base include Vault::EncryptedModel - vault_attribute :date_of_birth_plaintext, type: :date + vault_attribute :date_of_birth_plaintext, type: :date, encrypted_column: :date_of_birth_encrypted vault_attribute_proxy :date_of_birth, :date_of_birth_plaintext + vault_attribute :passport_number, encrypted_column: :passport_number_encrypted + vault_attribute :county_plaintext, encrypted_column: :county_encrypted vault_attribute_proxy :county, :county_plaintext diff --git a/spec/unit/encrypted_model_spec.rb b/spec/unit/encrypted_model_spec.rb index 853f2b84..65734fe4 100644 --- a/spec/unit/encrypted_model_spec.rb +++ b/spec/unit/encrypted_model_spec.rb @@ -168,6 +168,7 @@ "name" => nil, "non_ascii" => nil, "non_ascii_encrypted" => nil, + 'passport_number' => nil, "passport_number_encrypted" => nil, "ssn" => nil, "ssn_encrypted" => nil, @@ -203,6 +204,7 @@ 'ip_address' => nil, 'name' => nil, 'non_ascii' => nil, + 'passport_number' => nil, 'ssn' => nil, 'state' => nil, 'state_plaintext' => nil,