diff --git a/lib/mongo/crypt/explicit_encrypter.rb b/lib/mongo/crypt/explicit_encrypter.rb index ffe885976b..a38c2705a1 100644 --- a/lib/mongo/crypt/explicit_encrypter.rb +++ b/lib/mongo/crypt/explicit_encrypter.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -# rubocop:todo all # Copyright (C) 2020 MongoDB Inc. # @@ -17,12 +16,13 @@ module Mongo module Crypt - # An ExplicitEncrypter is an object that performs explicit encryption # operations and handles all associated options and instance variables. # # @api private class ExplicitEncrypter + extend Forwardable + # Create a new ExplicitEncrypter object. # # @param [ Mongo::Client ] key_vault_client An instance of Mongo::Client @@ -44,7 +44,7 @@ def initialize(key_vault_client, key_vault_namespace, kms_providers, kms_tls_opt @encryption_io = EncryptionIO.new( key_vault_client: key_vault_client, metadata_client: nil, - key_vault_namespace: key_vault_namespace, + key_vault_namespace: key_vault_namespace ) end @@ -108,7 +108,7 @@ def encrypt(value, options) Crypt::ExplicitEncryptionContext.new( @crypt_handle, @encryption_io, - { 'v': value }, + { v: value }, options ).run_state_machine['v'] end @@ -167,7 +167,7 @@ def encrypt_expression(expression, options) Crypt::ExplicitEncryptionExpressionContext.new( @crypt_handle, @encryption_io, - { 'v': expression }, + { v: expression }, options ).run_state_machine['v'] end @@ -179,10 +179,10 @@ def encrypt_expression(expression, options) # # @return [ Object ] The decrypted value def decrypt(value) - result = Crypt::ExplicitDecryptionContext.new( + Crypt::ExplicitDecryptionContext.new( @crypt_handle, @encryption_io, - { 'v': value }, + { v: value } ).run_state_machine['v'] end @@ -203,9 +203,7 @@ def add_key_alt_name(id, key_alt_name) # # @return [ Operation::Result ] The response from the database for the delete_one # operation that deletes the key. - def delete_key(id) - @encryption_io.delete_key(id) - end + def_delegators :@encryption_io, :delete_key # Finds a single key with the given id. # @@ -213,9 +211,7 @@ def delete_key(id) # # @return [ BSON::Document | nil ] The found key document or nil # if not found. - def get_key(id) - @encryption_io.get_key(id) - end + def_delegators :@encryption_io, :get_key # Returns a key in the key vault collection with the given key_alt_name. # @@ -223,16 +219,12 @@ def get_key(id) # # @return [ BSON::Document | nil ] The found key document or nil # if not found. - def get_key_by_alt_name(key_alt_name) - @encryption_io.get_key_by_alt_name(key_alt_name) - end + def_delegators :@encryption_io, :get_key_by_alt_name # Returns all keys in the key vault collection. # # @return [ Collection::View ] Keys in the key vault collection. - def get_keys - @encryption_io.get_keys - end + def_delegators :@encryption_io, :get_keys # Removes a key_alt_name from a key in the key vault collection with the given id. # @@ -241,9 +233,7 @@ def get_keys # # @return [ BSON::Document | nil ] Document describing the identified key # before removing the key alt name, or nil if no such key. - def remove_key_alt_name(id, key_alt_name) - @encryption_io.remove_key_alt_name(id, key_alt_name) - end + def_delegators :@encryption_io, :remove_key_alt_name # Decrypts multiple data keys and (re-)encrypts them with a new master_key, # or with their current master_key if a new one is not given. @@ -259,11 +249,7 @@ def remove_key_alt_name(id, key_alt_name) def rewrap_many_data_key(filter, opts = {}) validate_rewrap_options!(opts) - master_key_document = if opts[:provider] - options = opts.dup - provider = options.delete(:provider) - KMS::MasterKeyDocument.new(provider, options) - end + master_key_document = master_key_for_provider(opts) rewrap_result = Crypt::RewrapManyDataKeyContext.new( @crypt_handle, @@ -271,11 +257,52 @@ def rewrap_many_data_key(filter, opts = {}) filter, master_key_document ).run_state_machine - if rewrap_result.nil? - return RewrapManyDataKeyResult.new(nil) - end - data_key_documents = rewrap_result.fetch('v') - updates = data_key_documents.map do |doc| + + return RewrapManyDataKeyResult.new(nil) if rewrap_result.nil? + + updates = updates_from_data_key_documents(rewrap_result.fetch('v')) + RewrapManyDataKeyResult.new(@encryption_io.update_data_keys(updates)) + end + + private + + # Ensures the consistency of the options passed to #rewrap_many_data_keys. + # + # @param [ Hash ] opts the options hash to validate + # + # @raise [ ArgumentError ] if the options are not consistent or + # compatible. + def validate_rewrap_options!(opts) + return unless opts.key?(:master_key) && !opts.key?(:provider) + + raise ArgumentError, 'If :master_key is specified, :provider must also be given' + end + + # If a :provider is given, construct a new master key document + # with that provider. + # + # @param [ Hash ] opts the options hash + # + # @option [ String ] :provider KMS provider to encrypt keys. + # + # @return [ KMS::MasterKeyDocument | nil ] the new master key document, + # or nil if no provider was given. + def master_key_for_provider(opts) + return nil unless opts[:provider] + + options = opts.dup + provider = options.delete(:provider) + KMS::MasterKeyDocument.new(provider, options) + end + + # Returns the corresponding update document for each for of the given + # data key documents. + # + # @param [ Array ] documents the data key documents + # + # @return [ Array ] the update documents + def updates_from_data_key_documents(documents) + documents.map do |doc| { update_one: { filter: { _id: doc[:_id] }, @@ -289,21 +316,6 @@ def rewrap_many_data_key(filter, opts = {}) } } end - RewrapManyDataKeyResult.new( - @encryption_io.update_data_keys(updates) - ) - end - - # Ensures the consistency of the options passed to #rewrap_many_data_keys. - # - # @param [Hash] opts the options hash to validate - # - # @raise [ ArgumentError ] if the options are not consistent or - # compatible. - def validate_rewrap_options!(opts) - if opts.key?(:master_key) && !opts.key?(:provider) - raise ArgumentError, 'If :master_key is specified, :provider must also be given' - end end end end