Comparing version 0.0.3 to 0.0.4
110
lib/index.js
@@ -7,27 +7,68 @@ /* | ||
var child = require('child_process'); | ||
var child = require('child_process'), | ||
path = require('path'); | ||
/* | ||
* Append default path if the command does not have a full path | ||
* For each whitelist path, add these commands | ||
* result is an array of full commands | ||
* eg | ||
* commands = [grep] | ||
* whitelistPaths = ['/usr/local/bin', '/bin'] | ||
* output | ||
* ['/usr/loca/bin/grep', | ||
* '/bin/grep'] | ||
*/ | ||
function getAbsolutePath(command, defaultPath) { | ||
if (command && command.charAt(0) !== '/') { | ||
return defaultPath + '/' + command; | ||
} | ||
return command; | ||
function getPathCombinations(commands, paths) { | ||
var arrayedPaths = [], | ||
pathCombinations = []; | ||
arrayedPaths = commands.map(function(thisCommand) { | ||
return paths.map(function(thisPath) { | ||
if (thisCommand && | ||
typeof thisCommand === 'string' | ||
&& thisCommand.charAt(0) === '/') { | ||
return thisCommand; | ||
} else { | ||
return path.join(thisPath, thisCommand); | ||
} | ||
}); | ||
}); | ||
pathCombinations = | ||
pathCombinations.concat.apply(pathCombinations, arrayedPaths); | ||
return pathCombinations; | ||
} | ||
/* | ||
* Returns a function which throws the exception. | ||
* Returns a function which throws the exception if not in whitelist | ||
* else does not alter behavior | ||
*/ | ||
function permissionDenied(name, originalMethod, whitelistPath, whitelist) { | ||
function permissionDenied(name, originalMethod, whitelistPaths, whitelistCommandPaths) { | ||
return function () { | ||
if (whitelist && whitelist.indexOf(getAbsolutePath(arguments[0], whitelistPath)) >= 0) { | ||
return originalMethod.apply(this, arguments); | ||
} else if (arguments.length >= 2 | ||
&& whitelist && whitelist.indexOf(getAbsolutePath((arguments[1])[1],whitelistPath)) >= 0) { | ||
return originalMethod.apply(this, arguments); | ||
var toCheckCommands = [], | ||
toCheckCommandPaths, | ||
found = false, | ||
i = 0; | ||
// command could be in arguments[0] in case of exec | ||
// or arguments[1][1] in case of execFile | ||
toCheckCommands.push(arguments[0]); | ||
if (arguments.length >= 2 && (arguments[1])[1]) { | ||
toCheckCommands.push((arguments[1])[1]); | ||
} | ||
toCheckCommandPaths | ||
= getPathCombinations(toCheckCommands, whitelistPaths); | ||
for (i = 0; i < toCheckCommandPaths.length; i++) { | ||
if (whitelistCommandPaths.indexOf(toCheckCommandPaths[i]) >= 0) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (found) { | ||
return originalMethod.apply(this, arguments); | ||
} else { | ||
throw new Error("Function call " + name + "() is prohibited in this environment."); | ||
throw new Error("Function call " + name + "() is prohibited in this environment."); | ||
} | ||
@@ -39,14 +80,27 @@ }; | ||
* Restict the APIs to return permission denied exception | ||
* config: { | ||
* whitelist: array of whitelist commands | ||
* whitelistPath: array of whitelist paths where commands could reside | ||
* } | ||
*/ | ||
function restrict(config) { | ||
var origBinding = process.binding, | ||
fn, | ||
whitelist = config.whitelist ? config.whitelist : [], | ||
whitelistPath = config.whitelistPath ? config.whitelistPath : '/usr/local/bin', | ||
whitelistAbs = whitelist.map(function(single) { | ||
return whitelistPath + "/" + single; | ||
}), | ||
originalMethod; | ||
var origBinding, | ||
whitelistCommands = [], | ||
whitelistPaths, | ||
whitelistCommandPaths = [], | ||
originalMethod, | ||
fn; | ||
origBinding = process.binding; | ||
whitelistCommands = config.whitelist ? config.whitelist : []; | ||
whitelistPaths = config.whitelistPath ? config.whitelistPath : '/usr/local/bin'; | ||
// Make sure its an array | ||
whitelistPaths = (whitelistPaths instanceof Array) ? whitelistPaths : [whitelistPaths]; | ||
// Generate a fully qualified whitelisted commands | ||
whitelistCommandPaths | ||
= getPathCombinations(whitelistCommands, whitelistPaths); | ||
process.binding = function (name) { | ||
@@ -60,6 +114,9 @@ if (name === 'process_wrap') { | ||
// For each of the methods in child_process | ||
// Verify if command is in whitelist | ||
// If not, throw an exception | ||
for (fn in child) { | ||
if (child.hasOwnProperty(fn)) { | ||
originalMethod = child[fn]; | ||
child[fn] = permissionDenied(fn, originalMethod, whitelistPath, whitelistAbs); | ||
child[fn] = permissionDenied(fn, originalMethod, whitelistPaths, whitelistCommandPaths); | ||
} | ||
@@ -69,5 +126,8 @@ } | ||
// prohibit kill | ||
process.kill = permissionDenied('process.kill'); | ||
process.kill = function () { | ||
var name = 'process.kill'; | ||
throw new Error("Function call " + name + "() is prohibited in this environment."); | ||
}; | ||
} | ||
module.exports = restrict; |
{ | ||
"name": "restrict", | ||
"description": "Restricts applications from calling certain methods on process and all methods on child_process", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"author": "Rohini Harendra <rohini.raghav@gmail.com>", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -23,3 +23,3 @@ # restrict | ||
'whitelist': ['ls'], | ||
'whitelistPath': '/bin' | ||
'whitelistPath': ['/bin'] | ||
}); | ||
@@ -26,0 +26,0 @@ |
@@ -13,3 +13,3 @@ /* | ||
'whitelist': ['ls'], | ||
'whitelistPath': '/bin' | ||
'whitelistPath': ['/bin', '/usr/bin'] | ||
}); | ||
@@ -16,0 +16,0 @@ |
11258
8
261
5