Introduce the UI for password confirmation
Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
parent
54ca411ff0
commit
d75e35b75e
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
* @author Christoph Wurst <christoph@owncloud.com>
|
||||
|
@ -31,6 +32,8 @@ use OC\User\Session;
|
|||
use OC_App;
|
||||
use OC_Util;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\Authentication\TwoFactorAuth\IProvider;
|
||||
|
@ -242,6 +245,8 @@ class LoginController extends Controller {
|
|||
// User has successfully logged in, now remove the password reset link, when it is available
|
||||
$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
|
||||
|
||||
$this->session->set('last-password-confirm', $loginResult->getLastLogin());
|
||||
|
||||
if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
|
||||
$this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
|
||||
|
||||
|
@ -273,4 +278,36 @@ class LoginController extends Controller {
|
|||
return $this->generateRedirect($redirect_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @UseSession
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* @param string $password
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function confirmPassword($password) {
|
||||
$currentDelay = $this->throttler->getDelay($this->request->getRemoteAddress());
|
||||
$this->throttler->sleepDelay($this->request->getRemoteAddress());
|
||||
|
||||
$user = $this->userSession->getUser();
|
||||
if (!$user instanceof IUser) {
|
||||
return new DataResponse([], Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$loginResult = $this->userManager->checkPassword($user->getUID(), $password);
|
||||
if ($loginResult === false) {
|
||||
$this->throttler->registerAttempt('sudo', $this->request->getRemoteAddress(), ['user' => $user->getUID()]);
|
||||
if ($currentDelay === 0) {
|
||||
$this->throttler->sleepDelay($this->request->getRemoteAddress());
|
||||
}
|
||||
|
||||
return new DataResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$confirmTimestamp = time();
|
||||
$this->session->set('last-password-confirm', $confirmTimestamp);
|
||||
return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ use OCP\IConfig;
|
|||
use OCP\IGroupManager;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
|
||||
|
@ -48,7 +49,8 @@ class OCJSController extends Controller {
|
|||
* @param IL10N $l
|
||||
* @param \OC_Defaults $defaults
|
||||
* @param IAppManager $appManager
|
||||
* @param IUserSession $session
|
||||
* @param ISession $session
|
||||
* @param IUserSession $userSession
|
||||
* @param IConfig $config
|
||||
* @param IGroupManager $groupManager
|
||||
* @param IniGetWrapper $iniWrapper
|
||||
|
@ -59,7 +61,8 @@ class OCJSController extends Controller {
|
|||
IL10N $l,
|
||||
\OC_Defaults $defaults,
|
||||
IAppManager $appManager,
|
||||
IUserSession $session,
|
||||
ISession $session,
|
||||
IUserSession $userSession,
|
||||
IConfig $config,
|
||||
IGroupManager $groupManager,
|
||||
IniGetWrapper $iniWrapper,
|
||||
|
@ -70,7 +73,8 @@ class OCJSController extends Controller {
|
|||
$l,
|
||||
$defaults,
|
||||
$appManager,
|
||||
$session->getUser(),
|
||||
$session,
|
||||
$userSession->getUser(),
|
||||
$config,
|
||||
$groupManager,
|
||||
$iniWrapper,
|
||||
|
|
|
@ -983,3 +983,34 @@ fieldset.warning legend + p, fieldset.update legend + p {
|
|||
opacity: 0;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
}
|
||||
|
||||
#sudo-login-background {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1d2d44;
|
||||
opacity:0.4;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#sudo-login-form {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 40%;
|
||||
border: 1px solid #e9322d;
|
||||
z-index: 1000;
|
||||
background: #e4b9c0;
|
||||
border-radius: 10px;
|
||||
opacity:1;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
#sudo-login-form .question {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#sudo-login-form .confirm {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: 25px;
|
||||
}
|
||||
|
|
|
@ -1512,8 +1512,72 @@ function initCore() {
|
|||
$(this).text(OC.Util.relativeModifiedDate(parseInt($(this).attr('data-timestamp'), 10)));
|
||||
});
|
||||
}, 30 * 1000);
|
||||
|
||||
OC.PasswordConfirmation.init();
|
||||
}
|
||||
|
||||
OC.PasswordConfirmation = {
|
||||
$form: null,
|
||||
$background: null,
|
||||
$input: null,
|
||||
$submit: null,
|
||||
|
||||
init: function() {
|
||||
this.$form = $('#sudo-login-form');
|
||||
this.$background = $('#sudo-login-background');
|
||||
this.$input = this.$form.find('.question');
|
||||
this.$submit = this.$form.find('.confirm');
|
||||
|
||||
this.$background.on('click', _.bind(this._fadeOut, this));
|
||||
$('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));
|
||||
this.$submit.on('click', _.bind(this._submitPasswordConfirmation, this));
|
||||
},
|
||||
|
||||
requirePasswordConfirmation: function() {
|
||||
var timeSinceLogin = moment.now() - nc_lastLogin * 1000;
|
||||
if (timeSinceLogin > 30 * 60 * 1000) { // 30 minutes
|
||||
this.$form.removeClass('hidden');
|
||||
this.$background.removeClass('hidden');
|
||||
|
||||
// Hack against firefox ignoring autocomplete="off"
|
||||
if (this.$input.val() === ' ') {
|
||||
this.$input.val('');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_submitPasswordConfirmation: function() {
|
||||
var self = this;
|
||||
|
||||
self.$submit.removeClass('icon-confirm').addClass('icon-loading-small');
|
||||
|
||||
$.ajax({
|
||||
url: OC.generateUrl('/login/confirm'),
|
||||
data: {
|
||||
password: this.$input.val()
|
||||
},
|
||||
type: 'POST',
|
||||
success: function(response) {
|
||||
nc_lastLogin = response.lastLogin;
|
||||
self.$submit.addClass('icon-confirm').removeClass('icon-loading-small');
|
||||
|
||||
self.$form.addClass('hidden');
|
||||
self.$background.addClass('hidden');
|
||||
},
|
||||
error: function() {
|
||||
OC.Notification.showTemporary(t('core', 'Failed to authenticate, try again'));
|
||||
self.$submit.addClass('icon-confirm').removeClass('icon-loading-small');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_fadeOut: function() {
|
||||
this.$form.addClass('hidden');
|
||||
this.$background.addClass('hidden');
|
||||
this.$input.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(initCore);
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,6 +46,7 @@ $application->registerRoutes($this, [
|
|||
['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'],
|
||||
['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'],
|
||||
['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'],
|
||||
['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'],
|
||||
['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'],
|
||||
['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'],
|
||||
['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'],
|
||||
|
|
|
@ -146,6 +146,13 @@
|
|||
</div>
|
||||
</div></nav>
|
||||
|
||||
<div id="sudo-login-background" class="hidden"></div>
|
||||
<div id="sudo-login-form" class="hidden">
|
||||
<input type="password" class="question" autocomplete="off" name="question" value=" "
|
||||
placeholder="<?php p($l->t('Confirm your password')); ?>" />
|
||||
<input class="confirm icon-confirm" title="<?php p($l->t('Confirm')); ?>" value="" type="submit">
|
||||
</div>
|
||||
|
||||
<div id="content-wrapper">
|
||||
<div id="content" class="app-<?php p($_['appid']) ?>" role="main">
|
||||
<?php print_unescaped($_['content']); ?>
|
||||
|
|
|
@ -27,6 +27,7 @@ use OCP\App\IAppManager;
|
|||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IL10N;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
|
||||
|
@ -41,7 +42,10 @@ class JSConfigHelper {
|
|||
/** @var IAppManager */
|
||||
private $appManager;
|
||||
|
||||
/** @var IUser */
|
||||
/** @var ISession */
|
||||
private $session;
|
||||
|
||||
/** @var IUser|null */
|
||||
private $currentUser;
|
||||
|
||||
/** @var IConfig */
|
||||
|
@ -60,6 +64,7 @@ class JSConfigHelper {
|
|||
* @param IL10N $l
|
||||
* @param \OC_Defaults $defaults
|
||||
* @param IAppManager $appManager
|
||||
* @param ISession $session
|
||||
* @param IUser|null $currentUser
|
||||
* @param IConfig $config
|
||||
* @param IGroupManager $groupManager
|
||||
|
@ -69,6 +74,7 @@ class JSConfigHelper {
|
|||
public function __construct(IL10N $l,
|
||||
\OC_Defaults $defaults,
|
||||
IAppManager $appManager,
|
||||
ISession $session,
|
||||
$currentUser,
|
||||
IConfig $config,
|
||||
IGroupManager $groupManager,
|
||||
|
@ -77,6 +83,7 @@ class JSConfigHelper {
|
|||
$this->l = $l;
|
||||
$this->defaults = $defaults;
|
||||
$this->appManager = $appManager;
|
||||
$this->session = $session;
|
||||
$this->currentUser = $currentUser;
|
||||
$this->config = $config;
|
||||
$this->groupManager = $groupManager;
|
||||
|
@ -119,6 +126,16 @@ class JSConfigHelper {
|
|||
$dataLocation = false;
|
||||
}
|
||||
|
||||
if ($this->currentUser instanceof IUser) {
|
||||
$lastConfirmTimestamp = $this->currentUser->getLastLogin();
|
||||
$sessionTime = $this->session->get('last-password-confirm');
|
||||
if (is_int($sessionTime)) {
|
||||
$lastConfirmTimestamp = $sessionTime;
|
||||
}
|
||||
} else {
|
||||
$lastConfirmTimestamp = 0;
|
||||
}
|
||||
|
||||
$array = [
|
||||
"oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
|
||||
"oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false',
|
||||
|
@ -126,6 +143,7 @@ class JSConfigHelper {
|
|||
"oc_webroot" => "\"".\OC::$WEBROOT."\"",
|
||||
"oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
|
||||
"datepickerFormatDate" => json_encode($this->l->l('jsdate', null)),
|
||||
'nc_lastLogin' => $lastConfirmTimestamp,
|
||||
"dayNames" => json_encode([
|
||||
(string)$this->l->t('Sunday'),
|
||||
(string)$this->l->t('Monday'),
|
||||
|
|
|
@ -148,6 +148,7 @@ class TemplateLayout extends \OC_Template {
|
|||
\OC::$server->getL10N('core'),
|
||||
\OC::$server->getThemingDefaults(),
|
||||
\OC::$server->getAppManager(),
|
||||
\OC::$server->getSession(),
|
||||
\OC::$server->getUserSession()->getUser(),
|
||||
\OC::$server->getConfig(),
|
||||
\OC::$server->getGroupManager(),
|
||||
|
|
Loading…
Reference in New Issue