You are here

saferpermissions.module in Safer Permissions 7

Disallows unwanted permissions for anonymous.

File

saferpermissions.module
View source
<?php

/**
 * @file
 * Disallows unwanted permissions for anonymous.
 */

/**
 * Implements hook_form_FORM_ID_alter().
 */
function saferpermissions_form_user_admin_permissions_alter(&$form, &$form_state) {
  if (isset($form['checkboxes'][DRUPAL_ANONYMOUS_RID])) {
    if (empty($form['checkboxes'][DRUPAL_ANONYMOUS_RID]['#process'])) {
      $checkboxes_element_info = element_info('checkboxes');
      $form['checkboxes'][DRUPAL_ANONYMOUS_RID]['#process'] = $checkboxes_element_info['#process'];
    }

    // Attach a process function which disables the checkboxes.
    $form['checkboxes'][DRUPAL_ANONYMOUS_RID]['#process'][] = '_saferpermissions_anonymous_permissions_process';

    // Attach a validator which makes sure that the checkbox is not checked
    // even if the user checks the checkbox by removing the disabled attribute
    // manually.
    $form['checkboxes'][DRUPAL_ANONYMOUS_RID]['#element_validate'][] = '_saferpermissions_anonymous_permissions_element_validate';
  }
}

/**
 * Form element process callback.
 *
 * This function disables permission checkboxes on anonymous users.
 */
function _saferpermissions_anonymous_permissions_process($element) {
  foreach (array_keys(saferpermissions_disallowed_permissions_anonymous()) as $permission) {
    $element[$permission]['#disabled'] = TRUE;
    $element[$permission]['#default_value'] = FALSE;
  }
  return $element;
}

/**
 * Form element validation callback.
 *
 * This function makes sure that a disabled permission checkbox will not be
 * checked.
 */
function _saferpermissions_anonymous_permissions_element_validate($element, &$form_state, $form) {
  foreach (saferpermissions_disallowed_permissions_anonymous() as $permission => $title) {
    if (isset($element[$permission]['#value']) && $element[$permission]['#value']) {
      form_error($element[$permission], t('You cannot grant %permission to anonymous users for security reasons.', array(
        '%permission' => strip_tags($title),
      )));
    }
  }
}

/**
 * Gathers the list of permission which should be banned for anonymous users.
 *
 * @return array
 *   List of permissions.
 */
function saferpermissions_disallowed_permissions_anonymous() {
  $cache =& drupal_static(__FUNCTION__, NULL);
  if ($cache === NULL) {
    $cache = array();
    $filters = array(
      '_saferpermissions_is_restricted',
      '_saferpermissions_is_banned',
      '_saferpermissions_is_banned_word',
    );
    foreach (module_invoke_all('permission') as $name => $info) {
      if (!_saferpermissions_is_whitelisted($name)) {
        foreach ($filters as $filter) {
          if ($filter($name, $info)) {
            $cache[$name] = $info['title'];
            break;
          }
        }
      }
    }
  }
  return $cache;
}

/**
 * Checks if a permission is on the whitelist.
 *
 * @param $name
 *   Name of the permission.
 *
 * @return bool
 */
function _saferpermissions_is_whitelisted($name) {
  return in_array($name, saferpermissions_permission_whitelist());
}

/**
 * Checks if a permission is restricted.
 *
 * @param string $name
 *   Name of the permission.
 * @param array $info
 *   Permission declaration.
 *
 * @return bool
 */
function _saferpermissions_is_restricted($name, array $info) {
  return !empty($info['restrict access']);
}

/**
 * Checks if a permission is on the blacklist.
 *
 * @param string $name
 *   Name of the permission.
 * @param array $info
 *   Permission declaration.
 *
 * @return bool
 */
function _saferpermissions_is_banned($name, array $info) {
  return in_array($name, saferpermissions_permission_blacklist());
}

/**
 * Returns a list of whitelisted permissions.
 *
 * @return array
 *   List of whitelisted words.
 */
function saferpermissions_permission_whitelist() {
  $cache =& drupal_static(__FUNCTION__, NULL);
  if ($cache === NULL) {
    $cache = module_invoke_all('saferpermissions_anonymous_permission_whitelist_info');
    drupal_alter('saferpermissions_anonymous_permission_whitelist_info', $cache);
  }
  return $cache;
}

/**
 * Returns the list of permissions which should be disabled on anonymous users.
 *
 * @return array
 *   List of disabled permissions.
 */
function saferpermissions_permission_blacklist() {
  $cache =& drupal_static(__FUNCTION__, NULL);
  if ($cache === NULL) {
    $cache = module_invoke_all('saferpermissions_anonymous_permission_ban_info');
    drupal_alter('saferpermissions_anonymous_permission_ban_info', $cache);
  }
  return $cache;
}

/**
 * Returns a list of words.
 *
 * These should disable any permission on anonymous users which contains them.
 *
 * @return array
 *   List of words.
 */
function saferpermissions_permission_wordlist() {
  $cache =& drupal_static(__FUNCTION__, NULL);
  if ($cache === NULL) {
    $cache = module_invoke_all('saferpermissions_anonymous_permission_wordlist_ban_info');
    drupal_alter('saferpermissions_anonymous_permission_wordlist_ban_info', $cache);
  }
  return $cache;
}

/**
 * Implements hook_saferpermissions_anonymous_permission_ban_info().
 */
function saferpermissions_saferpermissions_anonymous_permission_ban_info() {
  $permissions = array(
    // Book
    'create new books',
    'add content to books',
    // Contextual links
    'access contextual links',
    // Dashboard
    'access dashboard',
    // Locale
    'translate interface',
    // Node
    'access content overview',
    'view revisions',
    'revert revisions',
    'delete revisions',
    // Overlay
    'access overlay',
    // Path
    'create url aliases',
    // Shortcut
    'customize shortcut links',
    'switch shortcut sets',
    // Statistics
    'access statistics',
    'view post access counter',
    // System
    'access administration pages',
    'access site in maintenance mode',
    'view the administration theme',
    'access site reports',
    // Toolbar
    'access toolbar',
    // User
    'cancel account',
  );
  foreach (filter_formats() as $name => $format) {
    if (_saferpermissions_text_format_is_forbidden($name)) {
      $permissions[] = filter_permission_name($format);
    }
  }
  return $permissions;
}

/**
 * Decides if a text format is safe for anonymous.
 *
 * @param string $name
 *   Machine name of the text format.
 *
 * @return bool
 *   Returns FALSE if the text format is safe, TRUE otherwise.
 */
function _saferpermissions_text_format_is_forbidden($name) {
  $filters = filter_list_format($name);

  // Display any HTML as plain text.
  if ($filters['filter_html_escape']->status) {
    return FALSE;
  }

  // Limit allowed HTML tags.
  if ($filters['filter_html']->status) {

    // Make sure that malicious HTML tags are not enabled.
    $allowed_html = $filters['filter_html']->settings['allowed_html'];
    $malicious_tags = array(
      'iframe',
      'script',
      'style',
      'link',
      'object',
      'embed',
    );
    foreach ($malicious_tags as $malicious_tag) {
      if (strpos($allowed_html, "<{$malicious_tag}>") !== FALSE) {
        return TRUE;
      }
    }
    return FALSE;
  }

  // HTML Purifier.
  if (isset($filters['htmlpurifier_basic']) && $filters['htmlpurifier_basic']->status) {
    return FALSE;
  }
  return TRUE;
}

/**
 * Implements hook_saferpermissions_anonymous_permission_wordlist_ban_info().
 */
function saferpermissions_saferpermissions_anonymous_permission_wordlist_ban_info() {
  return array(
    'administer',
    'bypass',
    'migrate',
    'import',
    'own',
    'any',
    'all',
    'php',
    'edit terms in',
    'delete terms in',
  );
}

/**
 * Implements hook_saferpermissions_anonymous_permission_whitelist_info().
 */
function saferpermissions_saferpermissions_anonymous_permission_whitelist_info() {
  return array(
    // Node
    'view own unpublished content',
    // Vote
    'cancel own vote',
    'inspect all votes',
  );
}

/**
 * Checks if a permission contains a blacklisted word.
 *
 * @param string $name
 *   Name of the permission.
 * @param array $info
 *   Permission declaration.
 *
 * @return bool
 */
function _saferpermissions_is_banned_word($name, array $info) {
  foreach (saferpermissions_permission_wordlist() as $word) {
    if (preg_match('/\\b' . preg_quote($word, '/') . '\\b/im', $name)) {
      return TRUE;
    }
  }
  return FALSE;
}

Functions

Namesort descending Description
saferpermissions_disallowed_permissions_anonymous Gathers the list of permission which should be banned for anonymous users.
saferpermissions_form_user_admin_permissions_alter Implements hook_form_FORM_ID_alter().
saferpermissions_permission_blacklist Returns the list of permissions which should be disabled on anonymous users.
saferpermissions_permission_whitelist Returns a list of whitelisted permissions.
saferpermissions_permission_wordlist Returns a list of words.
saferpermissions_saferpermissions_anonymous_permission_ban_info Implements hook_saferpermissions_anonymous_permission_ban_info().
saferpermissions_saferpermissions_anonymous_permission_whitelist_info Implements hook_saferpermissions_anonymous_permission_whitelist_info().
saferpermissions_saferpermissions_anonymous_permission_wordlist_ban_info Implements hook_saferpermissions_anonymous_permission_wordlist_ban_info().
_saferpermissions_anonymous_permissions_element_validate Form element validation callback.
_saferpermissions_anonymous_permissions_process Form element process callback.
_saferpermissions_is_banned Checks if a permission is on the blacklist.
_saferpermissions_is_banned_word Checks if a permission contains a blacklisted word.
_saferpermissions_is_restricted Checks if a permission is restricted.
_saferpermissions_is_whitelisted Checks if a permission is on the whitelist.
_saferpermissions_text_format_is_forbidden Decides if a text format is safe for anonymous.