Class: Mongo::Crypt::EncryptionIO Private

Inherits:
Object
  • Object
show all
Defined in:
lib/mongo/crypt/encryption_io.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

A class that implements I/O methods between the driver and the MongoDB server or mongocryptd.

Constant Summary collapse

SOCKET_TIMEOUT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Timeout used for TLS socket connection, reading, and writing. There is no specific timeout written in the spec. See SPEC-1394 for a discussion and updates on what this timeout should be.

10

Instance Method Summary collapse

Constructor Details

#initialize(client: nil, mongocryptd_client: nil, key_vault_namespace:, key_vault_client:, metadata_client:, mongocryptd_options: {}) ⇒ EncryptionIO

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

When being used for auto encryption, all arguments are required. When being used for explicit encryption, only the key_vault_namespace and key_vault_client arguments are required.

Note:

This class expects that the key_vault_client and key_vault_namespace options are not nil and are in the correct format.

Creates a new EncryptionIO object with information about how to connect to the key vault.

Parameters:

  • client (Mongo::Client) (defaults to: nil)

    The client used to connect to the collection that stores the encrypted documents, defaults to nil.

  • mongocryptd_client (Mongo::Client) (defaults to: nil)

    The client connected to mongocryptd, defaults to nil.

  • key_vault_client (Mongo::Client)

    The client connected to the key vault collection.

  • metadata_client (Mongo::Client | nil)

    The client to be used to obtain collection metadata.

  • key_vault_namespace (String)

    The key vault namespace in the format db_name.collection_name.

  • mongocryptd_options (Hash) (defaults to: {})

    Options related to mongocryptd.

Options Hash (mongocryptd_options:):

  • :mongocryptd_bypass_spawn (Boolean)
  • :mongocryptd_spawn_path (String)
  • :mongocryptd_spawn_args (Array<String>)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/mongo/crypt/encryption_io.rb', line 57

def initialize(
  client: nil, mongocryptd_client: nil, key_vault_namespace:,
  key_vault_client:, metadata_client:, mongocryptd_options: {}
)
  validate_key_vault_client!(key_vault_client)
  validate_key_vault_namespace!(key_vault_namespace)

  @client = client
  @mongocryptd_client = mongocryptd_client
  @key_vault_db_name, @key_vault_collection_name = key_vault_namespace.split('.')
  @key_vault_client = key_vault_client
  @metadata_client = 
  @options = mongocryptd_options
end

Instance Method Details

#add_key_alt_name(id, key_alt_name, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Adds a key_alt_name to the key_alt_names array of the key document in the key vault collection with the given id.



185
186
187
188
189
190
191
# File 'lib/mongo/crypt/encryption_io.rb', line 185

def add_key_alt_name(id, key_alt_name, timeout_ms: nil)
  key_vault_collection.find_one_and_update(
    { _id: id },
    { '$addToSet' => { keyAltNames: key_alt_name } },
    timeout_ms: timeout_ms
  )
end

#collection_info(db_name, filter, timeout_ms: nil) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get collection info for a collection matching the provided filter

Parameters:

  • filter (Hash)
  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is not enabled.

Returns:

  • (Hash)

    The collection information



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/mongo/crypt/encryption_io.rb', line 105

def collection_info(db_name, filter, timeout_ms: nil)
  unless @metadata_client
    raise ArgumentError, 'collection_info requires metadata_client to have been passed to the constructor, but it was not'
  end

  @metadata_client
    .use(db_name)
    .database
    .list_collections(filter: filter, deserialize_as_bson: true, timeout_ms: timeout_ms)
    .first
end

#delete_key(id, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Removes the key document with the given id from the key vault collection.



195
196
197
# File 'lib/mongo/crypt/encryption_io.rb', line 195

def delete_key(id, timeout_ms: nil)
  key_vault_collection.delete_one(_id: id, timeout_ms: timeout_ms)
end

#feed_kms(kms_context, tls_options, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get information about the remote KMS encryption key and feed it to the the KmsContext object

Parameters:

  • kms_context (Mongo::Crypt::KmsContext)

    A KmsContext object corresponding to one remote KMS data key. Contains information about the endpoint at which to establish a TLS connection and the message to send on that connection.

  • tls_options. (Hash)

    TLS options to connect to KMS provider. The options are same as for Mongo::Client.

  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is not enabled.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/mongo/crypt/encryption_io.rb', line 161

def feed_kms(kms_context, tls_options, timeout_ms: nil)
  with_ssl_socket(kms_context.endpoint, tls_options) do |ssl_socket|
    Timeout.timeout(timeout_ms || SOCKET_TIMEOUT, Error::SocketTimeoutError,
      'Socket write operation timed out'
    ) do
      ssl_socket.syswrite(kms_context.message)
    end

    bytes_needed = kms_context.bytes_needed
    while bytes_needed > 0 do
      bytes = Timeout.timeout(timeout_ms || SOCKET_TIMEOUT, Error::SocketTimeoutError,
        'Socket read operation timed out'
      ) do
        ssl_socket.sysread(bytes_needed)
      end

      kms_context.feed(bytes)
      bytes_needed = kms_context.bytes_needed
    end
  end
end

#find_keys(filter, timeout_ms: nil) ⇒ Array<BSON::Document>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Query for keys in the key vault collection using the provided filter

Parameters:

  • filter (Hash)
  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is not enabled.

Returns:

  • (Array<BSON::Document>)

    The query results



81
82
83
# File 'lib/mongo/crypt/encryption_io.rb', line 81

def find_keys(filter, timeout_ms: nil)
  key_vault_collection.find(filter, timeout_ms: timeout_ms).to_a
end

#get_key(id, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Finds a single key document with the given id.



200
201
202
# File 'lib/mongo/crypt/encryption_io.rb', line 200

def get_key(id, timeout_ms: nil)
  key_vault_collection.find(_id: id, timeout_ms: timeout_ms).first
end

#get_key_by_alt_name(key_alt_name, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a key document in the key vault collection with the given key_alt_name.



206
207
208
# File 'lib/mongo/crypt/encryption_io.rb', line 206

def get_key_by_alt_name(key_alt_name, timeout_ms: nil)
  key_vault_collection.find(keyAltNames: key_alt_name, timeout_ms: timeout_ms).first
end

#get_keys(timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Finds all documents in the key vault collection.



211
212
213
# File 'lib/mongo/crypt/encryption_io.rb', line 211

def get_keys(timeout_ms: nil)
  key_vault_collection.find(nil, timeout_ms: timeout_ms)
end

#insert_data_key(document, timeout_ms: nil) ⇒ Mongo::Operation::Insert::Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Insert a document into the key vault collection

Parameters:

  • document (Hash)
  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is not enabled.

Returns:



93
94
95
# File 'lib/mongo/crypt/encryption_io.rb', line 93

def insert_data_key(document, timeout_ms: nil)
  key_vault_collection.insert_one(document, timeout_ms: timeout_ms)
end

#mark_command(cmd, timeout_ms: nil) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Send the command to mongocryptd to be marked with intent-to-encrypt markings

Parameters:

  • cmd (Hash)
  • :timeout_ms (Integer)

    The operation timeout in milliseconds. Must be a non-negative integer. An explicit value of 0 means infinite. The default value is unset which means the feature is not enabled.

Returns:

  • (Hash)

    The marked command



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mongo/crypt/encryption_io.rb', line 125

def mark_command(cmd, timeout_ms: nil)
  unless @mongocryptd_client
    raise ArgumentError, 'mark_command requires mongocryptd_client to have been passed to the constructor, but it was not'
  end

  # Ensure the response from mongocryptd is deserialized with { mode: :bson }
  # to prevent losing type information in commands
  options = {
    execution_options: { deserialize_as_bson: true },
    timeout_ms: timeout_ms
  }

  begin
    response = @mongocryptd_client.database.command(cmd, options)
  rescue Error::NoServerAvailable => e
    raise e if @options[:mongocryptd_bypass_spawn]

    spawn_mongocryptd
    response = @mongocryptd_client.database.command(cmd, options)
  end

  return response.first
end

#remove_key_alt_name(id, key_alt_name, timeout_ms: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Removes a key_alt_name from the key_alt_names array of the key document in the key vault collection with the given id.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/mongo/crypt/encryption_io.rb', line 217

def remove_key_alt_name(id, key_alt_name, timeout_ms: nil)
  key_vault_collection.find_one_and_update(
    { _id: id },
    [
      {
        '$set' => {
          keyAltNames: {
            '$cond' => [
              { '$eq' => [ '$keyAltNames', [ key_alt_name ] ] },
              '$$REMOVE',
              {
                '$filter' => {
                  input: '$keyAltNames',
                  cond: { '$ne' =>  [ '$$this', key_alt_name ] }
                }
              }
            ]
          }
        }
      }
    ],
    timeout_ms: timeout_ms
  )
end

#update_data_keys(updates, timeout_ms: nil) ⇒ BulkWrite::Result

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Apply given requests to the key vault collection using bulk write.

Parameters:

  • requests (Array<Hash>)

    The bulk write requests.

Returns:



247
248
249
# File 'lib/mongo/crypt/encryption_io.rb', line 247

def update_data_keys(updates, timeout_ms: nil)
  key_vault_collection.bulk_write(updates, timeout_ms: timeout_ms)
end