Merge pull request #242 from resin-io/jviotti/feature/us-pw-login

Implement user/password login with 2FA support
This commit is contained in:
Juan Cruz Viotti 2015-10-21 09:32:17 -04:00
commit ec72f93480
5 changed files with 100 additions and 76 deletions

View File

@ -1,52 +1,65 @@
(function() {
var Promise, _, events, form, open, resin, url, validEmail, visuals;
var Promise, _, events, form, helpers, resin, visuals;
Promise = require('bluebird');
open = Promise.promisify(require('open'));
_ = require('lodash');
url = require('url');
resin = require('resin-sdk');
form = require('resin-cli-form');
visuals = require('resin-cli-visuals');
validEmail = require('valid-email');
events = require('resin-cli-events');
helpers = require('../utils/helpers');
exports.login = {
signature: 'login [token]',
signature: 'login',
description: 'login to resin.io',
help: 'Use this command to login to your resin.io account.\n\nTo login, you need your token, which is accesible from the preferences page.\n\nExamples:\n\n $ resin login\n $ resin login "eyJ0eXAiOiJKV1Qi..."',
help: 'Use this command to login to your resin.io account.\n\nExamples:\n\n $ resin login',
options: [
{
signature: 'email',
parameter: 'email',
description: 'email',
alias: ['e', 'u']
}, {
signature: 'password',
parameter: 'password',
description: 'password',
alias: 'p'
}
],
primary: true,
action: function(params, options, done) {
return resin.settings.get('dashboardUrl').then(function(dashboardUrl) {
return url.resolve(dashboardUrl, '/preferences');
}).then(function(preferencesUrl) {
if (params.token != null) {
return params.token;
return form.run([
{
message: 'Email:',
name: 'email',
type: 'input',
validate: helpers.validateEmail
}, {
message: 'Password:',
name: 'password',
type: 'password'
}
], {
override: options
}).then(resin.auth.login).then(resin.auth.twoFactor.isPassed).then(function(isTwoFactorAuthPassed) {
if (isTwoFactorAuthPassed) {
return;
}
console.info("To login to the Resin CLI, you need your unique token, which is accesible from\nthe preferences page at " + preferencesUrl + "\n\nAttempting to open a browser at that location...");
return open(preferencesUrl)["catch"](function() {
return console.error("Unable to open a web browser in the current environment.\nPlease visit " + preferencesUrl + " manually.");
}).then(function() {
return form.ask({
message: 'What\'s your token? (visible in the preferences page)',
message: 'Two factor auth challenge:',
name: 'code',
type: 'input'
}).then(resin.auth.twoFactor.challenge)["catch"](function() {
return resin.auth.logout().then(function() {
throw new Error('Invalid two factor authentication code');
});
});
}).then(resin.auth.loginWithToken).then(function(token) {
return resin.auth.isLoggedIn().then(function(isLoggedIn) {
if (isLoggedIn) {
return token;
}
throw new Error('Authentication failed');
});
}).then(resin.auth.whoami).tap(function(username) {
console.info("Successfully logged in as: " + username);
return events.send('user.login');
@ -76,12 +89,7 @@
message: 'Email:',
name: 'email',
type: 'input',
validate: function(input) {
if (!validEmail(input)) {
return 'Email is not valid';
}
return true;
}
validate: helpers.validateEmail
}, {
message: 'Username:',
name: 'username',

View File

@ -1,5 +1,5 @@
(function() {
var Promise, _, capitano, chalk, child_process, os;
var Promise, _, capitano, chalk, child_process, os, validEmail;
Promise = require('bluebird');
@ -15,12 +15,21 @@
chalk = require('chalk');
validEmail = require('valid-email');
exports.getGroupDefaults = function(group) {
return _.chain(group).get('options').map(function(question) {
return [question.name, question["default"]];
}).object().value();
};
exports.validateEmail = function(input) {
if (!validEmail(input)) {
return 'Email is not valid';
}
return true;
};
exports.getOperatingSystem = function() {
var platform;
platform = os.platform();

View File

@ -1,55 +1,60 @@
Promise = require('bluebird')
open = Promise.promisify(require('open'))
_ = require('lodash')
url = require('url')
resin = require('resin-sdk')
form = require('resin-cli-form')
visuals = require('resin-cli-visuals')
validEmail = require('valid-email')
events = require('resin-cli-events')
helpers = require('../utils/helpers')
exports.login =
signature: 'login [token]'
signature: 'login'
description: 'login to resin.io'
help: '''
Use this command to login to your resin.io account.
To login, you need your token, which is accesible from the preferences page.
Examples:
$ resin login
$ resin login "eyJ0eXAiOiJKV1Qi..."
'''
options: [
{
signature: 'email'
parameter: 'email'
description: 'email'
alias: [ 'e', 'u' ]
}
{
signature: 'password'
parameter: 'password'
description: 'password'
alias: 'p'
}
]
primary: true
action: (params, options, done) ->
resin.settings.get('dashboardUrl').then (dashboardUrl) ->
return url.resolve(dashboardUrl, '/preferences')
.then (preferencesUrl) ->
return params.token if params.token?
console.info """
To login to the Resin CLI, you need your unique token, which is accesible from
the preferences page at #{preferencesUrl}
Attempting to open a browser at that location...
"""
open(preferencesUrl).catch ->
console.error """
Unable to open a web browser in the current environment.
Please visit #{preferencesUrl} manually.
"""
.then ->
form.ask
message: 'What\'s your token? (visible in the preferences page)'
form.run [
message: 'Email:'
name: 'email'
type: 'input'
.then(resin.auth.loginWithToken)
.then (token) ->
resin.auth.isLoggedIn().then (isLoggedIn) ->
return token if isLoggedIn
throw new Error('Authentication failed')
validate: helpers.validateEmail
,
message: 'Password:'
name: 'password'
type: 'password'
],
override: options
.then(resin.auth.login)
.then(resin.auth.twoFactor.isPassed)
.then (isTwoFactorAuthPassed) ->
return if isTwoFactorAuthPassed
return form.ask
message: 'Two factor auth challenge:'
name: 'code'
type: 'input'
.then(resin.auth.twoFactor.challenge)
.catch ->
resin.auth.logout().then ->
throw new Error('Invalid two factor authentication code')
.then(resin.auth.whoami)
.tap (username) ->
console.info("Successfully logged in as: #{username}")
@ -95,11 +100,7 @@ exports.signup =
message: 'Email:'
name: 'email'
type: 'input'
validate: (input) ->
if not validEmail(input)
return 'Email is not valid'
return true
validate: helpers.validateEmail
,
message: 'Username:'
name: 'username'

View File

@ -5,6 +5,7 @@ _.str = require('underscore.string')
child_process = require('child_process')
os = require('os')
chalk = require('chalk')
validEmail = require('valid-email')
exports.getGroupDefaults = (group) ->
return _.chain(group)
@ -14,6 +15,12 @@ exports.getGroupDefaults = (group) ->
.object()
.value()
exports.validateEmail = (input) ->
if not validEmail(input)
return 'Email is not valid'
return true
exports.getOperatingSystem = ->
platform = os.platform()
platform = 'osx' if platform is 'darwin'

View File

@ -48,7 +48,6 @@
"mkdirp": "~0.5.0",
"nplugm": "^3.0.0",
"npm": "^2.13.0",
"open": "0.0.5",
"resin-cli-errors": "^1.0.0",
"resin-cli-events": "^1.0.2",
"resin-cli-form": "^1.3.0",
@ -58,7 +57,7 @@
"resin-image": "^1.1.4",
"resin-image-manager": "^3.2.2",
"resin-pine": "^1.3.0",
"resin-sdk": "^3.0.0",
"resin-sdk": "^4.0.0",
"resin-settings-client": "^3.1.0",
"resin-vcs": "^2.0.0",
"rimraf": "^2.4.3",