HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux acmehomecare 5.15.0-151-generic #161-Ubuntu SMP Tue Jul 22 14:25:40 UTC 2025 x86_64
User: www-data (33)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/html/wp-content/plugins/wp-fail2ban/feature/user-enum.php
<?php declare(strict_types=1);
/**
 * User enumeration
 *
 * @package wp-fail2ban
 * @since   4.4.0   Require PHP 7.4
 * @since   4.0.0
 */
namespace    org\lecklider\charles\wordpress\wp_fail2ban\feature;

use          org\lecklider\charles\wordpress\wp_fail2ban\Syslog;

use function org\lecklider\charles\wordpress\wp_fail2ban\array_value;
use function org\lecklider\charles\wordpress\wp_fail2ban\bail;

defined('ABSPATH') or exit;

/**
 * Common enumeration handling
 *
 * @since  4.4.0    Add return type
 * @since  4.3.4.0  Refactor to use Syslog::single
 * @since  4.3.0    Remove JSON support
 * @since  4.1.0    Add JSON support
 * @since  4.0.0
 *
 * @return bool
 *
 * @codeCoverageIgnore
 *
 * @wp-f2b-hard Blocked user enumeration attempt
 */
function _log_bail_user_enum(): bool
{
    Syslog::single(LOG_NOTICE, 'Blocked user enumeration attempt');

    do_action(__FUNCTION__);

    return bail();
}

/**
 * Catch traditional user enum
 *
 * @see \WP::parse_request()
 *
 * @since  4.4.0    Add type hint
 * @since  4.3.2.1  Backport from 4.3.4.0
 * @since  4.3.0.6  Ignore `author` if it's the current user
 * @since  4.3.0    Refactored to make XDebug happy; h/t @dinghy
 *                  Changed cap to 'edit_others_posts'
 * @since  3.5.0    Refactored for unit testing
 * @since  2.1.0
 *
 * @param \WP   $query
 *
 * @return \WP|bool
 */
function parse_request(\WP $query)
{
    /**
     * Is there an author in the query?
     */
    if (is_null($author = array_value('author', $query->query_vars))) {
        return $query;

    /**
     * Are they asking about themselves?
     */
    } elseif (get_current_user_id() == intval($author)) {
        return $query;

    /**
     * Does the user have enough privileges this doesn't matter?
     */
    } elseif (current_user_can('edit_others_posts')) {
        return $query;

    /**
     * OK, we have an unprivileged user asking about a different user
     */
    } else {
        global $pagenow;

        /**
         * `edit.php` allows Contributors to list posts by other users
         */
        if (is_admin() && 'edit.php' == $pagenow && current_user_can('edit_posts')) {
            return $query;

        /**
         * TODO: is there some other esoteric case to handle?
         */
        } else {
            // noop
        }
    }

    return _log_bail_user_enum();
}

/**
 * Catch RESTful user list
 *
 * @see \WP_REST_Users_Controller::get_items()
 *
 * @since  4.4.0    Add return type
 * @since  4.3.4.0  Refactor to use Syslog::single
 * @since  4.3.0    Change to 'edit_others_posts'
 * @since  4.0.0
 *
 * @param  array            $prepared_args
 * @param  \WP_REST_Request $request
 *
 * @return array|\WP_Error
 *
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */
function rest_user_query(array $prepared_args, \WP_REST_Request $request)
{
    /**
     * ClassicPress and pre-WP 5.4: this is all that's needed
     */
    if (current_user_can('edit_others_posts')) {
        return $prepared_args;

    /**
     * >= 5.x WordPress tries to pre-load the list of Authors,
     * regardless of the current user's role or capabilities.
     *
     * Returning 403 seems not to break anything, but we don't
     * want to trigger fail2ban.
     */
    } elseif (is_user_logged_in() &&
              array_key_exists('who', $prepared_args) &&
              'authors' == $prepared_args['who'])
    {
        Syslog::single(LOG_DEBUG, 'Blocked authors enumeration');

        return bail();

    /**
     * TODO: is there some other esoteric case to handle?
     */
    } else {
        // noop
    }

    return _log_bail_user_enum();
}

/**
 * Catch oembed user info
 *
 * @see \get_oembed_response_data()
 *
 * @since  4.4.0    Add type hints, return type
 * @since  4.2.7
 *
 * @param  array    $data   The response data.
 * @param  WP_Post  $post   The post object.
 * @param  int      $width  The requested width.
 * @param  int      $height The calculated height.
 *
 * @return array
 *
 * @codeCoverageIgnore
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */
function oembed_response_data(array $data, \WP_Post $post, int $width, int $height): array
{
    unset($data['author_name']);
    unset($data['author_url']);

    return $data;
}

/**
 * Return empty user sitemap
 *
 * Bots can guess the sitemap name so return an empty list.
 *
 * @since  5.0.0
 *
 * @param  $null    null
 * @param  int      $page_num
 *
 * @return array    Empty array
 *
 * @codeCoverageIgnore
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */
function wp_sitemaps_users_pre_url_list($null, int $page_num): array
{
    return [];
}

/**
 * Return zero pages
 *
 * This removes the list of users from the sitemap to make search engines happier.
 *
 * @since  5.0.0
 *
 * @param  $null    null
 *
 * @return int      0
 *
 * @codeCoverageIgnore
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */
function wp_sitemaps_users_pre_max_num_pages($null): int
{
    return 0;
}

/**
 * Drop users sitemap provider
 *
 * @since  5.0.0
 *
 * @param  WP_Sitemaps_Provider $provider Instance of a WP_Sitemaps_Provider.
 * @param  string               $name     Name of the sitemap provider.
 *
 * @return bool false
 */
function wp_sitemaps_add_provider($provider, $name)
{
    return ('users' == $name)
        ? false
        : $provider;
}