Skip to content

Commit

Permalink
Add support for two-factor authentication for login
Browse files Browse the repository at this point in the history
  • Loading branch information
sheerun committed Mar 30, 2015
1 parent 1a7abfd commit 0f68da4
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 11 deletions.
38 changes: 37 additions & 1 deletion lib/commands/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,43 @@ function login(logger, options, config) {

return result;
}, function (error) {
logger.error('login error', 'Could not authenticate');
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);

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

Expand Down
47 changes: 37 additions & 10 deletions test/commands/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ var helpers = require('../helpers');
var fakeGitHub = function (authenticate) {
function FakeGitHub() { }

var _authenticated = false;
var _creds;

FakeGitHub.prototype.authenticate = function (creds) {
if (creds.password === 'validpassword') {
_authenticated = true;
}
_creds = creds;
};

FakeGitHub.prototype.authorization = {
create: function (options, cb) {
if (_authenticated) {
if (_creds.password === 'validpassword') {
cb(null, { token: 'faketoken' });
} else if (_creds.password === 'withtwofactor') {
if (options.headers && options.headers['X-GitHub-OTP'] === '123456') {
cb(null, { token: 'faketwoauthtoken' });
} else {
cb({ code: 401, message: '{ "message": "Must specify two-factor authentication OTP code." }' });
}
} else {
cb('Not authenticated');
cb({ code: 401, message: 'Bad credentials' });
}
}
};
Expand Down Expand Up @@ -82,6 +86,30 @@ describe('bower login', function () {
});
});

it('supports two-factor authorization', function () {
var login = loginFactory({});

var logger = login({}, { interactive: true });

logger.once('prompt', function (prompt, answer) {
logger.once('prompt', function (prompt, answer) {
answer({
otpcode: '123456'
});
});

answer({
username: 'user',
password: 'withtwofactor'
});
});

return helpers.expectEvent(logger, 'end')
.spread(function(options) {
expect(options.token).to.be('faketwoauthtoken');
});
});

it('fails if provided password is invalid', function () {
var login = loginFactory({});

Expand All @@ -94,10 +122,9 @@ describe('bower login', function () {
});
});

return helpers.expectEvent(logger, 'log').spread(function (log) {
expect(log.level).to.be('error');
expect(log.id).to.be('login error');
expect(log.message).to.be('Could not authenticate');
return helpers.expectEvent(logger, 'error').spread(function (error) {
expect(error.code).to.be('EAUTH');
expect(error.message).to.be('Authorization failed');
});
});

Expand Down

0 comments on commit 0f68da4

Please sign in to comment.