Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds User Keys #309

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 16 additions & 14 deletions lib/jitsu.js
Expand Up @@ -34,7 +34,7 @@ jitsu.use(flatiron.plugins.cli, {
string: true
},
jitsuconf: {
alias: 'j',
alias: 'j',
description: 'specify file to load configuration from',
string: true
},
Expand Down Expand Up @@ -69,7 +69,7 @@ jitsu.options.log = {
// Setup config, users, command aliases and prompt settings
//
jitsu.prompt.properties = flatiron.common.mixin(
jitsu.prompt.properties,
jitsu.prompt.properties,
require('./jitsu/properties')
);
jitsu.prompt.override = jitsu.argv;
Expand All @@ -95,6 +95,7 @@ jitsu.api.Databases = require('nodejitsu-api').Databases;
jitsu.api.Logs = require('nodejitsu-api').Logs;
jitsu.api.Snapshots = require('nodejitsu-api').Snapshots;
jitsu.api.Users = require('nodejitsu-api').Users;
jitsu.api.Keys = require('nodejitsu-api').Keys;

//
// ### function welcome ()
Expand All @@ -111,7 +112,7 @@ jitsu.welcome = function () {
// #### @callback {function} Continuation to pass control to when complete.
// Starts the jitsu CLI and runs the specified command.
//
jitsu.start = function (callback) {
jitsu.start = function (callback) {
//
// Check for --no-colors/--colors option, without hitting the config file
// yet
Expand All @@ -124,7 +125,7 @@ jitsu.start = function (callback) {
if (err) {
return callback();
}

jitsu.init(function (err) {
if (err) {
jitsu.welcome();
Expand Down Expand Up @@ -217,12 +218,13 @@ jitsu.exec = function (command, callback) {
// Sets up the instances of the Resource clients for jitsu.
// there is no io here, yet this function is ASYNC.
//
jitsu.setup = function (callback) {
jitsu.setup = function (callback) {
if (jitsu.started === true) {
return callback();
}

['Users', 'Apps', 'Snapshots', 'Databases', 'Logs'].forEach(function (key) {
['Users', 'Apps', 'Snapshots',
'Databases', 'Logs', 'Keys'].forEach(function (key) {
var k = key.toLowerCase();
jitsu[k] = new jitsu.api[key](jitsu.config);
jitsu[k].on('debug::request', debug);
Expand Down Expand Up @@ -258,12 +260,12 @@ jitsu.showError = function (command, err, shallow, skip) {
if (username) {
jitsu.log.error('Unable to authenticate as: ' + username.magenta);
}
jitsu.log.error('403 ' + err.result.error);

jitsu.log.error('403 ' + err.result.error);
}
else if (!skip) {
jitsu.log.error('Error running command ' + command.magenta);

if (!jitsu.config.get('nolog')) {
jitsu.logFile.log(err);
}
Expand All @@ -287,15 +289,15 @@ jitsu.showError = function (command, err, shallow, skip) {
jitsu.log.error('');
jitsu.log.error('This type of error is usually a ' + err.result.result.error.blame.type + ' error.');
}

jitsu.log.error('Error output from your application:');
jitsu.log.error('');
if (err.result.result.error.stdout) {
err.result.result.error.stdout.split('\n').forEach(function (line) {
jitsu.log.error(line);
});
}

if (err.result.result.error.stderr) {
err.result.result.error.stderr.split('\n').forEach(function (line) {
jitsu.log.error(line);
Expand All @@ -306,13 +308,13 @@ jitsu.showError = function (command, err, shallow, skip) {
jitsu.log.error('There was an error while attempting to deploy your application.');
jitsu.log.error('');
jitsu.log.error(err.result.result.error.message);

if (err.result.result.error.blame) {
jitsu.log.error(err.result.result.error.blame.message);
jitsu.log.error('');
jitsu.log.error('This type of error is usually a ' + err.result.result.error.blame.type + ' error.');
}
}

jitsu.log.error('Error output from Haibu:');
jitsu.log.error('');
stack = err.result.result.error.result || err.result.result.error.stack;
Expand Down
256 changes: 256 additions & 0 deletions lib/jitsu/commands/keys.js
@@ -0,0 +1,256 @@
/*
* keys.js: Commands related to user keys
*
* (C) 2010, Nodejitsu Inc.
*
*/

var jitsu = require('../../jitsu'),
fs = require('fs');

var keys = exports;

//
// ### function create (keyName, file, callback)
// #### @keyName {string} Desired key name
// #### @file {string} Path to public key file
// #### @callback {function} Continuation to pass control to when complete.
// Attempt to create a key on the user's behalf.
//
keys.create = function (keyName, file, callback) {
var user = jitsu.config.get('username');
var data = { name: keyName };

function checkType() {
jitsu.log.info('Type of key? ' + '(api/ssh)'.magenta);
jitsu.prompt.get(['type'], function (err, result) {
if (result.type === 'ssh') {
jitsu.log.info('Please enter location of public key.');
jitsu.log.info(
'~/.ssh/id_rsa.pub'.magenta
+ ' will be used by default.');
return jitsu.prompt.get(['file'], function (err, result) {
if (err) return callback(err);
file = result.file || jitsu.config.get('root') + '/.ssh/id_rsa.pub';
return checkTTL(readKey);
});
}
return checkTTL(function() {
jitsu.log.info('Generating API key.');
return createKey();
});
});
}

function checkTTL(next) {
if (data.ttl == null) {
jitsu.log.info('Time-to-live? Enter a date.');
return jitsu.prompt.get(['ttl'], function(err, result) {
if (err) return callback(err);

var ttl = new Date(result.ttl);
if (ttl + '' === 'Invalid Date'
|| isNaN(+ttl)
|| ttl < new Date) {
return next();
}

data.ttl = ttl - new Date;

return next();
});
}
return next();
}

function readKey() {
fs.readFile(file, 'utf8', function(err, val) {
if (err) return callback(err);

if (/private key/i.test(val)) {
jitsu.log.error(
'Private key detected. Stopping.'
+ ' Are you sure this is a'
+ ' public'.bold + ' key?');
return callback(new Error(), true);
}

data.value = val;

jitsu.log.info('Uploading public key.');
return createKey();
});
}

function createKey() {
jitsu.keys.create(user + '/keys/' + keyName, data, function (err, response) {
if (err) return callback(err);
jitsu.log.info('Key successfully created.');
return callback();
});
}

if (!user) {
return jitsu.commands.users.login(function (err) {
if (err) return callback(err, true);
return keys.create(keyName, file, callback);
});
}

if (!keyName) {
jitsu.log.info('Please enter a name for your key.');
return jitsu.prompt.get(['name'], function(err, result) {
return err
? callback(err)
: keys.create(result.name, file, callback);
});
}

// If there is a file path,
// we can assume it is a public key.
return file
? readKey()
: checkType();
};

//
// Usage for `jitsu keys create`.
//
keys.create.usage = [
'Adds a key to jitsu, if no file is specified, generate random API key.',
'',
'jitsu keys create',
'jitsu keys create <name>',
'jitsu keys create <name> <file>'
];

//
// ### function list (callback)
// #### @callback {function} Continuation to pass control to when complete.
// Attempt to list all keys bound to the user.
//
keys.list = function (callback) {
var user = jitsu.config.get('username');

if (!user) {
return jitsu.commands.users.login(function (err) {
if (err) return callback(err, true);
return keys.list(keyName, callback);
});
}

jitsu.keys.list(user, function (err, keys) {
if (err) return callback(err);

var rows = [['name', 'type', 'value', 'ttl']],
colors = ['underline', 'underline', 'underline', 'underline'];

Object.keys(keys).forEach(function (k) {
var key = keys[k];
rows.push([
k,
key.type,
key.value.substring(0, 40),
key.ttl || 'none'
]);
});

jitsu.inspect.putRows('data', rows, colors);

return callback();
});
};

//
// Usage for `jitsu keys list`.
//
keys.list.usage = [
'List all API and SSH keys.',
'',
'jitsu keys list'
];

//
// ### function view (keyName callback)
// #### @keyName {string} Name of the key
// #### @callback {function} Continuation to pass control to when complete.
// Attempt to return a key.
//
keys.view = function (keyName, callback) {
var user = jitsu.config.get('username');

if (!user) {
return jitsu.commands.users.login(function (err) {
if (err) return callback(err, true);
return keys.view(keyName, callback);
});
}

if (!keyName) {
jitsu.log.info('Please enter a name for your key.');
return jitsu.prompt.get(['name'], function(err, result) {
return err
? callback(err)
: keys.view(result.name, callback);
});
}

jitsu.keys.view(user + '/keys/' + keyName, function (err, key) {
if (err) return callback(err);
jitsu.inspect.putObject(key);
return callback();
});
};

//
// Usage for `jitsu keys view`.
//
keys.view.usage = [
'View a specific API or SSH key by name.',
'',
'jitsu keys view',
'jitsu keys view <name>'
];

//
// ### function delete (keyName, callback)
// #### @keyName {string} Name of the key
// #### @callback {function} Continuation to pass control to when complete.
// Attempt to return a key.
//
keys.delete = function (keyName, callback) {
var user = jitsu.config.get('username');

if (!user) {
return jitsu.commands.users.login(function (err) {
if (err) return callback(err, true);
return keys.delete(keyName, callback);
});
}

if (!keyName) {
jitsu.log.info('Please enter a name for your key.');
return jitsu.prompt.get(['name'], function(err, result) {
return err
? callback(err)
: keys.delete(result.name, callback);
});
}

// fix this ins nodejitsu-api
jitsu.keys.destroy(user + '/keys/' + keyName, function (err) {
if (err) return callback(err);
jitsu.log.help('Key deleted successfully.');
return callback();
});
};

//
// Usage for `jitsu keys delete`.
//
keys.delete.usage = [
'Delete the specified API or SSH key.',
'',
'jitsu keys delete',
'jitsu keys delete <name>'
];
13 changes: 13 additions & 0 deletions lib/jitsu/completion.js
Expand Up @@ -73,6 +73,12 @@ var complete = require('complete'),
// jitsu help users
// jitsu help wizard

// jitsu keys [<commands>]
// jitsu keys create <name> <file>
// jitsu keys list
// jitsu keys view <name>
// jitsu keys delete <name>

// jitsu signup
// jitsu login
// jitsu logout
Expand Down Expand Up @@ -328,6 +334,13 @@ var commands = {
'wizard': {}
},

'keys': {
'create': {},
'list': {},
'view': {},
'delete': {}
},

'signup': {},
'login': {},
'logout': {},
Expand Down