login.js 3.56 KB
var Configstore = require('configstore');
var GitHub = require('github');
var Q = require('q');

var createError = require('../util/createError');
var defaultConfig = require('../config');

function login(logger, options, config) {
    var configstore = new Configstore('bower-github');

    config = defaultConfig(config);

    var promise;

    options = options || {};

    if (options.token) {
        promise = Q.resolve({ token: options.token });
    } else {
        // This command requires interactive to be enabled
        if (!config.interactive) {
            logger.emit('error', createError('Login requires an interactive shell', 'ENOINT', {
                details: 'Note that you can manually force an interactive shell with --config.interactive'
            }));

            return;
        }

        var questions = [
            {
                'name': 'username',
                'message': 'Username',
                'type': 'input',
                'default': configstore.get('username')
            },
            {
                'name': 'password',
                'message': 'Password',
                'type': 'password'
            }
        ];

        var github = new GitHub({
            version: '3.0.0'
        });

        promise = Q.nfcall(logger.prompt.bind(logger), questions)
        .then(function (answers) {
            configstore.set('username', answers.username);

            github.authenticate({
                type: 'basic',
                username: answers.username,
                password: answers.password
            });

            return Q.ninvoke(github.authorization, 'create', {
                scopes: ['user', 'repo'],
                note: 'Bower command line client (' + (new Date()).toISOString() + ')'
            });
        });
    }

    return promise.then(function (result) {
        configstore.set('accessToken', result.token);
        logger.info('EAUTH', 'Logged in as ' + configstore.get('username'), {});

        return result;
    }, function (error) {
        var message;

        try {
            message = JSON.parse(error.message).message;
        } catch (e) {
            message = 'Authorization failed';
        }

        var questions = [
            {
                'name': 'otpcode',
                'message': 'Two-Factor Auth Code',
                'type': 'input'
            }
        ];

        if (message === 'Must specify two-factor authentication OTP code.') {
            return Q.nfcall(logger.prompt.bind(logger), questions)
            .then(function (answers) {
                return Q.ninvoke(github.authorization, 'create', {
                    scopes: ['user', 'repo'],
                    note: 'Bower command line client (' + (new Date()).toISOString() + ')',
                    headers: {
                        'X-GitHub-OTP': answers.otpcode
                    }
                });
            })
            .then(function (result) {
                configstore.set('accessToken', result.token);
                logger.info('EAUTH', 'Logged in as ' + configstore.get('username'), {});

                return result;
            }, function () {
                logger.emit('error', createError(message, 'EAUTH'));
            });
        } else {
            logger.emit('error', createError(message, 'EAUTH'));
        }
    });
}

// -------------------

login.readOptions = function (argv) {
    var cli = require('../util/cli');

    var options = cli.readOptions({
        token: { type: String, shorthand: 't' },
    }, argv);

    delete options.argv;

    return [options];
};

module.exports = login;