Class: ActiveRecord::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/symmetric_encryption/extensions/active_record/base.rb

Class Method Summary collapse

Class Method Details

.attr_encrypted(*params) ⇒ Object

Drop in replacement for attr_encrypted gem, except that it uses SymmetricEncryption for managing the encryption key

Parameters:

  • Symbolic names of each method to create which has a corresponding method already defined in rails starting with: encrypted_

  • Followed by an optional hash:

    :random_iv [true|false]
      Whether the encrypted value should use a random IV every time the
      field is encrypted.
      It is recommended to set this to true where feasible. If the encrypted
      value could be used as part of a SQL where clause, or as part
      of any lookup, then it must be false.
      Setting random_iv to true will result in a different encrypted output for
      the same input string.
      Note: Only set to true if the field will never be used as part of
        the where clause in an SQL query.
      Note: When random_iv is true it will add a 8 byte header, plus the bytes
        to store the random IV in every returned encrypted string, prior to the
        encoding if any.
      Default: false
      Highly Recommended where feasible: true
    
    :type [Symbol]
      The type for this field, #see SymmetricEncryption::COERCION_TYPES
      Default: :string
    
    :compress [true|false]
      Whether to compress str before encryption
      Should only be used for large strings since compression overhead and
      the overhead of adding the 'magic' header may exceed any benefits of
      compression
      Note: Adds a 6 byte header prior to encoding, only if :random_iv is false
      Default: false
    


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 39

def attr_encrypted(*params)
  # Ensure ActiveRecord has created all its methods first
  # Ignore failures since the table may not yet actually exist
  define_attribute_methods rescue nil

  options   = params.last.is_a?(Hash) ? params.pop.dup : {}
  random_iv = options.delete(:random_iv) || false
  compress  = options.delete(:compress) || false
  type      = options.delete(:type) || :string

  raise "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}" unless SymmetricEncryption::COERCION_TYPES.include?(type)

  # For backward compatibility
  if options.delete(:marshal) == true
    warn("The :marshal option has been deprecated in favor of :type. For example: attr_encrypted name, :type => :yaml")
    raise "Marshal is depreacted and cannot be used in conjunction with :type, just use :type. For #{params.inspect}" if type != :string
    type = :yaml
  end

  options.each {|option| warn "Ignoring unknown option #{option.inspect} supplied to attr_encrypted with #{params.inspect}"}

  if const_defined?(:EncryptedAttributes, _search_ancestors = false)
    mod = const_get(:EncryptedAttributes)
  else
    mod = const_set(:EncryptedAttributes, Module.new)
    include mod
  end

  params.each do |attribute|
    # Generate unencrypted attribute with getter and setter
    mod.module_eval("      # Returns the decrypted value for the encrypted attribute\n      # The decrypted value is cached and is only decrypted if the encrypted value has changed\n      # If this method is not called, then the encrypted value is never decrypted\n      def \#{attribute}\n        if @stored_encrypted_\#{attribute} != self.encrypted_\#{attribute}\n          @\#{attribute} = ::SymmetricEncryption.decrypt(self.encrypted_\#{attribute},version=nil,:\#{type}).freeze\n          @stored_encrypted_\#{attribute} = self.encrypted_\#{attribute}\n        end\n        @\#{attribute}\n      end\n\n      # Set the un-encrypted attribute\n      # Also updates the encrypted field with the encrypted value\n      def \#{attribute}=(value)\n        v = SymmetricEncryption::coerce(value, :\#{type})\n        self.encrypted_\#{attribute} = @stored_encrypted_\#{attribute} = ::SymmetricEncryption.encrypt(v,\#{random_iv},\#{compress},:\#{type})\n        @\#{attribute} = v.freeze\n      end\n    UNENCRYPTED\n\n    encrypted_attributes[attribute.to_sym] = \"encrypted_\#{attribute}\".to_sym\n  end\nend\n", __FILE__, __LINE__ + 1)

.encrypted_attribute?(attribute) ⇒ Boolean

Returns whether an attribute has been configured to be encrypted

Example

class User < ActiveRecord::Base
  attr_accessor :name
  attr_encrypted :email
end

User.encrypted_attribute?(:name) # false
User.encrypted_attribute?(:email) # true

Returns:

  • (Boolean)


131
132
133
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 131

def encrypted_attribute?(attribute)
  encrypted_keys.include?(attribute)
end

.encrypted_attributesObject

Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute names as values

Example

class User < ActiveRecord::Base
  attr_encrypted :email
end

User.encrypted_attributes # { :email => :encrypted_email }


104
105
106
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 104

def encrypted_attributes
  @encrypted_attributes ||= superclass.respond_to?(:encrypted_attributes) ? superclass.encrypted_attributes.dup : {}
end

.encrypted_column?(attribute) ⇒ Boolean

Returns whether the attribute is the database column to hold the encrypted data for a matching encrypted attribute

Example

class User < ActiveRecord::Base
  attr_accessor :name
  attr_encrypted :email
end

User.encrypted_column?(:encrypted_name) # false
User.encrypted_column?(:encrypted_email) # true

Returns:

  • (Boolean)


147
148
149
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 147

def encrypted_column?(attribute)
  encrypted_columns.include?(attribute)
end

.encrypted_columnsObject

Return the name of all encrypted columns as an Array of symbols Example: [:encrypted_email, :encrypted_password]



116
117
118
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 116

def encrypted_columns
  @encrypted_columns ||= encrypted_attributes.values
end

.encrypted_keysObject

Return the name of all encrypted virtual attributes as an Array of symbols Example: [:email, :password]



110
111
112
# File 'lib/symmetric_encryption/extensions/active_record/base.rb', line 110

def encrypted_keys
  @encrypted_keys ||= encrypted_attributes.keys
end