class Mongo::Crypt::Context

A wrapper around mongocrypt_ctx_t, which manages the state machine for encryption and decription.

This class is a superclass that defines shared methods amongst contexts that are initialized for different purposes (e.g. data key creation, encryption, explicit encryption, etc.)

@api private

Attributes

ctx_p[R]

Public Class Methods

new(mongocrypt_handle, io) click to toggle source
Create a new Context object

@param [ Mongo::Crypt::Handle ] mongocrypt_handle A handle to libmongocrypt

used to create a new context object.

@param [ ClientEncryption::IO ] io An instance of the IO class

that implements driver I/O methods required to run the
state machine.
# File lib/mongo/crypt/context.rb, line 37
def initialize(mongocrypt_handle, io)
  # Ideally, this level of the API wouldn't be passing around pointer
  # references between objects, so this method signature is subject to change.

  # FFI::AutoPointer uses a custom release strategy to automatically free
  # the pointer once this object goes out of scope
  @ctx_p = FFI::AutoPointer.new(
    Binding.mongocrypt_ctx_new(mongocrypt_handle.ref),
    Binding.method(:mongocrypt_ctx_destroy)
  )

  @encryption_io = io
end

Public Instance Methods

run_state_machine() click to toggle source

Runs the mongocrypt_ctx_t state machine and handles all I/O on behalf of libmongocrypt

@return [ BSON::Document ] A BSON document representing the outcome

of the state machine. Contents can differ depending on how the
context was initialized..

@raise [ Error::CryptError ] If the state machine enters the

:error state

This method is not currently unit tested. It is integration tested in spec/integration/explicit_encryption_spec.rb

# File lib/mongo/crypt/context.rb, line 72
def run_state_machine
  while true
    case state
    when :error
      Binding.check_ctx_status(self)
    when :ready
      # Finalize the state machine and return the result as a BSON::Document
      return Binding.ctx_finalize(self)
    when :done
      return nil
    when :need_mongo_keys
      filter = Binding.ctx_mongo_op(self)

      @encryption_io.find_keys(filter).each do |key|
        mongocrypt_feed(key) if key
      end

      mongocrypt_done
    when :need_mongo_collinfo
      filter = Binding.ctx_mongo_op(self)

      result = @encryption_io.collection_info(@db_name, filter)
      mongocrypt_feed(result) if result

      mongocrypt_done
    when :need_mongo_markings
      cmd = Binding.ctx_mongo_op(self)

      result = @encryption_io.mark_command(cmd)
      mongocrypt_feed(result)

      mongocrypt_done
    when :need_kms
      while kms_context = Binding.ctx_next_kms_ctx(self) do
        @encryption_io.feed_kms(kms_context)
      end

      Binding.ctx_kms_done(self)
    else
      raise Error::CryptError.new(
        # TODO: fix CryptError to improve this API -- the first argument
        # in the initializer should not be optional
        nil,
        "State #{state} is not supported by Mongo::Crypt::Context"
      )
    end
  end
end
state() click to toggle source

Returns the state of the mongocrypt_ctx_t

@return [ Symbol ] The context state

# File lib/mongo/crypt/context.rb, line 56
def state
  Binding.mongocrypt_ctx_state(@ctx_p)
end

Private Instance Methods

mongocrypt_done() click to toggle source

Indicate that state machine is done feeding I/O responses back to libmongocrypt

# File lib/mongo/crypt/context.rb, line 124
def mongocrypt_done
  Binding.mongocrypt_ctx_mongo_done(ctx_p)
end
mongocrypt_feed(doc) click to toggle source

Feeds the result of a Mongo operation back to libmongocrypt.

@param [ Hash ] doc BSON document to feed.

@return [ BSON::Document ] BSON document containing the result.

# File lib/mongo/crypt/context.rb, line 133
def mongocrypt_feed(doc)
  Binding.ctx_mongo_feed(self, doc)
end