From 7df1a03b4b348fdbbba2336d7cfadda2a2485f76 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 28 Apr 2021 21:49:32 +0100 Subject: [PATCH] Handle subflow modules that contain subflows --- .../@node-red/runtime/lib/flows/util.js | 5 +- .../runtime/lib/nodes/credentials.js | 6 +- .../runtime/lib/nodes/credentials_spec.js | 87 +++++++++---------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/packages/node_modules/@node-red/runtime/lib/flows/util.js b/packages/node_modules/@node-red/runtime/lib/flows/util.js index edb348ac4..79c70fb02 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/util.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/util.js @@ -95,6 +95,9 @@ function createNode(flow,config) { } else if (nodeTypeConstructor) { // console.log(nodeTypeConstructor) var subflowConfig = parseConfig([nodeTypeConstructor.subflow].concat(nodeTypeConstructor.subflow.flow)); + var subflowInstanceConfig = subflowConfig.subflows[nodeTypeConstructor.subflow.id]; + delete subflowConfig.subflows[nodeTypeConstructor.subflow.id]; + subflowInstanceConfig.subflows = subflowConfig.subflows; var instanceConfig = clone(config); instanceConfig.env = clone(nodeTypeConstructor.subflow.env); @@ -124,7 +127,7 @@ function createNode(flow,config) { nodeTypeConstructor.type, flow, flow.global, - subflowConfig.subflows[nodeTypeConstructor.subflow.id], + subflowInstanceConfig, instanceConfig ); subflow.start(); diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js b/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js index 86ea1d3a1..30b2ccdb0 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js @@ -343,7 +343,11 @@ var api = module.exports = { if (newCreds) { delete node.credentials; var savedCredentials = credentialCache[nodeID] || {}; - if (/^subflow(:|$)/.test(nodeType)) { + // Need to check the type of constructor for this node. + // - Function : regular node + // - !Function: subflow module + + if (/^subflow(:|$)/.test(nodeType) || typeof runtime.nodes.getType(nodeType) !== 'function') { for (cred in newCreds) { if (newCreds.hasOwnProperty(cred)) { if (newCreds[cred] === "__PWRD__") { diff --git a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js b/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js index 5e4bc8094..6db0b867b 100644 --- a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js +++ b/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js @@ -36,102 +36,96 @@ describe('red/runtime/nodes/credentials', function() { index.clearRegistry(); }); - it('loads provided credentials',function(done) { + it('loads provided credentials',function() { credentials.init({ log: log, settings: encryptionDisabledSettings }); - credentials.load({"a":{"b":1,"c":2}}).then(function() { - + return credentials.load({"a":{"b":1,"c":2}}).then(function() { credentials.get("a").should.have.property('b',1); credentials.get("a").should.have.property('c',2); - - done(); }); }); - it('adds a new credential',function(done) { + it('adds a new credential',function() { credentials.init({ log: log, settings: encryptionDisabledSettings }); - credentials.load({"a":{"b":1,"c":2}}).then(function() { + return credentials.load({"a":{"b":1,"c":2}}).then(function() { credentials.dirty().should.be.false(); should.not.exist(credentials.get("b")); - credentials.add("b",{"foo":"bar"}).then(function() { + return credentials.add("b",{"foo":"bar"}).then(function() { credentials.get("b").should.have.property("foo","bar"); credentials.dirty().should.be.true(); - done(); }); }); }); - it('deletes an existing credential',function(done) { + it('deletes an existing credential',function() { credentials.init({ log: log, settings: encryptionDisabledSettings }); - credentials.load({"a":{"b":1,"c":2}}).then(function() { + return credentials.load({"a":{"b":1,"c":2}}).then(function() { credentials.dirty().should.be.false(); credentials.delete("a"); should.not.exist(credentials.get("a")); credentials.dirty().should.be.true(); - done(); }); }); - it('exports the credentials, clearing dirty flag', function(done) { + it('exports the credentials, clearing dirty flag', function() { credentials.init({ log: log, settings: encryptionDisabledSettings }); var creds = {"a":{"b":1,"c":2}}; - credentials.load(creds).then(function() { - credentials.add("b",{"foo":"bar"}).then(function() { - credentials.dirty().should.be.true(); - credentials.export().then(function(exported) { - exported.should.eql(creds); - credentials.dirty().should.be.false(); - done(); - }) - }); + return credentials.load(creds).then(function() { + return credentials.add("b",{"foo":"bar"}) + }).then(function() { + credentials.dirty().should.be.true(); + return credentials.export().then(function(exported) { + exported.should.eql(creds); + credentials.dirty().should.be.false(); + }) }); }) describe("#clean",function() { - it("removes credentials of unknown nodes",function(done) { + it("removes credentials of unknown nodes",function() { credentials.init({ log: log, - settings: encryptionDisabledSettings + settings: encryptionDisabledSettings, + nodes: { getType: () => function(){} } }); var creds = {"a":{"b":1,"c":2},"b":{"d":3}}; - credentials.load(creds).then(function() { + return credentials.load(creds).then(function() { credentials.dirty().should.be.false(); should.exist(credentials.get("a")); should.exist(credentials.get("b")); - credentials.clean([{id:"b"}]).then(function() { + return credentials.clean([{id:"b"}]).then(function() { credentials.dirty().should.be.true(); should.not.exist(credentials.get("a")); should.exist(credentials.get("b")); - done(); }); }); }); - it("extracts credentials of known nodes",function(done) { + it("extracts credentials of known nodes",function() { credentials.init({ log: log, - settings: encryptionDisabledSettings + settings: encryptionDisabledSettings, + nodes: { getType: () => function(){} } }); credentials.register("testNode",{"b":"text","c":"password"}) var creds = {"a":{"b":1,"c":2}}; var newConfig = [{id:"a",type:"testNode",credentials:{"b":"newBValue","c":"newCValue"}}]; - credentials.load(creds).then(function() { + return credentials.load(creds).then(function() { credentials.dirty().should.be.false(); - credentials.clean(newConfig).then(function() { + return credentials.clean(newConfig).then(function() { credentials.dirty().should.be.true(); credentials.get("a").should.have.property('b',"newBValue"); credentials.get("a").should.have.property('c',"newCValue"); should.not.exist(newConfig[0].credentials); - done(); }); }); }); @@ -139,12 +133,13 @@ describe('red/runtime/nodes/credentials', function() { }); - it('warns if a node has no credential definition', function(done) { + it('warns if a node has no credential definition', function() { credentials.init({ log: log, - settings: encryptionDisabledSettings + settings: encryptionDisabledSettings, + nodes: { getType: () => function(){} } }); - credentials.load({}).then(function() { + return credentials.load({}).then(function() { var node = {id:"node",type:"test",credentials:{ user1:"newUser", password1:"newPassword" @@ -154,14 +149,14 @@ describe('red/runtime/nodes/credentials', function() { log.warn.called.should.be.true(); should.not.exist(node.credentials); log.warn.restore(); - done(); }); }) it('extract credential updates in the provided node', function(done) { credentials.init({ log: log, - settings: encryptionDisabledSettings + settings: encryptionDisabledSettings, + nodes: { getType: () => function(){} } }); var defintion = { user1:{type:"text"}, @@ -205,7 +200,8 @@ describe('red/runtime/nodes/credentials', function() { it('extract ignores node without credentials', function(done) { credentials.init({ log: log, - settings: encryptionDisabledSettings + settings: encryptionDisabledSettings, + nodes: { getType: () => function(){} } }); credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() { var node = {id:"node",type:"test"}; @@ -233,7 +229,8 @@ describe('red/runtime/nodes/credentials', function() { delete settings[key]; return Promise.resolve(); } - } + }, + nodes: { getType: () => function(){} } } it('migrates to encrypted and generates default key', function(done) { settings = {}; @@ -341,7 +338,7 @@ describe('red/runtime/nodes/credentials', function() { }); }); }); - it('migrates from default key to user key', function(done) { + it('migrates from default key to user key', function() { settings = { _credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a", credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee" @@ -349,21 +346,20 @@ describe('red/runtime/nodes/credentials', function() { // {"node":{user1:"abc",password1:"123"}} var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"}; credentials.init(runtime); - credentials.load(cryptedFlows).then(function() { + return credentials.load(cryptedFlows).then(function() { credentials.dirty().should.be.true(); should.exist(credentials.get("node")); - credentials.export().then(function(result) { + return credentials.export().then(function(result) { result.should.have.a.property("$"); settings.should.not.have.a.property("_credentialSecret"); // reset everything - but with _credentialSecret still set credentials.init(runtime); // load the freshly encrypted version - credentials.load(result).then(function() { + return credentials.load(result).then(function() { should.exist(credentials.get("node")); credentials.get("node").should.have.a.property("user1","abc"); credentials.get("node").should.have.a.property("password1","123"); - done(); }) }); }); @@ -459,7 +455,8 @@ describe('red/runtime/nodes/credentials', function() { set: function(key,value) { throw new Error(); } - } + }, + nodes: { getType: () => function(){} } } // {"node":{user1:"abc",password1:"123"}} credentials.init(runtime);