mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00: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:
		@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user