u2f cleanup

This commit is contained in:
Kyle Spearrin 2017-06-23 16:31:55 -04:00
parent dda64b301e
commit b8e9567501
9 changed files with 139 additions and 48 deletions

View File

@ -2,9 +2,10 @@ angular
.module('bit.accounts')
.controller('accountsLoginController', function ($scope, $rootScope, $cookies, apiService, cryptoService, authService,
$state, constants, $analytics, $uibModal, $timeout, $window) {
$state, constants, $analytics, $uibModal, $timeout, $window, $filter) {
$scope.state = $state;
$scope.twoFactorProviderConstants = constants.twoFactorProvider;
$scope.rememberTwoFactor = { checked: false };
var returnState;
if (!$state.params.returnState && $state.params.org) {
@ -52,7 +53,7 @@ angular
_email = model.email;
_masterPassword = model.masterPassword;
$scope.twoFactorProviders = twoFactorProviders;
$scope.twoFactorProvider = parseInt(Object.keys(twoFactorProviders)[0]);
$scope.twoFactorProvider = getDefaultProvider(twoFactorProviders);
$analytics.eventTrack('Logged In To Two-step');
$state.go('frontend.login.twoFactor', { returnState: returnState }).then(function () {
@ -66,11 +67,27 @@ angular
$analytics.eventTrack('Logged In');
loggedInGo();
}
model.masterPassword = '';
});
};
function getDefaultProvider(twoFactorProviders) {
var keys = Object.keys(twoFactorProviders);
var providerType = null;
var providerPriority = -1;
for (var i = 0; i < keys.length; i++) {
var provider = $filter('filter')(constants.twoFactorProviderInfo, { type: keys[i], active: true });
if (provider.length && provider[0].priority > providerPriority) {
providerType = provider[0].type;
}
}
return parseInt(providerType);
}
$scope.twoFactor = function (token) {
$scope.twoFactorPromise = authService.logIn(_email, _masterPassword, token, $scope.twoFactorProvider, true);
$scope.twoFactorPromise = authService.logIn(_email, _masterPassword, token, $scope.twoFactorProvider,
$scope.rememberTwoFactor.checked || false);
$scope.twoFactorPromise.then(function () {
$analytics.eventTrack('Logged In From Two-step');
@ -110,7 +127,7 @@ angular
if ($scope.twoFactorProvider === constants.twoFactorProvider.duo) {
var params = $scope.twoFactorProviders[constants.twoFactorProvider.duo];
Duo.init({
$window.Duo.init({
host: params.Host,
sig_request: params.Signature,
submit_callback: function (theForm) {
@ -122,18 +139,36 @@ angular
else if ($scope.twoFactorProvider === constants.twoFactorProvider.u2f) {
var params = $scope.twoFactorProviders[constants.twoFactorProvider.u2f];
var challenges = JSON.parse(params.Challenges);
if (challenges.length < 1) {
initU2f(challenges);
}
}
function initU2f(challenges) {
if (challenges.length < 1 || $scope.twoFactorProvider !== constants.twoFactorProvider.u2f) {
return;
}
console.log('listening for u2f key...');
$window.u2f.sign(challenges[0].appId, challenges[0].challenge, [{
version: challenges[0].version,
keyHandle: challenges[0].keyHandle
}], function (data) {
if ($scope.twoFactorProvider !== constants.twoFactorProvider.u2f) {
return;
}
$window.u2f.sign(challenges[0].appId, challenges[0].challenge, [{
version: challenges[0].version,
keyHandle: challenges[0].keyHandle
}], function (data) {
console.log('call back data:');
console.log(data);
$scope.twoFactor(JSON.stringify(data));
});
}
if (data.errorCode) {
console.log(data.errorCode);
if (data.errorCode === 5) {
initU2f(challenges);
}
return;
}
$scope.twoFactor(JSON.stringify(data));
}, 5);
}
});

View File

@ -21,7 +21,11 @@
</div>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
<div class="checkbox">
<label>
<input type="checkbox" id="rememberMe" ng-model="rememberTwoFactor.checked" /> Remember Me
</label>
</div>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
@ -34,7 +38,7 @@
<div ng-if="twoFactorProvider === twoFactorProviderConstants.yubikey">
<p class="login-box-msg">
Insert your YubiKey into a USB slot and touch its gold button.
Complete logging in with YubiKey.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
@ -43,13 +47,21 @@
<li ng-repeat="e in twoFactorForm.$errors">{{e}}</li>
</ul>
</div>
<p>Insert your YubiKey into your computer's USB port, then tap it's button.</p>
<p>
<img src="images/two-factor/yubikey.jpg" alt="" class="img-rounded img-responsive" />
</p>
<div class="form-group" show-errors>
<label for="code" class="sr-only">Token</label>
<input type="password" id="code" name="Token" class="form-control" ng-model="token" required api-field />
</div>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
<div class="checkbox">
<label>
<input type="checkbox" id="rememberMe" ng-model="rememberTwoFactor.checked" /> Remember Me
</label>
</div>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
@ -76,12 +88,16 @@
</div>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
<div class="checkbox">
<label>
<input type="checkbox" id="rememberMe" ng-model="rememberTwoFactor.checked" /> Remember Me
</label>
</div>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
</button>
<span ng-show="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon"></i> Logging in...
</span>
</div>
</div>
</form>
@ -89,25 +105,42 @@
<div ng-if="twoFactorProvider === twoFactorProviderConstants.u2f">
<p class="login-box-msg">
Complete logging in with U2F.
Complete logging in with FIDO U2F.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<form name="twoFactorForm" api-form="twoFactorPromise">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
<li ng-repeat="e in twoFactorForm.$errors">{{e}}</li>
</ul>
</div>
<p>Press the button on your security key to continue.</p>
<p>Insert your Security Key into your computer's USB port. If it has a button, tap it.</p>
<p>
<img src="images/two-factor/u2fkey.jpg" alt="" class="img-rounded img-responsive" />
</p>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
<div class="checkbox">
<label>
<input type="checkbox" id="rememberMe" ng-model="rememberTwoFactor.checked" /> Remember Me
</label>
</div>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
</button>
<span ng-show="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon"></i> Logging in...
</span>
</div>
</div>
</form>
</div>
<hr />
<ul>
<li>
<a stop-click href="#" ng-click="anotherMethod()">Use another two-step method</a>
</li>
<li>
<a ui-sref="frontend.login.info({returnState: returnState})">Back to log in</a>
</li>
</ul>

View File

@ -3,7 +3,7 @@
<h4 class="modal-title"><i class="fa fa-key"></i> Two-step Providers</h4>
</div>
<div class="modal-body">
<div class="list-group" ng-repeat="provider in providers">
<div class="list-group" ng-repeat="provider in providers | orderBy: 'displayOrder'">
<a href="#" stop-click class="list-group-item" ng-click="choose(provider)">
<img alt="{{::provider.name}}" ng-src="{{'images/two-factor/' + provider.image}}" class="pull-right hidden-xs" />
<h4 class="list-group-item-heading">{{::provider.name}}</h4>

View File

@ -21,11 +21,11 @@ angular.module('bit')
confirmed: 2
},
twoFactorProvider: {
u2f: 4,
yubikey: 3,
duo: 2,
authenticator: 0,
email: 1,
duo: 2,
yubikey: 3,
u2f: 4,
remember: 5
},
twoFactorProviderInfo: [
@ -35,36 +35,51 @@ angular.module('bit')
description: 'Use an authenticator app (such as Authy or Google Authenticator) to generate time-based ' +
'verification codes.',
enabled: false,
active: true,
free: true,
image: 'authapp.png'
image: 'authapp.png',
displayOrder: 0,
priority: 3
},
{
type: 3,
name: 'YubiKey OTP Security Key',
description: 'Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices.',
enabled: false,
image: 'yubico.png'
active: true,
image: 'yubico.png',
displayOrder: 1,
priority: 1
},
{
type: 2,
name: 'Duo',
description: 'Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.',
enabled: false,
image: 'duo.png'
active: true,
image: 'duo.png',
displayOrder: 2,
priority: 2
},
{
type: 4,
name: 'FIDO U2F Security Key',
description: 'Use any FIDO U2F enabled security key to access your account.',
enabled: false,
image: 'fido.png'
active: true,
image: 'fido.png',
displayOrder: 3,
priority: 0
},
{
type: 1,
name: 'Email',
description: 'Verification codes will be emailed to you.',
enabled: false,
image: 'gmail.png'
active: true,
image: 'gmail.png',
displayOrder: 4,
priority: 4
}
],
plans: {

View File

@ -2,21 +2,25 @@
.module('bit.settings')
.controller('settingsSessionsController', function ($scope, $state, apiService, $uibModalInstance, cryptoService,
authService, toastr, $analytics) {
authService, tokenService, toastr, $analytics) {
$analytics.eventTrack('settingsSessionsController', { category: 'Modal' });
$scope.submit = function (model) {
var request = {
masterPasswordHash: cryptoService.hashPassword(model.masterPassword)
};
$scope.submitPromise = apiService.accounts.putSecurityStamp(request, function () {
$uibModalInstance.dismiss('cancel');
authService.logOut();
$analytics.eventTrack('Deauthorized Sessions');
$state.go('frontend.login.info').then(function () {
toastr.success('Please log back in.', 'All Sessions Deauthorized');
$scope.submitPromise =
authService.getUserProfile().then(function (profile) {
apiService.accounts.putSecurityStamp(request, function () {
$uibModalInstance.dismiss('cancel');
authService.logOut();
tokenService.clearTwoFactorToken(profile.email);
$analytics.eventTrack('Deauthorized Sessions');
$state.go('frontend.login.info').then(function () {
toastr.success('Please log back in.', 'All Sessions Deauthorized');
});
}).$promise;
});
}).$promise;
};
$scope.close = function () {

View File

@ -6,10 +6,14 @@
<div class="modal-body">
<p>Concerned your account is logged in on another device?</p>
<p>Proceed below to deauthorize all computers or devices that you have previously used.</p>
<p>This security step is recommended if you previously used a public PC or accidentally saved your password on a device that isn't yours.</p>
<p>
This security step is recommended if you previously used a public PC or accidentally saved your password
on a device that isn't yours. This step will also clear all previously remembered two-step login sessions.
</p>
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning</h4>
Proceeding will log you out of your current session as well, requiring you to log back in.
Proceeding will also log you out of your current session, requiring you to log back in. You will also be prompted
for two-step login again, if enabled.
</div>
<div class="callout callout-danger validation-errors" ng-show="logoutSessionsForm.$errors">
<h4>Errors have occurred</h4>

View File

@ -18,7 +18,7 @@
<div class="table-responsive">
<table class="table table-striped table-hover table-vmiddle">
<tbody>
<tr ng-repeat="provider in providers">
<tr ng-repeat="provider in providers | orderBy: 'displayOrder'">
<td style="width: 120px; height: 75px;" align="center">
<img alt="{{::provider.name}}" ng-src="{{'images/two-factor/' + provider.image}}" />
</td>

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB