File: /var/www/html/wp-content/plugins/wp-fail2ban/admin/admin.php
<?php declare(strict_types=1);
/**
* Admin
*
* @package wp-fail2ban
* @since 4.4.0 Require PHP 7.4
* @since 4.0.0
*/
namespace org\lecklider\charles\wordpress\wp_fail2ban;
use WP_fail2ban\Lib\Badges\BadgeManager;
defined( 'ABSPATH' ) or exit;
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/widgets.php';
require_once __DIR__ . '/lib/about.php';
/**
* Helper: Add a new submenu "under" the Freemius "Add-Ons" submenu
*
* @since 4.4.0 Add type hints
* @since 4.3.2.1 Backport from 4.3.4.0
*
* @param string $page_title The text to be displayed in the title tags of the page when the menu
* is selected.
* @param string|null $capability The capability required for this menu to be displayed to the user.
* @param string $menu_slug The slug name to refer to this menu by. Should be unique for this menu
* and only include lowercase alphanumeric, dashes, and underscores characters
* to be compatible with sanitize_key().
* @param callable $function The function to be called to output the content for this page.
* @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required.
*/
function add_wpf2b_addon_page( string $page_title, ?string $capability, string $menu_slug, $function ) {
global $submenu;
$menu_title = " - $page_title";
if ( ! $capability ) {
$capability = ( is_multisite() )
? 'manage_network_options'
: 'manage_options';
}
$parent = ( wf_fs()->is_activation_mode() ) ? null : 'wp-fail2ban-menu';
$sub_menu = 'wp-fail2ban-menu-addons';
if ( $hook = add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function ) ) {
foreach ( $submenu as &$menu ) {
if ( isset( $menu[0] ) && $menu[0][2] == 'wp-fail2ban-menu' ) {
$new_submenu = array();
$menu_item = array_pop( $menu );
// Find the submenu we're appending to
for ( $i = 0; $i < count( $menu ) && $sub_menu != $menu[ $i ][2]; $i++ ) {
$new_submenu[] = $menu[ $i ];
}
if ( $i < count( $menu ) ) {
$new_submenu[] = $menu[ $i++ ];
}
// Find the menu item alphabetically before the new item
for ( ; $i < count( $menu ) && isset( $menu[ $i ][0] ) && 0 === strpos( $menu[ $i ][0], ' - ' ) && 0 > strcmp( $menu[ $i ][0], $menu_title ); $i++ ) {
$new_submenu[] = $menu[ $i ];
}
$new_submenu[] = $menu_item;
for ( ; $i < count( $menu ); $i++ ) {
$new_submenu[] = $menu[ $i ];
}
$menu = $new_submenu;
break;
}
}
}
return $hook;
}
/**
* Output readme.txt to standard About format
*
* @since 4.4.0 Add type hints, return type
* @since 4.3.2.2
*
* @param string $ver Version stem, e.g. 4.3.2
* @param string $file Full path to readme.txt
*
* @return void
*/
function readme( string $ver, string $file ): void {
if ( file_exists( $file ) ) {
$rm = file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$inChangelog = $inList = $inSubList = false;
foreach ( $rm as $line ) {
if ( '== Changelog ==' == $line ) {
$inChangelog = true;
echo "<dl>\n";
continue;
}
if ( $inChangelog ) {
if ( preg_match( '/^= (.*) =$/', $line, $matches ) &&
( 'Develop' == $matches[1] || substr( $matches[1], 0, strlen( $ver ) ) == $ver ) ) {
if ( $inList ) {
echo "</ul></dd>\n";
}
echo "<dt>{$matches[1]}</dt>\n";
echo "<dd><ul>\n";
$inList = true;
} elseif ( preg_match( '/^(\s*)\* (.*)$/', $line, $matches ) ) {
$li = $matches[2];
$li = preg_replace( '/\[(.*?)\]\((.*?)\)(\.)?/', '<a href="$2" target="_blank" rel="noopener">$1 <span class="dashicons dashicons-external"></span></a>', $li );
$li = preg_replace( '/`(.*?)`/', '<tt>$1</tt>', $li );
$li = preg_replace( '/\*\*(.*?)\*\*/', '<b>$1</b>', $li );
$li = preg_replace( '/\*(.*?)\*/', '<i>$1</i>', $li );
$li = preg_replace( '|\((h/t .*?)\)|', '<span class="ht">$1</span>', $li );
$li = preg_replace( '/^(Fix|Deprecate )/', '<span style="color:red">$1</span>', $li );
$li = preg_replace( '/^(Update )/', '<span style="color:purple">$1</span>', $li );
$li = preg_replace( '/^(Site Health|WAF: )/', '<span style="color:blue">$1</span>', $li );
$li = preg_replace( '/\[((Canonical|Premium) only)\]/', '<span style="color: grey; font-style: italic; font-weight: bold">$1</span>', $li );
if ( ! $inSubList && strlen( $matches[1] ) ) {
echo '<ul>';
$inSubList = true;
} elseif ( $inSubList && ! strlen( $matches[1] ) ) {
echo '</ul>';
$inSubList = false;
}
echo "<li>{$li}</li>\n";
} else {
if ( $inList ) {
echo "</ul></dd>\n";
$inList = false;
}
echo "</dl>\n";
$inChangelog = false;
break;
}
}
}
} else {
echo "<p>Error: Cannot open <tt>readme.txt</tt></p>\n";
}
}
/**
* Helper: Security and Settings menu
*
* @since 5.4.0 Drop security page
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @param string $capability Capability
*
* @return void
*/
function _security_settings( string $capability = 'manage_options' ): void {
_settings( apply_filters( __METHOD__ . '.page', 'logging' ), $capability );
}
/**
* Helper: Settings menu
*
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @param $page string|null
* @param $capability string
*
* @return void
*/
function _settings( string $page = null, string $capability = 'manage_options' ): void {
if ( $hook = add_submenu_page(
'wp-fail2ban-menu',
__( 'Settings', 'wp-fail2ban' ),
__( 'Settings', 'wp-fail2ban' ),
$capability,
'wpf2b-settings',
__NAMESPACE__ . '\settings'
) ) {
add_action(
"load-$hook",
function () use ( $page ) {
wp_enqueue_style( 'wpf2b-admin', plugins_url( 'css/admin.css', __FILE__ ) );
apply_filters( 'wp_fail2ban_init_tabs', false );
TabBase::setDefaultTab( $page );
TabBase::getActiveTab()->current_screen();
}
);
}
}
/**
* Register admin menus
*
* @since 4.4.0 Add return type
* @since 4.0.0
*
* @return void
*/
function admin_menu(): void {
if ( ! is_multisite() ) {
if ( ( defined( 'WP_FAIL2BAN_FREE_ONLY' ) && false !== WP_FAIL2BAN_FREE_ONLY ) || ! wf_fs()->can_use_premium_code() ) {
$hook = add_menu_page(
'WP fail2ban',
'WP fail2ban',
'manage_options',
'wp-fail2ban-menu',
__NAMESPACE__ . '\welcome',
plugin_dir_url( WP_FAIL2BAN_FILE ) . 'assets/menu.svg'
);
add_action(
"load-$hook",
function () {
wp_enqueue_style( 'wpf2b-admin', plugins_url( 'css/admin.css', __FILE__ ) );
}
);
add_action( 'admin_menu', __NAMESPACE__ . '\admin_menu_fix', PHP_INT_MAX );
do_action( 'wp_fail2ban_menu' );
_security_settings();
}
}
}
add_action( 'admin_menu', __NAMESPACE__ . '\admin_menu' );
/**
* Register network admin menus
*
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @return void
*/
function network_admin_menu(): void {
if ( ( defined( 'WP_FAIL2BAN_FREE_ONLY' ) && false !== WP_FAIL2BAN_FREE_ONLY ) || ! wf_fs()->can_use_premium_code() ) {
_network_admin_menu();
}
}
add_action( 'network_admin_menu', __NAMESPACE__ . '\network_admin_menu' );
/**
* Actual network admin menu handler
*
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @return void
*/
function _network_admin_menu(): void {
$hook = add_menu_page(
'WP fail2ban',
'WP fail2ban',
'manage_options',
'wp-fail2ban-menu',
__NAMESPACE__ . '\welcome',
plugin_dir_url( WP_FAIL2BAN_FILE ) . 'assets/menu.svg'
);
add_action(
"load-$hook",
function () {
wp_enqueue_style( 'wpf2b-admin', plugins_url( 'css/admin.css', __FILE__ ) );
}
);
add_action( 'network_admin_menu', __NAMESPACE__ . '\admin_menu_fix', PHP_INT_MAX );
do_action( 'wp_fail2ban_menu' );
_security_settings();
}
/**
* Fix first submenu name.
*
* @since 5.4.0 Handle incomplete submenu
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @return void
*/
function admin_menu_fix(): void {
global $submenu;
if ( 'WP fail2ban' == ( $submenu['wp-fail2ban-menu'][0][0] ?? '' ) ) {
$submenu['wp-fail2ban-menu'][0][0] = __( 'Welcome', 'wp-fail2ban' );
}
if ( defined( 'WP_FAIL2BAN_FREE_ONLY' ) && WP_FAIL2BAN_FREE_ONLY ) {
remove_submenu_page( 'wp-fail2ban-menu', 'wp-fail2ban-menu-pricing' );
}
}
/**
* Add Settings link on Plugins page
*
* @since 4.4.0.8 Activate "normal" plugin if running as MU
* @since 4.4.0.3 Allow $plugin_data to be null despite spec
* @since 4.4.0 Add type hints, return type
* @since 4.2.0
*
* @param string[] $actions An array of plugin action links. By default this can include 'activate',
* 'deactivate', and 'delete'.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param array|null $plugin_data An array of plugin data. See `get_plugin_data()`.
* @param string $context The plugin context. By default this can include 'all', 'active', 'inactive',
* 'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
*
* @return string[]
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
function plugin_action_links( array $actions, string $plugin_file, ?array $plugin_data, string $context ): array {
if ( preg_match( "|$plugin_file\$|", WP_FAIL2BAN_FILE ) &&
( ! is_multisite() || is_network_admin() ) ) {
foreach ( get_mu_plugins() as $plugin => $data ) {
if ( 0 === strpos( $data['Name'], 'WP fail2ban' ) ) {
// MU plugin
//
// * Make sure the "normal" plugin is activated
// * Remove "Deactivate" and "Delete" links
$plugin = plugin_basename( WP_FAIL2BAN_FILE );
if ( array_key_exists( $plugin, get_plugins() ) && ! is_plugin_active( $plugin ) ) {
activate_plugin(
$plugin,
'', // don't redirect anywhere
false,
true // don't call activation hooks
);
}
unset( $actions['deactivate'] );
unset( $actions['delete'] );
break;
}
}
if ( ! wf_fs()->is_activation_mode() &&
( ! wf_fs()->can_use_premium_code() ||
( ( is_multisite() && wf_fs()->is_plan_or_trial( 'silver' ) ) ||
( ! is_multisite() && wf_fs()->is_plan_or_trial( 'bronze' ) ) ) ) ) {
$settings = sprintf(
'<a href="%s?page=wpf2b-settings&tab=about" title="%s">%s</a>',
network_admin_url( 'admin.php' ),
__( 'Settings', 'wp-fail2ban' ),
( function_exists( '\add_security_page' ) )
? '<span class="dashicon dashicons-admin-generic"></span>'
: __( 'Settings', 'wp-fail2ban' )
);
// Add Settings at the start
$actions = array_merge(
array(
'settings' => $settings,
),
$actions
);
}
}
return $actions;
}
add_filter( 'plugin_action_links', __NAMESPACE__ . '\plugin_action_links', PHP_INT_MAX, 4 );
add_filter( 'network_admin_plugin_action_links', __NAMESPACE__ . '\plugin_action_links', 99999, 4 );
/**
* Add help tab to Dashboard
*
* @since 4.4.0 Add return type
* @since 4.3.0
*
* @return void
*/
function admin_head_dashboard(): void {
$content = '';
if ( ( ! is_multisite() && current_user_can( 'manage_options' ) ) ||
( is_network_admin() && current_user_can( 'manage_network_options' ) ) ) {
$message = __( 'Shows the last 5 messages sent to <code>syslog</code> - provides simple status at a glance and can be helpful for debugging.', 'wp-fail2ban' );
if ( ! wf_fs()->can_use_premium_code() ) {
$message .= sprintf(
/* translators: %s: <a href> internals */
__( 'The <a %s>Premium version</a> provides more advanced views.', 'wp-fail2ban' ),
sprintf( 'href="%s"', network_admin_url( 'admin.php?page=wp-fail2ban-menu-pricing' ) )
);
}
$content = sprintf(
'<p><strong>%s</strong> — %s.</p>',
__( 'Last 5 Messages', 'wp-fail2ban' ),
$message
);
}
if ( ! empty( $content = apply_filters( 'wp_fail2ban_dashboard_help', $content ) ) ) {
get_current_screen()->add_help_tab(
array(
'id' => 'wp-fail2ban',
'title' => 'WP fail2ban',
'content' => $content,
)
);
}
}
add_action( 'admin_head-index.php', __NAMESPACE__ . '\admin_head_dashboard', 9999 );
/**
* Add badges to plugin listing
*
* @since 5.4.0
*
* @return void
*/
function admin_init(): void {
require_once WP_FAIL2BAN_DIR . '/vendor/wp-fail2ban/lib-badges/src/BadgeManager.php';
BadgeManager::init(
array(
'plugin_file' => WP_FAIL2BAN_FILE,
'free' => true, // @wpf2b-free-only
'lts' => true,
'show' => array(
'non-canonical' => false,
),
)
);
}
add_action( 'admin_init', __NAMESPACE__ . '\admin_init' );