Spaces:
Paused
Paused
File size: 4,817 Bytes
d54c8f8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import { callbackify } from 'util';
import { AutoEncrypter, type AutoEncryptionOptions } from './client-side-encryption/auto_encrypter';
import { MONGO_CLIENT_EVENTS } from './constants';
import { getMongoDBClientEncryption } from './deps';
import { MongoInvalidArgumentError, MongoMissingDependencyError } from './error';
import { MongoClient, type MongoClientOptions } from './mongo_client';
import { type Callback } from './utils';
/** @internal */
const kInternalClient = Symbol('internalClient');
/** @internal */
export interface EncrypterOptions {
autoEncryption: AutoEncryptionOptions;
maxPoolSize?: number;
}
/** @internal */
export class Encrypter {
[kInternalClient]: MongoClient | null;
bypassAutoEncryption: boolean;
needsConnecting: boolean;
autoEncrypter: AutoEncrypter;
constructor(client: MongoClient, uri: string, options: MongoClientOptions) {
if (typeof options.autoEncryption !== 'object') {
throw new MongoInvalidArgumentError('Option "autoEncryption" must be specified');
}
// initialize to null, if we call getInternalClient, we may set this it is important to not overwrite those function calls.
this[kInternalClient] = null;
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, uri, options);
}
if (this.bypassAutoEncryption) {
options.autoEncryption.metadataClient = undefined;
} else if (options.maxPoolSize === 0) {
options.autoEncryption.metadataClient = client;
} else {
options.autoEncryption.metadataClient = this.getInternalClient(client, uri, options);
}
if (options.proxyHost) {
options.autoEncryption.proxyOptions = {
proxyHost: options.proxyHost,
proxyPort: options.proxyPort,
proxyUsername: options.proxyUsername,
proxyPassword: options.proxyPassword
};
}
this.autoEncrypter = new AutoEncrypter(client, options.autoEncryption);
}
getInternalClient(client: MongoClient, uri: string, options: MongoClientOptions): MongoClient {
// TODO(NODE-4144): Remove new variable for type narrowing
let internalClient = this[kInternalClient];
if (internalClient == null) {
const clonedOptions: MongoClientOptions = {};
for (const key of [
...Object.getOwnPropertyNames(options),
...Object.getOwnPropertySymbols(options)
] as string[]) {
if (['autoEncryption', 'minPoolSize', 'servers', 'caseTranslate', 'dbName'].includes(key))
continue;
Reflect.set(clonedOptions, key, Reflect.get(options, key));
}
clonedOptions.minPoolSize = 0;
internalClient = new MongoClient(uri, clonedOptions);
this[kInternalClient] = internalClient;
for (const eventName of MONGO_CLIENT_EVENTS) {
for (const listener of client.listeners(eventName)) {
internalClient.on(eventName, listener);
}
}
client.on('newListener', (eventName, listener) => {
internalClient?.on(eventName, listener);
});
this.needsConnecting = true;
}
return internalClient;
}
async connectInternalClient(): Promise<void> {
// TODO(NODE-4144): Remove new variable for type narrowing
const internalClient = this[kInternalClient];
if (this.needsConnecting && internalClient != null) {
this.needsConnecting = false;
await internalClient.connect();
}
}
closeCallback(client: MongoClient, force: boolean, callback: Callback<void>) {
callbackify(this.close.bind(this))(client, force, callback);
}
async close(client: MongoClient, force: boolean): Promise<void> {
let error;
try {
await this.autoEncrypter.teardown(force);
} catch (autoEncrypterError) {
error = autoEncrypterError;
}
const internalClient = this[kInternalClient];
if (internalClient != null && client !== internalClient) {
return await internalClient.close(force);
}
if (error != null) {
throw error;
}
}
static checkForMongoCrypt(): void {
const mongodbClientEncryption = getMongoDBClientEncryption();
if ('kModuleError' in mongodbClientEncryption) {
throw new MongoMissingDependencyError(
'Auto-encryption requested, but the module is not installed. ' +
'Please add `mongodb-client-encryption` as a dependency of your project',
{
cause: mongodbClientEncryption['kModuleError'],
dependencyName: 'mongodb-client-encryption'
}
);
}
}
}
|