Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)

This commit is contained in:
Hanson.xyz Dev
2025-11-28 17:19:54 -06:00
parent 78a744ef06
commit abbd3502e8
430 changed files with 137111 additions and 7 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
<?php
/**
* Do not modify the files in this folder.
*/
@@ -0,0 +1,626 @@
<?php
/**
* Inits the admin dashboard side of things.
* Main admin file which loads all settings panels and sets up admin menus.
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Admin_Init {
/**
* Whether the page is admin dashboard page.
*
* @var boolean
*/
private $is_admin_dashboard_page;
/**
* Whether the page is admin AIOS page.
*
* @var boolean
*/
private $is_aiowps_admin_page;
/**
* An array of submenu items
*
* @var array
*/
private $menu_items = array();
/**
* Used in the premium plugin to add submenus
*
* @var string
*/
public $main_menu_page;
/**
* Includes admin dependencies and hook admin actions.
*
* @return void
*/
public function __construct() {
// This class is only initialized if is_admin() is true
if (AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
$this->admin_includes();
add_action('admin_menu', array($this, 'setup_menu_items'));
add_action('admin_menu', array($this, 'create_admin_menus'));
add_action('admin_menu', array($this, 'premium_upgrade_submenu'), 40);
add_action('admin_init', array($this, 'aiowps_csv_download'));
}
add_action('admin_init', array($this, 'hook_admin_notices'));
// Make sure we are on our plugin's menu pages
if ($this->is_aiowps_admin_page()) {
add_action('admin_print_scripts', array($this, 'admin_menu_page_scripts'));
add_action('admin_print_styles', array($this, 'admin_menu_page_styles'));
add_action('init', array($this, 'init_hook_handler_for_admin_side'));
if (class_exists('AIOWPS_PREMIUM')) {
add_filter('admin_footer_text', array($this, 'display_footer_review_message'));
}
}
}
/**
* Sets up the menu items array which is used to build admin menus
*
* @return void
*/
public function setup_menu_items() {
$menu_items = array(
array(
'page_title' => __('Dashboard', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Dashboard', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_MAIN_MENU_SLUG,
'render_callback' => array($this, 'handle_dashboard_menu_rendering'),
'icon' => 'dashboard',
'order' => 20,
),
array(
'page_title' => __('Settings', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Settings', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_SETTINGS_MENU_SLUG,
'render_callback' => array($this, 'handle_settings_menu_rendering'),
'icon' => 'settings',
'order' => 30,
),
array(
'page_title' => __('User Security', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('User Security', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_USER_SECURITY_MENU_SLUG,
'render_callback' => array($this, 'handle_user_security_menu_rendering'),
'icon' => 'user_security',
'order' => 40,
),
array(
'page_title' => __('Database Security', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Database Security', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_DB_SEC_MENU_SLUG,
'render_callback' => array($this, 'handle_database_menu_rendering'),
'icon' => 'database_security',
'display_condition_callback' => 'is_super_admin',
'order' => 50,
),
array(
'page_title' => __('File Security', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('File Security', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_FILESYSTEM_MENU_SLUG,
'render_callback' => array($this, 'handle_filesystem_menu_rendering'),
'icon' => 'filesystem_security',
'order' => 60,
),
array(
'page_title' => __('Firewall', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Firewall', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_FIREWALL_MENU_SLUG,
'render_callback' => array($this, 'handle_firewall_menu_rendering'),
'icon' => 'firewall',
'order' => 70,
),
array(
'page_title' => __('Brute Force', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Brute Force', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_BRUTE_FORCE_MENU_SLUG,
'render_callback' => array($this, 'handle_brute_force_menu_rendering'),
'icon' => 'brute_force',
'order' => 80,
),
array(
'page_title' => __('Spam Prevention', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Spam Prevention', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_SPAM_MENU_SLUG,
'render_callback' => array($this, 'handle_spam_menu_rendering'),
'icon' => 'spam_prevention',
'order' => 90,
),
array(
'page_title' => __('Scanner', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Scanner', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_FILESCAN_MENU_SLUG,
'render_callback' => array($this, 'handle_filescan_menu_rendering'),
'icon' => 'scanner',
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
'order' => 100,
),
array(
'page_title' => __('Tools', 'all-in-one-wp-security-and-firewall'),
'menu_title' => __('Tools', 'all-in-one-wp-security-and-firewall'),
'menu_slug' => AIOWPSEC_TOOLS_MENU_SLUG,
'render_callback' => array($this, 'handle_tools_menu_rendering'),
'icon' => 'tools',
'order' => 110,
),
);
$menu_items = apply_filters('aiowpsecurity_menu_items', $menu_items);
$this->menu_items = array_filter($menu_items, 'AIOWPSecurity_Utility::should_display_item');
}
/**
* Function to get the menu items array
*
* @return array
*/
public function get_menu_items() {
return $this->menu_items;
}
/**
* This function creates and outputs the csv file for download
*
* @param array $items - the content
* @param array $export_keys - the keys for the content
* @param string $filename - the filename
*
* @return void
*/
public static function aiowps_output_csv($items, $export_keys, $filename = 'data.csv') {
header("Content-Type: text/csv; charset=utf-8");
header("Content-Disposition: attachment; filename=".$filename);
header("Pragma: no-cache");
header("Expires: 0");
$output = fopen('php://output', 'w'); //open output stream
fputcsv($output, $export_keys, ',', '"', '\\'); // let's put column names first
foreach ($items as $item) {
$csv_line = array();
foreach ($export_keys as $key => $value) {
if (isset($item[$key])) {
$csv_line[] = ('created' == $key) ? AIOWPSecurity_Utility::convert_timestamp($item[$key]) : $item[$key];
}
}
fputcsv($output, $csv_line, ',', '"', '\\');
}
}
/**
* This function will get the content that we want to export as CSV and send it to the download function
*
* @return void
*/
public function aiowps_csv_download() {
global $aio_wp_security;
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. Nonce check in two lines.
if (isset($_POST['aiowps_export_404_event_logs_to_csv'])) {//Export 404 event logs
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It IS the nonce, so...
$nonce = isset($_REQUEST['_wpnonce']) ? sanitize_key(wp_unslash($_REQUEST['_wpnonce'])) : '';
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-export-404-event-logs-to-csv-nonce');
if (is_wp_error($result)) {
$aio_wp_security->debug_logger->log_debug($result->get_error_message(), 4);
die(esc_html($result->get_error_message()));
}
include_once 'wp-security-list-404.php'; //For rendering the AIOWPSecurity_List_Table in tab1
$event_list_404 = new AIOWPSecurity_List_404(); //For rendering the AIOWPSecurity_List_Table in tab1
$event_list_404->prepare_items(true);
$export_keys = array(
'id' => __('Id', 'all-in-one-wp-security-and-firewall'),
'event_type' => __('Event Type', 'all-in-one-wp-security-and-firewall'),
'ip_or_host' => __('IP Address', 'all-in-one-wp-security-and-firewall'),
'url' => __('Attempted URL', 'all-in-one-wp-security-and-firewall'),
'referer_info' => __('Referer', 'all-in-one-wp-security-and-firewall'),
'created' => __('Date and time', 'all-in-one-wp-security-and-firewall'),
'status' => __('Lock Status', 'all-in-one-wp-security-and-firewall'),
);
AIOWPSecurity_Utility::output_csv($event_list_404->items, $export_keys, '404_event_logs.csv');
exit();
}
}
/**
* Check whether current admin page is All In One WP Security admin page or not.
*
* @return boolean True if All In One WP Security admin page, Otherwise false.
*/
private function is_aiowps_admin_page() {
if (isset($this->is_aiowps_admin_page)) {
return $this->is_aiowps_admin_page;
}
global $pagenow;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce on this _GET.
$this->is_aiowps_admin_page = (AIOWPSecurity_Utility_Permissions::has_manage_cap() && 'admin.php' == $pagenow && isset($_GET['page']) && false !== strpos(sanitize_title(wp_unslash($_GET['page'])), AIOWPSEC_MENU_SLUG_PREFIX));
return $this->is_aiowps_admin_page;
}
/**
* Hook admin notices on admin dashboard page and admin AIOS pages.
*
* @return void
*/
public function hook_admin_notices() {
if (!current_user_can('update_plugins')) {
return;
}
// If none of the admin dashboard page or the AIOS page, Then bail
if (!$this->is_admin_dashboard_page() && !$this->is_aiowps_admin_page()) {
return;
}
add_action('all_admin_notices', array($this, 'render_admin_notices'));
}
/**
* Check whether current admin page is Admin Dashboard page or not.
*
* @return boolean True if Admin Dashboard page, Otherwise false.
*/
private function is_admin_dashboard_page() {
if (isset($this->is_admin_dashboard_page)) {
return $this->is_admin_dashboard_page;
}
global $pagenow;
$this->is_admin_dashboard_page = 'index.php' == $pagenow;
return $this->is_admin_dashboard_page;
}
/**
* Render admin notices.
*
* @return void
*/
public function render_admin_notices() {
global $aio_wp_security;
$custom_notice_ids = array_merge(AIOS_Abstracted_Ids::custom_admin_notice_ids(), AIOS_Abstracted_Ids::htaccess_to_php_feature_notice_ids());
foreach ($custom_notice_ids as $custom_admin_notice_id) {
$aio_wp_security->notices->do_notice($custom_admin_notice_id, $custom_admin_notice_id);
}
// Bail if the premium plugin is active and does not show ads.
if (AIOWPSecurity_Utility_Permissions::is_premium_installed()) return;
$installed_at = $aio_wp_security->notices->get_aiowps_plugin_installed_timestamp();
$time_now = $aio_wp_security->notices->get_time_now();
$installed_for = $time_now - $installed_at;
$dismissed_dash_notice_until = (int) $aio_wp_security->configs->get_value('dismissdashnotice');
if ($this->is_admin_dashboard_page() && ($installed_at && $time_now > $dismissed_dash_notice_until && $installed_for > (14 * 86400)) || (defined('AIOWPSECURITY_FORCE_DASHNOTICE') && AIOWPSECURITY_FORCE_DASHNOTICE)) {
$aio_wp_security->include_template('notices/thanks-for-using-main-dash.php');
} elseif ($this->is_aiowps_admin_page() && $installed_at && $installed_for > 14*86400) {
$aio_wp_security->notices->do_notice(false, 'top');
}
}
/**
* This function will include any files needed for the admin dashboard
*
* @return void
*/
private function admin_includes() {
include_once('wp-security-admin-menu.php');
}
/**
* Enqueue admin JavaScripts.
*
* @return Void
*/
public function admin_menu_page_scripts() {
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
return;
}
wp_enqueue_script('jquery');
wp_enqueue_script('postbox');
wp_enqueue_script('dashboard');
wp_enqueue_script('thickbox');
wp_enqueue_script('media-upload');
wp_enqueue_script('chart-bundle', AIO_WP_SECURITY_URL . '/includes/chartjs/Chart.bundle.min.js', array(), AIO_WP_SECURITY_VERSION, true);
wp_enqueue_script('chartjs-gauge', AIO_WP_SECURITY_URL . '/includes/chartjs/chartjs-gauge.min.js', array(), AIO_WP_SECURITY_VERSION, true);
wp_register_script('jquery-blockui', AIO_WP_SECURITY_URL.'/includes/blockui/jquery.blockUI.js', array('jquery'), AIO_WP_SECURITY_VERSION, true);
wp_enqueue_script('jquery-blockui');
wp_register_script('aiowpsec-admin-js', AIO_WP_SECURITY_URL. '/js/wp-security-admin-script.js', array('jquery'), AIO_WP_SECURITY_VERSION, true);
wp_enqueue_script('aiowpsec-admin-js');
wp_localize_script('aiowpsec-admin-js',
'aios_data',
array(
'ajax_nonce' => wp_create_nonce('wp-security-ajax-nonce'),
)
);
wp_localize_script('aiowpsec-admin-js',
'aios_trans',
array(
'unexpected_response' => __('Unexpected response:', 'all-in-one-wp-security-and-firewall'),
'copied' => __('Copied', 'all-in-one-wp-security-and-firewall'),
'no_import_file' => __('You have not yet selected a file to import.', 'all-in-one-wp-security-and-firewall'),
'processing' => __('Processing...', 'all-in-one-wp-security-and-firewall'),
'invalid_domain' => __('Please enter a valid IP address or domain name.', 'all-in-one-wp-security-and-firewall'),
'logo' => AIO_WP_SECURITY_URL.'/images/plugin-logos/icon-aios-rgb.svg',
'saving' => __('Saving...', 'all-in-one-wp-security-and-firewall'),
'deleting' => __('Deleting...', 'all-in-one-wp-security-and-firewall'),
'blocking' => __('Blocking...', 'all-in-one-wp-security-and-firewall'),
'unlocking' => __('Unlocking...', 'all-in-one-wp-security-and-firewall'),
'clearing' => __('Clearing...', 'all-in-one-wp-security-and-firewall'),
'importing' => __('Importing...', 'all-in-one-wp-security-and-firewall'),
'exporting' => __('Exporting...', 'all-in-one-wp-security-and-firewall'),
'refreshing' => __('Refreshing...', 'all-in-one-wp-security-and-firewall'),
'scanning' => __('Scanning...', 'all-in-one-wp-security-and-firewall'),
'close' => __('Close', 'all-in-one-wp-security-and-firewall'),
'completed' => __('Completed.', 'all-in-one-wp-security-and-firewall'),
'refreshed' => __('Refreshed.', 'all-in-one-wp-security-and-firewall'),
'deleted' => __('Deleted.', 'all-in-one-wp-security-and-firewall'),
'show_info' => __('show more', 'all-in-one-wp-security-and-firewall'),
'hide_info' => __('hide', 'all-in-one-wp-security-and-firewall'),
'show_notices' => __('But the following notices have been raised', 'all-in-one-wp-security-and-firewall'),
'disabling' => __('Disabling...', 'all-in-one-wp-security-and-firewall'),
'setting_up_firewall' => __('Setting up firewall...', 'all-in-one-wp-security-and-firewall'),
'downgrading_firewall' => __('Downgrading firewall...', 'all-in-one-wp-security-and-firewall'),
'maintenance_mode_enabled' => __('Maintenance mode is currently enabled.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Remember to disable it when you are done.', 'all-in-one-wp-security-and-firewall'),
'maintenance_mode_disabled' => __('Maintenance mode is currently disabled.', 'all-in-one-wp-security-and-firewall'),
)
);
wp_register_script('aiowpsec-pw-tool-js', AIO_WP_SECURITY_URL. '/js/password-strength-tool.js', array('jquery'), AIO_WP_SECURITY_VERSION, true); // We will enqueue this in the user acct menu class
wp_localize_script('aiowpsec-pw-tool-js',
'aios_pwtool_trans',
array(
'years' => __('year(s)', 'all-in-one-wp-security-and-firewall'),
'months' => __('month(s)', 'all-in-one-wp-security-and-firewall'),
'days' => __('day(s)', 'all-in-one-wp-security-and-firewall'),
'hours' => __('hour(s)', 'all-in-one-wp-security-and-firewall'),
'minutes' => __('minute(s)', 'all-in-one-wp-security-and-firewall'),
'seconds' => __('second(s)', 'all-in-one-wp-security-and-firewall'),
'less_than_one_second' => __('less than one second', 'all-in-one-wp-security-and-firewall')
)
);
}
/**
* Enqueue admin styles.
*
* @return Void
*/
public function admin_menu_page_styles() {
wp_enqueue_style('dashboard');
wp_enqueue_style('thickbox');
wp_enqueue_style('global');
wp_enqueue_style('wp-admin');
$admin_css_version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : filemtime(AIO_WP_SECURITY_PATH. '/css/wp-security-admin-styles.css');
wp_enqueue_style('aiowpsec-admin-css', AIO_WP_SECURITY_URL. '/css/wp-security-admin-styles.css', array(), $admin_css_version);
}
/**
* Sets up various class and tasks needed for the admin dashboard
*
* @return void
*/
public function init_hook_handler_for_admin_side() {
$this->initialize_feature_manager();
$this->do_other_admin_side_init_tasks();
}
/**
* Show footer review message and link.
*
* @return string
*/
public function display_footer_review_message() {
$message = sprintf(
/* translators: 1: Product Name, 2: Rating, 3: Trustpilot URL, 4: G2 URL */
__('Enjoyed %1$s? Please leave us a %2$s rating on %3$s or %4$s', 'all-in-one-wp-security-and-firewall').' '.__('We really appreciate your support!', 'all-in-one-wp-security-and-firewall'),
'<b>' . htmlspecialchars('All In One Security') . '</b>',
'<span style="color:#2271b1">&starf;&starf;&starf;&starf;&starf;</span>',
'<a href="https://uk.trustpilot.com/review/aiosplugin.com" target="_blank">Trustpilot</a>',
'<a href="https://www.g2.com/products/all-in-one-wp-security-firewall/reviews" target="_blank">G2.com</a>'
);
return $message;
}
/**
* This function checks if the feature manager is initialized and initializes it if it is not then checks the feature status and recalculates the points
*
* @return void
*/
private function initialize_feature_manager() {
if (!isset($aiowps_feature_mgr)) {
$aiowps_feature_mgr = new AIOWPSecurity_Feature_Item_Manager();
$aiowps_feature_mgr->check_feature_status_and_recalculate_points();
$GLOBALS['aiowps_feature_mgr'] = $aiowps_feature_mgr;
}
}
/**
* Other admin side init tasks.
*
* @return Void
*/
private function do_other_admin_side_init_tasks() {
global $aio_wp_security;
//***New Feature improvement for Cookie Based Brute Force Protection***//
// The old "test cookie" used to be too easy to guess because someone could just read the code and get the value.
//So now we will drop a more secure test cookie using a 10 digit random string
if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention')) {
// This code is for users who had this feature saved using an older release. This will drop the new more secure test cookie to the browser
$test_cookie_name_saved = $aio_wp_security->configs->get_value('aiowps_cookie_brute_test');
if (empty($test_cookie_name_saved)) {
$random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
$test_cookie_name = 'aiowps_cookie_test_'.$random_suffix;
$aio_wp_security->configs->set_value('aiowps_cookie_brute_test', $test_cookie_name, true);
AIOWPSecurity_Utility::set_cookie_value($test_cookie_name, '1');
}
}
// For cookie test form submission case
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. No nonce on this _GET.
if (isset($_GET['page']) && AIOWPSEC_BRUTE_FORCE_MENU_SLUG == $_GET['page'] && isset($_GET['tab']) && 'cookie-based-brute-force-prevention' == $_GET['tab']) {
if (isset($_POST['aiowps_do_cookie_test_for_bfla'])) {
$random_suffix = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(10);
$test_cookie_name = 'aiowps_cookie_test_'.$random_suffix;
$aio_wp_security->configs->set_value('aiowps_cookie_brute_test', $test_cookie_name, true);
AIOWPSecurity_Utility::set_cookie_value($test_cookie_name, '1');
$cur_url = "admin.php?page=".AIOWPSEC_BRUTE_FORCE_MENU_SLUG."&tab=cookie-based-brute-force-prevention";
$redirect_url = AIOWPSecurity_Utility::add_query_data_to_url($cur_url, 'aiowps_cookie_test', "1");
AIOWPSecurity_Utility::redirect_to_url($redirect_url);
}
if (isset($_REQUEST['aiowps_cookie_test'])) {
$test_cookie = $aio_wp_security->configs->get_value('aiowps_cookie_brute_test');
$cookie_val = AIOWPSecurity_Utility::get_cookie_value($test_cookie);
if (empty($cookie_val)) {
$aio_wp_security->configs->set_value('aiowps_cookie_test_success', '');
} else {
$aio_wp_security->configs->set_value('aiowps_cookie_test_success', '1');
}
$aio_wp_security->configs->save_config();//save the value
}
}
}
/**
* Adds admin menu page and all submenus to the WordPress dashboard
*
* @return void
*/
public function create_admin_menus() {
$menu_icon_url = AIO_WP_SECURITY_URL.'/images/aios-plugin-icon.svg';
$this->main_menu_page = add_menu_page(__('AIOS', 'all-in-one-wp-security-and-firewall'), __('AIOS', 'all-in-one-wp-security-and-firewall'), apply_filters('aios_management_permission', 'manage_options'), AIOWPSEC_MAIN_MENU_SLUG, array($this, 'handle_dashboard_menu_rendering'), $menu_icon_url);
foreach ($this->menu_items as $menu_item) {
add_submenu_page(AIOWPSEC_MAIN_MENU_SLUG, $menu_item['page_title'], $menu_item['menu_title'], apply_filters('aios_management_permission', 'manage_options'), $menu_item['menu_slug'], $menu_item['render_callback'], $menu_item['order']);
}
do_action('aiowpsecurity_admin_menu_created');
}
/**
* Adds submenu link for premium upgrade tab.
*
* @return Void
*/
public function premium_upgrade_submenu() {
if (!AIOWPSecurity_Utility_Permissions::is_premium_installed()) {
global $submenu;
$submenu[AIOWPSEC_MAIN_MENU_SLUG][] = array(__('Premium Upgrade', 'all-in-one-wp-security-and-firewall'), apply_filters('aios_management_permission', 'manage_options'), 'admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=premium-upgrade');
}
}
/**
* Renders 'Dashboard' submenu page.
*
* @return Void
*/
public function handle_dashboard_menu_rendering() {
include_once('wp-security-dashboard-menu.php');
new AIOWPSecurity_Dashboard_Menu();
}
/**
* Renders 'Settings' submenu page.
*
* @return Void
*/
public function handle_settings_menu_rendering() {
include_once('wp-security-settings-menu.php');
new AIOWPSecurity_Settings_Menu();
}
/**
* Renders 'User Security' submenu page.
*
* @return Void
*/
public function handle_user_security_menu_rendering() {
include_once('wp-security-user-security-menu.php');
new AIOWPSecurity_User_Security_Menu();
}
/**
* Renders 'Database Security' submenu page.
*
* @return Void
*/
public function handle_database_menu_rendering() {
include_once('wp-security-database-menu.php');
new AIOWPSecurity_Database_Menu();
}
/**
* Renders 'Filesystem Security' submenu page.
*
* @return Void
*/
public function handle_filesystem_menu_rendering() {
include_once('wp-security-filesystem-menu.php');
new AIOWPSecurity_Filesystem_Menu();
}
/**
* Renders 'Firewall' submenu page.
*
* @return Void
*/
public function handle_firewall_menu_rendering() {
include_once('wp-security-firewall-menu.php');
new AIOWPSecurity_Firewall_Menu();
}
/**
* Renders 'Brute Force' submenu page.
*
* @return Void
*/
public function handle_brute_force_menu_rendering() {
include_once('wp-security-brute-force-menu.php');
new AIOWPSecurity_Brute_Force_Menu();
}
/**
* Renders 'Spam Prevention' submenu page.
*
* @return Void
*/
public function handle_spam_menu_rendering() {
include_once('wp-security-spam-menu.php');
new AIOWPSecurity_Spam_Menu();
}
/**
* Renders 'Scanner' submenu page.
*
* @return Void
*/
public function handle_filescan_menu_rendering() {
include_once('wp-security-filescan-menu.php');
new AIOWPSecurity_Filescan_Menu();
}
/**
* Renders 'Tools' submenu page.
*
* @return Void
*/
public function handle_tools_menu_rendering() {
include_once('wp-security-tools-menu.php');
new AIOWPSecurity_Tools_Menu();
}
} // End of class
@@ -0,0 +1,280 @@
<?php
/**
* Parent class for all admin menu classes
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
abstract class AIOWPSecurity_Admin_Menu {
/**
* Specify the menu slug
*
* @var string
*/
protected $menu_page_slug;
/**
* Specify all the tabs of this menu
*
* @var array
*/
protected $menu_tabs;
/**
* Constructor adds a admin menu
*
* @param string $title - Title of menu to be rendered
*/
public function __construct($title) {
$this->setup_menu_tabs();
$this->render_page($title);
}
/**
* Render the menu page
*
* @param string $title - the page title
*
* @return void
*/
protected function render_page($title) {
$current_tab = $this->get_current_tab();
?>
<div class="wrap">
<h2><?php echo esc_html($title); ?></h2>
<?php $this->render_tabs($current_tab); ?>
<div id="poststuff">
<div id="post-body">
<?php call_user_func($this->menu_tabs[$current_tab]['render_callback']); ?>
</div>
</div>
</div>
<?php
}
/**
* Render the menu tabs for this page
*
* @param string $current_tab - the current tab
*
* @return void
*/
protected function render_tabs($current_tab) {
echo '<h2 class="nav-tab-wrapper">';
foreach ($this->menu_tabs as $tab_key => $tab_info) {
$active = $current_tab == $tab_key ? 'nav-tab-active' : '';
echo '<a class="nav-tab ' . esc_attr($active) . '" href="?page=' . esc_attr($this->menu_page_slug) . '&tab=' . esc_attr($tab_key) . '">' . esc_html($tab_info['title']) . '</a>';
}
echo '</h2>';
}
/**
* Get valid current tab slug.
*
* @return string - current valid tab slug or empty string
*/
protected function get_current_tab() {
if (is_array($this->menu_tabs) && !empty($this->menu_tabs)) {
$tab_keys = array_keys($this->menu_tabs);
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
if (empty($_GET['tab'])) {
return $tab_keys[0];
} else {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
$current_tab = sanitize_text_field(wp_unslash($_GET['tab']));
return in_array($current_tab, $tab_keys) ? $current_tab : $tab_keys[0];
}
} else {
return '';
}
}
/**
* This function checks to see if there is a display condition for the tab and if so runs it otherwise it returns true to display the tab
*
* @param array $tab_info - the tab information array contains keys like title, render_callback and display_condition_callback
*
* @return boolean - true if the tab should be displayed or false to hide it
*/
protected function should_display_tab($tab_info) {
return AIOWPSecurity_Utility::apply_callback_filter($tab_info, 'display_condition_callback');
}
/**
* Shows postbox for settings menu
*
* @param string $id - css ID for postbox
* @param string $title - title of the postbox section
* @param string $content - the content of the postbox
**/
protected function postbox_toggle($id, $title, $content) {
//Always send string with translation markers in it
?>
<div id="<?php echo esc_attr($id); ?>" class="postbox">
<div class="handlediv" title="<?php echo esc_html__('Press to toggle', 'all-in-one-wp-security-and-firewall'); ?>"><br /></div>
<h3 class="hndle"><span><?php echo esc_html($title); ?></span></h3>
<div class="inside">
<?php echo wp_kses_post($content); ?>
</div>
</div>
<?php
}
/**
* Display a postbox with a title and content.
*
* This function generates and outputs HTML markup for a postbox with a specified title
* and content. The title and content should be provided as parameters, and they will be
* automatically escaped for security. The function ensures that translation markers are
* included in the output strings.
*
* @param string $title - The title of the postbox.
* @param string $content - The content to be displayed inside the postbox.
*
* @return void
*/
public function postbox($title, $content) {
// Always send string with translation markers in it
?>
<div class="postbox">
<h3 class="hndle"><label for="title"><?php echo esc_html($title); ?></label></h3>
<div class="inside">
<?php echo wp_kses_post($content); ?>
</div>
</div>
<?php
}
/**
* Render settings successfully updated message
*
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public function show_msg_settings_updated($return_instead_of_echo = false) {
$message = '<div id="aios_message" class="updated fade"><p><strong>';
$message .= esc_html__('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
/**
* Render settings successfully updated message
*
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public static function show_msg_settings_updated_st($return_instead_of_echo = false) {
$message = '<div id="aios_message" class="updated fade"><p><strong>';
$message .= esc_html__('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
/**
* Renders record(s) successfully deleted message at top of page.
*
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
* @return mixed
*/
public static function show_msg_record_deleted_st($return_instead_of_echo = false) {
return AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall'), $return_instead_of_echo);
}
/**
* Renders record(s) unsuccessfully deleted message at top of page.
*
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
* @return mixed
*/
public static function show_msg_record_not_deleted_st($return_instead_of_echo = false) {
return AIOWPSecurity_Admin_Menu::show_msg_error_st(__('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'), $return_instead_of_echo);
}
/**
* Render successfully updated message
*
* @param string $msg - This contains the message to show
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public function show_msg_updated($msg, $return_instead_of_echo = false) {
$message = '<div id="aios_message" class="updated fade"><p><strong>';
$message .= wp_kses_post($msg);
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
/**
* Render successfully updated message
*
* @param string $msg - This contains the message to show
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public static function show_msg_updated_st($msg, $return_instead_of_echo = false) {
$message = '<div id="aios_message" class="updated fade"><p><strong>';
$message .= wp_kses_post($msg);
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
/**
* Render error message
*
* @param string $error_msg - This contains the message to show
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public function show_msg_error($error_msg, $return_instead_of_echo = false) {
$message = '<div id="aios_message" class="error"><p><strong>';
$message .= wp_kses_post($error_msg);
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
/**
* Render error message
*
* @param string $error_msg - This contains the message to show
* @param bool $return_instead_of_echo - This is used for when the function needs to return the message
*
* @return string|void
*/
public static function show_msg_error_st($error_msg, $return_instead_of_echo = false) {
$message = '<div id="aios_message" class="error"><p><strong>';
$message .= wp_kses_post($error_msg);
$message .= '</strong></p></div>';
if ($return_instead_of_echo) return $message;
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable contains escaped HTML.
echo $message;
}
protected function start_buffer() {
ob_start();
}
protected function end_buffer_and_collect() {
$output = ob_get_contents();
ob_end_clean();
return $output;
}
}
@@ -0,0 +1,176 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
/**
* AIOWPSecurity_Brute_Force_Menu class for brute force prevention.
*
* @access public
*/
class AIOWPSecurity_Brute_Force_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Blacklist menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_BRUTE_FORCE_MENU_SLUG;
/**
* Constructor adds menu for Brute force
*/
public function __construct() {
parent::__construct(__('Brute force', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'rename-login' => array(
'title' => __('Rename login page', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_rename_login'),
),
'cookie-based-brute-force-prevention' => array(
'title' => __('Cookie based brute force prevention', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_cookie_based_brute_force_prevention'),
'display_condition_callback' => 'is_main_site',
),
'captcha-settings' => array(
'title' => __('CAPTCHA settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_captcha_settings'),
),
'login-whitelist' => array(
'title' => __('Login whitelist', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_login_whitelist'),
),
'404-detection' => array(
'title' => __('404 detection', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_404_detection'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'honeypot' => array(
'title' => __('Honeypot', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_honeypot'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Rename login page tab.
*
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*/
protected function render_rename_login() {
global $aio_wp_security, $aiowps_feature_mgr;
if (get_option('permalink_structure')) {
$home_url = trailingslashit(home_url());
} else {
$home_url = trailingslashit(home_url()) . '?';
}
$aio_wp_security->include_template('wp-admin/brute-force/rename-login.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'home_url' => $home_url));
}
/**
* Cookie based brute force prevention tab.
*
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*
* @return void
*/
protected function render_cookie_based_brute_force_prevention() {
global $aio_wp_security;
global $aiowps_feature_mgr;
$aio_wp_security->include_template('wp-admin/brute-force/cookie-based-brute-force-prevention.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
/**
* Login captcha tab.
*
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*
* @return void
*/
protected function render_captcha_settings() {
global $aio_wp_security, $aiowps_feature_mgr;
$supported_captchas = $aio_wp_security->captcha_obj->get_supported_captchas();
$captcha_themes = $aio_wp_security->captcha_obj->get_captcha_themes();
$captcha_theme = 'auto';
if ('cloudflare-turnstile' == $aio_wp_security->configs->get_value('aiowps_default_captcha')) $captcha_theme = $aio_wp_security->configs->get_value('aiowps_turnstile_theme');
if ('cloudflare-turnstile' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && false === $aio_wp_security->captcha_obj->cloudflare_turnstile_verify_configuration($aio_wp_security->configs->get_value('aiowps_turnstile_site_key'), $aio_wp_security->configs->get_value('aiowps_turnstile_secret_key'))) {
echo '<div class="notice notice-warning aio_red_box"><p>' . esc_html__('Your Cloudflare Turnstile configuration is invalid.', 'all-in-one-wp-security-and-firewall').' ' . esc_html__('Please enter the correct Cloudflare Turnstile keys below to use the Turnstile feature.', 'all-in-one-wp-security-and-firewall').'</p></div>';
}
if ('1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) {
echo '<div class="notice notice-warning aio_red_box"><p>' . esc_html__('Your Google reCAPTCHA configuration is invalid.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Please enter the correct reCAPTCHA keys below to use the reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall').'</p></div>';
}
$default_captcha = $aio_wp_security->configs->get_value('aiowps_default_captcha');
$aio_wp_security->include_template('wp-admin/brute-force/captcha-settings.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'supported_captchas' => $supported_captchas, 'default_captcha' => $default_captcha, 'captcha_themes' => $captcha_themes, 'captcha_theme' => $captcha_theme));
}
/**
* Login whitelist tab.
*
* @return void
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*/
protected function render_login_whitelist() {
global $aio_wp_security, $aiowps_feature_mgr;
$ip_v4 = false;
$your_ip_address = AIOWPSecurity_Utility_IP::get_user_ip_address();
if (filter_var($your_ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) $ip_v4 = true;
$aiowps_allowed_ip_addresses = $aio_wp_security->configs->get_value('aiowps_allowed_ip_addresses');
$aio_wp_security->include_template('wp-admin/brute-force/login-whitelist.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'your_ip_address' => $your_ip_address, 'ip_v4' => $ip_v4, 'aiowps_allowed_ip_addresses' => $aiowps_allowed_ip_addresses));
}
/**
* Renders the 404 Detection tab
*
* @return void
*/
protected function render_404_detection() {
global $aio_wp_security;
include_once 'wp-security-list-404.php'; // For rendering the AIOWPSecurity_List_Table in basic-firewall tab
$event_list_404 = new AIOWPSecurity_List_404(); // For rendering the AIOWPSecurity_List_Table in basic-firewall tab
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
$page = isset($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
$tab = isset($_REQUEST["tab"]) ? sanitize_text_field(wp_unslash($_REQUEST["tab"])) : '';
$aio_wp_security->include_template('wp-admin/brute-force/404-detection.php', false, array('event_list_404' => $event_list_404, 'page' => $page, 'tab' => $tab));
}
/**
* Honeypot tab.
*
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*
* @return void
*/
protected function render_honeypot() {
global $aio_wp_security, $aiowps_feature_mgr;
$aio_wp_security->include_template('wp-admin/brute-force/honeypot.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
}
@@ -0,0 +1,653 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Dashboard_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Dashboard menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_MAIN_MENU_SLUG;
/**
* Constructor adds menu for Dashboard
*/
public function __construct() {
parent::__construct(__('Dashboard', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'dashboard' => array(
'title' => __('Dashboard', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_dashboard'),
),
'locked-ip' => array(
'title' => __('Locked IP addresses', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_locked_ip'),
),
'permanent-block' => array(
'title' => __('Permanent block list', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_permanent_block'),
),
'audit-logs' => array(
'title' => __('Audit logs', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_audit_logs'),
),
'debug-logs' => array(
'title' => __('Debugging', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_debug_logs'),
),
'premium-upgrade' => array(
'title' => __('Premium upgrade', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_premium_upgrade_tab'),
'display_condition_callback' => function() {
return !AIOWPSecurity_Utility_Permissions::is_premium_installed();
}
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's dashboard tab
*
* @return Void
*/
protected function render_dashboard() {
/**
* Load WordPress dashboard API
*/
require_once(ABSPATH . 'wp-admin/includes/dashboard.php');
$this->wp_dashboard_setup();
wp_enqueue_script('dashboard');
if (wp_is_mobile()) wp_enqueue_script('jquery-touch-punch');
?>
<?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Needed for dashboard widget. ?>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<div id="dashboard-widgets-wrap">
<?php $this->wp_dashboard(); ?>
</div><!-- dashboard-widgets-wrap -->
<?php
}
/**
* Renders the submenu's locked IP addresses tab
*
* @return Void
*/
protected function render_locked_ip() {
global $aio_wp_security;
include_once 'wp-security-list-locked-ip.php';
$locked_ip_list = new AIOWPSecurity_List_Locked_IP();
$tab = isset($_REQUEST["tab"]) ? sanitize_text_field(wp_unslash($_REQUEST["tab"])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce for tabs.
$page = isset($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce for page.
$aio_wp_security->include_template('wp-admin/dashboard/locked-ip.php', false, array('locked_ip_list' => $locked_ip_list, 'page' => $page, 'tab' => $tab));
}
/**
* Renders the submenu's permanent block tab
*
* @return Void
*/
protected function render_permanent_block() {
global $aio_wp_security;
include_once 'wp-security-list-permanent-blocked-ip.php'; // For rendering the AIOWPSecurity_List_Table
$blocked_ip_list = new AIOWPSecurity_List_Blocked_IP(); // For rendering the AIOWPSecurity_List_Table
$tab = isset($_REQUEST["tab"]) ? sanitize_text_field(wp_unslash($_REQUEST["tab"])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce for tab.
$page = isset($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce for page.
$aio_wp_security->include_template('wp-admin/dashboard/permanent-block.php', false, array('blocked_ip_list' => $blocked_ip_list, 'page' => $page, 'tab' => $tab));
}
/**
* Renders the submenu's audit logs tab
*
* @return void
*/
protected function render_audit_logs() {
global $aio_wp_security;
// Needed for rendering the audit log table
include_once 'wp-security-list-audit.php';
$data = array();
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. Processing form data without nonce verification. No nonce.
if (isset($_GET['event-filter'])) $data['event-filter'] = sanitize_text_field(wp_unslash($_GET['event-filter'])); // Failed logins and logins only to show as audit log
$audit_log_list = new AIOWPSecurity_List_Audit_Log($data);
$tab = isset($_REQUEST["tab"]) ? sanitize_text_field(wp_unslash($_REQUEST["tab"])) : '';
$page = isset($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : '';
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. Processing form data without nonce verification. No nonce.
$aio_wp_security->include_template('wp-admin/dashboard/audit-logs.php', false, array('audit_log_list' => $audit_log_list, 'page' => $page, 'tab' => $tab));
}
/**
* Renders the submenu's debug logs tab
*
* @return void
*/
protected function render_debug_logs() {
// Needed for rendering the debug log table
include_once 'wp-security-list-debug.php';
$debug_log_list = new AIOWPSecurity_List_Debug_Log();
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/dashboard/debug-logs.php', false, array('debug_log_list' => $debug_log_list));
}
/**
* Renders the submenu's premium-upgrade tab body.
*
* @return Void
*/
protected function render_premium_upgrade_tab() {
global $aio_wp_security;
$enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? AIO_WP_SECURITY_VERSION.'.'.time() : AIO_WP_SECURITY_VERSION;
wp_enqueue_style('aiowpsec-admin-premium-upgrade-css', AIO_WP_SECURITY_URL.'/css/wp-security-premium-upgrade.css', array(), $enqueue_version);
echo '<div class="postbox wpo-tab-postbox">';
$aio_wp_security->include_template('wp-admin/dashboard/may-also-like.php');
echo '</div><!-- END .postbox -->';
}
/**
* Function to customize the layout of the WordPress dashboard.
* Organizes meta-boxes into different containers based on screen columns.
*/
private function wp_dashboard() {
$screen = get_current_screen();
$columns = absint($screen->get_columns());
$columns_css = '';
if ($columns) {
$columns_css = " columns-$columns";
}
?>
<div id="dashboard-widgets" class="metabox-holder<?php echo esc_attr($columns_css); ?>">
<div id="postbox-container-1" class="postbox-container">
<?php do_meta_boxes($screen->id, 'normal', ''); ?>
</div>
<div id="postbox-container-2" class="postbox-container">
<?php do_meta_boxes($screen->id, 'side', ''); ?>
</div>
<div id="postbox-container-3" class="postbox-container">
<?php do_meta_boxes($screen->id, 'column3', ''); ?>
</div>
<div id="postbox-container-4" class="postbox-container">
<?php do_meta_boxes($screen->id, 'column4', ''); ?>
</div>
</div>
<?php
wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
}
private function wp_dashboard_setup() {
global $aio_wp_security, $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks;
$wp_dashboard_control_callbacks = array();
get_current_screen();
// Add widgets
wp_add_dashboard_widget('security_strength_meter', __('Security strength meter', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_security_strength_meter'));
wp_add_dashboard_widget('security_points_breakdown', __('Security points breakdown', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_security_points_breakdown'));
wp_add_dashboard_widget('spread_the_word', __('Spread the word', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_spread_the_word'));
wp_add_dashboard_widget('know_developers', __('Get to know the developers', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_know_developers'));
wp_add_dashboard_widget('critical_feature_status', __('Critical feature status', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_critical_feature_status'));
wp_add_dashboard_widget('last_5_logins', __('Last 5 login summary', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_last_5_logins'));
wp_add_dashboard_widget('maintenance_mode_status', __('Maintenance mode status', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_maintenance_mode_status'));
if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention')
|| '1' == $aio_wp_security->configs->get_value('aiowps_enable_rename_login_page')
) {
wp_add_dashboard_widget('brute_force', __('Brute force prevention login page', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_brute_force'));
}
wp_add_dashboard_widget('logged_in_users', __('Logged in users', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_logged_in_users'));
wp_add_dashboard_widget('locked_ip_addresses', __('Locked IP addresses', 'all-in-one-wp-security-and-firewall'), array($this, 'widget_locked_ip_addresses'));
do_action('aiowps_dashboard_setup');
$dashboard_widgets = apply_filters('aiowps_dashboard_widgets', array());
foreach ($dashboard_widgets as $widget_id) {
$name = empty($wp_registered_widgets[$widget_id]['all_link']) ? $wp_registered_widgets[$widget_id]['name'] : $wp_registered_widgets[$widget_id]['name'] . " <a href='{$wp_registered_widgets[$widget_id]['all_link']}' class='edit-box open-box'>" . __('View all', 'all-in-one-wp-security-and-firewall') . '</a>';
wp_add_dashboard_widget($widget_id, $name, $wp_registered_widgets[$widget_id]['callback'], $wp_registered_widget_controls[$widget_id]['callback']);
}
}
public function widget_security_strength_meter() {
global $aiowps_feature_mgr;
$total_site_security_points = $aiowps_feature_mgr->get_total_site_points();
$total_security_points_achievable = $aiowps_feature_mgr->get_total_achievable_points();
?>
<script type='text/javascript'>
var total_security_points_achievable = <?php echo (int) $total_security_points_achievable; ?>;
var section = total_security_points_achievable / 8;
var config = {
type: 'gauge',
data: {
datasets: [{
value: <?php echo esc_js($total_site_security_points); ?>,
minValue: 0,
data: [section, section * 2, section * 3, section * 4, section * 5, section * 6, total_security_points_achievable],
backgroundColor: ['#26ddfd', '#26ddfd', '#00b0ea', '#00b0ea', '#2680ca', '#2680ca', '#563c82'],
borderWidth: 2.5
}]
},
options: {
cutoutPercentage: 75,
layout: {
padding: {
bottom: 20
}
},
needle: {
radiusPercentage: 5,
widthPercentage: 6,
lengthPercentage: 80,
color: '#3e3e3e'
},
valueLabel: {
display: false
}
}
};
window.onload = function() {
var ctx = document.getElementById('chart').getContext('2d');
window.myGauge = new Chart(ctx, config);
};
</script>
<div id="canvas-holder">
<canvas id="chart"></canvas>
</div>
<h2 id="website-strength-text"><?php echo esc_html__('Website strength:', 'all-in-one-wp-security-and-firewall') . ' ' . '<strong>' . esc_html($total_site_security_points) . '</strong>'; ?></h2>
<div id='security_strength_chart_div'></div>
<div class="aiowps_dashboard_widget_footer">
<?php
echo esc_html__('Total Achievable Points:', 'all-in-one-wp-security-and-firewall') . ' ' . '<strong>' . esc_html($total_security_points_achievable) . '</strong><br />';
echo esc_html__('Current Score of Your Site:', 'all-in-one-wp-security-and-firewall') . ' ' . '<strong>' . esc_html($total_site_security_points) . '</strong>';
?>
</div>
<?php
}
public function widget_security_points_breakdown() {
global $aiowps_feature_mgr;
$feature_mgr = $aiowps_feature_mgr;
$feature_items = $feature_mgr->feature_items;
$pt_src_chart_data = "";
$pt_src_chart_data .= "['Feature Name', 'Points'],";
foreach ($feature_items as $item) {
if ($item->is_active()) {
$pt_src_chart_data .= "['" . esc_html($item->feature_name) . "', " . esc_html($item->item_points) . "],";
}
}
?>
<?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- PCP error. Direct enqueue necessary. ?>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type="text/javascript">
google.load("visualization", "1", {packages: ["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
<?php echo $pt_src_chart_data; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JS array data. Variables escaped earlier. ?>
]);
var options = {
// height: '250',
// width: '450',
backgroundColor: 'F6F6F6',
pieHole: 0.4,
chartArea: {
width: '95%',
height: '95%',
}
};
var chart = new google.visualization.PieChart(document.getElementById('points_source_breakdown_chart_div'));
chart.draw(data, options);
}
</script>
<div id='points_source_breakdown_chart_div'></div>
<?php
}
public function widget_spread_the_word() {
?>
<p><?php echo esc_html__('We are working hard to make your WordPress site more secure.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Please support us, here is how:', 'all-in-one-wp-security-and-firewall');?></p>
<p><a href="https://x.com/TeamUpdraftWP" target="_blank"><?php esc_html_e('Follow us on', 'all-in-one-wp-security-and-firewall');?> X</a>
</p>
<p>
<a href="https://x.com/intent/tweet?url=https://wordpress.org/plugins/all-in-one-wp-security-and-firewall&text=I love the All In One WP Security and Firewall plugin!"
target="_blank" class="aio_tweet_link"><?php esc_html_e('Post to X', 'all-in-one-wp-security-and-firewall');?></a>
</p>
<p>
<a href="http://wordpress.org/support/view/plugin-reviews/all-in-one-wp-security-and-firewall/"
target="_blank" class="aio_rate_us_link"><?php esc_html_e('Give us a good rating', 'all-in-one-wp-security-and-firewall');?></a>
</p>
<?php
}
public function widget_know_developers() {
?>
<p><?php esc_html_e('Wanna know more about the developers behind this plugin?', 'all-in-one-wp-security-and-firewall');?></p>
<p><a href="https://teamupdraft.com/" target="_blank">Team UpdraftPlus</a></p>
<?php
}
/**
* This outputs the critical feature status widget
*
* @return void
*/
public function widget_critical_feature_status() {
global $aiowps_feature_mgr;
$critical_features = array(
'user-accounts-change-admin-user' => array(
'name' => __('Admin username', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG,
),
'user-login-login-lockdown' => array(
'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG . '&tab=login-lockout',
),
'filesystem-file-permissions' => array(
'name' => __('File permission', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG,
'feature_callback' => 'is_main_site'
),
'firewall-basic-rules' => array(
'name' => __('Basic firewall', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_FIREWALL_MENU_SLUG . '&tab=htaccess-rules',
'feature_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
),
'db-security-db-prefix' => array(
'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_DB_SEC_MENU_SLUG,
'feature_callback' => 'is_main_site'
),
'filesystem-file-editing' => array(
'name' => __('PHP file editing', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG . '&tab=file-protection',
'feature_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin')
),
'bf-rename-login-page' => array(
'name' => __('Renamed login page', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_BRUTE_FORCE_MENU_SLUG,
),
'wp-generator-meta-tag' => array(
'name' => __('Hidden WP meta info', 'all-in-one-wp-security-and-firewall'),
'url' => AIOWPSEC_SETTINGS_MENU_SLUG . '&tab=wp-version-info',
),
);
$critical_features = apply_filters('aiowps_filter_critical_features_array', $critical_features);
$critical_features = array_filter($critical_features, array($this, 'should_add_feature'));
esc_html_e('Below is the current status of the critical features that you should activate on your site to achieve a minimum level of recommended security', 'all-in-one-wp-security-and-firewall');
echo '<div class="aiowps_features_grid">';
foreach ($critical_features as $key => $feature) {
$feature_item = $aiowps_feature_mgr->get_feature_item_by_id($key);
if (!$feature_item) continue;
echo '<a href="admin.php?page=' . esc_attr($feature['url']) . '" class="aiowps_critical_feature_link">';
echo '<div class="aiowps_critical_feature_status_container">';
echo '<div class="aiowps_critical_feature_status_name">' . esc_html($feature['name']) . '</div>';
echo '<div class="aiowps_feature_status_circle">';
if ($feature_item->is_active()) {
echo '<div class="aiowps_feature_status_circle_on"></div>';
} else {
echo '<div class="aiowps_feature_status_circle_off"></div>';
}
echo '</div>';
echo '</div>';
echo '</a>';
}
echo "</div>";
}
/**
* This outputs the latest logins dashboard widget
*
* @return void
*/
public function widget_last_5_logins() {
global $wpdb;
$audit_log_table = AIOWPSEC_TBL_AUDIT_LOG;
$where_sql = (is_super_admin()) ? '' : ' and site_id = '.get_current_blog_id().' ';
$last_days = 7;
$days_before_time = strtotime('-'.$last_days.' days', time());
// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query necessary.
$login_data_lastx_days = $wpdb->get_results(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- pcp Warning. Ignore.
$wpdb->prepare("SELECT id,created FROM $audit_log_table WHERE event_type = %s $where_sql and created > %s", 'successful_login', $days_before_time),
ARRAY_A
); // Get the last x days records
if (!empty($login_data_lastx_days)) {
$chart_data = array();
$chart_data['columns'] = array(__('Date', 'all-in-one-wp-security-and-firewall'), __('Logins', 'all-in-one-wp-security-and-firewall'));
$chart_data['data'] = $login_data_lastx_days;
$chart_data['last_days'] = $last_days;
$chart_data['id'] = 'logins_last_'.$last_days.'days';
$this->dashboard_widget_chart($chart_data, 'bar');
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP Error. Ignore.
$data = $wpdb->get_results(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP error. Ignore.
$wpdb->prepare("SELECT * FROM $audit_log_table WHERE event_type = %s ORDER BY created DESC LIMIT %d", 'successful_login', 5),
ARRAY_A
); //Get the last 5 records
if (null == $data) {
echo '<p>' . esc_html__('No data found.', 'all-in-one-wp-security-and-firewall') . '</p>';
} else {
$login_summary_table_data = array();
//$login_summary_table_data['title'] = __('Last 5 login summary:', 'all-in-one-wp-security-and-firewall');
$login_summary_table_data['columns'] = array(__('User', 'all-in-one-wp-security-and-firewall'), __('Date', 'all-in-one-wp-security-and-firewall'), 'IP');
foreach ($data as $entry) {
$login_summary_table_data['data'][] = array($entry['username'], gmdate('Y-m-d H:i:s', $entry['created']), $entry['ip']);
}
$login_summary_table_data = apply_filters('aios_last5_logins_summary', $login_summary_table_data, $data);
$this->dashboard_widget($login_summary_table_data);
// View all login logs
echo '<p><a class="button" href="' . esc_url('admin.php?page=' . AIOWPSEC_MAIN_MENU_SLUG . '&tab=audit-logs&event-filter=successful_login') . '">' . esc_html__('View all', 'all-in-one-wp-security-and-firewall') . '</a></p>';
}
echo '<div class="aio_clear_float"></div>';
}
public function widget_maintenance_mode_status() {
global $aio_wp_security;
?>
<p id="aiowpsec-dashboard-maintenance-mode-status-message">
<?php
if ('1' == $aio_wp_security->configs->get_value('aiowps_site_lockout')) {
echo esc_html__('Maintenance mode is currently enabled.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Remember to disable it when you are done.', 'all-in-one-wp-security-and-firewall');
} else {
echo esc_html__('Maintenance mode is currently disabled.', 'all-in-one-wp-security-and-firewall');
}
?>
</p>
<table class="form-table">
<tr valign="top">
<th scope="row"><?php esc_html_e('Enable maintenance mode', 'all-in-one-wp-security-and-firewall'); ?>:</th>
<td>
<div id="aiowpsec-dashboard-maintenance-mode-switch-container" class="aiowps_switch_container">
<?php AIOWPSecurity_Utility_UI::setting_checkbox('', 'aiowps_site_lockout', '1' == $aio_wp_security->configs->get_value('aiowps_site_lockout')); ?>
</div>
</td>
</tr>
</table>
<?php
echo '<a href="admin.php?page=' . esc_attr(AIOWPSEC_TOOLS_MENU_SLUG) . '&tab=visitor-lockout">' . esc_html__('Configure', 'all-in-one-wp-security-and-firewall') . '</a>';
}
public function widget_brute_force() {
global $aio_wp_security;
if ($aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1') {
$brute_force_login_feature_link = '<a href="admin.php?page=' . esc_attr(AIOWPSEC_BRUTE_FORCE_MENU_SLUG) . '&tab=cookie-based-brute-force-prevention" target="_blank">' . __('Cookie-based brute force', 'all-in-one-wp-security-and-firewall') . '</a>';
$brute_force_feature_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
echo '<div class="aio_yellow_box">';
/* translators: %s: Brute Force Login URL */
echo '<p>' . sprintf(esc_html__('The %s feature is currently active.', 'all-in-one-wp-security-and-firewall'), $brute_force_login_feature_link) . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above.
echo '<p>' . esc_html__('Your new WordPress login URL is now:', 'all-in-one-wp-security-and-firewall') . '</p>';
echo '<p><strong>' . esc_url(AIOWPSEC_WP_URL) . '/?' . esc_html($brute_force_feature_secret_word) . '=1</strong></p>';
echo '</div>'; //yellow box div
echo '<div class="aio_clear_float"></div>';
}// End if statement for Cookie Based Brute Prevention box
// Insert Rename Login Page feature box if this feature is active
if ($aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') {
if (get_option('permalink_structure')) {
$home_url = trailingslashit(home_url());
} else {
$home_url = trailingslashit(home_url()) . '?';
}
$rename_login_feature_link = '<a href="admin.php?page=' . esc_attr(AIOWPSEC_BRUTE_FORCE_MENU_SLUG) . '&tab=rename-login" target="_blank">' . esc_html__('Rename login page', 'all-in-one-wp-security-and-firewall') . '</a>';
echo '<div class="aio_yellow_box">';
/* translators: %s: Rename Login URL */
echo '<p>' . sprintf(esc_html__('The %s feature is currently active.', 'all-in-one-wp-security-and-firewall'), $rename_login_feature_link) . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above.
echo '<p>' . esc_html__('Your new WordPress login URL is now:', 'all-in-one-wp-security-and-firewall') . '</p>';
echo '<p><strong>' . esc_url($home_url) . esc_html($aio_wp_security->configs->get_value('aiowps_login_page_slug')) . '</strong></p>';
echo '</div>'; //yellow box div
echo '<div class="aio_clear_float"></div>';
} // End if statement for Rename Login box
}
/**
* This outputs the logged in users dashboard widget
*
* @return void
*/
public function widget_logged_in_users() {
$users_online_link = '<a href="admin.php?page=' . AIOWPSEC_USER_SECURITY_MENU_SLUG . '&tab=logged-in-users">'.esc_html__('Logged in users', 'all-in-one-wp-security-and-firewall').'</a>';
// default display messages
$multiple_users_info_msg = esc_html__('Number of users currently logged into your site (including you) is:', 'all-in-one-wp-security-and-firewall');
$single_user_info_msg = esc_html__('There are no other users currently logged in.', 'all-in-one-wp-security-and-firewall');
if (is_multisite()) {
$current_blog_id = get_current_blog_id();
$is_main = is_main_site($current_blog_id);
if (empty($is_main)) {
// Subsite - only get logged in users for this blog_id
$logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users(false);
} else {
// Main site - get sitewide users
$logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users();
// If viewing AIOS from multisite main network dashboard, then display a different message
$multiple_users_info_msg = __('Number of users currently logged in site-wide (including you) is:', 'all-in-one-wp-security-and-firewall');
$single_user_info_msg = __('There are no other site-wide users currently logged in.', 'all-in-one-wp-security-and-firewall');
}
} else {
$logged_in_users = AIOWPSecurity_User_Login::get_logged_in_users();
}
if (empty($logged_in_users)) {
$num_users = 0;
} else {
$num_users = count($logged_in_users);
}
if ($num_users > 1) {
echo '<div class="aio_red_box"><p>' . esc_html($multiple_users_info_msg) . ' <strong>' . esc_html($num_users) . '</strong></p>';
/* translators: %s: Users Online URL */
$info_msg = '<p>' . sprintf(esc_html__('Go to the %s menu to see more details', 'all-in-one-wp-security-and-firewall'), $users_online_link) . '</p>';
echo $info_msg . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above.
} else {
echo '<div class="aio_green_box"><p>' . esc_html($single_user_info_msg) . '</p></div>';
}
}
public function widget_locked_ip_addresses() {
$locked_ips_link = '<a href="admin.php?page=' . esc_attr(AIOWPSEC_MAIN_MENU_SLUG) . '&tab=locked-ip">'. esc_html__('Locked IP addresses', 'all-in-one-wp-security-and-firewall').'</a>';
$locked_ips = AIOWPSecurity_Utility::get_locked_ips();
if (false === $locked_ips) {
echo '<div class="aio_green_box"><p>' . esc_html__('There are no IP addresses currently locked out.', 'all-in-one-wp-security-and-firewall') . '</p></div>';
} else {
$num_ips = count($locked_ips);
echo '<div class="aio_red_box"><p>' . esc_html__('Number of temporarily locked out IP addresses:', 'all-in-one-wp-security-and-firewall') . ' ' . ' <strong>' . esc_html($num_ips) . '</strong></p>';
/* translators: %s: Number of locked out IPs */
$info_msg = '<p>' . sprintf(esc_html__('Go to the %s menu to see more details', 'all-in-one-wp-security-and-firewall'), $locked_ips_link) . '</p>';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above.
echo $info_msg . '</div>';
}
}
/**
* Determines whether a security feature should be activated based on its callback.
*
* This method checks if a feature should be added by evaluating its callback function.
* If no callback is set, the feature is added by default. If a callback is set,
* it must be callable and return a boolean value.
*
* @param array $feature An array containing feature details with the following keys:
* 'name' => (string) Name of the feature
* 'feature_callback' => (callable|null) Optional callback to determine if feature should be added
*
* @return bool True if the feature should be added, false otherwise
*/
public static function should_add_feature($feature) {
if (empty($feature['feature_callback'])) {
return true;
} elseif (is_callable($feature['feature_callback'])) {
return call_user_func($feature['feature_callback']);
} else {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Part of internal error reporting system.
error_log("Callback function set but not callable (coding error). Feature: " . $feature['name']);
return false;
}
}
/**
* This function creates summary for dashboard widget in table format
*
* @param array $widget_data title, column names and row data
*
* @return void
*/
private function dashboard_widget($widget_data) {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/dashboard/widget-summary.php', false, array('widget_data' => $widget_data));
}
/**
* This function creates chart for dashboard widget
*
* @param array $chart_data column names, chart data, last_days and id
* @param string $type bar chart
*
* @return void
*/
private function dashboard_widget_chart($chart_data, $type = 'bar') {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/dashboard/widget-'.$type.'-chart.php', false, array('chart_data' => $chart_data));
}
}
@@ -0,0 +1,408 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Database_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Database menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_DB_SEC_MENU_SLUG;
/**
* Constructor adds menu for Database security
*/
public function __construct() {
parent::__construct(__('Database security', 'all-in-one-wp-security-and-firewall'));
}
/**
* Return installation or activation link of UpdraftPlus plugin
*
* @return String
*/
private function get_install_activate_link_of_updraft_plugin() {
// If UpdraftPlus is activated, then return empty.
if (class_exists('UpdraftPlus')) return '';
// Generally it is 'updraftplus/updraftplus.php',
// but we can't assume that the user hasn't renamed the plugin folder - with 3 million UDP users and 1 million AIOWPS, there will be some who have.
$updraftplus_plugin_file_rel_to_plugins_dir = $this->get_updraftplus_plugin_file_rel_to_plugins_dir();
// If UpdraftPlus is installed but not activated, then return activate link.
if ($updraftplus_plugin_file_rel_to_plugins_dir) {
$activate_url = add_query_arg(array(
'_wpnonce' => wp_create_nonce('activate-plugin_'.$updraftplus_plugin_file_rel_to_plugins_dir),
'action' => 'activate',
'plugin' => $updraftplus_plugin_file_rel_to_plugins_dir,
), network_admin_url('plugins.php'));
// If is network admin then add to link network activation.
if (is_network_admin()) {
$activate_url = add_query_arg(array('networkwide' => 1), $activate_url);
}
return sprintf('<a href="%s">%s</a>',
$activate_url,
__('UpdraftPlus is installed but currently not active.', 'all-in-one-wp-security-and-firewall') .' '. __('Follow this link to activate UpdraftPlus, to take a backup.', 'all-in-one-wp-security-and-firewall')
);
}
// If UpdraftPlus is not activated or installed, then return the installation link
return '<a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=updraftplus'), 'install-plugin_updraftplus').'">'.__('Follow this link to install UpdraftPlus, to take a database backup.', 'all-in-one-wp-security-and-firewall').'</a>';
}
/**
* Get path to the UpdraftPlus plugin file relative to the plugins directory.
*
* @return String|false path to the UpdraftPlus plugin file relative to the plugins directory
*/
private function get_updraftplus_plugin_file_rel_to_plugins_dir() {
if (!function_exists('get_plugins')) {
include_once ABSPATH . '/wp-admin/includes/plugin.php';
}
$installed_plugins = get_plugins();
$installed_plugins_keys = array_keys($installed_plugins);
foreach ($installed_plugins_keys as $plugin_file_rel_to_plugins_dir) {
$temp_plugin_file_name = substr($plugin_file_rel_to_plugins_dir, strpos($plugin_file_rel_to_plugins_dir, '/') + 1);
if ('updraftplus.php' == $temp_plugin_file_name) {
return $plugin_file_rel_to_plugins_dir;
}
}
return false;
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'database-prefix' => array(
'title' => __('Database prefix', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_database_prefix'),
'display_condition_callback' => 'is_main_site',
),
'database-backup' => array(
'title' => __('Database backup', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_database_backup'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's database prefix tab
*
* @return Void
*/
protected function render_database_prefix() {
global $wpdb, $aio_wp_security, $aiowps_feature_mgr;
$old_db_prefix = $wpdb->prefix;
$new_db_prefix = '';
$perform_db_change = false;
if (isset($_POST['aiowps_db_prefix_change'])) { // Do form submission tasks
$nonce = $_REQUEST['_wpnonce'];
if (!wp_verify_nonce($nonce, 'aiowpsec-db-prefix-change-nonce')) {
$aio_wp_security->debug_logger->log_debug("Nonce check failed for DB prefix change operation.", 4);
die(__('Nonce check failed for DB prefix change operation.', 'all-in-one-wp-security-and-firewall'));
}
// Let's first check if user's system allows writing to wp-config.php file. If plugin cannot write to wp-config we will not do the prefix change.
$config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
$file_write = AIOWPSecurity_Utility_File::is_file_writable($config_file);
if (!$file_write) {
$this->show_msg_error(__('The plugin has detected that it cannot write to the wp-config.php file.', 'all-in-one-wp-security-and-firewall') . ' ' . __('This feature can only be used if the plugin can successfully write to the wp-config.php file.', 'all-in-one-wp-security-and-firewall'));
} else {
if (isset($_POST['aiowps_enable_random_prefix'])) { // User has elected to generate a random DB prefix
$string = AIOWPSecurity_Utility::generate_alpha_random_string('5');
$new_db_prefix = $string . '_';
$perform_db_change = true;
} else {
if (empty($_POST['aiowps_new_manual_db_prefix'])) {
$this->show_msg_error(__('Please enter a value for the DB prefix.', 'all-in-one-wp-security-and-firewall'));
} else {
// User has chosen their own DB prefix value
$new_db_prefix = wp_strip_all_tags(trim($_POST['aiowps_new_manual_db_prefix']));
if ($new_db_prefix !== $_POST['aiowps_new_manual_db_prefix']) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> ".__('prefix contains HTML tags', 'all-in-one-wp-security-and-firewall'));
}
if (preg_match('|[^a-z0-9_]|i', $new_db_prefix)) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> ".__('prefix contains invalid characters, the prefix should only contain alphanumeric and underscore characters.', 'all-in-one-wp-security-and-firewall'));
}
$error = $wpdb->set_prefix($new_db_prefix); // validate the user chosen prefix
if (is_wp_error($error)) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> (".$error->get_error_code()."): ".$error->get_error_message());
}
$wpdb->set_prefix($old_db_prefix);
$perform_db_change = true;
}
}
}
}
if ($perform_db_change) {
// Do the DB prefix change operations
$this->change_db_prefix($old_db_prefix, $new_db_prefix);
}
$aio_wp_security->include_template('wp-admin/database-security/database-prefix.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'old_db_prefix' => $old_db_prefix));
}
/**
* Renders the submenu's database backup tab
*
* @return Void
*/
protected function render_database_backup() {
global $aio_wp_security;
$updraftplus_admin = !empty($GLOBALS['updraftplus_admin']) ? $GLOBALS['updraftplus_admin'] : null;
if ($updraftplus_admin) {
$updraftplus_admin->add_backup_scaffolding(__('Take a database backup using UpdraftPlus', 'all-in-one-wp-security-and-firewall'), array($updraftplus_admin, 'backupnow_modal_contents'));
}
$install_activate_link = $this->get_install_activate_link_of_updraft_plugin();
$aio_wp_security->include_template('wp-admin/database-security/database-backup.php', false, array('install_activate_link' => $install_activate_link));
}
/*
* Changes the DB prefix
*/
/**
* This function will change the DB prefix
*
* @param string $table_old_prefix - the old table prefix
* @param string $table_new_prefix - the new table prefix
*
* @return void
*/
private function change_db_prefix($table_old_prefix, $table_new_prefix) {
global $wpdb, $aio_wp_security;
$old_prefix_length = strlen($table_old_prefix);
$error = 0;
// Config file path
$config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
// Get the table resource
// $result = mysql_list_tables(DB_NAME);
$result = $this->get_mysql_tables(DB_NAME); //Fix for deprecated php mysql_list_tables function
// Count the number of tables
if (is_array($result) && count($result) > 0) {
$num_rows = count($result);
} else {
echo '<div class="aio_red_box"><p>'.__('Error - Could not get tables or no tables found!', 'all-in-one-wp-security-and-firewall').'</p></div>';
return;
}
$table_count = 0;
$info_msg_string = '<p class="aio_info_with_icon">'.__('Starting DB prefix change operations.....', 'all-in-one-wp-security-and-firewall').'</p>';
$info_msg_string .= '<p class="aio_info_with_icon">'.sprintf(__('Your WordPress system has a total of %s tables and your new DB prefix will be: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$num_rows.'</strong>', '<strong>'.$table_new_prefix.'</strong>').'</p>';
echo $info_msg_string;
// Do a back of the config file
if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) {
echo '<div class="aio_red_box"><p>'.__('Failed to make a backup of the wp-config.php file.', 'all-in-one-wp-security-and-firewall') . ' ' .__('This operation will not go ahead.', 'all-in-one-wp-security-and-firewall').'</p></div>';
return;
} else {
echo '<p class="aio_success_with_icon">'.__('A backup copy of your wp-config.php file was created successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
}
// Get multisite blog_ids if applicable
if (is_multisite()) {
$blog_ids = AIOWPSecurity_Utility::get_blog_ids();
}
// Rename all the table names
foreach ($result as $db_table) {
// Get table name with old prefix
$table_old_name = $db_table;
if (strpos($table_old_name, $table_old_prefix) === 0) {
// Get table name with new prefix
$table_new_name = AIOWPSecurity_Utility::backquote($table_new_prefix . substr($table_old_name, $old_prefix_length));
$table_old_name = AIOWPSecurity_Utility::backquote($table_old_name);
// Write query to rename tables name
$sql = "RENAME TABLE ".$table_old_name." TO ".$table_new_name;
// $sql = "RENAME TABLE %s TO %s";
// Execute the query
if (false === $wpdb->query($sql)) {
$error = 1;
echo '<p class="aio_error_with_icon">'.sprintf(__('%s table name update failed', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_old_name.'</strong>').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to change prefix of table ".$table_old_name, 4);
} else {
$table_count++;
}
} else {
continue;
}
}
if (1 == $error) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Please change the prefix manually for the above tables to: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_new_prefix.'</strong>').'</p>';
} else {
echo '<p class="aio_success_with_icon">'.sprintf(__('%s tables had their prefix updated successfully!', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_count.'</strong>').'</p>';
}
// Let's check for mysql tables of type "view"
$this->alter_table_views($table_old_prefix, $table_new_prefix);
// Get wp-config.php file contents and modify it with new info
$config_contents = file($config_file);
$prefix_match_string = '$table_prefix='; //this is our search string for the wp-config.php file
foreach ($config_contents as $line_num => $line) {
$no_ws_line = preg_replace('/\s+/', '', $line); //Strip white spaces
if (false !== strpos($no_ws_line, $prefix_match_string)) {
$prefix_parts = explode("=", $line);
$prefix_parts[1] = str_replace($table_old_prefix, $table_new_prefix, $prefix_parts[1]);
$config_contents[$line_num] = implode("=", $prefix_parts);
break;
}
}
// Now let's modify the wp-config.php file
if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
echo '<p class="aio_success_with_icon">'. __('wp-config.php file was updated successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
} else {
echo '<p class="aio_error_with_icon">'.sprintf(__('The "wp-config.php" file was not able to be modified.', 'all-in-one-wp-security-and-firewall').' '.__('Please modify this file manually using your favourite editor and search for variable "$table_prefix" and assign the following value to that variable: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_new_prefix.'</strong>').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to modify wp-config.php", 4);
}
// Now let's update the options table
$update_option_table_query = $wpdb->prepare("UPDATE " . $table_new_prefix . "options SET option_name = '".$table_new_prefix ."user_roles' WHERE option_name = %s LIMIT 1", $table_old_prefix."user_roles");
if (false === $wpdb->query($update_option_table_query)) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $table_new_prefix.'options', $table_old_prefix.'user_roles', $table_new_prefix.'user_roles').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Error when updating the options table", 4);//Log the highly unlikely event of DB error
} else {
echo '<p class="aio_success_with_icon">'. __('The options table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall') .'</p>';
}
// Now let's update the options tables for the multisite subsites if applicable
if (is_multisite()) {
if (!empty($blog_ids)) {
$main_site_id = get_main_site_id();
foreach ($blog_ids as $blog_id) {
if ($blog_id == $main_site_id) continue;
$new_pref_and_site_id = $table_new_prefix.$blog_id.'_';
$old_pref_and_site_id = $table_old_prefix.$blog_id.'_';
$update_ms_option_table_query = $wpdb->prepare("UPDATE " . $new_pref_and_site_id . "options SET option_name = '".$new_pref_and_site_id."user_roles' WHERE option_name = %s LIMIT 1", $old_pref_and_site_id."user_roles");
if (false === $wpdb->query($update_ms_option_table_query)) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options', $old_pref_and_site_id.'user_roles', $new_pref_and_site_id.'user_roles').'</p>';
$aio_wp_security->debug_logger->log_debug("DB change prefix feature - Error when updating the subsite options table: ".$new_pref_and_site_id.'options', 4);//Log the highly unlikely event of DB error
} else {
echo '<p class="aio_success_with_icon">'.sprintf(__('The %s table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options').'</p>';
}
}
}
}
//Now let's update the user meta table
$custom_sql = "SELECT user_id, meta_key FROM " . $table_new_prefix . "usermeta WHERE meta_key LIKE '" . $table_old_prefix . "%'";
$meta_keys = $wpdb->get_results($custom_sql);
$error_update_usermeta = '';
// Update all meta_key field values which have the old table prefix in user_meta table
foreach ($meta_keys as $meta_key) {
// Create new meta key
$new_meta_key = $table_new_prefix . substr($meta_key->meta_key, $old_prefix_length);
$update_user_meta_sql = $wpdb->prepare("UPDATE " . $table_new_prefix . "usermeta SET meta_key='" . $new_meta_key . "' WHERE meta_key=%s AND user_id=%s", $meta_key->meta_key, $meta_key->user_id);
if (false === $wpdb->query($update_user_meta_sql)) {
$error_update_usermeta .= '<p class="aio_error_with_icon">'.sprintf(__('Error updating user_meta table where new meta_key = %s, old meta_key = %s and user_id = %s.', 'all-in-one-wp-security-and-firewall'), $new_meta_key, $meta_key->meta_key, $meta_key->user_id).'</p>';
echo $error_update_usermeta;
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Error updating user_meta table where new meta_key = ".$new_meta_key." old meta_key = ".$meta_key->meta_key." and user_id = ".$meta_key->user_id, 4);//Log the highly unlikely event of DB error
}
}
echo '<p class="aio_success_with_icon">'.__('The usermeta table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
// Display tasks finished message
$tasks_finished_msg_string = '<p class="aio_info_with_icon">'. __('The database prefix change tasks have been completed.', 'all-in-one-wp-security-and-firewall').'</p>';
echo $tasks_finished_msg_string;
}
/**
* This is an alternative to the deprecated "mysql_list_tables
*
* @param string $database - database name
*
* @returns array - an array of table names
*/
public function get_mysql_tables($database = '') {
global $aio_wp_security;
$tables = array();
$list_tables_sql = "SHOW TABLES FROM `{$database}`;";
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($mysqli->connect_errno) {
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Database_Menu->get_mysql_tables() - DB connection error.", 4);
return false;
}
$result = $mysqli->query($list_tables_sql, MYSQLI_USE_RESULT);
if ($result) {
//Alternative way to get the tables
while ($row = $result->fetch_assoc()) {
foreach ($row as $value) {
$tables[] = $value;
}
}
$result->close();
}
$mysqli->close();
return $tables;
}
/**
* Will modify existing table view definitions to reflect the new DB prefix change
*
* @param string $old_db_prefix - old database prefix
* @param string $new_db_prefix - new database prefix
*
* @returns void
*/
private function alter_table_views($old_db_prefix, $new_db_prefix) {
global $wpdb, $aio_wp_security;
$db_name = $wpdb->dbname;
$info_msg_string = '<p class="aio_info_with_icon">'.__('Checking for MySQL tables of type "view".....', 'all-in-one-wp-security-and-firewall').'</p>';
echo $info_msg_string;
// get tables which are views
$query = "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA LIKE '".$db_name."'";
$res = $wpdb->get_results($query);
if (empty($res)) return;
$view_count = 0;
foreach ($res as $item) {
$old_def = $item->VIEW_DEFINITION;
$new_def = AIOWPSecurity_Utility::str_replace_once($old_db_prefix, $new_db_prefix, $old_def);
$new_def = AIOWPSecurity_Utility::backquote($new_def);
$view_name = AIOWPSecurity_Utility::backquote($item->TABLE_NAME);
$chg_view_sql = "ALTER VIEW $view_name AS $new_def";
$view_res = $wpdb->query($chg_view_sql);
if (false === $view_res) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of the following MySQL view definition failed: %s', 'all-in-one-wp-security-and-firewall'), $old_def).'</p>';
$aio_wp_security->debug_logger->log_debug("Update of the following MySQL view definition failed: ".$old_def, 4);//Log the highly unlikely event of DB error
} else {
$view_count++;
}
}
if ($view_count > 0) {
echo '<p class="aio_success_with_icon">'.sprintf(__('%s view definitions were updated successfully.', 'all-in-one-wp-security-and-firewall'), '<strong>'.$view_count.'</strong>').'</p>';
}
return;
}
}
@@ -0,0 +1,75 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
/**
* AIOWPSecurity_Filescan_Menu class for scanning file changes, maleware and available updates.
*
* @access public
*/
class AIOWPSecurity_Filescan_Menu extends AIOWPSecurity_Admin_Menu {
/**
* File scan menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_FILESCAN_MENU_SLUG;
/**
* Constructor adds menu for Scanner
*/
public function __construct() {
parent::__construct(__('Scanner', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'file-change-detect' => array(
'title' => __('File change detection', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_file_change_detect'),
),
'malware-scan' => array(
'title' => __('Malware scan', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_malware_scan'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* File change detection on your system files.
*
* @global $wpdb
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*/
protected function render_file_change_detect() {
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$scanner_data = $aios_commands->get_scanner_data();
$aio_wp_security->include_template('wp-admin/scanner/file-change-detect.php', false, $scanner_data);
}
/**
* Malware code scan on your system files.
*
* @return void
*/
protected function render_malware_scan() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/scanner/malware-scan.php', false, array());
}
}
@@ -0,0 +1,144 @@
<?php
if (!defined('ABSPATH')) {
exit; // Prevent direct access to file
}
class AIOWPSecurity_Filesystem_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Filesystem menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_FILESYSTEM_MENU_SLUG;
/**
* Constructor adds menu for Filesystem security
*/
public function __construct() {
parent::__construct(__('File security', 'all-in-one-wp-security-and-firewall'));
add_action('admin_footer', array($this, 'filesystem_menu_footer_code'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'file-permissions' => array(
'title' => __('File permissions', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_file_permissions'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'file-protection' => array(
'title' => __('File protection', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_file_protection'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'host-system-logs' => array(
'title' => __('Host system logs', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_host_system_logs'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'copy-protection' => array(
'title' => __('Copy protection', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_copy_protection'),
),
'frames' => array(
'title' => __('Frames', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_frames'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's file permissions tab
*
* @return Void
*/
protected function render_file_permissions() {
// if this is the case there is no need to display a "fix permissions" button
global $aio_wp_security, $aiowps_feature_mgr;
$files_dirs_to_check = AIOWPSecurity_Utility_File::get_files_and_dirs_to_check();
$aio_wp_security->include_template('wp-admin/filesystem-security/file-permissions.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'files_dirs_to_check' => $files_dirs_to_check, 'file_utility' => new AIOWPSecurity_Utility_File()));
}
/**
* Renders the submenu's 'File protection' tab
*
* @return void
*/
protected function render_file_protection() {
global $aio_wp_security;
$show_disallow_file_edit_warning = defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT && '1' != $aio_wp_security->configs->get_value('aiowps_disable_file_editing');
$aio_wp_security->include_template('wp-admin/filesystem-security/file-protection.php', false, array('show_disallow_file_edit_warning' => $show_disallow_file_edit_warning));
}
/**
* Renders the submenu's copy protection tab
*
* @return Void
*/
protected function render_copy_protection() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/filesystem-security/copy-protection.php', false, array());
}
/**
* Renders the submenu's render frames tab
*
* @return Void
*/
protected function render_frames() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/filesystem-security/frames.php', false, array());
}
/**
* Renders the submenu's host system logs tab
*
* @return Void
*/
protected function render_host_system_logs() {
global $aio_wp_security;
$sys_log_file = basename($aio_wp_security->configs->get_value('aiowps_system_log_file'));
$aio_wp_security->include_template('wp-admin/filesystem-security/host-system-logs.php', false, array('sys_log_file' => $sys_log_file));
}
/**
* Called via filter admin_footer, this adds the needed javascript to page
*
* @return void
*/
public function filesystem_menu_footer_code() {
?>
<script type="text/javascript">
/* <![CDATA[ */
jQuery(function($) {
loading_span = $('.aiowps_loading_1');
loading_span.hide(); //hide the spinner gif after page has successfully loaded
$('.search-error-files').on("click",function(){
loading_span.show();
});
});
function set_file_permission_tochange(path, recommended) {
jQuery('#aiowps_permission_chg_file').val(path);
jQuery('#aiowps_recommended_permissions').val(recommended);
return true;
}
/* ]]> */
</script>
<?php
}
}
@@ -0,0 +1,188 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
use AIOWPS\Firewall\Allow_List;
class AIOWPSecurity_Firewall_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Firewall menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_FIREWALL_MENU_SLUG;
/**
* Constructor adds menu for Firewall
*/
public function __construct() {
parent::__construct(__('Firewall', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'php-rules' => array(
'title' => __('PHP rules', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_php_rules'),
),
'htaccess-rules' => array(
'title' => __('.htaccess rules', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_htaccess_rules'),
'display_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess'),
),
'6g-firewall' => array(
'title' => __('6G firewall rules', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_6g_firewall'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'5g-firewall' => array(
'title' => __('5G legacy rules', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_5g_firewall'),
'display_condition_callback' => array('AIOWPSecurity_Utility', 'render_5g_legacy_tab'),
),
'internet-bots' => array(
'title' => __('Internet bots', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_internet_bots'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'block-and-allow-lists' => array(
'title' => __('Block & allow lists', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_block_and_allow_lists'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'advanced-settings' => array(
'title' => __('Advanced settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_advanced_settings'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
)
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the PHP Firewall settings tab
*
* @return void
*/
protected function render_php_rules() {
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$php_firewall_data = $aios_commands->get_php_firewall_data();
$aio_wp_security->include_template('wp-admin/firewall/php-firewall-rules.php', false, compact('php_firewall_data'));
}
/**
* Renders the Htaccess Firewall tab
*
* @return void
*/
protected function render_htaccess_rules() {
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$htaccess_rules_data = $aios_commands->get_htaccess_rules_data();
$aio_wp_security->include_template('wp-admin/firewall/htaccess-firewall-rules.php', false, compact('htaccess_rules_data'));
}
/**
* Renders the 6G Blacklist Firewall Rules tab
*
* @return void
*/
protected function render_6g_firewall() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/general/moved.php', false, array('key' => '6g'));
}
/**
* Renders the 5G Blacklist Firewall Rules tab
*
* @return void
*/
protected function render_5g_firewall() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/firewall/5g.php');
}
/**
* Renders the Internet Bots tab
*
* @return void
*/
protected function render_internet_bots() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/general/moved.php', false, array('key' => 'internet-bots'));
}
/**
* Renders the Advanced settings tab.
*
* @return void
*/
protected function render_advanced_settings() {
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$advanced_settings_data = $aios_commands->get_firewall_advanced_settings_data();
$aio_wp_security->include_template('wp-admin/firewall/advanced-settings.php', false, compact('advanced_settings_data'));
}
/**
* Renders ban user tab for blacklist IPs and user agents
*
* @global $aio_wp_security
* @global $aiowps_feature_mgr
*
* @return void
*/
protected function render_block_and_allow_lists() {
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$block_allowlist_data = $aios_commands->get_block_allow_lists_data();
$aio_wp_security->include_template('wp-admin/firewall/block-and-allow-lists.php', false, $block_allowlist_data);
}
/**
* Validates posted user agent list and set, save as config.
*
* @global $aio_wp_security
* @global $aiowps_firewall_config
*
* @param string $banned_user_agents
*
* @return int
*/
private function validate_user_agent_list($banned_user_agents) {
global $aio_wp_security;
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
$submitted_agents = AIOWPSecurity_Utility::splitby_newline_trim_filter_empty($banned_user_agents);
$agents = array_unique(array_filter(array_map('sanitize_text_field', $submitted_agents), 'strlen'));
$aio_wp_security->configs->set_value('aiowps_banned_user_agents', implode("\n", $agents));
$aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', $agents);
$_POST['aiowps_banned_user_agents'] = ''; // Clear the post variable for the banned address list
return 1;
}
}
@@ -0,0 +1,646 @@
<?php
if (!defined('ABSPATH')) {
exit; //Exit if accessed directly
}
class AIOWPSecurity_Firewall_Setup_Notice {
/**
* Holds reference to an instance of itself
*
* @var AIOWPSecurity_Firewall_Setup_Notice
*/
private static $instance = null;
/**
* Holds our wp-config file wrapped in our manager class
*
* @var AIOWPSecurity_Block_WpConfig
*/
private $wpconfig;
/**
* Holds our mu-plugin file wrapped in our manager class
*
* @var AIOWPSecurity_Block_Muplugin
*/
private $muplugin;
/**
* Holds our bootstrap file wrapped in our manager class
*
* @var AIOWPSecurity_Block_Bootstrap
*/
private $bootstrap;
/**
* Constants for the different notice types
*
* @var string
*/
const NOTICE_BOOTSTRAP = 'manual_bootstrap';
const NOTICE_MANUAL = 'manual';
const NOTICE_INSTALLED = 'success';
const NOTICE_DIRECTIVE_SET = 'userini_directive';
/**
* Constructs our object by setting up our essential files
*/
private function __construct() {
$this->bootstrap = AIOWPSecurity_Utility_Firewall::get_bootstrap_file();
$this->wpconfig = AIOWPSecurity_Utility_Firewall::get_wpconfig_file();
$this->muplugin = AIOWPSecurity_Utility_Firewall::get_muplugin_file();
AIOWPSecurity_Utility_Firewall::get_firewall_rules_path(true); // Creates the needed directories for the first time.
}
/**
* Entry point for the dashboard notice
*
* @return void
*/
public function start_firewall_setup() {
global $aio_wp_security;
$firewall_files = array(
'server' => AIOWPSecurity_Utility_Firewall::get_server_file(),
'bootstrap' => $this->bootstrap,
'wpconfig' => $this->wpconfig,
'muplugin' => $this->muplugin,
);
//Check each file and update the contents if necessary
foreach ($firewall_files as $name => $file) {
${'is_firewall_in_'.$name} = false;
if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP === $file) {
continue;
}
${'is_firewall_in_'.$name} = $file->contains_contents();
if (true === ${'is_firewall_in_'.$name}) {
$file->update_contents();
}
}
if (!$aio_wp_security->is_aiowps_admin_page()) {
return;
}
if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) {
if (true !== $is_firewall_in_server) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- variable is set in the foreach loop
$this->render_upgrade_protection_notice();
}
} else {
$this->render_automatic_setup_notice();
}
$this->render_notices();
}
/**
* Will execute when the user presses 'Set up now' button
*
* @return void
*/
public function do_setup() {
$is_inserted_firewall_file = false;
$is_inserted_bootstrap_file = $this->bootstrap->contains_contents();
if (true !== $is_inserted_bootstrap_file) {
$is_inserted_bootstrap_file = $this->bootstrap->insert_contents();
if (true !== $is_inserted_bootstrap_file) {
$this->log_wp_error($is_inserted_bootstrap_file);
$this->show_notice(self::NOTICE_BOOTSTRAP);
return;
}
}
$firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file();
if ($firewall_file instanceof AIOWPSecurity_Block_Userini) {
$directive = AIOWPSecurity_Utility_Firewall::get_already_set_directive($firewall_file);
if (!empty($directive)) {
if (AIOWPSecurity_Utility_Firewall::get_bootstrap_path() === $directive) {
$is_inserted_firewall_file = true;
} else {
$this->show_notice(self::NOTICE_DIRECTIVE_SET, array('directive' => $directive));
}
} else {
$is_inserted_firewall_file = $firewall_file->insert_contents();
}
} else {
if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP !== $firewall_file) {
$is_inserted_firewall_file = $firewall_file->insert_contents(); // attempts to insert firewall into required file
}
}
//Set up the firewall in the wp-config file
$is_inserted_wpconfig = $this->wpconfig->contains_contents();
if (true !== $is_inserted_wpconfig) {
$is_inserted_wpconfig = $this->wpconfig->insert_contents();
}
$this->log_wp_error($is_inserted_wpconfig);
//Set up the firewall in the mu-plugin
$is_inserted_muplugin = $this->muplugin->contains_contents();
if (true !== $is_inserted_muplugin) {
$is_inserted_muplugin = $this->muplugin->insert_contents();
}
if (false === $is_inserted_muplugin) {
$this->log_wp_error(new \WP_Error(
'file-mu-plugin-failed',
'Unable to create the mu-plugin',
$this->muplugin
));
}
$this->log_wp_error($is_inserted_muplugin);
if (true === $is_inserted_firewall_file) {
$this->show_notice(self::NOTICE_INSTALLED);
} else {
$this->log_wp_error($is_inserted_firewall_file);
$this->show_notice(self::NOTICE_MANUAL);
}
}
/**
* Dismisses the notice.
*
* @return void
*/
private function do_dismiss() {
global $aio_wp_security;
$aio_wp_security->configs->set_value('aios_firewall_dismiss', true, true);
}
/**
* Checks whether the notice is dismissed
*
* @return boolean
*/
private function is_dismissed() {
global $aio_wp_security;
return (true === $aio_wp_security->configs->get_value('aios_firewall_dismiss'));
}
/**
* Handles the form submission for the 'Set up now' notice
*
* @return void
*/
public function handle_setup_form() {
$nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : '';
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-setup');
if (!is_wp_error($result)) {
$this->do_setup();
$this->do_redirect();
}
}
/**
* Handles the dismiss form
*
* @return void
*/
public function handle_dismiss_form() {
$nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : '';
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-setup-dismiss');
if (!is_wp_error($result)) {
$this->do_dismiss();
$this->do_redirect();
}
}
/**
* Handles the form that downgrades the firewall's protection.
*
* @return void
*/
public function handle_downgrade_protection_form() {
$nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : '';
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($nonce, 'aiowpsec-firewall-downgrade');
if (!is_wp_error($result)) {
AIOWPSecurity_Utility_Firewall::remove_firewall();
$this->do_redirect();
}
}
/**
* Handles the redirect
*
* @return void
*/
private function do_redirect() {
// Go back to the previous page and tab if set
if (isset($_POST['_wp_http_referer'])) {
$matches = array();
if (preg_match('/\?page='.AIOWPSEC_MENU_SLUG_PREFIX.'(?<page>.*)(&tab=(?<tab>.*))?$/m', $_POST['_wp_http_referer'], $matches)) {
$url = 'admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX;
if (isset($matches['page'])) {
$url .= sanitize_text_field($matches['page']);
if (isset($matches['tab'])) {
$url .= '&tab='.sanitize_text_field($matches['tab']);
}
}
AIOWPSecurity_Utility::redirect_to_url(admin_url(sanitize_url($url)));
}
}
AIOWPSecurity_Utility::redirect_to_url(admin_url('admin.php?page='.AIOWPSEC_MENU_SLUG_PREFIX));
}
/**
* Wrapper function to log WP_Errors to debug log
*
* @param WP_Error $wp_error - Our error which gets logged
* @return void
*/
private function log_wp_error($wp_error) {
if (is_wp_error($wp_error)) {
global $aio_wp_security;
$error_message = $wp_error->get_error_message();
$error_message .= ' - ';
$error_message .= $wp_error->get_error_data();
$aio_wp_security->debug_logger->log_debug($error_message, 4);
}
}
/**
* Sets the flags to show notices
*
* @param string $type - the type of notice we want to set
* @param array $values - any values that need to be passed
* @return void
*/
private function show_notice($type, $values = array()) {
global $aio_wp_security;
$aio_wp_security->configs->set_value('firewall_notice_'.$type, true);
if (!empty($values)) {
$aio_wp_security->configs->set_value('firewall_notice_values', $values);
}
$aio_wp_security->configs->save_config();
}
/**
* Renders any necessary notices
*
* @return void
*/
public function render_notices() {
global $aio_wp_security;
$notices = array(
self::NOTICE_BOOTSTRAP,
self::NOTICE_MANUAL,
self::NOTICE_INSTALLED,
self::NOTICE_DIRECTIVE_SET,
);
foreach ($notices as $notice) {
if ($aio_wp_security->configs->get_value('firewall_notice_'.$notice)) {
switch ($notice) {
case self::NOTICE_BOOTSTRAP:
$this->render_bootstrap_notice();
break;
case self::NOTICE_MANUAL:
if (!$this->any_pending_notices(self::NOTICE_MANUAL)) {
$this->render_manual_setup_notice();
}
break;
case self::NOTICE_INSTALLED:
$this->render_firewall_installed_notice();
break;
case self::NOTICE_DIRECTIVE_SET:
$values = $aio_wp_security->configs->get_value('firewall_notice_values');
$this->render_userini_directive_set_notice($values['directive']);
$aio_wp_security->configs->delete_value('firewall_notice_values');
break;
}
$aio_wp_security->configs->delete_value('firewall_notice_'.$notice);
}
}
$aio_wp_security->configs->save_config();
}
/**
* Detects if we have any notices pending to display
*
* @param string ...$exclude - do not check the status of these notices
*
* @return boolean
*/
private function any_pending_notices(...$exclude) {
global $aio_wp_security;
$notices = array(
self::NOTICE_BOOTSTRAP,
self::NOTICE_MANUAL,
self::NOTICE_INSTALLED,
self::NOTICE_DIRECTIVE_SET,
);
$notices = array_diff($notices, $exclude);
foreach ($notices as $notice) {
if (true === $aio_wp_security->configs->get_value('firewall_notice_'.$notice)) {
return true;
}
}
return false;
}
/**
* Notice is shown if we are unable to write to the bootstrap file
*
* @return void
*/
private function render_bootstrap_notice() {
?>
<div class="notice notice-error is-dismissible">
<p>
<strong><?php _e('All-In-One Security', 'all-in-one-wp-security-and-firewall'); ?></strong>
</p>
<p><?php _e('We were unable to create the file necessary to give you the highest level of protection.', 'all-in-one-wp-security-and-firewall');?></p>
<p><?php _e('Your firewall will have reduced protection which means some of your firewall\'s functionality will be unavailable.', 'all-in-one-wp-security-and-firewall');?></p>
<p><?php _e('If you would like to manually set up the necessary file, please follow these steps:', 'all-in-one-wp-security-and-firewall');?></p>
<p>
<?php
/* translators: %s Bootstrap file name. */
printf(__('1. Create a file with the name %s in the same directory as your WordPress install is in, i.e.:', 'all-in-one-wp-security-and-firewall'), pathinfo($this->bootstrap, PATHINFO_BASENAME));
?>
</p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo esc_html($this->bootstrap); ?></pre>
<p><?php _e('2. Paste in the following code:', 'all-in-one-wp-security-and-firewall');?></p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo htmlentities($this->bootstrap->get_contents()); ?></pre>
<p><?php _e('3. Save the file and press the \'Try again\' button below:', 'all-in-one-wp-security-and-firewall');?></p>
<?php
$this->render_try_again_button();
$this->render_manual_notice_footer();
}
/**
* Notice is shown if auto_prepend_file directive is already set in user.ini
*
* @param string $directive_value
* @return void
*/
private function render_userini_directive_set_notice($directive_value) {
$firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file();
$this->render_manual_notice_header();
?>
<p>
<?php _e('1. Open the following file:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<p><code><?php echo esc_html($firewall_file); ?></code></p>
<?php if (empty($directive_value)) {?>
<p>
<?php _e('2. Look for the auto_prepend_file directive.', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<?php } else {?>
<p>
<?php _e('2. Look for the following:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo "auto_prepend_file='".esc_html($directive_value)."'";?></pre>
<?php } ?>
<p>
<?php _e('3. Change it to the following:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo esc_html(AIOWPSecurity_Utility_Firewall::get_server_file()->get_contents()); ?></pre>
<p>
<?php echo __('4. Save the file and press the \'Try again\' button below:', 'all-in-one-wp-security-and-firewall').' '.__('You may have to wait up to 5 minutes before the settings take effect.', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<?php
$this->render_try_again_button();
$this->render_manual_notice_footer();
}
/**
* Shows when the firewall has successfully installed
*
* @return void
*/
private function render_firewall_installed_notice() {
global $aio_wp_security;
$aio_wp_security->include_template('notices/firewall-installed-notice.php', false);
}
/**
* Renders the 'manual setup' dashboard notice
*
* @return void
*/
private function render_manual_setup_notice() {
$firewall_file = AIOWPSecurity_Utility_Firewall::get_server_file();
if (AIOWPSecurity_Utility_Firewall::MANUAL_SETUP === $firewall_file) {
//Show users how to manually add the firewall via php.ini if we can't detect their server
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
$this->render_manual_notice_header();
?>
<p>
<?php _e('1. Open your php.ini file.', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<p>
<?php _e('2. Set the auto_prepend_file directive like below:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo "auto_prepend_file='".esc_html($bootstrap_path)."'";?></pre>
<p>
<?php echo __('3. Restart the webserver and refresh the page', 'all-in-one-wp-security-and-firewall').' '.__('You may have to wait up to 5 minutes before the settings take effect.', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<?php
$this->render_manual_notice_footer();
} else {
//Show users how to manually add the firewall via their own server file
$this->render_manual_notice_header();
$firewall_file_name = pathinfo($firewall_file, PATHINFO_BASENAME);
?>
<p>
<?php
/* translators: %s Firewall file name. */
printf(__('1. Create a file with the name %s in the same directory as your WordPress install is in, i.e.:', 'all-in-one-wp-security-and-firewall'), $firewall_file_name);
?>
<p><code><?php echo esc_html($firewall_file); ?></code></p>
</p>
<p>
<?php _e('2. Paste in the following directives:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<pre style='max-width: 100%;background-color: #f0f0f0;border:#ccc solid 1px;padding: 10px;white-space:pre-wrap;'><?php echo htmlentities($firewall_file->get_contents()); ?></pre>
<p>
<?php echo __('3. Save the file and press the \'Try again\' button below:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<?php
$this->render_try_again_button();
$this->render_manual_notice_footer();
}
}
/**
* The header for notices that require manual intervention
*
* @return void
*/
private function render_manual_notice_header() {
?>
<div class="notice notice-warning is-dismissible">
<p>
<strong><?php _e('All-In-One Security', 'all-in-one-wp-security-and-firewall'); ?></strong>
</p>
<p>
<?php echo __('We were unable to set up your firewall with the highest level of protection.', 'all-in-one-wp-security-and-firewall').' '.
__('Your firewall will have reduced functionality.', 'all-in-one-wp-security-and-firewall');
?>
</p>
<p>
<?php _e('To give your site the highest level of protection, please follow these steps:', 'all-in-one-wp-security-and-firewall'); ?>
</p>
<?php
}
/**
* The footer for notices that require manual intervention
*
* @return void
*/
private function render_manual_notice_footer() {
?>
<p>
<strong><?php _e('Note: if you\'re unable to perform any of the aforementioned steps, please ask your web hosting provider for further assistance.', 'all-in-one-wp-security-and-firewall'); ?></strong>
</p>
</div>
<?php
}
/**
* Render Try again button.
*
* @return void
*/
private function render_try_again_button() {
?>
<form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="POST">
<?php wp_nonce_field('aiowpsec-firewall-setup'); ?>
<input type="hidden" name="action" value="aiowps_firewall_setup">
<div style="padding-top: 10px; padding-bottom: 10px;">
<input class="button button-primary" type="submit" name="btn_try_again" value="<?php _e('Try again', 'all-in-one-wp-security-and-firewall'); ?>">
</div>
</form>
<?php
}
/**
* Renders the warning that users do not have the highest level of protection
*
* @return void
*/
private function render_upgrade_protection_notice() {
if ($this->should_not_show_notice()) {
return;
}
?>
<div class="notice notice-warning">
<form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="POST">
<?php wp_nonce_field('aiowpsec-firewall-setup'); ?>
<input type="hidden" name="action" value="aiowps_firewall_setup">
<p>
<?php _e('We have detected that your AIOS firewall is not fully installed, and therefore does not have the highest level of protection.', 'all-in-one-wp-security-and-firewall');?>
<?php echo ' ' . __('Your firewall will have reduced functionality until it has been upgraded.', 'all-in-one-wp-security-and-firewall');?>
<div style="padding-top: 10px;">
<input class="button button-primary" type="submit" name="btn_upgrade_now" value="<?php _e('Upgrade your protection now', 'all-in-one-wp-security-and-firewall'); ?>">
</div>
</p>
</form>
</div>
<?php
}
/**
* Whether the firewall notice should not be shown.
*
* @return boolean True if the firewall notice should not be shown otherwise false.
*/
private function should_not_show_notice() {
if (!is_main_site()) {
return true;
}
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
return true;
}
if ($this->is_dismissed() && !AIOWPSecurity_Utility_Firewall::is_firewall_page()) {
return true;
}
if ($this->any_pending_notices()) {
return true; //only display if there are no other notices waiting to be displayed
}
return false;
}
/**
* Renders the 'Set up now' dashboard notice
*
* @return void
*/
private function render_automatic_setup_notice() {
global $aio_wp_security;
if ($this->should_not_show_notice()) {
return;
}
$aio_wp_security->include_template('notices/firewall-setup-notice.php', false, array('show_dismiss' => !AIOWPSecurity_Utility_Firewall::is_firewall_page()));
}
/**
* Ensures only one instance of the class can be created (singleton)
*
* @return AIOWPSecurity_Firewall_Setup_Notice|null
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
@@ -0,0 +1,362 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_404 extends AIOWPSecurity_List_Table {
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'item', //singular name of the listed records
'plural' => 'items', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
/**
* Returns created column in datetime format as per user setting time zone.
*
* @param array $item - data for the columns on the current row
*
* @return string - the datetime
*/
public function column_created($item) {
return AIOWPSecurity_Utility::convert_timestamp($item['created']);
}
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Returns id column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - html string for column rendered
*/
public function column_id($item) {
$ip = $item['ip_or_host'];
$is_locked = AIOWPSecurity_Utility::check_locked_ip($ip, '404');
$blacklist_tab = 'blacklist';
$is_blacklist = AIOWPSecurity_Utility::check_blacklist_ip($ip);
$actions = array();
$actions['delete'] = '<a class="aios-delete-404" data-id="' . esc_attr($item['id']) . '" data-message="' . esc_js(__('Are you sure you want to delete this item?', 'all-in-one-wp-security-and-firewall')) . '" href="#">' . __('Delete', 'all-in-one-wp-security-and-firewall') . '</a>';
if ($is_locked) {
// Build row actions for locked items
$actions['unblock'] = '<a class="aios-unblock-404" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js(__('Are you sure you want to unblock this item?', 'all-in-one-wp-security-and-firewall')) . '" href="#">' . __('Unblock', 'all-in-one-wp-security-and-firewall') . '</a>';
} elseif ($is_blacklist) {
$unblock_url_nonce = wp_nonce_url(sprintf('admin.php?page=%s&tab=%s', AIOWPSEC_FIREWALL_MENU_SLUG, $blacklist_tab), "404_log_item_action", "aiowps_nonce");
$actions = array(
'unblock' => '<a href="'.$unblock_url_nonce.'" onclick="return confirm(\'' . esc_js(__('Are you sure you want to unblock this item?', 'all-in-one-wp-security-and-firewall')) . '\')">'.__('Unblock', 'all-in-one-wp-security-and-firewall').'</a>',
);
} else {
// Build row actions for other items
$actions['temp_block'] = '<a class="aios-temp-block-404" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js(__('Are you sure you want to block this IP address?', 'all-in-one-wp-security-and-firewall')) . '" data-username="' . esc_attr($item['username']) . '" href="#">' . __('Temporarily block', 'all-in-one-wp-security-and-firewall') . '</a>';
$actions['blacklist_ip'] = '<a class="aios-blacklist-404" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js(__('Are you sure you want to permanently block this IP address?', 'all-in-one-wp-security-and-firewall')) . '" href="#">' . __('Blacklist IP', 'all-in-one-wp-security-and-firewall') . '</a>';
}
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/* $1%s */ $item['id'],
/* $2%s */ $this->row_actions($actions)
);
}
/**
* Returns status column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - html string for column rendered
*/
public function column_status($item) {
global $aio_wp_security;
$ip = $item['ip_or_host'];
//Check if this IP address is locked
$is_locked = AIOWPSecurity_Utility::check_locked_ip($ip, '404');
$blacklisted_string = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
$banned = strpos($blacklisted_string, $ip);
if (false !== $banned) {
return 'blacklisted';
} elseif ($is_locked) {
return 'temporarily blocked';
} else {
return '';
}
}
/**
* Returns checkbox column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - html string for column rendered
*/
public function column_cb($item) {
return sprintf('<input type="checkbox" name="%1$s[]" value="%2$s" />',
/* $1%s */ $this->_args['singular'], //Let's simply repurpose the table's singular label
/* $2%s */ $item['id'] //The value of the checkbox should be the record's id
);
}
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox" />', //Render a checkbox
'id' => 'ID',
'event_type' => __('Event type', 'all-in-one-wp-security-and-firewall'),
'ip_or_host' => __('IP address', 'all-in-one-wp-security-and-firewall'),
'url' => __('Attempted URL', 'all-in-one-wp-security-and-firewall'),
'referer_info' => __('Referer', 'all-in-one-wp-security-and-firewall'),
'created' => __('Date and time', 'all-in-one-wp-security-and-firewall'),
'status' => __('Lock status', 'all-in-one-wp-security-and-firewall'),
);
$columns = apply_filters('list_404_get_columns', $columns);
return $columns;
}
public function get_sortable_columns() {
$sortable_columns = array(
'id' => array('id', false),
'event_type' => array('event_type', false),
'ip_or_host' => array('ip_or_host', false),
'url' => array('url', false),
'referer_info' => array('referer_info', false),
'created' => array('created', false),
);
$sortable_columns = apply_filters('list_404_get_sortable_columns', $sortable_columns);
return $sortable_columns;
}
/**
* Get bulk actions for the current WordPress screen.
*
* @return array An associative array of bulk actions where the keys are action names
* and the values are the corresponding action labels.
*/
public function get_bulk_actions() {
return array(
//'unlock' => 'Unlock',
'bulk_block_ip' => __('Temporarily block IP', 'all-in-one-wp-security-and-firewall'),
'bulk_blacklist_ip' => __('Blacklist IP', 'all-in-one-wp-security-and-firewall'),
'delete' => __('Delete', 'all-in-one-wp-security-and-firewall')
);
}
/**
* Process bulk actions for the current WordPress screen.
*
* This method checks for the presence of a valid nonce and user capabilities,
* then performs the appropriate action based on the selected bulk action.
*
* @return void
*/
private function process_bulk_action() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Ignore.
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
if (is_wp_error($result)) return;
if ('bulk_block_ip' === $this->current_action()) {//Process delete bulk actions
if (!isset($_REQUEST['item'])) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
$this->block_ip(wp_unslash($_REQUEST['item']));
}
}
if ('bulk_blacklist_ip' === $this->current_action()) {//Process delete bulk actions
if (!isset($_REQUEST['item'])) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
$this->blacklist_ip_address(wp_unslash($_REQUEST['item']));
}
}
if ('delete' === $this->current_action()) {//Process delete bulk actions
if (!isset($_REQUEST['item'])) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning, ignore. Sanitized later.
$this->delete_404_event_records(wp_unslash($_REQUEST['item']));
}
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
}
/**
* Locks an IP address by adding it to the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
*
* @param array|string $entries - ids that correspond to ip addresses in the AIOWPSEC_TBL_EVENTS table or a single ip address
* @param string $username - (optional)username of user being locked
*
* @return boolean|void
*/
public function block_ip($entries, $username = '') {
global $wpdb;
if (is_array($entries)) {
//lock multiple records
$entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
$id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
$events_table = AIOWPSEC_TBL_EVENTS;
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$results = $wpdb->get_col("SELECT ip_or_host FROM $events_table WHERE ID IN " . $id_list);
if (empty($results)) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Could not process the request because the IP addresses for the selected entries could not be found.', 'all-in-one-wp-security-and-firewall'));
return false;
} else {
foreach ($results as $entry) {
if (filter_var($entry, FILTER_VALIDATE_IP)) {
AIOWPSecurity_Utility::lock_IP($entry, '404', $username);
}
}
}
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses are now temporarily blocked.', 'all-in-one-wp-security-and-firewall'));
}
}
/**
* Permanently blocks an IP address by adding it to the blacklist and writing rules to the htaccess file.
*
* @param array|string $entries - ids that correspond to ip addresses in the AIOWPSEC_TBL_EVENTS table or a single ip address
*
* @return boolean|void
*/
public function blacklist_ip_address($entries) {
global $wpdb, $aio_wp_security;
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
$bl_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses'); //get the currently saved blacklisted IPs
$ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($bl_ip_addresses);
if (is_array($entries)) {
//Get the selected IP addresses
$entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
$id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
$events_table = AIOWPSEC_TBL_EVENTS;
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$results = $wpdb->get_col("SELECT ip_or_host FROM $events_table WHERE ID IN " . $id_list);
if (empty($results)) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Could not process the request because the IP addresses for the selected entries could not be found.', 'all-in-one-wp-security-and-firewall'));
return false;
} else {
foreach ($results as $entry) {
$ip_list_array[] = $entry;
}
}
}
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
if (is_wp_error($validated_ip_list_array)) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(nl2br($validated_ip_list_array->get_error_message()));
} else {
$banned_ip_data = implode("\n", $validated_ip_list_array);
$aio_wp_security->configs->set_value('aiowps_enable_blacklisting', '1'); // Force blacklist feature to be enabled.
$aio_wp_security->configs->set_value('aiowps_banned_ip_addresses', $banned_ip_data);
$aio_wp_security->configs->save_config();
$aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses have been added to the blacklist and will be permanently blocked.', 'all-in-one-wp-security-and-firewall'));
}
}
/**
* Deletes one or more records from the AIOWPSEC_TBL_EVENTS table.
*
* @param array|string|integer $entries - ids or a single id
*
* @return void|string
*/
public function delete_404_event_records($entries) {
global $wpdb, $aio_wp_security;
$events_table = AIOWPSEC_TBL_EVENTS;
if (is_array($entries)) {
//Delete multiple records
$entries = array_map('esc_sql', $entries); //escape every array element
$entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
$id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query("DELETE FROM " . $events_table . " WHERE id IN " . $id_list);
if ($result) {
AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
} else {
// Error on bulk delete
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Events table. Database error: '.$wpdb->last_error, 4);
AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
}
}
}
/**
* Retrieves all items from AIOWPSEC_TBL_EVENTS according to a search term inside $_REQUEST['s'] and only '404' events if there is no search term. It then assigns to $this->items.
*
* @param Boolean $ignore_pagination - whether to not paginate
*
* @return Void
*/
public function prepare_items($ignore_pagination = false) {
/**
* First, lets decide how many records per page to show
*/
$per_page = 100;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. Nonce checked in previous function.
$search_term = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : '';
$this->_column_headers = array($columns, $hidden, $sortable);
$this->process_bulk_action();
global $wpdb;
$events_table_name = AIOWPSEC_TBL_EVENTS;
// Ordering parameters
// Parameters that are going to be used to order the result
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
$orderby = !empty($orderby) ? esc_sql($orderby) : 'id';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
if (empty($search_term)) {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM $events_table_name WHERE `event_type` = '404' ORDER BY $orderby $order", ARRAY_A);
} else {
// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQueryWithPlaceholder, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$data = $wpdb->get_results($wpdb->prepare("SELECT * FROM $events_table_name WHERE `ip_or_host` LIKE '%%%s%%' OR `url` LIKE '%%%s%%' OR `referer_info` LIKE '%%%s%%' ORDER BY $orderby $order", $wpdb->esc_like($search_term), $wpdb->esc_like($search_term), $wpdb->esc_like($search_term)), ARRAY_A);
}
if (!$ignore_pagination) {
$current_page = $this->get_pagenum();
$total_items = count($data);
$data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
));
}
foreach ($data as $index => $row) {
// Insert an empty status column - we will use later
$data[$index]['status'] = '';
}
$this->items = $data;
}
}
@@ -0,0 +1,527 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Audit_Log extends AIOWPSecurity_Ajax_Data_Table {
/**
* Constructs the table object and sets up its attributes.
*
* @param array $data - An array containing additional data for the table. Default is an empty array.
* @return void
*/
public function __construct($data = array()) {
// Set parent defaults
parent::__construct(array(
'singular' => 'item', // singular name of the listed records
'plural' => 'items', // plural name of the listed records
'ajax' => true, // does this table support ajax?
'data' => $data // Request data
));
}
/**
* Returns the default column item
*
* @param object $item - item from which column data is returned
* @param string $column_name - column name to be fetched from item
* @return string
*/
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Returns cb column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/* $1%s */ $this->_args['singular'], // Let's simply repurpose the table's singular label
/* $2%s */ $item['id'] // The value of the checkbox should be the record's id
);
}
/**
* Returns created column html to be rendered.
*
* @param array $item Data for the columns on the current row.
*
* @return string The html to be rendered.
*/
public function column_created($item) {
$actions = array(
'delete' => '<a class="aios-delete-audit-log" data-id="' . esc_attr($item['id']) . '" data-message="' . esc_js(__('Are you sure you want to delete this item?', 'all-in-one-wp-security-and-firewall')) . '" href="">' . esc_html__('Delete', 'all-in-one-wp-security-and-firewall') . '</a>'
);
return AIOWPSecurity_Utility::convert_timestamp($item['created']) . '<span style="color:silver"></span>' . $this->row_actions($actions);
}
/**
* Returns ip column html to be rendered.
*
* @param array $item Data for the columns on the current row.
*
* @return string The html to be rendered.
*/
public function column_ip($item) {
$ip = $item['ip'];
$unblacklist_ip_warning_translation = __('Are you sure you want to unblacklist this IP address?', 'all-in-one-wp-security-and-firewall');
$unlock_ip_warning_translation = __('Are you sure you want to unlock this IP address?', 'all-in-one-wp-security-and-firewall');
$lock_ip_warning_translation = __('Are you sure you want to temporarily lock this IP address?', 'all-in-one-wp-security-and-firewall');
$blacklist_ip_warning_translation = __('Are you sure you want to blacklist this IP address?', 'all-in-one-wp-security-and-firewall');
// Build row actions.
if (AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin() && AIOWPSecurity_Utility::check_blacklist_ip($ip)) {
$actions = array(
'unblacklist' => '<a class="aios-unblacklist-ip-button" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js($unblacklist_ip_warning_translation) . '" href="">' . esc_html__('Unblacklist', 'all-in-one-wp-security-and-firewall') . '</a>',
);
} elseif (AIOWPSecurity_Utility::check_locked_ip($ip, 'audit-log')) {
$actions = array(
'unlock' => '<a class="aios-unlock-ip-button" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js($unlock_ip_warning_translation) . '" href="">' . esc_html__('Unlock', 'all-in-one-wp-security-and-firewall') . '</a>',
);
} else {
$actions = array(
'lock_ip' => '<a class="aios-lock-ip-button" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js($lock_ip_warning_translation) . '" href="">' . esc_html__('Lock IP', 'all-in-one-wp-security-and-firewall') . '</a>',
);
if (AIOWPSecurity_Utility_Permissions::is_main_site_and_super_admin()) {
$actions['blacklist_ip'] = '<a class="aios-blacklist-ip-button" data-ip="' . esc_attr($ip) . '" data-message="' . esc_js($blacklist_ip_warning_translation) . '" href="">' . esc_html__('Blacklist IP', 'all-in-one-wp-security-and-firewall') . '</a>';
}
}
return $ip . '<span style="color:silver"></span>' . $this->row_actions($actions);
}
/**
* Returns event type column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_event_type($item) {
if (empty($item['event_type'])) return __('No event type available.', 'all-in-one-wp-security-and-firewall');
$output = isset(AIOWPSecurity_Audit_Events::$event_types[$item['event_type']]) ? AIOWPSecurity_Audit_Events::$event_types[$item['event_type']] : $item['event_type'];
return $output;
}
/**
* Returns details column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_details($item) {
$details = json_decode($item['details'], true);
if (!is_array($details)) return $item['details'];
$key = array_keys($details)[0];
if (method_exists("AIOWPSecurity_Audit_Text_Handler", "{$key}_to_text")) {
return call_user_func("AIOWPSecurity_Audit_Text_Handler::{$key}_to_text", $details[$key]);
}
return $item['details'];
}
/**
* Returns stack trace column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_stacktrace($item) {
if (empty($item['stacktrace'])) return __('No stack trace available.', 'all-in-one-wp-security-and-firewall');
if (is_serialized($item['stacktrace'])) {
$stacktrace = AIOWPSecurity_Utility::unserialize($item['stacktrace']);
} else {
$stacktrace = $item['stacktrace'];
}
ob_start();
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_dump -- Part of error reporting system.
var_dump($stacktrace);
$stacktrace_output = ob_get_contents();
ob_end_clean();
$output = sprintf('<a href="#TB_inline?&inlineId=trace-%s" title="%s" class="thickbox">%s</a>', $item['id'], esc_html__('Stack trace', 'all-in-one-wp-security-and-firewall'), esc_html__('Show trace', 'all-in-one-wp-security-and-firewall'));
$output .= sprintf('<div id="trace-%s" style="display: none"><pre>%s</pre></div>', $item['id'], htmlspecialchars($stacktrace_output));
return $output;
}
/**
* Sets the columns for the table
*
* @return array
*/
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox">', //Render a checkbox
'created' => __('Date and time', 'all-in-one-wp-security-and-firewall'),
'level' => __('Level', 'all-in-one-wp-security-and-firewall'),
'network_id' => __('Network ID', 'all-in-one-wp-security-and-firewall'),
'site_id' => __('Site ID', 'all-in-one-wp-security-and-firewall'),
'username' => __('Username', 'all-in-one-wp-security-and-firewall'),
'ip' => __('IP', 'all-in-one-wp-security-and-firewall'),
'event_type' => __('Event', 'all-in-one-wp-security-and-firewall'),
'details' => __('Details', 'all-in-one-wp-security-and-firewall'),
'stacktrace' => __('Stack trace', 'all-in-one-wp-security-and-firewall')
);
$columns = apply_filters('list_auditlogs_get_columns', $columns);
return $columns;
}
/**
* Sets which of the columns the table data can be sorted by
*
* @return array
*/
public function get_sortable_columns() {
$sortable_columns = array(
'created' => array('created', false),
'network_id' => array('network_id', false),
'site_id' => array('site_id', false),
'level' => array('level', false),
'username' => array('username', false),
'ip' => array('ip', false),
'event_type' => array('event_type', false),
'details' => array('details', false),
'stacktrace' => array('stacktrace', false)
);
$sortable_columns = apply_filters('list_auditlogs_get_sortable_columns', $sortable_columns);
return $sortable_columns;
}
/**
* This function will display a list of bulk actions for the list table
*
* @return array
*/
public function get_bulk_actions() {
$actions = array(
'delete_all' => __('Delete all', 'all-in-one-wp-security-and-firewall'),
'delete_selected' => __('Delete selected', 'all-in-one-wp-security-and-firewall'),
'delete_filtered' => __('Delete filtered', 'all-in-one-wp-security-and-firewall')
);
return $actions;
}
/**
* This function will process the bulk action request, $search_term and $filters are only used if the user is trying to bulk delete the filtered items
*
* @param string $search_term - The search term used for filtering records.
* @param array $filters - An array containing filters applied to the records.
* @param string $action - The bulk action to be performed.
* @param array $items - An array of record IDs on which the action will be performed. Default is an empty array.
*
* @return void
*/
private function process_bulk_action($search_term, $filters, $action, $items = array()) {
global $wpdb;
if ('delete_selected' === $action) { // Process delete bulk actions
if (!isset($items)) {
AIOS_Helper::set_message('aios_list_message', __('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'), 'error');
} else {
$this->delete_audit_event_records($items);
}
} elseif ('delete_filtered' === $action) {
if (!empty($filters) || '' !== $search_term) {
$audit_log_tbl = AIOWPSEC_TBL_AUDIT_LOG;
$where_sql = $this->get_audit_list_where_sql($search_term, $filters);
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$results = $wpdb->get_results("SELECT id FROM {$audit_log_tbl} {$where_sql}", 'ARRAY_A');
$items = array_column($results, 'id');
$this->delete_audit_event_records($items);
} else {
AIOS_Helper::set_message('aios_list_message', __('Please select the level or the event type filter or filter by a search term', 'all-in-one-wp-security-and-firewall'), 'error');
}
} elseif ('delete_all' === $action) {
$this->delete_audit_event_records(null, true);
}
}
/**
* Outputs extra controls to be displayed between bulk actions and pagination
*
* @param string $which - where we are outputting content (top or bottom)
*
* @return void
*/
protected function extra_tablenav($which) {
switch ($which) {
case 'top':
?>
<div class="alignleft actions">
<select name="level-filter" class="audit-filter-level">
<?php $selected = !isset($this->_args['data']['level-filter']) ? ' selected = "selected"' : ''; ?>
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- No user input to escape. ?>
<option value="-1" <?php echo $selected; ?>><?php esc_html_e('All levels', 'all-in-one-wp-security-and-firewall'); ?></option>
<?php
foreach (AIOWPSecurity_Audit_Events::$log_levels as $level) {
$selected = isset($this->_args['data']['level-filter']) && $this->_args['data']['level-filter'] == $level ? ' selected = "selected"' : '';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- No user input to escape.
echo '<option value="'. esc_attr($level) .'" '. $selected .'>'. esc_html($level) .'</option>';
}
?>
</select>
<select name="event-filter" class="audit-filter-event">
<?php $selected = !isset($this->_args['data']['event-filter']) ? ' selected = "selected"' : ''; ?>
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- No user input to escape. ?>
<option value="-1" <?php echo $selected; ?>><?php esc_html_e('All events', 'all-in-one-wp-security-and-firewall'); ?></option>
<?php
foreach (AIOWPSecurity_Audit_Events::$event_types as $event_type => $event) {
$selected = isset($this->_args['data']['event-filter']) && $this->_args['data']['event-filter'] == $event_type ? ' selected = "selected"' : '';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- No user input to escape.
echo '<option value="'. esc_attr($event_type) .'" '. $selected .'>'. esc_html($event) .'</option>';
}
?>
</select>
<?php submit_button(esc_html__('Filter', 'all-in-one-wp-security-and-firewall'), 'action', '', false); ?>
</div>
<?php
break;
case 'bottom':
submit_button(esc_html__('Export to CSV', 'all-in-one-wp-security-and-firewall'), 'primary', 'aiowps_export_audit_event_logs_to_csv', false);
break;
}
}
/**
* This function will process the delete request for the audit event records
*
* @param integer|array $entries - an ID or array of IDs to be deleted
* @param boolean $delete_all - indicates if all entries should be deleted or not (if true, then $entries will be ignored)
*
* @return void|string
*/
public function delete_audit_event_records($entries, $delete_all = false) {
global $wpdb, $aio_wp_security;
$audit_log_tbl = AIOWPSEC_TBL_AUDIT_LOG;
$result = false;
if ($delete_all) {
// Delete all records
$site_id_where_sql = (!is_super_admin()) ? ' WHERE site_id = ' . get_current_blog_id() : '';
$delete_command = "DELETE FROM " . $audit_log_tbl . $site_id_where_sql;
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($delete_command);
} elseif (is_array($entries)) {
// Delete multiple records
$entries = array_map('esc_sql', $entries); // Escape every array element
$entries = array_filter($entries, 'is_numeric'); // Discard non-numeric ID values
$chunks = array_chunk($entries, 1000);
$site_id_where_sql = (!is_super_admin()) ? ' AND site_id = ' . get_current_blog_id() : '';
// Processing each chunk
foreach ($chunks as $chunk) {
$id_list = "(" . implode(",", $chunk) . ")"; // Create comma separate list for DB operation
$delete_command = "DELETE FROM " . $audit_log_tbl . " WHERE id IN " . $id_list . $site_id_where_sql;
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($delete_command);
if (!$result) {
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Audit log table. Database error: '.$wpdb->last_error, 4);
AIOS_Helper::set_message('aios_list_message', __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'), 'error');
return;
}
}
} elseif (!empty($entries)) {
// Delete single record
$site_id_where_sql = (!is_super_admin()) ? ' AND site_id = ' . get_current_blog_id() : '';
$delete_command = "DELETE FROM " . $audit_log_tbl . " WHERE id = '" . absint($entries) . "'" . $site_id_where_sql;
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($delete_command);
}
if ($result || 0 < $result) {
$aios_list_message = __('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall');
AIOS_Helper::set_message('aios_list_message', $aios_list_message);
} else {
$aios_list_message = __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall');
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Audit log table. Database error: '.$wpdb->last_error, 4);
AIOS_Helper::set_message('aios_list_message', $aios_list_message, 'error');
}
return $aios_list_message;
}
/**
* This function will build and return the SQL WHERE statement
*
* @param string $search_term - the search term applied
* @param array $filters - the filters applied
*
* @return string - the SQL WHERE statement
*/
private function get_audit_list_where_sql($search_term, $filters) {
$where_sql = '';
if ('' == $search_term) {
$where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id() : '';
$extra_where = '';
if (!empty($filters)) {
$where_sql = empty($where_sql) ? 'WHERE ' : $where_sql . ' AND ';
foreach ($filters as $filter => $value) {
if (!empty($extra_where)) $extra_where .= ' AND ';
$extra_where .= "`{$filter}` = '".esc_sql($value)."'";
}
}
$where_sql .= $extra_where;
} else {
$where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id().' AND ' : 'WHERE ';
$extra_where = '';
if (!empty($filters)) {
foreach ($filters as $filter => $value) {
if (!empty($extra_where)) $extra_where .= ' AND ';
$extra_where .= "`{$filter}` = '".esc_sql($value)."'";
}
$where_sql .= $extra_where . ' AND (';
$extra_where = '';
}
// We don't use FILTER_VALIDATE_IP here as we want to be able to search for partial IP's
if (preg_match('/^[0-9a-f:\.]+$/i', $search_term)) {
$extra_where .= "`ip` LIKE '".esc_sql($search_term)."%'";
}
if (in_array($search_term, AIOWPSecurity_Audit_Events::$log_levels) && !isset($filters['level'])) {
if (!empty($extra_where)) $extra_where .= ' OR ';
$extra_where .= "`level` = '".esc_sql($search_term)."'";
}
if (!empty($extra_where)) $extra_where .= ' OR ';
if (isset($filters['event_type'])) {
$extra_where .= "`username` LIKE '".esc_sql($search_term)."%'";
} else {
$extra_where .= "(`username` LIKE '".esc_sql($search_term)."%' or `event_type` LIKE '%".esc_sql($search_term)."%')";
}
if (!empty($filters)) $extra_where .= ')';
$where_sql .= $extra_where;
}
return $where_sql;
}
/**
* Grabs the data from database and handles the pagination
*
* @param boolean $ignore_pagination - whether to not paginate
*
* @return void
*/
public function prepare_items($ignore_pagination = false) {
/**
* First, lets decide how many records per page to show
*/
$no_action = -1;
$per_page = defined('AIOWPSEC_AUDIT_LOG_PER_PAGE') ? absint(AIOWPSEC_AUDIT_LOG_PER_PAGE) : 100;
$per_page = empty($per_page) ? 100 : $per_page;
$current_page = $this->get_pagenum();
$offset = (!$ignore_pagination && $per_page > 0) ? ($current_page - 1) * $per_page : 0;
$columns = $this->get_columns();
$hidden = array('id'); // we really don't need the IDs of the log entries displayed
if (!is_multisite()) {
$hidden[] = 'network_id';
$hidden[] = 'site_id';
}
$sortable = $this->get_sortable_columns();
$filters = array();
if (isset($this->_args['data']['level-filter']) && $no_action != $this->_args['data']['level-filter']) $filters['level'] = sanitize_text_field($this->_args['data']['level-filter']);
if (isset($this->_args['data']['event-filter']) && $no_action != $this->_args['data']['event-filter']) $filters['event_type'] = sanitize_text_field($this->_args['data']['event-filter']);
$search_term = isset($this->_args['data']['s']) ? sanitize_text_field(stripslashes($this->_args['data']['s'])) : '';
$this->_column_headers = array($columns, $hidden, $sortable);
$items = array();
if (isset($this->_args['data']['items'])) {
if (is_array($this->_args['data']['items'])) {
foreach ($this->_args['data']['items'] as $item) {
$sanitized_item = sanitize_text_field($item);
$items[] = $sanitized_item;
}
} else {
$sanitized_item = sanitize_text_field($this->_args['data']['items']);
$items[] = $sanitized_item;
}
} else {
$items = null;
}
if (isset($this->_args['data']['action'])) $action = sanitize_text_field($this->_args['data']['action']);
else $action = $no_action;
if (isset($action) && $no_action !== $action) {
$this->process_bulk_action($search_term, $filters, $action, $items);
}
global $wpdb;
$audit_log_tbl = AIOWPSEC_TBL_AUDIT_LOG;
// Parameters that are going to be used to order the result
isset($this->_args['data']["orderby"]) ? $orderby = wp_strip_all_tags($this->_args['data']["orderby"]) : $orderby = '';
isset($this->_args['data']["order"]) ? $order = wp_strip_all_tags($this->_args['data']["order"]) : $order = '';
// By default show the most recent audit log entries.
$orderby = !empty($orderby) ? esc_sql($orderby) : 'created';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
$orderby = sanitize_sql_orderby($orderby);
$order = sanitize_sql_orderby($order);
$where_sql = $this->get_audit_list_where_sql($search_term, $filters);
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$audit_log_tbl} {$where_sql}");
if ($ignore_pagination) {
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$audit_log_tbl} {$where_sql} ORDER BY {$orderby} {$order}", 'ARRAY_A');
} else {
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$audit_log_tbl} {$where_sql} ORDER BY {$orderby} {$order} LIMIT {$per_page} OFFSET {$offset}", 'ARRAY_A');
}
// Filter the 'details' section
foreach ($data as $key => $entry) {
$details = json_decode($entry['details'], true);
$details = is_null($details) ? $entry['details'] : $details; // check if the decode worked, if not pass the json string
$data[$key]['details'] = wp_json_encode(apply_filters('aios_audit_filter_details', $details, $entry['event_type']));
}
$this->items = $data;
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, // We have to calculate the total number of items
'per_page' => $per_page, // We have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) // We have to calculate the total number of pages
));
}
}
@@ -0,0 +1,221 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Comment_Spammer_IP extends AIOWPSecurity_List_Table {
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'item', // singular name of the listed records
'plural' => 'items', // plural name of the listed records
'ajax' => false // does this table support ajax?
));
}
public function column_default($item, $column_name) {
return $item[$column_name];
}
public function column_comment_author_IP($item) {
//Build row actions
if (!is_main_site() || 'blocked' === $item['status']) {
//Suppress the block link if site is a multi site AND not the main site or the status is blocked
$actions = array(); //blank array
} else {
//Add IP to block URL
$ip = $item['comment_author_IP'];
$actions = array(
'block' => '<a class="aios-block-author-ip" data-ip="'.esc_attr($ip).'" data-message="'.esc_js(__('Are you sure you want to permanently block this IP address?', 'all-in-one-wp-security-and-firewall')).'" href="">'.__('Block', 'all-in-one-wp-security-and-firewall').'</a>',
);
}
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/*$1%s*/ $item['comment_author_IP'],
/*$2%s*/ $this->row_actions($actions)
);
}
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
/*$2%s*/ esc_attr($item['comment_author_IP']) //The value of the checkbox should be the record's id
);
}
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox" />', //Render a checkbox
'comment_author_IP' => __('Spammer IP', 'all-in-one-wp-security-and-firewall'),
'amount' => __('Number of spam comments from this IP', 'all-in-one-wp-security-and-firewall'),
'status' => __('Status', 'all-in-one-wp-security-and-firewall'),
);
return $columns;
}
public function get_sortable_columns() {
$sortable_columns = array(
'comment_author_IP' => array('comment_author_IP',false),
'amount' => array('amount',false),
'status' => array('status',false),
);
return $sortable_columns;
}
public function get_bulk_actions() {
if (!is_main_site()) {
//Suppress the block link if site is a multi site AND not the main site
$actions = array(); //blank array
} else {
$actions = array(
'block' => __('Block', 'all-in-one-wp-security-and-firewall')
);
}
return $actions;
}
/**
* This function handles bulk actions on the table
*
* @return void
*/
private function process_bulk_action() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This IS the nonce check.
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput -- This IS the nonce check.
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
if (is_wp_error($result)) return;
if ('block' === $this->current_action()) {
//Process block bulk actions
if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce already checked above.
$error_msg = '<div id="message" class="error"><p><strong>';
$error_msg .= esc_html__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall');
$error_msg .= '</strong></p></div>';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP error. Output already escaped.
echo $error_msg;
} else {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce already checked above.
$this->block_spammer_ip_records((filter_var(wp_unslash($_REQUEST['item']), FILTER_VALIDATE_IP)));
}
}
}
/**
* This function will add the selected IP addresses to the blacklist.
*
* @param int|array $entries - either an array of IDs or a single ID of ip to be blocked
*
* @return void
*/
public function block_spammer_ip_records($entries) {
if (is_array($entries)) {
$entries = array_map('esc_sql', $entries); // Escape every array element
//Bulk selection using checkboxes were used
foreach ($entries as $ip_add) {
AIOWPSecurity_Blocking::add_ip_to_block_list($ip_add, 'spam');
}
}
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP addresses are now permanently blocked.', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function prepare the items rendered on the table
*
* @return void
*/
public function prepare_items() {
//First, lets decide how many records per page to show
$per_page = 100;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
$this->process_bulk_action();
global $wpdb;
global $aio_wp_security;
$minimum_comments_per_ip = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments');
if (empty($minimum_comments_per_ip)) {
$minimum_comments_per_ip = 5;
}
// Ordering parameters
//Parameters that are going to be used to order the result
isset($_GET["orderby"]) ? $orderby = wp_strip_all_tags(wp_unslash($_GET["orderby"])) : $orderby = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check.
isset($_GET["order"]) ? $order = wp_strip_all_tags(wp_unslash($_GET["order"])) : $order = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce to check.
$orderby = !empty($orderby) ? esc_sql($orderby) : 'amount';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
// status is not a key in the database so we don't want to sort the database results, but sort the array later
if ('status' == $orderby) {
$sql = $wpdb->prepare("SELECT comment_author_IP, COUNT(*) AS amount
FROM $wpdb->comments
WHERE comment_approved = 'spam'
GROUP BY comment_author_IP
HAVING amount >= %d
", $minimum_comments_per_ip);
} else {
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby cannot be prepared.
$sql = $wpdb->prepare("SELECT comment_author_IP, COUNT(*) AS amount
FROM $wpdb->comments
WHERE comment_approved = 'spam'
GROUP BY comment_author_IP
HAVING amount >= %d
ORDER BY $orderby $order
", $minimum_comments_per_ip);
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby cannot be prepared.
}
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- Preparing done in conditional above.
$data = $wpdb->get_results($sql, ARRAY_A);
// Get all permanently blocked IP addresses
$block_list = AIOWPSecurity_Blocking::get_list_blocked_ips();
foreach ($data as $key => $value) {
if (in_array($value['comment_author_IP'], $block_list)) {
$data[$key]['status'] = 'blocked';
} else {
$data[$key]['status'] = 'not blocked';
}
}
if ('status' == $orderby) {
$keys = array_column($data, 'status');
if ('asc' == $order) {
array_multisort($keys, SORT_ASC, SORT_STRING, $data);
} else {
array_multisort($keys, SORT_DESC, SORT_STRING, $data);
}
}
$current_page = $this->get_pagenum();
$total_items = count($data);
$data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
$this->items = $data;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
));
}
}
@@ -0,0 +1,149 @@
<?php
if (!defined('ABSPATH')) {
exit;//Exit if accessed directly
}
class AIOWPSecurity_List_Debug_Log extends AIOWPSecurity_List_Table {
/**
* Sets up some table attributes (i.e: the plurals and whether it's ajax or not)
*/
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'entry', //singular name of the listed records
'plural' => 'entries', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
/**
* Returns logtime column in datetime format as per user setting time zone.
*
* @param array $item - data for the columns on the current row
*
* @return string - the datetime
*/
public function column_logtime($item) {
return AIOWPSecurity_Utility::convert_timestamp($item['logtime']);
}
/**
* This function renders a default column item
*
* @param array $item - Item object
* @param string $column_name - Column name to be rendered from item object
*
* @return mixed - data to be rendered for column
*/
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Sets the columns for the table
*
* @return array
*/
public function get_columns() {
return array(
'logtime' => __('Date and time', 'all-in-one-wp-security-and-firewall'),
'level' => __('Level', 'all-in-one-wp-security-and-firewall'),
'network_id' => __('Network ID', 'all-in-one-wp-security-and-firewall'),
'site_id' => __('Site ID', 'all-in-one-wp-security-and-firewall'),
'message' => __('Message', 'all-in-one-wp-security-and-firewall'),
'type' => __('Type', 'all-in-one-wp-security-and-firewall')
);
}
/**
* Sets which of the columns the table data can be sorted by
*
* @return array
*/
public function get_sortable_columns() {
return array(
'logtime' => array('logtime', false),
'level' => array('level', false),
'network_id' => array('network_id', false),
'site_id' => array('site_id', false),
'message'=>array('message', false),
'type' => array('type', false)
);
}
/**
* Grabs the data from database and handles the pagination
*
* @param boolean $ignore_pagination - whether to not paginate
*
* @return void
*/
public function prepare_items($ignore_pagination = false) {
/**
* First, lets decide how many records per page to show
*/
if (defined('AIOWPSEC_DEBUG_LOG_PER_PAGE')) {
$per_page = absint(AIOWPSEC_DEBUG_LOG_PER_PAGE);
}
$per_page = empty($per_page) ? 15 : $per_page;
$current_page = $this->get_pagenum();
$offset = ($current_page - 1) * $per_page;
$columns = $this->get_columns();
$hidden = array('id'); // we really don't need the IDs of the log entries displayed
if (!is_multisite()) {
$hidden[] = 'network_id';
$hidden[] = 'site_id';
}
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
global $wpdb;
$debug_log_tbl = AIOWPSEC_TBL_DEBUG_LOG;
/* -- Ordering parameters -- */
//Parameters that are going to be used to order the result
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
isset($_GET["orderby"]) ? $orderby = sanitize_text_field(wp_unslash($_GET["orderby"])) : $orderby = '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
isset($_GET["order"]) ? $order = sanitize_text_field(wp_unslash($_GET["order"])) : $order = '';
// By default show the most recent debug log entries.
$orderby = !empty($orderby) ? esc_sql($orderby) : 'logtime';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
$orderby = sanitize_sql_orderby($orderby);
$order = sanitize_sql_orderby($order);
$where_sql = (!is_super_admin()) ? 'WHERE site_id = '.get_current_blog_id() : '';
if ($ignore_pagination) {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$debug_log_tbl}$where_sql ORDER BY $orderby $order", 'ARRAY_A');
} else {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$debug_log_tbl} $where_sql ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
}
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$debug_log_tbl} $where_sql");
$this->items = $data;
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
));
}
}
@@ -0,0 +1,318 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Locked_IP extends AIOWPSecurity_List_Table {
public function __construct() {
// Set parent defaults
parent::__construct(array(
'singular' => 'item', //singular name of the listed records
'plural' => 'items', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
/**
* Returns created column in datetime format as per user setting time zone.
*
* @param array $item - data for the columns on the current row
*
* @return string - the datetime
*/
public function column_created($item) {
return AIOWPSecurity_Utility::convert_timestamp($item['created']);
}
/**
* Returns released column in datetime format as per user setting time zone.
*
* @param array $item - data for the columns on the current row
*
* @return string - the datetime
*/
public function column_released($item) {
return AIOWPSecurity_Utility::convert_timestamp($item['released']);
}
/**
* This function renders a column
*
* @param array $item - Item object
* @param string $column_name - Column name to be rendered from item object
*
* @return string - data to be rendered for column_name
*/
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Function to populate the locked ip actions column in the table
*
* @param array $item - Contains the current item data
*
* @return string
*/
public function column_failed_login_ip($item) {
$actions = array(
'unlock' => '<a href="" data-ip="'.esc_attr($item['failed_login_ip']).'" data-message="'.esc_js(__('Are you sure you want to unlock this address range?', 'all-in-one-wp-security-and-firewall')).'" class="aios-unlock-ip-button">'.esc_html__('Unlock', 'all-in-one-wp-security-and-firewall').'</a>',
'delete' => '<a href="" data-id="'.esc_attr($item['id']).'" data-message="'.esc_js(__('Are you sure you want to delete this item?', 'all-in-one-wp-security-and-firewall')).'" class="aios-delete-locked-ip-record">'.esc_html__('Delete', 'all-in-one-wp-security-and-firewall').'</a>',
);
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/*$1%s*/ $item['failed_login_ip'],
/*$2%s*/ $this->row_actions($actions)
);
}
/**
* This function renders the checkbox column
*
* @param array $item - item object
*
* @return string
*/
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
/*$2%s*/ $item['id'] //The value of the checkbox should be the record's id
);
}
/**
* Returns ip_lookup_result column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_ip_lookup_result($item) {
if (empty($item['ip_lookup_result'])) return __('There is no IP lookup result available.', 'all-in-one-wp-security-and-firewall');
$ip_lookup_result = json_decode($item['ip_lookup_result'], true);
// check that the json decode worked
if (null === $ip_lookup_result) return __('There is no IP lookup result available.', 'all-in-one-wp-security-and-firewall');
foreach ($ip_lookup_result as $key => $value) {
$ip_lookup_result[$key] = empty($value) ? __('Not Found', 'all-in-one-wp-security-and-firewall') : $value;
}
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- PCP warning. Part of error reporting system.
$ip_lookup_result = print_r($ip_lookup_result, true);
$output = sprintf('<a href="#TB_inline?&inlineId=trace-%s" title="%s" class="thickbox">%s</a>', esc_attr($item['id']), esc_html__('IP lookup result', 'all-in-one-wp-security-and-firewall'), esc_html__('Show result', 'all-in-one-wp-security-and-firewall'));
$output .= sprintf('<div id="trace-%s" style="display: none"><pre>%s</pre></div>', esc_attr($item['id']), esc_html($ip_lookup_result));
return $output;
}
/**
* Sets the columns for the table
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />', //Render a checkbox
'failed_login_ip' => __('Locked IP/range', 'all-in-one-wp-security-and-firewall'),
'user_id' => __('User ID', 'all-in-one-wp-security-and-firewall'),
'user_login' => __('Username', 'all-in-one-wp-security-and-firewall'),
'lock_reason' => __('Reason', 'all-in-one-wp-security-and-firewall'),
'created' => __('Date locked', 'all-in-one-wp-security-and-firewall'),
'released' => __('Release date', 'all-in-one-wp-security-and-firewall'),
'ip_lookup_result' => __('IP lookup result', 'all-in-one-wp-security-and-firewall')
);
}
/**
* This function returns sortable columns
*
* @return array[]
*/
public function get_sortable_columns() {
return array(
'failed_login_ip' => array('failed_login_ip',false),
'user_id' => array('user_id',false),
'user_login' => array('user_login',false),
'lock_reason' => array('lock_reason',false),
'created' => array('created',false),
'released' => array('released',false)
);
}
/**
* This returns the bulk actions for the table
*
* @return array
*/
public function get_bulk_actions() {
return array(
'unlock' => __('Unlock', 'all-in-one-wp-security-and-firewall'),
'delete' => __('Delete', 'all-in-one-wp-security-and-firewall'),
);
}
/**
* Process bulk actions.
*
* @return void
*/
private function process_bulk_action() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. This is the nonce.
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
if (is_wp_error($result)) return;
if ('delete' == $this->current_action()) { // Process delete bulk actions
if (!isset($_REQUEST['item'])) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Sanitized later.
$this->delete_lockout_records(wp_unslash($_REQUEST['item']));
}
}
if ('unlock' == $this->current_action()) { //Process unlock bulk actions
if (!isset($_REQUEST['item'])) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Sanitized later.
$this->unlock_ips((wp_unslash($_REQUEST['item'])));
}
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. This is the nonce.
}
/**
* Unlocks multiple IP addresses by modifying the released column of records in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
*
* @param array $entries IDs that correspond to IP addresses in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
*
* @return void
*/
public function unlock_ips($entries) {
global $wpdb;
$lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
// Unlock multiple records
$entries = array_filter($entries, 'is_numeric'); // Discard non-numeric ID values
$id_list = '(' .implode(',', $entries) .')'; // Create comma separate list for DB operation
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$result = $wpdb->query("UPDATE $lockout_table SET `released` = UNIX_TIMESTAMP() WHERE `id` IN $id_list");
if (null != $result) {
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected IP entries were unlocked successfully.', 'all-in-one-wp-security-and-firewall'));
}
}
/**
* Deletes one or more records from the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
*
* @param array|string|integer $entries - ids or a single id
*
* @return void|string
*/
public function delete_lockout_records($entries) {
global $wpdb, $aio_wp_security;
$lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
if (is_array($entries)) {
// Delete multiple records
$entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
$id_list = "(" .implode(",", $entries) .")"; //Create comma separate list for DB operation
$delete_command = "DELETE FROM ".$lockout_table." WHERE id IN ".$id_list;
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($delete_command);
if ($result) {
AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
} else {
// Error on bulk delete
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from login lockout table. Database error: '.$wpdb->last_error, 4);
AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
}
} elseif (null != $entries) {
// Delete single record
$delete_command = "DELETE FROM ".$lockout_table." WHERE id = '".absint($entries)."'";
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($delete_command);
if ($result) {
return AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st(true);
} elseif (false === $result) {
// Error on single delete
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from login lockout table. Database error: '.$wpdb->last_error, 4);
return AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st(true);
}
}
}
/**
* Retrieves all items from AIOWPSEC_TBL_LOGIN_LOCKOUT. It may paginate and then assigns to $this->items.
*
* @param Boolean $ignore_pagination - whether to not paginate
*
* @return Void
*/
public function prepare_items($ignore_pagination = false) {
global $wpdb;
$lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
$this->process_bulk_action();
// How many records per page to show
$per_page = 100;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
// Parameters that are going to be used to order the result
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
$orderby = !empty($orderby) ? esc_sql($orderby) : 'created';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
$current_page = $this->get_pagenum();
$offset = ($current_page - 1) * $per_page;
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP()");
if ($ignore_pagination) {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() ORDER BY {$orderby} {$order}", 'ARRAY_A');
} else {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() ORDER BY {$orderby} {$order} LIMIT {$per_page} OFFSET {$offset}", 'ARRAY_A');
}
$this->items = $data;
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, // WE have to calculate the total number of items
'per_page' => $per_page, // WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) // WE have to calculate the total number of pages
));
}
}
@@ -0,0 +1,260 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Logged_In_Users extends AIOWPSecurity_List_Table {
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'item', //singular name of the listed records
'plural' => 'items', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Returns user id column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_user_id($item) {
//Build row actions
$actions = array(
'logout' => '<a class="aios-force-logout-user" data-user-id="'.esc_attr($item['user_id']).'" data-message="'.esc_js(__('Are you sure you want to force this user to be logged out of this session?', 'all-in-one-wp-security-and-firewall')).'" href="">'.__('Force logout', 'all-in-one-wp-security-and-firewall').'</a>',
);
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/*$1%s*/ $item['user_id'],
/*$2%s*/ $this->row_actions($actions)
);
}
/**
* Sets the columns for the table
*
* @return array
*/
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox">',
'user_id' => __('User ID', 'all-in-one-wp-security-and-firewall'),
'username' => __('Login name', 'all-in-one-wp-security-and-firewall'),
'ip_address' => __('IP address', 'all-in-one-wp-security-and-firewall'),
'site_id' => __('Site ID', 'all-in-one-wp-security-and-firewall'),
);
return $columns;
}
/**
* Returns cb column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/* $1%s */ $this->_args['singular'], // Let's simply repurpose the table's singular label
/* $2%s */ $item['user_id'] // The value of the checkbox should be the record's id and its ip address
);
}
/**
* Sets which of the columns the table data can be sorted by
*
* @return array
*/
public function get_sortable_columns() {
return array(
'user_id' => array('user_id',false),
'username' => array('username',false),
'ip_address' => array('ip_address',false),
'site_id' => array('site_id',false),
);
}
/**
* Adds a bulk action user interface
*
* @return array
*/
public function get_bulk_actions() {
return array(
'force_logout_all' => __('Logout all', 'all-in-one-wp-security-and-firewall'),
'force_logout_selected' => __('Logout selected', 'all-in-one-wp-security-and-firewall'),
);
}
/**
* Process Bulk action from menu
*
* @return void
*/
private function process_bulk_action() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce used.
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
if (is_wp_error($result)) return;
if ('force_logout_all' === $this->current_action()) {
$this->force_user_logout(array(), true);
} elseif ('force_logout_selected' === $this->current_action()) {
if (isset($_REQUEST['item'])) {
if (is_array($_REQUEST['item'])) $this->force_user_logout(wp_unslash($_REQUEST['item']));
}
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. Nonce used.
}
/**
* This function will force selected user(s) to be logged out.
*
* @param int|array $users - id of selected user or array of user ids to be logged out
* @param bool $logout_all - Boolean to show if all users should be logged out
*
* @return void|string
*/
public function force_user_logout($users, $logout_all = false) {
global $wpdb, $aio_wp_security;
$logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
if ($logout_all) {
// get all user_id(except for the admin) in the table and make it an array for users
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$users = $wpdb->get_col("SELECT user_id FROM $logged_in_users_table");
}
if (is_array($users)) {
if (empty($users)) {
AIOWPSecurity_Admin_Menu::show_msg_record_not_deleted_st();
return;
}
$errors = 0;
// Escape the user IDs for security
$users = array_map('esc_sql', $users);
foreach ($users as $user_id) {
if (is_numeric($user_id) && !is_super_admin($user_id) && AIOWPSecurity_Utility::is_user_member_of_blog($user_id)) {
if ($aio_wp_security->user_login_obj->delete_logged_in_user($user_id)) {
$this->logout_user($user_id);
continue;
}
}
$errors++;
}
if ($errors > 0) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__("Some users were not logged out due to the ID being invalid, or them being a super admin or a member of a different subsite on a multisite", 'all-in-one-wp-security-and-firewall'));
return;
}
AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st();
}
}
/**
* This function handles logging out a user using user_id
*
* @param int $user_id - id of user being logged out
*
* @return void
*/
public function logout_user($user_id) {
$user_id = absint($user_id);
$manager = WP_Session_Tokens::get_instance($user_id);
$manager->destroy_all();
}
/**
* Prepares the items for the logged in users table
*
* @param bool $ignore_pagination - this is to check if data should be paginated or not
*
* @return void
*/
public function prepare_items($ignore_pagination = false) {
global $wpdb;
//First, lets decide how many records per page to show
$per_page = 100;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
$current_page = $this->get_pagenum();
$offset = ($current_page - 1) * $per_page;
// Parameters that are going to be used to order the result
// phpcs:disable -- Rule won't be silenced any other way. No nonce.
$orderby = isset($_GET["orderby"]) ? sanitize_text_field(wp_unslash($_GET["orderby"])) : '';
$order = isset($_GET["order"]) ? sanitize_text_field(wp_unslash($_GET["order"])) : '';
// phpcs:enable -- Rule won't be silenced any other way. No nonce.
// By default show the most recent logged in user entries.
$orderby = empty($orderby) ? 'created' : esc_sql($orderby);
$order = empty($order) ? 'DESC' : esc_sql($order);
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
$orderby = sanitize_sql_orderby($orderby);
$order = sanitize_sql_orderby($order);
$this->_column_headers = array($columns, $hidden, $sortable);
$this->process_bulk_action(); // Process bulk actions
$where_sql = $this->get_where_sql();
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$total_items = $wpdb->get_var("SELECT COUNT(*) FROM `{$logged_in_users_table}` $where_sql");
if ($ignore_pagination) {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM `{$logged_in_users_table}` $where_sql ORDER BY $orderby $order", 'ARRAY_A');
} else {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM `{$logged_in_users_table}` $where_sql ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
}
$this->items = $data;
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
));
}
/**
* This function will build and return the SQL WHERE statement
*
* @return string - the SQL WHERE statement
*/
private function get_where_sql() {
if (is_main_site() && is_super_admin()) return '';
return is_multisite() ? sprintf("WHERE site_id = %d", get_current_blog_id()) : '';
}
}
@@ -0,0 +1,238 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Blocked_IP extends AIOWPSecurity_List_Table {
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'item', //singular name of the listed records
'plural' => 'items', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
/**
* Returns created column in datetime format as per user setting time zone.
*
* @param array $item - data for the columns on the current row
*
* @return string - the datetime
*/
public function column_created($item) {
return AIOWPSecurity_Utility::convert_timestamp($item['created']);
}
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Function to populate the permanent blocked ip actions column in the table
*
* @param array $item - Contains the current item data
*
* @return string
*/
public function column_id($item) {
$actions = array(
'unblock' => '<a href="" class="aios-unblock-permanent-ip" data-id="'.esc_attr($item['id']).'" data-message="'.esc_js(__('Are you sure you want to unblock this IP address?', 'all-in-one-wp-security-and-firewall')).'">Unblock</a>',
);
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/*$1%s*/
$item['id'],
/*$2%s*/
$this->row_actions($actions)
);
}
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/*$1%s*/
$this->_args['singular'], //Let's simply repurpose the table's singular label
/*$2%s*/
$item['id'] //The value of the checkbox should be the record's id
);
}
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />', //Render a checkbox
'id' => 'ID',
'blocked_ip' => __('Blocked IP', 'all-in-one-wp-security-and-firewall'),
'block_reason' => __('Reason', 'all-in-one-wp-security-and-firewall'),
'created' => __('Date and Time', 'all-in-one-wp-security-and-firewall')
);
}
public function get_sortable_columns() {
return array(
'id' => array('id', false),
'blocked_ip' => array('blocked_ip', false),
'block_reason' => array('block_reason', false),
'created' => array('created', false)
);
}
public function get_bulk_actions() {
return array(
'unblock' => __('Unblock', 'all-in-one-wp-security-and-firewall')
);
}
private function process_bulk_action() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- PCP warning. It IS the nonce. Ignore.
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return;
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- PCP warning. Ignore.
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_REQUEST['_wpnonce'], 'bulk-items');
if (is_wp_error($result)) return;
if ('unblock' === $this->current_action()) { // Process unlock bulk actions
if (!isset($_REQUEST['item'])) {
AIOS_Helper::set_message('aios_list_message', __('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'), 'error');
} else {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitized later
$this->unblock_ip_address(wp_unslash($_REQUEST['item']));
}
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. It IS the nonce. Ignore.
}
/**
* Deletes one or more records from the AIOWPSEC_TBL_PERM_BLOCK table.
*
* @param array|string|integer $entries - ids or a single id
*
* @return void|string
*/
public function unblock_ip_address($entries) {
global $wpdb, $aio_wp_security;
if (is_array($entries)) {
// multiple records
$entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values
$id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation
$delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id IN " . $id_list; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $id_list cannot be prepared.
$result = $wpdb->query($delete_command);
if ($result) {
AIOS_Helper::set_message('aios_list_message', __('Successfully unblocked and deleted the selected record(s).', 'all-in-one-wp-security-and-firewall'));
} else {
// Error on bulk delete
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Perm Block table. Database error: '.$wpdb->last_error, 4);
AIOS_Helper::set_message('aios_list_message', __('Failed to unblock and delete the selected record(s).', 'all-in-one-wp-security-and-firewall'), 'error');
}
} elseif (!empty($entries)) {
//Delete single record
$delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id = %d";
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$result = $wpdb->query($wpdb->prepare($delete_command, absint($entries)));
if (false === $result) {
// Error on single delete
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Perm Block table. Database error: '.$wpdb->last_error, 4);
}
return $result;
}
}
/**
* This function will build and return the SQL WHERE statement
*
* @param string $search_term - the search term applied
*
* @return string - the SQL WHERE statement
*/
private function get_permanent_blocked_ip_list_where_sql($search_term) {
$where = '';
if (!empty($search_term)) {
$where = " WHERE";
// We don't use FILTER_VALIDATE_IP here as we want to be able to search for partial IP's
if (preg_match('/^[0-9a-f:\.]+$/i', $search_term)) {
$where .= " `blocked_ip` LIKE '%".esc_sql($search_term)."%' OR";
}
$where .= " `block_reason` LIKE '%".esc_sql($search_term)."%'";
$where .= " OR `country_origin` LIKE '%".esc_sql($search_term)."%'";
}
return $where;
}
/**
* Grabs the data from database and handles the pagination
*
* @param boolean $ignore_pagination - whether to not paginate
*
* @return void
*/
public function prepare_items($ignore_pagination = false) {
/**
* First, lets decide how many records per page to show
*/
$per_page = 100;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$search = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : '';
$this->_column_headers = array($columns, $hidden, $sortable);
$this->process_bulk_action();
global $wpdb;
$block_table_name = AIOWPSEC_TBL_PERM_BLOCK;
// Ordering parameters
// Parameters that are going to be used to order the result
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$orderby = isset($_GET["orderby"]) ? sanitize_text_field(wp_unslash($_GET["orderby"])) : '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$order = isset($_GET["order"]) ? sanitize_text_field(wp_unslash($_GET["order"])) : '';
$orderby = !empty($orderby) ? esc_sql($orderby) : 'id';
$order = !empty($order) ? esc_sql($order) : 'DESC';
$orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable);
$order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1'));
$current_page = $this->get_pagenum();
$offset = ($current_page - 1) * $per_page;
$search_query = $this->get_permanent_blocked_ip_list_where_sql($search);
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$total_items = $wpdb->get_var("SELECT COUNT(*) FROM {$block_table_name}{$search_query}");
if ($ignore_pagination) {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$block_table_name} {$search_query} ORDER BY $orderby$order", 'ARRAY_A');
} else {
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
$data = $wpdb->get_results("SELECT * FROM {$block_table_name}{$search_query} ORDER BY $orderby $order LIMIT $per_page OFFSET $offset", 'ARRAY_A');
}
$this->items = $data;
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
));
}
}
@@ -0,0 +1,355 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_List_Registered_Users extends AIOWPSecurity_List_Table {
public function __construct() {
//Set parent defaults
parent::__construct(array(
'singular' => 'item', //singular name of the listed records
'plural' => 'items', //plural name of the listed records
'ajax' => false //does this table support ajax?
));
}
public function column_default($item, $column_name) {
return $item[$column_name];
}
/**
* Returns ID column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_ID($item) {
//Build row actions
$actions = array(
'view' => '<a href="user-edit.php?user_id='.$item['ID'].'" target="_blank">'.__('View', 'all-in-one-wp-security-and-firewall').'</a>',
'approve_acct' => '<a class="aios-approve-user-acct" href="" data-id="'.esc_attr($item['ID']).'" data-message="'.esc_js(__('Are you sure you want to approve this account?', 'all-in-one-wp-security-and-firewall')).'">'. __('Approve', 'all-in-one-wp-security-and-firewall') . '</a>',
'delete_acct' => '<a class="aios-delete-user-acct" href="" data-id="'.esc_attr($item['ID']).'" data-message="'.esc_js(__('Are you sure you want to delete this account?', 'all-in-one-wp-security-and-firewall')).'">'. __('Delete', 'all-in-one-wp-security-and-firewall') . '</a>',
'block_ip' => '<a class="aios-block-ip" href="" data-ip="'.esc_attr($item['ip_address']).'" data-message="'.esc_js(__('Are you sure you want to block this IP address?', 'all-in-one-wp-security-and-firewall')).'">'. __('Block IP', 'all-in-one-wp-security-and-firewall') . '</a>',
);
//Return the user_login contents
return sprintf('%1$s <span style="color:silver"></span>%2$s',
/*$1%s*/ $item['ID'],
/*$2%s*/ $this->row_actions($actions)
);
}
/**
* Returns IP address column html to be rendered.
*
* @param array $item - data for the columns on the current row
*
* @return string - the html to be rendered
*/
public function column_ip_address($item) {
if (AIOWPSecurity_Blocking::is_ip_blocked($item['ip_address'])) {
return $item['ip_address'].'<br /><span class="aiowps-label aiowps-label-success">'.__('blocked', 'all-in-one-wp-security-and-firewall').'</span>';
} else {
return $item['ip_address'];
}
}
public function column_cb($item) {
return sprintf(
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
/*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label
/*$2%s*/ $item['ID'] //The value of the checkbox should be the record's id
);
}
/**
* Returns array of columns to be rendered.
*
* @return array
*/
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox">', // Render a checkbox
'ID' => __('User ID', 'all-in-one-wp-security-and-firewall'),
'user_login' => __('Login name', 'all-in-one-wp-security-and-firewall'),
'user_email' => __('Email', 'all-in-one-wp-security-and-firewall'),
'user_registered' => __('Register date', 'all-in-one-wp-security-and-firewall'),
'account_status' => __('Account status', 'all-in-one-wp-security-and-firewall'),
'ip_address' => __('IP address', 'all-in-one-wp-security-and-firewall')
);
return $columns;
}
public function get_sortable_columns() {
$sortable_columns = array(
// 'ID' => array('ID',false),
// 'user_login' => array('user_login',false),
// 'user_email' => array('user_email',false),
// 'user_registered' => array('user_registered',false),
// 'account_status' => array('account_status',false),
);
return $sortable_columns;
}
public function get_bulk_actions() {
$actions = array(
'approve' => __('Approve', 'all-in-one-wp-security-and-firewall'),
'delete' => __('Delete', 'all-in-one-wp-security-and-firewall'),
'block' => __('Block IP', 'all-in-one-wp-security-and-firewall')
);
return $actions;
}
/**
* Process bulk actions.
*
* @return void
*/
private function process_bulk_action() {
if (empty($_REQUEST['_wpnonce']) || !isset($_REQUEST['_wp_http_referer'])) return; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap(sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])), 'bulk-items'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
if (is_wp_error($result)) return;
if ('approve' == $this->current_action()) { //Process approve bulk actions
if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
$this->approve_selected_accounts(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
}
}
if ('delete' == $this->current_action()) { //Process delete bulk actions
if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
$this->delete_selected_accounts(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
}
}
if ('block' == $this->current_action()) { //Process block bulk actions
if (!isset($_REQUEST['item'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Please select some records using the checkboxes', 'all-in-one-wp-security-and-firewall'));
} else {
$this->block_selected_ips(array_map('sanitize_text_field', wp_unslash($_REQUEST['item']))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
}
}
}
/**
* This function approves selected user accounts
*
* @param array|int $entries - this is an array of users or user_id to be approved
*
* @return void|string
*/
public function approve_selected_accounts($entries) {
global $aio_wp_security;
$meta_key = 'aiowps_account_status';
$meta_value = 'approved'; // set account status
$failed_accts = ''; // string to store comma separated accounts which failed to update
$at_least_one_updated = false;
if (is_array($entries)) {
$entries = array_map('esc_sql', $entries); // Escape every array element
//Let's go through each entry and approve
foreach ($entries as $user_id) {
$result = update_user_meta($user_id, $meta_key, $meta_value);
if (false === $result) {
$failed_accts .= ' '.$user_id.', ';
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::approve_selected_accounts() - could not approve account ID: $user_id", 4);
} else {
$at_least_one_updated = true;
$user = get_user_by('id', $user_id);
if (false === $user) {
//don't send mail
} else {
$this->send_email_upon_account_activation($user);
}
}
}
if ($at_least_one_updated) {
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected accounts were approved successfully.', 'all-in-one-wp-security-and-firewall'));
}
if ('' != $failed_accts) {
//display any failed account updates
rtrim($failed_accts);
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('The following accounts failed to update successfully:', 'all-in-one-wp-security-and-firewall') . ' ' . $failed_accts);
}
}
}
/**
* This function sends an email to an approved user
*
* @param WP_User $user - the object for the approved user
*
* @return bool
*/
public function send_email_upon_account_activation($user) {
global $aio_wp_security;
if (!($user instanceof WP_User)) {
return false;
}
$to_email_address = $user->user_email;
$email_msg = '';
$subject = '['.network_site_url().'] '. __('Your account is now active', 'all-in-one-wp-security-and-firewall');
/* translators: %s: Username */
$email_msg .= sprintf(__('Your account with username: %s is now active', 'all-in-one-wp-security-and-firewall'), $user->user_login) . "\n";
$subject = apply_filters('aiowps_register_approval_email_subject', $subject);
$email_msg = apply_filters('aiowps_register_approval_email_msg', $email_msg, $user); //also pass the WP_User object
$sendMail = wp_mail($to_email_address, $subject, $email_msg);
if (false === $sendMail) {
$aio_wp_security->debug_logger->log_debug("Manual account approval notification email failed to send to " . $to_email_address, 4);
}
return $sendMail;
}
/**
* This function deletes selected entries pending approval
*
* @param array|int $entries - this is an array of users or single user to be deleted
*
* @return void|string
*/
public function delete_selected_accounts($entries) {
global $aio_wp_security;
if (is_array($entries)) {
$entries = array_map('esc_sql', $entries); // Escape every array element
//Let's go through each entry and delete account
foreach ($entries as $user_id) {
$result = wp_delete_user($user_id);
if (true !== $result) {
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::delete_selected_accounts() - could not delete account ID: $user_id", 4);
}
}
AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The selected accounts were deleted successfully.', 'all-in-one-wp-security-and-firewall'));
}
}
/**
* This function blocks selected ip
*
* @param array|int $entries - this is an array of ips or ip to be blocked
*
* @return void|string
*/
public function block_selected_ips($entries) {
global $aio_wp_security;
if (is_array($entries)) {
$entries = array_filter($entries, function ($entry) {
return AIOWPSecurity_Utility_IP::get_user_ip_address() != $entry;
});
if (empty($entries)) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('Only invalid IP addresses were provided: you can not block your own IP address', 'all-in-one-wp-security-and-firewall'));
return;
}
$entries = array_map('esc_sql', $entries); // Escape every array element
//Let's go through each entry and block IP
$total_success = 0;
foreach ($entries as $id) {
$ip_address = get_user_meta($id, 'aiowps_registrant_ip', true);
$result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip_address, 'registration_spam');
if (false === $result) {
if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip_address) {
AIOWPSecurity_Admin_Menu::show_msg_error_st(__('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip_address);
}
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::block_selected_ips() - could not block IP : $ip_address", 4);
} else {
$total_success++;
}
}
if ($total_success > 0) {
$msg = __('The selected IP addresses were successfully added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
$msg .= ' <a href="admin.php?page='.AIOWPSEC_MAIN_MENU_SLUG.'&tab=permanent-block" target="_blank">'.__('View Blocked IPs', 'all-in-one-wp-security-and-firewall').'</a>';
AIOWPSecurity_Admin_Menu::show_msg_updated_st($msg);
}
}
}
/**
* Grabs the data from database and handles the pagination
*
* @param boolean $ignore_pagination - whether to not paginate
* @return void
*/
public function prepare_items($ignore_pagination = false) {
//First, lets decide how many records per page to show
$per_page = 100;
$columns = $this->get_columns();
$current_page = $this->get_pagenum();
$offset = ($current_page - 1) * $per_page;
$hidden = array();
$sortable = $this->get_sortable_columns();
$search = isset($_REQUEST['s']) ? sanitize_text_field(wp_unslash($_REQUEST['s'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pcp check ingore this
$this->_column_headers = array($columns, $hidden, $sortable);
$this->process_bulk_action();
//Get registered users which have the special 'aiowps_account_status' meta key set to 'pending'
if ($ignore_pagination) {
$result = $this->get_registered_user_data('pending', $search);
} else {
$result = $this->get_registered_user_data('pending', $search, $per_page, $offset);
}
$total_items = $result['total'];
$this->items = $result['data'];
if ($ignore_pagination) return;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
));
}
/**
* Returns all users who have the special 'aiowps_account_status' meta key
*
* @param string $status - the status we want to search for
* @param string $search - the search query
* @param null $per_page - how many results per page
* @param int $offset - the page offset
*
* @return array - an array of users that match the search
*/
public function get_registered_user_data($status = '', $search = '', $per_page = null, $offset = 0) {
$user_fields = array( 'ID', 'user_login', 'user_email', 'user_registered');
$user_query = new WP_User_Query(array('meta_key' => 'aiowps_account_status', 'meta_value' => $status, 'fields' => $user_fields, 'number' => $per_page, 'offset' => $offset)); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- ignore this
$user_results = $user_query->results;
$user_total = $user_query->get_total();
$final_data = array();
foreach ($user_results as $user) {
$temp_array = get_object_vars($user); //Turn the object into array
$temp_array['account_status'] = get_user_meta($temp_array['ID'], 'aiowps_account_status', true);
$ip = get_user_meta($temp_array['ID'], 'aiowps_registrant_ip', true);
$temp_array['ip_address'] = empty($ip) ? '' : $ip;
if (empty($search)) {
$final_data[] = $temp_array;
} else {
$input = preg_quote($search, '~'); // don't forget to quote input string!
$result = preg_grep('~' . $input . '~', $temp_array);
if (!empty($result)) $final_data[] = $temp_array;
}
}
return array(
'data' => $final_data,
'total' => $user_total,
);
}
}
@@ -0,0 +1,90 @@
<?php
if (!defined('ABSPATH')) die('No direct access.');
if (!class_exists('AIOWPSecurity_Reset_Settings')) :
/**
* Reset Settings various methods
*/
class AIOWPSecurity_Reset_Settings {
/**
* Delete config option.
*
* @return boolean true if the aio_wp_security_configs option deleted successfully.
*/
public static function reset_options() {
$result_delete_option = false === get_option('aio_wp_security_configs', false) || delete_option('aio_wp_security_configs');
$result_reset_settings = AIOWPSecurity_Configure_Settings::set_default_settings();
return $result_delete_option && $result_reset_settings;
}
/**
* Delete htaccess rules.
*
* @param string $section - section used to find AIOS rules in .htaccess file
*
* @return boolean true if the aio_wp_security_configs option deleted successfully.
*/
public static function delete_htaccess($section = 'All In One WP Security') {
$htaccess = ABSPATH . '.htaccess';
if (!file_exists($htaccess)) {
return false;
}
// phpcs:disable WordPress.WP.AlternativeFunctions -- Cannot use wp_filesystem in the firewall.
$ht_contents = preg_split('/\r\n|\r|\n/', file_get_contents($htaccess));
if ($ht_contents) { // as long as there are lines in the file
$state = true;
$f = @fopen($htaccess, 'w+');
if (!$f) {
@chmod($htaccess, 0644);
$f = @fopen($htaccess, 'w+');
if (!$f) {
return false;
}
}
foreach ($ht_contents as $markerline) { // for each line in the file
if (strpos($markerline, '# BEGIN ' . $section) !== false) { // if we're at the beginning of the section
$state = false;
}
if (true == $state) { // as long as we're not in the section keep writing
fwrite($f, trim($markerline) . "\n");
}
if (strpos($markerline, '# END ' . $section) !== false) { // see if we're at the end of the section
$state = true;
}
}
@fclose($f);
return true;
}
// phpcs:enable WordPress.WP.AlternativeFunctions -- Cannot use wp_filesystem in the firewall.
return true;
}
/**
* Delete database tables
*
* @return boolean true
*/
public static function reset_db_tables() {
// Reset (TRUNCATE) all the db tables of the plugin.
global $wpdb;
$wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_login_lockdown');
$wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_global_meta');
$wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_events');
$wpdb->query('TRUNCATE ' . $wpdb->prefix . 'aiowps_permanent_block');
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Ignore.
if (is_main_site()) {
$wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_LOGGED_IN_USERS);
$wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_MESSAGE_STORE);
$wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_DEBUG_LOG);
$wpdb->query('TRUNCATE ' . AIOWPSEC_TBL_AUDIT_LOG);
}
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared -- PCP error. Ignore.
return true;
}
}
endif;
@@ -0,0 +1,157 @@
<?php
if (!defined('ABSPATH')) die('No direct access.');
/**
* AIOWPSecurity_Settings_Menu class for setting configs.
*
* @access public
*/
class AIOWPSecurity_Settings_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Settings menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_SETTINGS_MENU_SLUG;
/**
* Constructor adds menu for Settings
*/
public function __construct() {
parent::__construct(__('Settings', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
public function setup_menu_tabs() {
$menu_tabs = array(
'general-settings' => array(
'title' => __('General settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_general_settings'),
),
'htaccess-file-operations' => array(
'title' => '.htaccess '.__('file', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_htaccess_file_operations'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'wp-config-file-operations' => array(
'title' => 'wp-config.php '.__('file', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_wp_config_file_operations'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'delete-plugin-settings' => array(
'title' => __('Delete plugin settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_delete_plugin_settings_tab')
),
'wp-version-info' => array(
'title' => __('WP version info', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_wp_version_info'),
),
'settings-file-operations' => array(
'title' => __('Import/Export', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_settings_file_operations'),
),
'advanced-settings' => array(
'title' => __('Advanced settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_advanced_settings'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
);
$menu_tabs = apply_filters('aiowpsecurity_setting_tabs', $menu_tabs);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's general settings tab.
*
* @return void
*/
protected function render_general_settings() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/settings/general-settings.php', false, array());
}
/**
* Renders the submenu's htaccess file operations tab.
*
* @return void
*/
protected function render_htaccess_file_operations() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/settings/htaccess-file-operations.php', false, array());
}
/**
* Renders the submenu's wp config file operations tab.
*
* @return void
*/
protected function render_wp_config_file_operations() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/settings/wp-config-file-operations.php', false, array());
}
/**
* Renders the submenu's delete plugin settings tab.
*
* @return void
*/
protected function render_delete_plugin_settings_tab() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/settings/delete-plugin-settings.php', false, array());
}
/**
* Renders the submenu's wp version info tab.
*
* @return void
*/
protected function render_wp_version_info() {
global $aio_wp_security, $aiowps_feature_mgr;
$aio_wp_security->include_template('wp-admin/settings/wp-version-info.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
/**
* Renders the submenu's settings file operations tab.
*
* @return void
*/
protected function render_settings_file_operations() {
global $aio_wp_security;
$events_table_name = AIOWPSEC_TBL_EVENTS;
AIOWPSecurity_Utility::cleanup_table($events_table_name, 500);
$aio_wp_security->include_template('wp-admin/settings/settings-file-operations.php', false, array());
}
/**
* Renders advanced settings tab.
*
* @return void
*/
protected function render_advanced_settings() {
if (!is_main_site()) {
return;
}
global $aio_wp_security;
$aios_commands = new AIOWPSecurity_Commands();
$advanced_settings_data = $aios_commands->get_ip_address_detection_data();
$aio_wp_security->include_template('wp-admin/settings/advanced-settings.php', false, $advanced_settings_data);
}
}
@@ -0,0 +1,93 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Spam_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Spam menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_SPAM_MENU_SLUG;
/**
* Constructor adds menu for Spam prevention
*/
public function __construct() {
parent::__construct(__('Spam prevention', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'comment-spam' => array(
'title' => __('Comment spam', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_comment_spam'),
),
'comment-spam-ip-monitoring' => array(
'title' => __('Comment spam IP monitoring', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_comment_spam_ip_monitoring'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's comment spam ip monitoring tab body.
*
* @return Void
*/
protected function render_comment_spam() {
global $aiowps_feature_mgr, $aio_wp_security;
$aio_wp_security->include_template('wp-admin/spam-prevention/comment-spam.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
/**
* Renders the submenu's comment spam ip monitoring tab body.
*
* @return Void
*/
protected function render_comment_spam_ip_monitoring() {
global $aio_wp_security, $aiowps_feature_mgr, $wpdb;
include_once 'wp-security-list-comment-spammer-ip.php'; // For rendering the AIOWPSecurity_List_Table in tab2
$spammer_ip_list = new AIOWPSecurity_List_Comment_Spammer_IP();
$block_comments_output = '';
$min_block_comments = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
if (!empty($min_block_comments)) {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
$total_res = $wpdb->get_results($wpdb->prepare('SELECT * FROM '.AIOWPSEC_TBL_PERM_BLOCK.' WHERE block_reason=%s', 'spam'));
$block_comments_output = '<div class="aio_yellow_box">';
if (empty($total_res)) {
$block_comments_output .= '<p><strong>'.esc_html__('You currently have no IP addresses permanently blocked due to spam.', 'all-in-one-wp-security-and-firewall').'</strong></p></div>';
} else {
$total_count = count($total_res);
$todays_blocked_count = 0;
foreach ($total_res as $blocked_item) {
$now_date_time = new DateTime('now', new DateTimeZone('UTC'));
$blocked_date = new DateTime('@'.$blocked_item->created); //@ with timestamp creates correct DateTime
if ($blocked_date->format('Y-m-d') == $now_date_time->format('Y-m-d')) {
//there was an IP added to permanent block list today
++$todays_blocked_count;
}
}
$block_comments_output .= '<p><strong>'.esc_html__('Spammer IPs added to permanent block list today:', 'all-in-one-wp-security-and-firewall'). ' ' . esc_html($todays_blocked_count).'</strong></p>'.'<hr><p><strong>'.esc_html__('All time total:', 'all-in-one-wp-security-and-firewall'). ' ' .esc_html($total_count).'</strong></p>'.'<p><a class="button" href="admin.php?page='.esc_attr(AIOWPSEC_MAIN_MENU_SLUG).'&tab=permanent-block" target="_blank">'.esc_html__('View blocked IPs', 'all-in-one-wp-security-and-firewall').'</a></p></div>';
}
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$page = isset($_REQUEST['page']) ? sanitize_text_field(wp_unslash($_REQUEST['page'])) : '';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce.
$tab = isset($_REQUEST['tab']) ? sanitize_text_field(wp_unslash($_REQUEST['tab'])) : '';
$aio_wp_security->include_template('wp-admin/spam-prevention/comment-spam-ip-monitoring.php', false, array('spammer_ip_list' => $spammer_ip_list, 'aiowps_feature_mgr' => $aiowps_feature_mgr, 'block_comments_output' => $block_comments_output, 'page' => $page, 'tab' => $tab));
}
}
@@ -0,0 +1,98 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Tools_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Tools menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_TOOLS_MENU_SLUG;
/**
* Constructor adds menu for Tools
*/
public function __construct() {
parent::__construct(__('Tools', 'all-in-one-wp-security-and-firewall'));
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'password-tool' => array(
'title' => __('Password tool', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_password_tool'),
),
'whois-lookup' => array(
'title' => __('WHOIS lookup', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_whois_lookup_tab'),
),
'custom-rules' => array(
'title' => __('Custom .htaccess rules', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_custom_rules'),
'display_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess'),
),
'visitor-lockout' => array(
'title' => __('Visitor lockout', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_visitor_lockout'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Render the 'Custom (htaccess) rules' tab
*
* @return void
*/
protected function render_custom_rules() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/tools/custom-htaccess.php');
}
/**
* Renders the submenu's password tool tab
*
* @return Void
*/
protected function render_password_tool() {
global $aio_wp_security;
wp_enqueue_script('aiowpsec-pw-tool-js');
$aio_wp_security->include_template('wp-admin/tools/password-tool.php');
}
/**
* Renders the submenu's whois-lookup tab body.
*
* @return Void
*/
protected function render_whois_lookup_tab() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/tools/whois-lookup.php', false, array());
}
/**
* Renders the submenu's visitor lockout tab
*
* @return void
*/
protected function render_visitor_lockout() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/tools/visitor-lockout.php', false, array());
}
} // End of class
@@ -0,0 +1,296 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_User_Security_Menu extends AIOWPSecurity_Admin_Menu {
/**
* User Security menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_USER_SECURITY_MENU_SLUG;
/**
* Constructor adds menu for User Security
*/
public function __construct() {
parent::__construct(__('User Security', 'all-in-one-wp-security-and-firewall'));
}
/**
* Populates $menu_tabs array.
*
* @return Void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'wp-user_accounts' => array(
'title' => __('User accounts', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_wp_user_account'),
),
'login-lockout' => array(
'title' => __('Login lockout', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_login_lockout'),
),
'force-logout' => array(
'title' => __('Force logout', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_force_logout'),
),
'logged-in-users' => array(
'title' => __('Logged in users', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_logged_in_users'),
),
'manual-approval' => array(
'title' => __('Manual approval', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_manual_approval'),
),
'salt' => array(
'title' => __('Salt', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_salt_tab'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'http-authentication' => array(
'title' => __('HTTP authentication', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_http_authentication'),
),
'hibp' => array(
'title' => __('HIBP', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_hibp'),
'display_condition_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin'),
),
'additional' => array(
'title' => __('Additional settings', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_additional'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's WP User Account tab
*
* @return Void
*/
protected function render_wp_user_account() {
global $aio_wp_security, $aiowps_feature_mgr;
if (is_multisite()) { // Multi-site: get admin accounts for current site
$blog_id = get_current_blog_id();
$user_accounts = $this->get_all_admin_accounts($blog_id);
} else {
$user_accounts = $this->get_all_admin_accounts();
}
$aio_wp_security->include_template('wp-admin/user-security/user-accounts.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'user_accounts' => $user_accounts, 'AIOWPSecurity_User_Security_Menu' => $this));
}
/**
* This function will retrieve all user accounts which have 'administrator' role and will return html code with results in a table
*
* @param string $blog_id - the blog we want to get the user account information from
*
* @return string - the html from the result
*/
private function get_all_admin_accounts($blog_id = '') {
// TODO: Have included the "blog_id" variable for future use for cases where people want to search particular blog (eg, multi-site)
if ($blog_id) {
$admin_users = get_users('blog_id='.$blog_id.'&orderby=login&role=administrator');
} else {
$admin_users = get_users('orderby=login&role=administrator');
}
// now let's put the results in an HTML table
$account_output = "";
if (!empty($admin_users)) {
$account_output .= '<table>';
$account_output .= '<tr><th>'.esc_html(__('Account login name', 'all-in-one-wp-security-and-firewall')).'</th></tr>';
foreach ($admin_users as $entry) {
$account_output .= '<tr>';
if (strtolower($entry->user_login) == 'admin') {
$account_output .= '<td style="color:red; font-weight: bold;">'.esc_html($entry->user_login).'</td>';
} else {
$account_output .= '<td>'.esc_html($entry->user_login).'</td>';
}
$user_acct_edit_link = admin_url('user-edit.php?user_id=' . $entry->ID);
$account_output .= '<td><a href="'.esc_url($user_acct_edit_link).'" target="_blank">'.esc_html(__('Edit user', 'all-in-one-wp-security-and-firewall')).'</a></td>';
$account_output .= '</tr>';
}
$account_output .= '</table>';
}
return $account_output;
}
/**
* Login Lockout configuration to set.
*
* @global AIO_WP_Security $aio_wp_security
* @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
*
* @return Void
*/
protected function render_login_lockout() {
global $aio_wp_security, $aiowps_feature_mgr;
include_once 'wp-security-list-locked-ip.php'; // For rendering the AIOWPSecurity_List_Table in tab1
$locked_ip_list = new AIOWPSecurity_List_Locked_IP(); // For rendering the AIOWPSecurity_List_Table in tab1
$aiowps_lockdown_allowed_ip_addresses = $aio_wp_security->configs->get_value('aiowps_lockdown_allowed_ip_addresses');
$aio_wp_security->include_template('wp-admin/user-security/login-lockout.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'locked_ip_list' => $locked_ip_list, "aiowps_lockdown_allowed_ip_addresses" => $aiowps_lockdown_allowed_ip_addresses));
}
/**
* Force logged user to logout after x minutes.
*
* @global AIO_WP_Security $aio_wp_security
* @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
* @return void
*/
protected function render_force_logout() {
global $aio_wp_security, $aiowps_feature_mgr;
$aio_wp_security->include_template('wp-admin/user-security/force-logout.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
/**
* Logged in users list.
*
* @global AIO_WP_Security $aio_wp_security
* @return void
*/
protected function render_logged_in_users() {
global $aio_wp_security;
include_once 'wp-security-list-logged-in-users.php'; // For rendering the AIOWPSecurity_List_Table
$user_list = new AIOWPSecurity_List_Logged_In_Users();
$aio_wp_security->include_template('wp-admin/user-security/logged-in-users.php', false, array('user_list' => $user_list));
}
/**
* Renders the submenu's manual approval tab
*
* @return Void
*/
protected function render_manual_approval() {
global $aio_wp_security, $aiowps_feature_mgr;
include_once 'wp-security-list-registered-users.php'; // For rendering the AIOWPSecurity_List_Table
$user_list = new AIOWPSecurity_List_Registered_Users();
$aio_wp_security->include_template('wp-admin/user-security/manual-approval.php', false, array('user_list' => $user_list, 'aiowps_feature_mgr' => $aiowps_feature_mgr));
}
/**
* Renders the submenu's salt tab
*
* @return Void
*/
protected function render_salt_tab() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/user-security/salt.php');
}
/**
* Renders the submenu's http authentication tab.
*
* @global AIO_WP_Security $aio_wp_security
*
* @return void
*/
protected function render_http_authentication() {
global $aio_wp_security, $aiowps_feature_mgr;
if (isset($_POST['aiowps_save_http_authentication_settings'])) {
$nonce_user_cap_result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($_POST['_wpnonce'], 'aiowpsec-http-authentication-settings-nonce');
if (is_wp_error($nonce_user_cap_result)) {
$aio_wp_security->debug_logger->log_debug($nonce_user_cap_result->get_error_message(), 4);
die($nonce_user_cap_result->get_error_message());
}
$error = false;
$aio_wp_security->configs->set_value('aiowps_http_authentication_admin', '');
if (isset($_POST['aiowps_http_authentication_admin'])) {
if (!is_ssl()) {
$this->show_msg_error(__('Failed to save \'Enable for WordPress dashboard\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Your site is currently not using https.', 'all-in-one-wp-security-and-firewall'));
$error = true;
} else {
$aio_wp_security->configs->set_value('aiowps_http_authentication_admin', '1');
}
}
$aio_wp_security->configs->set_value('aiowps_http_authentication_frontend', '');
if (isset($_POST['aiowps_http_authentication_frontend'])) {
if (!is_ssl()) {
$this->show_msg_error(__('Failed to save \'Enable for frontend\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Your site is currently not using https.', 'all-in-one-wp-security-and-firewall'));
$error = true;
} else {
$aio_wp_security->configs->set_value('aiowps_http_authentication_frontend', '1');
}
}
if (empty($_POST['aiowps_http_authentication_username'])) {
$this->show_msg_error(__('Failed to save \'Username\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please enter a value for the HTTP authentication username.', 'all-in-one-wp-security-and-firewall'));
$error = true;
} else {
$aio_wp_security->configs->set_value('aiowps_http_authentication_username', sanitize_text_field($_POST['aiowps_http_authentication_username']));
}
if (empty($_POST['aiowps_http_authentication_password'])) {
$this->show_msg_error(__('Failed to save \'Password\'.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please enter a value for the HTTP authentication password.', 'all-in-one-wp-security-and-firewall'));
$error = true;
} else {
$aio_wp_security->configs->set_value('aiowps_http_authentication_password', sanitize_text_field($_POST['aiowps_http_authentication_password']));
}
$aio_wp_security->configs->set_value('aiowps_http_authentication_failure_message', htmlentities(stripslashes($_POST['aiowps_http_authentication_failure_message']), ENT_COMPAT, 'UTF-8'));
$aio_wp_security->configs->save_config();
// Recalculate points after the feature status/options have been altered.
$aiowps_feature_mgr->check_feature_status_and_recalculate_points();
if (!$error) {
$this->show_msg_settings_updated();
}
}
wp_enqueue_script('aiowpsec-pw-tool-js');
$aio_wp_security->include_template('wp-admin/user-security/http-authentication.php');
}
/**
* Renders the submenu's hibp tab.
*
* @global AIO_WP_Security $aio_wp_security
*
* @return void
*/
protected function render_hibp() {
global $aio_wp_security;
$aio_wp_security->include_template('wp-admin/user-security/hibp.php');
}
/**
* Shows additional tab and field for the disable application password and saves on submit.
*
* @global AIO_WP_Security $aio_wp_security
* @global AIOWPSecurity_Feature_Item_Manager $aiowps_feature_mgr
* @return void
*/
protected function render_additional() {
global $aio_wp_security, $aiowps_feature_mgr;
$aio_wp_security->include_template('wp-admin/user-security/additional.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr));
}
}