diff --git a/packages/node_modules/@node-red/nodes/core/common/20-inject.html b/packages/node_modules/@node-red/nodes/core/common/20-inject.html deleted file mode 100644 index f233c62fd..000000000 --- a/packages/node_modules/@node-red/nodes/core/common/20-inject.html +++ /dev/null @@ -1,711 +0,0 @@ - - - - - - diff --git a/packages/node_modules/@node-red/nodes/core/common/guide.html b/packages/node_modules/@node-red/nodes/core/common/guide.html new file mode 100644 index 000000000..dfff21e3e --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/guide.html @@ -0,0 +1,67 @@ + + + + + + diff --git a/packages/node_modules/@node-red/nodes/core/common/guide.js b/packages/node_modules/@node-red/nodes/core/common/guide.js new file mode 100644 index 000000000..44802d135 --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/guide.js @@ -0,0 +1,25 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +// 2022 Modification Copyright - Defense Unicorns + +module.exports = function(RED) { + "use strict"; + function GuideNode(n) { + RED.nodes.createNode(this,n); + } + RED.nodes.registerType("guide",GuideNode); +} diff --git a/packages/node_modules/@node-red/nodes/core/common/resource.html b/packages/node_modules/@node-red/nodes/core/common/resource.html new file mode 100644 index 000000000..d4db2f931 --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/resource.html @@ -0,0 +1,67 @@ + + + + + + diff --git a/packages/node_modules/@node-red/nodes/core/common/resource.js b/packages/node_modules/@node-red/nodes/core/common/resource.js new file mode 100644 index 000000000..180a600f2 --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/resource.js @@ -0,0 +1,25 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +// 2022 Modification Copyright - Defense Unicorns + +module.exports = function(RED) { + "use strict"; + function ResourceNode(n) { + RED.nodes.createNode(this,n); + } + RED.nodes.registerType("resource",ResourceNode); +} diff --git a/packages/node_modules/@node-red/nodes/core/common/task.html b/packages/node_modules/@node-red/nodes/core/common/task.html new file mode 100644 index 000000000..c1f8ebdac --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/task.html @@ -0,0 +1,67 @@ + + + + + + diff --git a/packages/node_modules/@node-red/nodes/core/common/task.js b/packages/node_modules/@node-red/nodes/core/common/task.js new file mode 100644 index 000000000..ce1c1410e --- /dev/null +++ b/packages/node_modules/@node-red/nodes/core/common/task.js @@ -0,0 +1,25 @@ +/** + * Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +// 2022 Modification Copyright - Defense Unicorns + +module.exports = function(RED) { + "use strict"; + function TaskNode(n) { + RED.nodes.createNode(this,n); + } + RED.nodes.registerType("task",TaskNode); +} diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.html b/packages/node_modules/@node-red/nodes/core/function/10-function.html deleted file mode 100644 index a1ed14f6d..000000000 --- a/packages/node_modules/@node-red/nodes/core/function/10-function.html +++ /dev/null @@ -1,611 +0,0 @@ - - - diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.js b/packages/node_modules/@node-red/nodes/core/function/10-function.js deleted file mode 100644 index b84ee8571..000000000 --- a/packages/node_modules/@node-red/nodes/core/function/10-function.js +++ /dev/null @@ -1,510 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - - var util = require("util"); - var vm = require("vm"); - var acorn = require("acorn"); - var acornWalk = require("acorn-walk"); - - function sendResults(node,send,_msgid,msgs,cloneFirstMessage) { - if (msgs == null) { - return; - } else if (!util.isArray(msgs)) { - msgs = [msgs]; - } - var msgCount = 0; - for (var m=0; m0) { - send(msgs); - } - } - - function createVMOpt(node, kind) { - var opt = { - filename: 'Function node'+kind+':'+node.id+(node.name?' ['+node.name+']':''), // filename for stack traces - displayErrors: true - // Using the following options causes node 4/6 to not include the line number - // in the stack output. So don't use them. - // lineOffset: -11, // line number offset to be used for stack traces - // columnOffset: 0, // column number offset to be used for stack traces - }; - return opt; - } - - function updateErrorInfo(err) { - if (err.stack) { - var stack = err.stack.toString(); - var m = /^([^:]+):([^:]+):(\d+).*/.exec(stack); - if (m) { - var line = parseInt(m[3]) -1; - var kind = "body:"; - if (/setup/.exec(m[1])) { - kind = "setup:"; - } - if (/cleanup/.exec(m[1])) { - kind = "cleanup:"; - } - err.message += " ("+kind+"line "+line+")"; - } - } - } - - function FunctionNode(n) { - RED.nodes.createNode(this,n); - var node = this; - node.name = n.name; - node.func = n.func; - node.outputs = n.outputs; - node.ini = n.initialize ? n.initialize.trim() : ""; - node.fin = n.finalize ? n.finalize.trim() : ""; - node.libs = n.libs || []; - - if (RED.settings.functionExternalModules === false && node.libs.length > 0) { - throw new Error(RED._("function.error.externalModuleNotAllowed")); - } - - - - var functionText = "var results = null;"+ - "results = (async function(msg,__send__,__done__){ "+ - "var __msgid__ = msg._msgid;"+ - "var node = {"+ - "id:__node__.id,"+ - "name:__node__.name,"+ - "path:__node__.path,"+ - "outputCount:__node__.outputCount,"+ - "log:__node__.log,"+ - "error:__node__.error,"+ - "warn:__node__.warn,"+ - "debug:__node__.debug,"+ - "trace:__node__.trace,"+ - "on:__node__.on,"+ - "status:__node__.status,"+ - "send:function(msgs,cloneMsg){ __node__.send(__send__,__msgid__,msgs,cloneMsg);},"+ - "done:__done__"+ - "};\n"+ - node.func+"\n"+ - "})(msg,__send__,__done__);"; - - var handleNodeDoneCall = true; - - // Check to see if the Function appears to call `node.done()`. If so, - // we will assume it is well written and does actually call node.done(). - // Otherwise, we will call node.done() after the function returns regardless. - if (/node\.done\s*\(\s*\)/.test(functionText)) { - // We have spotted the code contains `node.done`. It could be in a comment - // so need to do the extra work to parse the AST and examine it properly. - acornWalk.simple(acorn.parse(functionText,{ecmaVersion: "latest"} ), { - CallExpression(astNode) { - if (astNode.callee && astNode.callee.object) { - if (astNode.callee.object.name === "node" && astNode.callee.property.name === "done") { - handleNodeDoneCall = false; - } - } - } - }) - } - - var finScript = null; - var finOpt = null; - node.topic = n.topic; - node.outstandingTimers = []; - node.outstandingIntervals = []; - node.clearStatus = false; - - var sandbox = { - console:console, - util:util, - Buffer:Buffer, - Date: Date, - RED: { - util: RED.util - }, - __node__: { - id: node.id, - name: node.name, - path: node._path, - outputCount: node.outputs, - log: function() { - node.log.apply(node, arguments); - }, - error: function() { - node.error.apply(node, arguments); - }, - warn: function() { - node.warn.apply(node, arguments); - }, - debug: function() { - node.debug.apply(node, arguments); - }, - trace: function() { - node.trace.apply(node, arguments); - }, - send: function(send, id, msgs, cloneMsg) { - sendResults(node, send, id, msgs, cloneMsg); - }, - on: function() { - if (arguments[0] === "input") { - throw new Error(RED._("function.error.inputListener")); - } - node.on.apply(node, arguments); - }, - status: function() { - node.clearStatus = true; - node.status.apply(node, arguments); - } - }, - context: { - set: function() { - node.context().set.apply(node,arguments); - }, - get: function() { - return node.context().get.apply(node,arguments); - }, - keys: function() { - return node.context().keys.apply(node,arguments); - }, - get global() { - return node.context().global; - }, - get flow() { - return node.context().flow; - } - }, - flow: { - set: function() { - node.context().flow.set.apply(node,arguments); - }, - get: function() { - return node.context().flow.get.apply(node,arguments); - }, - keys: function() { - return node.context().flow.keys.apply(node,arguments); - } - }, - global: { - set: function() { - node.context().global.set.apply(node,arguments); - }, - get: function() { - return node.context().global.get.apply(node,arguments); - }, - keys: function() { - return node.context().global.keys.apply(node,arguments); - } - }, - env: { - get: function(envVar) { - return RED.util.getSetting(node, envVar); - } - }, - setTimeout: function () { - var func = arguments[0]; - var timerId; - arguments[0] = function() { - sandbox.clearTimeout(timerId); - try { - func.apply(node,arguments); - } catch(err) { - node.error(err,{}); - } - }; - timerId = setTimeout.apply(node,arguments); - node.outstandingTimers.push(timerId); - return timerId; - }, - clearTimeout: function(id) { - clearTimeout(id); - var index = node.outstandingTimers.indexOf(id); - if (index > -1) { - node.outstandingTimers.splice(index,1); - } - }, - setInterval: function() { - var func = arguments[0]; - var timerId; - arguments[0] = function() { - try { - func.apply(node,arguments); - } catch(err) { - node.error(err,{}); - } - }; - timerId = setInterval.apply(node,arguments); - node.outstandingIntervals.push(timerId); - return timerId; - }, - clearInterval: function(id) { - clearInterval(id); - var index = node.outstandingIntervals.indexOf(id); - if (index > -1) { - node.outstandingIntervals.splice(index,1); - } - } - }; - if (util.hasOwnProperty('promisify')) { - sandbox.setTimeout[util.promisify.custom] = function(after, value) { - return new Promise(function(resolve, reject) { - sandbox.setTimeout(function(){ resolve(value); }, after); - }); - }; - sandbox.promisify = util.promisify; - } - const moduleLoadPromises = []; - - 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; - var spec = module.module; - if (spec && (spec !== "")) { - moduleLoadPromises.push(RED.import(module.module).then(lib => { - sandbox[vname] = lib.default; - }).catch(err => { - node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:err.toString()})) - throw err; - })); - } - } - }); - if (moduleErrors) { - throw new Error(RED._("function.error.externalModuleLoadError")); - } - } - const RESOLVING = 0; - const RESOLVED = 1; - const ERROR = 2; - var state = RESOLVING; - var messages = []; - var processMessage = (() => {}); - - node.on("input", function(msg,send,done) { - if(state === RESOLVING) { - messages.push({msg:msg, send:send, done:done}); - } - else if(state === RESOLVED) { - processMessage(msg, send, done); - } - }); - Promise.all(moduleLoadPromises).then(() => { - var context = vm.createContext(sandbox); - try { - var iniScript = null; - var iniOpt = null; - if (node.ini && (node.ini !== "")) { - var iniText = ` - (async function(__send__) { - var node = { - id:__node__.id, - name:__node__.name, - path:__node__.path, - outputCount:__node__.outputCount, - log:__node__.log, - error:__node__.error, - warn:__node__.warn, - debug:__node__.debug, - trace:__node__.trace, - status:__node__.status, - send: function(msgs, cloneMsg) { - __node__.send(__send__, RED.util.generateId(), msgs, cloneMsg); - } - }; - `+ node.ini +` - })(__initSend__);`; - iniOpt = createVMOpt(node, " setup"); - iniScript = new vm.Script(iniText, iniOpt); - } - node.script = vm.createScript(functionText, createVMOpt(node, "")); - if (node.fin && (node.fin !== "")) { - var finText = `(function () { - var node = { - id:__node__.id, - name:__node__.name, - path:__node__.path, - outputCount:__node__.outputCount, - log:__node__.log, - error:__node__.error, - warn:__node__.warn, - debug:__node__.debug, - trace:__node__.trace, - status:__node__.status, - send: function(msgs, cloneMsg) { - __node__.error("Cannot send from close function"); - } - }; - `+node.fin +` - })();`; - finOpt = createVMOpt(node, " cleanup"); - finScript = new vm.Script(finText, finOpt); - } - var promise = Promise.resolve(); - if (iniScript) { - context.__initSend__ = function(msgs) { node.send(msgs); }; - promise = iniScript.runInContext(context, iniOpt); - } - - processMessage = function (msg, send, done) { - var start = process.hrtime(); - context.msg = msg; - context.__send__ = send; - context.__done__ = done; - - node.script.runInContext(context); - context.results.then(function(results) { - sendResults(node,send,msg._msgid,results,false); - if (handleNodeDoneCall) { - done(); - } - - var duration = process.hrtime(start); - var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100; - node.metric("duration", msg, converted); - if (process.env.NODE_RED_FUNCTION_TIME) { - node.status({fill:"yellow",shape:"dot",text:""+converted}); - } - }).catch(err => { - if ((typeof err === "object") && err.hasOwnProperty("stack")) { - //remove unwanted part - var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/); - err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n'); - var stack = err.stack.split(/\r?\n/); - - //store the error in msg to be used in flows - msg.error = err; - - var line = 0; - var errorMessage; - if (stack.length > 0) { - while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) { - line++; - } - - if (line < stack.length) { - errorMessage = stack[line]; - var m = /:(\d+):(\d+)$/.exec(stack[line+1]); - if (m) { - var lineno = Number(m[1])-1; - var cha = m[2]; - errorMessage += " (line "+lineno+", col "+cha+")"; - } - } - } - if (!errorMessage) { - errorMessage = err.toString(); - } - done(errorMessage); - } - else if (typeof err === "string") { - done(err); - } - else { - done(JSON.stringify(err)); - } - }); - } - - node.on("close", function() { - if (finScript) { - try { - finScript.runInContext(context, finOpt); - } - catch (err) { - node.error(err); - } - } - while (node.outstandingTimers.length > 0) { - clearTimeout(node.outstandingTimers.pop()); - } - while (node.outstandingIntervals.length > 0) { - clearInterval(node.outstandingIntervals.pop()); - } - if (node.clearStatus) { - node.status({}); - } - }); - - promise.then(function (v) { - var msgs = messages; - messages = []; - while (msgs.length > 0) { - msgs.forEach(function (s) { - processMessage(s.msg, s.send, s.done); - }); - msgs = messages; - messages = []; - } - state = RESOLVED; - }).catch((error) => { - messages = []; - state = ERROR; - node.error(error); - }); - - } - catch(err) { - // eg SyntaxError - which v8 doesn't include line number information - // so we can't do better than this - updateErrorInfo(err); - node.error(err); - } - }).catch(err => { - node.error(RED._("function.error.externalModuleLoadError")); - }); - } - RED.nodes.registerType("function",FunctionNode, { - dynamicModuleList: "libs", - settings: { - functionExternalModules: { value: true, exportable: true } - } - }); - RED.library.register("functions"); -}; diff --git a/packages/node_modules/@node-red/nodes/core/function/89-delay.html b/packages/node_modules/@node-red/nodes/core/function/89-delay.html deleted file mode 100644 index 8ee404924..000000000 --- a/packages/node_modules/@node-red/nodes/core/function/89-delay.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - diff --git a/packages/node_modules/@node-red/nodes/core/function/90-exec.js b/packages/node_modules/@node-red/nodes/core/function/90-exec.js deleted file mode 100644 index 2ae9947dd..000000000 --- a/packages/node_modules/@node-red/nodes/core/function/90-exec.js +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - var spawn = require('child_process').spawn; - var exec = require('child_process').exec; - var fs = require('fs'); - var isUtf8 = require('is-utf8'); - - function ExecNode(n) { - RED.nodes.createNode(this,n); - this.cmd = (n.command || "").trim(); - if (n.addpay === undefined) { n.addpay = true; } - this.addpay = n.addpay; - if (this.addpay === true) { - this.addpay = "payload"; - } - this.append = (n.append || "").trim(); - this.useSpawn = (n.useSpawn == "true"); - this.timer = Number(n.timer || 0)*1000; - this.activeProcesses = {}; - this.oldrc = (n.oldrc || false).toString(); - this.execOpt = {encoding:'binary', maxBuffer:RED.settings.execMaxBufferSize||10000000, windowsHide: (n.winHide === true)}; - this.spawnOpt = {windowsHide: (n.winHide === true) } - var node = this; - - if (process.platform === 'linux' && fs.existsSync('/bin/bash')) { node.execOpt.shell = '/bin/bash'; } - - var cleanup = function(p) { - node.activeProcesses[p].kill(); - //node.status({fill:"red",shape:"dot",text:"timeout"}); - //node.error("Exec node timeout"); - } - - this.on("input", function(msg, nodeSend, nodeDone) { - if (msg.hasOwnProperty("kill")) { - if (typeof msg.kill !== "string" || msg.kill.length === 0 || !msg.kill.toUpperCase().startsWith("SIG") ) { msg.kill = "SIGTERM"; } - if (msg.hasOwnProperty("pid")) { - if (node.activeProcesses.hasOwnProperty(msg.pid) ) { - node.activeProcesses[msg.pid].kill(msg.kill.toUpperCase()); - node.status({fill:"red",shape:"dot",text:"killed"}); - } - } - else { - if (Object.keys(node.activeProcesses).length === 1) { - node.activeProcesses[Object.keys(node.activeProcesses)[0]].kill(msg.kill.toUpperCase()); - node.status({fill:"red",shape:"dot",text:"killed"}); - } - } - nodeDone(); - } - else { - var child; - // make the extra args into an array - // then prepend with the msg.payload - var arg = node.cmd; - if (node.addpay) { - var value = RED.util.getMessageProperty(msg, node.addpay); - if (value !== undefined) { - arg += " " + value; - } - } - if (node.append.trim() !== "") { arg += " " + node.append; } - if (this.useSpawn === true) { - // slice whole line by spaces and removes any quotes since spawn can't handle them - arg = arg.match(/(?:[^\s"]+|"[^"]*")+/g).map((a) => { - if (/^".*"$/.test(a)) { - return a.slice(1,-1) - } else { - return a - } - }); - var cmd = arg.shift(); - /* istanbul ignore else */ - node.debug(cmd+" ["+arg+"]"); - child = spawn(cmd,arg,node.spawnOpt); - node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid}); - var unknownCommand = (child.pid === undefined); - if (node.timer !== 0) { - child.tout = setTimeout(function() { cleanup(child.pid); }, node.timer); - } - node.activeProcesses[child.pid] = child; - child.stdout.on('data', function (data) { - if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) { - // console.log('[exec] stdout: ' + data,child.pid); - if (isUtf8(data)) { msg.payload = data.toString(); } - else { msg.payload = data; } - nodeSend([RED.util.cloneMessage(msg),null,null]); - } - }); - child.stderr.on('data', function (data) { - if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) { - if (isUtf8(data)) { msg.payload = data.toString(); } - else { msg.payload = Buffer.from(data); } - nodeSend([null,RED.util.cloneMessage(msg),null]); - } - }); - child.on('close', function (code,signal) { - if (unknownCommand || (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null)) { - delete node.activeProcesses[child.pid]; - if (child.tout) { clearTimeout(child.tout); } - msg.payload = code; - if (node.oldrc === "false") { - msg.payload = {code:code}; - if (signal) { msg.payload.signal = signal; } - } - if (code === 0) { node.status({}); } - if (code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); } - else if (code < 0) { node.status({fill:"red",shape:"dot",text:"rc:"+code}); } - else { node.status({fill:"yellow",shape:"dot",text:"rc:"+code}); } - nodeSend([null,null,RED.util.cloneMessage(msg)]); - } - nodeDone(); - }); - child.on('error', function (code) { - if (child.tout) { clearTimeout(child.tout); } - delete node.activeProcesses[child.pid]; - if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) { - node.error(code,RED.util.cloneMessage(msg)); - } - }); - } - else { - /* istanbul ignore else */ - node.debug(arg); - child = exec(arg, node.execOpt, function (error, stdout, stderr) { - var msg2, msg3; - delete msg.payload; - if (stderr) { - msg2 = RED.util.cloneMessage(msg); - msg2.payload = stderr; - } - msg.payload = Buffer.from(stdout,"binary"); - if (isUtf8(msg.payload)) { msg.payload = msg.payload.toString(); } - node.status({}); - //console.log('[exec] stdout: ' + stdout); - //console.log('[exec] stderr: ' + stderr); - if (error !== null) { - msg3 = RED.util.cloneMessage(msg); - msg3.payload = {code:error.code, message:error.message}; - if (error.signal) { msg3.payload.signal = error.signal; } - if (error.code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); } - else { node.status({fill:"red",shape:"dot",text:"error:"+error.code}); } - node.debug('error:' + error); - } - else if (node.oldrc === "false") { - msg3 = RED.util.cloneMessage(msg); - msg3.payload = {code:0}; - } - if (!msg3) { node.status({}); } - else { - msg.rc = msg3.payload; - if (msg2) { msg2.rc = msg3.payload; } - } - nodeSend([msg,msg2,msg3]); - if (child.tout) { clearTimeout(child.tout); } - delete node.activeProcesses[child.pid]; - nodeDone(); - }); - node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid}); - child.on('error',function() {}); - if (node.timer !== 0) { - child.tout = setTimeout(function() { cleanup(child.pid); }, node.timer); - } - node.activeProcesses[child.pid] = child; - } - } - }); - - this.on('close',function() { - for (var pid in node.activeProcesses) { - /* istanbul ignore else */ - if (node.activeProcesses.hasOwnProperty(pid)) { - if (node.activeProcesses[pid].tout) { clearTimeout(node.activeProcesses[pid].tout); } - // console.log("KILLING",pid); - var process = node.activeProcesses[pid]; - node.activeProcesses[pid] = null; - process.kill(); - } - } - node.activeProcesses = {}; - node.status({}); - }); - } - RED.nodes.registerType("exec",ExecNode); -} diff --git a/packages/node_modules/@node-red/nodes/core/function/rbe.js b/packages/node_modules/@node-red/nodes/core/function/rbe.js deleted file mode 100644 index eb526a441..000000000 --- a/packages/node_modules/@node-red/nodes/core/function/rbe.js +++ /dev/null @@ -1,97 +0,0 @@ - -module.exports = function(RED) { - "use strict"; - function RbeNode(n) { - RED.nodes.createNode(this,n); - this.func = n.func || "rbe"; - this.gap = n.gap || "0"; - this.start = n.start || ''; - this.inout = n.inout || "out"; - this.pc = false; - if (this.gap.substr(-1) === "%") { - this.pc = true; - this.gap = parseFloat(this.gap); - } - this.g = this.gap; - this.property = n.property || "payload"; - this.topi = n.topi || "topic"; - this.septopics = true; - if (n.septopics !== undefined && n.septopics === false) { - this.septopics = false; - } - - var node = this; - - node.previous = {}; - this.on("input",function(msg) { - var topic; - try { - topic = RED.util.getMessageProperty(msg,node.topi); - } - catch(e) { } - if (msg.hasOwnProperty("reset")) { - if (node.septopics && topic && (typeof topic === "string") && (topic !== "")) { - delete node.previous[msg.topic]; - } - else { node.previous = {}; } - } - var value = RED.util.getMessageProperty(msg,node.property); - if (value !== undefined) { - var t = "_no_topic"; - if (node.septopics) { t = topic || t; } - if ((this.func === "rbe") || (this.func === "rbei")) { - var doSend = (this.func !== "rbei") || (node.previous.hasOwnProperty(t)) || false; - if (typeof(value) === "object") { - if (typeof(node.previous[t]) !== "object") { node.previous[t] = {}; } - if (!RED.util.compareObjects(value, node.previous[t])) { - node.previous[t] = RED.util.cloneMessage(value); - if (doSend) { node.send(msg); } - } - } - else { - if (value !== node.previous[t]) { - node.previous[t] = RED.util.cloneMessage(value); - if (doSend) { node.send(msg); } - } - } - } - else { - var n = parseFloat(value); - if (!isNaN(n)) { - if ((typeof node.previous[t] === 'undefined') && (this.func === "narrowband" || this.func === "narrowbandEq")) { - if (node.start === '') { node.previous[t] = n; } - else { node.previous[t] = node.start; } - } - if (node.pc) { node.gap = Math.abs(node.previous[t] * node.g / 100) || 0; } - else { node.gap = Number(node.gap); } - if ((node.previous[t] === undefined) && (node.func === "narrowbandEq")) { node.previous[t] = n; } - if (node.previous[t] === undefined) { node.previous[t] = n - node.gap - 1; } - if (Math.abs(n - node.previous[t]) === node.gap) { - if ((this.func === "deadbandEq")||(this.func === "narrowband")) { - if (node.inout === "out") { node.previous[t] = n; } - node.send(msg); - } - } - else if (Math.abs(n - node.previous[t]) > node.gap) { - if (this.func === "deadband" || this.func === "deadbandEq") { - if (node.inout === "out") { node.previous[t] = n; } - node.send(msg); - } - } - else if (Math.abs(n - node.previous[t]) < node.gap) { - if ((this.func === "narrowband")||(this.func === "narrowbandEq")) { - if (node.inout === "out") { node.previous[t] = n; } - node.send(msg); - } - } - if (node.inout === "in") { node.previous[t] = n; } - } - else { - node.warn(RED._("rbe.warn.nonumber")); - } - } - } // ignore msg with no payload property. - }); - } - RED.nodes.registerType("rbe",RbeNode); -} diff --git a/packages/node_modules/@node-red/nodes/core/network/21-httprequest.js b/packages/node_modules/@node-red/nodes/core/network/21-httprequest.js deleted file mode 100644 index bf677b490..000000000 --- a/packages/node_modules/@node-red/nodes/core/network/21-httprequest.js +++ /dev/null @@ -1,675 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - const got = require("got"); - const {CookieJar} = require("tough-cookie"); - const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent'); - const FormData = require('form-data'); - const { v4: uuid } = require('uuid'); - const crypto = require('crypto'); - const URL = require("url").URL - var mustache = require("mustache"); - var querystring = require("querystring"); - var cookie = require("cookie"); - var hashSum = require("hash-sum"); - - - // Cache a reference to the existing https.request function - // so we can compare later to see if an old agent-base instance - // has been required. - // This is generally okay as the core nodes are required before - // any contrib nodes. Where it will fail is if the agent-base module - // is required via the settings file or outside of Node-RED before it - // is started. - // If there are other modules that patch the function, they will get undone - // as well. Not much we can do about that right now. Patching core - // functions is bad. - const HTTPS_MODULE = require("https"); - const HTTPS_REQUEST = HTTPS_MODULE.request; - - function checkNodeAgentPatch() { - if (HTTPS_MODULE.request !== HTTPS_REQUEST && HTTPS_MODULE.request.length === 2) { - RED.log.warn(` - ---------------------------------------------------------------------- -Patched https.request function detected. This will break the -HTTP Request node. The original code has now been restored. - -This is likely caused by a contrib node including an old version of -the 'agent-base@<5.0.0' module. - -You can identify what node is at fault by running: - npm list agent-base -in your Node-RED user directory (${RED.settings.userDir}). ---------------------------------------------------------------------- -`); - HTTPS_MODULE.request = HTTPS_REQUEST - } - } - - function HTTPRequest(n) { - RED.nodes.createNode(this,n); - checkNodeAgentPatch(); - var node = this; - var nodeUrl = n.url; - var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1; - var nodeMethod = n.method || "GET"; - var paytoqs = false; - var paytobody = false; - var redirectList = []; - var sendErrorsToCatch = n.senderr; - - var nodeHTTPPersistent = n["persist"]; - if (n.tls) { - var tlsNode = RED.nodes.getNode(n.tls); - } - this.ret = n.ret || "txt"; - this.authType = n.authType || "basic"; - if (RED.settings.httpRequestTimeout) { this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000; } - else { this.reqTimeout = 120000; } - - if (n.paytoqs === true || n.paytoqs === "query") { paytoqs = true; } - else if (n.paytoqs === "body") { paytobody = true; } - - - var prox, noprox; - if (process.env.http_proxy) { prox = process.env.http_proxy; } - if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; } - if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); } - if (process.env.NO_PROXY) { noprox = process.env.NO_PROXY.split(","); } - - var proxyConfig = null; - if (n.proxy) { - proxyConfig = RED.nodes.getNode(n.proxy); - prox = proxyConfig.url; - noprox = proxyConfig.noproxy; - } - - let timingLog = false; - if (RED.settings.hasOwnProperty("httpRequestTimingLog")) { - timingLog = RED.settings.httpRequestTimingLog; - } - - this.on("input",function(msg,nodeSend,nodeDone) { - checkNodeAgentPatch(); - //reset redirectList on each request - redirectList = []; - var preRequestTimestamp = process.hrtime(); - node.status({fill:"blue",shape:"dot",text:"httpin.status.requesting"}); - var url = nodeUrl || msg.url; - if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed - node.warn(RED._("common.errors.nooverride")); - } - - if (isTemplatedUrl) { - url = mustache.render(nodeUrl,msg); - } - if (!url) { - node.error(RED._("httpin.errors.no-url"),msg); - nodeDone(); - return; - } - - - // url must start http:// or https:// so assume http:// if not set - if (url.indexOf("://") !== -1 && url.indexOf("http") !== 0) { - node.warn(RED._("httpin.errors.invalid-transport")); - node.status({fill:"red",shape:"ring",text:"httpin.errors.invalid-transport"}); - nodeDone(); - return; - } - if (!((url.indexOf("http://") === 0) || (url.indexOf("https://") === 0))) { - if (tlsNode) { - url = "https://"+url; - } else { - url = "http://"+url; - } - } - - // The Request module used in Node-RED 1.x was tolerant of query strings that - // were partially encoded. For example - "?a=hello%20there&b=20%" - // The GOT module doesn't like that. - // The following is an attempt to normalise the url to ensure it is properly - // encoded. We cannot just encode it directly as we don't want any valid - // encoded entity to end up doubly encoded. - if (url.indexOf("?") > -1) { - // Only do this if there is a query string to deal with - const [hostPath, ...queryString] = url.split("?") - const query = queryString.join("?"); - if (query) { - // Look for any instance of % not followed by two hex chars. - // Replace any we find with %25. - const escapedQueryString = query.replace(/(%.?.?)/g, function(v) { - if (/^%[a-f0-9]{2}/i.test(v)) { - return v; - } - return v.replace(/%/,"%25") - }) - url = hostPath+"?"+escapedQueryString; - } - } - - var method = nodeMethod.toUpperCase() || "GET"; - if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set - node.warn(RED._("common.errors.nooverride")); - } - if (msg.method && n.method && (n.method === "use")) { - method = msg.method.toUpperCase(); // use the msg parameter - } - - // var isHttps = (/^https/i.test(url)); - - var opts = {}; - // set defaultport, else when using HttpsProxyAgent, it's defaultPort of 443 will be used :(. - // Had to remove this to get http->https redirect to work - // opts.defaultPort = isHttps?443:80; - opts.timeout = node.reqTimeout; - opts.throwHttpErrors = false; - // TODO: add UI option to auto decompress. Setting to false for 1.x compatibility - opts.decompress = false; - opts.method = method; - opts.headers = {}; - opts.retry = 0; - opts.responseType = 'buffer'; - opts.maxRedirects = 21; - opts.cookieJar = new CookieJar(); - opts.ignoreInvalidCookies = true; - opts.forever = nodeHTTPPersistent; - if (msg.requestTimeout !== undefined) { - if (isNaN(msg.requestTimeout)) { - node.warn(RED._("httpin.errors.timeout-isnan")); - } else if (msg.requestTimeout < 1) { - node.warn(RED._("httpin.errors.timeout-isnegative")); - } else { - opts.timeout = msg.requestTimeout; - } - } - const originalHeaderMap = {}; - - opts.hooks = { - beforeRequest: [ - options => { - // Whilst HTTP headers are meant to be case-insensitive, - // in the real world, there are servers that aren't so compliant. - // GOT will lower case all headers given a chance, so we need - // to restore the case of any headers the user has set. - Object.keys(options.headers).forEach(h => { - if (originalHeaderMap[h] && originalHeaderMap[h] !== h) { - options.headers[originalHeaderMap[h]] = options.headers[h]; - delete options.headers[h]; - } - }) - } - ], - beforeRedirect: [ - (options, response) => { - let redirectInfo = { - location: response.headers.location - } - if (response.headers.hasOwnProperty('set-cookie')) { - redirectInfo.cookies = extractCookies(response.headers['set-cookie']); - } - redirectList.push(redirectInfo) - } - ] - } - - var ctSet = "Content-Type"; // set default camel case - var clSet = "Content-Length"; - if (msg.headers) { - if (msg.headers.hasOwnProperty('x-node-red-request-node')) { - var headerHash = msg.headers['x-node-red-request-node']; - delete msg.headers['x-node-red-request-node']; - var hash = hashSum(msg.headers); - if (hash === headerHash) { - delete msg.headers; - } - } - if (msg.headers) { - for (var v in msg.headers) { - if (msg.headers.hasOwnProperty(v)) { - var name = v.toLowerCase(); - if (name !== "content-type" && name !== "content-length") { - // only normalise the known headers used later in this - // function. Otherwise leave them alone. - name = v; - } - else if (name === 'content-type') { ctSet = v; } - else { clSet = v; } - opts.headers[name] = msg.headers[v]; - } - } - } - } - - if (msg.hasOwnProperty('followRedirects')) { - opts.followRedirect = !!msg.followRedirects; - } - - if (opts.headers.hasOwnProperty('cookie')) { - var cookies = cookie.parse(opts.headers.cookie, {decode:String}); - for (var name in cookies) { - opts.cookieJar.setCookieSync(cookie.serialize(name, cookies[name], {encode:String}), url, {ignoreError: true}); - } - delete opts.headers.cookie; - } - if (msg.cookies) { - for (var name in msg.cookies) { - if (msg.cookies.hasOwnProperty(name)) { - if (msg.cookies[name] === null || msg.cookies[name].value === null) { - // This case clears a cookie for HTTP In/Response nodes. - // Ignore for this node. - } else if (typeof msg.cookies[name] === 'object') { - if(msg.cookies[name].encode === false){ - // If the encode option is false, the value is not encoded. - opts.cookieJar.setCookieSync(cookie.serialize(name, msg.cookies[name].value, {encode: String}), url, {ignoreError: true}); - } else { - // The value is encoded by encodeURIComponent(). - opts.cookieJar.setCookieSync(cookie.serialize(name, msg.cookies[name].value), url, {ignoreError: true}); - } - } else { - opts.cookieJar.setCookieSync(cookie.serialize(name, msg.cookies[name]), url, {ignoreError: true}); - } - } - } - } - var parsedURL = new URL(url) - this.credentials = this.credentials || {} - if (parsedURL.username && !this.credentials.user) { - this.credentials.user = parsedURL.username - } - if (parsedURL.password && !this.credentials.password) { - this.credentials.password = parsedURL.password - } - if (Object.keys(this.credentials).length != 0) { - if (this.authType === "basic") { - // Workaround for https://github.com/sindresorhus/got/issues/1169 (fixed in got v12) - // var cred = "" - if (this.credentials.user || this.credentials.password) { - // cred = `${this.credentials.user}:${this.credentials.password}`; - if (this.credentials.user === undefined) { this.credentials.user = ""} - if (this.credentials.password === undefined) { this.credentials.password = ""} - opts.headers.Authorization = "Basic " + Buffer.from(`${this.credentials.user}:${this.credentials.password}`).toString("base64"); - } - // build own basic auth header - // opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64"); - } else if (this.authType === "digest") { - let digestCreds = this.credentials; - let sentCreds = false; - opts.hooks.afterResponse = [(response, retry) => { - if (response.statusCode === 401) { - if (sentCreds) { - return response - } - const requestUrl = new URL(response.request.requestUrl); - const options = response.request.options; - const normalisedHeaders = {}; - Object.keys(response.headers).forEach(k => { - normalisedHeaders[k.toLowerCase()] = response.headers[k] - }) - if (normalisedHeaders['www-authenticate']) { - let authHeader = buildDigestHeader(digestCreds.user,digestCreds.password, options.method, requestUrl.pathname, normalisedHeaders['www-authenticate']) - options.headers.Authorization = authHeader; - } - sentCreds = true; - return retry(options); - } - return response - }]; - } else if (this.authType === "bearer") { - opts.headers.Authorization = `Bearer ${this.credentials.password||""}` - } - } - var payload = null; - - - if (method !== 'GET' && method !== 'HEAD' && typeof msg.payload !== "undefined") { - if (opts.headers['content-type'] == 'multipart/form-data' && typeof msg.payload === "object") { - let formData = new FormData(); - for (var opt in msg.payload) { - if (msg.payload.hasOwnProperty(opt)) { - var val = msg.payload[opt]; - if (val !== undefined && val !== null) { - if (typeof val === 'string' || Buffer.isBuffer(val)) { - formData.append(opt, val); - } else if (typeof val === 'object' && val.hasOwnProperty('value')) { - formData.append(opt,val.value,val.options || {}); - } else { - formData.append(opt,JSON.stringify(val)); - } - } - } - } - // GOT will only set the content-type header with the correct boundary - // if the header isn't set. So we delete it here, for GOT to reset it. - delete opts.headers['content-type']; - opts.body = formData; - } else { - if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) { - payload = msg.payload; - } else if (typeof msg.payload == "number") { - payload = msg.payload+""; - } else { - if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') { - payload = querystring.stringify(msg.payload); - } else { - payload = JSON.stringify(msg.payload); - if (opts.headers['content-type'] == null) { - opts.headers[ctSet] = "application/json"; - } - } - } - if (opts.headers['content-length'] == null) { - if (Buffer.isBuffer(payload)) { - opts.headers[clSet] = payload.length; - } else { - opts.headers[clSet] = Buffer.byteLength(payload); - } - } - opts.body = payload; - } - } - - - if (method == 'GET' && typeof msg.payload !== "undefined" && paytoqs) { - if (typeof msg.payload === "object") { - try { - if (url.indexOf("?") !== -1) { - url += (url.endsWith("?")?"":"&") + querystring.stringify(msg.payload); - } else { - url += "?" + querystring.stringify(msg.payload); - } - } catch(err) { - - node.error(RED._("httpin.errors.invalid-payload"),msg); - nodeDone(); - return; - } - } else { - - node.error(RED._("httpin.errors.invalid-payload"),msg); - nodeDone(); - return; - } - } else if ( method == "GET" && typeof msg.payload !== "undefined" && paytobody) { - opts.allowGetBody = true; - if (typeof msg.payload === "object") { - opts.body = JSON.stringify(msg.payload); - } else if (typeof msg.payload == "number") { - opts.body = msg.payload+""; - } else if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) { - opts.body = msg.payload; - } - } - - // revert to user supplied Capitalisation if needed. - if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) { - opts.headers[ctSet] = opts.headers['content-type']; - delete opts.headers['content-type']; - } - if (opts.headers.hasOwnProperty('content-length') && (clSet !== 'content-length')) { - opts.headers[clSet] = opts.headers['content-length']; - delete opts.headers['content-length']; - } - - var noproxy; - if (noprox) { - for (var i = 0; i < noprox.length; i += 1) { - if (url.indexOf(noprox[i]) !== -1) { noproxy=true; } - } - } - if (prox && !noproxy) { - var match = prox.match(/^(https?:\/\/)?(.+)?:([0-9]+)?/i); - if (match) { - let proxyAgent; - let proxyURL = new URL(prox); - //set username/password to null to stop empty creds header - let proxyOptions = { - proxy: { - protocol: proxyURL.protocol, - hostname: proxyURL.hostname, - port: proxyURL.port, - username: null, - password: null - }, - maxFreeSockets: 256, - maxSockets: 256, - keepAlive: true - } - if (proxyConfig && proxyConfig.credentials) { - let proxyUsername = proxyConfig.credentials.username || ''; - let proxyPassword = proxyConfig.credentials.password || ''; - if (proxyUsername || proxyPassword) { - proxyOptions.proxy.username = proxyUsername; - proxyOptions.proxy.password = proxyPassword; - } - } else if (proxyURL.username || proxyURL.password){ - proxyOptions.proxy.username = proxyURL.username; - proxyOptions.proxy.password = proxyURL.password; - } - //need both incase of http -> https redirect - opts.agent = { - http: new HttpProxyAgent(proxyOptions), - https: new HttpsProxyAgent(proxyOptions) - }; - - } else { - node.warn("Bad proxy url: "+ prox); - } - } - if (tlsNode) { - opts.https = {}; - tlsNode.addTLSOptions(opts.https); - if (opts.https.ca) { - opts.https.certificateAuthority = opts.https.ca; - delete opts.https.ca; - } - if (opts.https.cert) { - opts.https.certificate = opts.https.cert; - delete opts.https.cert; - } - } else { - if (msg.hasOwnProperty('rejectUnauthorized')) { - opts.https = { rejectUnauthorized: msg.rejectUnauthorized }; - } - } - - // Now we have established all of our own headers, take a snapshot - // of their case so we can restore it prior to the request being sent. - if (opts.headers) { - Object.keys(opts.headers).forEach(h => { - originalHeaderMap[h.toLowerCase()] = h - }) - } - got(url,opts).then(res => { - msg.statusCode = res.statusCode; - msg.headers = res.headers; - msg.responseUrl = res.url; - msg.payload = res.body; - msg.redirectList = redirectList; - msg.retry = 0; - - if (msg.headers.hasOwnProperty('set-cookie')) { - msg.responseCookies = extractCookies(msg.headers['set-cookie']); - } - msg.headers['x-node-red-request-node'] = hashSum(msg.headers); - // msg.url = url; // revert when warning above finally removed - if (node.metric()) { - // Calculate request time - var diff = process.hrtime(preRequestTimestamp); - var ms = diff[0] * 1e3 + diff[1] * 1e-6; - var metricRequestDurationMillis = ms.toFixed(3); - node.metric("duration.millis", msg, metricRequestDurationMillis); - if (res.client && res.client.bytesRead) { - node.metric("size.bytes", msg, res.client.bytesRead); - } - if (timingLog) { - emitTimingMetricLog(res.timings, msg); - } - } - - // Convert the payload to the required return type - if (node.ret !== "bin") { - msg.payload = msg.payload.toString('utf8'); // txt - - if (node.ret === "obj") { - try { msg.payload = JSON.parse(msg.payload); } // obj - catch(e) { node.warn(RED._("httpin.errors.json-error")); } - } - } - node.status({}); - nodeSend(msg); - nodeDone(); - }).catch(err => { - // Pre 2.1, any errors would be sent to both Catch node and sent on as normal. - // This is not ideal but is the legacy behaviour of the node. - // 2.1 adds the 'senderr' option, if set to true, will *only* send errors - // to Catch nodes. If false, it still does both behaviours. - // TODO: 3.0 - make it one or the other. - - if (err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') { - node.error(RED._("common.notification.errors.no-response"), msg); - node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"}); - } else { - node.error(err,msg); - node.status({fill:"red", shape:"ring", text:err.code}); - } - msg.payload = err.toString() + " : " + url; - msg.statusCode = err.code || (err.response?err.response.statusCode:undefined); - if (node.metric() && timingLog) { - emitTimingMetricLog(err.timings, msg); - } - if (!sendErrorsToCatch) { - nodeSend(msg); - } - nodeDone(); - }); - }); - - this.on("close",function() { - node.status({}); - }); - - function emitTimingMetricLog(timings, msg) { - const props = [ - "start", - "socket", - "lookup", - "connect", - "secureConnect", - "upload", - "response", - "end", - "error", - "abort" - ]; - if (timings) { - props.forEach(p => { - if (timings[p]) { - node.metric(`timings.${p}`, msg, timings[p]); - } - }); - } - } - - function extractCookies(setCookie) { - var cookies = {}; - setCookie.forEach(function(c) { - var parsedCookie = cookie.parse(c); - var eq_idx = c.indexOf('='); - var key = c.substr(0, eq_idx).trim() - parsedCookie.value = parsedCookie[key]; - delete parsedCookie[key]; - cookies[key] = parsedCookie; - }); - return cookies; - } - } - - RED.nodes.registerType("http request",HTTPRequest,{ - credentials: { - user: {type:"text"}, - password: {type: "password"} - } - }); - - const md5 = (value) => { return crypto.createHash('md5').update(value).digest('hex') } - - function ha1Compute(algorithm, user, realm, pass, nonce, cnonce) { - /** - * RFC 2617: handle both MD5 and MD5-sess algorithms. - * - * If the algorithm directive's value is "MD5" or unspecified, then HA1 is - * HA1=MD5(username:realm:password) - * If the algorithm directive's value is "MD5-sess", then HA1 is - * HA1=MD5(MD5(username:realm:password):nonce:cnonce) - */ - var ha1 = md5(user + ':' + realm + ':' + pass) - if (algorithm && algorithm.toLowerCase() === 'md5-sess') { - return md5(ha1 + ':' + nonce + ':' + cnonce) - } else { - return ha1 - } - } - - - function buildDigestHeader(user, pass, method, path, authHeader) { - var challenge = {} - var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi - for (;;) { - var match = re.exec(authHeader) - if (!match) { - break - } - challenge[match[1]] = match[2] || match[3] - } - var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth' - var nc = qop && '00000001' - var cnonce = qop && uuid().replace(/-/g, '') - var ha1 = ha1Compute(challenge.algorithm, user, challenge.realm, pass, challenge.nonce, cnonce) - var ha2 = md5(method + ':' + path) - var digestResponse = qop - ? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2) - : md5(ha1 + ':' + challenge.nonce + ':' + ha2) - var authValues = { - username: user, - realm: challenge.realm, - nonce: challenge.nonce, - uri: path, - qop: qop, - response: digestResponse, - nc: nc, - cnonce: cnonce, - algorithm: challenge.algorithm, - opaque: challenge.opaque - } - - authHeader = [] - for (var k in authValues) { - if (authValues[k]) { - if (k === 'qop' || k === 'nc' || k === 'algorithm') { - authHeader.push(k + '=' + authValues[k]) - } else { - authHeader.push(k + '="' + authValues[k] + '"') - } - } - } - authHeader = 'Digest ' + authHeader.join(', ') - return authHeader - } -} diff --git a/packages/node_modules/@node-red/nodes/core/network/22-websocket.html b/packages/node_modules/@node-red/nodes/core/network/22-websocket.html deleted file mode 100644 index a7b54d72f..000000000 --- a/packages/node_modules/@node-red/nodes/core/network/22-websocket.html +++ /dev/null @@ -1,292 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packages/node_modules/@node-red/nodes/core/network/22-websocket.js b/packages/node_modules/@node-red/nodes/core/network/22-websocket.js deleted file mode 100644 index ed4c93b09..000000000 --- a/packages/node_modules/@node-red/nodes/core/network/22-websocket.js +++ /dev/null @@ -1,423 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - var ws = require("ws"); - var inspect = require("util").inspect; - var url = require("url"); - var HttpsProxyAgent = require('https-proxy-agent'); - - - var serverUpgradeAdded = false; - function handleServerUpgrade(request, socket, head) { - const pathname = url.parse(request.url).pathname; - if (listenerNodes.hasOwnProperty(pathname)) { - listenerNodes[pathname].server.handleUpgrade(request, socket, head, function done(ws) { - listenerNodes[pathname].server.emit('connection', ws, request); - }); - } else { - // Don't destroy the socket as other listeners may want to handle the - // event. - } - } - var listenerNodes = {}; - var activeListenerNodes = 0; - - - // A node red node that sets up a local websocket server - function WebSocketListenerNode(n) { - // Create a RED node - RED.nodes.createNode(this,n); - var node = this; - - // Store local copies of the node configuration (as defined in the .html) - node.path = n.path; - if (typeof n.subprotocol === "string") { - // Split the string on comma and trim each result - node.subprotocol = n.subprotocol.split(",").map(v => v.trim()) - } else { - node.subprotocol = []; - } - node.wholemsg = (n.wholemsg === "true"); - - node._inputNodes = []; // collection of nodes that want to receive events - node._clients = {}; - // match absolute url - node.isServer = !/^ws{1,2}:\/\//i.test(node.path); - node.closing = false; - node.tls = n.tls; - - if (n.hb) { - var heartbeat = parseInt(n.hb); - if (heartbeat > 0) { - node.heartbeat = heartbeat * 1000; - } - } - - function startconn() { // Connect to remote endpoint - node.tout = null; - var prox, noprox; - if (process.env.http_proxy) { prox = process.env.http_proxy; } - if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; } - if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); } - if (process.env.NO_PROXY) { noprox = process.env.NO_PROXY.split(","); } - - var noproxy = false; - if (noprox) { - for (var i in noprox) { - if (node.path.indexOf(noprox[i].trim()) !== -1) { noproxy=true; } - } - } - - var agent = undefined; - if (prox && !noproxy) { - agent = new HttpsProxyAgent(prox); - } - - var options = {}; - if (agent) { - options.agent = agent; - } - if (node.tls) { - var tlsNode = RED.nodes.getNode(node.tls); - if (tlsNode) { - tlsNode.addTLSOptions(options); - } - } - var socket = new ws(node.path,node.subprotocol,options); - socket.setMaxListeners(0); - node.server = socket; // keep for closing - handleConnection(socket); - } - - function handleConnection(/*socket*/socket) { - var id = RED.util.generateId(); - socket.nrId = id; - socket.nrPendingHeartbeat = false; - if (node.isServer) { - node._clients[id] = socket; - node.emit('opened',{count:Object.keys(node._clients).length,id:id}); - } - socket.on('open',function() { - if (!node.isServer) { - if (node.heartbeat) { - clearInterval(node.heartbeatInterval); - node.heartbeatInterval = setInterval(function() { - if (socket.nrPendingHeartbeat) { - // No pong received - socket.terminate(); - socket.nrErrorHandler(new Error("timeout")); - return; - } - socket.nrPendingHeartbeat = true; - try { - socket.ping(); - } catch(err) {} - },node.heartbeat); - } - node.emit('opened',{count:'',id:id}); - } - }); - socket.on('close',function() { - clearInterval(node.heartbeatInterval); - if (node.isServer) { - delete node._clients[id]; - node.emit('closed',{count:Object.keys(node._clients).length,id:id}); - } else { - node.emit('closed',{count:'',id:id}); - } - if (!node.closing && !node.isServer) { - clearTimeout(node.tout); - node.tout = setTimeout(function() { startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? - } - }); - socket.on('message',function(data,flags) { - node.handleEvent(id,socket,'message',data,flags); - }); - socket.nrErrorHandler = function(err) { - clearInterval(node.heartbeatInterval); - node.emit('erro',{err:err,id:id}); - if (!node.closing && !node.isServer) { - clearTimeout(node.tout); - node.tout = setTimeout(function() { startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? - } - } - socket.on('error',socket.nrErrorHandler); - socket.on('ping', function() { - socket.nrPendingHeartbeat = false; - }) - socket.on('pong', function() { - socket.nrPendingHeartbeat = false; - }) - } - - if (node.isServer) { - activeListenerNodes++; - if (!serverUpgradeAdded) { - RED.server.on('upgrade', handleServerUpgrade); - serverUpgradeAdded = true - } - - var path = RED.settings.httpNodeRoot || "/"; - path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path); - node.fullPath = path; - - if (listenerNodes.hasOwnProperty(path)) { - node.error(RED._("websocket.errors.duplicate-path",{path: node.path})); - return; - } - listenerNodes[node.fullPath] = node; - var serverOptions = { - noServer: true - } - if (RED.settings.webSocketNodeVerifyClient) { - serverOptions.verifyClient = RED.settings.webSocketNodeVerifyClient; - } - // Create a WebSocket Server - node.server = new ws.Server(serverOptions); - node.server.setMaxListeners(0); - node.server.on('connection', handleConnection); - // Not adding server-initiated heartbeats yet - // node.heartbeatInterval = setInterval(function() { - // node.server.clients.forEach(function(ws) { - // if (ws.nrPendingHeartbeat) { - // // No pong received - // ws.terminate(); - // ws.nrErrorHandler(new Error("timeout")); - // return; - // } - // ws.nrPendingHeartbeat = true; - // ws.ping(); - // }); - // }) - } - else { - node.closing = false; - startconn(); // start outbound connection - } - - node.on("close", function() { - if (node.heartbeatInterval) { - clearInterval(node.heartbeatInterval); - } - if (node.isServer) { - delete listenerNodes[node.fullPath]; - node.server.close(); - node._inputNodes = []; - activeListenerNodes--; - // if (activeListenerNodes === 0 && serverUpgradeAdded) { - // RED.server.removeListener('upgrade', handleServerUpgrade); - // serverUpgradeAdded = false; - // } - } - else { - node.closing = true; - node.server.close(); - if (node.tout) { - clearTimeout(node.tout); - node.tout = null; - } - } - }); - } - RED.nodes.registerType("websocket-listener",WebSocketListenerNode); - RED.nodes.registerType("websocket-client",WebSocketListenerNode); - - WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler) { - this._inputNodes.push(handler); - } - - WebSocketListenerNode.prototype.removeInputNode = function(/*Node*/handler) { - this._inputNodes.forEach(function(node, i, inputNodes) { - if (node === handler) { - inputNodes.splice(i, 1); - } - }); - } - - WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags) { - var msg; - if (this.wholemsg) { - try { - msg = JSON.parse(data); - if (typeof msg !== "object" && !Array.isArray(msg) && (msg !== null)) { - msg = { payload:msg }; - } - } - catch(err) { - msg = { payload:data }; - } - } else { - msg = { - payload:data - }; - } - msg._session = {type:"websocket",id:id}; - for (var i = 0; i < this._inputNodes.length; i++) { - this._inputNodes[i].send(msg); - } - } - - WebSocketListenerNode.prototype.broadcast = function(data) { - if (this.isServer) { - for (let client in this._clients) { - if (this._clients.hasOwnProperty(client)) { - try { - this._clients[client].send(data); - } catch(err) { - this.warn(RED._("websocket.errors.send-error")+" "+client+" "+err.toString()) - } - } - } - } - else { - try { - this.server.send(data); - } catch(err) { - this.warn(RED._("websocket.errors.send-error")+" "+err.toString()) - } - } - } - - WebSocketListenerNode.prototype.reply = function(id,data) { - var session = this._clients[id]; - if (session) { - try { - session.send(data); - } - catch(e) { // swallow any errors - } - } - } - - function WebSocketInNode(n) { - RED.nodes.createNode(this,n); - this.server = (n.client)?n.client:n.server; - var node = this; - this.serverConfig = RED.nodes.getNode(this.server); - if (this.serverConfig) { - this.serverConfig.registerInputNode(this); - // TODO: nls - this.serverConfig.on('opened', function(event) { - node.status({ - fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count}), - event:"connect", - _session: {type:"websocket",id:event.id} - }); - }); - this.serverConfig.on('erro', function(event) { - node.status({ - fill:"red",shape:"ring",text:"common.status.error", - event:"error", - _session: {type:"websocket",id:event.id} - }); - }); - this.serverConfig.on('closed', function(event) { - var status; - if (event.count > 0) { - status = {fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count})}; - } else { - status = {fill:"red",shape:"ring",text:"common.status.disconnected"}; - } - status.event = "disconnect"; - status._session = {type:"websocket",id:event.id} - node.status(status); - }); - } else { - this.error(RED._("websocket.errors.missing-conf")); - } - this.on('close', function() { - if (node.serverConfig) { - node.serverConfig.removeInputNode(node); - } - node.status({}); - }); - } - RED.nodes.registerType("websocket in",WebSocketInNode); - - function WebSocketOutNode(n) { - RED.nodes.createNode(this,n); - var node = this; - this.server = (n.client)?n.client:n.server; - this.serverConfig = RED.nodes.getNode(this.server); - if (!this.serverConfig) { - return this.error(RED._("websocket.errors.missing-conf")); - } - else { - // TODO: nls - this.serverConfig.on('opened', function(event) { - node.status({ - fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count}), - event:"connect", - _session: {type:"websocket",id:event.id} - }); - }); - this.serverConfig.on('erro', function(event) { - node.status({ - fill:"red",shape:"ring",text:"common.status.error", - event:"error", - _session: {type:"websocket",id:event.id} - }) - }); - this.serverConfig.on('closed', function(event) { - var status; - if (event.count > 0) { - status = {fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count})}; - } else { - status = {fill:"red",shape:"ring",text:"common.status.disconnected"}; - } - status.event = "disconnect"; - status._session = {type:"websocket",id:event.id} - node.status(status); - }); - } - this.on("input", function(msg, nodeSend, nodeDone) { - var payload; - if (this.serverConfig.wholemsg) { - var sess; - if (msg._session) { sess = JSON.stringify(msg._session); } - delete msg._session; - payload = JSON.stringify(msg); - if (sess) { msg._session = JSON.parse(sess); } - } - else if (msg.hasOwnProperty("payload")) { - if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string. - payload = RED.util.ensureString(msg.payload); - } - else { - payload = msg.payload; - } - } - if (payload) { - if (msg._session && msg._session.type == "websocket") { - node.serverConfig.reply(msg._session.id,payload); - } else { - node.serverConfig.broadcast(payload,function(error) { - if (!!error) { - node.warn(RED._("websocket.errors.send-error")+inspect(error)); - } - }); - } - } - nodeDone(); - }); - this.on('close', function() { - node.status({}); - }); - } - RED.nodes.registerType("websocket out",WebSocketOutNode); -} diff --git a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.html b/packages/node_modules/@node-red/nodes/core/network/31-tcpin.html deleted file mode 100644 index 97c8eb4d7..000000000 --- a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js b/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js deleted file mode 100644 index 24e6abf7e..000000000 --- a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js +++ /dev/null @@ -1,852 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - let reconnectTime = RED.settings.socketReconnectTime || 10000; - let socketTimeout = RED.settings.socketTimeout || null; - const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000; - const Denque = require('denque'); - const net = require('net'); - const tls = require('tls'); - - let connectionPool = {}; - - function normalizeConnectArgs(listArgs) { - const args = net._normalizeArgs(listArgs); - const options = args[0]; - const cb = args[1]; - - // If args[0] was options, then normalize dealt with it. - // If args[0] is port, or args[0], args[1] is host, port, we need to - // find the options and merge them in, normalize's options has only - // the host/port/path args that it knows about, not the tls options. - // This means that options.host overrides a host arg. - if (listArgs[1] !== null && typeof listArgs[1] === 'object') { - ObjectAssign(options, listArgs[1]); - } else if (listArgs[2] !== null && typeof listArgs[2] === 'object') { - ObjectAssign(options, listArgs[2]); - } - - return cb ? [options, cb] : [options]; - } - - function getAllowUnauthorized() { - const allowUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0'; - - if (allowUnauthorized) { - process.emitWarning( - 'Setting the NODE_TLS_REJECT_UNAUTHORIZED ' + - 'environment variable to \'0\' makes TLS connections ' + - 'and HTTPS requests insecure by disabling ' + - 'certificate verification.'); - } - return allowUnauthorized; - } - - /** - * Enqueue `item` in `queue` - * @param {Denque} queue - Queue - * @param {*} item - Item to enqueue - * @private - * @returns {Denque} `queue` - */ - const enqueue = (queue, item) => { - // drop msgs from front of queue if size is going to be exceeded - if (queue.length === msgQueueSize) { queue.shift(); } - queue.push(item); - return queue; - }; - - /** - * Shifts item off front of queue - * @param {Deque} queue - Queue - * @private - * @returns {*} Item previously at front of queue - */ - const dequeue = queue => queue.shift(); - - function TcpIn(n) { - RED.nodes.createNode(this,n); - this.host = n.host; - this.port = n.port * 1; - this.topic = n.topic; - this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/ - this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */ - this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t"); - this.base64 = n.base64; - this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server"); - this.closing = false; - this.connected = false; - var node = this; - var count = 0; - if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); } - - if (!node.server) { - var buffer = null; - var client; - var reconnectTimeout; - var end = false; - var setupTcpClient = function() { - node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port})); - node.status({fill:"grey",shape:"dot",text:"common.status.connecting"}); - var id = RED.util.generateId(); - var connOpts = {host: node.host}; - if (n.tls) { - var connOpts = tlsNode.addTLSOptions({host: node.host}); - client = tls.connect(node.port, connOpts, function() { - buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : ""; - node.connected = true; - node.log(RED._("status.connected", {host: node.host, port: node.port})); - node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}}); - }); - } - else { - client = net.connect(node.port, node.host, function() { - buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : ""; - node.connected = true; - node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port})); - node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}}); - }); - } - client.setKeepAlive(true, 120000); - connectionPool[id] = client; - - client.on('data', function (data) { - if (node.datatype != 'buffer') { - data = data.toString(node.datatype); - } - if (node.stream) { - var msg; - if ((node.datatype) === "utf8" && node.newline !== "") { - buffer = buffer+data; - var parts = buffer.split(node.newline); - for (var i = 0; i 0)) { - var msg = {topic:node.topic, payload:buffer}; - msg._session = {type:"tcp",id:id}; - if (buffer.length !== 0) { - end = true; // only ask for fast re-connect if we actually got something - node.send(msg); - } - buffer = null; - } - }); - client.on('close', function() { - delete connectionPool[id]; - node.connected = false; - node.status({fill:"red",shape:"ring",text:"common.status.disconnected",_session:{type:"tcp",id:id}}); - if (!node.closing) { - if (end) { // if we were asked to close then try to reconnect once very quick. - end = false; - reconnectTimeout = setTimeout(setupTcpClient, 20); - } - else { - node.log(RED._("tcpin.errors.connection-lost",{host:node.host,port:node.port})); - reconnectTimeout = setTimeout(setupTcpClient, reconnectTime); - } - } else { - if (node.doneClose) { node.doneClose(); } - } - }); - client.on('error', function(err) { - node.log(err); - }); - } - setupTcpClient(); - - this.on('close', function(done) { - node.doneClose = done; - this.closing = true; - if (client) { client.destroy(); } - clearTimeout(reconnectTimeout); - if (!node.connected) { done(); } - }); - } - else { - let srv = net; - let connOpts; - if (n.tls) { - srv = tls; - connOpts = tlsNode.addTLSOptions({}); - } - var server = srv.createServer(connOpts, function (socket) { - socket.setKeepAlive(true,120000); - if (socketTimeout !== null) { socket.setTimeout(socketTimeout); } - var id = RED.util.generateId(); - var fromi; - var fromp; - connectionPool[id] = socket; - count++; - node.status({ - text:RED._("tcpin.status.connections",{count:count}), - event:"connect", - ip:socket.remoteAddress, - port:socket.remotePort, - _session: {type:"tcp",id:id} - }); - - var buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : ""; - socket.on('data', function (data) { - if (node.datatype != 'buffer') { - data = data.toString(node.datatype); - } - if (node.stream) { - var msg; - if ((typeof data) === "string" && node.newline !== "") { - buffer = buffer+data; - var parts = buffer.split(node.newline); - for (var i = 0; i 0) { - var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp}; - msg._session = {type:"tcp",id:id}; - node.send(msg); - } - buffer = null; - } - }); - socket.on('timeout', function() { - node.log(RED._("tcpin.errors.timeout",{port:node.port})); - socket.end(); - }); - socket.on('close', function() { - delete connectionPool[id]; - count--; - node.status({ - text:RED._("tcpin.status.connections",{count:count}), - event:"disconnect", - ip:socket.remoteAddress, - port:socket.remotePort, - _session: {type:"tcp",id:id} - - }); - }); - socket.on('error',function(err) { - node.log(err); - }); - }); - - server.on('error', function(err) { - if (err) { - node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()})); - } - }); - - server.listen(node.port, function(err) { - if (err) { - node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()})); - } else { - node.log(RED._("tcpin.status.listening-port",{port:node.port})); - node.on('close', function() { - for (var c in connectionPool) { - if (connectionPool.hasOwnProperty(c)) { - connectionPool[c].end(); - connectionPool[c].unref(); - } - } - node.closing = true; - server.close(); - node.log(RED._("tcpin.status.stopped-listening",{port:node.port})); - }); - } - }); - } - } - RED.nodes.registerType("tcp in",TcpIn); - - - function TcpOut(n) { - RED.nodes.createNode(this,n); - this.host = n.host; - this.port = n.port * 1; - this.base64 = n.base64; - this.doend = n.end || false; - this.beserver = n.beserver; - this.name = n.name; - this.closing = false; - this.connected = false; - var node = this; - if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); } - - if (!node.beserver || node.beserver == "client") { - var reconnectTimeout; - var client = null; - var end = false; - - var setupTcpClient = function() { - node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port})); - node.status({fill:"grey",shape:"dot",text:"common.status.connecting"}); - if (n.tls) { - // connOpts = tlsNode.addTLSOptions(connOpts); - // client = tls.connect(connOpts, function() { - var connOpts = tlsNode.addTLSOptions({host: node.host}); - client = tls.connect(node.port, connOpts, function() { - // buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : ""; - node.connected = true; - node.log(RED._("status.connected", {host: node.host, port: node.port})); - node.status({fill:"green",shape:"dot",text:"common.status.connected"}); - }); - } - else { - client = net.connect(node.port, node.host, function() { - node.connected = true; - node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port})); - node.status({fill:"green",shape:"dot",text:"common.status.connected"}); - }); - } - client.setKeepAlive(true,120000); - client.on('error', function (err) { - node.log(RED._("tcpin.errors.error",{error:err.toString()})); - }); - client.on('end', function (err) { - node.status({}); - node.connected = false; - }); - client.on('close', function() { - node.status({fill:"red",shape:"ring",text:"common.status.disconnected"}); - node.connected = false; - client.destroy(); - if (!node.closing) { - if (end) { - end = false; - reconnectTimeout = setTimeout(setupTcpClient,20); - } - else { - node.log(RED._("tcpin.errors.connection-lost",{host:node.host,port:node.port})); - reconnectTimeout = setTimeout(setupTcpClient,reconnectTime); - } - } else { - if (node.doneClose) { node.doneClose(); } - } - }); - } - setupTcpClient(); - - node.on("input", function(msg, nodeSend, nodeDone) { - if (node.connected && msg.payload != null) { - if (Buffer.isBuffer(msg.payload)) { - client.write(msg.payload); - } else if (typeof msg.payload === "string" && node.base64) { - client.write(Buffer.from(msg.payload,'base64')); - } else { - client.write(Buffer.from(""+msg.payload)); - } - if (node.doend === true) { - end = true; - if (client) { node.status({}); client.destroy(); } - } - } - nodeDone(); - }); - - node.on("close", function(done) { - node.doneClose = done; - this.closing = true; - if (client) { client.destroy(); } - clearTimeout(reconnectTimeout); - if (!node.connected) { done(); } - }); - - } - else if (node.beserver == "reply") { - node.on("input",function(msg, nodeSend, nodeDone) { - if (msg._session && msg._session.type == "tcp") { - var client = connectionPool[msg._session.id]; - if (client) { - if (Buffer.isBuffer(msg.payload)) { - client.write(msg.payload); - } else if (typeof msg.payload === "string" && node.base64) { - client.write(Buffer.from(msg.payload,'base64')); - } else { - client.write(Buffer.from(""+msg.payload)); - } - } - } - else { - for (var i in connectionPool) { - if (Buffer.isBuffer(msg.payload)) { - connectionPool[i].write(msg.payload); - } else if (typeof msg.payload === "string" && node.base64) { - connectionPool[i].write(Buffer.from(msg.payload,'base64')); - } else { - connectionPool[i].write(Buffer.from(""+msg.payload)); - } - } - } - nodeDone(); - }); - } - else { - var connectedSockets = []; - node.status({text:RED._("tcpin.status.connections",{count:0})}); - let srv = net; - let connOpts; - if (n.tls) { - srv = tls; - connOpts = tlsNode.addTLSOptions({}); - } - var server = srv.createServer(connOpts, function (socket) { - socket.setKeepAlive(true,120000); - if (socketTimeout !== null) { socket.setTimeout(socketTimeout); } - node.log(RED._("tcpin.status.connection-from",{host:socket.remoteAddress, port:socket.remotePort})); - socket.on('timeout', function() { - node.log(RED._("tcpin.errors.timeout",{port:node.port})); - socket.end(); - }); - socket.on('data', function(d) { - // console.log("DATA",d) - }); - socket.on('close',function() { - node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort})); - connectedSockets.splice(connectedSockets.indexOf(socket),1); - node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})}); - }); - socket.on('error',function() { - node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort})); - connectedSockets.splice(connectedSockets.indexOf(socket),1); - node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})}); - }); - connectedSockets.push(socket); - node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})}); - }); - - node.on("input", function(msg, nodeSend, nodeDone) { - if (msg.payload != null) { - var buffer; - if (Buffer.isBuffer(msg.payload)) { - buffer = msg.payload; - } else if (typeof msg.payload === "string" && node.base64) { - buffer = Buffer.from(msg.payload,'base64'); - } else { - buffer = Buffer.from(""+msg.payload); - } - for (var i = 0; i < connectedSockets.length; i += 1) { - if (node.doend === true) { connectedSockets[i].end(buffer); } - else { connectedSockets[i].write(buffer); } - } - } - nodeDone(); - }); - - server.on('error', function(err) { - if (err) { - node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()})); - } - }); - - server.listen(node.port, function(err) { - if (err) { - node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()})); - } else { - node.log(RED._("tcpin.status.listening-port",{port:node.port})); - node.on('close', function() { - for (var c in connectedSockets) { - if (connectedSockets.hasOwnProperty(c)) { - connectedSockets[c].end(); - connectedSockets[c].unref(); - } - } - server.close(); - node.log(RED._("tcpin.status.stopped-listening",{port:node.port})); - }); - } - }); - } - } - RED.nodes.registerType("tcp out",TcpOut); - - - function TcpGet(n) { - RED.nodes.createNode(this,n); - this.server = n.server; - this.port = Number(n.port); - this.out = n.out; - this.ret = n.ret || "buffer"; - this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t"); - this.splitc = n.splitc; - if (n.tls) { - var tlsNode = RED.nodes.getNode(n.tls); - } - - if (this.out === "immed") { this.splitc = -1; this.out = "time"; } - if (this.out !== "char") { this.splitc = Number(this.splitc); } - else { - if (this.splitc[0] == '\\') { - this.splitc = parseInt(this.splitc.replace("\\n",0x0A).replace("\\r",0x0D).replace("\\t",0x09).replace("\\e",0x1B).replace("\\f",0x0C).replace("\\0",0x00)); - } // jshint ignore:line - if (typeof this.splitc == "string") { - if (this.splitc.substr(0,2) == "0x") { - this.splitc = parseInt(this.splitc); - } - else { - this.splitc = this.splitc.charCodeAt(0); - } - } // jshint ignore:line - } - - var node = this; - - var clients = {}; - - this.on("input", function(msg, nodeSend, nodeDone) { - var i = 0; - if ((!Buffer.isBuffer(msg.payload)) && (typeof msg.payload !== "string")) { - msg.payload = msg.payload.toString(); - } - - var host = node.server || msg.host; - var port = node.port || msg.port; - - // Store client information independently - // the clients object will have: - // clients[id].client, clients[id].msg, clients[id].timeout - var connection_id = host + ":" + port; - if (connection_id !== node.last_id) { - node.status({}); - node.last_id = connection_id; - } - clients[connection_id] = clients[connection_id] || { - msgQueue: new Denque(), - connected: false, - connecting: false - }; - enqueue(clients[connection_id].msgQueue, {msg:msg, nodeSend:nodeSend, nodeDone:nodeDone}); - clients[connection_id].lastMsg = msg; - - if (!clients[connection_id].connecting && !clients[connection_id].connected) { - var buf; - if (this.out == "count") { - if (this.splitc === 0) { buf = Buffer.alloc(1); } - else { buf = Buffer.alloc(this.splitc); } - } - else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully - - var connOpts = {host:host, port:port}; - if (n.tls) { - connOpts = tlsNode.addTLSOptions(connOpts); - const allowUnauthorized = getAllowUnauthorized(); - - let options = { - rejectUnauthorized: !allowUnauthorized, - ciphers: tls.DEFAULT_CIPHERS, - checkServerIdentity: tls.checkServerIdentity, - minDHSize: 1024, - ...connOpts - }; - - if (!options.keepAlive) { options.singleUse = true; } - - const context = options.secureContext || tls.createSecureContext(options); - - clients[connection_id].client = new tls.TLSSocket(options.socket, { - allowHalfOpen: options.allowHalfOpen, - pipe: !!options.path, - secureContext: context, - isServer: false, - requestCert: false, // true, - rejectUnauthorized: false, // options.rejectUnauthorized !== false, - session: options.session, - ALPNProtocols: options.ALPNProtocols, - requestOCSP: options.requestOCSP, - enableTrace: options.enableTrace, - pskCallback: options.pskCallback, - highWaterMark: options.highWaterMark, - onread: options.onread, - signal: options.signal, - }); - } - else { - clients[connection_id].client = net.Socket(); - } - if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);} - - if (host && port) { - clients[connection_id].connecting = true; - clients[connection_id].client.connect(connOpts, function() { - //node.log(RED._("tcpin.errors.client-connected")); - node.status({fill:"green",shape:"dot",text:"common.status.connected"}); - if (clients[connection_id] && clients[connection_id].client) { - clients[connection_id].connected = true; - clients[connection_id].connecting = false; - let event; - while (event = dequeue(clients[connection_id].msgQueue)) { - clients[connection_id].client.write(event.msg.payload); - event.nodeDone(); - } - if (node.out === "time" && node.splitc < 0) { - clients[connection_id].connected = clients[connection_id].connecting = false; - clients[connection_id].client.end(); - delete clients[connection_id]; - node.status({}); - } - } - }); - } - else { - node.warn(RED._("tcpin.errors.no-host")); - } - var chunk = ""; - clients[connection_id].client.on('data', function(data) { - if (node.out === "sit") { // if we are staying connected just send the buffer - if (clients[connection_id]) { - const msg = clients[connection_id].lastMsg || {}; - msg.payload = RED.util.cloneMessage(data); - if (node.ret === "string") { - try { - if (node.newline && node.newline !== "" ) { - chunk += msg.payload.toString(); - let parts = chunk.split(node.newline); - for (var p=0; p= node.splitc) { - if (clients[connection_id]) { - const msg = clients[connection_id].lastMsg || {}; - msg.payload = Buffer.alloc(i); - buf.copy(msg.payload,0,0,i); - if (node.ret === "string") { - try { msg.payload = msg.payload.toString(); } - catch(e) { node.error("Failed to create string", msg); } - } - nodeSend(msg); - if (clients[connection_id].client) { - node.status({}); - clients[connection_id].client.destroy(); - delete clients[connection_id]; - } - i = 0; - } - } - } - // look for a char - else { - buf[i] = data[j]; - i += 1; - if (data[j] == node.splitc) { - if (clients[connection_id]) { - const msg = clients[connection_id].lastMsg || {}; - msg.payload = Buffer.alloc(i); - buf.copy(msg.payload,0,0,i); - if (node.ret === "string") { - try { msg.payload = msg.payload.toString(); } - catch(e) { node.error("Failed to create string", msg); } - } - nodeSend(msg); - if (clients[connection_id].client) { - node.status({}); - clients[connection_id].client.destroy(); - delete clients[connection_id]; - } - i = 0; - } - } - } - } - } - }); - - clients[connection_id].client.on('end', function() { - //console.log("END"); - node.status({fill:"grey",shape:"ring",text:"common.status.disconnected"}); - if (clients[connection_id] && clients[connection_id].client) { - clients[connection_id].connected = clients[connection_id].connecting = false; - clients[connection_id].client = null; - } - }); - - clients[connection_id].client.on('close', function() { - //console.log("CLOSE"); - if (clients[connection_id]) { - clients[connection_id].connected = clients[connection_id].connecting = false; - } - - var anyConnected = false; - - for (var client in clients) { - if (clients[client].connected) { - anyConnected = true; - break; - } - } - if (node.doneClose && !anyConnected) { - clients = {}; - node.doneClose(); - } - }); - - clients[connection_id].client.on('error', function() { - //console.log("ERROR"); - node.status({fill:"red",shape:"ring",text:"common.status.error"}); - node.error(RED._("tcpin.errors.connect-fail") + " " + connection_id, msg); - if (clients[connection_id] && clients[connection_id].client) { - clients[connection_id].client.destroy(); - delete clients[connection_id]; - } - }); - - clients[connection_id].client.on('timeout',function() { - //console.log("TIMEOUT"); - if (clients[connection_id]) { - clients[connection_id].connected = clients[connection_id].connecting = false; - node.status({fill:"grey",shape:"dot",text:"tcpin.errors.connect-timeout"}); - //node.warn(RED._("tcpin.errors.connect-timeout")); - if (clients[connection_id].client) { - clients[connection_id].connecting = true; - - var connOpts = {host:host, port:port}; - if (n.tls) { - connOpts = tlsNode.addTLSOptions(connOpts); - } - - clients[connection_id].client.connect(connOpts, function() { - clients[connection_id].connected = true; - clients[connection_id].connecting = false; - node.status({fill:"green",shape:"dot",text:"common.status.connected"}); - }); - } - } - }); - } - else if (!clients[connection_id].connecting && clients[connection_id].connected) { - if (clients[connection_id] && clients[connection_id].client) { - let event = dequeue(clients[connection_id].msgQueue) - clients[connection_id].client.write(event.msg.payload); - event.nodeDone(); - } - } - }); - - this.on("close", function(done) { - node.doneClose = done; - for (var cl in clients) { - if (clients[cl].hasOwnProperty("client")) { - clients[cl].client.destroy(); - } - } - node.status({}); - - // this is probably not necessary and may be removed - var anyConnected = false; - for (var c in clients) { - if (clients[c].connected) { - anyConnected = true; - break; - } - } - if (!anyConnected) { clients = {}; } - done(); - }); - - } - RED.nodes.registerType("tcp request",TcpGet); -} diff --git a/packages/node_modules/@node-red/nodes/core/parsers/70-JSON.js b/packages/node_modules/@node-red/nodes/core/parsers/70-JSON.js deleted file mode 100644 index e16c4ec23..000000000 --- a/packages/node_modules/@node-red/nodes/core/parsers/70-JSON.js +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -module.exports = function(RED) { - "use strict"; - const Ajv = require('ajv'); - const ajv = new Ajv({allErrors: true}); - ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json')); - - function JSONNode(n) { - RED.nodes.createNode(this,n); - this.indent = n.pretty ? 4 : 0; - this.action = n.action||""; - this.property = n.property||"payload"; - this.schema = null; - this.compiledSchema = null; - - var node = this; - - this.on("input", function(msg,send,done) { - var validate = false; - if (msg.schema) { - // If input schema is different, re-compile it - if (JSON.stringify(this.schema) != JSON.stringify(msg.schema)) { - try { - this.compiledSchema = ajv.compile(msg.schema); - this.schema = msg.schema; - } catch(e) { - this.schema = null; - this.compiledSchema = null; - done(RED._("json.errors.schema-error-compile")); - return; - } - } - validate = true; - } - var value = RED.util.getMessageProperty(msg,node.property); - if (value !== undefined) { - if (typeof value === "string" || Buffer.isBuffer(value)) { - // if (Buffer.isBuffer(value) && node.action !== "obj") { - // node.warn(RED._("json.errors.dropped")); done(); - // } - // else - if (node.action === "" || node.action === "obj") { - try { - RED.util.setMessageProperty(msg,node.property,JSON.parse(value)); - if (validate) { - if (this.compiledSchema(msg[node.property])) { - delete msg.schema; - send(msg); - done(); - } else { - msg.schemaError = this.compiledSchema.errors; - done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); - } - } else { - send(msg); - done(); - } - } - catch(e) { done(e.message); } - } else { - // If node.action is str and value is str - if (validate) { - if (this.compiledSchema(JSON.parse(msg[node.property]))) { - delete msg.schema; - send(msg); - done(); - } else { - msg.schemaError = this.compiledSchema.errors; - done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); - } - } else { - send(msg); - done(); - } - } - } - else if ((typeof value === "object") || (typeof value === "boolean") || (typeof value === "number")) { - if (node.action === "" || node.action === "str") { - if (!Buffer.isBuffer(value)) { - try { - if (validate) { - if (this.compiledSchema(value)) { - RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent)); - delete msg.schema; - send(msg); - done(); - } else { - msg.schemaError = this.compiledSchema.errors; - done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); - } - } else { - RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent)); - send(msg); - done(); - } - } - catch(e) { done(RED._("json.errors.dropped-error")); } - } - else { node.warn(RED._("json.errors.dropped-object")); done(); } - } else { - // If node.action is obj and value is object - if (validate) { - if (this.compiledSchema(value)) { - delete msg.schema; - send(msg); - done(); - } else { - msg.schemaError = this.compiledSchema.errors; - done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); - } - } else { - send(msg); - done(); - } - } - } - else { node.warn(RED._("json.errors.dropped")); done(); } - } - else { send(msg); done(); } // If no property - just pass it on. - }); - } - RED.nodes.registerType("json",JSONNode); -} diff --git a/packages/node_modules/@node-red/nodes/icons/guide.svg b/packages/node_modules/@node-red/nodes/icons/guide.svg new file mode 100644 index 000000000..b46237cfb --- /dev/null +++ b/packages/node_modules/@node-red/nodes/icons/guide.svg @@ -0,0 +1 @@ + \ No newline at end of file