Implement purely interactive login command

The new login command interactively asks the user if he wants to login
using web/credentials/token.
This commit is contained in:
Juan Cruz Viotti 2016-01-12 09:07:15 -04:00
parent 70ea8dd1a3
commit 8d709aea7d
5 changed files with 166 additions and 79 deletions

View File

@ -19,13 +19,18 @@ limitations under the License.
exports.login = {
signature: 'login',
description: 'login to resin.io',
help: 'Use this command to login to your resin.io account.\n\nThis command will open your web browser and prompt you to authorize the CLI\nfrom the dashboard.\n\nIf you don\'t have access to a web browser (e.g: running in a headless server),\nyou can fetch your authentication token from the preferences page and pass\nthe token option.\n\nAlternatively, you can pass the `--credentials` boolean option to perform\na credential-based authentication, with optional `--email` and `--password`\noptions to avoid interactive behaviour (unless you have 2FA enabled).\n\nExamples:\n\n $ resin login\n $ resin login --token "..."\n $ resin login --credentials\n $ resin login --credentials --email johndoe@gmail.com --password secret',
help: 'Use this command to login to your resin.io account.\n\nThis command will prompt you to login using the following login types:\n\n- Web authorization: open your web browser and prompt you to authorize the CLI\nfrom the dashboard.\n\n- Credentials: using email/password and 2FA.\n\n- Token: using the authentication token from the preferences page.\n\nExamples:\n\n $ resin login\n $ resin login --web\n $ resin login --token "..."\n $ resin login --credentials\n $ resin login --credentials --email johndoe@gmail.com --password secret',
options: [
{
signature: 'token',
description: 'auth token',
parameter: 'token',
alias: 't'
}, {
signature: 'web',
description: 'web-based login',
boolean: true,
alias: 'w'
}, {
signature: 'credentials',
description: 'credential-based login',
@ -45,48 +50,40 @@ limitations under the License.
],
primary: true,
action: function(params, options, done) {
var Promise, auth, events, form, resin, validation;
var Promise, _, auth, events, form, login, patterns, resin;
_ = require('lodash');
Promise = require('bluebird');
resin = require('resin-sdk');
events = require('resin-cli-events');
form = require('resin-cli-form');
auth = require('resin-cli-auth');
validation = require('../utils/validation');
return resin.settings.get('resinUrl').then(function(resinUrl) {
console.log("Logging in to " + resinUrl);
form = require('resin-cli-form');
patterns = require('../utils/patterns');
login = function(options) {
if (options.token != null) {
return resin.auth.loginWithToken(options.token);
} else if (options.credentials) {
return form.run([
{
message: 'Email:',
name: 'email',
type: 'input',
validate: validation.validateEmail
}, {
message: 'Password:',
name: 'password',
type: 'password'
}
], {
override: options
}).then(resin.auth.login).then(resin.auth.twoFactor.isPassed).then(function(isTwoFactorAuthPassed) {
if (isTwoFactorAuthPassed) {
return;
return Promise["try"](function() {
if (_.isString(options.token)) {
return options.token;
}
return form.ask({
message: 'Two factor auth challenge:',
name: 'code',
message: 'Token (from the preferences page)',
name: 'token',
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);
} else if (options.credentials) {
return patterns.authenticate(options);
} else if (options.web) {
console.info('Connecting to the web dashboard');
return auth.login();
}
console.info('Connecting to the web dashboard');
return auth.login();
return patterns.askLoginType().then(function(loginType) {
options[loginType] = true;
return login(options);
});
};
return resin.settings.get('resinUrl').then(function(resinUrl) {
console.log("Logging in to " + resinUrl);
return login(options);
}).then(resin.auth.whoami).tap(function(username) {
console.info("Successfully logged in as: " + username);
return events.send('user.login');

View File

@ -32,6 +32,56 @@ limitations under the License.
validation = require('./validation');
exports.authenticate = function(options) {
return form.run([
{
message: 'Email:',
name: 'email',
type: 'input',
validate: validation.validateEmail
}, {
message: 'Password:',
name: 'password',
type: 'password'
}
], {
override: options
}).then(resin.auth.login).then(resin.auth.twoFactor.isPassed).then(function(isTwoFactorAuthPassed) {
if (isTwoFactorAuthPassed) {
return;
}
return form.ask({
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');
});
});
});
};
exports.askLoginType = function() {
return form.ask({
message: 'How would you like to login?',
name: 'loginType',
type: 'list',
choices: [
{
name: 'Web authorization (recommended)',
value: 'web'
}, {
name: 'Credentials',
value: 'credentials'
}, {
name: 'Authentication token',
value: 'token'
}
]
});
};
exports.selectDeviceType = function() {
return resin.models.device.getSupportedDeviceTypes().then(function(deviceTypes) {
return form.ask({

View File

@ -165,20 +165,19 @@ confirm non interactively
Use this command to login to your resin.io account.
This command will open your web browser and prompt you to authorize the CLI
This command will prompt you to login using the following login types:
- Web authorization: open your web browser and prompt you to authorize the CLI
from the dashboard.
If you don't have access to a web browser (e.g: running in a headless server),
you can fetch your authentication token from the preferences page and pass
the token option.
- Credentials: using email/password and 2FA.
Alternatively, you can pass the `--credentials` boolean option to perform
a credential-based authentication, with optional `--email` and `--password`
options to avoid interactive behaviour (unless you have 2FA enabled).
- Token: using the authentication token from the preferences page.
Examples:
$ resin login
$ resin login --web
$ resin login --token "..."
$ resin login --credentials
$ resin login --credentials --email johndoe@gmail.com --password secret
@ -189,6 +188,10 @@ Examples:
auth token
#### --web, -w
web-based login
#### --credentials, -c
credential-based login

View File

@ -20,20 +20,19 @@ exports.login =
help: '''
Use this command to login to your resin.io account.
This command will open your web browser and prompt you to authorize the CLI
This command will prompt you to login using the following login types:
- Web authorization: open your web browser and prompt you to authorize the CLI
from the dashboard.
If you don't have access to a web browser (e.g: running in a headless server),
you can fetch your authentication token from the preferences page and pass
the token option.
- Credentials: using email/password and 2FA.
Alternatively, you can pass the `--credentials` boolean option to perform
a credential-based authentication, with optional `--email` and `--password`
options to avoid interactive behaviour (unless you have 2FA enabled).
- Token: using the authentication token from the preferences page.
Examples:
$ resin login
$ resin login --web
$ resin login --token "..."
$ resin login --credentials
$ resin login --credentials --email johndoe@gmail.com --password secret
@ -45,6 +44,12 @@ exports.login =
parameter: 'token'
alias: 't'
}
{
signature: 'web'
description: 'web-based login'
boolean: true
alias: 'w'
}
{
signature: 'credentials'
description: 'credential-based login'
@ -66,45 +71,36 @@ exports.login =
]
primary: true
action: (params, options, done) ->
_ = require('lodash')
Promise = require('bluebird')
resin = require('resin-sdk')
events = require('resin-cli-events')
form = require('resin-cli-form')
auth = require('resin-cli-auth')
validation = require('../utils/validation')
form = require('resin-cli-form')
patterns = require('../utils/patterns')
login = (options) ->
if options.token?
return Promise.try ->
return options.token if _.isString(options.token)
return form.ask
message: 'Token (from the preferences page)'
name: 'token'
type: 'input'
.then(resin.auth.loginWithToken)
else if options.credentials
return patterns.authenticate(options)
else if options.web
console.info('Connecting to the web dashboard')
return auth.login()
return patterns.askLoginType().then (loginType) ->
options[loginType] = true
return login(options)
resin.settings.get('resinUrl').then (resinUrl) ->
console.log("Logging in to #{resinUrl}")
if options.token?
return resin.auth.loginWithToken(options.token)
else if options.credentials
return form.run [
message: 'Email:'
name: 'email'
type: 'input'
validate: validation.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')
console.info('Connecting to the web dashboard')
return auth.login()
return login(options)
.then(resin.auth.whoami)
.tap (username) ->
console.info("Successfully logged in as: #{username}")

View File

@ -22,6 +22,47 @@ resin = require('resin-sdk')
chalk = require('chalk')
validation = require('./validation')
exports.authenticate = (options) ->
return form.run [
message: 'Email:'
name: 'email'
type: 'input'
validate: validation.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')
exports.askLoginType = ->
return form.ask
message: 'How would you like to login?'
name: 'loginType'
type: 'list'
choices: [
name: 'Web authorization (recommended)'
value: 'web'
,
name: 'Credentials'
value: 'credentials'
,
name: 'Authentication token'
value: 'token'
]
exports.selectDeviceType = ->
resin.models.device.getSupportedDeviceTypes().then (deviceTypes) ->
return form.ask