attr_encrypted 1.3.3 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,59 +4,100 @@ if defined?(ActiveRecord::Base)
4
4
  module ActiveRecord
5
5
  def self.extended(base) # :nodoc:
6
6
  base.class_eval do
7
+
8
+ # https://github.com/attr-encrypted/attr_encrypted/issues/68
9
+ def reload_with_attr_encrypted(*args, &block)
10
+ result = reload_without_attr_encrypted(*args, &block)
11
+ self.class.encrypted_attributes.keys.each do |attribute_name|
12
+ instance_variable_set("@#{attribute_name}", nil)
13
+ end
14
+ result
15
+ end
16
+ alias_method_chain :reload, :attr_encrypted
17
+
7
18
  attr_encrypted_options[:encode] = true
19
+
8
20
  class << self
9
- alias_method :attr_encryptor, :attr_encrypted
10
21
  alias_method_chain :method_missing, :attr_encrypted
11
- alias_method :undefine_attribute_methods, :reset_column_information if ::ActiveRecord::VERSION::STRING < "3"
12
22
  end
13
23
 
14
24
  def perform_attribute_assignment(method, new_attributes, *args)
15
25
  return if new_attributes.blank?
16
- attributes = new_attributes.respond_to?(:with_indifferent_access) ? new_attributes.with_indifferent_access : new_attributes.symbolize_keys
17
- encrypted_attributes = self.class.encrypted_attributes.keys
18
- self.send method, attributes.except(*encrypted_attributes), *args
19
- self.send method, attributes.slice(*encrypted_attributes), *args
26
+
27
+ send method, new_attributes.reject { |k, _| self.class.encrypted_attributes.key?(k.to_sym) }, *args
28
+ send method, new_attributes.reject { |k, _| !self.class.encrypted_attributes.key?(k.to_sym) }, *args
20
29
  end
21
30
  private :perform_attribute_assignment
22
31
 
23
- if ::ActiveRecord::VERSION::STRING < "3.0" || ::ActiveRecord::VERSION::STRING > "3.1"
32
+ if ::ActiveRecord::VERSION::STRING > "3.1"
24
33
  def assign_attributes_with_attr_encrypted(*args)
25
34
  perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
26
35
  end
27
36
  alias_method_chain :assign_attributes, :attr_encrypted
28
- else
29
- def attributes_with_attr_encrypted=(*args)
30
- perform_attribute_assignment :attributes_without_attr_encrypted=, *args
31
- end
32
- alias_method_chain :attributes=, :attr_encrypted
33
37
  end
38
+
39
+ def attributes_with_attr_encrypted=(*args)
40
+ perform_attribute_assignment :attributes_without_attr_encrypted=, *args
41
+ end
42
+ alias_method_chain :attributes=, :attr_encrypted
34
43
  end
35
44
  end
36
45
 
37
46
  protected
38
47
 
39
- # Ensures the attribute methods for db fields have been defined before calling the original
40
48
  # <tt>attr_encrypted</tt> method
41
49
  def attr_encrypted(*attrs)
42
- define_attribute_methods rescue nil
43
50
  super
44
- undefine_attribute_methods
45
- attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
51
+ options = attrs.extract_options!
52
+ attr = attrs.pop
53
+ options.merge! encrypted_attributes[attr]
54
+
55
+ define_method("#{attr}_changed?") do
56
+ if send("#{options[:attribute]}_changed?")
57
+ send(attr) != send("#{attr}_was")
58
+ end
59
+ end
60
+
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)
69
+ end
70
+
71
+ alias_method "#{attr}_before_type_cast", attr
72
+ end
73
+
74
+ def attribute_instance_methods_as_symbols
75
+ # We add accessor methods of the db columns to the list of instance
76
+ # methods returned to let ActiveRecord define the accessor methods
77
+ # for the db columns
78
+
79
+ # Use with_connection so the connection doesn't stay pinned to the thread.
80
+ connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
81
+
82
+ if connected && table_exists?
83
+ columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
84
+ else
85
+ super
86
+ end
46
87
  end
47
88
 
48
- # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
89
+ # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
49
90
  # encrypted attributes
50
91
  #
51
92
  # NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
52
93
  #
53
- # This is useful for encrypting fields like email addresses. Your user's email addresses
94
+ # This is useful for encrypting fields like email addresses. Your user's email addresses
54
95
  # are encrypted in the database, but you can still look up a user by email for logging in
55
96
  #
56
97
  # Example
57
98
  #
58
99
  # class User < ActiveRecord::Base
59
- # attr_encrypted :email, :key => 'secret key'
100
+ # attr_encrypted :email, key: 'secret key'
60
101
  # end
61
102
  #
62
103
  # User.find_by_email_and_password('test@example.com', 'testing')
@@ -66,8 +107,9 @@ if defined?(ActiveRecord::Base)
66
107
  if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
67
108
  attribute_names = match.captures.last.split('_and_')
68
109
  attribute_names.each_with_index do |attribute, index|
69
- if attr_encrypted?(attribute)
110
+ if attr_encrypted?(attribute) && encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
70
111
  args[index] = send("encrypt_#{attribute}", args[index])
112
+ warn "DEPRECATION WARNING: This feature will be removed in the next major release."
71
113
  attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
72
114
  end
73
115
  end
@@ -79,5 +121,6 @@ if defined?(ActiveRecord::Base)
79
121
  end
80
122
  end
81
123
 
124
+ ActiveRecord::Base.extend AttrEncrypted
82
125
  ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
83
- end
126
+ end
@@ -11,6 +11,7 @@ if defined?(DataMapper)
11
11
 
12
12
  def included_with_attr_encrypted(base)
13
13
  included_without_attr_encrypted(base)
14
+ base.extend AttrEncrypted
14
15
  base.attr_encrypted_options[:encode] = true
15
16
  end
16
17
  end
@@ -9,5 +9,6 @@ if defined?(Sequel)
9
9
  end
10
10
  end
11
11
 
12
+ Sequel::Model.extend AttrEncrypted
12
13
  Sequel::Model.extend AttrEncrypted::Adapters::Sequel
13
14
  end
@@ -1,9 +1,9 @@
1
1
  module AttrEncrypted
2
2
  # Contains information about this gem's version
3
3
  module Version
4
- MAJOR = 1
5
- MINOR = 3
6
- PATCH = 3
4
+ MAJOR = 3
5
+ MINOR = 0
6
+ PATCH = 1
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
  #
@@ -1,15 +1,16 @@
1
- require File.expand_path('../test_helper', __FILE__)
1
+ require_relative 'test_helper'
2
2
 
3
- ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
3
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
4
4
 
5
5
  def create_tables
6
6
  silence_stream(STDOUT) do
7
- ActiveRecord::Schema.define(:version => 1) do
7
+ ActiveRecord::Schema.define(version: 1) do
8
8
  create_table :people do |t|
9
9
  t.string :encrypted_email
10
10
  t.string :password
11
11
  t.string :encrypted_credentials
12
12
  t.binary :salt
13
+ t.binary :key_iv
13
14
  t.string :encrypted_email_salt
14
15
  t.string :encrypted_credentials_salt
15
16
  t.string :encrypted_email_iv
@@ -23,8 +24,19 @@ def create_tables
23
24
  create_table :users do |t|
24
25
  t.string :login
25
26
  t.string :encrypted_password
27
+ t.string :encrypted_password_iv
26
28
  t.boolean :is_admin
27
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
28
40
  end
29
41
  end
30
42
  end
@@ -33,7 +45,6 @@ end
33
45
  create_tables
34
46
 
35
47
  ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
36
- ActiveRecord::Base.logger = Logger.new(nil) if ::ActiveRecord::VERSION::STRING < "3.0"
37
48
 
38
49
  if ::ActiveRecord::VERSION::STRING > "4.0"
39
50
  module Rack
@@ -47,22 +58,17 @@ end
47
58
 
48
59
  class Person < ActiveRecord::Base
49
60
  self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
50
- attr_encrypted :email, :key => SECRET_KEY
51
- attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY) }, :marshal => true
61
+ attr_encrypted :email, key: SECRET_KEY
62
+ attr_encrypted :credentials, key: Proc.new { |user| Encryptor.encrypt(value: user.salt, key: SECRET_KEY, iv: user.key_iv) }, marshal: true
52
63
 
53
- if ActiveRecord::VERSION::STRING < "3"
54
- def after_initialize
55
- initialize_salt_and_credentials
56
- end
57
- else
58
- after_initialize :initialize_salt_and_credentials
59
- end
64
+ after_initialize :initialize_salt_and_credentials
60
65
 
61
66
  protected
62
67
 
63
68
  def initialize_salt_and_credentials
69
+ self.key_iv ||= SecureRandom.random_bytes(12)
64
70
  self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15]
65
- self.credentials ||= { :username => 'example', :password => 'test' }
71
+ self.credentials ||= { username: 'example', password: 'test' }
66
72
  end
67
73
  end
68
74
 
@@ -70,48 +76,64 @@ class PersonWithValidation < Person
70
76
  validates_presence_of :email
71
77
  end
72
78
 
79
+ class PersonWithProcMode < Person
80
+ attr_encrypted :email, key: SECRET_KEY, mode: Proc.new { :per_attribute_iv_and_salt }
81
+ attr_encrypted :credentials, key: SECRET_KEY, mode: Proc.new { :single_iv_and_salt }, insecure_mode: true
82
+ end
83
+
73
84
  class Account < ActiveRecord::Base
74
85
  attr_accessor :key
75
- attr_encrypted :password, :key => Proc.new {|account| account.key}
86
+ attr_encrypted :password, key: Proc.new {|account| account.key}
76
87
  end
77
88
 
78
89
  class PersonWithSerialization < ActiveRecord::Base
79
90
  self.table_name = 'people'
80
- attr_encrypted :email, :key => 'a secret key'
91
+ attr_encrypted :email, key: SECRET_KEY
81
92
  serialize :password
82
93
  end
83
94
 
84
95
  class UserWithProtectedAttribute < ActiveRecord::Base
85
96
  self.table_name = 'users'
86
- attr_encrypted :password, :key => 'a secret key'
97
+ attr_encrypted :password, key: SECRET_KEY
87
98
  attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0"
88
99
  end
89
100
 
90
101
  class PersonUsingAlias < ActiveRecord::Base
91
102
  self.table_name = 'people'
92
- attr_encryptor :email, :key => 'a secret key'
103
+ attr_encryptor :email, key: SECRET_KEY
93
104
  end
94
105
 
95
- class ActiveRecordTest < Test::Unit::TestCase
106
+ class PrimeMinister < ActiveRecord::Base
107
+ attr_encrypted :name, marshal: true, key: SECRET_KEY
108
+ end
109
+
110
+ class Address < ActiveRecord::Base
111
+ self.attr_encrypted_options[:marshal] = false
112
+ self.attr_encrypted_options[:encode] = false
113
+ attr_encrypted :street, encode_iv: false, key: SECRET_KEY
114
+ attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true
115
+ end
116
+
117
+ class ActiveRecordTest < Minitest::Test
96
118
 
97
119
  def setup
98
120
  ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
99
121
  create_tables
100
- Account.create!(:key => SECRET_KEY, :password => "password")
122
+ Account.create!(key: SECRET_KEY, password: "password")
101
123
  end
102
124
 
103
125
  def test_should_encrypt_email
104
- @person = Person.create :email => 'test@example.com'
105
- assert_not_nil @person.encrypted_email
106
- assert_not_equal @person.email, @person.encrypted_email
107
- assert_equal @person.email, Person.find(:first).email
126
+ @person = Person.create(email: 'test@example.com')
127
+ refute_nil @person.encrypted_email
128
+ refute_equal @person.email, @person.encrypted_email
129
+ assert_equal @person.email, Person.first.email
108
130
  end
109
131
 
110
132
  def test_should_marshal_and_encrypt_credentials
111
133
  @person = Person.create
112
- assert_not_nil @person.encrypted_credentials
113
- assert_not_equal @person.credentials, @person.encrypted_credentials
114
- assert_equal @person.credentials, Person.find(:first).credentials
134
+ refute_nil @person.encrypted_credentials
135
+ refute_equal @person.credentials, @person.encrypted_credentials
136
+ assert_equal @person.credentials, Person.first.credentials
115
137
  end
116
138
 
117
139
  def test_should_encode_by_default
@@ -125,67 +147,103 @@ class ActiveRecordTest < Test::Unit::TestCase
125
147
  end
126
148
 
127
149
  def test_should_encrypt_decrypt_with_iv
128
- @person = Person.create :email => 'test@example.com'
150
+ @person = Person.create(email: 'test@example.com')
129
151
  @person2 = Person.find(@person.id)
130
- assert_not_nil @person2.encrypted_email_iv
152
+ refute_nil @person2.encrypted_email_iv
131
153
  assert_equal 'test@example.com', @person2.email
132
154
  end
133
155
 
134
156
  def test_should_ensure_attributes_can_be_deserialized
135
- @person = PersonWithSerialization.new :email => 'test@example.com', :password => %w(an array of strings)
157
+ @person = PersonWithSerialization.new(email: 'test@example.com', password: %w(an array of strings))
136
158
  @person.save
137
159
  assert_equal @person.password, %w(an array of strings)
138
160
  end
139
161
 
140
162
  def test_should_create_an_account_regardless_of_arguments_order
141
- Account.create!(:key => SECRET_KEY, :password => "password")
142
- Account.create!(:password => "password" , :key => SECRET_KEY)
163
+ Account.create!(key: SECRET_KEY, password: "password")
164
+ Account.create!(password: "password" , key: SECRET_KEY)
165
+ end
166
+
167
+ def test_should_set_attributes_regardless_of_arguments_order
168
+ # minitest does not implement `assert_nothing_raised` https://github.com/seattlerb/minitest/issues/112
169
+ Account.new.attributes = { password: "password", key: SECRET_KEY }
170
+ end
171
+
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
+ def test_should_create_changed_predicate
179
+ person = Person.create!(email: 'test@example.com')
180
+ refute person.email_changed?
181
+ person.email = 'test@example.com'
182
+ refute person.email_changed?
183
+ person.email = nil
184
+ assert person.email_changed?
185
+ person.email = 'test2@example.com'
186
+ assert person.email_changed?
187
+ end
188
+
189
+ def test_should_create_was_predicate
190
+ original_email = 'test@example.com'
191
+ person = Person.create!(email: original_email)
192
+ assert_equal original_email, person.email_was
193
+ person.email = 'test2@example.com'
194
+ assert_equal original_email, person.email_was
195
+ old_pm_name = "Winston Churchill"
196
+ pm = PrimeMinister.create!(name: old_pm_name)
197
+ assert_equal old_pm_name, pm.name_was
198
+ old_zipcode = "90210"
199
+ address = Address.create!(zipcode: old_zipcode, mode: "single_iv_and_salt")
200
+ assert_equal old_zipcode, address.zipcode_was
143
201
  end
144
202
 
145
203
  if ::ActiveRecord::VERSION::STRING > "4.0"
146
204
  def test_should_assign_attributes
147
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
148
- @user.attributes = ActionController::Parameters.new(:login => 'modified', :is_admin => true).permit(:login)
205
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
206
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
149
207
  assert_equal 'modified', @user.login
150
208
  end
151
209
 
152
210
  def test_should_not_assign_protected_attributes
153
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
154
- @user.attributes = ActionController::Parameters.new(:login => 'modified', :is_admin => true).permit(:login)
211
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
212
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
155
213
  assert !@user.is_admin?
156
214
  end
157
215
 
158
216
  def test_should_raise_exception_if_not_permitted
159
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
160
- assert_raise ActiveModel::ForbiddenAttributesError do
161
- @user.attributes = ActionController::Parameters.new(:login => 'modified', :is_admin => true)
217
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
218
+ assert_raises ActiveModel::ForbiddenAttributesError do
219
+ @user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true)
162
220
  end
163
221
  end
164
222
 
165
223
  def test_should_raise_exception_on_init_if_not_permitted
166
- assert_raise ActiveModel::ForbiddenAttributesError do
167
- @user = UserWithProtectedAttribute.new ActionController::Parameters.new(:login => 'modified', :is_admin => true)
224
+ assert_raises ActiveModel::ForbiddenAttributesError do
225
+ @user = UserWithProtectedAttribute.new ActionController::Parameters.new(login: 'modified', is_admin: true)
168
226
  end
169
227
  end
170
228
  else
171
229
  def test_should_assign_attributes
172
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
173
- @user.attributes = {:login => 'modified', :is_admin => true}
230
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
231
+ @user.attributes = { login: 'modified', is_admin: true }
174
232
  assert_equal 'modified', @user.login
175
233
  end
176
234
 
177
235
  def test_should_not_assign_protected_attributes
178
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
179
- @user.attributes = {:login => 'modified', :is_admin => true}
236
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
237
+ @user.attributes = { login: 'modified', is_admin: true }
180
238
  assert !@user.is_admin?
181
239
  end
182
240
 
183
241
  def test_should_assign_protected_attributes
184
- @user = UserWithProtectedAttribute.new :login => 'login', :is_admin => false
242
+ @user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
185
243
  if ::ActiveRecord::VERSION::STRING > "3.1"
186
- @user.send :assign_attributes, {:login => 'modified', :is_admin => true}, :without_protection => true
244
+ @user.send(:assign_attributes, { login: 'modified', is_admin: true }, without_protection: true)
187
245
  else
188
- @user.send :attributes=, {:login => 'modified', :is_admin => true}, false
246
+ @user.send(:attributes=, { login: 'modified', is_admin: true }, false)
189
247
  end
190
248
  assert @user.is_admin?
191
249
  end
@@ -196,6 +254,22 @@ class ActiveRecordTest < Test::Unit::TestCase
196
254
  assert_nil(@person.attributes = nil)
197
255
  end
198
256
 
257
+ def test_should_allow_proc_based_mode
258
+ @person = PersonWithProcMode.create(email: 'test@example.com', credentials: 'password123')
259
+
260
+ # Email is :per_attribute_iv_and_salt
261
+ assert_equal @person.class.encrypted_attributes[:email][:mode].class, Proc
262
+ assert_equal @person.class.encrypted_attributes[:email][:mode].call, :per_attribute_iv_and_salt
263
+ refute_nil @person.encrypted_email_salt
264
+ refute_nil @person.encrypted_email_iv
265
+
266
+ # Credentials is :single_iv_and_salt
267
+ assert_equal @person.class.encrypted_attributes[:credentials][:mode].class, Proc
268
+ assert_equal @person.class.encrypted_attributes[:credentials][:mode].call, :single_iv_and_salt
269
+ assert_nil @person.encrypted_credentials_salt
270
+ assert_nil @person.encrypted_credentials_iv
271
+ end
272
+
199
273
  if ::ActiveRecord::VERSION::STRING > "3.1"
200
274
  def test_should_allow_assign_attributes_with_nil
201
275
  @person = Person.new
@@ -203,15 +277,41 @@ class ActiveRecordTest < Test::Unit::TestCase
203
277
  end
204
278
  end
205
279
 
206
- class TestAlias < Test::Unit::TestCase
207
- def test_that_alias_encrypts_column
208
- user = PersonUsingAlias.new
209
- user.email = 'test@example.com'
210
- user.save
280
+ def test_that_alias_encrypts_column
281
+ user = PersonUsingAlias.new
282
+ user.email = 'test@example.com'
283
+ user.save
211
284
 
212
- assert_not_nil user.encrypted_email
213
- assert_not_equal user.email, user.encrypted_email
214
- assert_equal user.email, PersonUsingAlias.find(:first).email
215
- end
285
+ refute_nil user.encrypted_email
286
+ refute_equal user.email, user.encrypted_email
287
+ assert_equal user.email, PersonUsingAlias.first.email
288
+ end
289
+
290
+ # See https://github.com/attr-encrypted/attr_encrypted/issues/68
291
+ def test_should_invalidate_virtual_attributes_on_reload
292
+ old_pm_name = 'Winston Churchill'
293
+ new_pm_name = 'Neville Chamberlain'
294
+ pm = PrimeMinister.create!(name: old_pm_name)
295
+ assert_equal old_pm_name, pm.name
296
+ pm.name = new_pm_name
297
+ assert_equal new_pm_name, pm.name
298
+
299
+ result = pm.reload
300
+ assert_equal pm, result
301
+ assert_equal old_pm_name, pm.name
302
+ end
303
+
304
+ def test_should_save_encrypted_data_as_binary
305
+ street = '123 Elm'
306
+ address = Address.create!(street: street)
307
+ refute_equal address.encrypted_street, street
308
+ assert_equal Address.first.street, street
309
+ end
310
+
311
+ def test_should_evaluate_proc_based_mode
312
+ street = '123 Elm'
313
+ zipcode = '12345'
314
+ address = Address.new(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
315
+ assert_nil address.encrypted_zipcode_iv
216
316
  end
217
317
  end