attr_encrypted 3.0.0 → 4.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.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +14 -16
  3. data/CHANGELOG.md +60 -14
  4. data/README.md +27 -9
  5. data/Rakefile +3 -0
  6. data/attr_encrypted.gemspec +6 -13
  7. data/checksum/attr_encrypted-3.0.0.gem.sha256 +1 -0
  8. data/checksum/attr_encrypted-3.0.0.gem.sha512 +1 -0
  9. data/checksum/attr_encrypted-3.0.1.gem.sha256 +1 -0
  10. data/checksum/attr_encrypted-3.0.1.gem.sha512 +1 -0
  11. data/checksum/attr_encrypted-3.0.2.gem.sha256 +1 -0
  12. data/checksum/attr_encrypted-3.0.2.gem.sha512 +1 -0
  13. data/checksum/attr_encrypted-3.0.3.gem.sha256 +1 -0
  14. data/checksum/attr_encrypted-3.0.3.gem.sha512 +1 -0
  15. data/checksum/attr_encrypted-3.1.0.gem.sha256 +1 -0
  16. data/checksum/attr_encrypted-3.1.0.gem.sha512 +1 -0
  17. data/lib/attr_encrypted/adapters/active_record.rb +58 -30
  18. data/lib/attr_encrypted/adapters/data_mapper.rb +3 -1
  19. data/lib/attr_encrypted/adapters/sequel.rb +3 -1
  20. data/lib/attr_encrypted/version.rb +3 -1
  21. data/lib/attr_encrypted.rb +160 -129
  22. data/test/active_record_test.rb +130 -104
  23. data/test/attr_encrypted_test.rb +113 -16
  24. data/test/compatibility_test.rb +21 -21
  25. data/test/data_mapper_test.rb +2 -0
  26. data/test/legacy_active_record_test.rb +9 -9
  27. data/test/legacy_attr_encrypted_test.rb +8 -6
  28. data/test/legacy_compatibility_test.rb +15 -15
  29. data/test/legacy_data_mapper_test.rb +2 -0
  30. data/test/legacy_sequel_test.rb +2 -0
  31. data/test/run.sh +15 -7
  32. data/test/sequel_test.rb +2 -0
  33. data/test/test_helper.rb +11 -5
  34. metadata +27 -50
  35. checksums.yaml.gz.sig +0 -0
  36. data/certs/saghaulor.pem +0 -21
  37. data.tar.gz.sig +0 -0
  38. metadata.gz.sig +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'encryptor'
2
4
 
3
5
  # Adds attr_accessors that encrypt and decrypt an object's attributes
@@ -8,7 +10,7 @@ module AttrEncrypted
8
10
  base.class_eval do
9
11
  include InstanceMethods
10
12
  attr_writer :attr_encrypted_options
11
- @attr_encrypted_options, @encrypted_attributes = {}, {}
13
+ @attr_encrypted_options, @attr_encrypted_encrypted_attributes = {}, {}
12
14
  end
13
15
  end
14
16
 
@@ -16,90 +18,93 @@ module AttrEncrypted
16
18
  #
17
19
  # Options (any other options you specify are passed to the Encryptor's encrypt and decrypt methods)
18
20
  #
19
- # attribute: The name of the referenced encrypted attribute. For example
20
- # <tt>attr_accessor :email, attribute: :ee</tt> would generate an
21
- # attribute named 'ee' to store the encrypted email. This is useful when defining
22
- # one attribute to encrypt at a time or when the :prefix and :suffix options
23
- # aren't enough.
24
- # Defaults to nil.
25
- #
26
- # prefix: A prefix used to generate the name of the referenced encrypted attributes.
27
- # For example <tt>attr_accessor :email, prefix: 'crypted_'</tt> would
28
- # generate attributes named 'crypted_email' to store the encrypted
29
- # email and password.
30
- # Defaults to 'encrypted_'.
31
- #
32
- # suffix: A suffix used to generate the name of the referenced encrypted attributes.
33
- # For example <tt>attr_accessor :email, prefix: '', suffix: '_encrypted'</tt>
34
- # would generate attributes named 'email_encrypted' to store the
35
- # encrypted email.
36
- # Defaults to ''.
37
- #
38
- # key: The encryption key. This option may not be required if
39
- # you're using a custom encryptor. If you pass a symbol
40
- # representing an instance method then the :key option
41
- # will be replaced with the result of the method before
42
- # being passed to the encryptor. Objects that respond
43
- # to :call are evaluated as well (including procs).
44
- # Any other key types will be passed directly to the encryptor.
45
- # Defaults to nil.
46
- #
47
- # encode: If set to true, attributes will be encoded as well as
48
- # encrypted. This is useful if you're planning on storing
49
- # the encrypted attributes in a database. The default
50
- # encoding is 'm' (base64), however this can be overwritten
51
- # by setting the :encode option to some other encoding
52
- # string instead of just 'true'. See
53
- # http://www.ruby-doc.org/core/classes/Array.html#M002245
54
- # for more encoding directives.
55
- # Defaults to false unless you're using it with ActiveRecord, DataMapper, or Sequel.
56
- #
57
- # encode_iv: Defaults to true.
58
-
59
- # encode_salt: Defaults to true.
60
- #
61
- # default_encoding: Defaults to 'm' (base64).
62
- #
63
- # marshal: If set to true, attributes will be marshaled as well
64
- # as encrypted. This is useful if you're planning on
65
- # encrypting something other than a string.
66
- # Defaults to false.
67
- #
68
- # marshaler: The object to use for marshaling.
69
- # Defaults to Marshal.
70
- #
71
- # dump_method: The dump method name to call on the <tt>:marshaler</tt> object to.
72
- # Defaults to 'dump'.
73
- #
74
- # load_method: The load method name to call on the <tt>:marshaler</tt> object.
75
- # Defaults to 'load'.
76
- #
77
- # encryptor: The object to use for encrypting.
78
- # Defaults to Encryptor.
79
- #
80
- # encrypt_method: The encrypt method name to call on the <tt>:encryptor</tt> object.
81
- # Defaults to 'encrypt'.
82
- #
83
- # decrypt_method: The decrypt method name to call on the <tt>:encryptor</tt> object.
84
- # Defaults to 'decrypt'.
85
- #
86
- # if: Attributes are only encrypted if this option evaluates
87
- # to true. If you pass a symbol representing an instance
88
- # method then the result of the method will be evaluated.
89
- # Any objects that respond to <tt>:call</tt> are evaluated as well.
90
- # Defaults to true.
91
- #
92
- # unless: Attributes are only encrypted if this option evaluates
93
- # to false. If you pass a symbol representing an instance
94
- # method then the result of the method will be evaluated.
95
- # Any objects that respond to <tt>:call</tt> are evaluated as well.
96
- # Defaults to false.
97
- #
98
- # mode: Selects encryption mode for attribute: choose <tt>:single_iv_and_salt</tt> for compatibility
99
- # with the old attr_encrypted API: the IV is derived from the encryption key by the underlying Encryptor class; salt is not used.
100
- # The <tt>:per_attribute_iv_and_salt</tt> mode uses a per-attribute IV and salt. The salt is used to derive a unique key per attribute.
101
- # A <tt>:per_attribute_iv</default> mode derives a unique IV per attribute; salt is not used.
102
- # Defaults to <tt>:per_attribute_iv</tt>.
21
+ # attribute: The name of the referenced encrypted attribute. For example
22
+ # <tt>attr_accessor :email, attribute: :ee</tt> would generate an
23
+ # attribute named 'ee' to store the encrypted email. This is useful when defining
24
+ # one attribute to encrypt at a time or when the :prefix and :suffix options
25
+ # aren't enough.
26
+ # Defaults to nil.
27
+ #
28
+ # prefix: A prefix used to generate the name of the referenced encrypted attributes.
29
+ # For example <tt>attr_accessor :email, prefix: 'crypted_'</tt> would
30
+ # generate attributes named 'crypted_email' to store the encrypted
31
+ # email and password.
32
+ # Defaults to 'encrypted_'.
33
+ #
34
+ # suffix: A suffix used to generate the name of the referenced encrypted attributes.
35
+ # For example <tt>attr_accessor :email, prefix: '', suffix: '_encrypted'</tt>
36
+ # would generate attributes named 'email_encrypted' to store the
37
+ # encrypted email.
38
+ # Defaults to ''.
39
+ #
40
+ # key: The encryption key. This option may not be required if
41
+ # you're using a custom encryptor. If you pass a symbol
42
+ # representing an instance method then the :key option
43
+ # will be replaced with the result of the method before
44
+ # being passed to the encryptor. Objects that respond
45
+ # to :call are evaluated as well (including procs).
46
+ # Any other key types will be passed directly to the encryptor.
47
+ # Defaults to nil.
48
+ #
49
+ # encode: If set to true, attributes will be encoded as well as
50
+ # encrypted. This is useful if you're planning on storing
51
+ # the encrypted attributes in a database. The default
52
+ # encoding is 'm' (base64), however this can be overwritten
53
+ # by setting the :encode option to some other encoding
54
+ # string instead of just 'true'. See
55
+ # http://www.ruby-doc.org/core/classes/Array.html#M002245
56
+ # for more encoding directives.
57
+ # Defaults to false unless you're using it with ActiveRecord, DataMapper, or Sequel.
58
+ #
59
+ # encode_iv: Defaults to true.
60
+
61
+ # encode_salt: Defaults to true.
62
+ #
63
+ # default_encoding: Defaults to 'm' (base64).
64
+ #
65
+ # marshal: If set to true, attributes will be marshaled as well
66
+ # as encrypted. This is useful if you're planning on
67
+ # encrypting something other than a string.
68
+ # Defaults to false.
69
+ #
70
+ # marshaler: The object to use for marshaling.
71
+ # Defaults to Marshal.
72
+ #
73
+ # dump_method: The dump method name to call on the <tt>:marshaler</tt> object to.
74
+ # Defaults to 'dump'.
75
+ #
76
+ # load_method: The load method name to call on the <tt>:marshaler</tt> object.
77
+ # Defaults to 'load'.
78
+ #
79
+ # encryptor: The object to use for encrypting.
80
+ # Defaults to Encryptor.
81
+ #
82
+ # encrypt_method: The encrypt method name to call on the <tt>:encryptor</tt> object.
83
+ # Defaults to 'encrypt'.
84
+ #
85
+ # decrypt_method: The decrypt method name to call on the <tt>:encryptor</tt> object.
86
+ # Defaults to 'decrypt'.
87
+ #
88
+ # if: Attributes are only encrypted if this option evaluates
89
+ # to true. If you pass a symbol representing an instance
90
+ # method then the result of the method will be evaluated.
91
+ # Any objects that respond to <tt>:call</tt> are evaluated as well.
92
+ # Defaults to true.
93
+ #
94
+ # unless: Attributes are only encrypted if this option evaluates
95
+ # to false. If you pass a symbol representing an instance
96
+ # method then the result of the method will be evaluated.
97
+ # Any objects that respond to <tt>:call</tt> are evaluated as well.
98
+ # Defaults to false.
99
+ #
100
+ # mode: Selects encryption mode for attribute: choose <tt>:single_iv_and_salt</tt> for compatibility
101
+ # with the old attr_encrypted API: the IV is derived from the encryption key by the underlying Encryptor class; salt is not used.
102
+ # The <tt>:per_attribute_iv_and_salt</tt> mode uses a per-attribute IV and salt. The salt is used to derive a unique key per attribute.
103
+ # A <tt>:per_attribute_iv</default> mode derives a unique IV per attribute; salt is not used.
104
+ # Defaults to <tt>:per_attribute_iv</tt>.
105
+ #
106
+ # allow_empty_value: Attributes which have nil or empty string values will not be encrypted unless this option
107
+ # has a truthy value.
103
108
  #
104
109
  # You can specify your own default options
105
110
  #
@@ -140,23 +145,26 @@ module AttrEncrypted
140
145
  encrypted_attribute_name = (options[:attribute] ? options[:attribute] : [options[:prefix], attribute, options[:suffix]].join).to_sym
141
146
 
142
147
  instance_methods_as_symbols = attribute_instance_methods_as_symbols
143
- attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
144
- attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
145
148
 
146
- iv_name = "#{encrypted_attribute_name}_iv".to_sym
147
- attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
148
- attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
149
+ if attribute_instance_methods_as_symbols_available?
150
+ attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
151
+ attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
152
+
153
+ iv_name = "#{encrypted_attribute_name}_iv".to_sym
154
+ attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
155
+ attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
149
156
 
150
- salt_name = "#{encrypted_attribute_name}_salt".to_sym
151
- attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
152
- attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
157
+ salt_name = "#{encrypted_attribute_name}_salt".to_sym
158
+ attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
159
+ attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
160
+ end
153
161
 
154
162
  define_method(attribute) do
155
- instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
163
+ instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", attr_encrypted_decrypt(attribute, send(encrypted_attribute_name)))
156
164
  end
157
165
 
158
166
  define_method("#{attribute}=") do |value|
159
- send("#{encrypted_attribute_name}=", encrypt(attribute, value))
167
+ send("#{encrypted_attribute_name}=", attr_encrypted_encrypt(attribute, value))
160
168
  instance_variable_set("@#{attribute}", value)
161
169
  end
162
170
 
@@ -165,7 +173,7 @@ module AttrEncrypted
165
173
  value.respond_to?(:empty?) ? !value.empty? : !!value
166
174
  end
167
175
 
168
- encrypted_attributes[attribute.to_sym] = options.merge(attribute: encrypted_attribute_name)
176
+ self.attr_encrypted_encrypted_attributes[attribute.to_sym] = options.merge(attribute: encrypted_attribute_name)
169
177
  end
170
178
  end
171
179
 
@@ -197,6 +205,7 @@ module AttrEncrypted
197
205
  decrypt_method: 'decrypt',
198
206
  mode: :per_attribute_iv,
199
207
  algorithm: 'aes-256-gcm',
208
+ allow_empty_value: false,
200
209
  }
201
210
  end
202
211
 
@@ -214,7 +223,7 @@ module AttrEncrypted
214
223
  # User.attr_encrypted?(:name) # false
215
224
  # User.attr_encrypted?(:email) # true
216
225
  def attr_encrypted?(attribute)
217
- encrypted_attributes.has_key?(attribute.to_sym)
226
+ attr_encrypted_encrypted_attributes.has_key?(attribute.to_sym)
218
227
  end
219
228
 
220
229
  # Decrypts a value for the attribute specified
@@ -225,10 +234,10 @@ module AttrEncrypted
225
234
  # attr_encrypted :email
226
235
  # end
227
236
  #
228
- # email = User.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
229
- def decrypt(attribute, encrypted_value, options = {})
230
- options = encrypted_attributes[attribute.to_sym].merge(options)
231
- if options[:if] && !options[:unless] && !encrypted_value.nil? && !(encrypted_value.is_a?(String) && encrypted_value.empty?)
237
+ # email = User.attr_encrypted_decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
238
+ def attr_encrypted_decrypt(attribute, encrypted_value, options = {})
239
+ options = attr_encrypted_encrypted_attributes[attribute.to_sym].merge(options)
240
+ if options[:if] && !options[:unless] && not_empty?(encrypted_value)
232
241
  encrypted_value = encrypted_value.unpack(options[:encode]).first if options[:encode]
233
242
  value = options[:encryptor].send(options[:decrypt_method], options.merge!(value: encrypted_value))
234
243
  if options[:marshal]
@@ -251,10 +260,10 @@ module AttrEncrypted
251
260
  # attr_encrypted :email
252
261
  # end
253
262
  #
254
- # encrypted_email = User.encrypt(:email, 'test@example.com')
255
- def encrypt(attribute, value, options = {})
256
- options = encrypted_attributes[attribute.to_sym].merge(options)
257
- if options[:if] && !options[:unless] && !value.nil? && !(value.is_a?(String) && value.empty?)
263
+ # encrypted_email = User.attr_encrypted_encrypt(:email, 'test@example.com')
264
+ def attr_encrypted_encrypt(attribute, value, options = {})
265
+ options = attr_encrypted_encrypted_attributes[attribute.to_sym].merge(options)
266
+ if options[:if] && !options[:unless] && (options[:allow_empty_value] || not_empty?(value))
258
267
  value = options[:marshal] ? options[:marshaler].send(options[:dump_method], value) : value.to_s
259
268
  encrypted_value = options[:encryptor].send(options[:encrypt_method], options.merge!(value: value))
260
269
  encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
@@ -264,6 +273,10 @@ module AttrEncrypted
264
273
  end
265
274
  end
266
275
 
276
+ def not_empty?(value)
277
+ !value.nil? && !(value.is_a?(String) && value.empty?)
278
+ end
279
+
267
280
  # Contains a hash of encrypted attributes with virtual attribute names as keys
268
281
  # and their corresponding options as values
269
282
  #
@@ -273,9 +286,9 @@ module AttrEncrypted
273
286
  # attr_encrypted :email, key: 'my secret key'
274
287
  # end
275
288
  #
276
- # User.encrypted_attributes # { email: { attribute: 'encrypted_email', key: 'my secret key' } }
277
- def encrypted_attributes
278
- @encrypted_attributes ||= superclass.encrypted_attributes.dup
289
+ # User.attr_encrypted_encrypted_attributes # { email: { attribute: 'encrypted_email', key: 'my secret key' } }
290
+ def attr_encrypted_encrypted_attributes
291
+ @attr_encrypted_encrypted_attributes ||= superclass.attr_encrypted_encrypted_attributes.dup
279
292
  end
280
293
 
281
294
  # Forwards calls to :encrypt_#{attribute} or :decrypt_#{attribute} to the corresponding encrypt or decrypt method
@@ -290,7 +303,7 @@ module AttrEncrypted
290
303
  # User.encrypt_email('SOME_ENCRYPTED_EMAIL_STRING')
291
304
  def method_missing(method, *arguments, &block)
292
305
  if method.to_s =~ /^((en|de)crypt)_(.+)$/ && attr_encrypted?($3)
293
- send($1, $3, *arguments)
306
+ send("attr_encrypted_#{$1}", $3, *arguments)
294
307
  else
295
308
  super
296
309
  end
@@ -312,9 +325,10 @@ module AttrEncrypted
312
325
  #
313
326
  # @user = User.new('some-secret-key')
314
327
  # @user.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
315
- def decrypt(attribute, encrypted_value)
316
- encrypted_attributes[attribute.to_sym][:operation] = :decrypting
317
- self.class.decrypt(attribute, encrypted_value, evaluated_attr_encrypted_options_for(attribute))
328
+ def attr_encrypted_decrypt(attribute, encrypted_value)
329
+ attr_encrypted_encrypted_attributes[attribute.to_sym][:operation] = :decrypting
330
+ attr_encrypted_encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(encrypted_value)
331
+ self.class.attr_encrypted_decrypt(attribute, encrypted_value, evaluated_attr_encrypted_options_for(attribute))
318
332
  end
319
333
 
320
334
  # Encrypts a value for the attribute specified using options evaluated in the current object's scope
@@ -331,17 +345,22 @@ module AttrEncrypted
331
345
  # end
332
346
  #
333
347
  # @user = User.new('some-secret-key')
334
- # @user.encrypt(:email, 'test@example.com')
335
- def encrypt(attribute, value)
336
- encrypted_attributes[attribute.to_sym][:operation] = :encrypting
337
- self.class.encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
348
+ # @user.attr_encrypted_encrypt(:email, 'test@example.com')
349
+ def attr_encrypted_encrypt(attribute, value)
350
+ attr_encrypted_encrypted_attributes[attribute.to_sym][:operation] = :encrypting
351
+ attr_encrypted_encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(value)
352
+ self.class.attr_encrypted_encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
338
353
  end
339
354
 
340
355
  # Copies the class level hash of encrypted attributes with virtual attribute names as keys
341
356
  # and their corresponding options as values to the instance
342
357
  #
343
- def encrypted_attributes
344
- @encrypted_attributes ||= self.class.encrypted_attributes.dup
358
+ def attr_encrypted_encrypted_attributes
359
+ @attr_encrypted_encrypted_attributes ||= begin
360
+ duplicated= {}
361
+ self.class.attr_encrypted_encrypted_attributes.map { |key, value| duplicated[key] = value.dup }
362
+ duplicated
363
+ end
345
364
  end
346
365
 
347
366
  protected
@@ -349,20 +368,28 @@ module AttrEncrypted
349
368
  # Returns attr_encrypted options evaluated in the current object's scope for the attribute specified
350
369
  def evaluated_attr_encrypted_options_for(attribute)
351
370
  evaluated_options = Hash.new
352
- attribute_option_value = encrypted_attributes[attribute.to_sym][:attribute]
353
- encrypted_attributes[attribute.to_sym].map do |option, value|
354
- evaluated_options[option] = evaluate_attr_encrypted_option(value)
371
+ attributes = attr_encrypted_encrypted_attributes[attribute.to_sym]
372
+ attribute_option_value = attributes[:attribute]
373
+
374
+ [:if, :unless, :value_present, :allow_empty_value].each do |option|
375
+ evaluated_options[option] = evaluate_attr_encrypted_option(attributes[option])
355
376
  end
356
377
 
357
378
  evaluated_options[:attribute] = attribute_option_value
358
379
 
359
380
  evaluated_options.tap do |options|
360
- unless options[:mode] == :single_iv_and_salt
361
- load_iv_for_attribute(attribute, options)
362
- end
363
-
364
- if options[:mode] == :per_attribute_iv_and_salt
365
- load_salt_for_attribute(attribute, options)
381
+ if options[:if] && !options[:unless] && options[:value_present] || options[:allow_empty_value]
382
+ (attributes.keys - evaluated_options.keys).each do |option|
383
+ options[option] = evaluate_attr_encrypted_option(attributes[option])
384
+ end
385
+
386
+ unless options[:mode] == :single_iv_and_salt
387
+ load_iv_for_attribute(attribute, options)
388
+ end
389
+
390
+ if options[:mode] == :per_attribute_iv_and_salt
391
+ load_salt_for_attribute(attribute, options)
392
+ end
366
393
  end
367
394
  end
368
395
  end
@@ -371,7 +398,7 @@ module AttrEncrypted
371
398
  #
372
399
  # If the option is not a symbol or proc then the original option is returned
373
400
  def evaluate_attr_encrypted_option(option)
374
- if option.is_a?(Symbol) && respond_to?(option)
401
+ if option.is_a?(Symbol) && respond_to?(option, true)
375
402
  send(option)
376
403
  elsif option.respond_to?(:call)
377
404
  option.call(self)
@@ -408,7 +435,7 @@ module AttrEncrypted
408
435
  encrypted_attribute_name = options[:attribute]
409
436
  encode_salt = options[:encode_salt]
410
437
  salt = options[:salt] || send("#{encrypted_attribute_name}_salt")
411
- if (salt == nil)
438
+ if options[:operation] == :encrypting
412
439
  salt = SecureRandom.random_bytes
413
440
  salt = prefix_and_encode_salt(salt, encode_salt) if encode_salt
414
441
  send("#{encrypted_attribute_name}_salt=", salt)
@@ -436,6 +463,10 @@ module AttrEncrypted
436
463
  instance_methods.collect { |method| method.to_sym }
437
464
  end
438
465
 
466
+ def attribute_instance_methods_as_symbols_available?
467
+ true
468
+ end
469
+
439
470
  end
440
471
 
441
472