Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mongo-escape

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mongo-escape - npm Package Compare versions

Comparing version 0.0.1 to 2.0.1

.eslintrc.js

162

index.js
/**
* Escapes MongoDB operators from the given "Object" and returns a new Object with
* the operators escaped with "__ESCAPED_DOLLAR_SIGN__".
* Copyright (c) 2014, 2016 Tim Kuijsten
*
* http://www.mongodb.org/display/DOCS/Legal+Key+Names
* Key names in inserted documents are limited as follows:
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* * The '$' character must not be the first character in the key name.
* * The '.' character must not appear anywhere in the key name.
*
* var escapedObj = mongo_escape({ $push: 'foo' });
*
* console.log(escapedObj);
* // { __ESCAPED_DOLLAR_SIGN__push: 'foo' }
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* Module dependencies.
*/
'use strict';
var type = require('type-component');
function escaper(input) {
return input.replace(/\$/g, '\uFF04').replace(/\./g, '\uFF0E');
}
function unescaper(input) {
return input.replace(/\uFF04/g, '$').replace(/\uFF0E/g, '.');
}
/*
Note: this ought to be foolproof only if [server side JavaScript is disabled],
so make sure `security.javascriptEnabled` is set to `false` in your mongodb
configuration file. This has the effect that the [mapReduce] command and [$where]
operator can not be used since these functions allow the execution of arbitrary
JavaScript code.
*/
/**
* Used to escape "$" signs from key names.
* Ensure any input is properly escaped. Where needed `$` and `.` are replaced
* with `$` and `.`, respectively.
*
* If input is an object, all keys are escaped. If input is not an object but a
* string it is escaped as well. Otherwise return the original value. If input
* is a function or a symbol an error is raised.
*
* Note: if input is an object, keys are replaced in place.
*
* @param {mixed} input input to escape
* @param {Boolean, default: true} recurse whether or not to recurse
* @return {mixed} properly escaped input
*/
function escape(input, recurse) {
if (input == null)
return input;
var dollar_token = '__ESCAPED_DOLLAR_SIGN__';
var dollar_regexp = /\$/g;
switch (typeof input) {
case 'string':
return escaper(input);
case 'number':
case 'boolean':
return input;
}
if (typeof recurse !== 'boolean')
recurse = true;
transform(input, escaper, recurse);
return input;
}
/**
* Used to escape "." symbols from key names.
* Ensure any input is properly unescaped. Where needed `$` and `.` are
* replaced with `$` and `.`, respectively.
*
* If input is an object, all keys are unescaped. If input is not an object but
* a string it is unescaped as well. Otherwise return the original value. If
* input is a function or a symbol an error is raised.
*
* Note: if input is an object, keys are replaced in place.
*
* @param {mixed} input input to unescape
* @param {Boolean, default: true} recurse whether or not to recurse
* @return {mixed} properly unescaped input
*/
function unescape(input, recurse) {
if (input == null)
return input;
var period_token = '__ESCAPED_PERIOD__';
var period_regexp = /\./g;
switch (typeof input) {
case 'string':
return unescaper(input);
case 'number':
case 'boolean':
return input;
}
if (typeof recurse !== 'boolean')
recurse = true;
transform(input, unescaper, recurse);
return input;
}
/**
* Escapes an Object for insersion into a MongoDB database.
* source: object-key-transform npm
*
* @param {Object} obj The object that should be escaped.
* @return {Object} The escaped object.
* @api public
* Iterate over all object keys (and optionally recurse) and run a transformation
* on each key. Modify the object in-place.
*
* @param {Object} obj object to transform
* @param {Function} iterator first parameter will be the key to transform, second
* parameter is the value of that key (though this is
* informational only). This function should return the
* new key to be used.
* @param {Boolean, default: false} recurse whether or not to recurse
* @return {undefined} replaces keys in-place
*/
function transform(obj, iterator, recurse) {
if (typeof obj !== 'object') { throw new TypeError('obj must be an object'); }
if (typeof iterator !== 'function') { throw new TypeError('iterator must be a function'); }
exports = module.exports = function mongo_escape(obj){
var out = {}, o, k;
if (!obj) return obj;
for (var key in obj) {
o = obj[key];
k = key.replace(dollar_regexp, dollar_token)
.replace(period_regexp, period_token);
switch (type(o)) {
case 'array':
out[k] = o.map(mongo_escape);
break;
case 'object':
out[k] = mongo_escape(o);
break;
default:
out[k] = o;
break;
recurse = recurse || false;
if (typeof recurse !== 'boolean') { throw new TypeError('recurse must be a boolean'); }
Object.keys(obj).forEach(function(key) {
// recurse if requested and possible
if (recurse && typeof obj[key] === 'object' && obj[key] !== null && Object.keys(obj[key]).length) {
transform(obj[key], iterator, recurse);
}
}
return out;
};
var transformed = iterator(key, obj[key]);
if (transformed !== key) {
obj[transformed] = obj[key];
delete obj[key];
}
});
}
module.exports.escape = escape;
module.exports.unescape = unescape;
{
"name": "mongo-escape",
"description": "Escapes the MongoDB operators from the given Object",
"version": "0.0.1",
"bundledDependencies": [
"core"
"version": "2.0.1",
"author": {
"name": "Tim Kuijsten",
"email": "tim@netsend.nl",
"url": "https://github.com/timkuijsten"
},
"license": "ISC",
"description": "Escape variables to prevent NoSQL injection in MongoDB",
"keywords": [
"mongo",
"key",
"escape",
"sanitize",
"injection"
],
"dependencies": {
"type-component": "*"
"main": "index.js",
"bugs": "https://github.com/timkuijsten/node-mongo-escape/issues",
"scripts": {
"test": "node test"
},
"component": {
"scripts": ["index.js"]
"repository": {
"type": "git",
"url": "git://github.com/timkuijsten/node-mongo-escape.git"
}
}

@@ -0,8 +1,125 @@

/**
* Copyright (c) 2014, 2016 Tim Kuijsten
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
'use strict';
var assert = require('assert');
var mongo_escape = require('./');
var input = { $push: 'foo' };
var escaped = mongo_escape(input);
var escaper = require('./index');
assert.notDeepEqual(input, escaped);
var obj;
/* escape */
/* don't fall over undefined */
escaper.escape(obj);
assert.strictEqual(obj, undefined, 'don\'t fall over undefined');
/* don't fall over null */
obj = null;
escaper.escape(obj);
assert.strictEqual(obj, null, 'don\'t fall over null');
/* don't fall over boolean */
obj = false;
escaper.escape(obj);
assert.strictEqual(obj, false, 'don\'t fall over boolean');
/* don't fall over numbers */
obj = 0;
escaper.escape(obj);
assert.strictEqual(obj, 0, 'don\'t fall over numbers');
/* don't fall over strings */
obj = '';
escaper.escape(obj);
assert.strictEqual(obj, '', 'don\'t fall over empty string');
obj = '$set';
assert.strictEqual(escaper.escape(obj), '\uFF04set', 'escape string');
obj = {};
escaper.escape(obj);
assert.deepEqual(obj, {}, 'escape empty object');
obj = { $: '$', 'foo.bar': { $: '$' } };
escaper.escape(obj, false);
assert.deepEqual(obj, { '\uFF04': '$', 'foo\uFF0Ebar': { $: '$' } }, 'should not recurse');
obj = { $: '$', 'foo.bar': { $: '$' } };
escaper.escape(obj, false);
escaper.escape(obj, false);
assert.deepEqual(obj, { '\uFF04': '$', 'foo\uFF0Ebar': { $: '$' } }, 'should be idempotent');
obj = { $: '$', foo: { $: '$', bar: { 'some.foo': 'other' } }, a: 'b' };
escaper.escape(obj);
assert.deepEqual(obj, { '\uFF04': '$', foo: { '\uFF04': '$', bar: { 'some\uFF0Efoo': 'other' } }, a: 'b' }, 'should recurse by default');
obj = [ { $: '$', 'foo.bar': { $: '$' } }, { $: [ '$', { 'foo.qux': { $: '$' } } ], 'foo.baz': { $: '$' } } ];
escaper.escape(obj);
assert.deepEqual(obj, [ { '\uFF04': '$', 'foo\uFF0Ebar': { '\uFF04': '$' } }, { '\uFF04': [ '$', { 'foo\uFF0Equx': { '\uFF04': '$' } } ], 'foo\uFF0Ebaz': { '\uFF04': '$' } } ], 'should recurse on array values');
/* unescape */
/* don't fall over undefined */
obj = undefined
escaper.unescape(obj);
assert.strictEqual(obj, undefined, 'don\'t fall over undefined');
/* don't fall over null */
obj = null;
escaper.unescape(obj);
assert.strictEqual(obj, null, 'don\'t fall over null');
/* don't fall over boolean */
obj = false;
escaper.unescape(obj);
assert.strictEqual(obj, false, 'don\'t fall over boolean');
/* don't fall over strings */
obj = '';
escaper.unescape(obj);
assert.strictEqual(obj, '', 'don\'t fall over empty string');
obj = '\uFF04set';
assert.strictEqual(escaper.unescape(obj), '$set', 'unescape string');
obj = {};
escaper.unescape(obj);
assert.deepEqual(obj, {}, 'unescape empty object');
obj = { 'a': 'b' };
escaper.unescape(obj, true);
assert.deepEqual(obj, { 'a': 'b' }, 'should return original object');
obj = { '\uFF04': '$', 'foo\uFF0Ebar': { $: '$' } };
escaper.unescape(obj, false);
assert.deepEqual(obj, { $: '$', 'foo.bar': { $: '$' } }, 'should not recurse');
obj = { '\uFF04': '$', 'foo\uFF0Ebar': { $: '$' } };
escaper.unescape(obj, false);
escaper.unescape(obj, false);
assert.deepEqual(obj, { $: '$', 'foo.bar': { $: '$' } }, 'should be idempotent');
obj = { '\uFF04': '$', foo: { '\uFF04': '$', bar: { 'some\uFF0Efoo': 'other' } }, a: 'b' };
escaper.unescape(obj);
assert.deepEqual(obj, { $: '$', foo: { $: '$', bar: { 'some.foo': 'other' } }, a: 'b' }, 'should recurse by default');
obj = [ { '\uFF04': '$', 'foo\uFF0Ebar': { '\uFF04': '$' } }, { '\uFF04': [ '$', { 'foo\uFF0Equx': { '\uFF04': '$' } } ], 'foo\uFF0Ebaz': { '\uFF04': '$' } } ];
escaper.unescape(obj);
assert.deepEqual(obj, [ { $: '$', 'foo.bar': { $: '$' } }, { $: [ '$', { 'foo.qux': { $: '$' } } ], 'foo.baz': { $: '$' } } ], 'should recurse on array values');
console.log('ok');
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc