mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Rewrite credentials API to work with save on deploy.
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user