diff --git a/lib/operations/db_ops.js b/lib/operations/db_ops.js index 0551e600d5..86f4d4393e 100644 --- a/lib/operations/db_ops.js +++ b/lib/operations/db_ops.js @@ -1,13 +1,10 @@ 'use strict'; - -const crypto = require('crypto'); const ReadPreference = require('../read_preference'); const { BSON: { Code } } = require('../deps'); const { MongoError } = require('../error'); const CONSTANTS = require('../constants'); -const { count, findOne, remove, updateOne } = require('./collection_ops'); const { applyWriteConcern, debugOptions, @@ -17,21 +14,6 @@ const { MongoDBNamespace } = require('../utils'); -let collection; -function loadCollection() { - if (!collection) { - collection = require('../collection'); - } - return collection; -} -let db; -function loadDb() { - if (!db) { - db = require('../db'); - } - return db; -} - const debugFields = [ 'authSource', 'w', @@ -52,114 +34,6 @@ const debugFields = [ 'noListener' ]; -/** - * Add a user to the database. - * - * @function - * @param {Db} db The Db instance on which to add a user. - * @param {string} username The username. - * @param {string} password The password. - * @param {object} [options] Optional settings. See Db.prototype.addUser for a list of options. - * @param {Db~resultCallback} [callback] The command result callback - */ -function addUser(db, username, password, options, callback) { - let Db = loadDb(); - - // Did the user destroy the topology - if (db.serverConfig && db.serverConfig.isDestroyed()) - return callback(new MongoError('topology was destroyed')); - // Attempt to execute auth command - executeAuthCreateUserCommand(db, username, password, options, (err, r) => { - // We need to perform the backward compatible insert operation - if (err && err.code === -5000) { - const finalOptions = applyWriteConcern(Object.assign({}, options), { db }, options); - - // Use node md5 generator - const md5 = crypto.createHash('md5'); - // Generate keys used for authentication - md5.update(username + ':mongo:' + password); - const userPassword = md5.digest('hex'); - - // If we have another db set - const dbToUse = options.dbName ? new Db(options.dbName, db.s.topology, db.s.options) : db; - - // Fetch a user collection - const collection = dbToUse.collection(CONSTANTS.SYSTEM_USER_COLLECTION); - - // Check if we are inserting the first user - count(collection, {}, finalOptions, (err, count) => { - // We got an error (f.ex not authorized) - if (err != null) return handleCallback(callback, err, null); - // Check if the user exists and update i - const findOptions = Object.assign({ projection: { dbName: 1 } }, finalOptions); - collection.find({ user: username }, findOptions).toArray(err => { - // We got an error (f.ex not authorized) - if (err != null) return handleCallback(callback, err, null); - // Add command keys - finalOptions.upsert = true; - - // We have a user, let's update the password or upsert if not - updateOne( - collection, - { user: username }, - { $set: { user: username, pwd: userPassword } }, - finalOptions, - err => { - if (count === 0 && err) - return handleCallback(callback, null, [{ user: username, pwd: userPassword }]); - if (err) return handleCallback(callback, err, null); - handleCallback(callback, null, [{ user: username, pwd: userPassword }]); - } - ); - }); - }); - - return; - } - - if (err) return handleCallback(callback, err); - handleCallback(callback, err, r); - }); -} - -/** - * Fetch all collections for the current db. - * - * @function - * @param {Db} db The Db instance on which to fetch collections. - * @param {object} [options] Optional settings. See Db.prototype.collections for a list of options. - * @param {Db~collectionsResultCallback} [callback] The results callback - */ -function collections(db, options, callback) { - let Collection = loadCollection(); - - options = Object.assign({}, options, { nameOnly: true }); - // Let's get the collection names - db.listCollections({}, options).toArray((err, documents) => { - if (err != null) return handleCallback(callback, err, null); - // Filter collections removing any illegal ones - documents = documents.filter(doc => { - return doc.name.indexOf('$') === -1; - }); - - // Return the collection objects - handleCallback( - callback, - null, - documents.map(d => { - return new Collection( - db, - db.s.topology, - db.databaseName, - d.name, - db.s.pkFactory, - db.s.options - ); - }) - ); - }); -} - /** * Creates an index on the db and collection. * @@ -242,50 +116,6 @@ function createListener(db, e, object) { return listener; } -/** - * Drop a collection from the database, removing it permanently. New accesses will create a new collection. - * - * @function - * @param {Db} db The Db instance on which to drop the collection. - * @param {string} name Name of collection to drop - * @param {object} [options] Optional settings. See Db.prototype.dropCollection for a list of options. - * @param {Db~resultCallback} [callback] The results callback - */ -function dropCollection(db, name, options, callback) { - executeCommand(db, name, options, (err, result) => { - // Did the user destroy the topology - if (db.serverConfig && db.serverConfig.isDestroyed()) { - return callback(new MongoError('topology was destroyed')); - } - - if (err) return handleCallback(callback, err); - if (result.ok) return handleCallback(callback, null, true); - handleCallback(callback, null, false); - }); -} - -/** - * Drop a database, removing it permanently from the server. - * - * @function - * @param {Db} db The Db instance to drop. - * @param {object} cmd The command document. - * @param {object} [options] Optional settings. See Db.prototype.dropDatabase for a list of options. - * @param {Db~resultCallback} [callback] The results callback - */ -function dropDatabase(db, cmd, options, callback) { - executeCommand(db, cmd, options, (err, result) => { - // Did the user destroy the topology - if (db.serverConfig && db.serverConfig.isDestroyed()) { - return callback(new MongoError('topology was destroyed')); - } - - if (callback == null) return; - if (err) return handleCallback(callback, err, null); - handleCallback(callback, null, result.ok ? true : false); - }); -} - /** * Ensures that an index exists. If it does not, creates it. * @@ -497,44 +327,6 @@ function profilingInfo(db, options, callback) { } } -/** - * Remove a user from a database - * - * @function - * @param {Db} db The Db instance on which to remove the user. - * @param {string} username The username. - * @param {object} [options] Optional settings. See Db.prototype.removeUser for a list of options. - * @param {Db~resultCallback} [callback] The command result callback - */ -function removeUser(db, username, options, callback) { - let Db = loadDb(); - - // Attempt to execute command - executeAuthRemoveUserCommand(db, username, options, (err, result) => { - if (err && err.code === -5000) { - const finalOptions = applyWriteConcern(Object.assign({}, options), { db }, options); - // If we have another db set - const db = options.dbName ? new Db(options.dbName, db.s.topology, db.s.options) : db; - - // Fetch a user collection - const collection = db.collection(CONSTANTS.SYSTEM_USER_COLLECTION); - - // Locate the user - findOne(collection, { user: username }, finalOptions, (err, user) => { - if (user == null) return handleCallback(callback, err, false); - remove(collection, { user: username }, finalOptions, err => { - handleCallback(callback, err, true); - }); - }); - - return; - } - - if (err) return handleCallback(callback, err); - handleCallback(callback, err, result); - }); -} - // Validate the database name function validateDatabaseName(databaseName) { if (typeof databaseName !== 'string') @@ -659,165 +451,14 @@ function createIndexUsingCreateIndexes(db, name, fieldOrSpec, options, callback) }); } -/** - * Run the createUser command. - * - * @param {Db} db The Db instance on which to execute the command. - * @param {string} username The username of the user to add. - * @param {string} password The password of the user to add. - * @param {object} [options] Optional settings. See Db.prototype.addUser for a list of options. - * @param {Db~resultCallback} [callback] The command result callback - */ -function executeAuthCreateUserCommand(db, username, password, options, callback) { - // Special case where there is no password ($external users) - if (typeof username === 'string' && password != null && typeof password === 'object') { - options = password; - password = null; - } - - // Unpack all options - if (typeof options === 'function') { - callback = options; - options = {}; - } - - // Error out if we digestPassword set - if (options.digestPassword != null) { - return callback( - toError( - "The digestPassword option is not supported via add_user. Please use db.command('createUser', ...) instead for this option." - ) - ); - } - - // Get additional values - const customData = options.customData != null ? options.customData : {}; - let roles = Array.isArray(options.roles) ? options.roles : []; - const maxTimeMS = typeof options.maxTimeMS === 'number' ? options.maxTimeMS : null; - - // If not roles defined print deprecated message - if (roles.length === 0) { - console.log('Creating a user without roles is deprecated in MongoDB >= 2.6'); - } - - // Get the error options - const commandOptions = { writeCommand: true }; - if (options['dbName']) commandOptions.dbName = options['dbName']; - - // Add maxTimeMS to options if set - if (maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS; - - // Check the db name and add roles if needed - if ( - (db.databaseName.toLowerCase() === 'admin' || options.dbName === 'admin') && - !Array.isArray(options.roles) - ) { - roles = ['root']; - } else if (!Array.isArray(options.roles)) { - roles = ['dbOwner']; - } - - const digestPassword = db.s.topology.lastIsMaster().maxWireVersion >= 7; - - // Build the command to execute - let command = { - createUser: username, - customData: customData, - roles: roles, - digestPassword - }; - - // Apply write concern to command - command = applyWriteConcern(command, { db }, options); - - let userPassword = password; - - if (!digestPassword) { - // Use node md5 generator - const md5 = crypto.createHash('md5'); - // Generate keys used for authentication - md5.update(username + ':mongo:' + password); - userPassword = md5.digest('hex'); - } - - // No password - if (typeof password === 'string') { - command.pwd = userPassword; - } - - // Force write using primary - commandOptions.readPreference = ReadPreference.primary; - - // Execute the command - executeCommand(db, command, commandOptions, (err, result) => { - if (err && err.ok === 0 && err.code === undefined) - return handleCallback(callback, { code: -5000 }, null); - if (err) return handleCallback(callback, err, null); - handleCallback( - callback, - !result.ok ? toError(result) : null, - result.ok ? [{ user: username, pwd: '' }] : null - ); - }); -} - -/** - * Run the dropUser command. - * - * @param {Db} db The Db instance on which to execute the command. - * @param {string} username The username of the user to remove. - * @param {object} [options] Optional settings. See Db.prototype.removeUser for a list of options. - * @param {Db~resultCallback} [callback] The command result callback - */ -function executeAuthRemoveUserCommand(db, username, options, callback) { - if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - - // Did the user destroy the topology - if (db.serverConfig && db.serverConfig.isDestroyed()) - return callback(new MongoError('topology was destroyed')); - // Get the error options - const commandOptions = { writeCommand: true }; - if (options['dbName']) commandOptions.dbName = options['dbName']; - - // Get additional values - const maxTimeMS = typeof options.maxTimeMS === 'number' ? options.maxTimeMS : null; - - // Add maxTimeMS to options if set - if (maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS; - - // Build the command to execute - let command = { - dropUser: username - }; - - // Apply write concern to command - command = applyWriteConcern(command, { db }, options); - - // Force write using primary - commandOptions.readPreference = ReadPreference.primary; - - // Execute the command - executeCommand(db, command, commandOptions, (err, result) => { - if (err && !err.ok && err.code === undefined) return handleCallback(callback, { code: -5000 }); - if (err) return handleCallback(callback, err, null); - handleCallback(callback, null, result.ok ? true : false); - }); -} - module.exports = { - addUser, - collections, createListener, createIndex, - dropCollection, - dropDatabase, ensureIndex, evaluate, executeCommand, executeDbAdminCommand, indexInformation, profilingInfo, - removeUser, validateDatabaseName }; diff --git a/test/benchmarks/driverBench/common.js b/test/benchmarks/driverBench/common.js index f0c593d3ed..696312d85a 100644 --- a/test/benchmarks/driverBench/common.js +++ b/test/benchmarks/driverBench/common.js @@ -2,8 +2,8 @@ const fs = require('fs'); const path = require('path'); -const MongoClient = require('../../lib/mongo_client'); -const GridFsBucket = require('../../lib/gridfs-stream'); +const MongoClient = require('../../../lib/mongo_client'); +const GridFsBucket = require('../../../lib/gridfs-stream'); const DB_NAME = 'perftest'; const COLLECTION_NAME = 'corpus';