diff --git a/public/red/main.js b/public/red/main.js index da315439c..43dd9e030 100644 --- a/public/red/main.js +++ b/public/red/main.js @@ -92,6 +92,14 @@ var RED = function() { node.dirty = true; node.changed = false; } + if(node._creds) { + delete node._creds; + } + }); + RED.nodes.eachConfig(function (confNode) { + if (confNode._creds) { + delete confNode._creds; + } }); // Once deployed, cannot undo back to a clean state RED.history.markAllDirty(); diff --git a/public/red/nodes.js b/public/red/nodes.js index e5df40cf9..a2ea02015 100644 --- a/public/red/nodes.js +++ b/public/red/nodes.js @@ -175,13 +175,17 @@ RED.nodes = function() { /** * Converts a node to an exportable JSON Object **/ - function convertNode(n) { + function convertNode(n, exportCreds) { + exportCreds = exportCreds || false; var node = {}; node.id = n.id; node.type = n.type; for (var d in n._def.defaults) { node[d] = n[d]; } + if(exportCreds && n._creds) { + node._creds = n._creds.send; + } if (n._def.category != "config") { node.x = n.x; node.y = n.y; @@ -235,11 +239,11 @@ RED.nodes = function() { nns.push(workspaces[i]); } for (var i in configNodes) { - nns.push(convertNode(configNodes[i])); + nns.push(convertNode(configNodes[i], true)); } for (var i in nodes) { var node = nodes[i]; - nns.push(convertNode(node)); + nns.push(convertNode(node, true)); } return nns; } diff --git a/public/red/ui/editor.js b/public/red/ui/editor.js index 995102154..1dd7d57b1 100644 --- a/public/red/ui/editor.js +++ b/public/red/ui/editor.js @@ -22,25 +22,40 @@ RED.editor = function() { return 'credentials/' + dashedType + "/" + nodeID; } - function sendCredentials(node,credDefinition,prefix) { - var credentials = {}; + /** + * Assign the credentials to the node + * @param node - the node containing the credentials + * @param credDefinition - definition of the credentials + * @param prefix - prefix of the input fields + */ + function manageNodeCredentials(node, credDefinition, prefix) { + if(!node._creds) { + node._creds = {server: {}, send: {}, input: {}}; + } + for (var cred in credDefinition) { var input = $("#" + prefix + '-' + cred); var value = input.val(); - if (credDefinition[cred].type == 'password' && value == '__PWRD__') { - continue; + if (credDefinition[cred].type == 'password') { + if(value != '') { + node._creds.input['has' + cred] = true; + if (value == '__PWRD__') { + continue; + } + } else { + node._creds.input['has' + cred] = false; + } } - credentials[cred] = value; - } - node._def._creds = credentials; - $.ajax({ - url: getCredentialsURL(node.type, node.id), - type: 'POST', - data: credentials, - success: function (result) { + if (node._creds.server[cred] != value) { + node._creds.send[cred] = value; + } else { + delete node._creds.send[cred]; + } + if (credDefinition[cred].type != 'password') { + node._creds.input[cred] = value; } - }); + } } @@ -222,7 +237,7 @@ RED.editor = function() { if (editing_node._def.credentials) { var prefix = 'node-input'; var credDefinition = editing_node._def.credentials; - sendCredentials(editing_node,credDefinition,prefix); + manageNodeCredentials(editing_node,credDefinition,prefix); } @@ -357,6 +372,32 @@ RED.editor = function() { }); } + /** + * Assign the value to each credential field + * @param node + * @param credDef + * @param credData + * @param prefix + */ + function populateCredentialsInputs(node, credDef, credData, prefix) { + for (var cred in credDef) { + if (credDef[cred].type == 'password') { + if (credData['has' + cred]) { + $('#' + prefix + '-' + cred).val('__PWRD__'); + } + else { + $('#' + prefix + '-' + cred).val(''); + } + } else { + preparePropertyEditor(credData, cred, prefix); + } + attachPropertyChangeHandler(node, credDef, cred, prefix); + for (var cred in credDef) { + $("#" + prefix + "-" + cred).change(); + } + } + } + /** * Prepare all of the editor dialog fields * @param node - the node being edited @@ -373,25 +414,16 @@ RED.editor = function() { attachPropertyChangeHandler(node,definition.defaults,d,prefix); } if (definition.credentials) { - - $.getJSON(getCredentialsURL(node.type, node.id), function (data) { - for (var cred in definition.credentials) { - if (definition.credentials[cred].type == 'password') { - if (data['has' + cred]) { - $('#' + prefix + '-' + cred).val('__PWRD__'); - } - else { - $('#' + prefix + '-' + cred).val(''); - } - } else { - preparePropertyEditor(data, cred, prefix); - } - attachPropertyChangeHandler(node, definition.credentials, cred, prefix); - for (var cred in definition.credentials) { - $("#" + prefix + "-" + cred).change(); - } - } - }); + if (node._creds) { + populateCredentialsInputs(node, definition.credentials, node._creds.input, prefix); + } else { + node._creds = {server: {}, send: {}, input: {}}; + $.getJSON(getCredentialsURL(node.type, node.id), function (data) { + node._creds.server = data; + node._creds.input = jQuery.extend({}, data); + populateCredentialsInputs(node, definition.credentials, node._creds.input, prefix); + }); + } } if (definition.oneditprepare) { definition.oneditprepare.call(node); @@ -449,14 +481,6 @@ RED.editor = function() { var configNode = RED.nodes.node(configId); var configTypeDef = RED.nodes.getType(configType); - if (configTypeDef.credentials) { - $.ajax({ - url: getCredentialsURL(configType, configId), - type: 'DELETE', - success: function (result) { - } - }); - } if (configTypeDef.ondelete) { configTypeDef.ondelete.call(RED.nodes.node(configId)); } @@ -546,7 +570,7 @@ RED.editor = function() { updateConfigNodeSelect(configProperty,configType,configId); } if (configTypeDef.credentials) { - sendCredentials(configNode,configTypeDef.credentials,"node-config-input"); + manageNodeCredentials(configNode,configTypeDef.credentials,"node-config-input"); } if (configTypeDef.oneditsave) { configTypeDef.oneditsave.call(RED.nodes.node(configId)); diff --git a/red/nodes/credentials.js b/red/nodes/credentials.js index a4eb6c9e4..b5bfe6400 100644 --- a/red/nodes/credentials.js +++ b/red/nodes/credentials.js @@ -15,6 +15,7 @@ **/ var util = require("util"); +var when = require("when"); var credentials = {}; var storage = null; @@ -32,40 +33,6 @@ function isRegistered(type) { return getCredDef(type) !== undefined; } -function restPOST(type) { - redApp.post('/credentials/' + type + '/:id', function (req, res) { - var body = ""; - req.on('data', function (chunk) { - body += chunk; - }); - req.on('end', function () { - var nodeType = type; - var nodeID = req.params.id; - - var newCreds = querystring.parse(body); - var credentials = Credentials.get(nodeID) || {}; - var definition = getCredDef(nodeType); - - for (var cred in definition) { - if (definition.hasOwnProperty(cred)) { - if (newCreds[cred] === undefined) { - continue; - } - if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') { - continue; - } - if (newCreds[cred] === '') { - delete credentials[cred]; - } - credentials[cred] = newCreds[cred]; - } - } - Credentials.add(nodeID, credentials); - res.send(200); - }); - }); -} - function restGET(type) { redApp.get('/credentials/' + type + '/:id', function (req, res) { var nodeType = type; @@ -93,14 +60,6 @@ function restGET(type) { }); } -function restDELETE(type) { - redApp.delete('/credentials/' + type + '/:id', function (req, res) { - var nodeID = req.params.id; - - Credentials.delete(nodeID); - res.send(200); - }); -} module.exports = { init: function (_storage) { @@ -148,8 +107,41 @@ module.exports = { register: function (type, definition) { var dashedType = type.replace(/\s+/g, '-'); credentialsDef[dashedType] = definition; - restDELETE(dashedType); restGET(dashedType); - restPOST(dashedType); + }, + /** + * Merge the new credentials with the existings one + * @param nodeID + * @param nodeType + * @param newCreds + */ + merge: function (nodeID, nodeType, newCreds) { + var savedCredentials = Credentials.get(nodeID) || {}; + + if (!isRegistered(nodeType)) { + util.log('Credential Type ' + nodeType + ' is not registered.'); + return; + } + + var definition = getCredDef(nodeType); + for (var cred in definition) { + if (definition.hasOwnProperty(cred)) { + if (newCreds[cred] === undefined) { + continue; + } + if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') { + continue; + } + if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) { + delete savedCredentials[cred]; + continue; + } + savedCredentials[cred] = newCreds[cred]; + } + } + credentials[nodeID] = savedCredentials; + }, + save: function () { + return storage.saveCredentials(credentials); } } diff --git a/red/nodes/flows.js b/red/nodes/flows.js index 747e1b461..870c8ec33 100644 --- a/red/nodes/flows.js +++ b/red/nodes/flows.js @@ -40,7 +40,26 @@ events.on('type-registered',function(type) { } } }); - +var parseCredentials = function (config) { + return when.promise(function (resolve, defect) { + for (var i in config) { + if (config.hasOwnProperty(i)) { + var node = config[i]; + if (!node._creds) { + continue; + } + var type = node.type; + credentials.merge(node.id, type, node._creds); + delete node._creds; + } + } + credentials.save().then(function () { + resolve(config); + }).otherwise(function (err) { + defect(err); + }); + }); +} var parseConfig = function() { var i; @@ -155,13 +174,16 @@ var flowNodes = module.exports = { getFlows: function() { return activeConfig; }, - setFlows: function(conf) { - return storage.saveFlows(conf).then(function() { - return stopFlows().then(function() { - activeConfig = conf; - parseConfig(); - }); - }); + setFlows: function (conf) { + return parseCredentials(conf).then(function (confCredsRemoved) { + return storage.saveFlows(confCredsRemoved).then(function () { + return stopFlows().then(function () { + activeConfig = confCredsRemoved; + parseConfig(); + }); + }) + + }) }, stopFlows: stopFlows };