module AttrEncrypted::InstanceMethods

Public Instance Methods

decrypt(attribute, encrypted_value) click to toggle source

Decrypts a value for the attribute specified using options evaluated in the current object's scope

Example

class User
  attr_accessor :secret_key
  attr_encrypted :email, key: :secret_key

  def initialize(secret_key)
    self.secret_key = secret_key
  end
end

@user = User.new('some-secret-key')
@user.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
    # File lib/attr_encrypted.rb
326 def decrypt(attribute, encrypted_value)
327   encrypted_attributes[attribute.to_sym][:operation] = :decrypting
328   encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(encrypted_value)
329   self.class.decrypt(attribute, encrypted_value, evaluated_attr_encrypted_options_for(attribute))
330 end
encrypt(attribute, value) click to toggle source

Encrypts a value for the attribute specified using options evaluated in the current object's scope

Example

class User
  attr_accessor :secret_key
  attr_encrypted :email, key: :secret_key

  def initialize(secret_key)
    self.secret_key = secret_key
  end
end

@user = User.new('some-secret-key')
@user.encrypt(:email, 'test@example.com')
    # File lib/attr_encrypted.rb
347 def encrypt(attribute, value)
348   encrypted_attributes[attribute.to_sym][:operation] = :encrypting
349   encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(value)
350   self.class.encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
351 end
encrypted_attributes() click to toggle source

Copies the class level hash of encrypted attributes with virtual attribute names as keys and their corresponding options as values to the instance

    # File lib/attr_encrypted.rb
356 def encrypted_attributes
357   @encrypted_attributes ||= self.class.encrypted_attributes.dup
358 end

Protected Instance Methods

decode_salt_if_encoded(salt, encoding) click to toggle source
    # File lib/attr_encrypted.rb
442 def decode_salt_if_encoded(salt, encoding)
443   prefix = '_'
444   salt.slice(0).eql?(prefix) ? salt.slice(1..-1).unpack(encoding).first : salt
445 end
evaluate_attr_encrypted_option(option) click to toggle source

Evaluates symbol (method reference) or proc (responds to call) options

If the option is not a symbol or proc then the original option is returned

    # File lib/attr_encrypted.rb
388 def evaluate_attr_encrypted_option(option)
389   if option.is_a?(Symbol) && respond_to?(option, true)
390     send(option)
391   elsif option.respond_to?(:call)
392     option.call(self)
393   else
394     option
395   end
396 end
evaluated_attr_encrypted_options_for(attribute) click to toggle source

Returns attr_encrypted options evaluated in the current object's scope for the attribute specified

    # File lib/attr_encrypted.rb
363 def evaluated_attr_encrypted_options_for(attribute)
364   evaluated_options = Hash.new
365   attribute_option_value = encrypted_attributes[attribute.to_sym][:attribute]
366   encrypted_attributes[attribute.to_sym].map do |option, value|
367     evaluated_options[option] = evaluate_attr_encrypted_option(value)
368   end
369 
370   evaluated_options[:attribute] = attribute_option_value
371 
372   evaluated_options.tap do |options|
373     if options[:if] && !options[:unless] && options[:value_present] || options[:allow_empty_value]
374       unless options[:mode] == :single_iv_and_salt
375         load_iv_for_attribute(attribute, options)
376       end
377 
378       if options[:mode] == :per_attribute_iv_and_salt
379         load_salt_for_attribute(attribute, options)
380       end
381     end
382   end
383 end
generate_iv(algorithm) click to toggle source
    # File lib/attr_encrypted.rb
416 def generate_iv(algorithm)
417   algo = OpenSSL::Cipher.new(algorithm)
418   algo.encrypt
419   algo.random_iv
420 end
load_iv_for_attribute(attribute, options) click to toggle source
    # File lib/attr_encrypted.rb
398 def load_iv_for_attribute(attribute, options)
399   encrypted_attribute_name = options[:attribute]
400   encode_iv = options[:encode_iv]
401   iv = options[:iv] || send("#{encrypted_attribute_name}_iv")
402   if options[:operation] == :encrypting
403     begin
404       iv = generate_iv(options[:algorithm])
405       iv = [iv].pack(encode_iv) if encode_iv
406       send("#{encrypted_attribute_name}_iv=", iv)
407     rescue RuntimeError
408     end
409   end
410   if iv && !iv.empty?
411     iv = iv.unpack(encode_iv).first if encode_iv
412     options[:iv] = iv
413   end
414 end
load_salt_for_attribute(attribute, options) click to toggle source
    # File lib/attr_encrypted.rb
422 def load_salt_for_attribute(attribute, options)
423   encrypted_attribute_name = options[:attribute]
424   encode_salt = options[:encode_salt]
425   salt = options[:salt] || send("#{encrypted_attribute_name}_salt")
426   if options[:operation] == :encrypting
427     salt = SecureRandom.random_bytes
428     salt = prefix_and_encode_salt(salt, encode_salt) if encode_salt
429     send("#{encrypted_attribute_name}_salt=", salt)
430   end
431   if salt && !salt.empty?
432     salt = decode_salt_if_encoded(salt, encode_salt) if encode_salt
433     options[:salt] = salt
434   end
435 end
prefix_and_encode_salt(salt, encoding) click to toggle source
    # File lib/attr_encrypted.rb
437 def prefix_and_encode_salt(salt, encoding)
438   prefix = '_'
439   prefix + [salt].pack(encoding)
440 end