diff --git a/js/ajax.js b/js/ajax.js index f484d522a7..1616c0545f 100644 --- a/js/ajax.js +++ b/js/ajax.js @@ -336,7 +336,115 @@ var AJAX = { if (typeof onsubmit !== 'function' || onsubmit.apply(this, [event])) { AJAX.active = true; AJAX.$msgbox = PMA_ajaxShowMessage(); - $.post(url, params, AJAX.responseHandler); + if($(this).attr('id') === 'login_form') { + $.post(url, params, AJAX.loginResponseHandler); + } else { + $.post(url, params, AJAX.responseHandler); + } + } + } + }, + /** + * Response handler to handle login request from login modal after session expiration + * + * To refer to self use 'AJAX', instead of 'this' as this function + * is called in the jQuery context. + * + * @param object data Event data + * + * @return void + */ + loginResponseHandler: function (data) { + if (typeof data === 'undefined' || data === null) { + return; + } + PMA_ajaxRemoveMessage(AJAX.$msgbox); + + PMA_commonParams.set("token", data.new_token); + + AJAX.scriptHandler.load([]); + + if (data._displayMessage) { + $('#page_content').prepend(data._displayMessage); + PMA_highlightSQL($('#page_content')); + } + + $('#pma_errors').remove(); + + var msg = ''; + if (data._errSubmitMsg) { + msg = data._errSubmitMsg; + } + if (data._errors) { + $('
', { id : 'pma_errors', class : 'clearfloat' }) + .insertAfter('#selflink') + .append(data._errors); + // bind for php error reporting forms (bottom) + $('#pma_ignore_errors_bottom').on('click', function (e) { + e.preventDefault(); + PMA_ignorePhpErrors(); + }); + $('#pma_ignore_all_errors_bottom').on('click', function (e) { + e.preventDefault(); + PMA_ignorePhpErrors(false); + }); + // In case of 'sendErrorReport'='always' + // submit the hidden error reporting form. + if (data._sendErrorAlways === '1' && + data._stopErrorReportLoop !== '1' + ) { + $('#pma_report_errors_form').submit(); + PMA_ajaxShowMessage(PMA_messages.phpErrorsBeingSubmitted, false); + $('html, body').animate({ scrollTop:$(document).height() }, 'slow'); + } else if (data._promptPhpErrors) { + // otherwise just prompt user if it is set so. + msg = msg + PMA_messages.phpErrorsFound; + // scroll to bottom where all the errors are displayed. + $('html, body').animate({ scrollTop:$(document).height() }, 'slow'); + } + } + + PMA_ajaxShowMessage(msg, false); + // bind for php error reporting forms (popup) + $('#pma_ignore_errors_popup').on('click', function () { + PMA_ignorePhpErrors(); + }); + $('#pma_ignore_all_errors_popup').on('click', function () { + PMA_ignorePhpErrors(false); + }); + + if (typeof data.success !== 'undefined' && data.success) { + // reload page if user trying to login has changed + if(PMA_commonParams.get('user') !== data._params['user']) { + window.location = "index.php"; + PMA_ajaxShowMessage(PMA_messages.strLoading, false); + AJAX.active = false; + AJAX.xhr = null; + return; + } + // remove the login modal if the login is successful otherwise show error. + if(typeof data.logged_in !== 'undefined' && data.logged_in === 1) { + if($("#modalOverlay").length) { + $("#modalOverlay").remove(); + } + $("fieldset.disabled_for_expiration").removeAttr("disabled").removeClass("disabled_for_expiration"); + AJAX.fireTeardown("functions.js"); + AJAX.fireOnload("functions.js"); + } + if(typeof data.new_token !== 'undefined') { + $("input[name=token]").val(data.new_token); + } + + } else if(typeof data.logged_in !== 'undefined' && data.logged_in === 0) { + $("#modalOverlay").replaceWith(data.error); + } else { + PMA_ajaxShowMessage(data.error, false); + AJAX.active = false; + AJAX.xhr = null; + PMA_handleRedirectAndReload(data); + if (data.fieldWithError) { + $(':input.error').removeClass('error'); + $('#' + data.fieldWithError).addClass('error'); } } }, diff --git a/js/functions.js b/js/functions.js index c16c034d8d..9262adfd9d 100644 --- a/js/functions.js +++ b/js/functions.js @@ -949,7 +949,8 @@ AJAX.registerOnload('functions.js', function () { 'server' : PMA_commonParams.get('server'), 'db' : PMA_commonParams.get('db'), 'guid': guid, - 'access_time':_idleSecondsCounter + 'access_time': _idleSecondsCounter, + 'check_timeout': 1 }; $.ajax({ type: 'POST', @@ -978,7 +979,19 @@ AJAX.registerOnload('functions.js', function () { if (isStorageSupported('sessionStorage')) { window.sessionStorage.clear(); } - window.location.reload(true); + // append the login form on the page, disable all the forms which were not disabled already, close all the open jqueryui modal boxes + if (!$("#modalOverlay").length) { + $("fieldset").not(':disabled').attr("disabled", "disabled").addClass("disabled_for_expiration"); + $('body').append(data.error); + $(".ui-dialog").each(function(i) { + $("#" + $(this).attr("aria-describedby")).dialog("close"); + }); + $("#input_username").focus(); + } else { + PMA_commonParams.set("token", data.new_token); + $("input[name=token]").val(data.new_token); + } + _idleSecondsCounter = 0; } } }); @@ -4321,6 +4334,9 @@ function PMA_slidingMessage (msg, $obj) { */ AJAX.registerOnload('functions.js', function () { var $elm = $('#sqlquery'); + if ($elm.siblings().filter(".CodeMirror").length > 0) { + return; + } if ($elm.length > 0) { if (typeof CodeMirror !== 'undefined') { codemirror_editor = PMA_getSQLEditor($elm); diff --git a/js/shortcuts_handler.js b/js/shortcuts_handler.js index 4fc3c59a7b..d53d773d11 100644 --- a/js/shortcuts_handler.js +++ b/js/shortcuts_handler.js @@ -38,6 +38,10 @@ $(document).ready(function () { } }); $(document).on('keydown', function (e) { + //disable the shortcuts when session has timed out. + if ($("#modalOverlay").length > 0) { + return; + } if (e.ctrlKey && e.altKey && e.keyCode === keyC) { PMA_console.toggle(); } diff --git a/js/sql.js b/js/sql.js index e8f299fe88..fd648b8e31 100644 --- a/js/sql.js +++ b/js/sql.js @@ -177,7 +177,7 @@ AJAX.registerTeardown('sql.js', function () { $(document).off('mouseenter', 'th.column_heading.pointer'); $(document).off('mouseleave', 'th.column_heading.pointer'); $(document).off('click', 'th.column_heading.marker'); - $(window).off('scroll'); + $(document).off('scroll', window); $(document).off('keyup', '.filter_rows'); $(document).off('click', '#printView'); if (codemirror_editor) { @@ -405,7 +405,7 @@ AJAX.registerOnload('sql.js', function () { var $stick_columns = initStickyColumns($table_results); rearrangeStickyColumns($stick_columns, $table_results); // adjust sticky columns on scroll - $(window).on('scroll', function () { + $(document).on('scroll', window, function () { handleStickyColumns($stick_columns, $table_results); }); }); diff --git a/libraries/classes/Plugins/Auth/AuthenticationCookie.php b/libraries/classes/Plugins/Auth/AuthenticationCookie.php index 0120bda179..459eaf9e2a 100644 --- a/libraries/classes/Plugins/Auth/AuthenticationCookie.php +++ b/libraries/classes/Plugins/Auth/AuthenticationCookie.php @@ -86,7 +86,10 @@ class AuthenticationCookie extends AuthenticationPlugin global $conn_error; $response = Response::getInstance(); - if ($response->loginPage()) { + + // When sending login modal after session has expired, send the new token explicitly with the response to update the token in all the forms having a hidden token. + $session_expired = isset($_REQUEST['check_timeout']) || isset($_REQUEST['session_timedout']); + if (!$session_expired && $response->loginPage()) { if (defined('TESTSUITE')) { return true; } else { @@ -94,6 +97,23 @@ class AuthenticationCookie extends AuthenticationPlugin } } + // When sending login modal after session has expired, send the new token explicitly with the response to update the token in all the forms having a hidden token. + if($session_expired) { + $response->setRequestStatus(false); + $response->addJSON( + 'new_token', + $_SESSION[' PMA_token '] + ); + } + + // logged_in response parameter is used to check if the login, using the modal was successful after session expiration + if(isset($_REQUEST['session_timedout'])) { + $response->addJSON( + 'logged_in', + 0 + ); + } + // No recall if blowfish secret is not configured as it would produce // garbage if ($GLOBALS['cfg']['LoginCookieRecall'] @@ -109,7 +129,14 @@ class AuthenticationCookie extends AuthenticationPlugin $autocomplete = ' autocomplete="off"'; } - echo $this->template->render('login/header', ['theme' => $GLOBALS['PMA_Theme']]); + // wrap the login form in a div which overlays the whole page. + if($session_expired) { + echo $this->template->render('login/header', ['theme' => $GLOBALS['PMA_Theme'], + 'add_class' => ' modal_form', 'session_expired' => 1]); + } else { + echo $this->template->render('login/header', ['theme' => $GLOBALS['PMA_Theme'], + 'add_class' => '', 'session_expired' => 0]); + } if ($GLOBALS['cfg']['DBG']['demo']) { echo '