From 516e28d436160db0b2d95712bcc01d78bf07e894 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Wed, 3 Nov 2021 15:58:34 +0100 Subject: [PATCH 1/2] feat(NODE-3728): Allow to pass authorizedCollections option to the db.listCollections method --- src/operations/list_collections.ts | 7 +- test/unit/operations/list_collections.test.js | 101 ++++++++++++++++-- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/operations/list_collections.ts b/src/operations/list_collections.ts index 82c8004d379..b9e704cfd53 100644 --- a/src/operations/list_collections.ts +++ b/src/operations/list_collections.ts @@ -15,6 +15,8 @@ const LIST_COLLECTIONS_WIRE_VERSION = 3; export interface ListCollectionsOptions extends CommandOperationOptions { /** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */ nameOnly?: boolean; + /** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */ + authorizedCollections?: boolean; /** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */ batchSize?: number; } @@ -25,6 +27,7 @@ export class ListCollectionsOperation extends CommandOperation { db: Db; filter: Document; nameOnly: boolean; + authorizedCollections: boolean; batchSize?: number; constructor(db: Db, filter: Document, options?: ListCollectionsOptions) { @@ -34,6 +37,7 @@ export class ListCollectionsOperation extends CommandOperation { this.db = db; this.filter = filter; this.nameOnly = !!this.options.nameOnly; + this.authorizedCollections = !!this.options.authorizedCollections; if (typeof this.options.batchSize === 'number') { this.batchSize = this.options.batchSize; @@ -99,7 +103,8 @@ export class ListCollectionsOperation extends CommandOperation { listCollections: 1, filter: this.filter, cursor: this.batchSize ? { batchSize: this.batchSize } : {}, - nameOnly: this.nameOnly + nameOnly: this.nameOnly, + authorizedCollections: this.authorizedCollections }; } } diff --git a/test/unit/operations/list_collections.test.js b/test/unit/operations/list_collections.test.js index 541edc37f71..cf8ea48aa9c 100644 --- a/test/unit/operations/list_collections.test.js +++ b/test/unit/operations/list_collections.test.js @@ -12,7 +12,7 @@ describe('ListCollectionsOperation', function () { const operation = new ListCollectionsOperation(db, {}, { nameOnly: true, dbName: db }); it('sets nameOnly to true', function () { - expect(operation.nameOnly).to.be.true; + expect(operation).to.have.property('nameOnly', true); }); }); @@ -20,7 +20,33 @@ describe('ListCollectionsOperation', function () { const operation = new ListCollectionsOperation(db, {}, { nameOnly: false, dbName: db }); it('sets nameOnly to false', function () { - expect(operation.nameOnly).to.be.false; + expect(operation).to.have.property('nameOnly', false); + }); + }); + }); + + context('when authorizedCollections is provided', function () { + context('when authorizedCollections is true', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: true, dbName: db } + ); + + it('sets authorizedCollections to true', function () { + expect(operation).to.have.property('authorizedCollections', true); + }); + }); + + context('when authorizedCollections is false', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: false, dbName: db } + ); + + it('sets authorizedCollections to false', function () { + expect(operation).to.have.property('authorizedCollections', false); }); }); }); @@ -29,7 +55,15 @@ describe('ListCollectionsOperation', function () { const operation = new ListCollectionsOperation(db, {}, { dbName: db }); it('sets nameOnly to false', function () { - expect(operation.nameOnly).to.be.false; + expect(operation).to.have.property('nameOnly', false); + }); + }); + + context('when authorizedCollections is not provided', function () { + const operation = new ListCollectionsOperation(db, {}, { dbName: db }); + + it('sets authorizedCollections to false', function () { + expect(operation).to.have.property('authorizedCollections', false); }); }); }); @@ -44,7 +78,8 @@ describe('ListCollectionsOperation', function () { listCollections: 1, cursor: {}, filter: {}, - nameOnly: true + nameOnly: true, + authorizedCollections: false }); }); }); @@ -57,7 +92,46 @@ describe('ListCollectionsOperation', function () { listCollections: 1, cursor: {}, filter: {}, - nameOnly: false + nameOnly: false, + authorizedCollections: false + }); + }); + }); + }); + + context('when authorizedCollections is provided', function () { + context('when authorizedCollections is true', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: true, dbName: db } + ); + + it('sets authorizedCollections to true', function () { + expect(operation.generateCommand()).to.deep.equal({ + listCollections: 1, + cursor: {}, + filter: {}, + nameOnly: false, + authorizedCollections: true + }); + }); + }); + + context('when authorizedCollections is false', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: false, dbName: db } + ); + + it('sets authorizedCollections to false', function () { + expect(operation.generateCommand()).to.deep.equal({ + listCollections: 1, + cursor: {}, + filter: {}, + nameOnly: false, + authorizedCollections: false }); }); }); @@ -71,7 +145,22 @@ describe('ListCollectionsOperation', function () { listCollections: 1, cursor: {}, filter: {}, - nameOnly: false + nameOnly: false, + authorizedCollections: false + }); + }); + }); + + context('when authorizedCollections is not provided', function () { + const operation = new ListCollectionsOperation(db, {}, { dbName: db }); + + it('sets authorizedCollections to false', function () { + expect(operation.generateCommand()).to.deep.equal({ + listCollections: 1, + cursor: {}, + filter: {}, + nameOnly: false, + authorizedCollections: false }); }); }); From fa8a5140f3995f37a640d0d03099df6b17704812 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Fri, 5 Nov 2021 16:56:48 +0100 Subject: [PATCH 2/2] test(list_collections): Merge similar tests and test contexts into one --- test/unit/operations/list_collections.test.js | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/test/unit/operations/list_collections.test.js b/test/unit/operations/list_collections.test.js index cf8ea48aa9c..d63d7c0c160 100644 --- a/test/unit/operations/list_collections.test.js +++ b/test/unit/operations/list_collections.test.js @@ -51,16 +51,12 @@ describe('ListCollectionsOperation', function () { }); }); - context('when nameOnly is not provided', function () { + context('when no options are provided', function () { const operation = new ListCollectionsOperation(db, {}, { dbName: db }); it('sets nameOnly to false', function () { expect(operation).to.have.property('nameOnly', false); }); - }); - - context('when authorizedCollections is not provided', function () { - const operation = new ListCollectionsOperation(db, {}, { dbName: db }); it('sets authorizedCollections to false', function () { expect(operation).to.have.property('authorizedCollections', false); @@ -137,24 +133,10 @@ describe('ListCollectionsOperation', function () { }); }); - context('when nameOnly is not provided', function () { + context('when no options are provided', function () { const operation = new ListCollectionsOperation(db, {}, { dbName: db }); - it('sets nameOnly to false', function () { - expect(operation.generateCommand()).to.deep.equal({ - listCollections: 1, - cursor: {}, - filter: {}, - nameOnly: false, - authorizedCollections: false - }); - }); - }); - - context('when authorizedCollections is not provided', function () { - const operation = new ListCollectionsOperation(db, {}, { dbName: db }); - - it('sets authorizedCollections to false', function () { + it('sets nameOnly and authorizedCollections properties to false', function () { expect(operation.generateCommand()).to.deep.equal({ listCollections: 1, cursor: {},