allow users to enable/disable U2F via their personal settings
This commit is contained in:
Родитель
b2ecea2c82
Коммит
022e8ea063
|
@ -19,16 +19,26 @@
|
|||
*
|
||||
*/
|
||||
return [
|
||||
'routes' => [
|
||||
[
|
||||
'name' => 'settings#startRegister',
|
||||
'url' => '/settings/startregister',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#finishRegister',
|
||||
'url' => '/settings/finishregister',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
]
|
||||
'routes' => [
|
||||
[
|
||||
'name' => 'settings#state',
|
||||
'url' => '/settings/state',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#disable',
|
||||
'url' => '/settings/disable',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#startRegister',
|
||||
'url' => '/settings/startregister',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#finishRegister',
|
||||
'url' => '/settings/finishregister',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
]
|
||||
];
|
||||
|
|
|
@ -1,49 +1,107 @@
|
|||
/* global Backbone, Handlebars, OC, u2f */
|
||||
|
||||
(function (OC, Backbone, Handlebars, $, u2f) {
|
||||
(function(OC, Backbone, Handlebars, $, u2f) {
|
||||
'use strict';
|
||||
|
||||
OC.Settings = OC.Settings || {};
|
||||
OC.Settings.TwoFactorU2F = OC.Settings.TwoFactorU2F || {};
|
||||
|
||||
var TEMPLATE = '<div>'
|
||||
+ ' <button id="u2f-register">Register</button>'
|
||||
+ ' <input type="checkbox" class="checkbox" id="u2f-enabled" {{#if enabled}}checked{{/if}}>'
|
||||
+ ' <label for="u2f-enabled">' + t('twofactor_u2f', 'Use U2F device') + '</label>'
|
||||
+ '</div>';
|
||||
|
||||
var View = Backbone.View.extend({
|
||||
template: Handlebars.compile(TEMPLATE),
|
||||
_template: undefined,
|
||||
_enabled: undefined,
|
||||
template: function(data) {
|
||||
if (!this._template) {
|
||||
this._template = Handlebars.compile(TEMPLATE);
|
||||
}
|
||||
return this._template(data);
|
||||
},
|
||||
events: {
|
||||
'click #u2f-register': 'onRegister'
|
||||
'change #u2f-enabled': '_onToggleEnabled',
|
||||
},
|
||||
initialize: function () {
|
||||
initialize: function() {
|
||||
this._load();
|
||||
},
|
||||
render: function() {
|
||||
this.$el.html(this.template({
|
||||
enabled: this._enabled
|
||||
}));
|
||||
},
|
||||
_load: function() {
|
||||
var url = OC.generateUrl('/apps/twofactor_u2f/settings/state');
|
||||
$.ajax(url, {
|
||||
method: 'GET',
|
||||
}).done(function(data) {
|
||||
this._enabled = data.enabled;
|
||||
this.render();
|
||||
}.bind(this)).fail(function() {
|
||||
OC.Notification.showTemporary('Could not get U2F enabled/disabled state.');
|
||||
});
|
||||
},
|
||||
_onToggleEnabled: function() {
|
||||
if (this._loading) {
|
||||
// Ignore event
|
||||
return;
|
||||
}
|
||||
|
||||
var enabled = this.$('#u2f-enabled').is(':checked');
|
||||
|
||||
if (enabled === this._enabled) {
|
||||
console.log('ign');
|
||||
return;
|
||||
}
|
||||
this._enabled = enabled;
|
||||
|
||||
if (enabled) {
|
||||
this._onRegister();
|
||||
} else {
|
||||
this._onDisable();
|
||||
}
|
||||
},
|
||||
render: function (data) {
|
||||
this.$el.html(this.template(data));
|
||||
},
|
||||
onRegister: function () {
|
||||
_onRegister: function() {
|
||||
this._loading = true;
|
||||
console.log('start register…');
|
||||
var url = OC.generateUrl('apps/twofactor_u2f/settings/startregister');
|
||||
$.ajax(url, {
|
||||
method: 'POST'
|
||||
}).done(function (data) {
|
||||
}).done(function(data) {
|
||||
this.doRegister(data.req, data.sigs);
|
||||
}.bind(this)).fail(function() {
|
||||
OC.Notification.showTemporary('server error while trying to add U2F device');
|
||||
});
|
||||
}).always(function() {
|
||||
this._loading = false;
|
||||
}.bind(this));
|
||||
},
|
||||
doRegister: function (req, sigs) {
|
||||
_onDisable: function() {
|
||||
this._loading = true;
|
||||
console.log('disabling U2F…');
|
||||
var url = OC.generateUrl('apps/twofactor_u2f/settings/disable');
|
||||
$.ajax(url, {
|
||||
method: 'POST'
|
||||
}).fail(function() {
|
||||
OC.Notification.showTemporary('Could not disable U2F');
|
||||
}.bind(this)).always(function() {
|
||||
this._loading = false;
|
||||
}.bind(this));
|
||||
},
|
||||
doRegister: function(req, sigs) {
|
||||
console.log('doRegister', req, sigs);
|
||||
u2f.register([req], sigs, function (data) {
|
||||
u2f.register([req], sigs, function(data) {
|
||||
console.log(data.errorCode);
|
||||
if (data.errorCode && data.errorCode !== 0) {
|
||||
OC.Notification.showTemporary('U2F device registration failed (error code ' + data.errorCode + ')');
|
||||
this._enabled = false;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
this.finishRegister(data);
|
||||
}.bind(this));
|
||||
},
|
||||
finishRegister: function (data) {
|
||||
finishRegister: function(data) {
|
||||
console.log('finish register…', data);
|
||||
var url = OC.generateUrl('apps/twofactor_u2f/settings/finishregister');
|
||||
$.ajax(url, {
|
||||
|
|
|
@ -27,12 +27,34 @@ class SettingsController extends Controller {
|
|||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param U2FManager $manager
|
||||
* @param IUserSession $userSession
|
||||
*/
|
||||
public function __construct($appName, IRequest $request, U2FManager $manager, IUserSession $userSession) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->manager = $manager;
|
||||
$this->userSession = $userSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function state() {
|
||||
return [
|
||||
'enabled' => $this->manager->isEnabled($this->userSession->getUser())
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function disable() {
|
||||
$this->manager->disableU2F($this->userSession->getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @UseSession
|
||||
|
|
|
@ -62,6 +62,13 @@ class U2FManager {
|
|||
return count($registrations) > 0;
|
||||
}
|
||||
|
||||
public function disableU2F(IUser $user) {
|
||||
// TODO: use single query instead
|
||||
foreach ($this->mapper->findRegistrations($user) as $registration) {
|
||||
$this->mapper->delete($registration);
|
||||
}
|
||||
}
|
||||
|
||||
public function startRegistration(IUser $user) {
|
||||
$u2f = $this->getU2f();
|
||||
$data = $u2f->getRegisterData($this->getRegistrations($user));
|
||||
|
|
Загрузка…
Ссылка в новой задаче