You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							169 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
	
	
							169 lines
						
					
					
						
							4.6 KiB
						
					
					
				'use strict';
 | 
						|
const MongoClient = require('./mongo_client');
 | 
						|
const BSON = require('./core/connection/utils').retrieveBSON();
 | 
						|
const MongoError = require('./core/error').MongoError;
 | 
						|
 | 
						|
let mongodbClientEncryption = undefined;
 | 
						|
try {
 | 
						|
  // Ensure you always wrap an optional require in the try block NODE-3199
 | 
						|
  mongodbClientEncryption = require('mongodb-client-encryption');
 | 
						|
} catch (err) {
 | 
						|
  throw new MongoError(
 | 
						|
    'Auto-encryption requested, but the module is not installed. ' +
 | 
						|
      'Please add `mongodb-client-encryption` as a dependency of your project'
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
if (
 | 
						|
  mongodbClientEncryption === undefined ||
 | 
						|
  typeof mongodbClientEncryption.extension !== 'function'
 | 
						|
) {
 | 
						|
  throw new MongoError(
 | 
						|
    'loaded version of `mongodb-client-encryption` does not have property `extension`. ' +
 | 
						|
      'Please make sure you are loading the correct version of `mongodb-client-encryption`'
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
const AutoEncrypter = mongodbClientEncryption.extension(require('../index')).AutoEncrypter;
 | 
						|
 | 
						|
const kInternalClient = Symbol('internalClient');
 | 
						|
 | 
						|
class Encrypter {
 | 
						|
  /**
 | 
						|
   * @param {MongoClient} client
 | 
						|
   * @param {{autoEncryption: import('./mongo_client').AutoEncryptionOptions, bson: object}} options
 | 
						|
   */
 | 
						|
  constructor(client, options) {
 | 
						|
    this.bypassAutoEncryption = !!options.autoEncryption.bypassAutoEncryption;
 | 
						|
    this.needsConnecting = false;
 | 
						|
 | 
						|
    if (options.maxPoolSize === 0 && options.autoEncryption.keyVaultClient == null) {
 | 
						|
      options.autoEncryption.keyVaultClient = client;
 | 
						|
    } else if (options.autoEncryption.keyVaultClient == null) {
 | 
						|
      options.autoEncryption.keyVaultClient = this.getInternalClient(client);
 | 
						|
    }
 | 
						|
 | 
						|
    if (this.bypassAutoEncryption) {
 | 
						|
      options.autoEncryption.metadataClient = undefined;
 | 
						|
    } else if (options.maxPoolSize === 0) {
 | 
						|
      options.autoEncryption.metadataClient = client;
 | 
						|
    } else {
 | 
						|
      options.autoEncryption.metadataClient = this.getInternalClient(client);
 | 
						|
    }
 | 
						|
 | 
						|
    options.autoEncryption.bson = Encrypter.makeBSON(options);
 | 
						|
 | 
						|
    this.autoEncrypter = new AutoEncrypter(client, options.autoEncryption);
 | 
						|
  }
 | 
						|
 | 
						|
  getInternalClient(client) {
 | 
						|
    if (!this[kInternalClient]) {
 | 
						|
      const clonedOptions = {};
 | 
						|
 | 
						|
      for (const key of Object.keys(client.s.options)) {
 | 
						|
        if (
 | 
						|
          ['autoEncryption', 'minPoolSize', 'servers', 'caseTranslate', 'dbName'].indexOf(key) !==
 | 
						|
          -1
 | 
						|
        )
 | 
						|
          continue;
 | 
						|
        clonedOptions[key] = client.s.options[key];
 | 
						|
      }
 | 
						|
 | 
						|
      clonedOptions.minPoolSize = 0;
 | 
						|
 | 
						|
      const allEvents = [
 | 
						|
        // APM
 | 
						|
        'commandStarted',
 | 
						|
        'commandSucceeded',
 | 
						|
        'commandFailed',
 | 
						|
 | 
						|
        // SDAM
 | 
						|
        'serverOpening',
 | 
						|
        'serverClosed',
 | 
						|
        'serverDescriptionChanged',
 | 
						|
        'serverHeartbeatStarted',
 | 
						|
        'serverHeartbeatSucceeded',
 | 
						|
        'serverHeartbeatFailed',
 | 
						|
        'topologyOpening',
 | 
						|
        'topologyClosed',
 | 
						|
        'topologyDescriptionChanged',
 | 
						|
 | 
						|
        // Legacy
 | 
						|
        'joined',
 | 
						|
        'left',
 | 
						|
        'ping',
 | 
						|
        'ha',
 | 
						|
 | 
						|
        // CMAP
 | 
						|
        'connectionPoolCreated',
 | 
						|
        'connectionPoolClosed',
 | 
						|
        'connectionCreated',
 | 
						|
        'connectionReady',
 | 
						|
        'connectionClosed',
 | 
						|
        'connectionCheckOutStarted',
 | 
						|
        'connectionCheckOutFailed',
 | 
						|
        'connectionCheckedOut',
 | 
						|
        'connectionCheckedIn',
 | 
						|
        'connectionPoolCleared'
 | 
						|
      ];
 | 
						|
 | 
						|
      this[kInternalClient] = new MongoClient(client.s.url, clonedOptions);
 | 
						|
 | 
						|
      for (const eventName of allEvents) {
 | 
						|
        for (const listener of client.listeners(eventName)) {
 | 
						|
          this[kInternalClient].on(eventName, listener);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      client.on('newListener', (eventName, listener) => {
 | 
						|
        this[kInternalClient].on(eventName, listener);
 | 
						|
      });
 | 
						|
 | 
						|
      this.needsConnecting = true;
 | 
						|
    }
 | 
						|
    return this[kInternalClient];
 | 
						|
  }
 | 
						|
 | 
						|
  connectInternalClient(callback) {
 | 
						|
    if (this.needsConnecting) {
 | 
						|
      this.needsConnecting = false;
 | 
						|
      return this[kInternalClient].connect(callback);
 | 
						|
    }
 | 
						|
 | 
						|
    return callback();
 | 
						|
  }
 | 
						|
 | 
						|
  close(client, force, callback) {
 | 
						|
    this.autoEncrypter.teardown(e => {
 | 
						|
      if (this[kInternalClient] && client !== this[kInternalClient]) {
 | 
						|
        return this[kInternalClient].close(force, callback);
 | 
						|
      }
 | 
						|
      callback(e);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  static makeBSON(options) {
 | 
						|
    return (
 | 
						|
      (options || {}).bson ||
 | 
						|
      new BSON([
 | 
						|
        BSON.Binary,
 | 
						|
        BSON.Code,
 | 
						|
        BSON.DBRef,
 | 
						|
        BSON.Decimal128,
 | 
						|
        BSON.Double,
 | 
						|
        BSON.Int32,
 | 
						|
        BSON.Long,
 | 
						|
        BSON.Map,
 | 
						|
        BSON.MaxKey,
 | 
						|
        BSON.MinKey,
 | 
						|
        BSON.ObjectId,
 | 
						|
        BSON.BSONRegExp,
 | 
						|
        BSON.Symbol,
 | 
						|
        BSON.Timestamp
 | 
						|
      ])
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
module.exports = { Encrypter };
 |