From 76e51b2c4bdadac666276cb4ef3f8dfea0f023a8 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Mon, 1 Nov 2021 16:08:40 +0100 Subject: [PATCH] feat(NODE-3728): Allow to pass authorizedCollections option to the db.listCollections method --- src/operations/list_collections.ts | 7 ++++++- .../unit_db_list_collections.test.js | 20 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/operations/list_collections.ts b/src/operations/list_collections.ts index 4ba93ea82c..15e6d1cd95 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; @@ -94,7 +98,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 }; return super.executeCommand(server, session, command, callback); diff --git a/test/functional/unit_db_list_collections.test.js b/test/functional/unit_db_list_collections.test.js index 9baa658ad4..d930dde2d4 100644 --- a/test/functional/unit_db_list_collections.test.js +++ b/test/functional/unit_db_list_collections.test.js @@ -34,17 +34,27 @@ describe('db.listCollections', function () { { description: 'should always send nameOnly option, defaulting to false', command: db => db.listCollections().toArray(() => {}), - listCollectionsValue: false + listCollectionsOptions: { nameOnly: false } }, { description: 'should propagate the nameOnly option', command: db => db.listCollections({}, { nameOnly: true }).toArray(() => {}), - listCollectionsValue: true + listCollectionsOptions: { nameOnly: true } + }, + { + description: 'should always send authorizedCollections option, defaulting to false', + command: db => db.listCollections().toArray(() => {}), + listCollectionsOptions: { authorizedCollections: false } + }, + { + description: 'should propagate the authorizedCollections option', + command: db => db.listCollections({}, { authorizedCollections: true }).toArray(() => {}), + listCollectionsOptions: { authorizedCollections: true } }, { description: 'should send nameOnly: true for db.collections', command: db => db.collections(() => {}), - listCollectionsValue: true + listCollectionsOptions: { nameOnly: true } } ].forEach(config => { function testFn(done) { @@ -59,7 +69,9 @@ describe('db.listCollections', function () { client.on('commandStarted', e => { if (e.commandName === 'listCollections') { try { - expect(e).to.have.nested.property('command.nameOnly', config.listCollectionsValue); + for (const [name, value] of Object.entries(config.listCollectionsOptions)) { + expect(e).to.have.nested.property(`command.${name}`, value); + } client.close(done); } catch (err) { client.close(() => done(err));