add GUI and other small enhancements
This commit is contained in:
Родитель
ed7d8759db
Коммит
42156f9b6e
|
@ -19,3 +19,5 @@
|
|||
*
|
||||
*/
|
||||
include_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
\OC_App::registerPersonal('twofactor_totp', 'settings/personal');
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\TwoFactorTotp\AppInfo;
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
|
@ -20,14 +18,15 @@ namespace OCA\TwoFactorTotp\AppInfo;
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\TwoFactorTotp\AppInfo;
|
||||
|
||||
use OCP\AppFramework\App;
|
||||
|
||||
class Application extends App {
|
||||
|
||||
public function __construct($urlParams = []) {
|
||||
parent::__construct('twofactor_totps', $urlParams);
|
||||
|
||||
$container = $this->getContainer();
|
||||
}
|
||||
public function __construct($urlParams = []) {
|
||||
parent::__construct('twofactor_totps', $urlParams);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* ownCloud - Two-factor TOTP
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
return [
|
||||
'routes' => [
|
||||
[
|
||||
'name' => 'settings#state',
|
||||
'url' => '/settings/state',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#enable',
|
||||
'url' => '/settings/enable',
|
||||
'verb' => 'POST'
|
||||
]
|
||||
]
|
||||
];
|
|
@ -0,0 +1,14 @@
|
|||
(function (OC) {
|
||||
'use strict';
|
||||
|
||||
OC.Settings = OC.Settings || {};
|
||||
OC.Settings.TwoFactorTotp = OC.Settings.TwoFactorTotp || {};
|
||||
|
||||
$(function () {
|
||||
var view = new OC.Settings.TwoFactorTotp.View({
|
||||
el: $('#twofactor-totp-settings')
|
||||
});
|
||||
view.render();
|
||||
});
|
||||
})(OC);
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/* global Backbone, Handlebars */
|
||||
|
||||
(function (OC, Backbone, Handlebars, $) {
|
||||
'use strict';
|
||||
|
||||
OC.Settings = OC.Settings || {};
|
||||
OC.Settings.TwoFactorTotp = OC.Settings.TwoFactorTotp || {};
|
||||
|
||||
var TEMPLATE = '<div>'
|
||||
+ '<input type="checkbox" class="checkbox" id="totp-enabled">'
|
||||
+ '<label for="totp-enabled">Enable TOTP</label>'
|
||||
+ '</div>'
|
||||
+ '{{#if qr}}'
|
||||
+ '<div>'
|
||||
+ '<a href="{{qr}}" target="_blank">Scan QR code with your TOTP app</a><br>'
|
||||
+ '<img src="{{qr}}>'
|
||||
+ '</div>'
|
||||
+ '{{/if}}';
|
||||
|
||||
var View = Backbone.View.extend({
|
||||
template: Handlebars.compile(TEMPLATE),
|
||||
_loading: undefined,
|
||||
_enabled: undefined,
|
||||
events: {
|
||||
'change #totp-enabled': '_onToggleEnabled'
|
||||
},
|
||||
initialize: function () {
|
||||
this._load();
|
||||
},
|
||||
render: function (data) {
|
||||
this.$el.html(this.template(data));
|
||||
},
|
||||
_load: function () {
|
||||
this._loading = true;
|
||||
|
||||
var url = OC.generateUrl('/apps/twofactor_totp/settings/state');
|
||||
var loading = $.ajax(url, {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
var _this = this;
|
||||
$.when(loading).done(function (data) {
|
||||
_this._enabled = data.enabled;
|
||||
_this.$('#totp-enabled').attr('checked', data.enabled);
|
||||
});
|
||||
$.when(loading).always(function () {
|
||||
_this._loading = false;
|
||||
});
|
||||
},
|
||||
_onToggleEnabled: function () {
|
||||
if (this._loading) {
|
||||
// Ignore event
|
||||
return;
|
||||
}
|
||||
|
||||
var enabled = this.$('#totp-enabled').is(':checked');
|
||||
|
||||
if (enabled !== this._enabled) {
|
||||
this._loading = true;
|
||||
var url = OC.generateUrl('/apps/twofactor_totp/settings/enable');
|
||||
var updating = $.ajax(url, {
|
||||
method: 'POST',
|
||||
data: {
|
||||
state: enabled
|
||||
}
|
||||
});
|
||||
|
||||
var _this = this;
|
||||
$.when(updating).done(function(data) {
|
||||
_this._enabled = data.enabled;
|
||||
_this._showQr(data.qr);
|
||||
_this.$('#totp-enabled').attr('checked', data.enabled);
|
||||
});
|
||||
$.when(updating).always(function () {
|
||||
_this._loading = false;
|
||||
});
|
||||
this._enabled = enabled;
|
||||
}
|
||||
},
|
||||
_showQr: function(qr) {
|
||||
this.render({
|
||||
qr: qr
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
OC.Settings.TwoFactorTotp.View = View;
|
||||
|
||||
})(OC, Backbone, Handlebars, $);
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* ownCloud - Two-factor TOTP
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\TwoFactorTotp\Controller;
|
||||
|
||||
use OCA\TwoFactorTotp\Service\ITotp;
|
||||
use OCA\TwoFactorTotp\Service\Totp;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class SettingsController extends Controller {
|
||||
|
||||
/** @var ITotp */
|
||||
private $totp;
|
||||
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
public function __construct($appName, IRequest $request, IUserSession $userSession, Totp $totp) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->userSession = $userSession;
|
||||
$this->totp = $totp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function state() {
|
||||
$user = $this->userSession->getUser();
|
||||
return [
|
||||
'enabled' => $this->totp->hasSecret($user),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @param bool $state
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function enable($state) {
|
||||
$user = $this->userSession->getUser();
|
||||
if ($state) {
|
||||
$qr = $this->totp->createSecret($user);
|
||||
return [
|
||||
'enabled' => true,
|
||||
'qr' => $qr,
|
||||
];
|
||||
}
|
||||
|
||||
$this->totp->deleteSecret($user);
|
||||
return [
|
||||
'enabled' => false,
|
||||
'qr' => null,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -39,8 +39,6 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Get unique identifier of this 2FA provider
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId() {
|
||||
|
@ -50,10 +48,6 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Get the display name for selecting the 2FA provider
|
||||
*
|
||||
* Example: "Email"
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName() {
|
||||
|
@ -63,10 +57,6 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Get the description for selecting the 2FA provider
|
||||
*
|
||||
* Example: "Get a token via e-mail"
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription() {
|
||||
|
@ -76,18 +66,10 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Get the template for rending the 2FA provider view
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @param IUser $user
|
||||
* @return Template
|
||||
*/
|
||||
public function getTemplate(IUser $user) {
|
||||
try {
|
||||
$this->totp->getSecret($user);
|
||||
} catch (NoTotpSecretFoundException $ex) {
|
||||
$qr = $this->totp->createSecret($user);
|
||||
}
|
||||
|
||||
$tmpl = new Template('twofactor_totp', 'challenge');
|
||||
$tmpl->assign('qr', $qr);
|
||||
return $tmpl;
|
||||
|
@ -96,8 +78,6 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Verify the given challenge
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @param IUser $user
|
||||
* @param string $challenge
|
||||
*/
|
||||
|
@ -108,13 +88,11 @@ class TotpProvider implements IProvider {
|
|||
/**
|
||||
* Decides whether 2FA is enabled for the given user
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @param IUser $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function isTwoFactorAuthEnabledForUser(IUser $user) {
|
||||
return true;
|
||||
return $this->totp->hasSecret($user);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,18 +29,22 @@ interface ITotp {
|
|||
/**
|
||||
* @param IUser $user
|
||||
*/
|
||||
public function getSecret(IUser $user);
|
||||
public function hasSecret(IUser $user);
|
||||
|
||||
/**
|
||||
* @param IUser $user
|
||||
* @throws TotpSecretAlreadySet
|
||||
*/
|
||||
public function createSecret(IUser $user);
|
||||
|
||||
|
||||
/**
|
||||
* @param IUser $user
|
||||
*/
|
||||
public function deleteSecret(IUser $user);
|
||||
|
||||
/**
|
||||
* @param IUser $user
|
||||
* @param string $key
|
||||
*/
|
||||
public function validateSecret(IUser $user, $key);
|
||||
|
||||
}
|
||||
|
|
|
@ -44,15 +44,13 @@ class Totp implements ITotp {
|
|||
$this->crypto = $crypto;
|
||||
}
|
||||
|
||||
public function getSecret(IUser $user) {
|
||||
public function hasSecret(IUser $user) {
|
||||
try {
|
||||
$secret = $this->secretMapper->getSecret($user);
|
||||
$this->secretMapper->getSecret($user);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new NoTotpSecretFoundException();
|
||||
return false;
|
||||
}
|
||||
|
||||
$encryptedSecret = $secret->getSecret();
|
||||
return $this->crypto->decrypt($encryptedSecret);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,6 +70,16 @@ class Totp implements ITotp {
|
|||
return GoogleAuthenticator::getQrCodeUrl('totp', 'ownCloud TOTP', $secret);
|
||||
}
|
||||
|
||||
public function deleteSecret(IUser $user) {
|
||||
try {
|
||||
// TODO: execute DELETE sql in mapper instead
|
||||
$dbSecret = $this->secretMapper->getSecret($user);
|
||||
$this->secretMapper->delete($dbSecret);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function validateSecret(IUser $user, $key) {
|
||||
try {
|
||||
$dbSecret = $this->secretMapper->getSecret($user);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$tmpl = new \OCP\Template('twofactor_totp', 'personal');
|
||||
|
||||
return $tmpl->fetchPage();
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
script('twofactor_totp', 'settingsview');
|
||||
script('twofactor_totp', 'settings');
|
||||
|
||||
?>
|
||||
|
||||
<div class="section">
|
||||
<h2>TOTP Second-factor Auth</h2>
|
||||
<div id="twofactor-totp-settings"></div>
|
||||
</div>
|
Загрузка…
Ссылка в новой задаче