123456789_123456789_123456789_123456789_123456789_

Module: Mongoid::Config::Encryption Private

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Extended In:
Defined in: lib/mongoid/config/encryption.rb

Overview

This module contains the logic for configuring Client Side Field Level automatic encryption.

Constant Summary

Instance Method Summary

Instance Method Details

#algorithm_for(field) ⇒ String (private)

Get the encryption algorithm to use for the provided field.

Parameters:

  • field (Mongoid::Field) —

    The field to get the algorithm for.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 196

def algorithm_for(field)
  case field.deterministic?
  when true
    DETERMINISTIC_ALGORITHM
  when false
    RANDOM_ALGORITHM
  end
end

#bson_type_for(field) ⇒ String (private)

Get the ::BSON type identifier for the provided field according to the https://www.mongodb.com/docs/manual/reference/bson-types/#std-bson-types

Parameters:

  • field (Mongoid::Field) —

    The field to get the ::BSON type identifier for.

Returns:

  • (String) —

    The BSON type identifier.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 187

def bson_type_for(field)
  TYPE_MAPPINGS[field.type]
end

#encryption_schema_map(default_database, models = ::Mongoid.models) ⇒ Hash

Generate the encryption schema map for the provided models.

Parameters:

  • default_database (String) —

    The default database name.

  • models (Array<Mongoid::Document>) (defaults to: ::Mongoid.models) —

    The models to generate the schema map for. Defaults to all models in the application.

Returns:

  • (Hash) —

    The encryption schema map.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 22

def encryption_schema_map(default_database, models = ::Mongoid.models)
  models.each_with_object({}) do |model, map|
    next if model.embedded?
    next unless model.requires_encryption_schema?

    database = model.storage_options.fetch(:database) { default_database }
    # A callable database name cannot be resolved here: the documented
    # multi-tenant idiom has no correct value while the client is being
    # built. Interpolating the callable would produce a key that never
    # matches any namespace, so leave the model out of the map. Writes
    # are refused later, by PersistenceContext, rather than silently
    # going out unencrypted.
    next if database.respond_to?(:call)

    key = "#{database}.#{model.collection_name}"
    props = (model).merge(properties_for(model, [ model ]))
    # The root of a collection schema describes the document, so it is
    # always an object. Saying so matters when a nested schema carries
    # encryptMetadata: mongocryptd rejects the schema otherwise.
    map[key] = { 'bsonType' => 'object' }.merge(props) unless props.empty?
  end
end

#key_id_for(key_id_base64, key_name_field) ⇒ Array<BSON::Binary> | String | nil (private)

Get the keyId encryption schema field for the base64 encrypted key id.

Parameters:

  • key_id_base64 (String | nil) —

    The base64 encoded key id.

  • key_name_field (String | nil) —

    The name of the key name field.

Returns:

  • (Array<BSON::Binary> | String | nil) —

    The keyId encryption schema field, JSON pointer to the field that contains keyAltName, or nil if both key_id_base64 and key_name_field are nil.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 214

def key_id_for(key_id_base64, key_name_field)
  return nil if key_id_base64.nil? && key_name_field.nil?
  if !key_id_base64.nil? && !key_name_field.nil?
    raise ArgumentError, 'Specifying both key_id and key_name_field is not allowed'
  end

  if key_id_base64.nil?
    "/#{key_name_field}"
  else
    [ BSON::Binary.new(Base64.decode64(key_id_base64), :uuid) ]
  end
end

#metadata_for(model) ⇒ Hash (private)

Generate the encryptMetadata object for the provided model.

Parameters:

Returns:

  • (Hash) —

    The encryptMetadata object.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 81

def (model)
   = {}.tap do ||
    if (key_id = key_id_for(model.[:key_id], model.[:key_name_field]))
      ['keyId'] = key_id
    end
    if model..key?(:deterministic)
      ['algorithm'] = if model.[:deterministic]
                                DETERMINISTIC_ALGORITHM
                              else
                                RANDOM_ALGORITHM
                              end
    end
  end
  if .empty?
    {}
  else
    {
      'bsonType' => 'object',
      'encryptMetadata' => 
    }
  end
end

#properties_for(model, path) ⇒ Hash (private)

Generate encryption properties for the provided model.

This method generates the properties for the fields and relations that are marked as encrypted.

Parameters:

Returns:

  • (Hash) —

    The encryption properties.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 114

def properties_for(model, path)
  result = properties_for_fields(model).merge(properties_for_relations(model, path))
  if result.empty?
    {}
  else
    { 'properties' => result }
  end
end

#properties_for_fields(model) ⇒ Hash (private)

Generate encryption properties for the fields of the provided model.

Parameters:

Returns:

  • (Hash) —

    The encryption properties.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 128

def properties_for_fields(model)
  model.fields.each_with_object({}) do |(name, field), props|
    next unless field.is_a?(Mongoid::Fields::Encrypted)

    props[name] = {
      'encrypt' => {
        'bsonType' => bson_type_for(field)
      }
    }
    if (algorithm = algorithm_for(field))
      props[name]['encrypt']['algorithm'] = algorithm
    end
    if (key_id = key_id_for(field.key_id, field.key_name_field))
      props[name]['encrypt']['keyId'] = key_id
    end
  end
end

#properties_for_relations(model, path) ⇒ Hash (private)

Generate encryption properties for the relations of the provided model.

This method generates the properties for the embedded relations that are configured to be encrypted.

Parameters:

Returns:

  • (Hash) —

    The encryption properties.

[ GitHub ]

  
# File 'lib/mongoid/config/encryption.rb', line 156

def properties_for_relations(model, path)
  model.relations.each_with_object({}) do |(name, relation), props|
    # relation_class constantizes, and a polymorphic embedded_in has no
    # class to resolve, so the relation type has to be checked first.
    next unless relation.is_a?(Association::Embedded::EmbedsOne)

    klass = relation.try_relation_class
    # An association target does not have to be a Mongoid document, and
    # the class it names does not have to exist.
    next unless klass.respond_to?(:requires_encryption_schema?)
    # Stop at a model the walk is already inside of, or a self-embedding
    # model never terminates. The path covers the current branch only:
    # a model embedded by two parents, or twice by one parent, has to be
    # emitted at every place it appears.
    next if path.include?(klass)
    next unless klass.requires_encryption_schema?

    (klass).merge(
      properties_for(klass, path + [ klass ])
    ).tap do |properties|
      props[name] = { 'bsonType' => 'object' }.merge(properties) unless properties.empty?
    end
  end
end