Skip to content

Commit

Permalink
feat(NODE-4136): adjust Node.js bindings for shared library spec (#306)
Browse files Browse the repository at this point in the history
  • Loading branch information
addaleax committed Apr 21, 2022
1 parent d973772 commit d3f3884
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
25 changes: 23 additions & 2 deletions bindings/node/lib/autoEncrypter.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ module.exports = function (modules) {
: this._bson.serialize(options.schemaMap);
}

if (options.encryptedFieldsMap) {
mongoCryptOptions.encryptedFieldsMap = Buffer.isBuffer(options.encryptedFieldsMap)
? options.encryptedFieldsMap
: this._bson.serialize(options.encryptedFieldsMap);
}

if (options.kmsProviders) {
mongoCryptOptions.kmsProviders = !Buffer.isBuffer(options.kmsProviders)
? this._bson.serialize(options.kmsProviders)
Expand All @@ -125,16 +131,27 @@ module.exports = function (modules) {
}

if (options.extraOptions && options.extraOptions.csfleSearchPaths) {
// Only for driver testing
mongoCryptOptions.csfleSearchPaths = options.extraOptions.csfleSearchPaths;
} else if (!this._bypassEncryption) {
mongoCryptOptions.csfleSearchPaths = ['$SYSTEM'];
}

if (options.bypassQueryAnalysis) {
mongoCryptOptions.bypassQueryAnalysis = options.bypassQueryAnalysis;
}

Object.assign(mongoCryptOptions, { cryptoCallbacks });
this._mongocrypt = new mc.MongoCrypt(mongoCryptOptions);
this._contextCounter = 0;

if (options.extraOptions && options.extraOptions.csfleRequired && !this.csfleVersionInfo) {
throw new MongoError('`csfleRequired` set but no csfle shared library loaded');
}

// Only instantiate mongocryptd manager/client once we know for sure
// that we are not using the CSFLE shared library.
if (!this._bypassAutoEncryption && !this.csfleVersionInfo) {
if (!this._bypassEncryption && !this.csfleVersionInfo) {
this._mongocryptdManager = new MongocryptdManager(options.extraOptions);
this._mongocryptdClient = new MongoClient(this._mongocryptdManager.uri, {
useNewUrlParser: true,
Expand Down Expand Up @@ -181,7 +198,11 @@ module.exports = function (modules) {
* @param {Function} callback Invoked when the mongocryptd client either successfully disconnects or errors
*/
teardown(force, callback) {
this._mongocryptdClient.close(force, callback);
if (this._mongocryptdClient) {
this._mongocryptdClient.close(force, callback);
} else {
callback();
}
}

/**
Expand Down
18 changes: 18 additions & 0 deletions bindings/node/src/mongocrypt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,20 @@ MongoCrypt::MongoCrypt(const CallbackInfo& info)
}
}

if (options.Has("encryptedFieldsMap")) {
Napi::Value encryptedFieldsMapBuffer = options["encryptedFieldsMap"];

if (!encryptedFieldsMapBuffer.IsBuffer()) {
throw TypeError::New(Env(), "Option `encryptedFieldsMap` must be a Buffer");
}

std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> encryptedFieldsMapBinary(
BufferToBinary(encryptedFieldsMapBuffer.As<Uint8Array>()));
if (!mongocrypt_setopt_encrypted_field_config_map(_mongo_crypt.get(), encryptedFieldsMapBinary.get())) {
throw TypeError::New(Env(), errorStringFromStatus(_mongo_crypt.get()));
}
}

if (options.Has("logger")) {
SetCallback("logger", options["logger"]);
if (!mongocrypt_setopt_log_handler(
Expand Down Expand Up @@ -438,6 +452,10 @@ MongoCrypt::MongoCrypt(const CallbackInfo& info)
options.Get("csflePath").ToString().Utf8Value().c_str());
}

if (options.Get("bypassQueryAnalysis").ToBoolean()) {
mongocrypt_setopt_bypass_query_analysis(_mongo_crypt.get());
}

mongocrypt_setopt_use_need_kms_credentials_state(_mongo_crypt.get());

// Initialize after all options are set.
Expand Down
33 changes: 30 additions & 3 deletions bindings/node/test/autoEncrypter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ describe('AutoEncrypter', function () {
const client = new MockClient();
this.mc = new AutoEncrypter(client, encryptionOptions);

const localMcdm = this.mc._mongocryptdManager;
const localMcdm = this.mc._mongocryptdManager || { spawn: () => {} };
sandbox.spy(localMcdm, 'spawn');

this.mc.init(err => {
Expand Down Expand Up @@ -640,7 +640,30 @@ describe('AutoEncrypter', function () {
});

describe('CSFLE shared library', function () {
it('should load a shared library by specifying its path', function () {
it('should fail if no library can be found in the search path and csfleRequired is set', function () {
// NB: This test has to be run before the tests/without having previously
// loaded a CSFLE shared library below to get the right error path.
const client = new MockClient();
try {
new AutoEncrypter(client, {
keyVaultNamespace: 'admin.datakeys',
logger: () => {},
kmsProviders: {
aws: { accessKeyId: 'example', secretAccessKey: 'example' },
local: { key: Buffer.alloc(96) }
},
extraOptions: {
csfleSearchPaths: ['/nonexistent'],
csfleRequired: true
}
});
expect.fail('missed exception');
} catch (err) {
expect(err.message).to.include('`csfleRequired` set but no csfle shared library loaded');
}
});

it('should load a shared library by specifying its path', function (done) {
const client = new MockClient();
this.mc = new AutoEncrypter(client, {
keyVaultNamespace: 'admin.datakeys',
Expand All @@ -661,9 +684,11 @@ describe('AutoEncrypter', function () {
version: BigInt(0x000600020001000),
versionStr: 'stubbed-mongo_csfle'
});

this.mc.teardown(true, done);
});

it('should load a shared library by specifying a search path', function () {
it('should load a shared library by specifying a search path', function (done) {
const client = new MockClient();
this.mc = new AutoEncrypter(client, {
keyVaultNamespace: 'admin.datakeys',
Expand All @@ -684,6 +709,8 @@ describe('AutoEncrypter', function () {
version: BigInt(0x000600020001000),
versionStr: 'stubbed-mongo_csfle'
});

this.mc.teardown(true, done);
});
});
});

0 comments on commit d3f3884

Please sign in to comment.