attr_encrypted 1.3.4 → 2.0.0

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.
@@ -1,4 +1,4 @@
1
- require File.expand_path('../test_helper', __FILE__)
1
+ require_relative 'test_helper'
2
2
 
3
3
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
4
4
 
@@ -28,6 +28,12 @@ def create_tables
28
28
  create_table :prime_ministers do |t|
29
29
  t.string :encrypted_name
30
30
  end
31
+ create_table :addresses do |t|
32
+ t.binary :encrypted_street
33
+ t.binary :encrypted_street_iv
34
+ t.binary :encrypted_zipcode
35
+ t.string :mode
36
+ end
31
37
  end
32
38
  end
33
39
  end
@@ -36,7 +42,6 @@ end
36
42
  create_tables
37
43
 
38
44
  ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
39
- ActiveRecord::Base.logger = Logger.new(nil) if ::ActiveRecord::VERSION::STRING < "3.0"
40
45
 
41
46
  if ::ActiveRecord::VERSION::STRING > "4.0"
42
47
  module Rack
@@ -51,15 +56,9 @@ end
51
56
  class Person < ActiveRecord::Base
52
57
  self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
53
58
  attr_encrypted :email, :key => SECRET_KEY
54
- attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY) }, :marshal => true
59
+ attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY, iv: SecureRandom.random_bytes(12)) }, :marshal => true
55
60
 
56
- if ActiveRecord::VERSION::STRING < "3"
57
- def after_initialize
58
- initialize_salt_and_credentials
59
- end
60
- else
61
- after_initialize :initialize_salt_and_credentials
62
- end
61
+ after_initialize :initialize_salt_and_credentials
63
62
 
64
63
  protected
65
64
 
@@ -75,7 +74,7 @@ end
75
74
 
76
75
  class PersonWithProcMode < Person
77
76
  attr_encrypted :email, :key => SECRET_KEY, :mode => Proc.new { :per_attribute_iv_and_salt }
78
- attr_encrypted :credentials, :key => SECRET_KEY, :mode => Proc.new { :single_iv_and_salt }
77
+ attr_encrypted :credentials, :key => SECRET_KEY, :mode => Proc.new { :single_iv_and_salt }, insecure_mode: true
79
78
  end
80
79
 
81
80
  class Account < ActiveRecord::Base
@@ -85,23 +84,30 @@ end
85
84
 
86
85
  class PersonWithSerialization < ActiveRecord::Base
87
86
  self.table_name = 'people'
88
- attr_encrypted :email, :key => 'a secret key'
87
+ attr_encrypted :email, :key => SECRET_KEY
89
88
  serialize :password
90
89
  end
91
90
 
92
91
  class UserWithProtectedAttribute < ActiveRecord::Base
93
92
  self.table_name = 'users'
94
- attr_encrypted :password, :key => 'a secret key'
93
+ attr_encrypted :password, :key => SECRET_KEY
95
94
  attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0"
96
95
  end
97
96
 
98
97
  class PersonUsingAlias < ActiveRecord::Base
99
98
  self.table_name = 'people'
100
- attr_encryptor :email, :key => 'a secret key'
99
+ attr_encryptor :email, :key => SECRET_KEY
101
100
  end
102
101
 
103
102
  class PrimeMinister < ActiveRecord::Base
104
- attr_encrypted :name, :marshal => true, :key => 'SECRET_KEY'
103
+ attr_encrypted :name, :marshal => true, :key => SECRET_KEY
104
+ end
105
+
106
+ class Address < ActiveRecord::Base
107
+ self.attr_encrypted_options[:marshal] = false
108
+ self.attr_encrypted_options[:encode] = false
109
+ attr_encrypted :street, encode_iv: false, key: SECRET_KEY
110
+ attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true
105
111
  end
106
112
 
107
113
  class ActiveRecordTest < Minitest::Test
@@ -116,14 +122,14 @@ class ActiveRecordTest < Minitest::Test
116
122
  @person = Person.create :email => 'test@example.com'
117
123
  refute_nil @person.encrypted_email
118
124
  refute_equal @person.email, @person.encrypted_email
119
- assert_equal @person.email, Person.find(:first).email
125
+ assert_equal @person.email, Person.first.email
120
126
  end
121
127
 
122
128
  def test_should_marshal_and_encrypt_credentials
123
129
  @person = Person.create
124
130
  refute_nil @person.encrypted_credentials
125
131
  refute_equal @person.credentials, @person.encrypted_credentials
126
- assert_equal @person.credentials, Person.find(:first).credentials
132
+ assert_equal @person.credentials, Person.first.credentials
127
133
  end
128
134
 
129
135
  def test_should_encode_by_default
@@ -155,6 +161,7 @@ class ActiveRecordTest < Minitest::Test
155
161
  end
156
162
 
157
163
  def test_should_set_attributes_regardless_of_arguments_order
164
+ # minitest does not implement `assert_nothing_raised` https://github.com/seattlerb/minitest/issues/112
158
165
  Account.new.attributes = { :password => "password" , :key => SECRET_KEY }
159
166
  end
160
167
 
@@ -164,6 +171,21 @@ class ActiveRecordTest < Minitest::Test
164
171
  assert_equal account.key, hash
165
172
  end
166
173
 
174
+ def test_should_create_changed_predicate
175
+ person = Person.create!(:email => 'test@example.com')
176
+ assert !person.email_changed?
177
+ person.email = 'test2@example.com'
178
+ assert person.email_changed?
179
+ end
180
+
181
+ def test_should_create_was_predicate
182
+ original_email = 'test@example.com'
183
+ person = Person.create!(:email => original_email)
184
+ assert !person.email_was
185
+ person.email = 'test2@example.com'
186
+ assert_equal person.email_was, original_email
187
+ end
188
+
167
189
  if ::ActiveRecord::VERSION::STRING > "4.0"
168
190
  def test_should_assign_attributes
169
191
  @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
@@ -248,7 +270,7 @@ class ActiveRecordTest < Minitest::Test
248
270
 
249
271
  refute_nil user.encrypted_email
250
272
  refute_equal user.email, user.encrypted_email
251
- assert_equal user.email, PersonUsingAlias.find(:first).email
273
+ assert_equal user.email, PersonUsingAlias.first.email
252
274
  end
253
275
 
254
276
  # See https://github.com/attr-encrypted/attr_encrypted/issues/68
@@ -263,4 +285,19 @@ class ActiveRecordTest < Minitest::Test
263
285
  assert_equal pm, result
264
286
  assert_equal 'Winston Churchill', pm.name
265
287
  end
288
+
289
+ def test_should_save_encrypted_data_as_binary
290
+ street = '123 Elm'
291
+ address = Address.new(street: street)
292
+ address.save!
293
+ refute_equal address.encrypted_street, street
294
+ assert_equal Address.first.street, street
295
+ end
296
+
297
+ def test_should_evaluate_proc_based_mode
298
+ street = '123 Elm'
299
+ zipcode = '12345'
300
+ address = Address.new(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
301
+ assert_nil address.encrypted_zipcode_iv
302
+ end
266
303
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
- require File.expand_path('../test_helper', __FILE__)
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
- assert !User.encrypted_attributes.include?(:salt)
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
- assert_equal User.encrypt_email('test@example.com'), @user.encrypted_email
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
- @user.encrypted_email = User.encrypt_email('test@example.com')
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 Object, Object.new.send(:evaluate_attr_encrypted_option, :class)
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 Object, Object.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
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 Object, Object.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
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 Object, Object.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
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
- assert_equal 'Object', Object.new.send(:evaluate_attr_encrypted_option, 'Object')
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
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../test_helper', __FILE__)
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,40 +62,20 @@ class CompatibilityTest < Minitest::Test
58
62
  end
59
63
 
60
64
  def test_marshalling_backwards_compatibility
61
- # Marshalling formats changed significantly from Ruby 1.8.7 to 1.9.3.
62
- # Also, Date class did not correctly support marshalling pre-1.9.3, so here
63
- # we just marshal it as a string in the Ruby 1.8.7 case.
64
- if RUBY_VERSION < '1.9.3'
65
- pet = MarshallingPet.create!(
66
- :name => 'Fido',
67
- :encrypted_nickname => 'NhpLBIp3aKRzNZrUgUfVuceYi4x+8lE3wUsVCSI9BcU=',
68
- :encrypted_nickname_iv => 'wpQqrj3KN16fN6PsAerUTA==',
69
- :encrypted_nickname_salt => '8f1a62d274ca8a3a',
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
- # See earlier comment.
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
@@ -123,4 +107,3 @@ class CompatibilityTest < Minitest::Test
123
107
  end
124
108
 
125
109
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
126
-
@@ -1,4 +1,4 @@
1
- require File.expand_path('../test_helper', __FILE__)
1
+ require_relative 'test_helper'
2
2
 
3
3
  DataMapper.setup(:default, 'sqlite3::memory:')
4
4
 
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../test_helper', __FILE__)
2
+ require_relative 'test_helper'
3
3
 
4
4
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
5
5
 
@@ -22,8 +22,12 @@ create_people_table
22
22
  ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
23
23
 
24
24
  class LegacyPerson < ActiveRecord::Base
25
+ self.attr_encrypted_options[:insecure_mode] = true
26
+ self.attr_encrypted_options[:algorithm] = 'aes-256-cbc'
27
+ self.attr_encrypted_options[:mode] = :single_iv_and_salt
28
+
25
29
  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
30
+ 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
31
 
28
32
  ActiveSupport::Deprecation.silenced = true
29
33
  def after_initialize; end
@@ -55,7 +59,7 @@ class LegacyActiveRecordTest < Minitest::Test
55
59
  def test_should_decrypt_with_correct_encoding
56
60
  if defined?(Encoding)
57
61
  @person = LegacyPerson.create :email => 'test@example.com'
58
- assert_equal 'UTF-8', LegacyPerson.find(:first).email.encoding.name
62
+ assert_equal 'UTF-8', LegacyPerson.first.email.encoding.name
59
63
  end
60
64
  end
61
65
 
@@ -63,14 +67,14 @@ class LegacyActiveRecordTest < Minitest::Test
63
67
  @person = LegacyPerson.create :email => 'test@example.com'
64
68
  refute_nil @person.encrypted_email
65
69
  refute_equal @person.email, @person.encrypted_email
66
- assert_equal @person.email, LegacyPerson.find(:first).email
70
+ assert_equal @person.email, LegacyPerson.first.email
67
71
  end
68
72
 
69
73
  def test_should_marshal_and_encrypt_credentials
70
74
  @person = LegacyPerson.create
71
75
  refute_nil @person.encrypted_credentials
72
76
  refute_equal @person.credentials, @person.encrypted_credentials
73
- assert_equal @person.credentials, LegacyPerson.find(:first).credentials
77
+ assert_equal @person.credentials, LegacyPerson.first.credentials
74
78
  end
75
79
 
76
80
  def test_should_find_by_email
@@ -86,13 +90,13 @@ class LegacyActiveRecordTest < Minitest::Test
86
90
 
87
91
  def test_should_scope_by_email
88
92
  @person = LegacyPerson.create(:email => 'test@example.com')
89
- assert_equal @person, LegacyPerson.scoped_by_email('test@example.com').find(:first) rescue NoMethodError
93
+ assert_equal @person, LegacyPerson.scoped_by_email('test@example.com').first rescue NoMethodError
90
94
  end
91
95
 
92
96
  def test_should_scope_by_email_and_password
93
97
  LegacyPerson.create(:email => 'test@example.com', :password => 'invalid')
94
98
  @person = LegacyPerson.create(:email => 'test@example.com', :password => 'test')
95
- assert_equal @person, LegacyPerson.scoped_by_email_and_password('test@example.com', 'test').find(:first) rescue NoMethodError
99
+ assert_equal @person, LegacyPerson.scoped_by_email_and_password('test@example.com', 'test').first rescue NoMethodError
96
100
  end
97
101
 
98
102
  def test_should_encode_by_default