/** * Copyright 2014 IBM Corp. * * 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. **/ var util = require("util"); var when = require("when"); var credentialCache = {}; var storage = null; var credentialsDef = {}; var redApp = null; /** * Adds an HTTP endpoint to allow look up of credentials for a given node id. */ function registerEndpoint(type) { redApp.get('/credentials/' + type + '/:id', function (req, res) { // TODO: This could be a generic endpoint with the type value // parameterised. // // TODO: It should verify the given node id is of the type specified - // but that would add a dependency from this module to the // registry module that knows about node types. var nodeType = type; var nodeID = req.params.id; var credentials = credentialCache[nodeID]; if (credentials === undefined) { res.json({}); return; } var definition = credentialsDef[nodeType]; var sendCredentials = {}; for (var cred in definition) { if (definition.hasOwnProperty(cred)) { if (definition[cred].type == "password") { var key = 'has_' + cred; sendCredentials[key] = credentials[cred] != null && credentials[cred] !== ''; continue; } sendCredentials[cred] = credentials[cred] || ''; } } res.json(sendCredentials); }); } module.exports = { init: function (_storage) { storage = _storage; // TODO: this should get passed in init function call rather than // required directly. redApp = require("../server").app; }, /** * Loads the credentials from storage. */ load: function () { return storage.getCredentials().then(function (creds) { credentialCache = creds; }).otherwise(function (err) { util.log("[red] Error loading credentials : " + err); }); }, /** * Adds a set of credentials for the given node id. * @param id the node id for the credentials * @param creds an object of credential key/value pairs * @return a promise for the saving of credentials to storage */ add: function (id, creds) { credentialCache[id] = creds; return storage.saveCredentials(credentialCache); }, /** * Gets the credentials for the given node id. * @param id the node id for the credentials * @return the credentials */ get: function (id) { return credentialCache[id]; }, /** * Deletes the credentials for the given node id. * @param id the node id for the credentials * @return a promise for the saving of credentials to storage */ delete: function (id) { delete credentialCache[id]; storage.saveCredentials(credentialCache); }, /** * Deletes any credentials for nodes that no longer exist * @param getNode a function that can return a node for a given id * @return a promise for the saving of credentials to storage */ clean: function (getNode) { var deletedCredentials = false; for (var c in credentialCache) { if (credentialCache.hasOwnProperty(c)) { var n = getNode(c); if (!n) { deletedCredentials = true; delete credentialCache[c]; } } } if (deletedCredentials) { return storage.saveCredentials(credentialCache); } else { return when.resolve(); } }, /** * Registers a node credential definition. * @param type the node type * @param definition the credential definition */ register: function (type, definition) { var dashedType = type.replace(/\s+/g, '-'); credentialsDef[dashedType] = definition; registerEndpoint(dashedType); }, /** * Extracts and stores any credential updates in the provided node. * The provided node may have a .credentials property that contains * new credentials for the node. * This function loops through the credentials in the definition for * the node-type and applies any of the updates provided in the node. * * This function does not save the credentials to disk as it is expected * to be called multiple times when a new flow is deployed. * * @param node the node to extract credentials from */ extract: function(node) { var nodeID = node.id; var nodeType = node.type; var newCreds = node.credentials; if (newCreds) { var savedCredentials = credentialCache[nodeID] || {}; var dashedType = nodeType.replace(/\s+/g, '-'); var definition = credentialsDef[dashedType]; if (!definition) { util.log('Credential Type ' + nodeType + ' is not registered.'); return; } 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]; } } credentialCache[nodeID] = savedCredentials; } }, /** * Saves the credentials to storage * @return a promise for the saving of credentials to storage */ save: function () { return storage.saveCredentials(credentialCache); } }