@node-red/runtime 1.3.3 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/api/nodes.js CHANGED
@@ -272,7 +272,7 @@ var api = module.exports = {
272
272
  } catch(error) {
273
273
  runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
274
274
  error.status = 400;
275
- throw err;
275
+ throw error;
276
276
  }
277
277
  },
278
278
 
@@ -319,7 +319,7 @@ var api = module.exports = {
319
319
  } catch(error) {
320
320
  runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
321
321
  error.status = 400;
322
- throw err;
322
+ throw error;
323
323
  }
324
324
  },
325
325
 
@@ -366,7 +366,7 @@ var api = module.exports = {
366
366
  } catch(error) {
367
367
  runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req);
368
368
  error.status = 400;
369
- throw err;
369
+ throw error;
370
370
  }
371
371
  },
372
372
 
@@ -58,7 +58,7 @@ var api = module.exports = {
58
58
  * @memberof @node-red/runtime_plugins
59
59
  */
60
60
  getPluginConfigs: async function(opts) {
61
- if (/[^a-z\-]/i.test(opts.lang)) {
61
+ if (/[^0-9a-z=\-\*]/i.test(opts.lang)) {
62
62
  throw new Error("Invalid language: "+opts.lang)
63
63
  return;
64
64
  }
package/lib/flows/Flow.js CHANGED
@@ -369,12 +369,12 @@ class Flow {
369
369
  return undefined;
370
370
  }
371
371
  // console.log((new Error().stack).toString().split("\n").slice(1,3).join("\n"))
372
- if ((this.flow.configs && this.flow.configs[id]) || (this.flow.nodes && this.flow.nodes[id])) {
372
+ if ((this.flow.configs && this.flow.configs[id]) || (this.flow.nodes && this.flow.nodes[id] && this.flow.nodes[id].type.substring(0,8) != "subflow:")) {
373
373
  // This is a node owned by this flow, so return whatever we have got
374
374
  // During a stop/restart, activeNodes could be null for this id
375
375
  return this.activeNodes[id];
376
376
  } else if (this.activeNodes[id]) {
377
- // TEMP: this is a subflow internal node within this flow
377
+ // TEMP: this is a subflow internal node within this flow or subflow instance node
378
378
  return this.activeNodes[id];
379
379
  } else if (this.subflowInstanceNodes[id]) {
380
380
  return this.subflowInstanceNodes[id];
@@ -697,7 +697,9 @@ async function updateFlow(id,newFlow, user) {
697
697
 
698
698
  nodes = [tabNode].concat(newFlow.nodes||[]).concat(newFlow.configs||[]);
699
699
  nodes.forEach(function(n) {
700
- n.z = id;
700
+ if (n.type !== 'tab') {
701
+ n.z = id;
702
+ }
701
703
  });
702
704
  }
703
705
 
package/lib/flows/util.js CHANGED
@@ -95,6 +95,9 @@ function createNode(flow,config) {
95
95
  } else if (nodeTypeConstructor) {
96
96
  // console.log(nodeTypeConstructor)
97
97
  var subflowConfig = parseConfig([nodeTypeConstructor.subflow].concat(nodeTypeConstructor.subflow.flow));
98
+ var subflowInstanceConfig = subflowConfig.subflows[nodeTypeConstructor.subflow.id];
99
+ delete subflowConfig.subflows[nodeTypeConstructor.subflow.id];
100
+ subflowInstanceConfig.subflows = subflowConfig.subflows;
98
101
  var instanceConfig = clone(config);
99
102
  instanceConfig.env = clone(nodeTypeConstructor.subflow.env);
100
103
 
@@ -107,7 +110,7 @@ function createNode(flow,config) {
107
110
  switch(typeof config[nodeProp.name]) {
108
111
  case "string": nodePropType = "str"; break;
109
112
  case "number": nodePropType = "num"; break;
110
- case "boolean": nodePropType = "bool"; nodePropValue = nodeProp?"true":"false"; break;
113
+ case "boolean": nodePropType = "bool"; nodePropValue == nodeProp?"true":"false"; break;
111
114
  default:
112
115
  nodePropType = config[nodeProp.name].type;
113
116
  nodePropValue = config[nodeProp.name].value;
@@ -124,7 +127,7 @@ function createNode(flow,config) {
124
127
  nodeTypeConstructor.type,
125
128
  flow,
126
129
  flow.global,
127
- subflowConfig.subflows[nodeTypeConstructor.subflow.id],
130
+ subflowInstanceConfig,
128
131
  instanceConfig
129
132
  );
130
133
  subflow.start();
package/lib/index.js CHANGED
@@ -64,6 +64,27 @@ var server;
64
64
  */
65
65
  function init(userSettings,httpServer,_adminApi) {
66
66
  server = httpServer;
67
+
68
+ if (server && server.on) {
69
+ // Add a listener to the upgrade event so that we can properly timeout connection
70
+ // attempts that do not get handled by any nodes in the user's flow.
71
+ // See #2956
72
+ server.on('upgrade',(request, socket, head) => {
73
+ // Add a no-op handler to the error event in case nothing upgrades this socket
74
+ // before the remote end closes it. This ensures we don't get as uncaughtException
75
+ socket.on("error", err => {})
76
+ setTimeout(function() {
77
+ // If this request has been handled elsewhere, the upgrade will have
78
+ // been completed and bytes written back to the client.
79
+ // If nothing has been written on the socket, nothing has handled the
80
+ // upgrade, so we can consider this an unhandled upgrade.
81
+ if (socket.bytesWritten === 0) {
82
+ socket.destroy();
83
+ }
84
+ },userSettings.inboundWebSocketTimeout || 5000)
85
+ });
86
+ }
87
+
67
88
  userSettings.version = getVersion();
68
89
  settings.init(userSettings);
69
90
 
@@ -197,7 +218,7 @@ var reinstallTimeout;
197
218
  function reinstallModules(moduleList) {
198
219
  const promises = [];
199
220
  const reinstallList = [];
200
- const installRetry = 30000;
221
+ var installRetry = 30000;
201
222
  if (settings.hasOwnProperty('autoInstallModulesRetry')) {
202
223
  log.warn(log._("server.deprecatedOption",{old:"autoInstallModulesRetry", new:"externalModules.autoInstallRetry"}));
203
224
  installRetry = settings.autoInstallModulesRetry;
@@ -215,6 +215,22 @@ function followParentContext(parent, key) {
215
215
  return null;
216
216
  }
217
217
 
218
+ function validateContextKey(key) {
219
+ try {
220
+ const keys = Array.isArray(key) ? key : [key];
221
+ if(!keys.length) { return false }; //no key to get/set
222
+ for (let index = 0; index < keys.length; index++) {
223
+ const k = keys[index];
224
+ if (typeof k !== "string" || !k.length) {
225
+ return false; //not string or zero-length
226
+ }
227
+ }
228
+ } catch (error) {
229
+ return false;
230
+ }
231
+ return true;
232
+ }
233
+
218
234
  function createContext(id,seed,parent) {
219
235
  // Seed is only set for global context - sourced from functionGlobalContext
220
236
  var scope = id;
@@ -251,11 +267,11 @@ function createContext(id,seed,parent) {
251
267
  }
252
268
  }
253
269
  }
270
+
254
271
  Object.defineProperties(obj, {
255
272
  get: {
256
273
  value: function(key, storage, callback) {
257
274
  var context;
258
-
259
275
  if (!callback && typeof storage === 'function') {
260
276
  callback = storage;
261
277
  storage = undefined;
@@ -263,7 +279,14 @@ function createContext(id,seed,parent) {
263
279
  if (callback && typeof callback !== 'function'){
264
280
  throw new Error("Callback must be a function");
265
281
  }
266
-
282
+ if (!validateContextKey(key)) {
283
+ var err = Error("Invalid context key");
284
+ if(callback) {
285
+ return callback(err);
286
+ } else {
287
+ throw err;
288
+ }
289
+ }
267
290
  if (!Array.isArray(key)) {
268
291
  var keyParts = util.parseContextStore(key);
269
292
  key = keyParts.key;
@@ -337,7 +360,6 @@ function createContext(id,seed,parent) {
337
360
  set: {
338
361
  value: function(key, value, storage, callback) {
339
362
  var context;
340
-
341
363
  if (!callback && typeof storage === 'function') {
342
364
  callback = storage;
343
365
  storage = undefined;
@@ -345,7 +367,14 @@ function createContext(id,seed,parent) {
345
367
  if (callback && typeof callback !== 'function'){
346
368
  throw new Error("Callback must be a function");
347
369
  }
348
-
370
+ if (!validateContextKey(key)) {
371
+ var err = Error("Invalid context key");
372
+ if(callback) {
373
+ return callback(err);
374
+ } else {
375
+ throw err;
376
+ }
377
+ }
349
378
  if (!Array.isArray(key)) {
350
379
  var keyParts = util.parseContextStore(key);
351
380
  key = keyParts.key;
@@ -343,7 +343,11 @@ var api = module.exports = {
343
343
  if (newCreds) {
344
344
  delete node.credentials;
345
345
  var savedCredentials = credentialCache[nodeID] || {};
346
- if (/^subflow(:|$)/.test(nodeType)) {
346
+ // Need to check the type of constructor for this node.
347
+ // - Function : regular node
348
+ // - !Function: subflow module
349
+
350
+ if (/^subflow(:|$)/.test(nodeType) || typeof runtime.nodes.getType(nodeType) !== 'function') {
347
351
  for (cred in newCreds) {
348
352
  if (newCreds.hasOwnProperty(cred)) {
349
353
  if (newCreds[cred] === "__PWRD__") {
@@ -291,7 +291,7 @@ function parseLog(log) {
291
291
  currentCommit = {}
292
292
  return;
293
293
  }
294
- var m = /^(.*): (.*)$/.exec(l);
294
+ var m = /^(.*?): (.*)$/.exec(l);
295
295
  if (m) {
296
296
  // git 2.1.4 (Debian Stable) doesn't support %D for refs - so filter out
297
297
  if (m[1] === 'refs' && m[2]) {
@@ -608,8 +608,15 @@ async function saveFlows(flows, user) {
608
608
  var workflowMode = (gitSettings.workflow||{}).mode || settings.editorTheme.projects.workflow.mode;
609
609
  if (workflowMode === 'auto') {
610
610
  return activeProject.stageFile([flowsFullPath, credentialsFile]).then(() => {
611
- return activeProject.commit(user,{message:"Update flow files"})
612
- })
611
+ return activeProject.status(user, false).then((result) => {
612
+ const items = Object.values(result.files || {});
613
+ // check if saved flow make modification to repository
614
+ if (items.findIndex((item) => (item.status === "M ")) < 0) {
615
+ return Promise.resolve();
616
+ }
617
+ return activeProject.commit(user,{message:"Update flow files"})
618
+ });
619
+ });
613
620
  }
614
621
  }
615
622
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/runtime",
3
- "version": "1.3.3",
3
+ "version": "1.3.7",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./lib/index.js",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  }
17
17
  ],
18
18
  "dependencies": {
19
- "@node-red/registry": "1.3.3",
20
- "@node-red/util": "1.3.3",
19
+ "@node-red/registry": "1.3.7",
20
+ "@node-red/util": "1.3.7",
21
21
  "async-mutex": "0.3.1",
22
22
  "clone": "2.1.2",
23
23
  "express": "4.17.1",