diff --git a/lib/command_utils.js b/lib/command_utils.js new file mode 100644 index 0000000000..ba8289c326 --- /dev/null +++ b/lib/command_utils.js @@ -0,0 +1,122 @@ +'use strict'; +const Msg = require('./core/connection/msg').Msg; +const KillCursor = require('./core/connection/commands').KillCursor; +const GetMore = require('./core/connection/commands').GetMore; + +/** Commands that we want to redact because of the sensitive nature of their contents */ +const SENSITIVE_COMMANDS = new Set([ + 'authenticate', + 'saslStart', + 'saslContinue', + 'getnonce', + 'createUser', + 'updateUser', + 'copydbgetnonce', + 'copydbsaslstart', + 'copydb' +]); + +const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']); + +const LEGACY_FIND_QUERY_MAP = { + $query: 'filter', + $orderby: 'sort', + $hint: 'hint', + $comment: 'comment', + $maxScan: 'maxScan', + $max: 'max', + $min: 'min', + $returnKey: 'returnKey', + $showDiskLoc: 'showRecordId', + $maxTimeMS: 'maxTimeMS', + $snapshot: 'snapshot' +}; + +const LEGACY_FIND_OPTIONS_MAP = { + numberToSkip: 'skip', + numberToReturn: 'batchSize', + returnFieldsSelector: 'projection' +}; + +const OP_QUERY_KEYS = [ + 'tailable', + 'oplogReplay', + 'noCursorTimeout', + 'awaitData', + 'partial', + 'exhaust' +]; + +const collectionName = command => command.ns.split('.')[1]; + +const shouldRedactCommand = (commandName, cmd) => + SENSITIVE_COMMANDS.has(commandName) || + (HELLO_COMMANDS.has(commandName) && !!cmd.speculativeAuthenticate); + +/** + * Extract the actual command from the query, possibly upconverting if it's a legacy + * format + * + * @param {Object} command the command + */ +const extractCommand = command => { + let extractedCommand; + if (command instanceof GetMore) { + extractedCommand = { + getMore: command.cursorId, + collection: collectionName(command), + batchSize: command.numberToReturn + }; + } else if (command instanceof KillCursor) { + extractedCommand = { + killCursors: collectionName(command), + cursors: command.cursorIds + }; + } else if (command instanceof Msg) { + extractedCommand = command.command; + } else if (command.query && command.query.$query) { + let result; + if (command.ns === 'admin.$cmd') { + // upconvert legacy command + result = Object.assign({}, command.query.$query); + } else { + // upconvert legacy find command + result = { find: collectionName(command) }; + Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => { + if (typeof command.query[key] !== 'undefined') + result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key]; + }); + } + + Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => { + if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key]; + }); + + OP_QUERY_KEYS.forEach(key => { + if (command[key]) result[key] = command[key]; + }); + + if (typeof command.pre32Limit !== 'undefined') { + result.limit = command.pre32Limit; + } + + if (command.query.$explain) { + extractedCommand = { explain: result }; + } else { + extractedCommand = result; + } + } else { + extractedCommand = command.query || command; + } + + const commandName = Object.keys(extractedCommand)[0]; + return { + cmd: extractedCommand, + name: commandName, + shouldRedact: shouldRedactCommand(commandName, extractedCommand) + }; +}; + +module.exports = { + extractCommand +}; diff --git a/lib/core/connection/apm.js b/lib/core/connection/apm.js index 85f991b12a..875e418262 100644 --- a/lib/core/connection/apm.js +++ b/lib/core/connection/apm.js @@ -1,123 +1,16 @@ 'use strict'; -const Msg = require('../connection/msg').Msg; const KillCursor = require('../connection/commands').KillCursor; const GetMore = require('../connection/commands').GetMore; const calculateDurationInMs = require('../../utils').calculateDurationInMs; - -/** Commands that we want to redact because of the sensitive nature of their contents */ -const SENSITIVE_COMMANDS = new Set([ - 'authenticate', - 'saslStart', - 'saslContinue', - 'getnonce', - 'createUser', - 'updateUser', - 'copydbgetnonce', - 'copydbsaslstart', - 'copydb' -]); - -const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']); +const extractCommand = require('../../command_utils').extractCommand; // helper methods const namespace = command => command.ns; const databaseName = command => command.ns.split('.')[0]; -const collectionName = command => command.ns.split('.')[1]; const generateConnectionId = pool => pool.options ? `${pool.options.host}:${pool.options.port}` : pool.address; -const shouldRedactCommand = (commandName, cmd) => - SENSITIVE_COMMANDS.has(commandName) || - (HELLO_COMMANDS.has(commandName) && !!cmd.speculativeAuthenticate); const isLegacyPool = pool => pool.s && pool.queue; -const LEGACY_FIND_QUERY_MAP = { - $query: 'filter', - $orderby: 'sort', - $hint: 'hint', - $comment: 'comment', - $maxScan: 'maxScan', - $max: 'max', - $min: 'min', - $returnKey: 'returnKey', - $showDiskLoc: 'showRecordId', - $maxTimeMS: 'maxTimeMS', - $snapshot: 'snapshot' -}; - -const LEGACY_FIND_OPTIONS_MAP = { - numberToSkip: 'skip', - numberToReturn: 'batchSize', - returnFieldsSelector: 'projection' -}; - -const OP_QUERY_KEYS = [ - 'tailable', - 'oplogReplay', - 'noCursorTimeout', - 'awaitData', - 'partial', - 'exhaust' -]; - -/** - * Extract the actual command from the query, possibly upconverting if it's a legacy - * format - * - * @param {Object} command the command - */ -const extractCommand = command => { - let extractedCommand; - if (command instanceof GetMore) { - extractedCommand = { - getMore: command.cursorId, - collection: collectionName(command), - batchSize: command.numberToReturn - }; - } else if (command instanceof KillCursor) { - extractedCommand = { - killCursors: collectionName(command), - cursors: command.cursorIds - }; - } else if (command instanceof Msg) { - extractedCommand = command.command; - } else if (command.query && command.query.$query) { - let result; - if (command.ns === 'admin.$cmd') { - // upconvert legacy command - result = Object.assign({}, command.query.$query); - } else { - // upconvert legacy find command - result = { find: collectionName(command) }; - Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => { - if (typeof command.query[key] !== 'undefined') - result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key]; - }); - } - - Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => { - if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key]; - }); - - OP_QUERY_KEYS.forEach(key => { - if (command[key]) result[key] = command[key]; - }); - - if (typeof command.pre32Limit !== 'undefined') { - result.limit = command.pre32Limit; - } - - if (command.query.$explain) { - extractedCommand = { explain: result }; - } else { - extractedCommand = result; - } - } else { - extractedCommand = command.query || command; - } - - return { cmd: extractedCommand, name: Object.keys(extractedCommand)[0] }; -}; - const extractReply = (command, reply) => { if (command instanceof GetMore) { return { @@ -178,7 +71,6 @@ class CommandStartedEvent { */ constructor(pool, command) { const extractedCommand = extractCommand(command); - const cmd = extractedCommand.cmd; const commandName = extractedCommand.name; const connectionDetails = extractConnectionDetails(pool); @@ -186,7 +78,7 @@ class CommandStartedEvent { requestId: command.requestId, databaseName: databaseName(command), commandName, - command: shouldRedactCommand(commandName, cmd) ? {} : cmd + command: extractedCommand.shouldRedact ? {} : extractedCommand.cmd }); } } @@ -203,7 +95,6 @@ class CommandSucceededEvent { */ constructor(pool, command, reply, started) { const extractedCommand = extractCommand(command); - const cmd = extractedCommand.cmd; const commandName = extractedCommand.name; const connectionDetails = extractConnectionDetails(pool); @@ -211,7 +102,7 @@ class CommandSucceededEvent { requestId: command.requestId, commandName, duration: calculateDurationInMs(started), - reply: shouldRedactCommand(commandName, cmd) ? {} : extractReply(command, reply) + reply: extractedCommand.shouldRedact ? {} : extractReply(command, reply) }); } } @@ -228,7 +119,6 @@ class CommandFailedEvent { */ constructor(pool, command, error, started) { const extractedCommand = extractCommand(command); - const cmd = extractedCommand.cmd; const commandName = extractedCommand.name; const connectionDetails = extractConnectionDetails(pool); @@ -236,7 +126,7 @@ class CommandFailedEvent { requestId: command.requestId, commandName, duration: calculateDurationInMs(started), - failure: shouldRedactCommand(commandName, cmd) ? {} : error + failure: extractedCommand.shouldRedact ? {} : error }); } }