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
			| 
											3 years ago
										 | '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 }; |