mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Prevent function module overwriting built-in sandbox properties
This commit is contained in:
parent
9d34abf603
commit
785c349adc
@ -344,6 +344,16 @@
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('change',that.propertyType,that.value());
|
||||
});
|
||||
this.input.on('keyup', function(evt) {
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('keyup',evt);
|
||||
});
|
||||
this.input.on('paste', function(evt) {
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('paste',evt);
|
||||
});
|
||||
this.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
||||
evt.stopPropagation();
|
||||
|
@ -23,6 +23,11 @@
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 2px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.node-libs-entry > span > i {
|
||||
@ -89,6 +94,25 @@
|
||||
|
||||
(function() {
|
||||
|
||||
var invalidModuleVNames = [
|
||||
'console',
|
||||
'util',
|
||||
'Buffer',
|
||||
'Date',
|
||||
'RED',
|
||||
'node',
|
||||
'__node__',
|
||||
'context',
|
||||
'flow',
|
||||
'global',
|
||||
'env',
|
||||
'setTimeout',
|
||||
'clearTimeout',
|
||||
'setInterval',
|
||||
'clearInterval',
|
||||
'promisify'
|
||||
]
|
||||
|
||||
var knownFunctionNodes = {};
|
||||
RED.events.on("nodes:add", function(n) {
|
||||
if (n.type === "function") {
|
||||
@ -193,6 +217,16 @@
|
||||
width: "120px",
|
||||
"margin-left": "5px"
|
||||
}).appendTo(row0).val(opt.var);
|
||||
var vnameWarning = $('<span style="display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(row0);
|
||||
RED.popover.tooltip(vnameWarning.find("i"),function() {
|
||||
var val = fvar.val();
|
||||
if (invalidModuleVNames.indexOf(val) !== -1) {
|
||||
return RED._("node-red:function.error.moduleNameReserved",{name:val})
|
||||
} else {
|
||||
return RED._("node-red:function.error.moduleNameError",{name:val})
|
||||
}
|
||||
})
|
||||
|
||||
$('<code> = require(</code>').appendTo(row0);
|
||||
var fmodule = $("<input/>", {
|
||||
class: "node-input-libs-val",
|
||||
@ -210,29 +244,33 @@
|
||||
|
||||
$('<code>)</code>').appendTo(row0);
|
||||
|
||||
var warning = $('<span style="display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(row0);
|
||||
RED.popover.tooltip(warning.find("i"),function() {
|
||||
var moduleWarning = $('<span style="display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(row0);
|
||||
RED.popover.tooltip(moduleWarning.find("i"),function() {
|
||||
var val = fmodule.typedInput("type");
|
||||
if (val === "_custom_") {
|
||||
val = fmodule.val();
|
||||
}
|
||||
var errors = [];
|
||||
|
||||
if (!RED.utils.checkModuleAllowed(val,null,installAllowList,installDenyList)) {
|
||||
return "Module not allowed"
|
||||
return RED._("node-red:function.error.moduleNotAllowed",{module:val});
|
||||
} else {
|
||||
return "Module not installed: "+missingModuleReasons[val]
|
||||
return RED._("node-red:function.error.moduleLoadError",{module:val,error:missingModuleReasons[val]});
|
||||
}
|
||||
})
|
||||
|
||||
fvar.on("change", function (e) {
|
||||
fvar.on("change keyup paste", function (e) {
|
||||
var v = $(this).val().trim();
|
||||
if (v === "" || / /.test(v)) {
|
||||
if (v === "" || / /.test(v) || invalidModuleVNames.indexOf(v) !== -1) {
|
||||
fvar.addClass("input-error");
|
||||
vnameWarning.addClass("input-error");
|
||||
} else {
|
||||
fvar.removeClass("input-error");
|
||||
vnameWarning.removeClass("input-error");
|
||||
}
|
||||
});
|
||||
|
||||
fmodule.on("change", function (e) {
|
||||
fmodule.on("change keyup paste", function (e) {
|
||||
var val = $(this).typedInput("type");
|
||||
if (val === "_custom_") {
|
||||
val = $(this).val();
|
||||
@ -243,18 +281,18 @@
|
||||
|
||||
if (RED.utils.checkModuleAllowed(val,null,installAllowList,installDenyList) && (missingModules.indexOf(val) === -1)) {
|
||||
fmodule.removeClass("input-error");
|
||||
warning.removeClass("input-error");
|
||||
moduleWarning.removeClass("input-error");
|
||||
} else {
|
||||
fmodule.addClass("input-error");
|
||||
warning.addClass("input-error");
|
||||
moduleWarning.addClass("input-error");
|
||||
}
|
||||
});
|
||||
if (RED.utils.checkModuleAllowed(opt.module,null,installAllowList,installDenyList) && (missingModules.indexOf(opt.module) === -1)) {
|
||||
fmodule.removeClass("input-error");
|
||||
warning.removeClass("input-error");
|
||||
moduleWarning.removeClass("input-error");
|
||||
} else {
|
||||
fmodule.addClass("input-error");
|
||||
warning.addClass("input-error");
|
||||
moduleWarning.addClass("input-error");
|
||||
}
|
||||
if (opt.var) {
|
||||
fvar.trigger("change");
|
||||
@ -293,6 +331,9 @@
|
||||
if (missingModules.indexOf(m.module) > -1) {
|
||||
return false;
|
||||
}
|
||||
if (invalidModuleVNames.indexOf(m.var) !== -1){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}}
|
||||
@ -325,15 +366,15 @@
|
||||
|
||||
tabs.addTab({
|
||||
id: "func-tab-init",
|
||||
label: "On Start", //that._("function.label.initialize")
|
||||
label: that._("function.label.initialize")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "func-tab-body",
|
||||
label: "On Message"//that._("function.label.function")
|
||||
label: that._("function.label.function")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "func-tab-finalize",
|
||||
label: "On Stop"//that._("function.label.finalize")
|
||||
label: that._("function.label.finalize")
|
||||
});
|
||||
|
||||
tabs.activateTab("func-tab-body");
|
||||
|
@ -273,6 +273,37 @@ module.exports = function(RED) {
|
||||
sandbox.promisify = util.promisify;
|
||||
}
|
||||
|
||||
if (node.hasOwnProperty("libs")) {
|
||||
let moduleErrors = false;
|
||||
var modules = node.libs;
|
||||
modules.forEach(module => {
|
||||
var vname = module.hasOwnProperty("var") ? module.var : null;
|
||||
if (vname && (vname !== "")) {
|
||||
if (sandbox.hasOwnProperty(vname) || vname === 'node') {
|
||||
node.error(RED._("function.error.moduleNameError",{name:vname}))
|
||||
moduleErrors = true;
|
||||
return;
|
||||
}
|
||||
sandbox[vname] = null;
|
||||
try {
|
||||
var spec = module.module;
|
||||
if (spec && (spec !== "")) {
|
||||
var lib = RED.require(module.module);
|
||||
sandbox[vname] = lib;
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO: NLS error message
|
||||
node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:e.toString()}))
|
||||
moduleErrors = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (moduleErrors) {
|
||||
throw new Error("Function node failed to load external modules");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const RESOLVING = 0;
|
||||
const RESOLVED = 1;
|
||||
const ERROR = 2;
|
||||
@ -289,26 +320,6 @@ module.exports = function(RED) {
|
||||
}
|
||||
});
|
||||
|
||||
if (node.hasOwnProperty("libs")) {
|
||||
var modules = node.libs;
|
||||
modules.forEach(module => {
|
||||
var vname = module.hasOwnProperty("var") ? module.var : null;
|
||||
if (vname && (vname !== "")) {
|
||||
sandbox[vname] = null;
|
||||
try {
|
||||
var spec = module.module;
|
||||
if (spec && (spec !== "")) {
|
||||
var lib = RED.require(module.module);
|
||||
sandbox[vname] = lib;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
node.warn("failed to load library: "+ module.spec);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var context = vm.createContext(sandbox);
|
||||
try {
|
||||
var iniScript = null;
|
||||
|
@ -209,9 +209,9 @@
|
||||
"function": {
|
||||
"function": "",
|
||||
"label": {
|
||||
"function": "Function",
|
||||
"initialize": "Setup",
|
||||
"finalize": "Close",
|
||||
"function": "On Message",
|
||||
"initialize": "On Start",
|
||||
"finalize": "On Stop",
|
||||
"outputs": "Outputs",
|
||||
"require": "Require"
|
||||
},
|
||||
@ -224,6 +224,10 @@
|
||||
"module": "module"
|
||||
},
|
||||
"error": {
|
||||
"moduleNotAllowed": "Module __module__ not allowed",
|
||||
"moduleLoadError": "Failed to load module __module__: __error__",
|
||||
"moduleNameError": "Invalid module variable name: __name__",
|
||||
"moduleNameReserved": "Reserved variable name: __name__",
|
||||
"inputListener":"Cannot add listener to 'input' event within Function",
|
||||
"non-message-returned":"Function tried to send a message of type __type__"
|
||||
}
|
||||
|
@ -1438,7 +1438,6 @@ describe('function node', function() {
|
||||
}
|
||||
},20);
|
||||
}).catch(err => done(err));
|
||||
|
||||
})
|
||||
it('should require the OS module', function(done) {
|
||||
var flow = [
|
||||
@ -1459,9 +1458,18 @@ describe('function node', function() {
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
}).catch(err => done(err));
|
||||
|
||||
})
|
||||
|
||||
it('should fail if module variable name clashes with sandbox builtin', function(done) {
|
||||
var flow = [
|
||||
{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload = os.type(); return msg;", "libs": [{var:"flow", module:"os"}]},
|
||||
{id:"n2", type:"helper"}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
should.not.exist(n1);
|
||||
done();
|
||||
}).catch(err => done(err));
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
@ -94,7 +94,7 @@ describe("externalModules api", function() {
|
||||
it("installs missing modules", async function() {
|
||||
externalModules.init({userDir: homeDir});
|
||||
externalModules.register("function", "libs");
|
||||
fs.existsSync(path.join(homeDir,"externalModuels")).should.be.false();
|
||||
fs.existsSync(path.join(homeDir,"externalModules")).should.be.false();
|
||||
await externalModules.checkFlowDependencies([
|
||||
{type: "function", libs:[{module: "foo"}]}
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user