mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3394 from Alkarex/fix-debug-node-hasOwnProperty
Fix no-prototype-builtins bug in debug node and utils
This commit is contained in:
commit
5293563a6a
@ -7,6 +7,7 @@ module.exports = function(RED) {
|
|||||||
var debuglength = RED.settings.debugMaxLength || 1000;
|
var debuglength = RED.settings.debugMaxLength || 1000;
|
||||||
var useColors = RED.settings.debugUseColors || false;
|
var useColors = RED.settings.debugUseColors || false;
|
||||||
util.inspect.styles.boolean = "red";
|
util.inspect.styles.boolean = "red";
|
||||||
|
const { hasOwnProperty } = Object.prototype;
|
||||||
|
|
||||||
function DebugNode(n) {
|
function DebugNode(n) {
|
||||||
var hasEditExpression = (n.targetType === "jsonata");
|
var hasEditExpression = (n.targetType === "jsonata");
|
||||||
@ -107,7 +108,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.on("input", function(msg, send, done) {
|
this.on("input", function(msg, send, done) {
|
||||||
if (msg.hasOwnProperty("status") && msg.status.hasOwnProperty("source") && msg.status.source.hasOwnProperty("id") && (msg.status.source.id === node.id)) {
|
if (hasOwnProperty.call(msg, "status") && hasOwnProperty.call(msg.status, "source") && hasOwnProperty.call(msg.status.source, "id") && (msg.status.source.id === node.id)) {
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -118,17 +119,17 @@ module.exports = function(RED) {
|
|||||||
var st = (typeof output === 'string') ? output : util.inspect(output);
|
var st = (typeof output === 'string') ? output : util.inspect(output);
|
||||||
var fill = "grey";
|
var fill = "grey";
|
||||||
var shape = "dot";
|
var shape = "dot";
|
||||||
if (typeof output === 'object' && output.hasOwnProperty("fill") && output.hasOwnProperty("shape") && output.hasOwnProperty("text")) {
|
if (typeof output === 'object' && hasOwnProperty.call(output, "fill") && hasOwnProperty.call(output, "shape") && hasOwnProperty.call(output, "text")) {
|
||||||
fill = output.fill;
|
fill = output.fill;
|
||||||
shape = output.shape;
|
shape = output.shape;
|
||||||
st = output.text;
|
st = output.text;
|
||||||
}
|
}
|
||||||
if (node.statusType === "auto") {
|
if (node.statusType === "auto") {
|
||||||
if (msg.hasOwnProperty("error")) {
|
if (hasOwnProperty.call(msg, "error")) {
|
||||||
fill = "red";
|
fill = "red";
|
||||||
st = msg.error.message;
|
st = msg.error.message;
|
||||||
}
|
}
|
||||||
if (msg.hasOwnProperty("status")) {
|
if (hasOwnProperty.call(msg, "status")) {
|
||||||
fill = msg.status.fill || "grey";
|
fill = msg.status.fill || "grey";
|
||||||
shape = msg.status.shape || "ring";
|
shape = msg.status.shape || "ring";
|
||||||
st = msg.status.text || "";
|
st = msg.status.text || "";
|
||||||
@ -194,7 +195,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
function sendDebug(msg) {
|
function sendDebug(msg) {
|
||||||
// don't put blank errors in sidebar (but do add to logs)
|
// don't put blank errors in sidebar (but do add to logs)
|
||||||
//if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; }
|
//if ((msg.msg === "") && (hasOwnProperty.call(msg, "level")) && (msg.level === 20)) { return; }
|
||||||
msg = RED.util.encodeObject(msg,{maxLength:debuglength});
|
msg = RED.util.encodeObject(msg,{maxLength:debuglength});
|
||||||
RED.comms.publish("debug",msg);
|
RED.comms.publish("debug",msg);
|
||||||
}
|
}
|
||||||
|
41
packages/node_modules/@node-red/util/lib/util.js
vendored
41
packages/node_modules/@node-red/util/lib/util.js
vendored
@ -24,6 +24,17 @@ const jsonata = require("jsonata");
|
|||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
const safeJSONStringify = require("json-stringify-safe");
|
const safeJSONStringify = require("json-stringify-safe");
|
||||||
const util = require("util");
|
const util = require("util");
|
||||||
|
const { hasOwnProperty } = Object.prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely returns the object construtor name.
|
||||||
|
* @return {String} the name of the object constructor if it exists, empty string otherwise.
|
||||||
|
*/
|
||||||
|
function constructorName(obj) {
|
||||||
|
// Note: This function could be replaced by optional chaining in Node.js 14+:
|
||||||
|
// obj?.constructor?.name
|
||||||
|
return obj && obj.constructor ? obj.constructor.name : '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a psuedo-unique-random id.
|
* Generates a psuedo-unique-random id.
|
||||||
@ -171,7 +182,7 @@ function compareObjects(obj1,obj2) {
|
|||||||
}
|
}
|
||||||
for (var k in obj1) {
|
for (var k in obj1) {
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (obj1.hasOwnProperty(k)) {
|
if (hasOwnProperty.call(obj1, k)) {
|
||||||
if (!compareObjects(obj1[k],obj2[k])) {
|
if (!compareObjects(obj1[k],obj2[k])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -462,7 +473,7 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
|||||||
for (var i=0;i<length-1;i++) {
|
for (var i=0;i<length-1;i++) {
|
||||||
key = msgPropParts[i];
|
key = msgPropParts[i];
|
||||||
if (typeof key === 'string' || (typeof key === 'number' && !Array.isArray(obj))) {
|
if (typeof key === 'string' || (typeof key === 'number' && !Array.isArray(obj))) {
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (hasOwnProperty.call(obj, key)) {
|
||||||
if (length > 1 && ((typeof obj[key] !== "object" && typeof obj[key] !== "function") || obj[key] === null)) {
|
if (length > 1 && ((typeof obj[key] !== "object" && typeof obj[key] !== "function") || obj[key] === null)) {
|
||||||
// Break out early as we cannot create a property beneath
|
// Break out early as we cannot create a property beneath
|
||||||
// this type of value
|
// this type of value
|
||||||
@ -561,7 +572,7 @@ function getSetting(node, name, flow_) {
|
|||||||
* @memberof @node-red/util_util
|
* @memberof @node-red/util_util
|
||||||
*/
|
*/
|
||||||
function evaluateEnvProperty(value, node) {
|
function evaluateEnvProperty(value, node) {
|
||||||
var flow = (node && node.hasOwnProperty("_flow")) ? node._flow : null;
|
var flow = (node && hasOwnProperty.call(node, "_flow")) ? node._flow : null;
|
||||||
var result;
|
var result;
|
||||||
if (/^\${[^}]+}$/.test(value)) {
|
if (/^\${[^}]+}$/.test(value)) {
|
||||||
// ${ENV_VAR}
|
// ${ENV_VAR}
|
||||||
@ -785,7 +796,7 @@ function normaliseNodeTypeName(name) {
|
|||||||
function encodeObject(msg,opts) {
|
function encodeObject(msg,opts) {
|
||||||
try {
|
try {
|
||||||
var debuglength = 1000;
|
var debuglength = 1000;
|
||||||
if (opts && opts.hasOwnProperty('maxLength')) {
|
if (opts && hasOwnProperty.call(opts, 'maxLength')) {
|
||||||
debuglength = opts.maxLength;
|
debuglength = opts.maxLength;
|
||||||
}
|
}
|
||||||
var msgType = typeof msg.msg;
|
var msgType = typeof msg.msg;
|
||||||
@ -795,7 +806,7 @@ function encodeObject(msg,opts) {
|
|||||||
if (msg.msg.name) {
|
if (msg.msg.name) {
|
||||||
errorMsg.name = msg.msg.name;
|
errorMsg.name = msg.msg.name;
|
||||||
}
|
}
|
||||||
if (msg.msg.hasOwnProperty('message')) {
|
if (hasOwnProperty.call(msg.msg, 'message')) {
|
||||||
errorMsg.message = msg.msg.message;
|
errorMsg.message = msg.msg.message;
|
||||||
} else {
|
} else {
|
||||||
errorMsg.message = msg.msg.toString();
|
errorMsg.message = msg.msg.toString();
|
||||||
@ -809,7 +820,7 @@ function encodeObject(msg,opts) {
|
|||||||
}
|
}
|
||||||
} else if (msg.msg && msgType === 'object') {
|
} else if (msg.msg && msgType === 'object') {
|
||||||
try {
|
try {
|
||||||
msg.format = msg.msg.constructor.name || "Object";
|
msg.format = constructorName(msg.msg) || "Object";
|
||||||
// Handle special case of msg.req/res objects from HTTP In node
|
// Handle special case of msg.req/res objects from HTTP In node
|
||||||
if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") {
|
if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") {
|
||||||
msg.format = "Object";
|
msg.format = "Object";
|
||||||
@ -836,7 +847,7 @@ function encodeObject(msg,opts) {
|
|||||||
length: msg.msg.length
|
length: msg.msg.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (msg.msg && msg.msg.constructor.name === "Set") {
|
} else if (constructorName(msg.msg) === "Set") {
|
||||||
msg.format = "set["+msg.msg.size+"]";
|
msg.format = "set["+msg.msg.size+"]";
|
||||||
msg.msg = {
|
msg.msg = {
|
||||||
__enc__: true,
|
__enc__: true,
|
||||||
@ -845,7 +856,7 @@ function encodeObject(msg,opts) {
|
|||||||
length: msg.msg.size
|
length: msg.msg.size
|
||||||
}
|
}
|
||||||
needsStringify = true;
|
needsStringify = true;
|
||||||
} else if (msg.msg && msg.msg.constructor.name === "Map") {
|
} else if (constructorName(msg.msg) === "Map") {
|
||||||
msg.format = "map";
|
msg.format = "map";
|
||||||
msg.msg = {
|
msg.msg = {
|
||||||
__enc__: true,
|
__enc__: true,
|
||||||
@ -854,7 +865,7 @@ function encodeObject(msg,opts) {
|
|||||||
length: msg.msg.size
|
length: msg.msg.size
|
||||||
}
|
}
|
||||||
needsStringify = true;
|
needsStringify = true;
|
||||||
} else if (msg.msg && msg.msg.constructor.name === "RegExp") {
|
} else if (constructorName(msg.msg) === "RegExp") {
|
||||||
msg.format = 'regexp';
|
msg.format = 'regexp';
|
||||||
msg.msg = msg.msg.toString();
|
msg.msg = msg.msg.toString();
|
||||||
}
|
}
|
||||||
@ -904,25 +915,25 @@ function encodeObject(msg,opts) {
|
|||||||
if (value.length > debuglength) {
|
if (value.length > debuglength) {
|
||||||
value.data = value.data.slice(0,debuglength);
|
value.data = value.data.slice(0,debuglength);
|
||||||
}
|
}
|
||||||
} else if (value.constructor.name === "ServerResponse") {
|
} else if (constructorName(value) === "ServerResponse") {
|
||||||
value = "[internal]"
|
value = "[internal]"
|
||||||
} else if (value.constructor.name === "Socket") {
|
} else if (constructorName(value) === "Socket") {
|
||||||
value = "[internal]"
|
value = "[internal]"
|
||||||
} else if (value.constructor.name === "Set") {
|
} else if (constructorName(value) === "Set") {
|
||||||
value = {
|
value = {
|
||||||
__enc__: true,
|
__enc__: true,
|
||||||
type: "set",
|
type: "set",
|
||||||
data: Array.from(value).slice(0,debuglength),
|
data: Array.from(value).slice(0,debuglength),
|
||||||
length: value.size
|
length: value.size
|
||||||
}
|
}
|
||||||
} else if (value.constructor.name === "Map") {
|
} else if (constructorName(value) === "Map") {
|
||||||
value = {
|
value = {
|
||||||
__enc__: true,
|
__enc__: true,
|
||||||
type: "map",
|
type: "map",
|
||||||
data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)),
|
data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)),
|
||||||
length: value.size
|
length: value.size
|
||||||
}
|
}
|
||||||
} else if (value.constructor.name === "RegExp") {
|
} else if (constructorName(value) === "RegExp") {
|
||||||
value = {
|
value = {
|
||||||
__enc__: true,
|
__enc__: true,
|
||||||
type: "regexp",
|
type: "regexp",
|
||||||
@ -974,7 +985,7 @@ function encodeObject(msg,opts) {
|
|||||||
if (e.name) {
|
if (e.name) {
|
||||||
errorMsg.name = e.name;
|
errorMsg.name = e.name;
|
||||||
}
|
}
|
||||||
if (e.hasOwnProperty('message')) {
|
if (hasOwnProperty.call(e, 'message')) {
|
||||||
errorMsg.message = 'encodeObject Error: ['+e.message + '] Value: '+util.inspect(msg.msg);
|
errorMsg.message = 'encodeObject Error: ['+e.message + '] Value: '+util.inspect(msg.msg);
|
||||||
} else {
|
} else {
|
||||||
errorMsg.message = 'encodeObject Error: ['+e.toString() + '] Value: '+util.inspect(msg.msg);
|
errorMsg.message = 'encodeObject Error: ['+e.toString() + '] Value: '+util.inspect(msg.msg);
|
||||||
|
@ -265,6 +265,38 @@ describe('debug node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should publish an object with no-prototype-builtins', function(done) {
|
||||||
|
const flow = [{id:"n1", type:"debug" }];
|
||||||
|
helper.load(debugNode, flow, function() {
|
||||||
|
const n1 = helper.getNode("n1");
|
||||||
|
const payload = Object.create(null);
|
||||||
|
payload.type = 'foo';
|
||||||
|
websocket_test(function() {
|
||||||
|
n1.emit("input", {payload: payload});
|
||||||
|
}, function(msg) {
|
||||||
|
JSON.parse(msg).should.eql([{
|
||||||
|
topic:"debug",
|
||||||
|
data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||||
|
}]);
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should publish an object with overriden hasOwnProperty', function(done) {
|
||||||
|
const flow = [{id:"n1", type:"debug" }];
|
||||||
|
helper.load(debugNode, flow, function() {
|
||||||
|
const n1 = helper.getNode("n1");
|
||||||
|
websocket_test(function() {
|
||||||
|
n1.emit("input", {payload: {type:'foo', hasOwnProperty: null}});
|
||||||
|
}, function(msg) {
|
||||||
|
JSON.parse(msg).should.eql([{
|
||||||
|
topic:"debug",
|
||||||
|
data:{id:"n1",msg:'{"type":"foo","hasOwnProperty":null}',property:"payload",format:"Object",path:"global"}
|
||||||
|
}]);
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should publish an array', function(done) {
|
it('should publish an array', function(done) {
|
||||||
var flow = [{id:"n1", type:"debug" }];
|
var flow = [{id:"n1", type:"debug" }];
|
||||||
helper.load(debugNode, flow, function() {
|
helper.load(debugNode, flow, function() {
|
||||||
|
@ -830,6 +830,24 @@ describe("@node-red/util/util", function() {
|
|||||||
resultJson.b.should.have.property("__enc__", true);
|
resultJson.b.should.have.property("__enc__", true);
|
||||||
resultJson.b.should.have.property("type", "undefined");
|
resultJson.b.should.have.property("type", "undefined");
|
||||||
});
|
});
|
||||||
|
it('object with no prototype builtins', function() {
|
||||||
|
const payload = new Object(null);
|
||||||
|
payload.c = 3;
|
||||||
|
var msg = { msg:{b:payload} };
|
||||||
|
var result = util.encodeObject(msg);
|
||||||
|
result.format.should.eql("Object");
|
||||||
|
var resultJson = JSON.parse(result.msg);
|
||||||
|
resultJson.should.have.property("b");
|
||||||
|
resultJson.b.should.have.property("c", 3);
|
||||||
|
});
|
||||||
|
it('object with overriden hasOwnProperty', function() {
|
||||||
|
var msg = { msg:{b:{hasOwnProperty:null}} };
|
||||||
|
var result = util.encodeObject(msg);
|
||||||
|
result.format.should.eql("Object");
|
||||||
|
var resultJson = JSON.parse(result.msg);
|
||||||
|
resultJson.should.have.property("b");
|
||||||
|
resultJson.b.should.have.property("hasOwnProperty");
|
||||||
|
});
|
||||||
it('object with Map property', function() {
|
it('object with Map property', function() {
|
||||||
const m = new Map();
|
const m = new Map();
|
||||||
m.set("a",1);
|
m.set("a",1);
|
||||||
|
Loading…
Reference in New Issue
Block a user