autologout.module in Automated Logout 8
Same filename and directory in other branches
Automated Logout - Module.
File
autologout.moduleView source
<?php
/**
* @file
* Automated Logout - Module.
*/
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\user\Entity\User;
use Drupal\Component\Utility\Xss;
/**
* Implements hook_help().
*/
function autologout_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.autologout':
$seconds = \Drupal::service('autologout.manager')
->getUserTimeout();
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t("This module allows you to force site users to be logged out after a given amount of time due to inactivity after first being presented with a confirmation dialog. Your current logout threshold is %seconds seconds.", [
'%seconds' => $seconds,
]) . '</p>';
return $output;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Adds a field to user/edit to change that users logout.
*/
function autologout_form_user_form_alter(&$form, FormStateInterface $form_state) {
$user = \Drupal::currentUser();
$account = $form_state
->getFormObject()
->getEntity();
$user_id = $account
->id();
$access = FALSE;
// If user-specific thresholds are enabled (the default), and user has access
// to change and they are changing their own and only
// their own timeout, or they are an admin.
if (!\Drupal::config('autologout.settings')
->get('no_individual_logout_threshold') && !\Drupal::currentUser()
->isAnonymous() && ($user
->hasPermission('change own logout threshold') && $user
->id() == $user_id || $user
->hasPermission('administer autologout'))) {
$access = TRUE;
if ($user_id !== NULL) {
$autologout_data = \Drupal::service('user.data')
->get('autologout', $user_id, 'timeout');
}
}
if ($access) {
$max_timeout = \Drupal::config('autologout.settings')
->get('max_timeout');
$form['user_' . $user_id] = [
'#type' => 'textfield',
'#title' => t('Your current logout threshold'),
'#default_value' => isset($autologout_data) ? $autologout_data : '',
'#size' => 8,
'#description' => t('The length of inactivity time, in seconds, before automated log out. Must be between 60 and @max_timeout seconds.', [
'@max_timeout' => $max_timeout,
]),
'#element_validate' => [
'_autologout_user_uid_timeout_validate',
],
];
$form['actions']['submit']['#submit'][] = 'autologout_user_profile_submit';
}
}
/**
* Form validation.
*/
function _autologout_user_uid_timeout_validate($element, FormStateInterface $form_state) {
$max_timeout = \Drupal::config('autologout.settings')
->get('max_timeout');
$timeout = $element['#value'];
// Set error if timeout isn't strictly a number between 60 and max.
if ($timeout != "" && ($timeout < 10 || $timeout > 0 && $timeout < 60 || $timeout > $max_timeout || !is_numeric($timeout))) {
$form_state
->setError($element, t('The timeout must be an integer greater than 60, and less then %max.', [
'%max' => $max_timeout,
]));
}
}
/**
* Handle submission of timeout threshold in user/edit.
*/
function autologout_user_profile_submit(&$form, FormStateInterface $form_state) {
$user = \Drupal::currentUser();
$user_id = $form_state
->getFormObject()
->getEntity()
->id();
$access = FALSE;
// If user-specific thresholds are enabled (the default), and user has access
// to change and they are changing their own and only
// their own timeout, or they are an admin.
if (!\Drupal::currentUser()
->isAnonymous() && ($user
->hasPermission('change own logout threshold') && $user
->id() == $user_id || $user
->hasPermission('administer autologout'))) {
$access = TRUE;
}
// Access is reused here as a security measure. Not only will the element not
// display but wont submit without access.
// Do not store config if setting to not store config for every user is TRUE.
if ($access && !\Drupal::config('autologout.settings')
->get('no_individual_logout_threshold')) {
$timeout = $form_state
->getValue('user_' . $user_id);
\Drupal::service('user.data')
->set('autologout', $user_id, 'timeout', $timeout);
}
\Drupal::service('user.data')
->set('autologout', $user_id, 'timeout', $timeout);
}
/**
* Implements hook_autologout_prevent().
*/
function autologout_autologout_prevent() {
$user = \Drupal::currentUser();
$user_ip = \Drupal::request()
->getClientIp();
// Don't include autologout JS checks on ajax callbacks.
$paths = [
'system',
'autologout_ajax_get_time_left',
'autologout_ajax_logout',
'autologout_ajax_set_last',
];
// getPath is used because Url::fromRoute('<current>')->toString() doesn't
// give correct path for XHR request.
$url = \Drupal::service('path.current')
->getPath();
$path_args = explode('/', $url);
// Check if user IP address is in the whitelist.
$ip_address_whitelist = array_map('trim', explode("\n", trim(\Drupal::config('autologout.settings')
->get('whitelisted_ip_addresses'))));
if (in_array($path_args[1], $paths)) {
return TRUE;
}
// If user is anonymous or has no timeout set.
if ($user
->id() == 0 || !\Drupal::service('autologout.manager')
->getUserTimeout()) {
return TRUE;
}
// If the user has checked remember_me via the remember_me module.
$remember_me = \Drupal::service('user.data')
->get('remember_me', $user
->id(), 'remember_me');
if (!empty($remember_me)) {
return TRUE;
}
// If the user has checked Remember me on the login page via
// the persistent_login module.
if (\Drupal::hasService('persistent_login.token_manager')) {
$request = \Drupal::request();
// Get cookie from request.
$cookie = \Drupal::service('persistent_login.cookie_helper')
->getCookieValue($request);
if (isset($cookie)) {
// Get all user's tokens.
$rememberPersistentTokens = \Drupal::service('persistent_login.token_manager')
->getTokensForUser(User::load($user
->id()));
$count = count($rememberPersistentTokens);
if ($count > 0) {
// Get current token.
$currentToken = \Drupal::service('persistent_login.token_handler')
->getTokenFromCookie($request);
foreach ($rememberPersistentTokens as $value) {
if (1 == $value
->getStatus() && $value
->getSeries() == $currentToken
->getSeries()) {
return TRUE;
}
}
}
}
}
if (!empty($ip_address_whitelist) && in_array($user_ip, $ip_address_whitelist)) {
return TRUE;
}
}
/**
* Implements hook_autologout_refresh_only().
*/
function autologout_autologout_refresh_only() {
if (!\Drupal::config('autologout.settings')
->get('enforce_admin') && \Drupal::service('router.admin_context')
->isAdminRoute(\Drupal::routeMatch()
->getRouteObject())) {
return TRUE;
}
}
/**
* Implements hook_page_attachments().
*
* Add a form element to every page which is used to detect if the page was
* loaded from browser cache. This happens when the browser's back button is
* pressed for example. The JS will set the value of the hidden input element
* to 1 after initial load. If this is 1 on subsequent loads, the page was
* loaded from cache and an autologout timeout refresh needs to be triggered.
*/
function autologout_page_attachments(array &$page) {
$autologout_manager = \Drupal::service('autologout.manager');
// Check if JS should be included on this request.
if ($autologout_manager
->preventJs()) {
return;
}
// Check if anything wants to be refresh only. This URL would include the
// javascript but will keep the login alive whilst that page is opened.
$refresh_only = $autologout_manager
->refreshOnly();
$settings = \Drupal::config('autologout.settings');
// Get all settings JS will need for dialog.
$timeout = $autologout_manager
->getUserTimeout();
$timeout_padding = $settings
->get('padding');
$redirect_url = $autologout_manager
->getUserRedirectUrl();
$redirect_query = \Drupal::service('redirect.destination')
->getAsArray() + array(
'autologout_timeout' => 1,
);
$no_dialog = $settings
->get('no_dialog');
$disable_buttons = $settings
->get('disable_buttons');
$yes_button = $settings
->get('yes_button');
if (empty($yes_button)) {
$yes_button = t('Yes');
}
$no_button = $settings
->get('no_button');
if (empty($no_button)) {
$no_button = t('No');
}
$use_alt_logout_method = $settings
->get('use_alt_logout_method');
$title = $settings
->get('dialog_title');
if (!$title) {
$title = \Drupal::config('system.site')
->get('name') . ' Alert';
}
$msg = t(Xss::filter($settings
->get('message')));
$logout_regardless_of_activity = $settings
->get('logout_regardless_of_activity');
$settings = [
'timeout' => $refresh_only ? $timeout * 500 : $timeout * 1000,
'timeout_padding' => $timeout_padding * 1000,
'message' => $msg,
'redirect_url' => Url::fromUserInput($redirect_url, [
'query' => $redirect_query,
])
->toString(),
'title' => t($title),
'refresh_only' => $refresh_only,
'no_dialog' => $no_dialog,
'disable_buttons' => $disable_buttons,
'yes_button' => $yes_button,
'no_button' => $no_button,
'use_alt_logout_method' => $use_alt_logout_method,
'logout_regardless_of_activity' => $logout_regardless_of_activity,
];
// If this is an AJAX request, then the logout redirect url should still be
// referring to the page that generated this request.
$current_request = \Drupal::request();
if ($current_request
->isXmlHttpRequest()) {
$base_url = Url::fromRoute('<front>', [], [
'absolute' => TRUE,
])
->toString();
$referer = $current_request->headers
->get('referer');
if ($referer) {
$destination = str_replace($base_url . '/', '', $referer);
}
else {
$destination = $base_url;
}
$settings['redirect_url'] = Url::fromUserInput($redirect_url, [
'query' => [
'destination' => urlencode($destination),
],
'autologout_timeout' => 1,
]);
}
autologout_attach_js($page, $settings);
}
/**
* Implements hook_page_bottom().
*/
function autologout_page_bottom() {
if (!\Drupal::service('autologout.manager')
->preventJs()) {
$page_bottom['autologout'] = [
'#markup' => '<form id="autologout-cache-check"><input type="hidden" id="autologout-cache-check-bit" value="0" /></form>',
];
}
}
/**
* Adds the necessary js and libraries.
*
* @param array $element
* The renderable array element to #attach the js to.
* @param array $settings
* The JS Settings.
*/
function autologout_attach_js(array &$element, array $settings) {
$element['#attached']['drupalSettings']['autologout'] = $settings;
$element['#attached']['library'][] = 'autologout/drupal.autologout';
$element['#cache']['tags'][] = 'config:autologout.settings';
}
/**
* Implements hook_user_login().
*
* Delete stale sessions for the user on login. This stops
* session_limit module thinking the user has reached their
* session limit.
*/
function autologout_user_login($account) {
// Cleanup old sessions.
$timeout = \Drupal::service('autologout.manager')
->getUserTimeout($account
->id());
if (empty($timeout)) {
// Users that don't get logged have their sessions left.
return;
}
$timeout_padding = \Drupal::config('autologout.settings')
->get('padding');
$timestamp = \Drupal::time()
->getRequestTime() - ($timeout + $timeout_padding);
// Find all stale sessions.
$database = \Drupal::database();
$sids = $database
->select('sessions', 's')
->fields('s', [
'sid',
])
->condition('uid', $account
->id())
->condition('timestamp', $timestamp, '<')
->orderBy('timestamp', 'DESC')
->execute()
->fetchCol();
if (!empty($sids)) {
// Delete stale sessions at login.
$database
->delete('sessions')
->condition('sid', $sids, 'IN')
->execute();
}
// Add login time cookie.
user_cookie_save([
'autologout_login' => \Drupal::time()
->getCurrentTime(),
]);
}
Functions
Name | Description |
---|---|
autologout_attach_js | Adds the necessary js and libraries. |
autologout_autologout_prevent | Implements hook_autologout_prevent(). |
autologout_autologout_refresh_only | Implements hook_autologout_refresh_only(). |
autologout_form_user_form_alter | Implements hook_form_FORM_ID_alter(). |
autologout_help | Implements hook_help(). |
autologout_page_attachments | Implements hook_page_attachments(). |
autologout_page_bottom | Implements hook_page_bottom(). |
autologout_user_login | Implements hook_user_login(). |
autologout_user_profile_submit | Handle submission of timeout threshold in user/edit. |
_autologout_user_uid_timeout_validate | Form validation. |