mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Refactoring ssh-keygen function (#1533)
This commit is contained in:
		
				
					committed by
					
						 Nick O'Leary
						Nick O'Leary
					
				
			
			
				
	
			
			
			
						parent
						
							9c350311e8
						
					
				
				
					commit
					5a6cde1446
				
			| @@ -59,7 +59,6 @@ | ||||
|         "raw-body":"2.2.0", | ||||
|         "semver": "5.3.0", | ||||
|         "sentiment":"2.1.0", | ||||
|         "ssh-keygen":"0.4.1", | ||||
|         "uglify-js":"3.0.20", | ||||
|         "when": "3.7.8", | ||||
|         "ws": "1.1.1", | ||||
|   | ||||
| @@ -23,6 +23,7 @@ var crypto = require('crypto'); | ||||
| var storageSettings = require("../settings"); | ||||
| var util = require("../util"); | ||||
| var gitTools = require("./git"); | ||||
| var sshTools = require("./ssh"); | ||||
|  | ||||
| var Projects = require("./Project"); | ||||
|  | ||||
| @@ -89,6 +90,7 @@ function init(_settings, _runtime) { | ||||
|                 projectsEnabled = false; | ||||
|             } else { | ||||
|                 Projects.init(settings,runtime); | ||||
|                 sshTools.init(settings,runtime); | ||||
|                 projectsDir = fspath.join(settings.userDir,"projects"); | ||||
|                 if (!settings.readOnly) { | ||||
|                     return fs.ensureDir(projectsDir) | ||||
|   | ||||
							
								
								
									
										80
									
								
								red/runtime/storage/localfilesystem/projects/ssh.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								red/runtime/storage/localfilesystem/projects/ssh.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| /** | ||||
|  * 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. | ||||
|  **/ | ||||
|  | ||||
| var exec = require('child_process').exec; | ||||
| var spawn = require('child_process').spawn; | ||||
|  | ||||
| var sshkeygenCommand = "ssh-keygen"; | ||||
|  | ||||
| var log; | ||||
|  | ||||
| function runSshKeygenCommand(args,cwd,env) { | ||||
|     // console.log("[run ssh-keygen] args:", args); | ||||
|     return new Promise(function(resolve, reject) { | ||||
|         var child = spawn(sshkeygenCommand, args, {cwd: cwd, detached: true, env: env}); | ||||
|         var stdout = ""; | ||||
|         var stderr = ""; | ||||
|  | ||||
|         child.stdout.on('data', function(data) { | ||||
|             stdout += data; | ||||
|         }); | ||||
|         child.stderr.on('data', function(data) { | ||||
|             stderr += data; | ||||
|         }); | ||||
|         child.on('close', function(code, signal) { | ||||
|             if (code !== 0) { | ||||
|                 var err = new Error(stderr); | ||||
|                 err.stdout = stdout; | ||||
|                 err.stderr = stderr; | ||||
|                 if (/passphrase is too short/.test(stderr)) { | ||||
|                     err.code = "key_passphrase_too_short"; | ||||
|                 } else if(/Key must at least be 1024 bits/.test(stderr)) { | ||||
|                     err.code = "key_length_too_short"; | ||||
|                 } | ||||
|                 reject(err); | ||||
|             } | ||||
|             else { | ||||
|                 resolve(stdout); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function init(_settings, _runtime) { | ||||
|     log = _runtime.log; | ||||
| } | ||||
|  | ||||
| function generateKey(options) { | ||||
|     var args = ['-q', '-t', 'rsa']; | ||||
|     if (options.size) { | ||||
|         args.push('-b', options.size); | ||||
|     } | ||||
|     if (options.location) { | ||||
|         args.push('-f', options.location); | ||||
|     } | ||||
|     if (options.comment) { | ||||
|         args.push('-C', options.comment); | ||||
|     } | ||||
|     if (options.password) { | ||||
|         args.push('-N', options.password); | ||||
|     } | ||||
|     return runSshKeygenCommand(args,__dirname); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: init, | ||||
|     generateKey: generateKey, | ||||
| }; | ||||
| @@ -17,7 +17,7 @@ | ||||
| var fs = require('fs-extra'); | ||||
| var when = require('when'); | ||||
| var fspath = require("path"); | ||||
| var keygen = require('ssh-keygen'); | ||||
| var sshTools = require("./projects/ssh"); | ||||
|  | ||||
| var settings; | ||||
| var runtime; | ||||
| @@ -97,26 +97,12 @@ function generateSSHKey(username, options) { | ||||
|             } else { | ||||
|                 var comment = options.comment || ""; | ||||
|                 var password = options.password || ""; | ||||
|                 if (password.length > 0 && password.length < 5) { | ||||
|                     var e2 = new Error("SSH Key passphrase too short"); | ||||
|                     e2.code = "key_passphrase_too_short"; | ||||
|                     throw e2; | ||||
|                 } | ||||
|                 var size = options.size || 2048; | ||||
|                 var sshKeyFileBasename = username + '_' + name; | ||||
|                 var privateKeyFilePath = fspath.join(sshkeyDir, sshKeyFileBasename); | ||||
|                 return generateSSHKeyPair(name, privateKeyFilePath, comment, password, size) | ||||
|             } | ||||
|         }) | ||||
|         // .then(function(keyfile_name) { | ||||
|         //     return checkSSHKeyFileAndGetPublicKeyFileName(username, name) | ||||
|         //         .then(function() { | ||||
|         //             return keyfile_name; | ||||
|         //         }) | ||||
|         //         .catch(function(err) { | ||||
|         //             throw new Error('Failed to generate ssh key files'); | ||||
|         //         }); | ||||
|         // }); | ||||
| } | ||||
|  | ||||
| function deleteSSHKey(username, name) { | ||||
| @@ -162,27 +148,22 @@ function deleteSSHKeyFiles(username, name) { | ||||
|     return Promise.all([ | ||||
|         fs.remove(privateKeyFilePath), | ||||
|         fs.remove(publicKeyFilePath) | ||||
|     ]); | ||||
|     ]) | ||||
|     .then(function() { | ||||
|         return true; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function generateSSHKeyPair(name, privateKeyPath, comment, password, size) { | ||||
|     log.trace("ssh-keygen["+[name,privateKeyPath,comment,size,"hasPassword?"+!!password].join(",")+"]"); | ||||
|     return new Promise(function(resolve, reject) { | ||||
|         keygen({ | ||||
|             location: privateKeyPath, | ||||
|             comment: comment, | ||||
|             password: password, | ||||
|             size: size | ||||
|         }, function(err, out) { | ||||
|             if ( err ) { | ||||
|                 err.code = "key_generation_failed"; | ||||
|                 reject(err); | ||||
|             } | ||||
|             else { | ||||
|                 resolve(name); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|     return sshTools.generateKey({location: privateKeyPath, comment: comment, password: password, size: size}) | ||||
|             .then(function(stdout) { | ||||
|                 return name; | ||||
|             }) | ||||
|             .catch(function(err) { | ||||
|                 log.log('[SSHKey generation] error:', err); | ||||
|                 throw err; | ||||
|             }); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   | ||||
| @@ -29,6 +29,7 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         log:{ | ||||
|             _:function() { return "placeholder message"}, | ||||
|             info: function() { }, | ||||
|             log: function() { }, | ||||
|             trace: function() { } | ||||
|         } | ||||
|     }; | ||||
| @@ -61,7 +62,6 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         localfilesystem.init(mockSettings, mockRuntime).then(function() { | ||||
|             sshkeys.init(mockSettings, mockRuntime).then(function() { | ||||
|                 sshkeys.listSSHKeys(username).then(function(retObj) { | ||||
|                     console.log('retObj:', retObj); | ||||
|                     retObj.should.be.instanceOf(Array).and.have.lengthOf(0); | ||||
|                     done(); | ||||
|                 }).catch(function(err) { | ||||
| @@ -246,7 +246,31 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             email: 'test@test.com', | ||||
|             name: 'test-key01' | ||||
|         }; | ||||
|         localfilesystem.init(mockSettings, mockRuntime).then(function() { | ||||
|             sshkeys.init(mockSettings, mockRuntime).then(function() { | ||||
|                 sshkeys.generateSSHKey(username, options).then(function(retObj) { | ||||
|                     retObj.should.be.equal(options.name); | ||||
|                     fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true(); | ||||
|                     fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true(); | ||||
|                     done(); | ||||
|                 }).catch(function(err) { | ||||
|                     done(err); | ||||
|                 }); | ||||
|             }).catch(function(err) { | ||||
|                 done(err); | ||||
|             }); | ||||
|         }).catch(function(err) { | ||||
|             done(err); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     it('should generate sshkey file with only comment data', function(done) { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01' | ||||
|         }; | ||||
|         localfilesystem.init(mockSettings, mockRuntime).then(function() { | ||||
| @@ -271,7 +295,7 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             email: 'test@test.com', | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01', | ||||
|             password: 'testtest' | ||||
|         }; | ||||
| @@ -297,7 +321,7 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             email: 'test@test.com', | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01', | ||||
|             size: 4096 | ||||
|         }; | ||||
| @@ -324,7 +348,7 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             email: 'test@test.com', | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01', | ||||
|             password: 'testtest', | ||||
|             size: 4096 | ||||
| @@ -352,19 +376,52 @@ describe("storage/localfilesystem/sshkeys", function() { | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             email: 'test@test.com', | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01', | ||||
|             size: 3333 | ||||
|             size: 1023 | ||||
|         }; | ||||
|         localfilesystem.init(mockSettings, mockRuntime).then(function() { | ||||
|             sshkeys.init(mockSettings, mockRuntime).then(function() { | ||||
|                 sshkeys.generateSSHKey(username, options).then(function(retObj) { | ||||
|                     retObj.should.be.equal(options.name); | ||||
|                     fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true(); | ||||
|                     fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true(); | ||||
|                     done(); | ||||
|                     done(new Error('Does NOT throw error!')); | ||||
|                 }).catch(function(err) { | ||||
|                     done(err); | ||||
|                     try { | ||||
|                         err.should.have.have.property('code', 'key_length_too_short'); | ||||
|                         done(); | ||||
|                     } | ||||
|                     catch (error) { | ||||
|                         done(error); | ||||
|                     } | ||||
|                 }); | ||||
|             }).catch(function(err) { | ||||
|                 done(err); | ||||
|             }); | ||||
|         }).catch(function(err) { | ||||
|             done(err); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     it('should not generate sshkey file with illegal password', function(done) { | ||||
|         this.timeout(5000); | ||||
|         var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys'); | ||||
|         var username = 'test'; | ||||
|         var options = { | ||||
|             comment: 'test@test.com', | ||||
|             name: 'test-key01', | ||||
|             password: 'aa' | ||||
|         }; | ||||
|         localfilesystem.init(mockSettings, mockRuntime).then(function() { | ||||
|             sshkeys.init(mockSettings, mockRuntime).then(function() { | ||||
|                 sshkeys.generateSSHKey(username, options).then(function(retObj) { | ||||
|                     done(new Error('Does NOT throw error!')); | ||||
|                 }).catch(function(err) { | ||||
|                     try { | ||||
|                         err.should.have.have.property('code', 'key_passphrase_too_short'); | ||||
|                         done(); | ||||
|                     } | ||||
|                     catch (error) { | ||||
|                         done(error); | ||||
|                     } | ||||
|                 }); | ||||
|             }).catch(function(err) { | ||||
|                 done(err); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user