diff --git a/lib/attr_encrypted/adapters/active_record.rb b/lib/attr_encrypted/adapters/active_record.rb index 5117d0cb..935aff71 100644 --- a/lib/attr_encrypted/adapters/active_record.rb +++ b/lib/attr_encrypted/adapters/active_record.rb @@ -1,3 +1,4 @@ +require 'byebug' if defined?(ActiveRecord::Base) module AttrEncrypted module Adapters @@ -51,10 +52,10 @@ def attr_encrypted(*attrs) super options = attrs.extract_options! attr = attrs.pop - # if ::ActiveRecord::VERSION::STRING >= "5.1.0" - # column_type = columns_hash[attr.to_s].type unless columns_hash[attr.to_s].nil? - # column_type.nil? ? attribute(attr) : attribute(attr, column_type) - # end + if ::ActiveRecord::VERSION::STRING >= "5.1.0" + column_type = columns_hash[attr.to_s].type unless columns_hash[attr.to_s].nil? + column_type.nil? ? attribute(attr) : attribute(attr, column_type) + end options.merge! encrypted_attributes[attr] define_method("#{attr}_was") do diff --git a/test/active_record_test.rb b/test/active_record_test.rb index 89134548..08b71dfd 100644 --- a/test/active_record_test.rb +++ b/test/active_record_test.rb @@ -1,6 +1,6 @@ require_relative 'test_helper' -ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') +ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'test.db') def create_tables ActiveRecord::Schema.define(version: 1) do @@ -41,6 +41,17 @@ def create_tables end end +def drop_tables + ActiveRecord::Schema.define(version: 1) do + self.verbose = false + drop_table :people, if_exists: true + drop_table :accounts, if_exists: true + drop_table :users, if_exists: true + drop_table :prime_ministers, if_exists: true + drop_table :addresses, if_exists: true + end +end + ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError) if ::ActiveRecord::VERSION::STRING > "4.0" @@ -53,7 +64,12 @@ class UploadedFile; end require 'action_controller/metal/strong_parameters' end -class Person < ActiveRecord::Base +class ActiveRecordTest < Minitest::Test + + drop_tables + create_tables + + class Person < ActiveRecord::Base self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt attr_encrypted :email, key: SECRET_KEY attr_encrypted :credentials, key: Proc.new { |user| Encryptor.encrypt(value: user.salt, key: SECRET_KEY, iv: user.key_iv) }, marshal: true @@ -67,67 +83,60 @@ def initialize_salt_and_credentials self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15] self.credentials ||= { username: 'example', password: 'test' } end -end + end -class PersonWithValidation < Person - validates_presence_of :email -end + class PersonWithValidation < Person + validates_presence_of :email + end -class PersonWithProcMode < Person - attr_encrypted :email, key: SECRET_KEY, mode: Proc.new { :per_attribute_iv_and_salt } - attr_encrypted :credentials, key: SECRET_KEY, mode: Proc.new { :single_iv_and_salt }, insecure_mode: true -end + class PersonWithProcMode < Person + attr_encrypted :email, key: SECRET_KEY, mode: Proc.new { :per_attribute_iv_and_salt } + attr_encrypted :credentials, key: SECRET_KEY, mode: Proc.new { :single_iv_and_salt }, insecure_mode: true + end -class Account < ActiveRecord::Base - ACCOUNT_ENCRYPTION_KEY = SecureRandom.urlsafe_base64(24) - attr_encrypted :password, key: :password_encryption_key + class Account < ActiveRecord::Base + ACCOUNT_ENCRYPTION_KEY = SecureRandom.urlsafe_base64(24) + attr_encrypted :password, key: :password_encryption_key - def encrypting?(attr) - encrypted_attributes[attr][:operation] == :encrypting - end + def encrypting?(attr) + encrypted_attributes[attr][:operation] == :encrypting + end - def password_encryption_key - if encrypting?(:password) - self.key = ACCOUNT_ENCRYPTION_KEY - else - self.key + def password_encryption_key + if encrypting?(:password) + self.key = ACCOUNT_ENCRYPTION_KEY + else + self.key + end end end -end - -class PersonWithSerialization < ActiveRecord::Base - self.table_name = 'people' - attr_encrypted :email, key: SECRET_KEY - serialize :password -end - -class UserWithProtectedAttribute < ActiveRecord::Base - self.table_name = 'users' - attr_encrypted :password, key: SECRET_KEY - attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0" -end -class PersonUsingAlias < ActiveRecord::Base - self.table_name = 'people' - attr_encryptor :email, key: SECRET_KEY -end + class PersonWithSerialization < ActiveRecord::Base + self.table_name = 'people' + attr_encrypted :email, key: SECRET_KEY + serialize :password + end -class PrimeMinister < ActiveRecord::Base - attr_encrypted :name, marshal: true, key: SECRET_KEY -end + class UserWithProtectedAttribute < ActiveRecord::Base + self.table_name = 'users' + attr_encrypted :password, key: SECRET_KEY + attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0" + end -class Address < ActiveRecord::Base - self.attr_encrypted_options[:marshal] = false - self.attr_encrypted_options[:encode] = false - attr_encrypted :street, encode_iv: false, key: SECRET_KEY - attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true -end + class PersonUsingAlias < ActiveRecord::Base + self.table_name = 'people' + attr_encryptor :email, key: SECRET_KEY + end -class ActiveRecordTest < Minitest::Test + class PrimeMinister < ActiveRecord::Base + attr_encrypted :name, marshal: true, key: SECRET_KEY + end - def setup - drop_all_tables - create_tables + class Address < ActiveRecord::Base + self.attr_encrypted_options[:marshal] = false + self.attr_encrypted_options[:encode] = false + attr_encrypted :street, encode_iv: false, key: SECRET_KEY + attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true end def test_should_encrypt_email @@ -162,6 +171,7 @@ def test_should_encrypt_decrypt_with_iv end def test_should_ensure_attributes_can_be_deserialized + debugger @person = PersonWithSerialization.new(email: 'test@example.com', password: %w(an array of strings)) @person.save assert_equal @person.password, %w(an array of strings) diff --git a/test/compatibility_test.rb b/test/compatibility_test.rb index 9440f316..622b3ab0 100644 --- a/test/compatibility_test.rb +++ b/test/compatibility_test.rb @@ -1,11 +1,47 @@ # -*- encoding: utf-8 -*- require_relative 'test_helper' +ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => 'test.db' + +def create_tables + ActiveRecord::Schema.define(:version => 1) do + create_table :nonmarshalling_pets do |t| + t.string :name + t.string :encrypted_nickname + t.string :encrypted_nickname_iv + t.string :encrypted_nickname_salt + t.string :encrypted_birthdate + t.string :encrypted_birthdate_iv + t.string :encrypted_birthdate_salt + end + create_table :marshalling_pets do |t| + t.string :name + t.string :encrypted_nickname + t.string :encrypted_nickname_iv + t.string :encrypted_nickname_salt + t.string :encrypted_birthdate + t.string :encrypted_birthdate_iv + t.string :encrypted_birthdate_salt + end + end +end + +def drop_tables + ActiveRecord::Schema.define(version: 1) do + self.verbose = false + drop_table :nonmarshalling_pets, if_exists: true + drop_table :marshalling_pets, if_exists: true + end +end + # Test to ensure that existing representations in database do not break on # migrating to new versions of this gem. This ensures that future versions of # this gem will retain backwards compatibility with data generated by earlier # versions. class CompatibilityTest < Minitest::Test + drop_tables + create_tables + class NonmarshallingPet < ActiveRecord::Base PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt') PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key' @@ -40,11 +76,6 @@ class MarshallingPet < ActiveRecord::Base :marshal => true end - def setup - drop_all_tables - create_tables - end - def test_nonmarshalling_backwards_compatibility pet = NonmarshallingPet.create!( :name => 'Fido', @@ -78,30 +109,4 @@ def test_marshalling_backwards_compatibility assert_equal Date.new(2011, 7, 9), pet.birthdate end - private - - def create_tables - ActiveRecord::Schema.define(:version => 1) do - create_table :nonmarshalling_pets do |t| - t.string :name - t.string :encrypted_nickname - t.string :encrypted_nickname_iv - t.string :encrypted_nickname_salt - t.string :encrypted_birthdate - t.string :encrypted_birthdate_iv - t.string :encrypted_birthdate_salt - end - create_table :marshalling_pets do |t| - t.string :name - t.string :encrypted_nickname - t.string :encrypted_nickname_iv - t.string :encrypted_nickname_salt - t.string :encrypted_birthdate - t.string :encrypted_birthdate_iv - t.string :encrypted_birthdate_salt - end - end - end end - -ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:' diff --git a/test/legacy_active_record_test.rb b/test/legacy_active_record_test.rb index 0c85fc22..7308f451 100644 --- a/test/legacy_active_record_test.rb +++ b/test/legacy_active_record_test.rb @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- require_relative 'test_helper' -ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:' +ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => 'test.db' def create_people_table ActiveRecord::Schema.define(:version => 1) do @@ -14,7 +14,14 @@ def create_people_table end end +def drop_tables + ActiveRecord::Schema.define(:version => 1) do + drop_table :legacy_people, if_exists: true + end +end + # The table needs to exist before defining the class +drop_tables create_people_table ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError) @@ -49,11 +56,6 @@ class LegacyPersonWithValidation < LegacyPerson class LegacyActiveRecordTest < Minitest::Test - def setup - drop_all_tables - create_people_table - end - def test_should_decrypt_with_correct_encoding if defined?(Encoding) @person = LegacyPerson.create :email => 'test@example.com' diff --git a/test/legacy_compatibility_test.rb b/test/legacy_compatibility_test.rb index 32e51350..e1b1027e 100644 --- a/test/legacy_compatibility_test.rb +++ b/test/legacy_compatibility_test.rb @@ -1,6 +1,35 @@ # -*- encoding: utf-8 -*- require_relative 'test_helper' +ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => 'test.db' + +def create_tables + ActiveRecord::Schema.define(:version => 1) do + create_table :legacy_nonmarshalling_pets do |t| + t.string :name + t.string :encrypted_nickname + t.string :encrypted_birthdate + t.string :salt + end + create_table :legacy_marshalling_pets do |t| + t.string :name + t.string :encrypted_nickname + t.string :encrypted_birthdate + t.string :salt + end + end +end + +def drop_tables + ActiveRecord::Schema.define(version: 1) do + drop_table :legacy_nonmarshalling_pets, if_exists: true + drop_table :legacy_marshalling_pets, if_exists: true + end +end + +drop_tables +create_tables + # Test to ensure that existing representations in database do not break on # migrating to new versions of this gem. This ensures that future versions of # this gem will retain backwards compatibility with data generated by earlier @@ -40,11 +69,6 @@ class LegacyMarshallingPet < ActiveRecord::Base :marshal => true end - def setup - drop_all_tables - create_tables - end - def test_nonmarshalling_backwards_compatibility pet = LegacyNonmarshallingPet.create!( :name => 'Fido', @@ -70,24 +94,5 @@ def test_marshalling_backwards_compatibility assert_equal Date.new(2011, 7, 9), pet.birthdate end - private - - def create_tables - ActiveRecord::Schema.define(:version => 1) do - create_table :legacy_nonmarshalling_pets do |t| - t.string :name - t.string :encrypted_nickname - t.string :encrypted_birthdate - t.string :salt - end - create_table :legacy_marshalling_pets do |t| - t.string :name - t.string :encrypted_nickname - t.string :encrypted_birthdate - t.string :salt - end - end - end end -ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'