/
encrypter.ts
128 lines (105 loc) · 4.34 KB
/
encrypter.ts
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
/* eslint-disable @typescript-eslint/no-var-requires */
import { deserialize, serialize } from './bson';
import { MONGO_CLIENT_EVENTS } from './constants';
import type { AutoEncrypter, AutoEncryptionOptions } from './deps';
import { MongoInvalidArgumentError, MongoMissingDependencyError } from './error';
import { MongoClient, MongoClientOptions } from './mongo_client';
import type { Callback } from './utils';
let AutoEncrypterClass: AutoEncrypter;
/** @internal */
const kInternalClient = Symbol('internalClient');
/** @internal */
export interface EncrypterOptions {
autoEncryption: AutoEncryptionOptions;
maxPoolSize?: number;
}
/** @internal */
export class Encrypter {
[kInternalClient]: MongoClient;
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');
}
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
};
}
options.autoEncryption.bson = Object.create(null);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
options.autoEncryption.bson!.serialize = serialize;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
options.autoEncryption.bson!.deserialize = deserialize;
this.autoEncrypter = new AutoEncrypterClass(client, options.autoEncryption);
}
getInternalClient(client: MongoClient, uri: string, options: MongoClientOptions): MongoClient {
if (!this[kInternalClient]) {
const clonedOptions: MongoClientOptions = {};
for (const key of Object.keys(options)) {
if (['autoEncryption', 'minPoolSize', 'servers', 'caseTranslate', 'dbName'].includes(key))
continue;
Reflect.set(clonedOptions, key, Reflect.get(options, key));
}
clonedOptions.minPoolSize = 0;
this[kInternalClient] = new MongoClient(uri, clonedOptions);
for (const eventName of MONGO_CLIENT_EVENTS) {
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: Callback): void {
if (this.needsConnecting) {
this.needsConnecting = false;
return this[kInternalClient].connect(callback);
}
return callback();
}
close(client: MongoClient, force: boolean, callback: Callback): void {
this.autoEncrypter.teardown(!!force, e => {
if (this[kInternalClient] && client !== this[kInternalClient]) {
return this[kInternalClient].close(force, callback);
}
callback(e);
});
}
static checkForMongoCrypt(): void {
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 MongoMissingDependencyError(
'Auto-encryption requested, but the module is not installed. ' +
'Please add `mongodb-client-encryption` as a dependency of your project'
);
}
AutoEncrypterClass = mongodbClientEncryption.extension(require('../lib/index')).AutoEncrypter;
}
}