mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-25 02:51:59 +01:00
new two-factor management page
This commit is contained in:
parent
10fe79c558
commit
00e74dd2c8
@ -14,7 +14,7 @@ angular
|
||||
recoveryCode: model.code.replace(/\s/g, '').toLowerCase()
|
||||
};
|
||||
|
||||
$scope.submitPromise = apiService.accounts.postTwoFactorRecover(request, function () {
|
||||
$scope.submitPromise = apiService.twoFactor.recover(request, function () {
|
||||
$analytics.eventTrack('Recovered 2FA');
|
||||
$scope.success = true;
|
||||
}).$promise;
|
||||
|
@ -103,9 +103,6 @@
|
||||
putProfile: { url: _apiUri + '/accounts/profile', method: 'POST', params: {} },
|
||||
getDomains: { url: _apiUri + '/accounts/domains', method: 'GET', params: {} },
|
||||
putDomains: { url: _apiUri + '/accounts/domains', method: 'POST', params: {} },
|
||||
getTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'GET', params: {} },
|
||||
putTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'POST', params: {} },
|
||||
postTwoFactorRecover: { url: _apiUri + '/accounts/two-factor-recover', method: 'POST', params: {} },
|
||||
postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} },
|
||||
putSecurityStamp: { url: _apiUri + '/accounts/security-stamp', method: 'POST', params: {} },
|
||||
putKeys: { url: _apiUri + '/accounts/keys', method: 'POST', params: {} },
|
||||
@ -115,8 +112,13 @@
|
||||
});
|
||||
|
||||
_service.twoFactor = $resource(_apiUri + '/two-factor', {}, {
|
||||
get: { method: 'GET', params: { provider: '@provider' } },
|
||||
list: { method: 'GET', params: {} }
|
||||
list: { method: 'GET', params: {} },
|
||||
getEmail: { url: _apiUri + '/two-factor/get-email', method: 'POST', params: {} },
|
||||
getAuthenticator: { url: _apiUri + '/two-factor/get-authenticator', method: 'POST', params: {} },
|
||||
putEmail: { url: _apiUri + '/two-factor/email', method: 'POST', params: {} },
|
||||
putAuthenticator: { url: _apiUri + '/two-factor/authenticator', method: 'POST', params: {} },
|
||||
disable: { url: _apiUri + '/two-factor/disable', method: 'POST', params: {} },
|
||||
recover: { url: _apiUri + '/two-factor/recover', method: 'POST', params: {} },
|
||||
});
|
||||
|
||||
_service.settings = $resource(_apiUri + '/settings', {}, {
|
||||
|
@ -105,22 +105,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.twoFactor = function () {
|
||||
var twoFactorModal = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: 'app/settings/views/settingsTwoFactor.html',
|
||||
controller: 'settingsTwoFactorController'
|
||||
});
|
||||
|
||||
twoFactorModal.result.then(function (enabled) {
|
||||
if (enabled === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.model.twoFactorEnabled = enabled;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.sessions = function () {
|
||||
$uibModal.open({
|
||||
animation: true,
|
||||
|
@ -1,93 +0,0 @@
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsTwoFactorController', function ($scope, apiService, $uibModalInstance, cryptoService, authService,
|
||||
$q, toastr, $analytics) {
|
||||
$analytics.eventTrack('settingsTwoFactorController', { category: 'Modal' });
|
||||
var _issuer = 'bitwarden',
|
||||
_profile = null,
|
||||
_masterPasswordHash;
|
||||
|
||||
authService.getUserProfile().then(function (profile) {
|
||||
_profile = profile;
|
||||
$scope.account = _profile.email;
|
||||
$scope.enabled = function () {
|
||||
return _profile.extended && _profile.extended.twoFactorEnabled;
|
||||
};
|
||||
});
|
||||
|
||||
$scope.auth = function (model) {
|
||||
_masterPasswordHash = cryptoService.hashPassword(model.masterPassword);
|
||||
|
||||
$scope.authPromise = apiService.accounts.getTwoFactor({
|
||||
masterPasswordHash: _masterPasswordHash,
|
||||
provider: 0 /* Only authenticator provider for now. */
|
||||
}, function (response) {
|
||||
processResponse(response);
|
||||
}).$promise;
|
||||
};
|
||||
|
||||
function formatString(s) {
|
||||
if (!s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return s.replace(/(.{4})/g, '$1 ').trim().toUpperCase();
|
||||
}
|
||||
|
||||
function processResponse(response) {
|
||||
var key = response.AuthenticatorKey;
|
||||
$scope.twoFactorModel = {
|
||||
enabled: response.TwoFactorEnabled,
|
||||
key: formatString(key),
|
||||
recovery: formatString(response.TwoFactorRecoveryCode),
|
||||
qr: 'https://chart.googleapis.com/chart?chs=120x120&chld=L|0&cht=qr&chl=otpauth://totp/' +
|
||||
_issuer + ':' + encodeURIComponent(_profile.email) +
|
||||
'%3Fsecret=' + encodeURIComponent(key) +
|
||||
'%26issuer=' + _issuer
|
||||
};
|
||||
}
|
||||
|
||||
$scope.update = function (model) {
|
||||
var currentlyEnabled = $scope.twoFactorModel.enabled;
|
||||
if (currentlyEnabled && !confirm('Are you sure you want to disable two-step login?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var request = {
|
||||
enabled: !currentlyEnabled,
|
||||
token: model.token.replace(' ', ''),
|
||||
masterPasswordHash: _masterPasswordHash
|
||||
};
|
||||
|
||||
$scope.updatePromise = apiService.accounts.putTwoFactor({}, request, function (response) {
|
||||
if (response.TwoFactorEnabled) {
|
||||
$analytics.eventTrack('Enabled Two-step Login');
|
||||
toastr.success('Two-step login has been enabled.');
|
||||
if (_profile.extended) _profile.extended.twoFactorEnabled = true;
|
||||
processResponse(response);
|
||||
$('#token').blur();
|
||||
model.token = null;
|
||||
}
|
||||
else {
|
||||
$analytics.eventTrack('Disabled Two-step Login');
|
||||
toastr.success('Two-step login has been disabled.');
|
||||
if (_profile.extended) _profile.extended.twoFactorEnabled = false;
|
||||
$scope.close();
|
||||
}
|
||||
}).$promise;
|
||||
};
|
||||
|
||||
$scope.print = function (printContent) {
|
||||
$analytics.eventTrack('Print Recovery Code');
|
||||
var w = window.open();
|
||||
w.document.write('<div style="font-size: 18px; text-align: center;"><p>bitwarden two-step login recovery code:</p>' +
|
||||
'<pre>' + printContent + '</pre>');
|
||||
w.print();
|
||||
w.close();
|
||||
};
|
||||
|
||||
$scope.close = function () {
|
||||
$uibModalInstance.close(!_profile.extended ? null : _profile.extended.twoFactorEnabled);
|
||||
};
|
||||
});
|
88
src/app/settings/settingsTwoStepAuthenticatorController.js
Normal file
88
src/app/settings/settingsTwoStepAuthenticatorController.js
Normal file
@ -0,0 +1,88 @@
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsTwoStepAuthenticatorController', function ($scope, apiService, $uibModalInstance, cryptoService,
|
||||
authService, $q, toastr, $analytics, constants) {
|
||||
$analytics.eventTrack('settingsTwoStepAuthenticatorController', { category: 'Modal' });
|
||||
var _issuer = 'bitwarden',
|
||||
_profile = null,
|
||||
_masterPasswordHash;
|
||||
|
||||
$scope.auth = function (model) {
|
||||
_masterPasswordHash = cryptoService.hashPassword(model.masterPassword);
|
||||
|
||||
var response = null;
|
||||
$scope.authPromise = apiService.twoFactor.getAuthenticator({}, {
|
||||
masterPasswordHash: _masterPasswordHash
|
||||
}).$promise.then(function (apiResponse) {
|
||||
response = apiResponse;
|
||||
return authService.getUserProfile();
|
||||
}).then(function (profile) {
|
||||
_profile = profile;
|
||||
$scope.account = _profile.email;
|
||||
processResponse(response);
|
||||
});
|
||||
};
|
||||
|
||||
function formatString(s) {
|
||||
if (!s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return s.replace(/(.{4})/g, '$1 ').trim().toUpperCase();
|
||||
}
|
||||
|
||||
function processResponse(response) {
|
||||
$scope.enabled = response.Enabled;
|
||||
|
||||
$scope.model = {
|
||||
key: formatString(response.Key),
|
||||
qr: 'https://chart.googleapis.com/chart?chs=120x120&chld=L|0&cht=qr&chl=otpauth://totp/' +
|
||||
_issuer + ':' + encodeURIComponent(_profile.email) +
|
||||
'%3Fsecret=' + encodeURIComponent(response.Key) +
|
||||
'%26issuer=' + _issuer
|
||||
};
|
||||
$scope.updateModel = {
|
||||
token: null
|
||||
};
|
||||
}
|
||||
|
||||
$scope.submit = function (model) {
|
||||
if (!model || !model.token) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
update(model);
|
||||
};
|
||||
|
||||
function disable() {
|
||||
if (!confirm('Are you sure you want to disable the authenticator app provider?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.submitPromise = apiService.twoFactor.disable({}, {
|
||||
masterPasswordHash: _masterPasswordHash,
|
||||
type: constants.twoFactorProvider.authenticator
|
||||
}, function (response) {
|
||||
$analytics.eventTrack('Disabled Two-step Authenticator');
|
||||
toastr.success('Authenticator app has been disabled.');
|
||||
$scope.close();
|
||||
}).$promise;
|
||||
}
|
||||
|
||||
function update(model) {
|
||||
$scope.submitPromise = apiService.twoFactor.putAuthenticator({}, {
|
||||
token: model.token.replace(' ', ''),
|
||||
masterPasswordHash: _masterPasswordHash
|
||||
}, function (response) {
|
||||
$analytics.eventTrack('Enabled Two-step Authenticator');
|
||||
processResponse(response);
|
||||
model.token = null;
|
||||
}).$promise;
|
||||
}
|
||||
|
||||
$scope.close = function () {
|
||||
$uibModalInstance.close();
|
||||
};
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsTwoStepController', function ($scope, apiService, authService, toastr, $analytics, constants,
|
||||
$filter) {
|
||||
$filter, $uibModal) {
|
||||
$scope.providers = [
|
||||
{
|
||||
type: constants.twoFactorProvider.authenticator,
|
||||
@ -53,4 +53,21 @@
|
||||
authService.getUserProfile().then(function (profile) {
|
||||
_profile = profile;
|
||||
});
|
||||
|
||||
$scope.edit = function (provider) {
|
||||
if (provider.type === constants.twoFactorProvider.authenticator) {
|
||||
var authenticatorModal = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: 'app/settings/views/settingsTwoStepAuthenticator.html',
|
||||
controller: 'settingsTwoStepAuthenticatorController',
|
||||
resolve: {
|
||||
enabled: function () { return provider.enabled; }
|
||||
}
|
||||
});
|
||||
|
||||
authenticatorModal.result.then(function () {
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -85,27 +85,6 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Two-step Log In</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>
|
||||
Current Status:
|
||||
<span class="label bg-green" ng-show="model.twoFactorEnabled">ENABLED</span>
|
||||
<span class="label bg-gray" ng-show="!model.twoFactorEnabled">DISABLED</span>
|
||||
</p>
|
||||
<p>
|
||||
Two-step login helps keep your account more secure by requiring a code provided by an app on your mobile device
|
||||
while logging in (in addition to your master password).
|
||||
</p>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="twoFactor()">
|
||||
Manage Two-step Log In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Organizations</h3>
|
||||
|
@ -1,15 +1,13 @@
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="twoFactorModelLabel"><i class="fa fa-key"></i> Two-step Log In</h4>
|
||||
<h4 class="modal-title">
|
||||
<i class="fa fa-key"></i> Two-step Log In <small>authenticator app</small>
|
||||
</h4>
|
||||
</div>
|
||||
<form name="authTwoStepForm" ng-submit="authTwoStepForm.$valid && auth(authModel)" api-form="authPromise"
|
||||
ng-if="!twoFactorModel">
|
||||
ng-if="!model">
|
||||
<div class="modal-body">
|
||||
<p ng-show="enabled()">
|
||||
Two-step log in is already enabled on your account. To access your two-step
|
||||
settings enter your master password below.
|
||||
</p>
|
||||
<p ng-show="!enabled()">To get started with two-step log in enter your master password below.</p>
|
||||
<p>Enter your master password to modify two-step login settings.</p>
|
||||
<div class="callout callout-danger validation-errors" ng-show="authTwoStepForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
<ul>
|
||||
@ -29,22 +27,22 @@
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
<form name="updateTwoStepForm" ng-submit="updateTwoStepForm.$valid && update(updateModel)" api-form="updatePromise"
|
||||
ng-if="twoFactorModel">
|
||||
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit(updateModel)" api-form="submitPromise"
|
||||
ng-if="model">
|
||||
<div class="modal-body">
|
||||
<div ng-show="enabled()">
|
||||
<div ng-if="enabled">
|
||||
<div class="callout callout-success">
|
||||
<h4><i class="fa fa-check-circle"></i> Enabled</h4>
|
||||
<p>
|
||||
Two-step log in is enabled on your account. Incase you need to add it to another device, below is the QR
|
||||
code (or key) required by your verification app.
|
||||
code (or key) required by your authenticator app.
|
||||
</p>
|
||||
</div>
|
||||
<p>Need a two-step verification app? Download one of the following:</p>
|
||||
<p>Need a two-step authenticator app? Download one of the following:</p>
|
||||
</div>
|
||||
<div ng-show="!enabled()">
|
||||
<p>Setting up two-step verification is easy, just follow these steps:</p>
|
||||
<h4>1. Download a two-step verification app</h4>
|
||||
<div ng-if="!enabled">
|
||||
<p>Setting up two-step login with an authenticator app is easy, just follow these steps:</p>
|
||||
<h4>1. Download a two-step authenticator app</h4>
|
||||
</div>
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
@ -70,11 +68,11 @@
|
||||
</li>
|
||||
</ul>
|
||||
<p>These apps are recommended, however, other authenticator apps will also work.</p>
|
||||
<hr ng-show="enabled()" />
|
||||
<h4 ng-show="!enabled()" style="margin-top: 30px;">2. Scan this QR code with your verification app</h4>
|
||||
<hr ng-if="enabled" />
|
||||
<h4 ng-if="!enabled" style="margin-top: 30px;">2. Scan this QR code with your authenticator app</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-4 text-center">
|
||||
<p><img ng-src="{{twoFactorModel.qr}}" alt="QR" class="img-thumbnail" /></p>
|
||||
<p><img ng-src="{{model.qr}}" alt="QR" class="img-thumbnail" /></p>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<p>
|
||||
@ -82,54 +80,34 @@
|
||||
following details:
|
||||
</p>
|
||||
<ul class="list-unstyled">
|
||||
<li><strong>Key:</strong> <code>{{twoFactorModel.key}}</code></li>
|
||||
<li><strong>Key:</strong> <code>{{model.key}}</code></li>
|
||||
<li><strong>Account:</strong> {{account}}</li>
|
||||
<li><strong>Time based:</strong> Yes</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="enabled()">
|
||||
<hr />
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-warning"></i> Recovery Code <i class="fa fa-warning"></i></h4>
|
||||
<p>
|
||||
The recovery code allows you to access your account in the event that you lose your authenticator app.
|
||||
bitwarden support won't be able to assist you if you lose access to your account. We recommend
|
||||
you write down or print the recovery code below and keep it in a safe place.
|
||||
</p>
|
||||
<p><strong>Recovery Code:</strong> <code>{{twoFactorModel.recovery}}</code></p>
|
||||
<button type="button" class="btn btn-default" ng-click="print(twoFactorModel.recovery)">
|
||||
<i class="fa fa-print"></i> Print
|
||||
</button>
|
||||
<div ng-if="!enabled">
|
||||
<h4 style="margin-top: 30px;">
|
||||
3. Enter the resulting 6 digit verification code from the app
|
||||
</h4>
|
||||
<div class="callout callout-danger validation-errors" ng-show="submitTwoStepForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
<ul>
|
||||
<li ng-repeat="e in submitTwoStepForm.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="token" class="sr-only">Verification Code</label>
|
||||
<input type="text" id="token" name="Token" placeholder="Verification Code" ng-model="updateModel.token"
|
||||
class="form-control" required api-field />
|
||||
</div>
|
||||
</div>
|
||||
<hr ng-show="enabled()" />
|
||||
<div class="callout callout-danger validation-errors" ng-show="updateTwoStepForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
<ul>
|
||||
<li ng-repeat="e in updateTwoStepForm.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h4 style="margin-top: 30px;">
|
||||
<span ng-show="enabled()">Want to disable? </span><span ng-show="!enabled()">3. </span>
|
||||
Enter the resulting verification code from the app
|
||||
</h4>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="token" class="sr-only">Verification Code</label>
|
||||
<input type="text" id="token" name="Token" placeholder="Verification Code" ng-model="updateModel.token"
|
||||
class="form-control" required api-field />
|
||||
</div>
|
||||
<p ng-show="!enabled()">
|
||||
NOTE: After enabling two-step log in, you will be required to enter the current code
|
||||
generated by your verification app each time you log in.
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="updateTwoStepForm.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="updateTwoStepForm.$loading"></i>
|
||||
<span ng-show="enabled()">Disable Two-step</span>
|
||||
<span ng-show="!enabled()">Enable Two-step</span>
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="submitTwoStepForm.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="submitTwoStepForm.$loading"></i>
|
||||
{{enabled ? 'Disable' : 'Enable'}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
@ -188,7 +188,7 @@
|
||||
<script src="app/settings/settingsController.js"></script>
|
||||
<script src="app/settings/settingsChangePasswordController.js"></script>
|
||||
<script src="app/settings/settingsChangeEmailController.js"></script>
|
||||
<script src="app/settings/settingsTwoFactorController.js"></script>
|
||||
<script src="app/settings/settingsTwoStepAuthenticatorController.js"></script>
|
||||
<script src="app/settings/settingsSessionsController.js"></script>
|
||||
<script src="app/settings/settingsDomainsController.js"></script>
|
||||
<script src="app/settings/settingsTwoStepController.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user