1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Refactoring ssh-keygen function (#1533)

This commit is contained in:
Hideki Nakamura 2018-01-06 01:12:01 +09:00 committed by Nick O'Leary
parent 9c350311e8
commit 5a6cde1446
5 changed files with 164 additions and 45 deletions

View File

@ -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",

View File

@ -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)

View 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,
};

View File

@ -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 = {

View File

@ -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);