From b71c28cec0e1e7605e599eb5f9e1065f8f648bbd Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Sat, 12 Dec 2015 00:09:31 -0400 Subject: [PATCH] Add optional credential-based authentication --- build/actions/auth.js | 52 +++++++++++++++++++++++++++++++-- doc/cli.markdown | 18 ++++++++++++ lib/actions/auth.coffee | 64 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/build/actions/auth.js b/build/actions/auth.js index 1e7bd56f..53845057 100644 --- a/build/actions/auth.js +++ b/build/actions/auth.js @@ -2,25 +2,71 @@ 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\nExamples:\n\n $ resin login\n $ resin login --token "..."', + 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', options: [ { signature: 'token', description: 'auth token', parameter: 'token', alias: 't' + }, { + signature: 'credentials', + description: 'credential-based login', + boolean: true, + alias: 'c' + }, { + signature: 'email', + parameter: 'email', + description: 'email', + alias: ['e', 'u'] + }, { + signature: 'password', + parameter: 'password', + description: 'password', + alias: 'p' } ], primary: true, action: function(params, options, done) { - var Promise, auth, events, resin; + var Promise, auth, events, form, resin, validation; Promise = require('bluebird'); resin = require('resin-sdk'); events = require('resin-cli-events'); + form = require('resin-cli-form'); auth = require('resin-cli-auth'); - return Promise["try"](function() { + validation = require('../utils/validation'); + return resin.settings.get('resinUrl').then(function(resinUrl) { + console.log("Logging in to " + resinUrl); 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 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'); + }); + }); + }); } console.info('Connecting to the web dashboard'); return auth.login(); diff --git a/doc/cli.markdown b/doc/cli.markdown index 8a0bfd00..ef39dfae 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -172,10 +172,16 @@ 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. +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). + Examples: $ resin login $ resin login --token "..." + $ resin login --credentials + $ resin login --credentials --email johndoe@gmail.com --password secret ### Options @@ -183,6 +189,18 @@ Examples: auth token +#### --credentials, -c + +credential-based login + +#### --email, --e,u, --e,u <email> + +email + +#### --password, -p <password> + +password + ## logout Use this command to logout from your resin.io account.o diff --git a/lib/actions/auth.coffee b/lib/actions/auth.coffee index d34bd074..33dc8be6 100644 --- a/lib/actions/auth.coffee +++ b/lib/actions/auth.coffee @@ -11,27 +11,81 @@ exports.login = you can fetch your authentication token from the preferences page and pass the token option. + 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). + Examples: $ resin login $ resin login --token "..." + $ resin login --credentials + $ resin login --credentials --email johndoe@gmail.com --password secret ''' options: [ - signature: 'token' - description: 'auth token' - parameter: 'token' - alias: 't' + { + signature: 'token' + description: 'auth token' + parameter: 'token' + alias: 't' + } + { + signature: 'credentials' + description: 'credential-based login' + boolean: true + alias: 'c' + } + { + signature: 'email' + parameter: 'email' + description: 'email' + alias: [ 'e', 'u' ] + } + { + signature: 'password' + parameter: 'password' + description: 'password' + alias: 'p' + } ] primary: true action: (params, options, done) -> 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') + + resin.settings.get('resinUrl').then (resinUrl) -> + console.log("Logging in to #{resinUrl}") - Promise.try -> 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()