attr_encrypted 1.4.0 → 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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +6 -0
- data/.travis.yml +31 -0
- data/CHANGELOG.md +87 -0
- data/Gemfile +3 -0
- data/README.md +444 -0
- data/Rakefile +3 -15
- data/attr_encrypted.gemspec +63 -0
- data/certs/saghaulor.pem +21 -0
- data/checksum/attr_encrypted-3.0.0.gem.sha256 +1 -0
- data/checksum/attr_encrypted-3.0.0.gem.sha512 +1 -0
- data/checksum/attr_encrypted-3.0.1.gem.sha256 +1 -0
- data/checksum/attr_encrypted-3.0.1.gem.sha512 +1 -0
- data/checksum/attr_encrypted-3.0.2.gem.sha256 +1 -0
- data/checksum/attr_encrypted-3.0.2.gem.sha512 +1 -0
- data/lib/attr_encrypted/adapters/active_record.rb +38 -19
- data/lib/attr_encrypted/adapters/data_mapper.rb +1 -0
- data/lib/attr_encrypted/adapters/sequel.rb +1 -0
- data/lib/attr_encrypted/version.rb +3 -3
- data/lib/attr_encrypted.rb +198 -115
- data/test/active_record_test.rb +145 -88
- data/test/attr_encrypted_test.rb +101 -39
- data/test/compatibility_test.rb +37 -56
- data/test/data_mapper_test.rb +1 -1
- data/test/legacy_active_record_test.rb +17 -15
- data/test/legacy_attr_encrypted_test.rb +17 -16
- data/test/legacy_compatibility_test.rb +33 -44
- data/test/legacy_data_mapper_test.rb +6 -3
- data/test/legacy_sequel_test.rb +8 -4
- data/test/run.sh +12 -52
- data/test/sequel_test.rb +1 -1
- data/test/test_helper.rb +27 -17
- data.tar.gz.sig +0 -0
- metadata +75 -29
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -344
data/test/attr_encrypted_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
2
|
+
require_relative 'test_helper'
|
3
3
|
|
4
4
|
class SillyEncryptor
|
5
5
|
def self.silly_encrypt(options)
|
@@ -12,6 +12,7 @@ class SillyEncryptor
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class User
|
15
|
+
extend AttrEncrypted
|
15
16
|
self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
|
16
17
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
17
18
|
|
@@ -33,7 +34,8 @@ class User
|
|
33
34
|
attr_accessor :salt
|
34
35
|
attr_accessor :should_encrypt
|
35
36
|
|
36
|
-
def initialize
|
37
|
+
def initialize(email: nil)
|
38
|
+
self.email = email
|
37
39
|
self.salt = Time.now.to_i.to_s
|
38
40
|
self.should_encrypt = true
|
39
41
|
end
|
@@ -48,19 +50,40 @@ class Admin < User
|
|
48
50
|
end
|
49
51
|
|
50
52
|
class SomeOtherClass
|
53
|
+
extend AttrEncrypted
|
51
54
|
def self.call(object)
|
52
55
|
object.class
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
59
|
+
class YetAnotherClass
|
60
|
+
extend AttrEncrypted
|
61
|
+
self.attr_encrypted_options[:encode_iv] = false
|
62
|
+
|
63
|
+
attr_encrypted :email, :key => SECRET_KEY
|
64
|
+
attr_encrypted :phone_number, :key => SECRET_KEY, mode: Proc.new { |thing| thing.mode }, encode_iv: Proc.new { |thing| thing.encode_iv }, encode_salt: Proc.new { |thing| thing.encode_salt }
|
65
|
+
|
66
|
+
def initialize(email: nil, encode_iv: 'm', encode_salt: 'm', mode: :per_attribute_iv_and_salt)
|
67
|
+
self.email = email
|
68
|
+
@encode_iv = encode_iv
|
69
|
+
@encode_salt = encode_salt
|
70
|
+
@mode = mode
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :encode_iv, :encode_salt, :mode
|
74
|
+
end
|
75
|
+
|
56
76
|
class AttrEncryptedTest < Minitest::Test
|
77
|
+
def setup
|
78
|
+
@iv = SecureRandom.random_bytes(12)
|
79
|
+
end
|
57
80
|
|
58
81
|
def test_should_store_email_in_encrypted_attributes
|
59
82
|
assert User.encrypted_attributes.include?(:email)
|
60
83
|
end
|
61
84
|
|
62
85
|
def test_should_not_store_salt_in_encrypted_attributes
|
63
|
-
|
86
|
+
refute User.encrypted_attributes.include?(:salt)
|
64
87
|
end
|
65
88
|
|
66
89
|
def test_attr_encrypted_should_return_true_for_email
|
@@ -88,16 +111,16 @@ class AttrEncryptedTest < Minitest::Test
|
|
88
111
|
end
|
89
112
|
|
90
113
|
def test_should_not_encrypt_nil_value
|
91
|
-
assert_nil User.encrypt_email(nil)
|
114
|
+
assert_nil User.encrypt_email(nil, iv: @iv)
|
92
115
|
end
|
93
116
|
|
94
117
|
def test_should_not_encrypt_empty_string
|
95
|
-
assert_equal '', User.encrypt_email('')
|
118
|
+
assert_equal '', User.encrypt_email('', iv: @iv)
|
96
119
|
end
|
97
120
|
|
98
121
|
def test_should_encrypt_email
|
99
|
-
refute_nil User.encrypt_email('test@example.com')
|
100
|
-
refute_equal 'test@example.com', User.encrypt_email('test@example.com')
|
122
|
+
refute_nil User.encrypt_email('test@example.com', iv: @iv)
|
123
|
+
refute_equal 'test@example.com', User.encrypt_email('test@example.com', iv: @iv)
|
101
124
|
end
|
102
125
|
|
103
126
|
def test_should_encrypt_email_when_modifying_the_attr_writer
|
@@ -105,48 +128,52 @@ class AttrEncryptedTest < Minitest::Test
|
|
105
128
|
assert_nil @user.encrypted_email
|
106
129
|
@user.email = 'test@example.com'
|
107
130
|
refute_nil @user.encrypted_email
|
108
|
-
|
131
|
+
iv = @user.encrypted_email_iv.unpack('m').first
|
132
|
+
salt = @user.encrypted_email_salt[1..-1].unpack('m').first
|
133
|
+
assert_equal User.encrypt_email('test@example.com', iv: iv, salt: salt), @user.encrypted_email
|
109
134
|
end
|
110
135
|
|
111
136
|
def test_should_not_decrypt_nil_value
|
112
|
-
assert_nil User.decrypt_email(nil)
|
137
|
+
assert_nil User.decrypt_email(nil, iv: @iv)
|
113
138
|
end
|
114
139
|
|
115
140
|
def test_should_not_decrypt_empty_string
|
116
|
-
assert_equal '', User.decrypt_email('')
|
141
|
+
assert_equal '', User.decrypt_email('', iv: @iv)
|
117
142
|
end
|
118
143
|
|
119
144
|
def test_should_decrypt_email
|
120
|
-
encrypted_email = User.encrypt_email('test@example.com')
|
145
|
+
encrypted_email = User.encrypt_email('test@example.com', iv: @iv)
|
121
146
|
refute_equal 'test@test.com', encrypted_email
|
122
|
-
assert_equal 'test@example.com', User.decrypt_email(encrypted_email)
|
147
|
+
assert_equal 'test@example.com', User.decrypt_email(encrypted_email, iv: @iv)
|
123
148
|
end
|
124
149
|
|
125
150
|
def test_should_decrypt_email_when_reading
|
126
151
|
@user = User.new
|
127
152
|
assert_nil @user.email
|
128
|
-
|
153
|
+
iv = @user.encrypted_email_iv.unpack('m').first
|
154
|
+
salt = @user.encrypted_email_salt[1..-1].unpack('m').first
|
155
|
+
@user.encrypted_email = User.encrypt_email('test@example.com', iv: iv, salt: salt)
|
129
156
|
assert_equal 'test@example.com', @user.email
|
130
157
|
end
|
131
158
|
|
132
159
|
def test_should_encrypt_with_encoding
|
133
|
-
assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
|
160
|
+
assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
|
134
161
|
end
|
135
162
|
|
136
163
|
def test_should_decrypt_with_encoding
|
137
|
-
encrypted = User.encrypt_with_encoding('test')
|
138
|
-
assert_equal 'test', User.decrypt_with_encoding(encrypted)
|
139
|
-
assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
|
164
|
+
encrypted = User.encrypt_with_encoding('test', iv: @iv)
|
165
|
+
assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
|
166
|
+
assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
|
140
167
|
end
|
141
168
|
|
142
169
|
def test_should_encrypt_with_custom_encoding
|
143
|
-
assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
|
170
|
+
assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
|
144
171
|
end
|
145
172
|
|
146
173
|
def test_should_decrypt_with_custom_encoding
|
147
|
-
encrypted = User.encrypt_with_encoding('test')
|
148
|
-
assert_equal 'test', User.decrypt_with_encoding(encrypted)
|
149
|
-
assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
|
174
|
+
encrypted = User.encrypt_with_encoding('test', iv: @iv)
|
175
|
+
assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
|
176
|
+
assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
|
150
177
|
end
|
151
178
|
|
152
179
|
def test_should_encrypt_with_marshaling
|
@@ -164,7 +191,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
164
191
|
assert_nil @user.ssn_encrypted
|
165
192
|
@user.ssn = 'testing'
|
166
193
|
refute_nil @user.ssn_encrypted
|
167
|
-
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt )
|
194
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt.unpack("m").first )
|
168
195
|
assert_equal encrypted, @user.ssn_encrypted
|
169
196
|
end
|
170
197
|
|
@@ -173,7 +200,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
173
200
|
assert_nil @user.crypted_password_test
|
174
201
|
@user.password = 'testing'
|
175
202
|
refute_nil @user.crypted_password_test
|
176
|
-
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
|
203
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
|
177
204
|
assert_equal encrypted, @user.crypted_password_test
|
178
205
|
end
|
179
206
|
|
@@ -182,7 +209,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
182
209
|
assert_nil @user.crypted_password_test
|
183
210
|
@user.password = 'testing'
|
184
211
|
refute_nil @user.crypted_password_test
|
185
|
-
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
|
212
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
|
186
213
|
assert_equal encrypted, @user.crypted_password_test
|
187
214
|
end
|
188
215
|
|
@@ -201,23 +228,24 @@ class AttrEncryptedTest < Minitest::Test
|
|
201
228
|
end
|
202
229
|
|
203
230
|
def test_should_evaluate_a_symbol_option
|
204
|
-
assert_equal
|
231
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
|
205
232
|
end
|
206
233
|
|
207
234
|
def test_should_evaluate_a_proc_option
|
208
|
-
assert_equal
|
235
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
|
209
236
|
end
|
210
237
|
|
211
238
|
def test_should_evaluate_a_lambda_option
|
212
|
-
assert_equal
|
239
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
|
213
240
|
end
|
214
241
|
|
215
242
|
def test_should_evaluate_a_method_option
|
216
|
-
assert_equal
|
243
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
|
217
244
|
end
|
218
245
|
|
219
246
|
def test_should_return_a_string_option
|
220
|
-
|
247
|
+
class_string = 'SomeOtherClass'
|
248
|
+
assert_equal class_string, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
|
221
249
|
end
|
222
250
|
|
223
251
|
def test_should_encrypt_with_true_if
|
@@ -225,7 +253,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
225
253
|
assert_nil @user.encrypted_with_true_if
|
226
254
|
@user.with_true_if = 'testing'
|
227
255
|
refute_nil @user.encrypted_with_true_if
|
228
|
-
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt)
|
256
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt.unpack("m").first)
|
229
257
|
assert_equal encrypted, @user.encrypted_with_true_if
|
230
258
|
end
|
231
259
|
|
@@ -242,7 +270,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
242
270
|
assert_nil @user.encrypted_with_false_unless
|
243
271
|
@user.with_false_unless = 'testing'
|
244
272
|
refute_nil @user.encrypted_with_false_unless
|
245
|
-
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt)
|
273
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt.unpack("m").first)
|
246
274
|
assert_equal encrypted, @user.encrypted_with_false_unless
|
247
275
|
end
|
248
276
|
|
@@ -261,11 +289,6 @@ class AttrEncryptedTest < Minitest::Test
|
|
261
289
|
def test_should_always_reset_options
|
262
290
|
@user = User.new
|
263
291
|
@user.with_if_changed = "encrypt_stuff"
|
264
|
-
@user.stubs(:instance_variable_get).returns(nil)
|
265
|
-
@user.stubs(:instance_variable_set).raises("BadStuff")
|
266
|
-
assert_raises RuntimeError do
|
267
|
-
@user.with_if_changed
|
268
|
-
end
|
269
292
|
|
270
293
|
@user = User.new
|
271
294
|
@user.should_encrypt = false
|
@@ -275,9 +298,9 @@ class AttrEncryptedTest < Minitest::Test
|
|
275
298
|
end
|
276
299
|
|
277
300
|
def test_should_cast_values_as_strings_before_encrypting
|
278
|
-
string_encrypted_email = User.encrypt_email('3')
|
279
|
-
assert_equal string_encrypted_email, User.encrypt_email(3)
|
280
|
-
assert_equal '3', User.decrypt_email(string_encrypted_email)
|
301
|
+
string_encrypted_email = User.encrypt_email('3', iv: @iv)
|
302
|
+
assert_equal string_encrypted_email, User.encrypt_email(3, iv: @iv)
|
303
|
+
assert_equal '3', User.decrypt_email(string_encrypted_email, iv: @iv)
|
281
304
|
end
|
282
305
|
|
283
306
|
def test_should_create_query_accessor
|
@@ -296,12 +319,18 @@ class AttrEncryptedTest < Minitest::Test
|
|
296
319
|
refute_equal @user.encrypted_email_iv, @user.crypted_password_test_iv
|
297
320
|
end
|
298
321
|
|
322
|
+
def test_should_generate_iv_per_attribute_by_default
|
323
|
+
thing = YetAnotherClass.new(email: 'thing@thing.com')
|
324
|
+
refute_nil thing.encrypted_email_iv
|
325
|
+
end
|
326
|
+
|
299
327
|
def test_should_vary_iv_per_instance
|
300
328
|
@user1 = User.new
|
301
329
|
@user1.email = 'email@example.com'
|
302
330
|
@user2 = User.new
|
303
331
|
@user2.email = 'email@example.com'
|
304
332
|
refute_equal @user1.encrypted_email_iv, @user2.encrypted_email_iv
|
333
|
+
refute_equal @user1.encrypted_email, @user2.encrypted_email
|
305
334
|
end
|
306
335
|
|
307
336
|
def test_should_vary_salt_per_attribute
|
@@ -319,6 +348,11 @@ class AttrEncryptedTest < Minitest::Test
|
|
319
348
|
refute_equal @user1.encrypted_email_salt, @user2.encrypted_email_salt
|
320
349
|
end
|
321
350
|
|
351
|
+
def test_should_not_generate_salt_per_attribute_by_default
|
352
|
+
thing = YetAnotherClass.new(email: 'thing@thing.com')
|
353
|
+
assert_nil thing.encrypted_email_salt
|
354
|
+
end
|
355
|
+
|
322
356
|
def test_should_decrypt_second_record
|
323
357
|
@user1 = User.new
|
324
358
|
@user1.email = 'test@example.com'
|
@@ -328,4 +362,32 @@ class AttrEncryptedTest < Minitest::Test
|
|
328
362
|
|
329
363
|
assert_equal 'test@example.com', @user1.decrypt(:email, @user1.encrypted_email)
|
330
364
|
end
|
365
|
+
|
366
|
+
def test_should_specify_the_default_algorithm
|
367
|
+
assert YetAnotherClass.encrypted_attributes[:email][:algorithm]
|
368
|
+
assert_equal YetAnotherClass.encrypted_attributes[:email][:algorithm], 'aes-256-gcm'
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_should_not_encode_iv_when_encode_iv_is_false
|
372
|
+
email = 'thing@thing.com'
|
373
|
+
thing = YetAnotherClass.new(email: email)
|
374
|
+
refute thing.encrypted_email_iv =~ base64_encoding_regex
|
375
|
+
assert_equal thing.email, email
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_should_base64_encode_iv_by_default
|
379
|
+
phone_number = '555-555-5555'
|
380
|
+
thing = YetAnotherClass.new
|
381
|
+
thing.phone_number = phone_number
|
382
|
+
assert thing.encrypted_phone_number_iv =~ base64_encoding_regex
|
383
|
+
assert_equal thing.phone_number, phone_number
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_should_generate_unique_iv_for_every_encrypt_operation
|
387
|
+
user = User.new
|
388
|
+
user.email = 'initial_value@test.com'
|
389
|
+
original_iv = user.encrypted_email_iv
|
390
|
+
user.email = 'revised_value@test.com'
|
391
|
+
refute_equal original_iv, user.encrypted_email_iv
|
392
|
+
end
|
331
393
|
end
|
data/test/compatibility_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'test_helper'
|
3
3
|
|
4
4
|
# Test to ensure that existing representations in database do not break on
|
5
5
|
# migrating to new versions of this gem. This ensures that future versions of
|
@@ -13,11 +13,13 @@ class CompatibilityTest < Minitest::Test
|
|
13
13
|
PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
|
14
14
|
|
15
15
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
16
|
+
self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
|
17
|
+
self.attr_encrypted_options[:insecure_mode] = true
|
16
18
|
|
17
19
|
attr_encrypted :nickname,
|
18
|
-
:key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) }
|
20
|
+
:key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
|
19
21
|
attr_encrypted :birthdate,
|
20
|
-
:key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) }
|
22
|
+
:key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') }
|
21
23
|
end
|
22
24
|
|
23
25
|
class MarshallingPet < ActiveRecord::Base
|
@@ -27,12 +29,14 @@ class CompatibilityTest < Minitest::Test
|
|
27
29
|
PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
|
28
30
|
|
29
31
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
32
|
+
self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
|
33
|
+
self.attr_encrypted_options[:insecure_mode] = true
|
30
34
|
|
31
35
|
attr_encrypted :nickname,
|
32
|
-
:key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) },
|
36
|
+
:key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
|
33
37
|
:marshal => true
|
34
38
|
attr_encrypted :birthdate,
|
35
|
-
:key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) },
|
39
|
+
:key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY, insecure_mode: true, algorithm: 'aes-256-cbc') },
|
36
40
|
:marshal => true
|
37
41
|
end
|
38
42
|
|
@@ -58,69 +62,46 @@ class CompatibilityTest < Minitest::Test
|
|
58
62
|
end
|
59
63
|
|
60
64
|
def test_marshalling_backwards_compatibility
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
:encrypted_birthdate => '4nbCEzcj6CjLd3B9liKm9Q==',
|
71
|
-
:encrypted_birthdate_iv => 'Vt10PQZMrbamh/gmjSLdkQ==',
|
72
|
-
:encrypted_birthdate_salt => 'cfb245a3df76404f'
|
73
|
-
)
|
74
|
-
else
|
75
|
-
pet = MarshallingPet.create!(
|
76
|
-
:name => 'Fido',
|
77
|
-
:encrypted_nickname => 'EsQScJYkPw80vVGvKWkE37Px99HHpXPFjoEPTNa4rbs=',
|
78
|
-
:encrypted_nickname_iv => 'fNq1OZcGvty4KfcvGTcFSw==',
|
79
|
-
:encrypted_nickname_salt => '733b459b7d34c217',
|
80
|
-
:encrypted_birthdate => '+VUlKQGfNWkOgCwI4hv+3qlGIwh9h6cJ/ranJlaxvU+xxQdL3H3cOzTcI2rkYkdR',
|
81
|
-
:encrypted_birthdate_iv => 'Ka+zF/SwEYZKwVa24lvFfA==',
|
82
|
-
:encrypted_birthdate_salt => 'd5e892d5bbd81566'
|
83
|
-
)
|
84
|
-
end
|
65
|
+
pet = MarshallingPet.create!(
|
66
|
+
:name => 'Fido',
|
67
|
+
:encrypted_nickname => 'EsQScJYkPw80vVGvKWkE37Px99HHpXPFjoEPTNa4rbs=',
|
68
|
+
:encrypted_nickname_iv => 'fNq1OZcGvty4KfcvGTcFSw==',
|
69
|
+
:encrypted_nickname_salt => '733b459b7d34c217',
|
70
|
+
:encrypted_birthdate => '+VUlKQGfNWkOgCwI4hv+3qlGIwh9h6cJ/ranJlaxvU+xxQdL3H3cOzTcI2rkYkdR',
|
71
|
+
:encrypted_birthdate_iv => 'Ka+zF/SwEYZKwVa24lvFfA==',
|
72
|
+
:encrypted_birthdate_salt => 'd5e892d5bbd81566'
|
73
|
+
)
|
85
74
|
|
86
75
|
assert_equal 'Fido', pet.name
|
87
76
|
assert_equal 'Mummy\'s little helper', pet.nickname
|
88
77
|
|
89
|
-
|
90
|
-
if RUBY_VERSION < '1.9.3'
|
91
|
-
assert_equal '2011-07-09', pet.birthdate
|
92
|
-
else
|
93
|
-
assert_equal Date.new(2011, 7, 9), pet.birthdate
|
94
|
-
end
|
78
|
+
assert_equal Date.new(2011, 7, 9), pet.birthdate
|
95
79
|
end
|
96
80
|
|
97
81
|
private
|
98
82
|
|
99
83
|
def create_tables
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
t.string :encrypted_birthdate_salt
|
119
|
-
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
|
120
102
|
end
|
121
103
|
end
|
122
104
|
end
|
123
105
|
end
|
124
106
|
|
125
107
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
126
|
-
|
data/test/data_mapper_test.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'test_helper'
|
3
3
|
|
4
4
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
5
5
|
|
6
6
|
def create_people_table
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
@@ -22,8 +20,12 @@ create_people_table
|
|
22
20
|
ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
|
23
21
|
|
24
22
|
class LegacyPerson < ActiveRecord::Base
|
23
|
+
self.attr_encrypted_options[:insecure_mode] = true
|
24
|
+
self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
|
25
|
+
self.attr_encrypted_options[:mode] = :single_iv_and_salt
|
26
|
+
|
25
27
|
attr_encrypted :email, :key => 'a secret key'
|
26
|
-
attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
|
28
|
+
attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key', insecure_mode: true, algorithm: 'aes-256-cbc') }, :marshal => true
|
27
29
|
|
28
30
|
ActiveSupport::Deprecation.silenced = true
|
29
31
|
def after_initialize; end
|
@@ -55,7 +57,7 @@ class LegacyActiveRecordTest < Minitest::Test
|
|
55
57
|
def test_should_decrypt_with_correct_encoding
|
56
58
|
if defined?(Encoding)
|
57
59
|
@person = LegacyPerson.create :email => 'test@example.com'
|
58
|
-
assert_equal 'UTF-8', LegacyPerson.
|
60
|
+
assert_equal 'UTF-8', LegacyPerson.first.email.encoding.name
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
@@ -63,14 +65,14 @@ class LegacyActiveRecordTest < Minitest::Test
|
|
63
65
|
@person = LegacyPerson.create :email => 'test@example.com'
|
64
66
|
refute_nil @person.encrypted_email
|
65
67
|
refute_equal @person.email, @person.encrypted_email
|
66
|
-
assert_equal @person.email, LegacyPerson.
|
68
|
+
assert_equal @person.email, LegacyPerson.first.email
|
67
69
|
end
|
68
70
|
|
69
71
|
def test_should_marshal_and_encrypt_credentials
|
70
72
|
@person = LegacyPerson.create
|
71
73
|
refute_nil @person.encrypted_credentials
|
72
74
|
refute_equal @person.credentials, @person.encrypted_credentials
|
73
|
-
assert_equal @person.credentials, LegacyPerson.
|
75
|
+
assert_equal @person.credentials, LegacyPerson.first.credentials
|
74
76
|
end
|
75
77
|
|
76
78
|
def test_should_find_by_email
|
@@ -86,13 +88,13 @@ class LegacyActiveRecordTest < Minitest::Test
|
|
86
88
|
|
87
89
|
def test_should_scope_by_email
|
88
90
|
@person = LegacyPerson.create(:email => 'test@example.com')
|
89
|
-
assert_equal @person, LegacyPerson.scoped_by_email('test@example.com').
|
91
|
+
assert_equal @person, LegacyPerson.scoped_by_email('test@example.com').first rescue NoMethodError
|
90
92
|
end
|
91
93
|
|
92
94
|
def test_should_scope_by_email_and_password
|
93
95
|
LegacyPerson.create(:email => 'test@example.com', :password => 'invalid')
|
94
96
|
@person = LegacyPerson.create(:email => 'test@example.com', :password => 'test')
|
95
|
-
assert_equal @person, LegacyPerson.scoped_by_email_and_password('test@example.com', 'test').
|
97
|
+
assert_equal @person, LegacyPerson.scoped_by_email_and_password('test@example.com', 'test').first rescue NoMethodError
|
96
98
|
end
|
97
99
|
|
98
100
|
def test_should_encode_by_default
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require_relative 'test_helper'
|
3
3
|
|
4
4
|
class LegacySillyEncryptor
|
5
5
|
def self.silly_encrypt(options)
|
@@ -12,7 +12,11 @@ class LegacySillyEncryptor
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class LegacyUser
|
15
|
+
extend AttrEncrypted
|
15
16
|
self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
|
17
|
+
self.attr_encrypted_options[:insecure_mode] = true
|
18
|
+
self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
|
19
|
+
self.attr_encrypted_options[:mode] = :single_iv_and_salt
|
16
20
|
|
17
21
|
attr_encrypted :email, :without_encoding, :key => 'secret key'
|
18
22
|
attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
|
@@ -43,6 +47,7 @@ class LegacyAdmin < LegacyUser
|
|
43
47
|
end
|
44
48
|
|
45
49
|
class LegacySomeOtherClass
|
50
|
+
extend AttrEncrypted
|
46
51
|
def self.call(object)
|
47
52
|
object.class
|
48
53
|
end
|
@@ -174,7 +179,7 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
174
179
|
assert_nil @user.ssn_encrypted
|
175
180
|
@user.ssn = 'testing'
|
176
181
|
refute_nil @user.ssn_encrypted
|
177
|
-
assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt), @user.ssn_encrypted
|
182
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt, insecure_mode: true, algorithm: 'aes-256-cbc'), @user.ssn_encrypted
|
178
183
|
end
|
179
184
|
|
180
185
|
def test_should_evaluate_a_key_passed_as_a_proc
|
@@ -182,7 +187,7 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
182
187
|
assert_nil @user.crypted_password_test
|
183
188
|
@user.password = 'testing'
|
184
189
|
refute_nil @user.crypted_password_test
|
185
|
-
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser'), @user.crypted_password_test
|
190
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.crypted_password_test
|
186
191
|
end
|
187
192
|
|
188
193
|
def test_should_use_options_found_in_the_attr_encrypted_options_attribute
|
@@ -190,7 +195,7 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
190
195
|
assert_nil @user.crypted_password_test
|
191
196
|
@user.password = 'testing'
|
192
197
|
refute_nil @user.crypted_password_test
|
193
|
-
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser'), @user.crypted_password_test
|
198
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'LegacyUser', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.crypted_password_test
|
194
199
|
end
|
195
200
|
|
196
201
|
def test_should_inherit_encrypted_attributes
|
@@ -208,23 +213,24 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
208
213
|
end
|
209
214
|
|
210
215
|
def test_should_evaluate_a_symbol_option
|
211
|
-
assert_equal
|
216
|
+
assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
|
212
217
|
end
|
213
218
|
|
214
219
|
def test_should_evaluate_a_proc_option
|
215
|
-
assert_equal
|
220
|
+
assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
|
216
221
|
end
|
217
222
|
|
218
223
|
def test_should_evaluate_a_lambda_option
|
219
|
-
assert_equal
|
224
|
+
assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
|
220
225
|
end
|
221
226
|
|
222
227
|
def test_should_evaluate_a_method_option
|
223
|
-
assert_equal
|
228
|
+
assert_equal LegacySomeOtherClass, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, LegacySomeOtherClass.method(:call))
|
224
229
|
end
|
225
230
|
|
226
231
|
def test_should_return_a_string_option
|
227
|
-
|
232
|
+
class_string = 'LegacySomeOtherClass'
|
233
|
+
assert_equal class_string, LegacySomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
|
228
234
|
end
|
229
235
|
|
230
236
|
def test_should_encrypt_with_true_if
|
@@ -232,7 +238,7 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
232
238
|
assert_nil @user.encrypted_with_true_if
|
233
239
|
@user.with_true_if = 'testing'
|
234
240
|
refute_nil @user.encrypted_with_true_if
|
235
|
-
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_true_if
|
241
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.encrypted_with_true_if
|
236
242
|
end
|
237
243
|
|
238
244
|
def test_should_not_encrypt_with_false_if
|
@@ -248,7 +254,7 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
248
254
|
assert_nil @user.encrypted_with_false_unless
|
249
255
|
@user.with_false_unless = 'testing'
|
250
256
|
refute_nil @user.encrypted_with_false_unless
|
251
|
-
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_false_unless
|
257
|
+
assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key', insecure_mode: true, algorithm: 'aes-256-cbc'), @user.encrypted_with_false_unless
|
252
258
|
end
|
253
259
|
|
254
260
|
def test_should_not_encrypt_with_true_unless
|
@@ -266,11 +272,6 @@ class LegacyAttrEncryptedTest < Minitest::Test
|
|
266
272
|
def test_should_always_reset_options
|
267
273
|
@user = LegacyUser.new
|
268
274
|
@user.with_if_changed = "encrypt_stuff"
|
269
|
-
@user.stubs(:instance_variable_get).returns(nil)
|
270
|
-
@user.stubs(:instance_variable_set).raises("BadStuff")
|
271
|
-
assert_raises RuntimeError do
|
272
|
-
@user.with_if_changed
|
273
|
-
end
|
274
275
|
|
275
276
|
@user = LegacyUser.new
|
276
277
|
@user.should_encrypt = false
|