Commit
This commit is contained in:
commit
d1c8cae2c1
1417 changed files with 326736 additions and 0 deletions
609
node_modules/mongodb/lib/client-side-encryption/client_encryption.js
generated
vendored
Normal file
609
node_modules/mongodb/lib/client-side-encryption/client_encryption.js
generated
vendored
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ClientEncryption = void 0;
|
||||
exports.autoSelectSocketOptions = autoSelectSocketOptions;
|
||||
const bson_1 = require("../bson");
|
||||
const deps_1 = require("../deps");
|
||||
const timeout_1 = require("../timeout");
|
||||
const utils_1 = require("../utils");
|
||||
const errors_1 = require("./errors");
|
||||
const index_1 = require("./providers/index");
|
||||
const state_machine_1 = require("./state_machine");
|
||||
/**
|
||||
* @public
|
||||
* The public interface for explicit in-use encryption
|
||||
*/
|
||||
class ClientEncryption {
|
||||
/** @internal */
|
||||
static getMongoCrypt() {
|
||||
const encryption = (0, deps_1.getMongoDBClientEncryption)();
|
||||
if ('kModuleError' in encryption) {
|
||||
throw encryption.kModuleError;
|
||||
}
|
||||
return encryption.MongoCrypt;
|
||||
}
|
||||
/**
|
||||
* Create a new encryption instance
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* new ClientEncryption(mongoClient, {
|
||||
* keyVaultNamespace: 'client.encryption',
|
||||
* kmsProviders: {
|
||||
* local: {
|
||||
* key: masterKey // The master key used for encryption/decryption. A 96-byte long Buffer
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* new ClientEncryption(mongoClient, {
|
||||
* keyVaultNamespace: 'client.encryption',
|
||||
* kmsProviders: {
|
||||
* aws: {
|
||||
* accessKeyId: AWS_ACCESS_KEY,
|
||||
* secretAccessKey: AWS_SECRET_KEY
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
constructor(client, options) {
|
||||
this._client = client;
|
||||
this._proxyOptions = options.proxyOptions ?? {};
|
||||
this._tlsOptions = options.tlsOptions ?? {};
|
||||
this._kmsProviders = options.kmsProviders || {};
|
||||
const { timeoutMS } = (0, utils_1.resolveTimeoutOptions)(client, options);
|
||||
this._timeoutMS = timeoutMS;
|
||||
this._credentialProviders = options.credentialProviders;
|
||||
if (options.credentialProviders?.aws && !(0, index_1.isEmptyCredentials)('aws', this._kmsProviders)) {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError('Can only provide a custom AWS credential provider when the state machine is configured for automatic AWS credential fetching');
|
||||
}
|
||||
if (options.keyVaultNamespace == null) {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError('Missing required option `keyVaultNamespace`');
|
||||
}
|
||||
const mongoCryptOptions = {
|
||||
...options,
|
||||
kmsProviders: !Buffer.isBuffer(this._kmsProviders)
|
||||
? (0, bson_1.serialize)(this._kmsProviders)
|
||||
: this._kmsProviders,
|
||||
errorWrapper: errors_1.defaultErrorWrapper
|
||||
};
|
||||
this._keyVaultNamespace = options.keyVaultNamespace;
|
||||
this._keyVaultClient = options.keyVaultClient || client;
|
||||
const MongoCrypt = ClientEncryption.getMongoCrypt();
|
||||
this._mongoCrypt = new MongoCrypt(mongoCryptOptions);
|
||||
}
|
||||
/**
|
||||
* Creates a data key used for explicit encryption and inserts it into the key vault namespace
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Using async/await to create a local key
|
||||
* const dataKeyId = await clientEncryption.createDataKey('local');
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Using async/await to create an aws key
|
||||
* const dataKeyId = await clientEncryption.createDataKey('aws', {
|
||||
* masterKey: {
|
||||
* region: 'us-east-1',
|
||||
* key: 'xxxxxxxxxxxxxx' // CMK ARN here
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Using async/await to create an aws key with a keyAltName
|
||||
* const dataKeyId = await clientEncryption.createDataKey('aws', {
|
||||
* masterKey: {
|
||||
* region: 'us-east-1',
|
||||
* key: 'xxxxxxxxxxxxxx' // CMK ARN here
|
||||
* },
|
||||
* keyAltNames: [ 'mySpecialKey' ]
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
async createDataKey(provider, options = {}) {
|
||||
if (options.keyAltNames && !Array.isArray(options.keyAltNames)) {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError(`Option "keyAltNames" must be an array of strings, but was of type ${typeof options.keyAltNames}.`);
|
||||
}
|
||||
let keyAltNames = undefined;
|
||||
if (options.keyAltNames && options.keyAltNames.length > 0) {
|
||||
keyAltNames = options.keyAltNames.map((keyAltName, i) => {
|
||||
if (typeof keyAltName !== 'string') {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError(`Option "keyAltNames" must be an array of strings, but item at index ${i} was of type ${typeof keyAltName}`);
|
||||
}
|
||||
return (0, bson_1.serialize)({ keyAltName });
|
||||
});
|
||||
}
|
||||
let keyMaterial = undefined;
|
||||
if (options.keyMaterial) {
|
||||
keyMaterial = (0, bson_1.serialize)({ keyMaterial: options.keyMaterial });
|
||||
}
|
||||
const dataKeyBson = (0, bson_1.serialize)({
|
||||
provider,
|
||||
...options.masterKey
|
||||
});
|
||||
const context = this._mongoCrypt.makeDataKeyContext(dataKeyBson, {
|
||||
keyAltNames,
|
||||
keyMaterial
|
||||
});
|
||||
const stateMachine = new state_machine_1.StateMachine({
|
||||
proxyOptions: this._proxyOptions,
|
||||
tlsOptions: this._tlsOptions,
|
||||
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
||||
});
|
||||
const timeoutContext = options?.timeoutContext ??
|
||||
timeout_1.TimeoutContext.create((0, utils_1.resolveTimeoutOptions)(this._client, { timeoutMS: this._timeoutMS }));
|
||||
const dataKey = (0, bson_1.deserialize)(await stateMachine.execute(this, context, { timeoutContext }));
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
const { insertedId } = await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.insertOne(dataKey, {
|
||||
writeConcern: { w: 'majority' },
|
||||
timeoutMS: timeoutContext?.csotEnabled()
|
||||
? timeoutContext?.getRemainingTimeMSOrThrow()
|
||||
: undefined
|
||||
});
|
||||
return insertedId;
|
||||
}
|
||||
/**
|
||||
* Searches the keyvault for any data keys matching the provided filter. If there are matches, rewrapManyDataKey then attempts to re-wrap the data keys using the provided options.
|
||||
*
|
||||
* If no matches are found, then no bulk write is performed.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // rewrapping all data data keys (using a filter that matches all documents)
|
||||
* const filter = {};
|
||||
*
|
||||
* const result = await clientEncryption.rewrapManyDataKey(filter);
|
||||
* if (result.bulkWriteResult != null) {
|
||||
* // keys were re-wrapped, results will be available in the bulkWrite object.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // attempting to rewrap all data keys with no matches
|
||||
* const filter = { _id: new Binary() } // assume _id matches no documents in the database
|
||||
* const result = await clientEncryption.rewrapManyDataKey(filter);
|
||||
*
|
||||
* if (result.bulkWriteResult == null) {
|
||||
* // no keys matched, `bulkWriteResult` does not exist on the result object
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async rewrapManyDataKey(filter, options) {
|
||||
let keyEncryptionKeyBson = undefined;
|
||||
if (options) {
|
||||
const keyEncryptionKey = Object.assign({ provider: options.provider }, options.masterKey);
|
||||
keyEncryptionKeyBson = (0, bson_1.serialize)(keyEncryptionKey);
|
||||
}
|
||||
const filterBson = (0, bson_1.serialize)(filter);
|
||||
const context = this._mongoCrypt.makeRewrapManyDataKeyContext(filterBson, keyEncryptionKeyBson);
|
||||
const stateMachine = new state_machine_1.StateMachine({
|
||||
proxyOptions: this._proxyOptions,
|
||||
tlsOptions: this._tlsOptions,
|
||||
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
||||
});
|
||||
const timeoutContext = timeout_1.TimeoutContext.create((0, utils_1.resolveTimeoutOptions)(this._client, { timeoutMS: this._timeoutMS }));
|
||||
const { v: dataKeys } = (0, bson_1.deserialize)(await stateMachine.execute(this, context, { timeoutContext }));
|
||||
if (dataKeys.length === 0) {
|
||||
return {};
|
||||
}
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
const replacements = dataKeys.map((key) => ({
|
||||
updateOne: {
|
||||
filter: { _id: key._id },
|
||||
update: {
|
||||
$set: {
|
||||
masterKey: key.masterKey,
|
||||
keyMaterial: key.keyMaterial
|
||||
},
|
||||
$currentDate: {
|
||||
updateDate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
const result = await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.bulkWrite(replacements, {
|
||||
writeConcern: { w: 'majority' },
|
||||
timeoutMS: timeoutContext.csotEnabled() ? timeoutContext?.remainingTimeMS : undefined
|
||||
});
|
||||
return { bulkWriteResult: result };
|
||||
}
|
||||
/**
|
||||
* Deletes the key with the provided id from the keyvault, if it exists.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // delete a key by _id
|
||||
* const id = new Binary(); // id is a bson binary subtype 4 object
|
||||
* const { deletedCount } = await clientEncryption.deleteKey(id);
|
||||
*
|
||||
* if (deletedCount != null && deletedCount > 0) {
|
||||
* // successful deletion
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
async deleteKey(_id) {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
return await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.deleteOne({ _id }, { writeConcern: { w: 'majority' }, timeoutMS: this._timeoutMS });
|
||||
}
|
||||
/**
|
||||
* Finds all the keys currently stored in the keyvault.
|
||||
*
|
||||
* This method will not throw.
|
||||
*
|
||||
* @returns a FindCursor over all keys in the keyvault.
|
||||
* @example
|
||||
* ```ts
|
||||
* // fetching all keys
|
||||
* const keys = await clientEncryption.getKeys().toArray();
|
||||
* ```
|
||||
*/
|
||||
getKeys() {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
return this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.find({}, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
|
||||
}
|
||||
/**
|
||||
* Finds a key in the keyvault with the specified _id.
|
||||
*
|
||||
* Returns a promise that either resolves to a {@link DataKey} if a document matches the key or null if no documents
|
||||
* match the id. The promise rejects with an error if an error is thrown.
|
||||
* @example
|
||||
* ```ts
|
||||
* // getting a key by id
|
||||
* const id = new Binary(); // id is a bson binary subtype 4 object
|
||||
* const key = await clientEncryption.getKey(id);
|
||||
* if (!key) {
|
||||
* // key is null if there was no matching key
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async getKey(_id) {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
return await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.findOne({ _id }, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
|
||||
}
|
||||
/**
|
||||
* Finds a key in the keyvault which has the specified keyAltName.
|
||||
*
|
||||
* @param keyAltName - a keyAltName to search for a key
|
||||
* @returns Returns a promise that either resolves to a {@link DataKey} if a document matches the key or null if no documents
|
||||
* match the keyAltName. The promise rejects with an error if an error is thrown.
|
||||
* @example
|
||||
* ```ts
|
||||
* // get a key by alt name
|
||||
* const keyAltName = 'keyAltName';
|
||||
* const key = await clientEncryption.getKeyByAltName(keyAltName);
|
||||
* if (!key) {
|
||||
* // key is null if there is no matching key
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async getKeyByAltName(keyAltName) {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
return await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.findOne({ keyAltNames: keyAltName }, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
|
||||
}
|
||||
/**
|
||||
* Adds a keyAltName to a key identified by the provided _id.
|
||||
*
|
||||
* This method resolves to/returns the *old* key value (prior to adding the new altKeyName).
|
||||
*
|
||||
* @param _id - The id of the document to update.
|
||||
* @param keyAltName - a keyAltName to search for a key
|
||||
* @returns Returns a promise that either resolves to a {@link DataKey} if a document matches the key or null if no documents
|
||||
* match the id. The promise rejects with an error if an error is thrown.
|
||||
* @example
|
||||
* ```ts
|
||||
* // adding an keyAltName to a data key
|
||||
* const id = new Binary(); // id is a bson binary subtype 4 object
|
||||
* const keyAltName = 'keyAltName';
|
||||
* const oldKey = await clientEncryption.addKeyAltName(id, keyAltName);
|
||||
* if (!oldKey) {
|
||||
* // null is returned if there is no matching document with an id matching the supplied id
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async addKeyAltName(_id, keyAltName) {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
const value = await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.findOneAndUpdate({ _id }, { $addToSet: { keyAltNames: keyAltName } }, { writeConcern: { w: 'majority' }, returnDocument: 'before', timeoutMS: this._timeoutMS });
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Adds a keyAltName to a key identified by the provided _id.
|
||||
*
|
||||
* This method resolves to/returns the *old* key value (prior to removing the new altKeyName).
|
||||
*
|
||||
* If the removed keyAltName is the last keyAltName for that key, the `altKeyNames` property is unset from the document.
|
||||
*
|
||||
* @param _id - The id of the document to update.
|
||||
* @param keyAltName - a keyAltName to search for a key
|
||||
* @returns Returns a promise that either resolves to a {@link DataKey} if a document matches the key or null if no documents
|
||||
* match the id. The promise rejects with an error if an error is thrown.
|
||||
* @example
|
||||
* ```ts
|
||||
* // removing a key alt name from a data key
|
||||
* const id = new Binary(); // id is a bson binary subtype 4 object
|
||||
* const keyAltName = 'keyAltName';
|
||||
* const oldKey = await clientEncryption.removeKeyAltName(id, keyAltName);
|
||||
*
|
||||
* if (!oldKey) {
|
||||
* // null is returned if there is no matching document with an id matching the supplied id
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async removeKeyAltName(_id, keyAltName) {
|
||||
const { db: dbName, collection: collectionName } = utils_1.MongoDBCollectionNamespace.fromString(this._keyVaultNamespace);
|
||||
const pipeline = [
|
||||
{
|
||||
$set: {
|
||||
keyAltNames: {
|
||||
$cond: [
|
||||
{
|
||||
$eq: ['$keyAltNames', [keyAltName]]
|
||||
},
|
||||
'$$REMOVE',
|
||||
{
|
||||
$filter: {
|
||||
input: '$keyAltNames',
|
||||
cond: {
|
||||
$ne: ['$$this', keyAltName]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
const value = await this._keyVaultClient
|
||||
.db(dbName)
|
||||
.collection(collectionName)
|
||||
.findOneAndUpdate({ _id }, pipeline, {
|
||||
writeConcern: { w: 'majority' },
|
||||
returnDocument: 'before',
|
||||
timeoutMS: this._timeoutMS
|
||||
});
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* A convenience method for creating an encrypted collection.
|
||||
* This method will create data keys for any encryptedFields that do not have a `keyId` defined
|
||||
* and then create a new collection with the full set of encryptedFields.
|
||||
*
|
||||
* @param db - A Node.js driver Db object with which to create the collection
|
||||
* @param name - The name of the collection to be created
|
||||
* @param options - Options for createDataKey and for createCollection
|
||||
* @returns created collection and generated encryptedFields
|
||||
* @throws MongoCryptCreateDataKeyError - If part way through the process a createDataKey invocation fails, an error will be rejected that has the partial `encryptedFields` that were created.
|
||||
* @throws MongoCryptCreateEncryptedCollectionError - If creating the collection fails, an error will be rejected that has the entire `encryptedFields` that were created.
|
||||
*/
|
||||
async createEncryptedCollection(db, name, options) {
|
||||
const { provider, masterKey, createCollectionOptions: { encryptedFields: { ...encryptedFields }, ...createCollectionOptions } } = options;
|
||||
const timeoutContext = this._timeoutMS != null
|
||||
? timeout_1.TimeoutContext.create((0, utils_1.resolveTimeoutOptions)(this._client, { timeoutMS: this._timeoutMS }))
|
||||
: undefined;
|
||||
if (Array.isArray(encryptedFields.fields)) {
|
||||
const createDataKeyPromises = encryptedFields.fields.map(async (field) => field == null || typeof field !== 'object' || field.keyId != null
|
||||
? field
|
||||
: {
|
||||
...field,
|
||||
keyId: await this.createDataKey(provider, {
|
||||
masterKey,
|
||||
// clone the timeoutContext
|
||||
// in order to avoid sharing the same timeout for server selection and connection checkout across different concurrent operations
|
||||
timeoutContext: timeoutContext?.csotEnabled() ? timeoutContext?.clone() : undefined
|
||||
})
|
||||
});
|
||||
const createDataKeyResolutions = await Promise.allSettled(createDataKeyPromises);
|
||||
encryptedFields.fields = createDataKeyResolutions.map((resolution, index) => resolution.status === 'fulfilled' ? resolution.value : encryptedFields.fields[index]);
|
||||
const rejection = createDataKeyResolutions.find((result) => result.status === 'rejected');
|
||||
if (rejection != null) {
|
||||
throw new errors_1.MongoCryptCreateDataKeyError(encryptedFields, { cause: rejection.reason });
|
||||
}
|
||||
}
|
||||
try {
|
||||
const collection = await db.createCollection(name, {
|
||||
...createCollectionOptions,
|
||||
encryptedFields,
|
||||
timeoutMS: timeoutContext?.csotEnabled()
|
||||
? timeoutContext?.getRemainingTimeMSOrThrow()
|
||||
: undefined
|
||||
});
|
||||
return { collection, encryptedFields };
|
||||
}
|
||||
catch (cause) {
|
||||
throw new errors_1.MongoCryptCreateEncryptedCollectionError(encryptedFields, { cause });
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Explicitly encrypt a provided value. Note that either `options.keyId` or `options.keyAltName` must
|
||||
* be specified. Specifying both `options.keyId` and `options.keyAltName` is considered an error.
|
||||
*
|
||||
* @param value - The value that you wish to serialize. Must be of a type that can be serialized into BSON
|
||||
* @param options -
|
||||
* @returns a Promise that either resolves with the encrypted value, or rejects with an error.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Encryption with async/await api
|
||||
* async function encryptMyData(value) {
|
||||
* const keyId = await clientEncryption.createDataKey('local');
|
||||
* return clientEncryption.encrypt(value, { keyId, algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' });
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Encryption using a keyAltName
|
||||
* async function encryptMyData(value) {
|
||||
* await clientEncryption.createDataKey('local', { keyAltNames: 'mySpecialKey' });
|
||||
* return clientEncryption.encrypt(value, { keyAltName: 'mySpecialKey', algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' });
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async encrypt(value, options) {
|
||||
return await this._encrypt(value, false, options);
|
||||
}
|
||||
/**
|
||||
* Encrypts a Match Expression or Aggregate Expression to query a range index.
|
||||
*
|
||||
* Only supported when queryType is "range" and algorithm is "Range".
|
||||
*
|
||||
* @param expression - a BSON document of one of the following forms:
|
||||
* 1. A Match Expression of this form:
|
||||
* `{$and: [{<field>: {$gt: <value1>}}, {<field>: {$lt: <value2> }}]}`
|
||||
* 2. An Aggregate Expression of this form:
|
||||
* `{$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]}`
|
||||
*
|
||||
* `$gt` may also be `$gte`. `$lt` may also be `$lte`.
|
||||
*
|
||||
* @param options -
|
||||
* @returns Returns a Promise that either resolves with the encrypted value or rejects with an error.
|
||||
*/
|
||||
async encryptExpression(expression, options) {
|
||||
return await this._encrypt(expression, true, options);
|
||||
}
|
||||
/**
|
||||
* Explicitly decrypt a provided encrypted value
|
||||
*
|
||||
* @param value - An encrypted value
|
||||
* @returns a Promise that either resolves with the decrypted value, or rejects with an error
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Decrypting value with async/await API
|
||||
* async function decryptMyValue(value) {
|
||||
* return clientEncryption.decrypt(value);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
async decrypt(value) {
|
||||
const valueBuffer = (0, bson_1.serialize)({ v: value });
|
||||
const context = this._mongoCrypt.makeExplicitDecryptionContext(valueBuffer);
|
||||
const stateMachine = new state_machine_1.StateMachine({
|
||||
proxyOptions: this._proxyOptions,
|
||||
tlsOptions: this._tlsOptions,
|
||||
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
||||
});
|
||||
const timeoutContext = this._timeoutMS != null
|
||||
? timeout_1.TimeoutContext.create((0, utils_1.resolveTimeoutOptions)(this._client, { timeoutMS: this._timeoutMS }))
|
||||
: undefined;
|
||||
const { v } = (0, bson_1.deserialize)(await stateMachine.execute(this, context, { timeoutContext }));
|
||||
return v;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
* Ask the user for KMS credentials.
|
||||
*
|
||||
* This returns anything that looks like the kmsProviders original input
|
||||
* option. It can be empty, and any provider specified here will override
|
||||
* the original ones.
|
||||
*/
|
||||
async askForKMSCredentials() {
|
||||
return await (0, index_1.refreshKMSCredentials)(this._kmsProviders, this._credentialProviders);
|
||||
}
|
||||
static get libmongocryptVersion() {
|
||||
return ClientEncryption.getMongoCrypt().libmongocryptVersion;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
* A helper that perform explicit encryption of values and expressions.
|
||||
* Explicitly encrypt a provided value. Note that either `options.keyId` or `options.keyAltName` must
|
||||
* be specified. Specifying both `options.keyId` and `options.keyAltName` is considered an error.
|
||||
*
|
||||
* @param value - The value that you wish to encrypt. Must be of a type that can be serialized into BSON
|
||||
* @param expressionMode - a boolean that indicates whether or not to encrypt the value as an expression
|
||||
* @param options - options to pass to encrypt
|
||||
* @returns the raw result of the call to stateMachine.execute(). When expressionMode is set to true, the return
|
||||
* value will be a bson document. When false, the value will be a BSON Binary.
|
||||
*
|
||||
*/
|
||||
async _encrypt(value, expressionMode, options) {
|
||||
const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions, textOptions } = options;
|
||||
const contextOptions = {
|
||||
expressionMode,
|
||||
algorithm
|
||||
};
|
||||
if (keyId) {
|
||||
contextOptions.keyId = keyId.buffer;
|
||||
}
|
||||
if (keyAltName) {
|
||||
if (keyId) {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError(`"options" cannot contain both "keyId" and "keyAltName"`);
|
||||
}
|
||||
if (typeof keyAltName !== 'string') {
|
||||
throw new errors_1.MongoCryptInvalidArgumentError(`"options.keyAltName" must be of type string, but was of type ${typeof keyAltName}`);
|
||||
}
|
||||
contextOptions.keyAltName = (0, bson_1.serialize)({ keyAltName });
|
||||
}
|
||||
if (typeof contentionFactor === 'number' || typeof contentionFactor === 'bigint') {
|
||||
contextOptions.contentionFactor = contentionFactor;
|
||||
}
|
||||
if (typeof queryType === 'string') {
|
||||
contextOptions.queryType = queryType;
|
||||
}
|
||||
if (typeof rangeOptions === 'object') {
|
||||
contextOptions.rangeOptions = (0, bson_1.serialize)(rangeOptions);
|
||||
}
|
||||
if (typeof textOptions === 'object') {
|
||||
contextOptions.textOptions = (0, bson_1.serialize)(textOptions);
|
||||
}
|
||||
const valueBuffer = (0, bson_1.serialize)({ v: value });
|
||||
const stateMachine = new state_machine_1.StateMachine({
|
||||
proxyOptions: this._proxyOptions,
|
||||
tlsOptions: this._tlsOptions,
|
||||
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
||||
});
|
||||
const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);
|
||||
const timeoutContext = this._timeoutMS != null
|
||||
? timeout_1.TimeoutContext.create((0, utils_1.resolveTimeoutOptions)(this._client, { timeoutMS: this._timeoutMS }))
|
||||
: undefined;
|
||||
const { v } = (0, bson_1.deserialize)(await stateMachine.execute(this, context, { timeoutContext }));
|
||||
return v;
|
||||
}
|
||||
}
|
||||
exports.ClientEncryption = ClientEncryption;
|
||||
/**
|
||||
* Get the socket options from the client.
|
||||
* @param baseOptions - The mongo client options.
|
||||
* @returns ClientEncryptionSocketOptions
|
||||
*/
|
||||
function autoSelectSocketOptions(baseOptions) {
|
||||
const options = { autoSelectFamily: true };
|
||||
if ('autoSelectFamily' in baseOptions) {
|
||||
options.autoSelectFamily = baseOptions.autoSelectFamily;
|
||||
}
|
||||
if ('autoSelectFamilyAttemptTimeout' in baseOptions) {
|
||||
options.autoSelectFamilyAttemptTimeout = baseOptions.autoSelectFamilyAttemptTimeout;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
//# sourceMappingURL=client_encryption.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue