attr_encrypted 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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