attr_encrypted 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac79c02884af5b1ee935a1f50d238f17d72346ff
4
- data.tar.gz: cfdf773acde0d0b7c752f972064237395ba57071
3
+ metadata.gz: 5c1a2bcf5e2b7fc8937e96cb0fcd99926bd98d1e
4
+ data.tar.gz: 40112aef07bda5ba8145b2fb634a9bdbfea34d7a
5
5
  SHA512:
6
- metadata.gz: 42303b9fe3e46f0ce59c52a6cdcbaf73a3f8b6457f30ab7cbc62c765e9decb2c6b6559fc36135ff81867f5497c7952a1f84d14b1ef70020226dac12bc0f4d68e
7
- data.tar.gz: 183ebc248cb0af6a621aa7edd471532634437a6367cc503810cd9409a94a04b60d6c7a186945bb533a3bf16f1e88c39f0e01c3da5e8afd00f95e5ea961b346d1
6
+ metadata.gz: cbb4fb1d4fa7e22f791139ab1b9a96324cbb8e07f7e8472561a3dd0ce1fcb0a7c048c0ba413b5bccb876dade09f9528ccc7d23caa4378de3da8ef2c540ba76ad
7
+ data.tar.gz: ef6b487235f2f92ccdf73de3c806b3b3f9161c2ebcd78b2102e1975edc3150cda28a7b458136a051100e939a271b2e92ca690cd38360ec5c43c9c33db22dc1f4
checksums.yaml.gz.sig CHANGED
Binary file
data/.travis.yml CHANGED
@@ -4,7 +4,7 @@ cache: bundler
4
4
  rvm:
5
5
  - 2.0
6
6
  - 2.1
7
- - 2.2
7
+ - 2.2.2
8
8
  - 2.3.0
9
9
  - rbx
10
10
  env:
@@ -14,8 +14,15 @@ env:
14
14
  - ACTIVERECORD=4.0.0
15
15
  - ACTIVERECORD=4.1.0
16
16
  - ACTIVERECORD=4.2.0
17
+ - ACTIVERECORD=5.0.0
17
18
  matrix:
18
19
  exclude:
20
+ - rvm: 2.0
21
+ env: ACTIVERECORD=5.0.0
22
+ - rvm: 2.1
23
+ env: ACTIVERECORD=5.0.0
24
+ - rvm: rbx
25
+ env: ACTIVERECORD=5.0.0
19
26
  allow_failures:
20
27
  - rvm: rbx
21
28
  fast_finish: true
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # attr_encrypted #
2
2
 
3
+ ## 3.0.3 ##
4
+ * Fixed: attr_was would decrypt the attribute upon every call. This is inefficient and introduces problems when the options change between decrypting an old value and encrypting a new value; for example, when rotating the encryption key. As such, the new approach caches the decrypted value of the old encrypted value such that the old options are no longer needed. (@johnny-lai) (@saghaulor)
5
+
6
+ ## 3.0.2 ##
7
+ * Changed: Removed alias_method_chain for compatibility with Rails v5.x (@grosser)
8
+ * Changed: Updated Travis build matrix to include Rails 5. (@saghaulor) (@connorshea)
9
+ * Changed: Removed `.silence_stream` from tests as it has been removed from Rails 5. (@sblackstone)
10
+
3
11
  ## 3.0.1 ##
4
12
  * Fixed: attr_was method no longer calls undefined methods. (@saghaulor)
5
13
 
data/README.md CHANGED
@@ -403,7 +403,7 @@ It is recommended that you implement a strategy to insure that you do not mix th
403
403
  attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: :is_decrypting?(:ssn)
404
404
 
405
405
  def is_decrypting?(attribute)
406
- encrypted_atributes[attribute][operation] == :decrypting
406
+ encrypted_attributes[attribute][:operation] == :decrypting
407
407
  end
408
408
  end
409
409
 
@@ -0,0 +1 @@
1
+ 33140af4b223177db7a19efb2fa38472a299a745b29ca1c5ba9d3fa947390b77
@@ -0,0 +1 @@
1
+ 0c467cab98b9b2eb331f9818323a90ae01392d6cb03cf1f32faccc954d0fc54be65f0fc7bf751b0fce57925eef1c9e2af90181bc40d81ad93e21d15a001c53c6
@@ -0,0 +1 @@
1
+ c1256b459336d4a2012a0d0c70ce5cd3dac46acb5e78da6f77f6f104cb1e8b7b
@@ -0,0 +1 @@
1
+ dca0c8a729974c0e26fde4cd4216c7d0f66d9eca9f6cf0ccca64999f5180a00bf7c05b630c1d420ec1673141a2923946e8bd28b12e711faf64a4cd42c7a3ac9e
@@ -6,19 +6,20 @@ if defined?(ActiveRecord::Base)
6
6
  base.class_eval do
7
7
 
8
8
  # https://github.com/attr-encrypted/attr_encrypted/issues/68
9
- def reload_with_attr_encrypted(*args, &block)
9
+ alias_method :reload_without_attr_encrypted, :reload
10
+ def reload(*args, &block)
10
11
  result = reload_without_attr_encrypted(*args, &block)
11
12
  self.class.encrypted_attributes.keys.each do |attribute_name|
12
13
  instance_variable_set("@#{attribute_name}", nil)
13
14
  end
14
15
  result
15
16
  end
16
- alias_method_chain :reload, :attr_encrypted
17
17
 
18
18
  attr_encrypted_options[:encode] = true
19
19
 
20
20
  class << self
21
- alias_method_chain :method_missing, :attr_encrypted
21
+ alias_method :method_missing_without_attr_encrypted, :method_missing
22
+ alias_method :method_missing, :method_missing_with_attr_encrypted
22
23
  end
23
24
 
24
25
  def perform_attribute_assignment(method, new_attributes, *args)
@@ -30,16 +31,16 @@ if defined?(ActiveRecord::Base)
30
31
  private :perform_attribute_assignment
31
32
 
32
33
  if ::ActiveRecord::VERSION::STRING > "3.1"
33
- def assign_attributes_with_attr_encrypted(*args)
34
+ alias_method :assign_attributes_without_attr_encrypted, :assign_attributes
35
+ def assign_attributes(*args)
34
36
  perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
35
37
  end
36
- alias_method_chain :assign_attributes, :attr_encrypted
37
38
  end
38
39
 
39
- def attributes_with_attr_encrypted=(*args)
40
+ alias_method :attributes_without_attr_encrypted=, :attributes=
41
+ def attributes=(*args)
40
42
  perform_attribute_assignment :attributes_without_attr_encrypted=, *args
41
43
  end
42
- alias_method_chain :attributes=, :attr_encrypted
43
44
  end
44
45
  end
45
46
 
@@ -52,22 +53,32 @@ if defined?(ActiveRecord::Base)
52
53
  attr = attrs.pop
53
54
  options.merge! encrypted_attributes[attr]
54
55
 
55
- define_method("#{attr}_changed?") do
56
- if send("#{options[:attribute]}_changed?")
57
- send(attr) != send("#{attr}_was")
56
+ define_method("#{attr}_was") do
57
+ attribute_was(attr)
58
+ end
59
+
60
+ if ::ActiveRecord::VERSION::STRING >= "4.1"
61
+ define_method("#{attr}_changed?") do |options = {}|
62
+ attribute_changed?(attr, options)
63
+ end
64
+ else
65
+ define_method("#{attr}_changed?") do
66
+ attribute_changed?(attr)
58
67
  end
59
68
  end
60
69
 
61
- define_method("#{attr}_was") do
62
- attr_was_options = { operation: :decrypting }
63
- attr_was_options[:iv]= send("#{options[:attribute]}_iv_was") if respond_to?("#{options[:attribute]}_iv_was")
64
- attr_was_options[:salt]= send("#{options[:attribute]}_salt_was") if respond_to?("#{options[:attribute]}_salt_was")
65
- encrypted_attributes[attr].merge!(attr_was_options)
66
- evaluated_options = evaluated_attr_encrypted_options_for(attr)
67
- [:iv, :salt, :operation].each { |key| encrypted_attributes[attr].delete(key) }
68
- self.class.decrypt(attr, send("#{options[:attribute]}_was"), evaluated_options)
70
+ define_method("#{attr}_change") do
71
+ attribute_change(attr)
72
+ end
73
+
74
+ define_method("#{attr}_with_dirtiness=") do |value|
75
+ attribute_will_change!(attr) if value != __send__(attr)
76
+ __send__("#{attr}_without_dirtiness=", value)
69
77
  end
70
78
 
79
+ alias_method "#{attr}_without_dirtiness=", "#{attr}="
80
+ alias_method "#{attr}=", "#{attr}_with_dirtiness="
81
+
71
82
  alias_method "#{attr}_before_type_cast", attr
72
83
  end
73
84
 
@@ -3,7 +3,7 @@ module AttrEncrypted
3
3
  module Version
4
4
  MAJOR = 3
5
5
  MINOR = 0
6
- PATCH = 1
6
+ PATCH = 3
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
@@ -3,40 +3,39 @@ require_relative 'test_helper'
3
3
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
4
4
 
5
5
  def create_tables
6
- silence_stream(STDOUT) do
7
- ActiveRecord::Schema.define(version: 1) do
8
- create_table :people do |t|
9
- t.string :encrypted_email
10
- t.string :password
11
- t.string :encrypted_credentials
12
- t.binary :salt
13
- t.binary :key_iv
14
- t.string :encrypted_email_salt
15
- t.string :encrypted_credentials_salt
16
- t.string :encrypted_email_iv
17
- t.string :encrypted_credentials_iv
18
- end
19
- create_table :accounts do |t|
20
- t.string :encrypted_password
21
- t.string :encrypted_password_iv
22
- t.string :encrypted_password_salt
23
- end
24
- create_table :users do |t|
25
- t.string :login
26
- t.string :encrypted_password
27
- t.string :encrypted_password_iv
28
- t.boolean :is_admin
29
- end
30
- create_table :prime_ministers do |t|
31
- t.string :encrypted_name
32
- t.string :encrypted_name_iv
33
- end
34
- create_table :addresses do |t|
35
- t.binary :encrypted_street
36
- t.binary :encrypted_street_iv
37
- t.binary :encrypted_zipcode
38
- t.string :mode
39
- end
6
+ ActiveRecord::Schema.define(version: 1) do
7
+ create_table :people do |t|
8
+ t.string :encrypted_email
9
+ t.string :password
10
+ t.string :encrypted_credentials
11
+ t.binary :salt
12
+ t.binary :key_iv
13
+ t.string :encrypted_email_salt
14
+ t.string :encrypted_credentials_salt
15
+ t.string :encrypted_email_iv
16
+ t.string :encrypted_credentials_iv
17
+ end
18
+ create_table :accounts do |t|
19
+ t.string :encrypted_password
20
+ t.string :encrypted_password_iv
21
+ t.string :encrypted_password_salt
22
+ t.binary :key
23
+ end
24
+ create_table :users do |t|
25
+ t.string :login
26
+ t.string :encrypted_password
27
+ t.string :encrypted_password_iv
28
+ t.boolean :is_admin
29
+ end
30
+ create_table :prime_ministers do |t|
31
+ t.string :encrypted_name
32
+ t.string :encrypted_name_iv
33
+ end
34
+ create_table :addresses do |t|
35
+ t.binary :encrypted_street
36
+ t.binary :encrypted_street_iv
37
+ t.binary :encrypted_zipcode
38
+ t.string :mode
40
39
  end
41
40
  end
42
41
  end
@@ -82,8 +81,20 @@ class PersonWithProcMode < Person
82
81
  end
83
82
 
84
83
  class Account < ActiveRecord::Base
85
- attr_accessor :key
86
- attr_encrypted :password, key: Proc.new {|account| account.key}
84
+ ACCOUNT_ENCRYPTION_KEY = SecureRandom.base64(32)
85
+ attr_encrypted :password, key: :password_encryption_key
86
+
87
+ def encrypting?(attr)
88
+ encrypted_attributes[attr][:operation] == :encrypting
89
+ end
90
+
91
+ def password_encryption_key
92
+ if encrypting?(:password)
93
+ self.key = ACCOUNT_ENCRYPTION_KEY
94
+ else
95
+ self.key
96
+ end
97
+ end
87
98
  end
88
99
 
89
100
  class PersonWithSerialization < ActiveRecord::Base
@@ -119,7 +130,6 @@ class ActiveRecordTest < Minitest::Test
119
130
  def setup
120
131
  ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
121
132
  create_tables
122
- Account.create!(key: SECRET_KEY, password: "password")
123
133
  end
124
134
 
125
135
  def test_should_encrypt_email
@@ -169,12 +179,6 @@ class ActiveRecordTest < Minitest::Test
169
179
  Account.new.attributes = { password: "password", key: SECRET_KEY }
170
180
  end
171
181
 
172
- def test_should_preserve_hash_key_type
173
- hash = { foo: 'bar' }
174
- account = Account.create!(key: hash)
175
- assert_equal account.key, hash
176
- end
177
-
178
182
  def test_should_create_changed_predicate
179
183
  person = Person.create!(email: 'test@example.com')
180
184
  refute person.email_changed?
@@ -200,6 +204,23 @@ class ActiveRecordTest < Minitest::Test
200
204
  assert_equal old_zipcode, address.zipcode_was
201
205
  end
202
206
 
207
+ def test_attribute_was_works_when_options_for_old_encrypted_value_are_different_than_options_for_new_encrypted_value
208
+ pw = 'password'
209
+ crypto_key = SecureRandom.base64(32)
210
+ old_iv = SecureRandom.random_bytes(12)
211
+ account = Account.create
212
+ encrypted_value = Encryptor.encrypt(value: pw, iv: old_iv, key: crypto_key)
213
+ Account.where(id: account.id).update_all(key: crypto_key, encrypted_password_iv: [old_iv].pack('m'), encrypted_password: [encrypted_value].pack('m'))
214
+ account = Account.find(account.id)
215
+ assert_equal pw, account.password
216
+ account.password = pw.reverse
217
+ assert_equal pw, account.password_was
218
+ account.save
219
+ account.reload
220
+ assert_equal Account::ACCOUNT_ENCRYPTION_KEY, account.key
221
+ assert_equal pw.reverse, account.password
222
+ end
223
+
203
224
  if ::ActiveRecord::VERSION::STRING > "4.0"
204
225
  def test_should_assign_attributes
205
226
  @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
@@ -81,26 +81,24 @@ class CompatibilityTest < Minitest::Test
81
81
  private
82
82
 
83
83
  def create_tables
84
- silence_stream(STDOUT) do
85
- ActiveRecord::Schema.define(:version => 1) do
86
- create_table :nonmarshalling_pets do |t|
87
- t.string :name
88
- t.string :encrypted_nickname
89
- t.string :encrypted_nickname_iv
90
- t.string :encrypted_nickname_salt
91
- t.string :encrypted_birthdate
92
- t.string :encrypted_birthdate_iv
93
- t.string :encrypted_birthdate_salt
94
- end
95
- create_table :marshalling_pets do |t|
96
- t.string :name
97
- t.string :encrypted_nickname
98
- t.string :encrypted_nickname_iv
99
- t.string :encrypted_nickname_salt
100
- t.string :encrypted_birthdate
101
- t.string :encrypted_birthdate_iv
102
- t.string :encrypted_birthdate_salt
103
- end
84
+ ActiveRecord::Schema.define(:version => 1) do
85
+ create_table :nonmarshalling_pets do |t|
86
+ t.string :name
87
+ t.string :encrypted_nickname
88
+ t.string :encrypted_nickname_iv
89
+ t.string :encrypted_nickname_salt
90
+ t.string :encrypted_birthdate
91
+ t.string :encrypted_birthdate_iv
92
+ t.string :encrypted_birthdate_salt
93
+ end
94
+ create_table :marshalling_pets do |t|
95
+ t.string :name
96
+ t.string :encrypted_nickname
97
+ t.string :encrypted_nickname_iv
98
+ t.string :encrypted_nickname_salt
99
+ t.string :encrypted_birthdate
100
+ t.string :encrypted_birthdate_iv
101
+ t.string :encrypted_birthdate_salt
104
102
  end
105
103
  end
106
104
  end
@@ -4,14 +4,12 @@ require_relative 'test_helper'
4
4
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
5
5
 
6
6
  def create_people_table
7
- silence_stream(STDOUT) do
8
- ActiveRecord::Schema.define(:version => 1) do
9
- create_table :legacy_people do |t|
10
- t.string :encrypted_email
11
- t.string :password
12
- t.string :encrypted_credentials
13
- t.string :salt
14
- end
7
+ ActiveRecord::Schema.define(:version => 1) do
8
+ create_table :legacy_people do |t|
9
+ t.string :encrypted_email
10
+ t.string :password
11
+ t.string :encrypted_credentials
12
+ t.string :salt
15
13
  end
16
14
  end
17
15
  end
@@ -73,20 +73,18 @@ class LegacyCompatibilityTest < Minitest::Test
73
73
  private
74
74
 
75
75
  def create_tables
76
- silence_stream(STDOUT) do
77
- ActiveRecord::Schema.define(:version => 1) do
78
- create_table :legacy_nonmarshalling_pets do |t|
79
- t.string :name
80
- t.string :encrypted_nickname
81
- t.string :encrypted_birthdate
82
- t.string :salt
83
- end
84
- create_table :legacy_marshalling_pets do |t|
85
- t.string :name
86
- t.string :encrypted_nickname
87
- t.string :encrypted_birthdate
88
- t.string :salt
89
- end
76
+ ActiveRecord::Schema.define(:version => 1) do
77
+ create_table :legacy_nonmarshalling_pets do |t|
78
+ t.string :name
79
+ t.string :encrypted_nickname
80
+ t.string :encrypted_birthdate
81
+ t.string :salt
82
+ end
83
+ create_table :legacy_marshalling_pets do |t|
84
+ t.string :name
85
+ t.string :encrypted_nickname
86
+ t.string :encrypted_birthdate
87
+ t.string :salt
90
88
  end
91
89
  end
92
90
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_encrypted
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
@@ -33,7 +33,7 @@ cert_chain:
33
33
  ZjeLmnSDiwL6doiP5IiwALH/dcHU67ck3NGf6XyqNwQrrmtPY0mv1WVVL4Uh+vYE
34
34
  kHoFzE2no0BfBg78Re8fY69P5yES5ncC
35
35
  -----END CERTIFICATE-----
36
- date: 2016-04-02 00:00:00.000000000 Z
36
+ date: 2016-07-22 00:00:00.000000000 Z
37
37
  dependencies:
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: encryptor
@@ -224,6 +224,10 @@ files:
224
224
  - certs/saghaulor.pem
225
225
  - checksum/attr_encrypted-3.0.0.gem.sha256
226
226
  - checksum/attr_encrypted-3.0.0.gem.sha512
227
+ - checksum/attr_encrypted-3.0.1.gem.sha256
228
+ - checksum/attr_encrypted-3.0.1.gem.sha512
229
+ - checksum/attr_encrypted-3.0.2.gem.sha256
230
+ - checksum/attr_encrypted-3.0.2.gem.sha512
227
231
  - lib/attr_encrypted.rb
228
232
  - lib/attr_encrypted/adapters/active_record.rb
229
233
  - lib/attr_encrypted/adapters/data_mapper.rb
metadata.gz.sig CHANGED
Binary file