Skip to content

Commit

Permalink
Move command extraction logic to utils
Browse files Browse the repository at this point in the history
  • Loading branch information
dariakp committed Jun 22, 2021
1 parent a16ce4b commit cb621ba
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 114 deletions.
122 changes: 122 additions & 0 deletions lib/command_utils.js
Original file line number Diff line number Diff line change
@@ -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
};
118 changes: 4 additions & 114 deletions lib/core/connection/apm.js
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -178,15 +71,14 @@ class CommandStartedEvent {
*/
constructor(pool, command) {
const extractedCommand = extractCommand(command);
const cmd = extractedCommand.cmd;
const commandName = extractedCommand.name;
const connectionDetails = extractConnectionDetails(pool);

Object.assign(this, connectionDetails, {
requestId: command.requestId,
databaseName: databaseName(command),
commandName,
command: shouldRedactCommand(commandName, cmd) ? {} : cmd
command: extractedCommand.shouldRedact ? {} : extractedCommand.cmd
});
}
}
Expand All @@ -203,15 +95,14 @@ class CommandSucceededEvent {
*/
constructor(pool, command, reply, started) {
const extractedCommand = extractCommand(command);
const cmd = extractedCommand.cmd;
const commandName = extractedCommand.name;
const connectionDetails = extractConnectionDetails(pool);

Object.assign(this, connectionDetails, {
requestId: command.requestId,
commandName,
duration: calculateDurationInMs(started),
reply: shouldRedactCommand(commandName, cmd) ? {} : extractReply(command, reply)
reply: extractedCommand.shouldRedact ? {} : extractReply(command, reply)
});
}
}
Expand All @@ -228,15 +119,14 @@ class CommandFailedEvent {
*/
constructor(pool, command, error, started) {
const extractedCommand = extractCommand(command);
const cmd = extractedCommand.cmd;
const commandName = extractedCommand.name;
const connectionDetails = extractConnectionDetails(pool);

Object.assign(this, connectionDetails, {
requestId: command.requestId,
commandName,
duration: calculateDurationInMs(started),
failure: shouldRedactCommand(commandName, cmd) ? {} : error
failure: extractedCommand.shouldRedact ? {} : error
});
}
}
Expand Down

0 comments on commit cb621ba

Please sign in to comment.