Top Level Namespace
Defined Under Namespace
Modules: ActiveRecord, SymmetricEncryption Classes: SymmetricEncryptionValidator
Instance Method Summary collapse
-
#encrypted ⇒ Field
Add :encrypted option for Mongoid models.
Instance Method Details
#encrypted ⇒ Field
Add :encrypted option for Mongoid models
Example:
require 'mongoid'
require 'symmetric-encryption'
# Initialize Mongoid in a standalone environment. In a Rails app this is not required
Mongoid.logger = Logger.new($stdout)
Mongoid.load!('config/mongoid.yml')
# Initialize SymmetricEncryption in a standalone environment. In a Rails app this is not required
SymmetricEncryption.load!('config/symmetric-encryption.yml', 'test')
class Person
include Mongoid::Document
field :name, :type => String
field :encrypted_social_security_number, :type => String, :encrypted => true
field :date_of_birth, :type => Date
field :encrypted_life_history, :type => String, :encrypted => {:compress => true, :random_iv => true}
# Encrypted fields are _always_ stored in Mongo as a String
# To get the result back as an Integer, Symmetric Encryption can do the
# necessary conversions by specifying the internal type as an option
# to :encrypted
# #see SymmetricEncryption::COERCION_TYPES for full list of types
field :encrypted_age, :type => String, :encrypted => {:type => :integer, :random_iv => true}
end
The above document results in the following document in the Mongo collection ‘persons’:
"name" : "Joe",
"encrypted_social_security_number" : "...",
"age" : 21
"encrypted_life_history" : "...",
Symmetric Encryption creates the getters and setters to be able to work with the field in it’s unencrypted form. For example
Example:
person = Person.where(:encrypted_social_security_number => '...').first
puts "Decrypted Social Security Number is: #{person.social_security_number}"
# Or is the same as
puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
# Sets the encrypted_social_security_number to encrypted version
person. = "123456789"
# Or, is equivalent to:
person. = SymmetricEncryption.encrypt("123456789")
Note: Only “String” types are currently supported for encryption
Note: Unlike attr_encrypted finders must use the encrypted field name
Invalid Example, does not work:
person = Person.where(:social_security_number => '123456789').first
Valid Example:
person = Person.where(:encrypted_social_security_number => SymmetricEncryption.encrypt('123456789')).first
Defines all the fields that are accessible on the Document For each field that is defined, a getter and setter will be added as an instance method to the Document.
Some of the other regular Mongoid options:
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/symmetric_encryption/mongoid.rb', line 90 Mongoid::Fields.option :encrypted do |model, field, | if != false = .is_a?(Hash) ? .dup : {} encrypted_field_name = field.name decrypted_field_name = .delete(:decrypt_as) if decrypted_field_name.nil? && encrypted_field_name.to_s.start_with?('encrypted_') decrypted_field_name = encrypted_field_name.to_s['encrypted_'.length..-1] end if decrypted_field_name.nil? raise "SymmetricEncryption for Mongoid. Encryption enabled for field #{encrypted_field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied" end random_iv = .delete(:random_iv) || false compress = .delete(:compress) || false type = .delete(:type) || :string raise "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}" unless SymmetricEncryption::COERCION_TYPES.include?(type) .each {|option| warn "Ignoring unknown option #{option.inspect} supplied to Mongoid :encrypted for #{model}##{field}"} if model.const_defined?(:EncryptedAttributes, _search_ancestors = false) mod = model.const_get(:EncryptedAttributes) else mod = model.const_set(:EncryptedAttributes, Module.new) model.send(:include, mod) end # Generate getter and setter methods mod.module_eval(" # Set the un-encrypted field\n # Also updates the encrypted field with the encrypted value\n # Freeze the decrypted field value so that it is not modified directly\n def \#{decrypted_field_name}=(value)\n v = SymmetricEncryption::coerce(value, :\#{type})\n self.\#{encrypted_field_name} = @stored_\#{encrypted_field_name} = ::SymmetricEncryption.encrypt(v,\#{random_iv},\#{compress},:\#{type})\n @\#{decrypted_field_name} = v.freeze\n end\n\n # Returns the decrypted value for the encrypted field\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 \#{decrypted_field_name}\n if @stored_\#{encrypted_field_name} != self.\#{encrypted_field_name}\n @\#{decrypted_field_name} = ::SymmetricEncryption.decrypt(self.\#{encrypted_field_name},version=nil,:\#{type}).freeze\n @stored_\#{encrypted_field_name} = self.\#{encrypted_field_name}\n end\n @\#{decrypted_field_name}\n end\n EOS\n end\nend\n", __FILE__, __LINE__ + 1) |