diff --git a/bindings/node/lib/autoEncrypter.js b/bindings/node/lib/autoEncrypter.js index bbc86f149..c02926f15 100644 --- a/bindings/node/lib/autoEncrypter.js +++ b/bindings/node/lib/autoEncrypter.js @@ -8,6 +8,7 @@ module.exports = function (modules) { const MongocryptdManager = require('./mongocryptdManager').MongocryptdManager; const MongoClient = modules.mongodb.MongoClient; const MongoError = modules.mongodb.MongoError; + const BSON = modules.mongodb.BSON; const cryptoCallbacks = require('./cryptoCallbacks'); /** @@ -91,7 +92,7 @@ module.exports = function (modules) { */ constructor(client, options) { this._client = client; - this._bson = options.bson || client.topology.bson; + this._bson = options.bson || BSON || client.topology.bson; this._bypassEncryption = options.bypassAutoEncryption === true; this._keyVaultNamespace = options.keyVaultNamespace || 'admin.datakeys'; diff --git a/bindings/node/lib/clientEncryption.js b/bindings/node/lib/clientEncryption.js index 828e3eaae..710275cac 100644 --- a/bindings/node/lib/clientEncryption.js +++ b/bindings/node/lib/clientEncryption.js @@ -7,6 +7,7 @@ module.exports = function (modules) { const collectionNamespace = common.collectionNamespace; const promiseOrCallback = common.promiseOrCallback; const StateMachine = modules.stateMachine.StateMachine; + const BSON = modules.mongodb.BSON; const cryptoCallbacks = require('./cryptoCallbacks'); const { promisify } = require('util'); @@ -99,7 +100,7 @@ module.exports = function (modules) { */ constructor(client, options) { this._client = client; - this._bson = options.bson || client.topology.bson; + this._bson = options.bson || BSON || client.topology.bson; this._proxyOptions = options.proxyOptions; this._tlsOptions = options.tlsOptions; diff --git a/bindings/node/package-lock.json b/bindings/node/package-lock.json index 3fea74130..c319be33e 100644 --- a/bindings/node/package-lock.json +++ b/bindings/node/package-lock.json @@ -16,7 +16,6 @@ "socks": "^2.6.1" }, "devDependencies": { - "bson": "^4.6.4", "chai": "^4.3.6", "chai-subset": "^1.6.0", "chalk": "^4.1.2", @@ -27,7 +26,7 @@ "eslint-plugin-prettier": "^4.0.0", "jsdoc-to-markdown": "^7.1.1", "mocha": "^9.2.0", - "mongodb": "^4.6.0", + "mongodb": "^4.9.0", "node-gyp": "^8.4.1", "prebuild": "^11.0.2", "prettier": "^2.5.1", @@ -324,9 +323,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", - "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==", + "version": "18.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -342,9 +341,9 @@ "dev": true }, "node_modules/@types/whatwg-url": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", - "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", "dev": true, "dependencies": { "@types/node": "*", @@ -793,9 +792,9 @@ "dev": true }, "node_modules/bson": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz", - "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", "dev": true, "dependencies": { "buffer": "^5.6.0" @@ -2086,9 +2085,9 @@ "dev": true }, "node_modules/denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "dev": true, "engines": { "node": ">=0.10" @@ -3540,9 +3539,9 @@ } }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, "node_modules/is-arrayish": { "version": "0.2.1", @@ -4688,15 +4687,15 @@ } }, "node_modules/mongodb": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.6.0.tgz", - "integrity": "sha512-1gsxVXmjFTPJ+CkMG9olE4bcVsyY8lBJN9m5B5vj+LZ7wkBqq3PO8RVmNX9GwCBOBz1KV0zM00vPviUearSv7A==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.0.tgz", + "integrity": "sha512-tJJEFJz7OQTQPZeVHZJIeSOjMRqc5eSyXTt86vSQENEErpkiG7279tM/GT5AVZ7TgXNh9HQxoa2ZkbrANz5GQw==", "dev": true, "dependencies": { - "bson": "^4.6.3", - "denque": "^2.0.1", - "mongodb-connection-string-url": "^2.5.2", - "socks": "^2.6.2" + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", + "socks": "^2.7.0" }, "engines": { "node": ">=12.9.0" @@ -4706,9 +4705,9 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", - "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", + "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", "dev": true, "dependencies": { "@types/whatwg-url": "^8.2.1", @@ -6683,11 +6682,11 @@ } }, "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", "dependencies": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { @@ -8130,9 +8129,9 @@ "dev": true }, "@types/node": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", - "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==", + "version": "18.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", "dev": true }, "@types/normalize-package-data": { @@ -8148,9 +8147,9 @@ "dev": true }, "@types/whatwg-url": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", - "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", "dev": true, "requires": { "@types/node": "*", @@ -8508,9 +8507,9 @@ "dev": true }, "bson": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz", - "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", "dev": true, "requires": { "buffer": "^5.6.0" @@ -9554,9 +9553,9 @@ "dev": true }, "denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "dev": true }, "depd": { @@ -10700,9 +10699,9 @@ "dev": true }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, "is-arrayish": { "version": "0.2.1", @@ -11618,22 +11617,22 @@ "dev": true }, "mongodb": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.6.0.tgz", - "integrity": "sha512-1gsxVXmjFTPJ+CkMG9olE4bcVsyY8lBJN9m5B5vj+LZ7wkBqq3PO8RVmNX9GwCBOBz1KV0zM00vPviUearSv7A==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.0.tgz", + "integrity": "sha512-tJJEFJz7OQTQPZeVHZJIeSOjMRqc5eSyXTt86vSQENEErpkiG7279tM/GT5AVZ7TgXNh9HQxoa2ZkbrANz5GQw==", "dev": true, "requires": { - "bson": "^4.6.3", - "denque": "^2.0.1", - "mongodb-connection-string-url": "^2.5.2", + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", "saslprep": "^1.0.3", - "socks": "^2.6.2" + "socks": "^2.7.0" } }, "mongodb-connection-string-url": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", - "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", + "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", "dev": true, "requires": { "@types/whatwg-url": "^8.2.1", @@ -13185,11 +13184,11 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", "requires": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" } }, diff --git a/bindings/node/package.json b/bindings/node/package.json index 9c17e076c..9ccd8bc79 100644 --- a/bindings/node/package.json +++ b/bindings/node/package.json @@ -40,7 +40,6 @@ "socks": "^2.6.1" }, "devDependencies": { - "bson": "^4.6.4", "chai": "^4.3.6", "chai-subset": "^1.6.0", "chalk": "^4.1.2", @@ -51,7 +50,7 @@ "eslint-plugin-prettier": "^4.0.0", "jsdoc-to-markdown": "^7.1.1", "mocha": "^9.2.0", - "mongodb": "^4.6.0", + "mongodb": "^4.9.0", "node-gyp": "^8.4.1", "prebuild": "^11.0.2", "prettier": "^2.5.1", diff --git a/bindings/node/test/autoEncrypter.test.js b/bindings/node/test/autoEncrypter.test.js index 8e13a4306..8380739b5 100644 --- a/bindings/node/test/autoEncrypter.test.js +++ b/bindings/node/test/autoEncrypter.test.js @@ -2,10 +2,10 @@ const fs = require('fs'); const path = require('path'); -const BSON = require('bson'); -const EJSON = require('bson').EJSON; const sinon = require('sinon'); const mongodb = require('mongodb'); +const BSON = mongodb.BSON; +const EJSON = BSON.EJSON; const requirements = require('./requirements.helper'); const MongoNetworkTimeoutError = mongodb.MongoNetworkTimeoutError || mongodb.MongoTimeoutError; const MongoError = mongodb.MongoError; @@ -110,6 +110,94 @@ describe('AutoEncrypter', function () { sandbox.restore(); }); + describe('#constructor', function () { + context('when mongodb exports BSON (driver >= 4.9.0)', function () { + context('when a bson option is provided', function () { + const bson = Object.assign({}, BSON); + const encrypter = new AutoEncrypter( + {}, + { + bson: bson, + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the bson option', function () { + expect(encrypter._bson).to.equal(bson); + }); + }); + + context('when a bson option is not provided', function () { + const encrypter = new AutoEncrypter( + {}, + { + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the mongodb exported BSON', function () { + expect(encrypter._bson).to.equal(BSON); + }); + }); + + it('never uses bson from the topology', function () { + expect(() => new AutoEncrypter({}, {})).not.to.throw(); + }); + }); + + context('when mongodb does not export BSON (driver < 4.9.0)', function () { + context('when a bson option is provided', function () { + const bson = Object.assign({}, BSON); + const encrypter = new AutoEncrypter( + {}, + { + bson: bson, + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the bson option', function () { + expect(encrypter._bson).to.equal(bson); + }); + }); + + context('when a bson option is not provided', function () { + const mongoNoBson = { ...mongodb, BSON: undefined }; + const AutoEncrypterNoBson = require('../lib/autoEncrypter')({ + mongodb: mongoNoBson, + stateMachine + }).AutoEncrypter; + + context('when the client has a topology', function () { + const client = new MockClient(); + const encrypter = new AutoEncrypterNoBson(client, { + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + }); + + it('uses the bson on the topology', function () { + expect(encrypter._bson).to.equal(client.topology.bson); + }); + }); + + context('when the client does not have a topology', function () { + it('raises an error', function () { + expect(() => { + new AutoEncrypterNoBson({}, {}); + }).to.throw(/bson/); + }); + }); + }); + }); + }); + it('should support `bypassAutoEncryption`', function (done) { const client = new MockClient(); const autoEncrypter = new AutoEncrypter(client, { diff --git a/bindings/node/test/clientEncryption.test.js b/bindings/node/test/clientEncryption.test.js index adb722b1a..d269fb5c0 100644 --- a/bindings/node/test/clientEncryption.test.js +++ b/bindings/node/test/clientEncryption.test.js @@ -2,8 +2,8 @@ const fs = require('fs'); const expect = require('chai').expect; const sinon = require('sinon'); -const BSON = require('bson'); const mongodb = require('mongodb'); +const BSON = mongodb.BSON; const MongoClient = mongodb.MongoClient; const cryptoCallbacks = require('../lib/cryptoCallbacks'); const stateMachine = require('../lib/stateMachine')({ mongodb }); @@ -62,6 +62,108 @@ describe('ClientEncryption', function () { return client.close(); } + describe('#constructor', function () { + context('when mongodb exports BSON (driver >= 4.9.0)', function () { + context('when a bson option is provided', function () { + const bson = Object.assign({}, BSON); + const encrypter = new ClientEncryption( + {}, + { + bson: bson, + keyVaultNamespace: 'client.encryption', + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the bson option', function () { + expect(encrypter._bson).to.equal(bson); + }); + }); + + context('when a bson option is not provided', function () { + const encrypter = new ClientEncryption( + {}, + { + keyVaultNamespace: 'client.encryption', + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the mongodb exported BSON', function () { + expect(encrypter._bson).to.equal(BSON); + }); + }); + + it('never uses bson from the topology', function () { + expect(() => { + new ClientEncryption( + {}, + { + keyVaultNamespace: 'client.encryption', + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + }).not.to.throw(); + }); + }); + + context('when mongodb does not export BSON (driver < 4.9.0)', function () { + context('when a bson option is provided', function () { + const bson = Object.assign({}, BSON); + const encrypter = new ClientEncryption( + {}, + { + bson: bson, + keyVaultNamespace: 'client.encryption', + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + } + ); + + it('uses the bson option', function () { + expect(encrypter._bson).to.equal(bson); + }); + }); + + context('when a bson option is not provided', function () { + const mongoNoBson = { ...mongodb, BSON: undefined }; + const ClientEncryptionNoBson = require('../lib/clientEncryption')({ + mongodb: mongoNoBson, + stateMachine + }).ClientEncryption; + + context('when the client has a topology', function () { + const client = new MockClient(); + const encrypter = new ClientEncryptionNoBson(client, { + keyVaultNamespace: 'client.encryption', + kmsProviders: { + local: { key: Buffer.alloc(96) } + } + }); + + it('uses the bson on the topology', function () { + expect(encrypter._bson).to.equal(client.topology.bson); + }); + }); + + context('when the client does not have a topology', function () { + it('raises an error', function () { + expect(() => { + new ClientEncryptionNoBson({}, {}); + }).to.throw(/bson/); + }); + }); + }); + }); + }); + describe('stubbed stateMachine', function () { let sandbox = sinon.createSandbox(); diff --git a/bindings/node/test/stateMachine.test.js b/bindings/node/test/stateMachine.test.js index 074076190..677d24332 100644 --- a/bindings/node/test/stateMachine.test.js +++ b/bindings/node/test/stateMachine.test.js @@ -1,6 +1,5 @@ 'use strict'; -const BSON = require('bson'); const { EventEmitter, once } = require('events'); const net = require('net'); const tls = require('tls'); @@ -8,6 +7,7 @@ const fs = require('fs'); const expect = require('chai').expect; const sinon = require('sinon'); const mongodb = require('mongodb'); +const BSON = mongodb.BSON; const StateMachine = require('../lib/stateMachine')({ mongodb }).StateMachine; describe('StateMachine', function () {