mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	WIP: create new runtime-api
This commit is contained in:
		
							
								
								
									
										17
									
								
								jsdoc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								jsdoc.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| { | ||||
|     "tags": { | ||||
|         "allowUnknownTags": false, | ||||
|         "dictionaries": ["jsdoc"] | ||||
|     }, | ||||
|     "source": { | ||||
|         "include": [ | ||||
|             "./red/runtime-api" | ||||
|         ] | ||||
|     }, | ||||
|     "templates": { | ||||
|         "systemName": "Node-RED Runtime API", | ||||
|         "theme":"yeti", | ||||
|         "footer": "", | ||||
|         "copyright": "Released under the Apache License v2.0" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										226
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,115 +1,119 @@ | ||||
| { | ||||
|   "name": "node-red", | ||||
|   "version": "0.18.4", | ||||
|   "description": "A visual tool for wiring the Internet of Things", | ||||
|   "homepage": "http://nodered.org", | ||||
|   "license": "Apache-2.0", | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "https://github.com/node-red/node-red.git" | ||||
|   }, | ||||
|   "main": "red/red.js", | ||||
|   "scripts": { | ||||
|     "start": "node red.js", | ||||
|     "test": "grunt", | ||||
|     "build": "grunt build" | ||||
|   }, | ||||
|   "bin": { | ||||
|     "node-red": "./red.js", | ||||
|     "node-red-pi": "bin/node-red-pi" | ||||
|   }, | ||||
|   "contributors": [ | ||||
|     { | ||||
|       "name": "Nick O'Leary" | ||||
|     "name": "node-red", | ||||
|     "version": "0.18.4", | ||||
|     "description": "A visual tool for wiring the Internet of Things", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|         "url": "https://github.com/node-red/node-red.git" | ||||
|     }, | ||||
|     { | ||||
|       "name": "Dave Conway-Jones" | ||||
|     "main": "red/red.js", | ||||
|     "scripts": { | ||||
|         "start": "node red.js", | ||||
|         "test": "grunt", | ||||
|         "build": "grunt build", | ||||
|         "doc": "jsdoc --pedantic --recurse -c jsdoc.json -t ./node_modules/ink-docstrap/template" | ||||
|     }, | ||||
|     "bin": { | ||||
|         "node-red": "./red.js", | ||||
|         "node-red-pi": "bin/node-red-pi" | ||||
|     }, | ||||
|     "contributors": [ | ||||
|         { | ||||
|             "name": "Nick O'Leary" | ||||
|         }, | ||||
|         { | ||||
|             "name": "Dave Conway-Jones" | ||||
|         } | ||||
|     ], | ||||
|     "keywords": [ | ||||
|         "editor", | ||||
|         "messaging", | ||||
|         "iot", | ||||
|         "flow" | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "basic-auth": "2.0.0", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.18.2", | ||||
|         "cheerio": "0.22.0", | ||||
|         "clone": "2.1.1", | ||||
|         "cookie": "0.3.1", | ||||
|         "cookie-parser": "1.4.3", | ||||
|         "cors": "2.8.4", | ||||
|         "cron": "1.3.0", | ||||
|         "express": "4.16.2", | ||||
|         "express-session": "1.15.6", | ||||
|         "follow-redirects": "1.3.0", | ||||
|         "fs-extra": "5.0.0", | ||||
|         "fs.notify": "0.0.4", | ||||
|         "hash-sum": "1.0.2", | ||||
|         "i18next": "1.10.6", | ||||
|         "ink-docstrap": "^1.3.2", | ||||
|         "is-utf8": "0.2.1", | ||||
|         "js-yaml": "3.10.0", | ||||
|         "json-stringify-safe": "5.0.1", | ||||
|         "jsonata": "1.5.0", | ||||
|         "media-typer": "0.3.0", | ||||
|         "memorystore": "1.6.0", | ||||
|         "mime": "1.4.1", | ||||
|         "mqtt": "2.15.1", | ||||
|         "multer": "1.3.0", | ||||
|         "mustache": "2.3.0", | ||||
|         "node-red-node-email": "0.1.*", | ||||
|         "node-red-node-feedparser": "0.1.*", | ||||
|         "node-red-node-rbe": "0.2.*", | ||||
|         "node-red-node-twitter": "0.1.*", | ||||
|         "nopt": "4.0.1", | ||||
|         "oauth2orize": "1.11.0", | ||||
|         "on-headers": "1.0.1", | ||||
|         "passport": "0.4.0", | ||||
|         "passport-http-bearer": "1.0.1", | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "raw-body": "2.3.2", | ||||
|         "semver": "5.4.1", | ||||
|         "sentiment": "2.1.0", | ||||
|         "uglify-js": "3.3.6", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "1.1.5", | ||||
|         "xml2js": "0.4.19" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "~1.0.3" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "chromedriver": "^2.33.2", | ||||
|         "grunt": "~1.0.1", | ||||
|         "grunt-chmod": "~1.1.1", | ||||
|         "grunt-cli": "~1.2.0", | ||||
|         "grunt-concurrent": "~2.3.1", | ||||
|         "grunt-contrib-clean": "~1.1.0", | ||||
|         "grunt-contrib-compress": "~1.4.0", | ||||
|         "grunt-contrib-concat": "~1.0.1", | ||||
|         "grunt-contrib-copy": "~1.0.0", | ||||
|         "grunt-contrib-jshint": "~1.1.0", | ||||
|         "grunt-contrib-uglify": "~3.3.0", | ||||
|         "grunt-contrib-watch": "~1.0.0", | ||||
|         "grunt-jsonlint": "~1.1.0", | ||||
|         "grunt-mocha-istanbul": "5.0.2", | ||||
|         "grunt-nodemon": "~0.4.2", | ||||
|         "grunt-sass": "~2.0.0", | ||||
|         "grunt-simple-mocha": "~0.4.1", | ||||
|         "grunt-webdriver": "^2.0.3", | ||||
|         "istanbul": "0.4.5", | ||||
|         "jsdoc": "3.5.5", | ||||
|         "mocha": "^5.1.1", | ||||
|         "should": "^8.4.0", | ||||
|         "sinon": "1.17.7", | ||||
|         "stoppable": "^1.0.6", | ||||
|         "supertest": "3.0.0", | ||||
|         "wdio-chromedriver-service": "^0.1.1", | ||||
|         "wdio-mocha-framework": "^0.5.11", | ||||
|         "wdio-spec-reporter": "^0.1.3", | ||||
|         "webdriverio": "^4.9.11" | ||||
|     }, | ||||
|     "engines": { | ||||
|         "node": ">=4" | ||||
|     } | ||||
|   ], | ||||
|   "keywords": [ | ||||
|     "editor", | ||||
|     "messaging", | ||||
|     "iot", | ||||
|     "flow" | ||||
|   ], | ||||
|   "dependencies": { | ||||
|     "basic-auth": "2.0.0", | ||||
|     "bcryptjs": "2.4.3", | ||||
|     "body-parser": "1.18.2", | ||||
|     "cheerio": "0.22.0", | ||||
|     "clone": "2.1.1", | ||||
|     "cookie": "0.3.1", | ||||
|     "cookie-parser": "1.4.3", | ||||
|     "cors": "2.8.4", | ||||
|     "cron": "1.3.0", | ||||
|     "express": "4.16.2", | ||||
|     "express-session": "1.15.6", | ||||
|     "follow-redirects": "1.3.0", | ||||
|     "fs-extra": "5.0.0", | ||||
|     "fs.notify": "0.0.4", | ||||
|     "hash-sum": "1.0.2", | ||||
|     "i18next": "1.10.6", | ||||
|     "is-utf8": "0.2.1", | ||||
|     "js-yaml": "3.10.0", | ||||
|     "json-stringify-safe": "5.0.1", | ||||
|     "jsonata": "1.5.0", | ||||
|     "media-typer": "0.3.0", | ||||
|     "memorystore": "1.6.0", | ||||
|     "mqtt": "2.15.1", | ||||
|     "multer": "1.3.0", | ||||
|     "mustache": "2.3.0", | ||||
|     "node-red-node-email": "0.1.*", | ||||
|     "node-red-node-feedparser": "0.1.*", | ||||
|     "node-red-node-rbe": "0.2.*", | ||||
|     "node-red-node-twitter": "0.1.*", | ||||
|     "nopt": "4.0.1", | ||||
|     "oauth2orize": "1.11.0", | ||||
|     "on-headers": "1.0.1", | ||||
|     "passport": "0.4.0", | ||||
|     "passport-http-bearer": "1.0.1", | ||||
|     "passport-oauth2-client-password": "0.1.2", | ||||
|     "raw-body": "2.3.2", | ||||
|     "semver": "5.4.1", | ||||
|     "sentiment": "2.1.0", | ||||
|     "uglify-js": "3.3.6", | ||||
|     "when": "3.7.8", | ||||
|     "ws": "1.1.5", | ||||
|     "xml2js": "0.4.19" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "bcrypt": "~1.0.3" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "chromedriver": "^2.33.2", | ||||
|     "grunt": "~1.0.1", | ||||
|     "grunt-chmod": "~1.1.1", | ||||
|     "grunt-cli": "~1.2.0", | ||||
|     "grunt-concurrent": "~2.3.1", | ||||
|     "grunt-contrib-clean": "~1.1.0", | ||||
|     "grunt-contrib-compress": "~1.4.0", | ||||
|     "grunt-contrib-concat": "~1.0.1", | ||||
|     "grunt-contrib-copy": "~1.0.0", | ||||
|     "grunt-contrib-jshint": "~1.1.0", | ||||
|     "grunt-contrib-uglify": "~3.3.0", | ||||
|     "grunt-contrib-watch": "~1.0.0", | ||||
|     "grunt-jsonlint": "~1.1.0", | ||||
|     "grunt-mocha-istanbul": "5.0.2", | ||||
|     "grunt-nodemon": "~0.4.2", | ||||
|     "grunt-sass": "~2.0.0", | ||||
|     "grunt-simple-mocha": "~0.4.1", | ||||
|     "grunt-webdriver": "^2.0.3", | ||||
|     "istanbul": "0.4.5", | ||||
|     "mocha": "^5.1.1", | ||||
|     "should": "^8.4.0", | ||||
|     "sinon": "1.17.7", | ||||
|     "stoppable": "^1.0.6", | ||||
|     "supertest": "3.0.0", | ||||
|     "wdio-chromedriver-service": "^0.1.1", | ||||
|     "wdio-mocha-framework": "^0.5.11", | ||||
|     "wdio-spec-reporter": "^0.1.3", | ||||
|     "webdriverio": "^4.9.11" | ||||
|   }, | ||||
|   "engines": { | ||||
|     "node": ">=4" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -14,72 +14,56 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| var log; | ||||
| var redNodes; | ||||
| var runtimeAPI; | ||||
| var apiUtils = require("../util"); | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         redNodes = runtime.nodes; | ||||
|         log = runtime.log; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|     }, | ||||
|     get: function(req,res) { | ||||
|         var id = req.params.id; | ||||
|         var flow = redNodes.getFlow(id); | ||||
|         if (flow) { | ||||
|             log.audit({event: "flow.get",id:id},req); | ||||
|             res.json(flow); | ||||
|         } else { | ||||
|             log.audit({event: "flow.get",id:id,error:"not_found"},req); | ||||
|             res.status(404).end(); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id | ||||
|         } | ||||
|         runtimeAPI.flows.getFlow(opts).then(function(result) { | ||||
|             return res.json(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|     post: function(req,res) { | ||||
|         var flow = req.body; | ||||
|         redNodes.addFlow(flow).then(function(id) { | ||||
|             log.audit({event: "flow.add",id:id},req); | ||||
|             res.json({id:id}); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             flow: req.body | ||||
|         } | ||||
|         runtimeAPI.flows.addFlow(opts).then(function(id) { | ||||
|             return res.json({id:id}); | ||||
|         }).catch(function(err) { | ||||
|             log.audit({event: "flow.add",error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|             res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|  | ||||
|     }, | ||||
|     put: function(req,res) { | ||||
|         var id = req.params.id; | ||||
|         var flow = req.body; | ||||
|         try { | ||||
|             redNodes.updateFlow(id,flow).then(function() { | ||||
|                 log.audit({event: "flow.update",id:id},req); | ||||
|                 res.json({id:id}); | ||||
|             }).catch(function(err) { | ||||
|                 log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             }) | ||||
|         } catch(err) { | ||||
|             if (err.code === 404) { | ||||
|                 log.audit({event: "flow.update",id:id,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } else { | ||||
|                 log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             } | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id, | ||||
|             flow: req.body | ||||
|         } | ||||
|         runtimeAPI.flows.updateFlow(opts).then(function(id) { | ||||
|             return res.json({id:id}); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|     delete: function(req,res) { | ||||
|         var id = req.params.id; | ||||
|         try { | ||||
|             redNodes.removeFlow(id).then(function() { | ||||
|                 log.audit({event: "flow.remove",id:id},req); | ||||
|                 res.status(204).end(); | ||||
|             }) | ||||
|         } catch(err) { | ||||
|             if (err.code === 404) { | ||||
|                 log.audit({event: "flow.remove",id:id,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } else { | ||||
|                 log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             } | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params.id | ||||
|         } | ||||
|         runtimeAPI.flows.deleteFlow(opts).then(function() { | ||||
|             res.status(204).end(); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,72 +14,56 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| var log; | ||||
| var redNodes; | ||||
| var runtimeAPI; | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         redNodes = runtime.nodes; | ||||
|         log = runtime.log; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|     }, | ||||
|     get: function(req,res) { | ||||
|         var version = req.get("Node-RED-API-Version")||"v1"; | ||||
|         if (version === "v1") { | ||||
|             log.audit({event: "flows.get",version:"v1"},req); | ||||
|             res.json(redNodes.getFlows().flows); | ||||
|         } else if (version === "v2") { | ||||
|             log.audit({event: "flows.get",version:"v2"},req); | ||||
|             res.json(redNodes.getFlows()); | ||||
|         } else { | ||||
|             log.audit({event: "flows.get",version:version,error:"invalid_api_version"},req); | ||||
|             res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"}); | ||||
|         if (!/^v[12]$/.test(version)) { | ||||
|             return res.status(500).json({code:"invalid_api_version", message:"Invalid API Version requested"}); | ||||
|         } | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|         } | ||||
|         runtimeAPI.flows.getFlows(opts).then(function(result) { | ||||
|             if (version === "v1") { | ||||
|                 res.json(result.flows); | ||||
|             } else if (version === "v2") { | ||||
|                 res.json(result); | ||||
|             } | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|     post: function(req,res) { | ||||
|         var version = req.get("Node-RED-API-Version")||"v1"; | ||||
|         if (!/^v[12]$/.test(version)) { | ||||
|             log.audit({event: "flows.set",version:version,error:"invalid_api_version"},req); | ||||
|             res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"}); | ||||
|             return; | ||||
|             return res.status(500).json({code:"invalid_api_version", message:"Invalid API Version requested"}); | ||||
|         } | ||||
|         var flows = req.body; | ||||
|         var deploymentType = req.get("Node-RED-Deployment-Type")||"full"; | ||||
|         log.audit({event: "flows.set",type:deploymentType,version:version},req); | ||||
|         if (deploymentType === 'reload') { | ||||
|             redNodes.loadFlows().then(function(flowId) { | ||||
|                 if (version === "v1") { | ||||
|                     res.status(204).end(); | ||||
|                 } else { | ||||
|                     res.json({rev:flowId}); | ||||
|                 } | ||||
|             }).catch(function(err) { | ||||
|                 log.warn(log._("api.flows.error-reload",{message:err.message})); | ||||
|                 log.warn(err.stack); | ||||
|                 res.status(500).json({error:"unexpected_error", message:err.message}); | ||||
|             }); | ||||
|         } else { | ||||
|             var flowConfig = flows; | ||||
|             if (version === "v2") { | ||||
|                 flowConfig = flows.flows; | ||||
|                 if (flows.hasOwnProperty('rev')) { | ||||
|                     var currentVersion = redNodes.getFlows().rev; | ||||
|                     if (currentVersion !== flows.rev) { | ||||
|                         //TODO: log warning | ||||
|                         return res.status(409).json({code:"version_mismatch"}); | ||||
|                     } | ||||
|                 } | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             deploymentType: req.get("Node-RED-Deployment-Type")||"full" | ||||
|         } | ||||
|  | ||||
|         if (opts.deploymentType !== 'reload') { | ||||
|             if (version === "v1") { | ||||
|                 opts.flows = {flows: req.body} | ||||
|             } else { | ||||
|                 opts.flows = req.body; | ||||
|             } | ||||
|             redNodes.setFlows(flowConfig,deploymentType).then(function(flowId) { | ||||
|                 if (version === "v1") { | ||||
|                     res.status(204).end(); | ||||
|                 } else if (version === "v2") { | ||||
|                     res.json({rev:flowId}); | ||||
|                 } | ||||
|             }).catch(function(err) { | ||||
|                 log.warn(log._("api.flows.error-save",{message:err.message})); | ||||
|                 log.warn(err.stack); | ||||
|                 res.status(500).json({error:err.code || "unexpected_error", message:err.message}); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         runtimeAPI.flows.setFlows(opts).then(function(result) { | ||||
|             if (version === "v1") { | ||||
|                 res.status(204).end(); | ||||
|             } else { | ||||
|                 res.json(result); | ||||
|             } | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -24,10 +24,10 @@ var auth = require("../auth"); | ||||
| var apiUtil = require("../util"); | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         flows.init(runtime); | ||||
|         flow.init(runtime); | ||||
|         nodes.init(runtime); | ||||
|     init: function(runtimeAPI) { | ||||
|         flows.init(runtimeAPI); | ||||
|         flow.init(runtimeAPI); | ||||
|         nodes.init(runtimeAPI); | ||||
|  | ||||
|         var needsPermission = auth.needsPermission; | ||||
|  | ||||
|   | ||||
| @@ -14,230 +14,133 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| var when = require("when"); | ||||
| var apiUtils = require("../util"); | ||||
| var redNodes; | ||||
| var log; | ||||
| var settings; | ||||
|  | ||||
| var runtimeAPI; | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         redNodes = runtime.nodes; | ||||
|         log = runtime.log; | ||||
|         settings = runtime.settings; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|     }, | ||||
|     getAll: function(req,res) { | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|         } | ||||
|         if (req.get("accept") == "application/json") { | ||||
|             log.audit({event: "nodes.list.get"},req); | ||||
|             res.json(redNodes.getNodeList()); | ||||
|             runtimeAPI.nodes.getNodeList(opts).then(function(list) { | ||||
|                 res.json(list); | ||||
|             }) | ||||
|         } else { | ||||
|             var lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); | ||||
|             log.audit({event: "nodes.configs.get"},req); | ||||
|             res.send(redNodes.getNodeConfigs(lang)); | ||||
|             opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); | ||||
|             runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) { | ||||
|                 res.send(configs); | ||||
|             }) | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     post: function(req,res) { | ||||
|         if (!settings.available()) { | ||||
|             log.audit({event: "nodes.install",error:"settings_unavailable"},req); | ||||
|             res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"}); | ||||
|             return; | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.body.module, | ||||
|             version: req.body.version | ||||
|         } | ||||
|         var node = req.body; | ||||
|         var promise; | ||||
|         var isUpgrade = false; | ||||
|         if (node.module) { | ||||
|             var module = redNodes.getModuleInfo(node.module); | ||||
|             if (module) { | ||||
|                 if (!node.version || module.version === node.version) { | ||||
|                     log.audit({event: "nodes.install",module:node.module, version:node.version, error:"module_already_loaded"},req); | ||||
|                     res.status(400).json({error:"module_already_loaded", message:"Module already loaded"}); | ||||
|                     return; | ||||
|                 } | ||||
|                 if (!module.local) { | ||||
|                     log.audit({event: "nodes.install",module:node.module, version:node.version, error:"module_not_local"},req); | ||||
|                     res.status(400).json({error:"module_not_local", message:"Module not locally installed"}); | ||||
|                     return; | ||||
|                 } | ||||
|                 isUpgrade = true; | ||||
|             } | ||||
|             promise = redNodes.installModule(node.module,node.version); | ||||
|         } else { | ||||
|             log.audit({event: "nodes.install",module:node.module,error:"invalid_request"},req); | ||||
|             res.status(400).json({error:"invalid_request", message:"Invalid request"}); | ||||
|             return; | ||||
|         } | ||||
|         promise.then(function(info) { | ||||
|             if (node.module) { | ||||
|                 log.audit({event: "nodes.install",module:node.module,version:node.version},req); | ||||
|                 res.json(info); | ||||
|             } | ||||
|         runtimeAPI.nodes.addModule(opts).then(function(info) { | ||||
|             res.json(info); | ||||
|         }).catch(function(err) { | ||||
|             if (err.code === 404) { | ||||
|                 log.audit({event: "nodes.install",module:node.module,version:node.version,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } else if (err.code) { | ||||
|                 log.audit({event: "nodes.install",module:node.module,version:node.version,error:err.code},req); | ||||
|                 res.status(400).json({error:err.code, message:err.message}); | ||||
|             } else { | ||||
|                 log.audit({event: "nodes.install",module:node.module,version:node.version,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             } | ||||
|         }); | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     delete: function(req,res) { | ||||
|         if (!settings.available()) { | ||||
|             log.audit({event: "nodes.remove",error:"settings_unavailable"},req); | ||||
|             res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"}); | ||||
|             return; | ||||
|         } | ||||
|         var mod = req.params[0]; | ||||
|         try { | ||||
|             var promise = null; | ||||
|             var module = redNodes.getModuleInfo(mod); | ||||
|             if (!module) { | ||||
|                 log.audit({event: "nodes.remove",module:mod,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|                 return; | ||||
|             } else { | ||||
|                 promise = redNodes.uninstallModule(mod); | ||||
|             } | ||||
|  | ||||
|             promise.then(function(list) { | ||||
|                 log.audit({event: "nodes.remove",module:mod},req); | ||||
|                 res.status(204).end(); | ||||
|             }).catch(function(err) { | ||||
|                 log.audit({event: "nodes.remove",module:mod,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             }); | ||||
|         } catch(err) { | ||||
|             log.audit({event: "nodes.remove",module:mod,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|             res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0] | ||||
|         } | ||||
|         runtimeAPI.nodes.removeModule(opts).then(function(info) { | ||||
|             res.status(204).end(); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     getSet: function(req,res) { | ||||
|         var id = req.params[0] + "/" + req.params[2]; | ||||
|         var result = null; | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params[0] + "/" + req.params[2] | ||||
|         } | ||||
|         if (req.get("accept") === "application/json") { | ||||
|             result = redNodes.getNodeInfo(id); | ||||
|             if (result) { | ||||
|                 log.audit({event: "nodes.info.get",id:id},req); | ||||
|                 delete result.loaded; | ||||
|             runtimeAPI.nodes.getNodeInfo(opts).then(function(result) { | ||||
|                 res.send(result); | ||||
|             } else { | ||||
|                 log.audit({event: "nodes.info.get",id:id,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }) | ||||
|         } else { | ||||
|             var lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); | ||||
|             result = redNodes.getNodeConfig(id,lang); | ||||
|             if (result) { | ||||
|                 log.audit({event: "nodes.config.get",id:id},req); | ||||
|                 res.send(result); | ||||
|             } else { | ||||
|                 log.audit({event: "nodes.config.get",id:id,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } | ||||
|             opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages()); | ||||
|             runtimeAPI.nodes.getNodeConfig(opts).then(function(result) { | ||||
|                 return res.json(result); | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }) | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     getModule: function(req,res) { | ||||
|         var module = req.params[0]; | ||||
|         var result = redNodes.getModuleInfo(module); | ||||
|         if (result) { | ||||
|             log.audit({event: "nodes.module.get",module:module},req); | ||||
|             res.json(result); | ||||
|         } else { | ||||
|             log.audit({event: "nodes.module.get",module:module,error:"not_found"},req); | ||||
|             res.status(404).end(); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0] | ||||
|         } | ||||
|         runtimeAPI.nodes.getModuleInfo(opts).then(function(result) { | ||||
|             res.send(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     putSet: function(req,res) { | ||||
|         if (!settings.available()) { | ||||
|             log.audit({event: "nodes.info.set",error:"settings_unavailable"},req); | ||||
|             res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"}); | ||||
|             return; | ||||
|         } | ||||
|         var body = req.body; | ||||
|         if (!body.hasOwnProperty("enabled")) { | ||||
|             log.audit({event: "nodes.info.set",error:"invalid_request"},req); | ||||
|             // log.audit({event: "nodes.module.set",error:"invalid_request"},req); | ||||
|             res.status(400).json({error:"invalid_request", message:"Invalid request"}); | ||||
|             return; | ||||
|         } | ||||
|         var id = req.params[0] + "/" + req.params[2]; | ||||
|         try { | ||||
|             var node = redNodes.getNodeInfo(id); | ||||
|             var info; | ||||
|             if (!node) { | ||||
|                 log.audit({event: "nodes.info.set",id:id,error:"not_found"},req); | ||||
|                 res.status(404).end(); | ||||
|             } else { | ||||
|                 delete node.loaded; | ||||
|                 putNode(node, body.enabled).then(function(result) { | ||||
|                     log.audit({event: "nodes.info.set",id:id,enabled:body.enabled},req); | ||||
|                     res.json(result); | ||||
|                 }); | ||||
|             } | ||||
|         } catch(err) { | ||||
|             log.audit({event: "nodes.info.set",id:id,enabled:body.enabled,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|             res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             id: req.params[0] + "/" + req.params[2], | ||||
|             enabled: body.enabled | ||||
|         } | ||||
|         runtimeAPI.nodes.setNodeSetState(opts).then(function(result) { | ||||
|             res.send(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     putModule: function(req,res) { | ||||
|         if (!settings.available()) { | ||||
|             log.audit({event: "nodes.module.set",error:"settings_unavailable"},req); | ||||
|             res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"}); | ||||
|             return; | ||||
|         } | ||||
|         var body = req.body; | ||||
|         if (!body.hasOwnProperty("enabled")) { | ||||
|             log.audit({event: "nodes.module.set",error:"invalid_request"},req); | ||||
|             // log.audit({event: "nodes.module.set",error:"invalid_request"},req); | ||||
|             res.status(400).json({error:"invalid_request", message:"Invalid request"}); | ||||
|             return; | ||||
|         } | ||||
|         var mod = req.params[0]; | ||||
|         try { | ||||
|             var module = redNodes.getModuleInfo(mod); | ||||
|             if (!module) { | ||||
|                 log.audit({event: "nodes.module.set",module:mod,error:"not_found"},req); | ||||
|                 return res.status(404).end(); | ||||
|             } | ||||
|  | ||||
|             var nodes = module.nodes; | ||||
|             var promises = []; | ||||
|             for (var i = 0; i < nodes.length; ++i) { | ||||
|                 promises.push(putNode(nodes[i],body.enabled)); | ||||
|             } | ||||
|             when.settle(promises).then(function() { | ||||
|                 res.json(redNodes.getModuleInfo(mod)); | ||||
|             }); | ||||
|         } catch(err) { | ||||
|             log.audit({event: "nodes.module.set",module:mod,enabled:body.enabled,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|             res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             module: req.params[0], | ||||
|             enabled: body.enabled | ||||
|         } | ||||
|         runtimeAPI.nodes.setModuleState(opts).then(function(result) { | ||||
|             res.send(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|  | ||||
|     }, | ||||
|  | ||||
|     getIcons: function(req,res) { | ||||
|         log.audit({event: "nodes.icons.get"},req); | ||||
|         res.json(redNodes.getNodeIcons()); | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|         } | ||||
|         runtimeAPI.nodes.getIconList(opts).then(function(list) { | ||||
|             res.json(list); | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function putNode(node, enabled) { | ||||
|     var info; | ||||
|     var promise; | ||||
|     if (!node.err && node.enabled === enabled) { | ||||
|         promise = when.resolve(node); | ||||
|     } else { | ||||
|         if (enabled) { | ||||
|             promise = redNodes.enableNode(node.id); | ||||
|         } else { | ||||
|             promise = redNodes.disableNode(node.id); | ||||
|         } | ||||
|     } | ||||
|     return promise; | ||||
| } | ||||
|   | ||||
| @@ -14,39 +14,23 @@ | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
|  | ||||
| var log; | ||||
| var api; | ||||
| var runtimeAPI; | ||||
| var apiUtils = require("../util"); | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         log = runtime.log; | ||||
|         api = runtime.nodes; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI | ||||
|     }, | ||||
|     get: function (req, res) { | ||||
|         // 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 = req.params.type; | ||||
|         var nodeID = req.params.id; | ||||
|         log.audit({event: "credentials.get",type:nodeType,id:nodeID},req); | ||||
|         var credentials = api.getCredentials(nodeID); | ||||
|         if (!credentials) { | ||||
|             res.json({}); | ||||
|             return; | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             type: req.params.type, | ||||
|             id: req.params.id | ||||
|         } | ||||
|         var definition = api.getCredentialDefinition(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); | ||||
|         runtimeAPI.flows.getNodeCredentials(opts).then(function(result) { | ||||
|             res.json(result); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,7 @@ var auth = require("../auth"); | ||||
| var nodes = require("../admin/nodes"); // TODO: move /icons into here | ||||
| var needsPermission; | ||||
| var runtime; | ||||
| var runtimeAPI; | ||||
| var log; | ||||
| var apiUtil = require("../util"); | ||||
|  | ||||
| @@ -38,16 +39,17 @@ var ensureRuntimeStarted = function(req,res,next) { | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(server, _runtime) { | ||||
|     init: function(server, settings, _runtime, _runtimeAPI) { | ||||
|         runtime = _runtime; | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|         log = runtime.log; | ||||
|         needsPermission = auth.needsPermission; | ||||
|         var settings = runtime.settings; | ||||
|         if (!settings.disableEditor) { | ||||
|             info.init(runtime); | ||||
|             info.init(runtimeAPI); | ||||
|             comms.init(server,runtime); | ||||
|  | ||||
|             var ui = require("./ui"); | ||||
|             // ui is passed runtime so it get access runtime.nodes.getNodeIconPath | ||||
|             ui.init(runtime); | ||||
|             var editorApp = express(); | ||||
|             if (settings.requireHttps === true) { | ||||
| @@ -67,7 +69,7 @@ module.exports = { | ||||
|             editorApp.get("/icons/:scope/:module/:icon",ui.icon); | ||||
|  | ||||
|             var theme = require("./theme"); | ||||
|             theme.init(runtime); | ||||
|             theme.init(settings, runtime.version()); | ||||
|             editorApp.use("/theme",theme.app()); | ||||
|             editorApp.use("/",ui.editorResources); | ||||
|  | ||||
| @@ -91,7 +93,7 @@ module.exports = { | ||||
|  | ||||
|             // Credentials | ||||
|             var credentials = require("./credentials"); | ||||
|             credentials.init(runtime); | ||||
|             credentials.init(runtimeAPI); | ||||
|             editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler); | ||||
|  | ||||
|             // Settings | ||||
| @@ -100,11 +102,8 @@ module.exports = { | ||||
|             editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler); | ||||
|             // User Settings | ||||
|             editorApp.post("/settings/user",needsPermission("settings.write"),info.updateUserSettings,apiUtil.errorHandler); | ||||
|  | ||||
|             // SSH keys | ||||
|             var sshkeys = require("./sshkeys"); | ||||
|             sshkeys.init(runtime); | ||||
|             editorApp.use("/settings/user/keys",sshkeys.app()); | ||||
|             editorApp.use("/settings/user/keys",info.sshkeys()); | ||||
|  | ||||
|             return editorApp; | ||||
|         } | ||||
|   | ||||
| @@ -13,117 +13,48 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  **/ | ||||
| var theme = require("../editor/theme"); | ||||
| var util = require('util'); | ||||
| var runtime; | ||||
| var settings; | ||||
| var log; | ||||
| var apiUtils = require("../util"); | ||||
| var runtimeAPI; | ||||
| var sshkeys = require("./sshkeys"); | ||||
| var theme = require("./theme"); | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(_runtime) { | ||||
|         runtime = _runtime; | ||||
|         settings = runtime.settings; | ||||
|         log = runtime.log; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|         sshkeys.init(runtimeAPI); | ||||
|     }, | ||||
|     runtimeSettings: function(req,res) { | ||||
|         var safeSettings = { | ||||
|             httpNodeRoot: settings.httpNodeRoot||"/", | ||||
|             version: settings.version, | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|         } | ||||
|  | ||||
|         var themeSettings = theme.settings(); | ||||
|         if (themeSettings) { | ||||
|             safeSettings.editorTheme = themeSettings; | ||||
|         } | ||||
|  | ||||
|         if (util.isArray(settings.paletteCategories)) { | ||||
|             safeSettings.paletteCategories = settings.paletteCategories; | ||||
|         } | ||||
|  | ||||
|         if (settings.flowFilePretty) { | ||||
|             safeSettings.flowFilePretty = settings.flowFilePretty; | ||||
|         } | ||||
|  | ||||
|         if (!runtime.nodes.paletteEditorEnabled()) { | ||||
|             safeSettings.editorTheme = safeSettings.editorTheme || {}; | ||||
|             safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; | ||||
|             safeSettings.editorTheme.palette.editable = false; | ||||
|         } | ||||
|         if (runtime.storage.projects) { | ||||
|             var activeProject = runtime.storage.projects.getActiveProject(); | ||||
|             if (activeProject) { | ||||
|                 safeSettings.project = activeProject; | ||||
|             } else if (runtime.storage.projects.flowFileExists()) { | ||||
|                 safeSettings.files = { | ||||
|                     flow: runtime.storage.projects.getFlowFilename(), | ||||
|                     credentials: runtime.storage.projects.getCredentialsFilename() | ||||
|                 } | ||||
|         runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) { | ||||
|             var themeSettings = theme.settings(); | ||||
|             if (themeSettings) { | ||||
|                 result.editorTheme = themeSettings; | ||||
|             } | ||||
|             safeSettings.git = { | ||||
|                 globalUser: runtime.storage.projects.getGlobalGitUser() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); | ||||
|  | ||||
|         settings.exportNodeSettings(safeSettings); | ||||
|         res.json(safeSettings); | ||||
|             res.json(result); | ||||
|         }); | ||||
|     }, | ||||
|     userSettings: function(req, res) { | ||||
|         var username; | ||||
|         if (!req.user || req.user.anonymous) { | ||||
|             username = '_'; | ||||
|         } else { | ||||
|             username = req.user.username; | ||||
|         var opts = { | ||||
|             user: req.user | ||||
|         } | ||||
|         res.json(settings.getUserSettings(username)||{}); | ||||
|         runtimeAPI.settings.getUserSettings(opts).then(function(result) { | ||||
|             res.json(result); | ||||
|         }); | ||||
|     }, | ||||
|     updateUserSettings: function(req,res) { | ||||
|         var username; | ||||
|         if (!req.user || req.user.anonymous) { | ||||
|             username = '_'; | ||||
|         } else { | ||||
|             username = req.user.username; | ||||
|         } | ||||
|         var currentSettings = settings.getUserSettings(username)||{}; | ||||
|         currentSettings = extend(currentSettings, req.body); | ||||
|         try { | ||||
|             settings.setUserSettings(username, currentSettings).then(function() { | ||||
|                 log.audit({event: "settings.update",username:username},req); | ||||
|                 res.status(204).end(); | ||||
|             }).catch(function(err) { | ||||
|                 log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             }); | ||||
|         } catch(err) { | ||||
|             log.warn(log._("settings.user-not-available",{message:log._("settings.not-available")})); | ||||
|             log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()},req); | ||||
|             res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|         var opts = { | ||||
|             user: req.user, | ||||
|             settings: req.body | ||||
|         } | ||||
|         runtimeAPI.settings.updateUserSettings(opts).then(function(result) { | ||||
|             res.status(204).end(); | ||||
|         }).catch(function(err) { | ||||
|             apiUtils.rejectHandler(req,res,err); | ||||
|         }); | ||||
|     }, | ||||
|     sshkeys: function() { | ||||
|         return sshkeys.app() | ||||
|     } | ||||
| } | ||||
|  | ||||
| function extend(target, source) { | ||||
|     var keys = Object.keys(source); | ||||
|     var i = keys.length; | ||||
|     while(i--) { | ||||
|         var value = source[keys[i]] | ||||
|         var type = typeof value; | ||||
|         if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) { | ||||
|             target[keys[i]] = value; | ||||
|         } else if (value === null) { | ||||
|             if (target.hasOwnProperty(keys[i])) { | ||||
|                 delete target[keys[i]]; | ||||
|             } | ||||
|         } else { | ||||
|             // Object | ||||
|             if (target.hasOwnProperty(keys[i])) { | ||||
|                 target[keys[i]] = extend(target[keys[i]],value); | ||||
|             } else { | ||||
|                 target[keys[i]] = value; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return target; | ||||
| } | ||||
|   | ||||
| @@ -15,8 +15,7 @@ | ||||
|  **/ | ||||
|  | ||||
| var express = require("express"); | ||||
| var os = require("os"); | ||||
| var runtime; | ||||
| var runtimeAPI; | ||||
| var needsPermission = require("../auth").needsPermission; | ||||
|  | ||||
| function getUsername(userObj) { | ||||
| @@ -28,94 +27,66 @@ function getUsername(userObj) { | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(_runtime) { | ||||
|         runtime = _runtime; | ||||
|     init: function(_runtimeAPI) { | ||||
|         runtimeAPI = _runtimeAPI; | ||||
|     }, | ||||
|     app: function() { | ||||
|         var app = express(); | ||||
|  | ||||
|         // SSH keys | ||||
|  | ||||
|         // List all SSH keys | ||||
|         app.get("/", needsPermission("settings.read"), function(req,res) { | ||||
|             var username = getUsername(req.user); | ||||
|             runtime.storage.projects.ssh.listSSHKeys(username) | ||||
|             .then(function(list) { | ||||
|             var opts = { | ||||
|                 user: req.user | ||||
|             } | ||||
|             runtimeAPI.settings.getUserKeys(opts).then(function(list) { | ||||
|                 res.json({ | ||||
|                     keys: list | ||||
|                 }); | ||||
|             }) | ||||
|             .catch(function(err) { | ||||
|                 // console.log(err.stack); | ||||
|                 if (err.code) { | ||||
|                     res.status(400).json({error:err.code, message: err.message}); | ||||
|                 } else { | ||||
|                     res.status(400).json({error:"unexpected_error", message:err.toString()}); | ||||
|                 } | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Get SSH key detail | ||||
|         app.get("/:id", needsPermission("settings.read"), function(req,res) { | ||||
|             var username = getUsername(req.user); | ||||
|             // console.log('username:', username); | ||||
|             runtime.storage.projects.ssh.getSSHKey(username, req.params.id) | ||||
|             .then(function(data) { | ||||
|                 if (data) { | ||||
|                     res.json({ | ||||
|                         publickey: data | ||||
|                     }); | ||||
|                 } else { | ||||
|                     res.status(404).end(); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(function(err) { | ||||
|                 if (err.code) { | ||||
|                     res.status(400).json({error:err.code, message: err.message}); | ||||
|                 } else { | ||||
|                     res.status(400).json({error:"unexpected_error", message:err.toString()}); | ||||
|                 } | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|             } | ||||
|             runtimeAPI.settings.getUserKey(opts).then(function(data) { | ||||
|                 res.json({ | ||||
|                     publickey: data | ||||
|                 }); | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Generate a SSH key | ||||
|         app.post("/", needsPermission("settings.write"), function(req,res) { | ||||
|             var username = getUsername(req.user); | ||||
|             // console.log('req.body:', req.body); | ||||
|             if ( req.body && req.body.name && /^[a-zA-Z0-9\-_]+$/.test(req.body.name)) { | ||||
|                 runtime.storage.projects.ssh.generateSSHKey(username, req.body) | ||||
|                 .then(function(name) { | ||||
|                     // console.log('generate key --- success  name:', name); | ||||
|                     res.json({ | ||||
|                         name: name | ||||
|                     }); | ||||
|                 }) | ||||
|                 .catch(function(err) { | ||||
|                     if (err.code) { | ||||
|                         res.status(400).json({error:err.code, message: err.message}); | ||||
|                     } else { | ||||
|                         res.status(400).json({error:"unexpected_error", message:err.toString()}); | ||||
|                     } | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|             } | ||||
|             runtimeAPI.settings.generateUserKey(opts).then(function(name) { | ||||
|                 res.json({ | ||||
|                     name: name | ||||
|                 }); | ||||
|             } | ||||
|             else { | ||||
|                 res.status(400).json({error:"unexpected_error", message:"You need to have body or body.name"}); | ||||
|             } | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         // Delete a SSH key | ||||
|         app.delete("/:id", needsPermission("settings.write"), function(req,res) { | ||||
|             var username = getUsername(req.user); | ||||
|             runtime.storage.projects.ssh.deleteSSHKey(username, req.params.id) | ||||
|             .then(function() { | ||||
|             var opts = { | ||||
|                 user: req.user, | ||||
|                 id: req.params.id | ||||
|             } | ||||
|             runtimeAPI.settings.generateUserKey(opts).then(function(name) { | ||||
|                 res.status(204).end(); | ||||
|             }) | ||||
|             .catch(function(err) { | ||||
|                 if (err.code) { | ||||
|                     res.status(400).json({error:err.code, message: err.message}); | ||||
|                 } else { | ||||
|                     res.status(400).json({error:"unexpected_error", message:err.toString()}); | ||||
|                 } | ||||
|             }).catch(function(err) { | ||||
|                 apiUtils.rejectHandler(req,res,err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -40,7 +40,6 @@ var defaultContext = { | ||||
| var theme = null; | ||||
| var themeContext = clone(defaultContext); | ||||
| var themeSettings = null; | ||||
| var runtime = null; | ||||
|  | ||||
| var themeApp; | ||||
|  | ||||
| @@ -78,11 +77,10 @@ function serveFilesFromTheme(themeValue, themeApp, directory) { | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: function(runtime) { | ||||
|         var settings = runtime.settings; | ||||
|     init: function(settings,version) { | ||||
|         themeContext = clone(defaultContext); | ||||
|         if (runtime.version) { | ||||
|             themeContext.version = runtime.version(); | ||||
|         if (version) { | ||||
|             themeContext.version = version; | ||||
|         } | ||||
|         themeSettings = null; | ||||
|         theme = settings.editorTheme || {}; | ||||
|   | ||||
| @@ -26,13 +26,10 @@ var apiUtil = require("./util"); | ||||
|  | ||||
| var adminApp; | ||||
| var server; | ||||
| var runtime; | ||||
| var editor; | ||||
|  | ||||
| function init(_server,_runtime) { | ||||
| function init(_server,settings,runtime,runtimeAPI) { | ||||
|     server = _server; | ||||
|     runtime = _runtime; | ||||
|     var settings = runtime.settings; | ||||
|     if (settings.httpAdminRoot !== false) { | ||||
|         apiUtil.init(runtime); | ||||
|         adminApp = express(); | ||||
| @@ -61,7 +58,7 @@ function init(_server,_runtime) { | ||||
|         // Editor | ||||
|         if (!settings.disableEditor) { | ||||
|             editor = require("./editor"); | ||||
|             var editorApp = editor.init(server, runtime); | ||||
|             var editorApp = editor.init(server, settings, runtime, runtimeAPI); | ||||
|             adminApp.use(editorApp); | ||||
|         } | ||||
|  | ||||
| @@ -70,7 +67,7 @@ function init(_server,_runtime) { | ||||
|             adminApp.use(corsHandler); | ||||
|         } | ||||
|  | ||||
|         var adminApiApp = require("./admin").init(runtime); | ||||
|         var adminApiApp = require("./admin").init(runtimeAPI); | ||||
|         adminApp.use(adminApiApp); | ||||
|     } else { | ||||
|         adminApp = null; | ||||
|   | ||||
| @@ -41,5 +41,15 @@ module.exports = { | ||||
|             lang = acceptedLanguages[0]; | ||||
|         } | ||||
|         return lang; | ||||
|     }, | ||||
|     rejectHandler: function(req,res,err) { | ||||
|         res.status(err.status||500); | ||||
|         if (err.code || err.message) { | ||||
|             res.json({ | ||||
|                 code: err.code||"unexpected_error", | ||||
|                 message: err.message | ||||
|             }) | ||||
|         } | ||||
|         res.end(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,6 +18,8 @@ var fs = require("fs"); | ||||
| var path = require('path'); | ||||
|  | ||||
| var runtime = require("./runtime"); | ||||
| var runtimeAPI = require("./runtime-api"); | ||||
|  | ||||
| var api = require("./api"); | ||||
|  | ||||
| process.env.NODE_RED_HOME = process.env.NODE_RED_HOME || path.resolve(__dirname+"/.."); | ||||
| @@ -67,7 +69,10 @@ module.exports = { | ||||
|  | ||||
|         if (userSettings.httpAdminRoot !== false) { | ||||
|             runtime.init(userSettings,api); | ||||
|             api.init(httpServer,runtime); | ||||
|  | ||||
|             runtimeAPI.init(runtime); | ||||
|             api.init(httpServer,userSettings,runtime,runtimeAPI); | ||||
|  | ||||
|             apiEnabled = true; | ||||
|             server = runtime.adminApi.server; | ||||
|             runtime.server = runtime.adminApi.server; | ||||
|   | ||||
							
								
								
									
										19
									
								
								red/runtime-api/auth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								red/runtime-api/auth.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| /** | ||||
|  * @module red/auth | ||||
|  */ | ||||
							
								
								
									
										19
									
								
								red/runtime-api/comms.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								red/runtime-api/comms.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| /** | ||||
|  * @module red/comms | ||||
|  */ | ||||
							
								
								
									
										248
									
								
								red/runtime-api/flows.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								red/runtime-api/flows.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,248 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
|  /** | ||||
|   * @namespace RED.flows | ||||
|   */ | ||||
|  | ||||
| /** | ||||
|  * @typedef Flows | ||||
|  * @alias Dave | ||||
|  * @type {object} | ||||
|  * @property {string} rev - the flow revision identifier | ||||
|  * @property {Array}  flows - the flow configuration, an array of node configuration objects | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @typedef Flow | ||||
|  * @type {object} | ||||
|  * @property {string} id - the flow identifier | ||||
|  * @property {string} label - a label for the flow | ||||
|  * @property {Array}  nodes - an array of node configuration objects | ||||
|  */ | ||||
|  | ||||
| var runtime; | ||||
|  | ||||
| var api = module.exports = { | ||||
|     init: function(_runtime) { | ||||
|         runtime = _runtime; | ||||
|     }, | ||||
|     /** | ||||
|     * Gets the current flow configuration | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<Flows>} - the active flow configuration | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     getFlows: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             runtime.log.audit({event: "flows.get"}/*,req*/); | ||||
|             var version = opts.version||"v1"; | ||||
|             return resolve(runtime.nodes.getFlows()); | ||||
|         }); | ||||
|     }, | ||||
|     /** | ||||
|     * Sets the current flow configuration | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<Flows>} - the active flow configuration | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     setFlows: function(opts) { | ||||
|         var err; | ||||
|         return new Promise(function(resolve,reject) { | ||||
|  | ||||
|             var flows = opts.flows; | ||||
|             var deploymentType = opts.deploymentType||"full"; | ||||
|             runtime.log.audit({event: "flows.set",type:deploymentType}/*,req*/); | ||||
|  | ||||
|             var apiPromise; | ||||
|             if (deploymentType === 'reload') { | ||||
|                 apiPromise = runtime.nodes.loadFlows(); | ||||
|             } else { | ||||
|                 if (flows.hasOwnProperty('rev')) { | ||||
|                     var currentVersion = runtime.nodes.getFlows().rev; | ||||
|                     if (currentVersion !== flows.rev) { | ||||
|                         err = new Error(); | ||||
|                         err.code = "version_mismatch"; | ||||
|                         err.status = 409; | ||||
|                         //TODO: log warning | ||||
|                         return reject(err); | ||||
|                     } | ||||
|                 } | ||||
|                 apiPromise = runtime.nodes.setFlows(flows.flows,deploymentType); | ||||
|             } | ||||
|             apiPromise.then(function(flowId) { | ||||
|                 return resolve({rev:flowId}); | ||||
|             }).catch(function(err) { | ||||
|                 log.warn(log._("api.flows.error-"+(deploymentType === 'reload'?'reload':'save'),{message:err.message})); | ||||
|                 log.warn(err.stack); | ||||
|                 return reject(err); | ||||
|             }); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Adds a flow configuration | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {Object} opts.flow - the flow to add | ||||
|     * @return {Promise<String>} - the id of the added flow | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     addFlow: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var flow = opts.flow; | ||||
|             runtime.nodes.addFlow(flow).then(function(id) { | ||||
|                 runtime.log.audit({event: "flow.add",id:id}); | ||||
|                 return resolve(id); | ||||
|             }).catch(function(err) { | ||||
|                 runtime.log.audit({event: "flow.add",error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             }) | ||||
|         }) | ||||
|  | ||||
|  | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets an individual flow configuration | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {Object} opts.id - the id of the flow to retrieve | ||||
|     * @return {Promise<Flow>} - the active flow configuration | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     getFlow: function(opts) { | ||||
|         return new Promise(function (resolve,reject) { | ||||
|             var flow = runtime.nodes.getFlow(opts.id); | ||||
|             if (flow) { | ||||
|                 runtime.log.audit({event: "flow.get",id:opts.id}); | ||||
|                 return resolve(flow); | ||||
|             } else { | ||||
|                 runtime.log.audit({event: "flow.get",id:opts.id,error:"not_found"}); | ||||
|                 var err = new Error(); | ||||
|                 err.status = 404; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }) | ||||
|  | ||||
|     }, | ||||
|     /** | ||||
|     * Updates an existing flow configuration | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {Object} opts.id - the id of the flow to update | ||||
|     * @param {Object} opts.flow - the flow configuration | ||||
|     * @return {Promise<String>} - the id of the updated flow | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     updateFlow: function(opts) { | ||||
|         return new Promise(function (resolve,reject) { | ||||
|             var flow = opts.flow; | ||||
|             var id = opts.id; | ||||
|             try { | ||||
|                 runtime.nodes.updateFlow(id,flow).then(function() { | ||||
|                     runtime.log.audit({event: "flow.update",id:id}); | ||||
|                     return resolve(id); | ||||
|                 }).catch(function(err) { | ||||
|                     runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     err.status = 400; | ||||
|                     return reject(err); | ||||
|                 }) | ||||
|             } catch(err) { | ||||
|                 if (err.code === 404) { | ||||
|                     runtime.log.audit({event: "flow.update",id:id,error:"not_found"}); | ||||
|                     // TODO: this swap around of .code and .status isn't ideal | ||||
|                     err.status = 404; | ||||
|                     err.code = "not_found"; | ||||
|                     return reject(err); | ||||
|                 } else { | ||||
|                     runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     err.status = 400; | ||||
|                     return reject(err); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     }, | ||||
|     /** | ||||
|     * Deletes a flow | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {Object} opts.id - the id of the flow to delete | ||||
|     * @return {Promise} - resolves if successful | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     deleteFlow: function(opts) { | ||||
|         return new Promise(function (resolve,reject) { | ||||
|             var id = opts.id; | ||||
|             try { | ||||
|                 runtime.nodes.removeFlow(id).then(function() { | ||||
|                     log.audit({event: "flow.remove",id:id}); | ||||
|                     return resolve(); | ||||
|                 }) | ||||
|             } catch(err) { | ||||
|                 if (err.code === 404) { | ||||
|                     log.audit({event: "flow.remove",id:id,error:"not_found"}); | ||||
|                     // TODO: this swap around of .code and .status isn't ideal | ||||
|                     err.status = 404; | ||||
|                     err.code = "not_found"; | ||||
|                     return reject(err); | ||||
|                 } else { | ||||
|                     log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     err.status = 400; | ||||
|                     return reject(err); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets the safe credentials for a node | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.type - the node type to return the credential information for | ||||
|     * @param {String} opts.id - the node id | ||||
|     * @return {Promise<Object>} - the safe credentials | ||||
|     * @memberof RED.flows | ||||
|     */ | ||||
|     getNodeCredentials: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             log.audit({event: "credentials.get",type:opts.type,id:opts.id}); | ||||
|             var credentials = runtime.nodes.getCredentials(opts.id); | ||||
|             if (!credentials) { | ||||
|                 return resolve({}); | ||||
|             } | ||||
|             var definition = runtime.nodes.getCredentialDefinition(opts.type); | ||||
|  | ||||
|             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] || ''; | ||||
|                 } | ||||
|             } | ||||
|             resolve(sendCredentials); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										64
									
								
								red/runtime-api/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								red/runtime-api/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
|  | ||||
|  /** | ||||
|   * A user accessing the API | ||||
|   * @typedef User | ||||
|   * @type {object} | ||||
|   */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @namespace RED | ||||
|  */ | ||||
| var api = module.exports = { | ||||
|     init: function(runtime) { | ||||
|         api.flows.init(runtime); | ||||
|         api.nodes.init(runtime); | ||||
|         api.settings.init(runtime); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Auth module | ||||
|     */ | ||||
|     auth: require("./auth"), | ||||
|  | ||||
|     /** | ||||
|     * Comms module | ||||
|     */ | ||||
|     comms: require("./comms"), | ||||
|  | ||||
|     /** | ||||
|     * Flows module | ||||
|     */ | ||||
|     flows: require("./flows"), | ||||
|  | ||||
|     /** | ||||
|     * Library module | ||||
|     */ | ||||
|     library: require("./library"), | ||||
|  | ||||
|     /** | ||||
|     * Nodes module | ||||
|     */ | ||||
|     nodes: require("./nodes"), | ||||
|  | ||||
|     /** | ||||
|     * Settings module | ||||
|     */ | ||||
|     settings: require("./settings") | ||||
| } | ||||
							
								
								
									
										35
									
								
								red/runtime-api/library.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								red/runtime-api/library.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| /** | ||||
|  * @module red/library | ||||
|  */ | ||||
|  | ||||
| module.exports = { | ||||
|  | ||||
|     /** | ||||
|     * Does something | ||||
|     */ | ||||
|     setEnty: function() {}, | ||||
|     /** | ||||
|     * Does something | ||||
|     */ | ||||
|     getEntry: function() {}, | ||||
|     /** | ||||
|     * Does something | ||||
|     */ | ||||
|     getEntries: function() {} | ||||
| } | ||||
							
								
								
									
										377
									
								
								red/runtime-api/nodes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								red/runtime-api/nodes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,377 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
| "use strict" | ||||
|  /** | ||||
|   * @namespace RED.nodes | ||||
|   */ | ||||
|  | ||||
| var runtime; | ||||
|  | ||||
| function putNode(node, enabled) { | ||||
|     var promise; | ||||
|     if (!node.err && node.enabled === enabled) { | ||||
|         promise = Promise.resolve(node); | ||||
|     } else { | ||||
|         if (enabled) { | ||||
|             promise = runtime.nodes.enableNode(node.id); | ||||
|         } else { | ||||
|             promise = runtime.nodes.disableNode(node.id); | ||||
|         } | ||||
|     } | ||||
|     return promise; | ||||
| } | ||||
|  | ||||
|  | ||||
| var api = module.exports = { | ||||
|     init: function(_runtime) { | ||||
|         runtime = _runtime; | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     /** | ||||
|     * Gets the info of an individual node set | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.id - the id of the node set to return | ||||
|     * @return {Promise<NodeInfo>} - the node information | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getNodeInfo: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var id = opts.id; | ||||
|             var result = redNodes.getNodeInfo(id); | ||||
|             if (result) { | ||||
|                 runtime.log.audit({event: "nodes.info.get",id:id}); | ||||
|                 delete result.loaded; | ||||
|                 return resolve(result); | ||||
|             } else { | ||||
|                 runtime.log.audit({event: "nodes.info.get",id:id,error:"not_found"}); | ||||
|                 var err = new Error(); | ||||
|                 err.code = "not_found"; | ||||
|                 err.status = 404; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets the list of node modules installed in the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<NodeList>} - the list of node modules | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getNodeList: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             runtime.log.audit({event: "nodes.list.get"}); | ||||
|             return resolve(runtime.nodes.getNodeList()); | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets an individual node's html content | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.id - the id of the node set to return | ||||
|     * @param {String} opts.lang - the locale language to return | ||||
|     * @return {Promise<String>} - the node html content | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getNodeConfig: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var id = opts.id; | ||||
|             var lang = opts.lang; | ||||
|             var result = runtime.nodes.getNodeConfig(id,lang); | ||||
|             if (result) { | ||||
|                 runtime.log.audit({event: "nodes.config.get",id:id}); | ||||
|                 return resolve(result); | ||||
|             } else { | ||||
|                 runtime.log.audit({event: "nodes.config.get",id:id,error:"not_found"}); | ||||
|                 var err = new Error(); | ||||
|                 err.code = "not_found"; | ||||
|                 err.status = 404; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|     /** | ||||
|     * Gets all node html content | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.lang - the locale language to return | ||||
|     * @return {Promise<String>} - the node html content | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getNodeConfigs: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             runtime.log.audit({event: "nodes.configs.get"}); | ||||
|             return resolve(runtime.nodes.getNodeConfigs(opts.lang)); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets the info of a node module | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.module - the id of the module to return | ||||
|     * @return {Promise<ModuleInfo>} - the node module info | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getModuleInfo: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var module = opts.module; | ||||
|             var result = redNodes.getModuleInfo(module); | ||||
|             if (result) { | ||||
|                 runtime.log.audit({event: "nodes.module.get",id:id}); | ||||
|                 return resolve(result); | ||||
|             } else { | ||||
|                 runtime.log.audit({event: "nodes.module.get",id:id,error:"not_found"}); | ||||
|                 var err = new Error(); | ||||
|                 err.code = "not_found"; | ||||
|                 err.status = 404; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Install a new module into the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.module - the id of the module to install | ||||
|     * @param {String} opts.version - (optional) the version of the module to install | ||||
|     * @return {Promise<ModuleInfo>} - the node module info | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     addModule: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             if (!runtime.settings.available()) { | ||||
|                 runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}); | ||||
|                 let err = new Error("Settings unavailable"); | ||||
|                 err.code = "settings_unavailable"; | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|             if (opts.module) { | ||||
|                 var existingModule = runtime.nodes.getModuleInfo(opts.module); | ||||
|                 if (existingModule) { | ||||
|                     if (!opts.version || existingModule.version === opts.version) { | ||||
|                         runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_already_loaded"}); | ||||
|                         let err = new Error("Module already loaded"); | ||||
|                         err.code = "module_already_loaded"; | ||||
|                         err.status = 400; | ||||
|                         return reject(err); | ||||
|                     } | ||||
|                     if (!module.local) { | ||||
|                         runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_not_local"}); | ||||
|                         let err = new Error("Module not locally installed"); | ||||
|                         err.code = "module_not_local"; | ||||
|                         err.status = 400; | ||||
|                         return reject(err); | ||||
|                     } | ||||
|                 } | ||||
|                 runtime.nodes.installModule(opts.module,opts.version).then(function(info) { | ||||
|                     runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version}); | ||||
|                     return resolve(info); | ||||
|                 }).catch(function(err) { | ||||
|                     if (err.code === 404) { | ||||
|                         runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:"not_found"}); | ||||
|                         // TODO: code/status | ||||
|                         err.status = 404; | ||||
|                     } else if (err.code) { | ||||
|                         err.status = 400; | ||||
|                         runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code}); | ||||
|                     } else { | ||||
|                         err.status = 400; | ||||
|                         runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     } | ||||
|                     return reject(err); | ||||
|                 }) | ||||
|             } else { | ||||
|                 runtime.log.audit({event: "nodes.install",module:opts.module,error:"invalid_request"}); | ||||
|                 let err = new Error("Invalid request"); | ||||
|                 err.code = "invalid_request"; | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|  | ||||
|         }); | ||||
|     }, | ||||
|     /** | ||||
|     * Removes a module from the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.module - the id of the module to remove | ||||
|     * @return {Promise} - resolves when complete | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     removeModule: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             if (!runtime.settings.available()) { | ||||
|                 runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}); | ||||
|                 let err = new Error("Settings unavailable"); | ||||
|                 err.code = "settings_unavailable"; | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|             var module = runtime.nodes.getModuleInfo(opts.module); | ||||
|             if (!module) { | ||||
|                 runtime.log.audit({event: "nodes.remove",module:opts.module,error:"not_found"}); | ||||
|                 var err = new Error(); | ||||
|                 err.code = "not_found"; | ||||
|                 err.status = 404; | ||||
|                 return reject(err); | ||||
|             } | ||||
|             try { | ||||
|                 runtime.nodes.uninstallModule(opts.module).then(function() { | ||||
|                     runtime.log.audit({event: "nodes.remove",module:opts.module}); | ||||
|                     resolve(); | ||||
|                 }).catch(function(err) { | ||||
|                     err.status = 400; | ||||
|                     runtime.log.audit({event: "nodes.remove",module:opts.module,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     return reject(err); | ||||
|                 }) | ||||
|             } catch(err) { | ||||
|                 runtime.log.audit({event: "nodes.remove",module:opts.module,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Enables or disables a module in the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.module - the id of the module to enable or disable | ||||
|     * @param {String} opts.enabled - whether the module should be enabled or disabled | ||||
|     * @return {Promise<ModuleInfo>} - the module info object | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     setModuleState: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             if (!runtime.settings.available()) { | ||||
|                 runtime.log.audit({event: "nodes.module.set",error:"settings_unavailable"}); | ||||
|                 let err = new Error("Settings unavailable"); | ||||
|                 err.code = "settings_unavailable"; | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|             try { | ||||
|                 var mod = opts.module; | ||||
|                 var module = runtime.nodes.getModuleInfo(mod); | ||||
|                 if (!module) { | ||||
|                     runtime.log.audit({event: "nodes.module.set",module:mod,error:"not_found"}); | ||||
|                     var err = new Error(); | ||||
|                     err.code = "not_found"; | ||||
|                     err.status = 404; | ||||
|                     return reject(err); | ||||
|                 } | ||||
|  | ||||
|                 var nodes = module.nodes; | ||||
|                 var promises = []; | ||||
|                 for (var i = 0; i < nodes.length; ++i) { | ||||
|                     promises.push(putNode(nodes[i],opts.enabled)); | ||||
|                 } | ||||
|                 Promise.all(promises).then(function() { | ||||
|                     return resolve(runtime.nodes.getModuleInfo(mod)); | ||||
|                 }).catch(function(err) { | ||||
|                     err.status = 400; | ||||
|                     return reject(err); | ||||
|                 }); | ||||
|             } catch(err) { | ||||
|                 runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Enables or disables a n individual node-set in the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {String} opts.id - the id of the node-set to enable or disable | ||||
|     * @param {String} opts.enabled - whether the module should be enabled or disabled | ||||
|     * @return {Promise<ModuleInfo>} - the module info object | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     setNodeSetState: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             if (!runtime.settings.available()) { | ||||
|                 runtime.log.audit({event: "nodes.info.set",error:"settings_unavailable"}); | ||||
|                 let err = new Error("Settings unavailable"); | ||||
|                 err.code = "settings_unavailable"; | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|  | ||||
|             var id = opts.id; | ||||
|             var enabled = opts.enabled; | ||||
|             try { | ||||
|                 var node = runtime.nodes.getNodeInfo(id); | ||||
|                 if (!node) { | ||||
|                     runtime.log.audit({event: "nodes.info.set",id:id,error:"not_found"}); | ||||
|                     var err = new Error(); | ||||
|                     err.code = "not_found"; | ||||
|                     err.status = 404; | ||||
|                     return reject(err); | ||||
|                 } else { | ||||
|                     delete node.loaded; | ||||
|                     putNode(node,enabled).then(function(result) { | ||||
|                         runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled}); | ||||
|                         return resolve(result); | ||||
|                     }).catch(function(err) { | ||||
|                         runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                         err.status = 400; | ||||
|                         return reject(err); | ||||
|                     }); | ||||
|                 } | ||||
|             } catch(err) { | ||||
|                 runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                 res.status(400).json({error:err.code||"unexpected_error", message:err.toString()}); | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * TODO: getModuleCatalogs | ||||
|     */ | ||||
|     getModuleCatalogs: function() {}, | ||||
|     /** | ||||
|     * TODO: getModuleCatalog | ||||
|     */ | ||||
|     getModuleCatalog: function() {}, | ||||
|  | ||||
|     /** | ||||
|     * Gets the list of all icons available in the modules installed within the runtime | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<IconList>} - the list of all icons | ||||
|     * @memberof RED.nodes | ||||
|     */ | ||||
|     getIconList: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             runtime.log.audit({event: "nodes.icons.get"}); | ||||
|             return resolve(runtime.nodes.getNodeIcons()); | ||||
|         }); | ||||
|  | ||||
|     }, | ||||
|     /** | ||||
|     * TODO: getIcon | ||||
|     */ | ||||
|     getIcon: function() {} | ||||
| } | ||||
							
								
								
									
										257
									
								
								red/runtime-api/settings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								red/runtime-api/settings.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| /** | ||||
|  * Copyright JS Foundation and other contributors, http://js.foundation | ||||
|  * | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| /** | ||||
|  * @namespace RED.settings | ||||
|  */ | ||||
|  | ||||
| var util = require("util"); | ||||
| var runtime; | ||||
|  | ||||
| function extend(target, source) { | ||||
|     var keys = Object.keys(source); | ||||
|     var i = keys.length; | ||||
|     while(i--) { | ||||
|         var value = source[keys[i]] | ||||
|         var type = typeof value; | ||||
|         if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) { | ||||
|             target[keys[i]] = value; | ||||
|         } else if (value === null) { | ||||
|             if (target.hasOwnProperty(keys[i])) { | ||||
|                 delete target[keys[i]]; | ||||
|             } | ||||
|         } else { | ||||
|             // Object | ||||
|             if (target.hasOwnProperty(keys[i])) { | ||||
|                 target[keys[i]] = extend(target[keys[i]],value); | ||||
|             } else { | ||||
|                 target[keys[i]] = value; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return target; | ||||
| } | ||||
|  | ||||
| function getUsername(userObj) { | ||||
|     var username = '__default'; | ||||
|     if ( userObj && userObj.name ) { | ||||
|         username = userObj.name; | ||||
|     } | ||||
|     return username; | ||||
| } | ||||
| var api = module.exports = { | ||||
|     init: function(_runtime) { | ||||
|         runtime = _runtime; | ||||
|     }, | ||||
|     /** | ||||
|     * Gets the runtime settings object | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<Object>} - the runtime settings | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     getRuntimeSettings: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             try { | ||||
|             var safeSettings = { | ||||
|                 httpNodeRoot: runtime.settings.httpNodeRoot||"/", | ||||
|                 version: runtime.settings.version, | ||||
|                 user: opts.user | ||||
|             } | ||||
|  | ||||
|             if (util.isArray(runtime.settings.paletteCategories)) { | ||||
|                 safeSettings.paletteCategories = runtime.settings.paletteCategories; | ||||
|             } | ||||
|  | ||||
|             if (runtime.settings.flowFilePretty) { | ||||
|                 safeSettings.flowFilePretty = runtime.settings.flowFilePretty; | ||||
|             } | ||||
|  | ||||
|             if (!runtime.nodes.paletteEditorEnabled()) { | ||||
|                 safeSettings.editorTheme = safeSettings.editorTheme || {}; | ||||
|                 safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; | ||||
|                 safeSettings.editorTheme.palette.editable = false; | ||||
|             } | ||||
|             if (runtime.storage.projects) { | ||||
|                 var activeProject = runtime.storage.projects.getActiveProject(); | ||||
|                 if (activeProject) { | ||||
|                     safeSettings.project = activeProject; | ||||
|                 } else if (runtime.storage.projects.flowFileExists()) { | ||||
|                     safeSettings.files = { | ||||
|                         flow: runtime.storage.projects.getFlowFilename(), | ||||
|                         credentials: runtime.storage.projects.getCredentialsFilename() | ||||
|                     } | ||||
|                 } | ||||
|                 safeSettings.git = { | ||||
|                     globalUser: runtime.storage.projects.getGlobalGitUser() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); | ||||
|  | ||||
|             runtime.settings.exportNodeSettings(safeSettings); | ||||
|  | ||||
|             resolve(safeSettings); | ||||
|         }catch(err) { | ||||
|             console.log(err); | ||||
|         } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets an individual user's settings object | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<Object>} - the user settings | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     getUserSettings: function(opts) { | ||||
|         var username; | ||||
|         if (!opts.user || opts.user.anonymous) { | ||||
|             username = '_'; | ||||
|         } else { | ||||
|             username = opts.user.username; | ||||
|         } | ||||
|         return Promise.resolve(runtime.settings.getUserSettings(username)||{}); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Updates an individual user's settings object. | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {Object} opts.settings - the updates to the user settings | ||||
|     * @return {Promise<Object>} - the user settings | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     updateUserSettings: function(opts) { | ||||
|         var username; | ||||
|         if (!opts.user || opts.user.anonymous) { | ||||
|             username = '_'; | ||||
|         } else { | ||||
|             username = opts.user.username; | ||||
|         } | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var currentSettings = runtime.settings.getUserSettings(username)||{}; | ||||
|             currentSettings = extend(currentSettings, opts.settings); | ||||
|             try { | ||||
|                 runtime.settings.setUserSettings(username, currentSettings).then(function() { | ||||
|                     runtime.log.audit({event: "settings.update",username:username}); | ||||
|                     return resolve(); | ||||
|                 }).catch(function(err) { | ||||
|                     runtime.log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                     err.status = 400; | ||||
|                     return reject(err); | ||||
|                 }); | ||||
|             } catch(err) { | ||||
|                 log.warn(log._("settings.user-not-available",{message:log._("settings.not-available")})); | ||||
|                 log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()}); | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             } | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets a list of a user's ssh keys | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @return {Promise<Object>} - the user's ssh keys | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     getUserKeys: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var username = getUsername(opts.user); | ||||
|             runtime.storage.projects.ssh.listSSHKeys(username).then(function(list) { | ||||
|                 return resolve(list); | ||||
|             }).catch(function(err) { | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             }); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Gets a user's ssh public key | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {User} opts.id - the id of the key to return | ||||
|     * @return {Promise<String>} - the user's ssh public key | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     getUserKey: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var username = getUsername(opts.user); | ||||
|             // console.log('username:', username); | ||||
|             runtime.storage.projects.ssh.getSSHKey(username, opts.id).then(function(data) { | ||||
|                 if (data) { | ||||
|                     return resolve(data); | ||||
|                 } else { | ||||
|                     var err = new Error("Key not found"); | ||||
|                     err.code = "not_found"; | ||||
|                     err.status = 404; | ||||
|                     return reject(err); | ||||
|                 } | ||||
|             }).catch(function(err) { | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             }); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Generates a new ssh key pair | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {User} opts.name - the id of the key to return | ||||
|     * @param {User} opts.password - (optional) the password for the key pair | ||||
|     * @param {User} opts.comment - (option) a comment to associate with the key pair | ||||
|     * @param {User} opts.size - (optional) the size of the key. Default: 2048 | ||||
|     * @return {Promise<String>} - the id of the generated key | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     generateUserKey: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var username = getUsername(opts.user); | ||||
|             runtime.storage.projects.ssh.generateSSHKey(username, opts).then(function(name) { | ||||
|                 return resolve(name); | ||||
|             }).catch(function(err) { | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             }); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|     * Deletes a user's ssh key pair | ||||
|     * @param {Object} opts | ||||
|     * @param {User} opts.user - the user calling the api | ||||
|     * @param {User} opts.id - the id of the key to delete | ||||
|     * @return {Promise} - resolves when deleted | ||||
|     * @memberof RED.settings | ||||
|     */ | ||||
|     removeUserKey: function(opts) { | ||||
|         return new Promise(function(resolve,reject) { | ||||
|             var username = getUsername(req.user); | ||||
|             runtime.storage.projects.ssh.deleteSSHKey(username, opts.id).then(function() { | ||||
|                 return resolve(); | ||||
|             }).catch(function(err) { | ||||
|                 err.status = 400; | ||||
|                 return reject(err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -107,6 +107,11 @@ function getSSHKey(username, name) { | ||||
| function generateSSHKey(username, options) { | ||||
|     options = options || {}; | ||||
|     var name = options.name || ""; | ||||
|     if (!/^[a-zA-Z0-9\-_]+$/.test(options.name)) { | ||||
|         var err = new Error("Invalid SSH Key name"); | ||||
|         e.code = "invalid_key_name"; | ||||
|         return Promise.reject(err); | ||||
|     } | ||||
|     return checkExistSSHKeyFiles(username, name) | ||||
|         .then(function(result) { | ||||
|             if ( result ) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user