From 86df50cde6e1a9c3561c5389ffeb0ec6cb35d61a Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 6 Dec 2023 21:42:11 -0500 Subject: [PATCH 01/16] fix(update): set CastError path to full path if casting update fails Fix #14114 --- lib/schema/bigint.js | 9 ++++++++- lib/schema/boolean.js | 9 ++++++++- lib/schema/buffer.js | 11 ++++++++++- lib/schema/date.js | 9 ++++++++- lib/schema/number.js | 11 ++++++++++- lib/schema/string.js | 9 ++++++++- lib/schemaType.js | 9 ++++++++- test/model.findOneAndUpdate.test.js | 30 +++++++++++++++++++++++++++++ 8 files changed, 90 insertions(+), 7 deletions(-) diff --git a/lib/schema/bigint.js b/lib/schema/bigint.js index f6619a19e35..02912627dd5 100644 --- a/lib/schema/bigint.js +++ b/lib/schema/bigint.js @@ -212,7 +212,14 @@ SchemaBigInt.prototype.castForQuery = function($conditional, val, context) { return this.applySetters(null, val, context); } - return this.applySetters(val, context); + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } }; /** diff --git a/lib/schema/boolean.js b/lib/schema/boolean.js index 1dc67e2aaa5..a887a9e07e9 100644 --- a/lib/schema/boolean.js +++ b/lib/schema/boolean.js @@ -256,7 +256,14 @@ SchemaBoolean.prototype.castForQuery = function($conditional, val, context) { return this.applySetters(null, val, context); } - return this.applySetters(val, context); + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } }; /** diff --git a/lib/schema/buffer.js b/lib/schema/buffer.js index 655ccc2c9f6..6444ebd8835 100644 --- a/lib/schema/buffer.js +++ b/lib/schema/buffer.js @@ -279,7 +279,16 @@ SchemaBuffer.prototype.castForQuery = function($conditional, val, context) { } return handler.call(this, val); } - const casted = this.applySetters(val, context); + + let casted; + try { + casted = this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } return casted ? casted.toObject({ transform: false, virtuals: false }) : casted; }; diff --git a/lib/schema/date.js b/lib/schema/date.js index 7dcd998922f..6cbfee83865 100644 --- a/lib/schema/date.js +++ b/lib/schema/date.js @@ -407,7 +407,14 @@ SchemaDate.prototype.$conditionalHandlers = { SchemaDate.prototype.castForQuery = function($conditional, val, context) { if ($conditional == null) { - return this.applySetters(val, context); + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } } const handler = this.$conditionalHandlers[$conditional]; diff --git a/lib/schema/number.js b/lib/schema/number.js index 432acd2aca7..d89ab7d63c0 100644 --- a/lib/schema/number.js +++ b/lib/schema/number.js @@ -429,7 +429,16 @@ SchemaNumber.prototype.castForQuery = function($conditional, val, context) { } return handler.call(this, val, context); } - val = this.applySetters(val, context); + + try { + val = this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } + return val; }; diff --git a/lib/schema/string.js b/lib/schema/string.js index 2e39baac733..e7eed1c4f03 100644 --- a/lib/schema/string.js +++ b/lib/schema/string.js @@ -688,7 +688,14 @@ SchemaString.prototype.castForQuery = function($conditional, val, context) { return val; } - return this.applySetters(val, context); + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } }; /*! diff --git a/lib/schemaType.js b/lib/schemaType.js index ee8c9a6aeeb..25e0c0b4de8 100644 --- a/lib/schemaType.js +++ b/lib/schemaType.js @@ -1630,7 +1630,14 @@ SchemaType.prototype.castForQuery = function($conditional, val, context) { return handler.call(this, val, context); } - return this.applySetters(val, context); + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; + } }; /** diff --git a/test/model.findOneAndUpdate.test.js b/test/model.findOneAndUpdate.test.js index 6296b529ffb..56ac556eb6c 100644 --- a/test/model.findOneAndUpdate.test.js +++ b/test/model.findOneAndUpdate.test.js @@ -2200,4 +2200,34 @@ describe('model: findOneAndUpdate:', function() { ); assert.equal(updated.defaultField, 'some non-default value'); }); + + it('sets CastError path to full path (gh-14114)', async function() { + const testSchema = new mongoose.Schema({ + id: mongoose.Schema.Types.ObjectId, + name: String, + accessories: [ + { + isEnabled: Boolean, + additionals: [ + { + k: String, + v: Number + } + ] + } + ] + }); + const Test = db.model('Test', testSchema); + const err = await Test.findOneAndUpdate( + {}, + { + $set: { + 'accessories.0.additionals.0.k': ['test'] + } + } + ).then(() => null, err => err); + assert.ok(err); + assert.equal(err.name, 'CastError'); + assert.equal(err.path, 'accessories.0.additionals.0.k'); + }); }); From 4348595ff0b05cc243aafafefccdfe29c9bee96b Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Mon, 11 Dec 2023 13:00:34 +1100 Subject: [PATCH 02/16] Fix TLS certificate documentation for mongoose v8 --- docs/guides.md | 2 +- docs/migrating_to_8.md | 10 +++++++ docs/tutorials/ssl.md | 66 +++++++++++++++++++++--------------------- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/docs/guides.md b/docs/guides.md index 379c48dd0f6..9cc835fdb07 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -41,7 +41,7 @@ integrating Mongoose with external tools and frameworks. * [Transactions](transactions.html) * [MongoDB Driver Deprecation Warnings](deprecations.html) * [Testing with Jest](jest.html) -* [SSL Connections](tutorials/ssl.html) +* [TLS/SSL Connections](tutorials/ssl.html) * [MongoDB Client Side Field Level Encryption](field-level-encryption.html) ## Other Guides diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 9d664b1316a..02267bfe733 100644 --- a/docs/migrating_to_8.md +++ b/docs/migrating_to_8.md @@ -71,6 +71,16 @@ There's a few noteable changes in MongoDB Node driver v6 that affect Mongoose: 1. The `ObjectId` constructor no longer accepts strings of length 12. In Mongoose 7, `new mongoose.Types.ObjectId('12charstring')` was perfectly valid. In Mongoose 8, `new mongoose.Types.ObjectId('12charstring')` throws an error. +1. Deprecated SSL options have been removed + + - `sslCA` -> `tlsCAFile` + - `sslCRL` -> `tlsCRLFile` + - `sslCert` -> `tlsCertificateKeyFile` + - `sslKey` -> `tlsCertificateKeyFile` + - `sslPass` -> `tlsCertificateKeyFilePassword` + - `sslValidate` -> `tlsAllowInvalidCertificates` + - `tlsCertificateFile` -> `tlsCertificateKeyFile` +

Removed findOneAndRemove()

In Mongoose 7, `findOneAndRemove()` was an alias for `findOneAndDelete()` that Mongoose supported for backwards compatibility. diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 43be1971b7a..4e4a771c797 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,6 +1,6 @@ -# SSL Connections +# TSL/SSL Connections -Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://www.mongodb.com/docs/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: +Mongoose supports connecting to [MongoDB clusters that require TLS/SSL connections](https://www.mongodb.com/docs/manual/tutorial/configure-ssl/). Setting the either the `tls` or `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using TLS/SSL: ```javascript mongoose.connect('mongodb://127.0.0.1:27017/test', { ssl: true }); @@ -12,8 +12,7 @@ mongoose.connect('mongodb://127.0.0.1:27017/test?ssl=true'); The `ssl` option defaults to `false` for connection strings that start with `mongodb://`. However, the `ssl` option defaults to `true` for connection strings that start with `mongodb+srv://`. So if you are using an srv connection string to connect to [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), SSL is enabled by default. -If you try to connect to a MongoDB cluster that requires SSL without enabling the `ssl` option, `mongoose.connect()` -will error out with the below error: +If you try to connect to a MongoDB cluster that requires TLS/SSL without enabling the `tls`/`ssl` option, `mongoose.connect()` will error out with the below error: ```no-highlight MongooseServerSelectionError: connection to 127.0.0.1:27017 closed @@ -21,22 +20,21 @@ MongooseServerSelectionError: connection to 127.0.0.1:27017 closed ... ``` -## SSL Validation +## TLS/SSL Validation -By default, Mongoose validates the SSL certificate against a [certificate authority](https://en.wikipedia.org/wiki/Certificate_authority) to ensure the SSL certificate is valid. To disable this validation, set the `sslValidate` option -to `false`. +By default, Mongoose validates the TLS/SSL certificate against a [certificate authority](https://en.wikipedia.org/wiki/Certificate_authority) to ensure the TLS/SSL certificate is valid. To disable this validation, set the `tlsAllowInvalidCertificates` (or `tlsInsecure`) option to `true`. ```javascript mongoose.connect('mongodb://127.0.0.1:27017/test', { - ssl: true, - sslValidate: false + tls: true, + tlsAllowInvalidCertificates: true, }); ``` -In most cases, you should not disable SSL validation in production. However, `sslValidate: false` is often helpful -for debugging SSL connection issues. If you can connect to MongoDB with `sslValidate: false`, but not with -`sslValidate: true`, then you can confirm Mongoose can connect to the server and the server is configured to use -SSL correctly, but there's some issue with the SSL certificate. +In most cases, you should not disable TLS/SSL validation in production. However, `tlsAllowInvalidCertificates: true` is often helpful +for debugging SSL connection issues. If you can connect to MongoDB with `tlsAllowInvalidCertificates: true`, but not with +`tlsAllowInvalidCertificates: false`, then you can confirm Mongoose can connect to the server and the server is configured to use +TLS/SSL correctly, but there's some issue with the certificate. For example, a common issue is the below error message: @@ -45,17 +43,16 @@ MongooseServerSelectionError: unable to verify the first certificate ``` This error is often caused by [self-signed MongoDB certificates](https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89) or other situations where the certificate sent by the MongoDB -server is not registered with an established certificate authority. The solution is to set the `sslCA` option, which essentially sets a list of allowed SSL certificates. +server is not registered with an established certificate authority. The solution is to set the `tlsCAFile` option, which essentially sets a list of allowed SSL certificates. ```javascript await mongoose.connect('mongodb://127.0.0.1:27017/test', { - ssl: true, - sslValidate: true, + tls: true, // For example, see https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89 // for where the `rootCA.pem` file comes from. // Please note that, in Mongoose >= 5.8.3, `sslCA` needs to be // the **path to** the CA file, **not** the contents of the CA file - sslCA: `${__dirname}/rootCA.pem` + tlsCAFile: `${__dirname}/rootCA.pem`, }); ``` @@ -66,7 +63,7 @@ MongooseServerSelectionError: Hostname/IP does not match certificate's altnames: ``` The SSL certificate's [common name](https://knowledge.digicert.com/solution/SO7239.html) **must** line up with the host name -in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../connections.html#replicaset-hostnames). +in your connection string. If the SSL certificate is for `hostname2.mydomain.com`, your connection string must connect to `hostname2.mydomain.com`, not any other hostname or IP address that may be equivalent to `hostname2.mydomain.com`. For replica sets, this also means that the SSL certificate's common name must line up with the [machine's `hostname`](../connections.html#replicaset-hostnames). To disable this validation, set the `tlsAllowInvalidHostnames` option to `true`. ## X.509 Authentication @@ -75,40 +72,43 @@ If you're using [X.509 authentication](https://www.mongodb.com/docs/drivers/node ```javascript // Do this: const username = 'myusername'; -await mongoose.connect(`mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, { - ssl: true, - sslValidate: true, - sslCA: `${__dirname}/rootCA.pem`, - authMechanism: 'MONGODB-X509' -}); +await mongoose.connect( + `mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, + { + tls: true, + tlsCAFile: `${__dirname}/rootCA.pem`, + authMechanism: 'MONGODB-X509', + } +); // Not this: await mongoose.connect('mongodb://127.0.0.1:27017/test', { - ssl: true, - sslValidate: true, - sslCA: `${__dirname}/rootCA.pem`, + tls: true, + tlsCAFile: `${__dirname}/rootCA.pem`, authMechanism: 'MONGODB-X509', - auth: { username } + auth: { username }, }); ``` ## X.509 Authentication with MongoDB Atlas -With MongoDB Atlas, X.509 certificates are not Root CA certificates and will not work with the `sslCA` parameter as self-signed certificates would. If the `sslCA` parameter is used an error similar to the following would be raised: +With MongoDB Atlas, X.509 certificates are not Root CA certificates and will not work with the `tlsCAFile` parameter as self-signed certificates would. If the `tlsCAFile` parameter is used an error similar to the following would be raised: ```no-highlight MongoServerSelectionError: unable to get local issuer certificate ``` -To connect to a MongoDB Atlas cluster using X.509 authentication the correct option to set is `tlsCertificateKeyFile`. The connection string already specifies the `authSource` and `authMechanism`, and the DNS `TXT` record would supply the parameter and value for `sslValidate`, however they're included below as `connect()` options for completeness: +To connect to a MongoDB Atlas cluster using X.509 authentication the correct option to set is `tlsCertificateKeyFile`. The connection string already specifies the `authSource` and `authMechanism`, however they're included below as `connect()` options for completeness: ```javascript -const url = 'mongodb+srv://xyz.mongodb.net/test?authSource=%24external&authMechanism=MONGODB-X509'; +const url = + 'mongodb+srv://xyz.mongodb.net/test?authSource=%24external&authMechanism=MONGODB-X509'; await mongoose.connect(url, { - sslValidate: true, + tls: true, + // location of a local .pem file that contains both the client's certificate and key, e.g. tlsCertificateKeyFile: '/path/to/certificate.pem', authMechanism: 'MONGODB-X509', - authSource: '$external' + authSource: '$external', }); ``` From 1359c445c18c1e0a308001d9a8c960b75357ed81 Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Mon, 11 Dec 2023 14:00:28 +1100 Subject: [PATCH 03/16] Update TLS header in sidenav --- docs/layout.pug | 2 +- docs/tutorials/ssl.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/layout.pug b/docs/layout.pug index be171657cac..16dd2cf9257 100644 --- a/docs/layout.pug +++ b/docs/layout.pug @@ -62,7 +62,7 @@ html(lang='en') - if ([`${versions.versionedPath}/docs/connections`, `${versions.versionedPath}/docs/tutorials/ssl`].some(path => outputUrl.startsWith(path))) ul.pure-menu-list li.pure-menu-item.sub-item - a.pure-menu-link(href=`${versions.versionedPath}/docs/tutorials/ssl.html`, class=outputUrl === `${versions.versionedPath}/docs/tutorials/ssl.html` ? 'selected' : '') SSL Connections + a.pure-menu-link(href=`${versions.versionedPath}/docs/tutorials/ssl.html`, class=outputUrl === `${versions.versionedPath}/docs/tutorials/ssl.html` ? 'selected' : '') TLS/SSL Connections li.pure-menu-item.sub-item a.pure-menu-link(href=`${versions.versionedPath}/docs/models.html`, class=outputUrl === `${versions.versionedPath}/docs/models.html` ? 'selected' : '') Models - if ([`${versions.versionedPath}/docs/models`, `${versions.versionedPath}/docs/change-streams`].some(path => outputUrl.startsWith(path))) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 4e4a771c797..92422417bd8 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,4 +1,4 @@ -# TSL/SSL Connections +# TLS/SSL Connections Mongoose supports connecting to [MongoDB clusters that require TLS/SSL connections](https://www.mongodb.com/docs/manual/tutorial/configure-ssl/). Setting the either the `tls` or `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using TLS/SSL: From a3e4e3285d59e85ee5f944468ef8b7acb62d5567 Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Mon, 11 Dec 2023 14:12:30 +1100 Subject: [PATCH 04/16] Restore line lengths fixed by prettier --- docs/tutorials/ssl.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 92422417bd8..e744a021c06 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -72,14 +72,11 @@ If you're using [X.509 authentication](https://www.mongodb.com/docs/drivers/node ```javascript // Do this: const username = 'myusername'; -await mongoose.connect( - `mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, - { - tls: true, - tlsCAFile: `${__dirname}/rootCA.pem`, - authMechanism: 'MONGODB-X509', - } -); +await mongoose.connect(`mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, { + tls: true, + tlsCAFile: `${__dirname}/rootCA.pem`, + authMechanism: 'MONGODB-X509', +}); // Not this: await mongoose.connect('mongodb://127.0.0.1:27017/test', { @@ -101,11 +98,10 @@ MongoServerSelectionError: unable to get local issuer certificate To connect to a MongoDB Atlas cluster using X.509 authentication the correct option to set is `tlsCertificateKeyFile`. The connection string already specifies the `authSource` and `authMechanism`, however they're included below as `connect()` options for completeness: ```javascript -const url = - 'mongodb+srv://xyz.mongodb.net/test?authSource=%24external&authMechanism=MONGODB-X509'; +const url = 'mongodb+srv://xyz.mongodb.net/test?authSource=%24external&authMechanism=MONGODB-X509'; await mongoose.connect(url, { tls: true, - // location of a local .pem file that contains both the client's certificate and key, e.g. + // location of a local .pem file that contains both the client's certificate and key tlsCertificateKeyFile: '/path/to/certificate.pem', authMechanism: 'MONGODB-X509', authSource: '$external', From d7dd6c09407070bfb549ff23be7fcdc89b3d6ce0 Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Mon, 11 Dec 2023 14:25:56 +1100 Subject: [PATCH 05/16] Remove unused comment --- docs/tutorials/ssl.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index e744a021c06..6bcd4d605dc 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -50,8 +50,6 @@ await mongoose.connect('mongodb://127.0.0.1:27017/test', { tls: true, // For example, see https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89 // for where the `rootCA.pem` file comes from. - // Please note that, in Mongoose >= 5.8.3, `sslCA` needs to be - // the **path to** the CA file, **not** the contents of the CA file tlsCAFile: `${__dirname}/rootCA.pem`, }); ``` From e1001296afd6b11b5e081373dd97751497aadac8 Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Mon, 11 Dec 2023 12:35:49 +0900 Subject: [PATCH 06/16] fix: cast error when there is an elemMatch in the and clause --- lib/schema/array.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/schema/array.js b/lib/schema/array.js index 893c78f7b95..4791865a4f7 100644 --- a/lib/schema/array.js +++ b/lib/schema/array.js @@ -637,15 +637,15 @@ handle.$or = createLogicalQueryOperatorHandler('$or'); handle.$and = createLogicalQueryOperatorHandler('$and'); handle.$nor = createLogicalQueryOperatorHandler('$nor'); -function createLogicalQueryOperatorHandler(op) { - return function logicalQueryOperatorHandler(val) { +function createLogicalQueryOperatorHandler(op, context) { + return function logicalQueryOperatorHandler(val, context) { if (!Array.isArray(val)) { throw new TypeError('conditional ' + op + ' requires an array'); } const ret = []; for (const obj of val) { - ret.push(cast(this.casterConstructor.schema, obj, null, this && this.$$context)); + ret.push(cast(this.casterConstructor.schema ?? context.schema, obj, null, this && this.$$context)); } return ret; From eaf14250068d1353fc5eab38d6fdfe03f3e35d03 Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Tue, 12 Dec 2023 11:24:36 +0900 Subject: [PATCH 07/16] remove: unnecessary context --- lib/schema/array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schema/array.js b/lib/schema/array.js index 4791865a4f7..e73f16d2849 100644 --- a/lib/schema/array.js +++ b/lib/schema/array.js @@ -637,7 +637,7 @@ handle.$or = createLogicalQueryOperatorHandler('$or'); handle.$and = createLogicalQueryOperatorHandler('$and'); handle.$nor = createLogicalQueryOperatorHandler('$nor'); -function createLogicalQueryOperatorHandler(op, context) { +function createLogicalQueryOperatorHandler(op) { return function logicalQueryOperatorHandler(val, context) { if (!Array.isArray(val)) { throw new TypeError('conditional ' + op + ' requires an array'); From ea64e171eb833a1846d40e6e854827189168451d Mon Sep 17 00:00:00 2001 From: Andrew Welch Date: Wed, 13 Dec 2023 14:10:38 +1100 Subject: [PATCH 08/16] Use tls property over ssl - use `tls: true` for likelihood of ssl: true being removed - confirm tls is enabled by mongodb+srv:// https://www.mongodb.com/docs/manual/reference/connection-string/ --- docs/tutorials/ssl.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index 6bcd4d605dc..cbea4253445 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -1,16 +1,16 @@ # TLS/SSL Connections -Mongoose supports connecting to [MongoDB clusters that require TLS/SSL connections](https://www.mongodb.com/docs/manual/tutorial/configure-ssl/). Setting the either the `tls` or `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using TLS/SSL: +Mongoose supports connecting to [MongoDB clusters that require TLS/SSL connections](https://www.mongodb.com/docs/manual/tutorial/configure-ssl/). Setting the `tls` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using TLS/SSL: ```javascript -mongoose.connect('mongodb://127.0.0.1:27017/test', { ssl: true }); +mongoose.connect('mongodb://127.0.0.1:27017/test', { tls: true }); // Equivalent: -mongoose.connect('mongodb://127.0.0.1:27017/test?ssl=true'); +mongoose.connect('mongodb://127.0.0.1:27017/test?tls=true'); ``` -The `ssl` option defaults to `false` for connection strings that start with `mongodb://`. However, -the `ssl` option defaults to `true` for connection strings that start with `mongodb+srv://`. So if you are using an srv connection string to connect to [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), SSL is enabled by default. +The `tls` option defaults to `false` for connection strings that start with `mongodb://`. However, +the `tls` option defaults to `true` for connection strings that start with `mongodb+srv://`. So if you are using an srv connection string to connect to [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), TLS/SSL is enabled by default. If you try to connect to a MongoDB cluster that requires TLS/SSL without enabling the `tls`/`ssl` option, `mongoose.connect()` will error out with the below error: From bfed8a6193a2b3230b9bce2d38f5f1993116503c Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Tue, 12 Dec 2023 19:28:34 -0500 Subject: [PATCH 09/16] Allow defining index on base model that applies to all discriminators --- lib/helpers/indexes/getRelatedIndexes.js | 4 +- .../helpers/indexes.getRelatedIndexes.test.js | 40 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/helpers/indexes/getRelatedIndexes.js b/lib/helpers/indexes/getRelatedIndexes.js index 42d5798c623..b323be84c16 100644 --- a/lib/helpers/indexes/getRelatedIndexes.js +++ b/lib/helpers/indexes/getRelatedIndexes.js @@ -46,7 +46,9 @@ function getRelatedIndexes({ return indexes.filter(index => { const partialFilterExpression = getPartialFilterExpression(index, indexesType); - return !partialFilterExpression || !partialFilterExpression[discriminatorKey]; + return !partialFilterExpression + || !partialFilterExpression[discriminatorKey] + || partialFilterExpression[discriminatorKey]['$exists']; }); } diff --git a/test/helpers/indexes.getRelatedIndexes.test.js b/test/helpers/indexes.getRelatedIndexes.test.js index 3eb597f883d..de71b9e324a 100644 --- a/test/helpers/indexes.getRelatedIndexes.test.js +++ b/test/helpers/indexes.getRelatedIndexes.test.js @@ -92,6 +92,46 @@ describe('getRelatedIndexes', () => { ] ); }); + it('with base model that has discriminator, it includes discriminator indexes that only checks for existence', () => { + // Arrange + const eventSchema = new Schema( + { actorId: { type: Schema.Types.ObjectId } }, + { autoIndex: false } + ); + eventSchema.index({ actorId: 1 }, + { unique: true, + partialFilterExpression: { + __t: { $exists: true } + } + }); + + const Event = db.model('Event', eventSchema); + + const clickEventSchema = new Schema( + { + clickedAt: Date, + productCategory: String + }, + { autoIndex: false } + ); + Event.discriminator('ClickEvent', clickEventSchema); + + // Act + const filteredSchemaIndexes = getRelatedSchemaIndexes(Event, Event.schema.indexes()); + + // Assert + assert.deepStrictEqual( + filteredSchemaIndexes, + [ + [{ actorId: 1 }, + { background: true, + unique: true, + partialFilterExpression: { __t: { $exists: true } } + } + ] + ] + ); + }); it('with discriminator model, it only gets discriminator indexes', () => { // Arrange const eventSchema = new Schema( From b052e65907ee08c70f4da4adf47c75632a071f9e Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Thu, 14 Dec 2023 18:55:13 +0900 Subject: [PATCH 10/16] add: test for nested $and in $elemMatch --- test/model.query.casting.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/model.query.casting.test.js b/test/model.query.casting.test.js index c287089461c..c7156959fc5 100644 --- a/test/model.query.casting.test.js +++ b/test/model.query.casting.test.js @@ -791,6 +791,38 @@ describe('model query casting', function() { assert.ok(res); assert.deepStrictEqual(res.map(doc => doc.arr[1].id), ['two', 'three']); }); + + it('should not throw a cast error when dealing with an array of objects in combination with $elemMatch and nested $and', async function() { + const testSchema = new Schema({ + arr: [Object] + }); + + const Test = db.model('Test', testSchema); + const obj1 = new Test({ arr: [{ id: 'one', name: 'sample1' }, { id: 'two' }] }); + await obj1.save(); + + const obj2 = new Test({ arr: [{ id: 'two', name: 'sample1' }, { id: 'three' }] }); + await obj2.save(); + + const obj3 = new Test({ arr: [{ id: 'three', name: 'sample1' }, { id: 'four' }] }); + await obj3.save(); + const res = await Test.find({ + arr: { + $elemMatch: { + $and: [ + { name: 'sample1' }, + { $or: [ + { id: 'one' }, + { id: 'two' } + ] } + ] + } + } + }).sort({ _id: 1 }); + assert.ok(res); + assert.equal(res.length, 2); + assert.deepStrictEqual(res.map(doc => doc.arr[1].id), ['two', 'three']); + }); }); function _geojsonPoint(coordinates) { From 48477211d42aa6430519b20799c40046fe9cd375 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 14 Dec 2023 18:03:39 -0500 Subject: [PATCH 11/16] fix: apply setters in castForQuery with uuid Re: #14114 --- lib/schema/uuid.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/schema/uuid.js b/lib/schema/uuid.js index 41ab1f60e49..aa72c42107f 100644 --- a/lib/schema/uuid.js +++ b/lib/schema/uuid.js @@ -344,8 +344,15 @@ SchemaUUID.prototype.castForQuery = function($conditional, val, context) { if (!handler) throw new Error('Can\'t use ' + $conditional + ' with UUID.'); return handler.call(this, val, context); - } else { - return this.cast(val); + } + + try { + return this.applySetters(val, context); + } catch (err) { + if (err instanceof CastError && err.path === this.path && this.$fullPath != null) { + err.path = this.$fullPath; + } + throw err; } }; From 909c773a58b78a862bd76b09ab2fbddde1d98dde Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 21 Dec 2023 11:10:24 -0500 Subject: [PATCH 12/16] Update getRelatedIndexes.js --- lib/helpers/indexes/getRelatedIndexes.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/helpers/indexes/getRelatedIndexes.js b/lib/helpers/indexes/getRelatedIndexes.js index b323be84c16..a22a5e1202d 100644 --- a/lib/helpers/indexes/getRelatedIndexes.js +++ b/lib/helpers/indexes/getRelatedIndexes.js @@ -1,5 +1,7 @@ 'use strict'; +const hasDollarKeys = require('../query/hasDollarKeys'); + function getRelatedSchemaIndexes(model, schemaIndexes) { return getRelatedIndexes({ baseModelName: model.baseModelName, @@ -48,7 +50,7 @@ function getRelatedIndexes({ const partialFilterExpression = getPartialFilterExpression(index, indexesType); return !partialFilterExpression || !partialFilterExpression[discriminatorKey] - || partialFilterExpression[discriminatorKey]['$exists']; + || (hasDollarKeys(partialFilterExpression[discriminatorKey]) && !('$eq' in partialFilterExpression[discriminatorKey])); }); } From 4636028cb310c7aa7cde7d6a27546bbb557fc766 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 21 Dec 2023 12:04:43 -0500 Subject: [PATCH 13/16] try only running failing test for debug --- test/schema.select.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/schema.select.test.js b/test/schema.select.test.js index 70631978c76..106366f8bbb 100644 --- a/test/schema.select.test.js +++ b/test/schema.select.test.js @@ -25,7 +25,7 @@ describe('schema select option', function() { afterEach(() => require('./util').clearTestData(db)); afterEach(() => require('./util').stopRemainingOps(db)); - it('excluding paths through schematype', async function() { + it.only('excluding paths through schematype', async function() { const schema = new Schema({ thin: Boolean, name: { type: String, select: false }, From 6d4f21534765f1091b88605ea91d700d4ba9f321 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 21 Dec 2023 12:09:48 -0500 Subject: [PATCH 14/16] add debug option to try to debug deno failure in GitHub actions --- test/schema.select.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/schema.select.test.js b/test/schema.select.test.js index 106366f8bbb..a45cf565bd8 100644 --- a/test/schema.select.test.js +++ b/test/schema.select.test.js @@ -15,17 +15,19 @@ describe('schema select option', function() { before(function() { db = start(); + mongoose.set('debug', true); }); after(async function() { await db.close(); + mongoose.set('debug', false); }); beforeEach(() => db.deleteModel(/.*/)); afterEach(() => require('./util').clearTestData(db)); afterEach(() => require('./util').stopRemainingOps(db)); - it.only('excluding paths through schematype', async function() { + it('excluding paths through schematype', async function() { const schema = new Schema({ thin: Boolean, name: { type: String, select: false }, From fed9a3f8bbefc74eb7f3e9c85914ff349e8415e0 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 21 Dec 2023 12:19:15 -0500 Subject: [PATCH 15/16] try commenting out potential offending code to debug deno issues --- test/schema.select.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/schema.select.test.js b/test/schema.select.test.js index a45cf565bd8..21775a070da 100644 --- a/test/schema.select.test.js +++ b/test/schema.select.test.js @@ -55,14 +55,14 @@ describe('schema select option', function() { assert.equal(findByIdDocAgain.isSelected('name'), false); assert.equal(findByIdDocAgain.isSelected('docs.name'), false); assert.strictEqual(undefined, findByIdDocAgain.name); - const findUpdateDoc = await Test.findOneAndUpdate({ _id: doc._id }); + /*const findUpdateDoc = await Test.findOneAndUpdate({ _id: doc._id }); assert.equal(findUpdateDoc.isSelected('name'), false); assert.equal(findUpdateDoc.isSelected('docs.name'), false); assert.strictEqual(undefined, findUpdateDoc.name); const findAndDeleteDoc = await Test.findOneAndDelete({ _id: doc._id }); assert.equal(findAndDeleteDoc.isSelected('name'), false); assert.equal(findAndDeleteDoc.isSelected('docs.name'), false); - assert.strictEqual(undefined, findAndDeleteDoc.name); + assert.strictEqual(undefined, findAndDeleteDoc.name);*/ }); it('including paths through schematype', async function() { From 6f7b6593d4e7286774972bdb35c82ec2a61ce2cd Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 24 Dec 2023 09:07:38 -0500 Subject: [PATCH 16/16] test: fix deno tests --- test/schema.select.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/schema.select.test.js b/test/schema.select.test.js index 21775a070da..1b739978a4f 100644 --- a/test/schema.select.test.js +++ b/test/schema.select.test.js @@ -55,14 +55,14 @@ describe('schema select option', function() { assert.equal(findByIdDocAgain.isSelected('name'), false); assert.equal(findByIdDocAgain.isSelected('docs.name'), false); assert.strictEqual(undefined, findByIdDocAgain.name); - /*const findUpdateDoc = await Test.findOneAndUpdate({ _id: doc._id }); + const findUpdateDoc = await Test.findOneAndUpdate({ _id: doc._id }, { name: 'the excluded' }); assert.equal(findUpdateDoc.isSelected('name'), false); assert.equal(findUpdateDoc.isSelected('docs.name'), false); assert.strictEqual(undefined, findUpdateDoc.name); const findAndDeleteDoc = await Test.findOneAndDelete({ _id: doc._id }); assert.equal(findAndDeleteDoc.isSelected('name'), false); assert.equal(findAndDeleteDoc.isSelected('docs.name'), false); - assert.strictEqual(undefined, findAndDeleteDoc.name);*/ + assert.strictEqual(undefined, findAndDeleteDoc.name); }); it('including paths through schematype', async function() {