Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)
This commit is contained in:
@@ -808,11 +808,31 @@ This implementation plan is a draft for review. Please confirm:
|
|||||||
- Site icon/favicon managed via WordPress Customizer (Appearance > Customize > Site Identity)
|
- Site icon/favicon managed via WordPress Customizer (Appearance > Customize > Site Identity)
|
||||||
- Theme color set to #0A0A0A (background dark) for mobile browser chrome
|
- Theme color set to #0A0A0A (background dark) for mobile browser chrome
|
||||||
|
|
||||||
### Phase 6: Performance & Security - PENDING
|
### Phase 6: Performance & Security - COMPLETED (Partial)
|
||||||
|
- [x] WebP image conversion via "Converter for Media" plugin
|
||||||
|
- [x] Nginx rewrite rules for serving WebP to supported browsers
|
||||||
|
- [x] Server dependencies documented in DEPENDENCIES.md
|
||||||
|
- [ ] Caching plugin - SKIPPED (not requested)
|
||||||
|
- [ ] Security plugin - SKIPPED (not requested)
|
||||||
|
- [ ] Backups plugin - SKIPPED (not requested)
|
||||||
|
|
||||||
|
**Technical Details:**
|
||||||
|
- Plugin: Converter for Media v6.3.2
|
||||||
|
- Conversion method: PHP GD/Imagick (both available, WebP supported)
|
||||||
|
- WebP files stored in: `/wp-content/uploads-webpc/`
|
||||||
|
- Nginx serves WebP when browser sends `Accept: image/webp` header
|
||||||
|
- No external APIs or services used (fully local processing)
|
||||||
|
|
||||||
|
**Files Created:**
|
||||||
|
- /var/www/html/DEPENDENCIES.md (server dependency documentation)
|
||||||
|
|
||||||
|
**Files Modified:**
|
||||||
|
- /etc/nginx/sites-available/default (WebP rewrite rules added)
|
||||||
|
|
||||||
### Phase 7: Testing & Launch - PENDING
|
### Phase 7: Testing & Launch - PENDING
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Document Version: 1.4*
|
*Document Version: 1.5*
|
||||||
*Last Updated: November 28, 2025*
|
*Last Updated: November 28, 2025*
|
||||||
*Prepared by: Hanson.xyz Development Team*
|
*Prepared by: Hanson.xyz Development Team*
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
|
|||||||
|
If you believe that you have found a security issue associated with the current release of this plugin, then please report it to the email address with local part security-reports-only and the domain updraftplus.com. If receipt of the email is not acknowledged within 3 working days, then you can try again and also use the inquiry form on the plugin's website.
|
||||||
|
|
||||||
|
Do not send emails on any other subject to this address. They will not be acknowledged, regardless of whether they contain pleas to do otherwise; there are inquiry forms and support forums available which are linked within the plugin and easy to find on the plugin website.
|
||||||
|
|
||||||
|
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
|
||||||
|
|
||||||
|
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
|
||||||
|
* Affected version(s)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* The location of the affected code
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Any log files that are related to this issue (if possible)
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
Thank you!
|
||||||
wp-content/plugins/all-in-one-wp-security-and-firewall/admin/general/wp-security-ajax-data-table.php
Executable
+1486
File diff suppressed because it is too large
Load Diff
Executable
+1451
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Do not modify the files in this folder.
|
||||||
|
*/
|
||||||
+626
@@ -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">★★★★★</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
|
||||||
+280
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+176
@@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+653
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+408
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+75
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+144
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+188
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+646
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+362
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+527
@@ -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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-list-comment-spammer-ip.php
Executable
+221
@@ -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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
+149
@@ -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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+318
@@ -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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+260
@@ -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()) : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
+238
@@ -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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+355
@@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+90
@@ -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;
|
||||||
Executable
+157
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+93
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
+98
@@ -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
|
||||||
Executable
+296
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+561
@@ -0,0 +1,561 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Brute_Force_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Brute_Force_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform saving rename login settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains PHP settings
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_rename_login_page($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$options = array();
|
||||||
|
$args = array();
|
||||||
|
|
||||||
|
$aiowps_login_page_slug = '';
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if ('' == $data['aiowps_login_page_slug'] && isset($data["aiowps_enable_rename_login_page"])) {
|
||||||
|
$error = __('Please enter a value for your login page slug.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ('' != $data['aiowps_login_page_slug']) {
|
||||||
|
$aiowps_login_page_slug = sanitize_text_field($data['aiowps_login_page_slug']);
|
||||||
|
if ('wp-admin' == $aiowps_login_page_slug) {
|
||||||
|
$error = '<br>' . __('You cannot use the value "wp-admin" for your login page slug.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif (preg_match('/[^\p{L}\p{N}_\-]/u', $aiowps_login_page_slug)) {
|
||||||
|
$error = '<br>' . __('You must use alphanumeric characters for your login page slug.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
$success = false;
|
||||||
|
$message = $error;
|
||||||
|
} else {
|
||||||
|
$options['aiowps_enable_rename_login_page'] = isset($data["aiowps_enable_rename_login_page"]) ? '1' : '';
|
||||||
|
$options['aiowps_login_page_slug'] = $aiowps_login_page_slug;
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
if (get_option('permalink_structure')) {
|
||||||
|
$home_url = trailingslashit(home_url());
|
||||||
|
} else {
|
||||||
|
$home_url = trailingslashit(home_url()) . '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$args['badges'] = array("bf-rename-login-page");
|
||||||
|
$args['content'] = array('aios-rename-login-notice' => $aio_wp_security->include_template('wp-admin/brute-force/partials/rename-login-notice.php', true, array('home_url' => $home_url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to enable or configure cookie-based brute force prevention.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_cookie_based_brute_force_prevention($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
$values = array();
|
||||||
|
$info = array();
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
if (isset($data['aiowps_enable_brute_force_attack_prevention'])) {
|
||||||
|
$brute_force_feature_secret_word = sanitize_text_field($data['aiowps_brute_force_secret_word']);
|
||||||
|
$redirect_url = sanitize_text_field($data['aiowps_cookie_based_brute_force_redirect_url']);
|
||||||
|
if (empty($brute_force_feature_secret_word)) {
|
||||||
|
$brute_force_feature_secret_word = AIOS_DEFAULT_BRUTE_FORCE_FEATURE_SECRET_WORD;
|
||||||
|
$info[] = __('You entered an invalid value for the secret word.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif (!ctype_alnum($brute_force_feature_secret_word)) {
|
||||||
|
$message = '<p>' . __('Settings have not been saved - your secret word must consist only of alphanumeric characters i.e., letters and/or numbers only.', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter_var($redirect_url, FILTER_VALIDATE_URL)) {
|
||||||
|
$redirect_url = esc_url_raw($redirect_url);
|
||||||
|
} else {
|
||||||
|
$redirect_url = 'http://127.0.0.1';
|
||||||
|
$info[] = __('You entered an invalid value for the redirect url.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['aiowps_cookie_based_brute_force_redirect_url'] = $redirect_url;
|
||||||
|
|
||||||
|
if ($success) {
|
||||||
|
$options['aiowps_enable_brute_force_attack_prevention'] = '1';
|
||||||
|
$options['aiowps_brute_force_secret_word'] = $brute_force_feature_secret_word;
|
||||||
|
|
||||||
|
$result = '<p>' . __('You have successfully enabled the cookie based brute force prevention feature', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$result .= '<p>' . __('From now on you will need to log into your WP Admin using the following URL:', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$result .= '<p><strong>'.AIOWPSEC_WP_URL.'/?'.esc_html($brute_force_feature_secret_word).'=1</strong></p>';
|
||||||
|
$result .= '<p>' . __('It is important that you save this URL value somewhere in case you forget it, OR,', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$result .= '<p>' . sprintf(__('simply remember to add a "?%s=1" to your current site URL address.', 'all-in-one-wp-security-and-firewall'), esc_html($brute_force_feature_secret_word)) . '</p>';
|
||||||
|
AIOWPSecurity_Utility::set_cookie_value(AIOWPSecurity_Utility::get_brute_force_secret_cookie_name(), AIOS_Helper::get_hash($brute_force_feature_secret_word));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$options['aiowps_enable_brute_force_attack_prevention'] = '';
|
||||||
|
$message = __('You have successfully saved cookie based brute force prevention feature settings.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$brute_force_feature_secret_word = $aio_wp_security->configs->get_value('aiowps_brute_force_secret_word');
|
||||||
|
$redirect_url = $aio_wp_security->configs->get_value('aiowps_cookie_based_brute_force_redirect_url');
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['aiowps_brute_force_attack_prevention_pw_protected_exception'] = isset($data['aiowps_brute_force_attack_prevention_pw_protected_exception']) ? '1' : '';
|
||||||
|
$options['aiowps_brute_force_attack_prevention_ajax_exception'] = isset($data['aiowps_brute_force_attack_prevention_ajax_exception']) ? '1' : '';
|
||||||
|
|
||||||
|
if ($success) {
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
AIOWPSecurity_Configure_Settings::set_cookie_based_bruteforce_firewall_configs();
|
||||||
|
|
||||||
|
$message = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$values['aiowps_brute_force_secret_word'] = $brute_force_feature_secret_word;
|
||||||
|
$values['aiowps_cookie_based_brute_force_redirect_url'] = $redirect_url;
|
||||||
|
}
|
||||||
|
$content = array(
|
||||||
|
'aios-brute-force-info-box' => $result
|
||||||
|
);
|
||||||
|
|
||||||
|
$badges = array("firewall-enable-brute-force-attack-prevention");
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => $badges,
|
||||||
|
'info' => $info,
|
||||||
|
'values' => $values,
|
||||||
|
'content' => $content
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request for performing cookie test.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_cookie_test() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
$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);
|
||||||
|
$set_cookie = AIOWPSecurity_Utility::set_cookie_value($test_cookie_name, '1');
|
||||||
|
$aiowps_cookie_test_success = '';
|
||||||
|
$args = array();
|
||||||
|
|
||||||
|
if ($set_cookie) {
|
||||||
|
$aiowps_cookie_test_success = '1';
|
||||||
|
$message = __('The cookie test was successful, you can now enable this feature.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$result = '<div class="aio_green_box"><p>' . __('The cookie test was successful, you can now enable this feature.', 'all-in-one-wp-security-and-firewall') . '</p></div>';
|
||||||
|
} else {
|
||||||
|
$success = false;
|
||||||
|
$message = __('The cookie test failed.', 'all-in-one-wp-security-and-firewall') .' '. __('Consequently, this feature cannot be used on this site.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$result = '<div class="aio_red_box"><p>' . __('The cookie test failed on this server.', 'all-in-one-wp-security-and-firewall') .' '. __('Consequently, this feature cannot be used on this site.', 'all-in-one-wp-security-and-firewall') . '</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings(array('aiowps_cookie_test_success' => $aiowps_cookie_test_success)); // save the value
|
||||||
|
$args['content'] = array(
|
||||||
|
'aios-perform-cookie-test-div' => $this->get_perform_cookie_test_content(),
|
||||||
|
'cookie-test-result-div' => $result
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to enable or configure login whitelist settings.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_login_whitelist_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$options = array();
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_allowed_ip_addresses'])) {
|
||||||
|
$ip_addresses = sanitize_textarea_field(stripslashes($data['aiowps_allowed_ip_addresses']));
|
||||||
|
$ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'whitelist');
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$result = -1;
|
||||||
|
$success = false;
|
||||||
|
$message = nl2br($validated_ip_list_array->get_error_message());
|
||||||
|
} else {
|
||||||
|
$result = 1;
|
||||||
|
$whitelist_ip_data = implode("\n", $validated_ip_list_array);
|
||||||
|
$options['aiowps_allowed_ip_addresses'] = $whitelist_ip_data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = 1;
|
||||||
|
$options['aiowps_allowed_ip_addresses'] = ''; // Clear the IP address config value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == $result) {
|
||||||
|
$options['aiowps_enable_whitelisting'] = isset($data["aiowps_enable_whitelisting"]) ? '1' : '';
|
||||||
|
if ('1' == $aio_wp_security->configs->get_value('aiowps_is_login_whitelist_disabled_on_upgrade')) {
|
||||||
|
$aio_wp_security->configs->delete_value('aiowps_is_login_whitelist_disabled_on_upgrade');
|
||||||
|
}
|
||||||
|
$this->save_settings($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => array('whitelist-manager-ip-login-whitelisting')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to enable or configure honeypot brute force settings.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_honeypot_settings($data) {
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
// Save all the form values to the options
|
||||||
|
$options['aiowps_enable_login_honeypot'] = isset($data["aiowps_enable_login_honeypot"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_registration_honeypot'] = isset($data["aiowps_enable_registration_honeypot"]) ? '1' : '';
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => array('login-honeypot', 'registration-honeypot')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to enable or configure captcha settings.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_captcha_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$captcha_themes = $aio_wp_security->captcha_obj->get_captcha_themes();
|
||||||
|
$supported_captchas = $aio_wp_security->captcha_obj->get_supported_captchas();
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
$default_captcha = isset($data['aiowps_default_captcha']) ? sanitize_text_field($data['aiowps_default_captcha']) : '';
|
||||||
|
|
||||||
|
$default_captcha = array_key_exists($default_captcha, $supported_captchas) ? $default_captcha : 'none';
|
||||||
|
|
||||||
|
$options['aiowps_default_captcha'] = $default_captcha;
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$random_20_digit_string = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20); // Generate random 20 char string for use during CAPTCHA encode/decode
|
||||||
|
$options['aiowps_captcha_secret_key'] = $random_20_digit_string;
|
||||||
|
$options['aiowps_enable_login_captcha'] = isset($data["aiowps_enable_login_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_registration_page_captcha'] = isset($data["aiowps_enable_registration_page_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_comment_captcha'] = isset($data["aiowps_enable_comment_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_bp_register_captcha'] = isset($data["aiowps_enable_bp_register_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_bbp_new_topic_captcha'] = isset($data["aiowps_enable_bbp_new_topic_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_woo_login_captcha'] = isset($data["aiowps_enable_woo_login_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_woo_register_captcha'] = isset($data["aiowps_enable_woo_register_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_woo_lostpassword_captcha'] = isset($data["aiowps_enable_woo_lostpassword_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_woo_checkout_captcha'] = isset($data["aiowps_enable_woo_checkout_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_custom_login_captcha'] = isset($data["aiowps_enable_custom_login_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_lost_password_captcha'] = isset($data["aiowps_enable_lost_password_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_contact_form_7_captcha'] = isset($data["aiowps_enable_contact_form_7_captcha"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_password_protected_captcha'] = isset($data["aiowps_enable_password_protected_captcha"]) ? '1' : '';
|
||||||
|
|
||||||
|
$options['aiowps_turnstile_site_key'] = sanitize_text_field(stripslashes($data['aiowps_turnstile_site_key']));
|
||||||
|
$options['aiowps_recaptcha_site_key'] = sanitize_text_field(stripslashes($data['aiowps_recaptcha_site_key']));
|
||||||
|
|
||||||
|
$turnstile_theme = isset($data['aiowps_turnstile_theme']) ? sanitize_text_field($data['aiowps_turnstile_theme']) : '';
|
||||||
|
$turnstile_theme = array_key_exists($turnstile_theme, $captcha_themes) ? $turnstile_theme : 'auto';
|
||||||
|
$options['aiowps_turnstile_theme'] = $turnstile_theme;
|
||||||
|
|
||||||
|
// If secret key is masked then don't resave it
|
||||||
|
$turnstile_secret_key = sanitize_text_field($data['aiowps_turnstile_secret_key']);
|
||||||
|
if (strpos($turnstile_secret_key, '********') === false) {
|
||||||
|
$options['aiowps_turnstile_secret_key'] = $turnstile_secret_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If secret key is masked then don't resave it
|
||||||
|
$recaptcha_secret_key = sanitize_text_field($data['aiowps_recaptcha_secret_key']);
|
||||||
|
if (strpos($recaptcha_secret_key, '********') === false) {
|
||||||
|
$options['aiowps_recaptcha_secret_key'] = $recaptcha_secret_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('google-recaptcha-v2' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && false === $aio_wp_security->captcha_obj->google_recaptcha_verify_configuration($aio_wp_security->configs->get_value('aiowps_recaptcha_site_key'), $aio_wp_security->configs->get_value('aiowps_recaptcha_secret_key'))) {
|
||||||
|
$options['aios_google_recaptcha_invalid_configuration'] = '1';
|
||||||
|
} elseif ('1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) {
|
||||||
|
$aio_wp_security->configs->delete_value('aios_google_recaptcha_invalid_configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$message = '';
|
||||||
|
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'))) {
|
||||||
|
$message = __('Your Cloudflare Turnstile configuration is invalid.', 'all-in-one-wp-security-and-firewall').' '.__('Please enter the correct Cloudflare Turnstile keys below to use the Turnstile feature.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ('google-recaptcha-v2' == $aio_wp_security->configs->get_value('aiowps_default_captcha') && '1' == $aio_wp_security->configs->get_value('aios_google_recaptcha_invalid_configuration')) {
|
||||||
|
$message = __('Your Google reCAPTCHA configuration is invalid.', 'all-in-one-wp-security-and-firewall').' '.__('Please enter the correct reCAPTCHA keys below to use the reCAPTCHA feature.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$features = array(
|
||||||
|
"user-login-captcha",
|
||||||
|
"user-registration-captcha",
|
||||||
|
"lost-password-captcha",
|
||||||
|
"custom-login-captcha",
|
||||||
|
"comment-form-captcha",
|
||||||
|
"password_protected-captcha",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility::is_woocommerce_plugin_active()) {
|
||||||
|
$woocommerce_features = array(
|
||||||
|
"woo-login-captcha",
|
||||||
|
"woo-lostpassword-captcha",
|
||||||
|
"woo-register-captcha",
|
||||||
|
"woo-checkout-captcha",
|
||||||
|
);
|
||||||
|
$features = array_merge($features, $woocommerce_features);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility::is_buddypress_plugin_active()) {
|
||||||
|
$features[] = "bp-register-captcha";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility::is_bbpress_plugin_active()) {
|
||||||
|
$features[] = "bbp-new-topic-captcha";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility::is_contact_form_7_plugin_active()) {
|
||||||
|
$features[] = "contact-form-7-captcha";
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => $features
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to enable or configure 404 detection and settings.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_404_settings($data) {
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
$info = array();
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
$options['aiowps_enable_404_logging'] = isset($data["aiowps_enable_404_IP_lockout"]) ? '1' : ''; //the "aiowps_enable_404_IP_lockout" checkbox currently controls both the 404 lockout and 404 logging
|
||||||
|
$options['aiowps_enable_404_IP_lockout'] = isset($data["aiowps_enable_404_IP_lockout"]) ? '1' : '';
|
||||||
|
|
||||||
|
$lockout_time_length = isset($data['aiowps_404_lockout_time_length']) ? sanitize_text_field($data['aiowps_404_lockout_time_length']) : '';
|
||||||
|
$redirect_url = isset($data['aiowps_404_lock_redirect_url']) ? sanitize_text_field(trim($data['aiowps_404_lock_redirect_url'])) : '';
|
||||||
|
|
||||||
|
if (isset($data["aiowps_enable_404_IP_lockout"])) {
|
||||||
|
if (!is_numeric($lockout_time_length) || $lockout_time_length < 1) {
|
||||||
|
$info[] = __('You entered a non numeric or negative value for the lockout time length field.', 'all-in-one-wp-security-and-firewall'). ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$lockout_time_length = '60'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' == $redirect_url || '' == esc_url($redirect_url, array('http', 'https'))) {
|
||||||
|
$info[] = __('You entered an incorrect format for the "Redirect URL" field.', 'all-in-one-wp-security-and-firewall') . ' ' . __('It has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$redirect_url = 'http://127.0.0.1';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['aiowps_404_lockout_time_length'] = absint($lockout_time_length);
|
||||||
|
$options['aiowps_404_lock_redirect_url'] = $redirect_url;
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$badges = array("firewall-enable-404-blocking");
|
||||||
|
$values['aiowps_404_lockout_time_length'] = $lockout_time_length;
|
||||||
|
$values['aiowps_404_lock_redirect_url'] = $redirect_url;
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => $badges,
|
||||||
|
'info' => $info,
|
||||||
|
'values' => $values
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request to clear 404 logs.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_delete_404_event_records() {
|
||||||
|
global $aio_wp_security, $wpdb;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$events_table_name = AIOWPSEC_TBL_EVENTS;
|
||||||
|
//Delete all 404 records from the events table
|
||||||
|
$where = array('event_type' => '404');
|
||||||
|
$result = $wpdb->delete($events_table_name, $where);
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
$error = empty($wpdb->last_error) ? '' : $wpdb->last_error;
|
||||||
|
$aio_wp_security->debug_logger->log_debug("404 Detection Feature - Delete all 404 event logs operation failed. $error", 4);
|
||||||
|
$success = false;
|
||||||
|
$message = __('404 Detection Feature - The operation to delete all the 404 event logs failed', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$message = __('All 404 event logs were deleted from the database successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the AJAX request for 404 log item actions.
|
||||||
|
*
|
||||||
|
* @param array $data The data received from the AJAX request.
|
||||||
|
*
|
||||||
|
* @return array The response containing the status, message, and badge.
|
||||||
|
*/
|
||||||
|
public function perform_404_log_item_action($data) {
|
||||||
|
global $wpdb, $aio_wp_security, $aiowps_firewall_config;
|
||||||
|
|
||||||
|
if (empty($data['action']) || !in_array($data['action'], array('delete', 'temp_block', 'blacklist', 'unblock'))) {
|
||||||
|
return $this->handle_response(false, __('Invalid action provided for 404 log item.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $data['action'];
|
||||||
|
$message = false;
|
||||||
|
|
||||||
|
switch ($action) {
|
||||||
|
case 'delete':
|
||||||
|
if (!isset($data['id'])) {
|
||||||
|
return $this->handle_response(false, __('Invalid 404 event log ID provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
$events_table = AIOWPSEC_TBL_EVENTS;
|
||||||
|
$id = absint($data['id']);
|
||||||
|
//Delete single record
|
||||||
|
$delete_command = "DELETE FROM " . $events_table . " WHERE id = '" . absint($id) . "'";
|
||||||
|
$result = $wpdb->query($delete_command);
|
||||||
|
if (false === $result) {
|
||||||
|
// Error on single delete
|
||||||
|
$aio_wp_security->debug_logger->log_debug('Database error occurred when deleting rows from Events table. Database error: '.$wpdb->last_error, 4);
|
||||||
|
return $this->handle_response(false, __('The selected record(s) have failed to delete.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
} else {
|
||||||
|
$message = __('The selected record(s) has been deleted successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'temp_block':
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
$ip = sanitize_text_field($data['ip']);
|
||||||
|
$username = isset($data['username']) ? sanitize_user($data['username']) : '';
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
|
||||||
|
return $this->handle_response(false, __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip);
|
||||||
|
}
|
||||||
|
//Block single record
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||||
|
AIOWPSecurity_Utility::lock_IP($ip, '404', $username);
|
||||||
|
$message = __('The selected IP address is now temporarily blocked.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$message = __('The selected entry is not a valid IP address.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $this->handle_response(false, $message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'blacklist':
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$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);
|
||||||
|
$ip = sanitize_text_field($data['ip']);
|
||||||
|
$ip_list_array[] = $ip;
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
|
||||||
|
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$response = nl2br($validated_ip_list_array->get_error_message());
|
||||||
|
return $this->handle_response(false, $response);
|
||||||
|
} 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);
|
||||||
|
$message = __('The selected IP addresses have been added to the blacklist and will be permanently blocked.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'unblock':
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('Invalid log event ID provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip_range = sanitize_text_field($data['ip']);
|
||||||
|
$lockout_table = AIOWPSEC_TBL_LOGIN_LOCKOUT;
|
||||||
|
|
||||||
|
// get the latest data with that ip in the table that's locked and reason is 404
|
||||||
|
$query = $wpdb->prepare("SELECT id FROM {$lockout_table} WHERE `released` > UNIX_TIMESTAMP() AND `lock_reason` = %s and failed_login_ip = %s ORDER BY id ASC LIMIT 1", '404', $ip_range);
|
||||||
|
$id = $wpdb->get_var($query);
|
||||||
|
|
||||||
|
if (null === $id) {
|
||||||
|
return $this->handle_response(false, __('Invalid log event ID provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $wpdb->query($wpdb->prepare("UPDATE $lockout_table SET `released` = UNIX_TIMESTAMP() WHERE `id` = %d", absint($id)));
|
||||||
|
|
||||||
|
if (null != $result) {
|
||||||
|
$message = __('Access from the selected IP address has been unblocked.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
return $this->handle_response(false, __('The selected IP entry could not be unlocked', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response(true, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content for performing a cookie test.
|
||||||
|
*
|
||||||
|
* This method checks if the cookie test is successful or if the brute-force attack prevention feature is already enabled.
|
||||||
|
* If either condition is true, it returns an empty string. Otherwise, it displays a message prompting the user to perform
|
||||||
|
* a cookie test before enabling the feature, along with a button to initiate the test.
|
||||||
|
*
|
||||||
|
* @return string The HTML content for the cookie test section.
|
||||||
|
*/
|
||||||
|
private function get_perform_cookie_test_content() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
$cookie_test_value = $aio_wp_security->configs->get_value('aiowps_cookie_test_success');
|
||||||
|
|
||||||
|
if ('1' == $cookie_test_value || '1' == $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention')) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return $aio_wp_security->include_template('wp-admin/brute-force/partials/cookie-test-container.php', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+221
@@ -0,0 +1,221 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Comment_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Comment_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the saving of comment spam prevention settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the post data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_comment_spam_prevention($data) {
|
||||||
|
$response = array();
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$options = array();
|
||||||
|
$info = array();
|
||||||
|
|
||||||
|
$options['aiowps_enable_spambot_detecting'] = isset($data["aiowps_enable_spambot_detecting"]) ? '1' : '';
|
||||||
|
$options['aiowps_spambot_detect_usecookies'] = isset($data["aiowps_spambot_detect_usecookies"]) ? '1' : '';
|
||||||
|
$options['aiowps_spam_comments_should'] = !empty($data["aiowps_spam_comments_should"]) ? '1' : '0';
|
||||||
|
$options['aiowps_enable_trash_spam_comments'] = isset($data['aiowps_enable_trash_spam_comments']) ? '1' : '';
|
||||||
|
if (isset($data['aiowps_trash_spam_comments_after_days'])) {
|
||||||
|
$aiowps_trash_spam_comments_after_days = sanitize_text_field($data['aiowps_trash_spam_comments_after_days']);
|
||||||
|
if (isset($data['aiowps_enable_trash_spam_comments']) && !is_numeric($aiowps_trash_spam_comments_after_days)) {
|
||||||
|
$error = __('You entered a non-numeric value for the "move spam comments to trash after number of days" field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
//Set it to the default value for this field
|
||||||
|
$info[] = $error;
|
||||||
|
$aiowps_trash_spam_comments_after_days = 14;
|
||||||
|
}
|
||||||
|
$aiowps_trash_spam_comments_after_days = absint($aiowps_trash_spam_comments_after_days);
|
||||||
|
$options['aiowps_trash_spam_comments_after_days'] = $aiowps_trash_spam_comments_after_days;
|
||||||
|
|
||||||
|
$response['values'] = array(
|
||||||
|
'aiowps_trash_spam_comments_after_days' => $aiowps_trash_spam_comments_after_days
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['status'] = 'success';
|
||||||
|
$response['message'] = __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['info'] = $info;
|
||||||
|
|
||||||
|
// Commit the config settings
|
||||||
|
$this->save_settings($options);
|
||||||
|
AIOWPSecurity_Comment::trash_spam_comments();
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('detect-spambots'));
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the saving of comment auto block spammers ip settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the post data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_auto_block_spam_ip($data) {
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'values' => array(),
|
||||||
|
'info' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$enable_auto_block_ip = isset($data["aiowps_enable_autoblock_spam_ip"]) ? '1' : '';
|
||||||
|
|
||||||
|
$spam_ip_min_comments = sanitize_text_field($data['aiowps_spam_ip_min_comments_block']);
|
||||||
|
if (!is_numeric($spam_ip_min_comments)) {
|
||||||
|
$response['info'][] = __('You entered a non-numeric value for the "minimum number of spam comments" field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$spam_ip_min_comments = '3';// Set it to the default value for this field
|
||||||
|
} elseif ((int) $spam_ip_min_comments <= 0 || empty($spam_ip_min_comments)) {
|
||||||
|
$response['info'][] = __('You must enter an integer greater than zero for the "minimum number of spam comments" field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$spam_ip_min_comments = '3';// Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$options = array(
|
||||||
|
'aiowps_enable_autoblock_spam_ip' => $enable_auto_block_ip,
|
||||||
|
'aiowps_spam_ip_min_comments_block' => absint($spam_ip_min_comments),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
$response['message'] = __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('auto-block-spam-ips'));
|
||||||
|
$response['values']['aiowps_spam_ip_min_comments_block'] = absint($spam_ip_min_comments);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the ip spam comment search
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the post data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_ip_spam_search($data) {
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'info' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$min_comments_per_ip = sanitize_text_field($data['aiowps_spam_ip_min_comments']);
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if (!is_numeric($min_comments_per_ip)) {
|
||||||
|
$error = __('You entered a non-numeric value for the minimum spam comments per IP field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$min_comments_per_ip = '5'; // Set it to the default value for this field
|
||||||
|
} elseif ((int) $min_comments_per_ip <= 0 || empty($min_comments_per_ip)) {
|
||||||
|
$error = __('You must enter an integer greater than zero for the minimum spam comments per IP field; it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$min_comments_per_ip = '5'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
$min_comments_per_ip = absint($min_comments_per_ip);
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$this->save_settings(array(
|
||||||
|
'aiowps_spam_ip_min_comments' => $min_comments_per_ip
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!empty($error)) {
|
||||||
|
$response['message'] = $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['values']['aiowps_spam_ip_min_comments'] = $min_comments_per_ip;
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the action of blocking a spam IP address.
|
||||||
|
*
|
||||||
|
* This function takes an IP address as input, checks if it is valid and not the user's own IP,
|
||||||
|
* and then attempts to add it to the block list for spam. It returns the status and message of the operation.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the IP address to block.
|
||||||
|
*
|
||||||
|
* @return array The result of the block operation, including status, message, and updated blocked comments output.
|
||||||
|
*/
|
||||||
|
public function perform_block_spam_ip($data) {
|
||||||
|
|
||||||
|
if (empty($data['ip'])) {
|
||||||
|
return array('status' => 'error', 'message' => __('Invalid IP address provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip = wp_strip_all_tags($data['ip']);
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
|
||||||
|
return array('status' => 'error', 'message' => __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip, 'spam');
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$status = 'success';
|
||||||
|
$message = __('The selected IP address is now permanently blocked.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$status = 'error';
|
||||||
|
$message = __('The selected IP address could not be blocked due to one of the following reasons:', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$message .= ' ' . __('either it has already been blocked, or your user account lacks sufficient permissions to perform IP blocking.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => $status,
|
||||||
|
'message' => $message,
|
||||||
|
'content' => array('aios-blocked-comments-output' => $this->get_blocked_comments_output())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the output for displaying blocked comments due to spam.
|
||||||
|
*
|
||||||
|
* This function queries the database to get IP addresses that are permanently blocked due to spam.
|
||||||
|
* It returns HTML output that displays the count of IPs blocked today and the all-time total count.
|
||||||
|
*
|
||||||
|
* @global object $aio_wp_security The global instance of the aio_wp_security class.
|
||||||
|
* @global object $wpdb The global instance of the WordPress database class.
|
||||||
|
*
|
||||||
|
* @return string HTML output for the blocked comments section.
|
||||||
|
*/
|
||||||
|
private function get_blocked_comments_output() {
|
||||||
|
global $aio_wp_security, $wpdb;
|
||||||
|
|
||||||
|
$block_comments_output = '';
|
||||||
|
$min_block_comments = $aio_wp_security->configs->get_value('aiowps_spam_ip_min_comments_block');
|
||||||
|
|
||||||
|
if (!empty($min_block_comments)) {
|
||||||
|
$now_date = (new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d');
|
||||||
|
|
||||||
|
$sql = $wpdb->prepare(
|
||||||
|
"SELECT COUNT(*) AS total_count,
|
||||||
|
SUM(CASE WHEN DATE(FROM_UNIXTIME(created)) = %s THEN 1 ELSE 0 END) AS todays_blocked_count FROM ".AIOWPSEC_TBL_PERM_BLOCK." WHERE block_reason = %s",
|
||||||
|
$now_date,
|
||||||
|
'spam'
|
||||||
|
);
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore
|
||||||
|
$result = $wpdb->get_row($sql);
|
||||||
|
|
||||||
|
$block_comments_output = '<div class="aio_yellow_box">';
|
||||||
|
if (empty($result) || 0 == $result->total_count) {
|
||||||
|
$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>';
|
||||||
|
} else {
|
||||||
|
$todays_blocked_count = $result->todays_blocked_count;
|
||||||
|
$total_count = $result->total_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>';
|
||||||
|
$block_comments_output .= '<hr><p><strong>'.esc_html__('All time total:', 'all-in-one-wp-security-and-firewall'). ' ' . $total_count.'</strong></p>';
|
||||||
|
$block_comments_output .= '<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>';
|
||||||
|
}
|
||||||
|
$block_comments_output .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $block_comments_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
+280
@@ -0,0 +1,280 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_File_Scan_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_File_Scan_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the operation to save file change detection settings.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the file change detection settings.
|
||||||
|
*
|
||||||
|
* @return array An array containing the status of the operation, any relevant messages,
|
||||||
|
* and updated content.
|
||||||
|
*/
|
||||||
|
public function perform_save_file_detection_change_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$info = array();
|
||||||
|
$content = array();
|
||||||
|
$options = array();
|
||||||
|
$errors = array();
|
||||||
|
$reset_scan_data = false;
|
||||||
|
$file_types = '';
|
||||||
|
$files = '';
|
||||||
|
|
||||||
|
$fcd_scan_frequency = sanitize_text_field($data['aiowps_fcd_scan_frequency']);
|
||||||
|
|
||||||
|
if (!is_numeric($fcd_scan_frequency)) {
|
||||||
|
$errors[] = __('You entered a non numeric value for the "backup time interval" field, it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$fcd_scan_frequency = '4'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_fcd_exclude_filetypes'])) {
|
||||||
|
$file_types = sanitize_textarea_field(trim($data['aiowps_fcd_exclude_filetypes']));
|
||||||
|
|
||||||
|
// Get the currently saved config value and check if this has changed. If so do another scan to reset the scan data so it omits these filetypes
|
||||||
|
if ($file_types != $aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes')) {
|
||||||
|
$reset_scan_data = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_fcd_exclude_files'])) {
|
||||||
|
$files = sanitize_textarea_field(trim($data['aiowps_fcd_exclude_files']));
|
||||||
|
// Get the currently saved config value and check if this has changed. If so do another scan to reset the scan data so it omits these files/dirs
|
||||||
|
if ($files != $aio_wp_security->configs->get_value('aiowps_fcd_exclude_files')) {
|
||||||
|
$reset_scan_data = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explode by end-of-line character, then trim and filter empty lines
|
||||||
|
$email_list_array = array_filter(array_map('trim', explode("\n", $data['aiowps_fcd_scan_email_address'])), 'strlen');
|
||||||
|
foreach ($email_list_array as $key => $value) {
|
||||||
|
$email_sane = sanitize_email($value);
|
||||||
|
if (!is_email($email_sane)) {
|
||||||
|
$errors[] = __('The following address was removed because it is not a valid email address:', 'all-in-one-wp-security-and-firewall') . ' ' . htmlspecialchars($value);
|
||||||
|
unset($email_list_array[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$email_address = implode("\n", $email_list_array);
|
||||||
|
if (!empty($errors)) {
|
||||||
|
$info[] = implode('<br>', $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$options['aiowps_enable_automated_fcd_scan'] = isset($data["aiowps_enable_automated_fcd_scan"]) ? '1' : '';
|
||||||
|
$options['aiowps_fcd_scan_frequency'] = absint($fcd_scan_frequency);
|
||||||
|
$options['aiowps_fcd_scan_interval'] = sanitize_text_field($data["aiowps_fcd_scan_interval"]);
|
||||||
|
$options['aiowps_fcd_exclude_filetypes'] = $file_types;
|
||||||
|
$options['aiowps_fcd_exclude_files'] = $files;
|
||||||
|
$options['aiowps_send_fcd_scan_email'] = isset($data["aiowps_send_fcd_scan_email"]) ? '1' : '';
|
||||||
|
$options['aiowps_fcd_scan_email_address'] = $email_address;
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$content['aios-file-change-info-box'] = '';
|
||||||
|
// Let's check if backup interval was set to less than 24 hours
|
||||||
|
if (isset($data["aiowps_enable_automated_fcd_scan"]) && ($fcd_scan_frequency < 24) && 0 == $data["aiowps_fcd_scan_interval"]) {
|
||||||
|
$content['aios-file-change-info-box'] = '<div class="aio_yellow_box">';
|
||||||
|
$content['aios-file-change-info-box'] .= '<p>' . __('You have configured your file change detection scan to occur at least once daily.', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$content['aios-file-change-info-box'] .= '<p>' . __('For most websites we recommended that you choose a less frequent schedule such as once every few days, once a week or once a month.', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$content['aios-file-change-info-box'] .= '<p>' . __('Choosing a less frequent schedule will also help reduce your server load.', 'all-in-one-wp-security-and-firewall') . '</p>';
|
||||||
|
$content['aios-file-change-info-box'] .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reset_scan_data) {
|
||||||
|
$aio_wp_security->scan_obj->execute_file_change_detection_scan();
|
||||||
|
$new_scan_alert = __('New scan completed: The plugin has detected that you have made changes to the "File Types To Ignore" or "Files To Ignore" fields.', 'all-in-one-wp-security-and-firewall').' '.__('In order to ensure that future scan results are accurate, the old scan data has been refreshed.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$info[] = $new_scan_alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
$next_fcd_scan_time = AIOWPSecurity_Scan::get_next_scheduled_scan();
|
||||||
|
|
||||||
|
if (false == $next_fcd_scan_time) {
|
||||||
|
$next_scheduled_scan = '<span>' . esc_html__('Nothing is currently scheduled', 'all-in-one-wp-security-and-firewall') . '</span>';
|
||||||
|
} else {
|
||||||
|
$scan_time = AIOWPSecurity_Utility::convert_timestamp($next_fcd_scan_time, 'D, F j, Y H:i');
|
||||||
|
$next_scheduled_scan = '<span class="aiowps_next_scheduled_date_time">' . esc_html($scan_time) . '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$content['aiowps-next-files-scan-inner'] = $next_scheduled_scan;
|
||||||
|
$values = array('aiowps_fcd_scan_frequency' => absint($fcd_scan_frequency));
|
||||||
|
$badges = array('scan-file-change-detection');
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'content' => $content,
|
||||||
|
'values' => $values,
|
||||||
|
'badges' => $badges,
|
||||||
|
'info' => $info
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last file scan data and returns the data to UDC.
|
||||||
|
*
|
||||||
|
* @param array $data The request data.
|
||||||
|
*
|
||||||
|
* @return array|string[]|WP_Error
|
||||||
|
*/
|
||||||
|
public function get_last_scan_data($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['reset_change_detected']) {
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fcd_data = AIOWPSecurity_Scan::get_fcd_data();
|
||||||
|
|
||||||
|
$data = $fcd_data['last_scan_result'];
|
||||||
|
|
||||||
|
foreach (array('files_added', 'files_removed', 'files_changed') as $key) {
|
||||||
|
/* Normalize missing or non-array buckets to an empty array and skip processing */
|
||||||
|
if (!isset($data[$key]) || !is_array($data[$key])) {
|
||||||
|
$data[$key] = array();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert last_modified for each entry */
|
||||||
|
foreach ($data[$key] as &$info) {
|
||||||
|
if (is_array($info) && array_key_exists('last_modified', $info) && is_numeric($info['last_modified'])) {
|
||||||
|
$info['last_modified'] = AIOWPSecurity_Utility::convert_timestamp($info['last_modified']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fcd_data['last_scan_result'] = $data;
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, array('extra_args' => $fcd_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last file scan result and returns the scan result HTML template
|
||||||
|
*
|
||||||
|
* @param array $data - the request data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_last_scan_results($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
if ($data['reset_change_detected']) $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', false, true);
|
||||||
|
|
||||||
|
$fcd_data = AIOWPSecurity_Scan::get_fcd_data();
|
||||||
|
|
||||||
|
if (!$fcd_data || !isset($fcd_data['last_scan_result'])) {
|
||||||
|
// no fcd data found
|
||||||
|
$message = __('No previous scan data was found; either run a manual scan or schedule regular file scans', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $this->handle_response(false, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = array('aiowps_previous_scan_wrapper' => $aio_wp_security->include_template('wp-admin/scanner/scan-result.php', true, array('fcd_data' => $fcd_data)));
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, array('content' => $content));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a file scan and returns the scan result
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_file_scan() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$content = array();
|
||||||
|
$extra_args = array();
|
||||||
|
|
||||||
|
$result = $aio_wp_security->scan_obj->execute_file_change_detection_scan();
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
// error case
|
||||||
|
$message = __('There was an error during the file change detection scan.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Please check the plugin debug logs.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $this->handle_response(false, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_last_scan_time', time(), true);
|
||||||
|
|
||||||
|
// If this is first scan display special message
|
||||||
|
if (1 == $result['initial_scan']) {
|
||||||
|
$extra_args['result'] = __('This is your first file change detection scan.', 'all-in-one-wp-security-and-firewall').' '.__('The details from this scan will be used for future scans.', 'all-in-one-wp-security-and-firewall'). ' <a href="#" class="aiowps_view_last_fcd_results">' . __('View the file scan results', 'all-in-one-wp-security-and-firewall') . '</a>';
|
||||||
|
$content['aiowps-previous-files-scan-inner'] = '<a href="#" class="aiowps_view_last_fcd_results">' . __('View last file scan results', 'all-in-one-wp-security-and-firewall') . '</a>';
|
||||||
|
} elseif (!$aio_wp_security->configs->get_value('aiowps_fcds_change_detected')) {
|
||||||
|
$extra_args['result'] = __('The scan is complete - There were no file changes detected.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ($aio_wp_security->configs->get_value('aiowps_fcds_change_detected')) {
|
||||||
|
$extra_args['result'] = __('The scan has detected that there was a change in your website\'s files.', 'all-in-one-wp-security-and-firewall'). ' <a href="#" class="aiowps_view_last_fcd_results">' . __('View the file scan results', 'all-in-one-wp-security-and-firewall') . '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'extra_args' => $extra_args,
|
||||||
|
'content' => $content
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the legacy UDC Scanner.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_scanner_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
|
||||||
|
|
||||||
|
$scanner_data = $this->get_scanner_data();
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/scanner/file-change-detect.php', true, $scanner_data);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return file scanner data.
|
||||||
|
*
|
||||||
|
* @return array Array of option values,
|
||||||
|
*/
|
||||||
|
public function get_scanner_data() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$fcd_data = AIOWPSecurity_Scan::get_fcd_data();
|
||||||
|
$previous_scan = isset($fcd_data['last_scan_result']);
|
||||||
|
|
||||||
|
$next_fcd_scan_time = AIOWPSecurity_Scan::get_next_scheduled_scan();
|
||||||
|
|
||||||
|
$aiowps_fcds_change_detected = $aio_wp_security->configs->get_value('aiowps_fcds_change_detected');
|
||||||
|
$aiowps_enable_automated_fcd_scan = $aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan');
|
||||||
|
$aiowps_fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency');
|
||||||
|
$aiowps_fcd_scan_interval = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval');
|
||||||
|
$aiowps_fcd_exclude_filetypes = $aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes');
|
||||||
|
$aiowps_fcd_exclude_files = $aio_wp_security->configs->get_value('aiowps_fcd_exclude_files');
|
||||||
|
$aiowps_send_fcd_scan_email = $aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email');
|
||||||
|
$aiowps_fcd_scan_email_address = $aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address');
|
||||||
|
$aiowps_last_scan_time = $aio_wp_security->configs->get_value('aiowps_last_scan_time');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'previous_scan' => $previous_scan,
|
||||||
|
'next_fcd_scan_time' => false === $next_fcd_scan_time ? '' : AIOWPSecurity_Utility::convert_timestamp($next_fcd_scan_time, 'D, F j, Y H:i'),
|
||||||
|
'aiowps_fcds_change_detected' => $aiowps_fcds_change_detected,
|
||||||
|
'aiowps_enable_automated_fcd_scan' => $aiowps_enable_automated_fcd_scan,
|
||||||
|
'aiowps_fcd_scan_frequency' => $aiowps_fcd_scan_frequency,
|
||||||
|
'aiowps_fcd_scan_interval' => $aiowps_fcd_scan_interval,
|
||||||
|
'aiowps_fcd_exclude_filetypes' => $aiowps_fcd_exclude_filetypes,
|
||||||
|
'aiowps_fcd_exclude_files' => $aiowps_fcd_exclude_files,
|
||||||
|
'aiowps_send_fcd_scan_email' => $aiowps_send_fcd_scan_email,
|
||||||
|
'aiowps_fcd_scan_email_address' => $aiowps_fcd_scan_email_address,
|
||||||
|
'aiowps_last_scan_time' => AIOWPSecurity_Utility::convert_timestamp($aiowps_last_scan_time, 'D, F j, Y H:i'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+224
@@ -0,0 +1,224 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Files_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Files_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs file permission fixing
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the files items
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_fix_permissions($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$files_dirs_to_check = AIOWPSecurity_Utility_File::get_files_and_dirs_to_check();
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
if (isset($data['aiowps_permission_chg_file'])) {
|
||||||
|
$file_found = false;
|
||||||
|
$folder_or_file = sanitize_text_field($data['aiowps_permission_chg_file']);
|
||||||
|
$rec_perm_oct_string = '';
|
||||||
|
foreach ($files_dirs_to_check as $file_or_dir) {
|
||||||
|
if ($folder_or_file == $file_or_dir['path']) {
|
||||||
|
$file_found = true;
|
||||||
|
$rec_perm_oct_string = $file_or_dir['permissions'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($file_found && !empty($rec_perm_oct_string)) {
|
||||||
|
$rec_perm_dec = octdec($rec_perm_oct_string); // Convert the octal string to dec so the chmod func will accept it
|
||||||
|
$perm_result = @chmod($folder_or_file, $rec_perm_dec);
|
||||||
|
if (true === $perm_result) {
|
||||||
|
$message = sprintf(__('The permissions for %s were successfully changed to %s', 'all-in-one-wp-security-and-firewall'), htmlspecialchars($folder_or_file), htmlspecialchars($rec_perm_oct_string));
|
||||||
|
} elseif (false === $perm_result) {
|
||||||
|
$message = sprintf(__('Unable to change permissions for %s', 'all-in-one-wp-security-and-firewall'), htmlspecialchars($folder_or_file));
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = sprintf(__('Unable to change permissions for %s : not in list of valid files', 'all-in-one-wp-security-and-firewall'), htmlspecialchars($folder_or_file));
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$badges = array("filesystem-file-permissions");
|
||||||
|
$content = array('aios_file_permissions_table' => $aio_wp_security->include_template('wp-admin/filesystem-security/partials/file-permissions-table.php', true, array('files_dirs_to_check' => $files_dirs_to_check, 'file_utility' => new AIOWPSecurity_Utility_File())));
|
||||||
|
$args = array(
|
||||||
|
'content' => $content,
|
||||||
|
'badges' => $badges,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs file protection settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the settings
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_file_protection_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
// Update settings for delete readme.html and wp-config-sample.php.
|
||||||
|
$options['aiowps_auto_delete_default_wp_files'] = isset($data['aiowps_auto_delete_default_wp_files']) ? '1' : '';
|
||||||
|
|
||||||
|
// Update settings for prevent hotlinking.
|
||||||
|
$options['aiowps_prevent_hotlinking'] = isset($data['aiowps_prevent_hotlinking']) ? '1' : '';
|
||||||
|
|
||||||
|
// Update settings for php file editing
|
||||||
|
$disable_file_editing = isset($data["aiowps_disable_file_editing"]) ? '1' : '';
|
||||||
|
$disable_file_editing_status = $disable_file_editing ? AIOWPSecurity_Utility::disable_file_edits() : AIOWPSecurity_Utility::enable_file_edits();
|
||||||
|
if ($disable_file_editing_status) {
|
||||||
|
// Save settings if no errors
|
||||||
|
$options['aiowps_disable_file_editing'] = $disable_file_editing;
|
||||||
|
} else {
|
||||||
|
$message = __('Disable PHP file editing failed: unable to modify or make a backup of the wp-config.php file.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $this->handle_response(false, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_Htaccess::write_to_htaccess() && '' !== $options['aiowps_prevent_hotlinking']) {
|
||||||
|
|
||||||
|
// Now let's write the applicable rules to the .htaccess file
|
||||||
|
$res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
|
||||||
|
|
||||||
|
if ($res) {
|
||||||
|
$message = __('The settings have been successfully updated', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$success = false;
|
||||||
|
$message = __('Could not write to the .htaccess file.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
// revert options affected by .htaccess write fail
|
||||||
|
$options['aiowps_prevent_hotlinking'] = $aio_wp_security->configs->get_value('aiowps_prevent_hotlinking');
|
||||||
|
$this->save_settings($options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$features = array(
|
||||||
|
"auto-delete-wp-files",
|
||||||
|
"prevent-hotlinking",
|
||||||
|
"filesystem-file-editing",
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, array('badges' => $features));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs deleting default wp files
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_delete_default_wp_files() {
|
||||||
|
$success = true;
|
||||||
|
$message = __('The files have been deleted successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
$result = AIOWPSecurity_Utility::delete_unneeded_default_files();
|
||||||
|
|
||||||
|
if (!empty($result['error'])) {
|
||||||
|
$success = false;
|
||||||
|
$message = sprintf(__('Failed to delete the %s file(s).', 'all-in-one-wp-security-and-firewall'), $result['error']) . '<br>' . __('Please try to delete them manually.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, array('info' => $result['info']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs save copy protection settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_save_copy_protection($data) {
|
||||||
|
$this->save_settings(array('aiowps_copy_protection' => isset($data["aiowps_copy_protection"]) ? '1' : ''));
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', array('badges' => array('enable-copy-protection')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs save frame display prevent setting
|
||||||
|
*
|
||||||
|
* @param array $data - the request data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_save_frame_display_prevent($data) {
|
||||||
|
$this->save_settings(array('aiowps_prevent_site_display_inside_frame' => isset($data["aiowps_prevent_site_display_inside_frame"]) ? '1' : ''));
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', array('badges' => array('enable-frame-protection')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs host system logs
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the lgos settings
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_host_system_logs($data) {
|
||||||
|
|
||||||
|
$content = array();
|
||||||
|
$success = true;
|
||||||
|
$message = false;
|
||||||
|
|
||||||
|
if (isset($data['aiowps_system_log_file'])) {
|
||||||
|
if ('' != $data['aiowps_system_log_file']) {
|
||||||
|
$sys_log_file = basename(sanitize_text_field($data['aiowps_system_log_file']));
|
||||||
|
} else {
|
||||||
|
$sys_log_file = 'error_log';
|
||||||
|
}
|
||||||
|
$this->save_settings(array('aiowps_system_log_file' => $sys_log_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
$logResults = AIOWPSecurity_Utility_File::recursive_file_search($sys_log_file, 0, ABSPATH);
|
||||||
|
|
||||||
|
if (empty($logResults) || '' == $logResults) {
|
||||||
|
$success = false;
|
||||||
|
$message = __('No system logs were found.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$content['aios-host-system-logs-results'] = '';
|
||||||
|
foreach ($logResults as $file) {
|
||||||
|
$content['aios-host-system-logs-results'] .= $this->display_system_logs_in_table($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = array('aiowps_system_log_file' => $sys_log_file);
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'content' => $content,
|
||||||
|
'values' => $values
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the last 50 entries of a system log file in a table format.
|
||||||
|
*
|
||||||
|
* This function reads the contents of the specified file and returns a
|
||||||
|
* rendered template displaying the last 50 entries of the log file.
|
||||||
|
*
|
||||||
|
* @param string $filepath The path to the log file to be read.
|
||||||
|
*
|
||||||
|
* @return string The rendered HTML template displaying the log entries.
|
||||||
|
*/
|
||||||
|
private function display_system_logs_in_table($filepath) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
// Get contents of the error_log file
|
||||||
|
$last_50_entries = AIOWPSecurity_Utility_File::read_file_lines($filepath, -1, 50, true);
|
||||||
|
return $aio_wp_security->include_template('wp-admin/filesystem-security/filesystem-log-result.php', true, array('filepath' => $filepath, 'last_50_entries' => $last_50_entries));
|
||||||
|
}
|
||||||
|
}
|
||||||
+787
@@ -0,0 +1,787 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Firewall_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Firewall_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform saving php firewall settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains PHP settings
|
||||||
|
*
|
||||||
|
* @return array - containing a status and message
|
||||||
|
*/
|
||||||
|
public function perform_php_firewall_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
$enable_pingback = isset($data["aiowps_enable_pingback_firewall"]);
|
||||||
|
$info = array();
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_enable_pingback_firewall', $enable_pingback);
|
||||||
|
$options['aiowps_disable_xmlrpc_pingback_methods'] = isset($data["aiowps_disable_xmlrpc_pingback_methods"]) ? '1' : ''; //this disables only pingback methods of xmlrpc but leaves other methods so that Jetpack and other apps will still work
|
||||||
|
$options['aiowps_disable_rss_and_atom_feeds'] = isset($data['aiowps_disable_rss_and_atom_feeds']) ? '1' : '';
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_forbid_proxy_comments', isset($data['aiowps_forbid_proxy_comments']));
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_deny_bad_query_strings', isset($data['aiowps_deny_bad_query_strings']));
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_advanced_char_string_filter', isset($data['aiowps_advanced_char_string_filter']));
|
||||||
|
|
||||||
|
$block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
|
||||||
|
$current_request_methods_settings = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
|
||||||
|
$current_other_settings = array(
|
||||||
|
$aiowps_firewall_config->get_value('aiowps_6g_block_query'),
|
||||||
|
$aiowps_firewall_config->get_value('aiowps_6g_block_request'),
|
||||||
|
$aiowps_firewall_config->get_value('aiowps_6g_block_referrers'),
|
||||||
|
$aiowps_firewall_config->get_value('aiowps_6g_block_agents'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$are_methods_set = !empty($current_request_methods_settings);
|
||||||
|
$are_others_set = array_reduce($current_other_settings, function($carry, $item) {
|
||||||
|
return $carry || $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (($are_methods_set || $are_others_set) && '1' !== $aio_wp_security->configs->get_value('aiowps_enable_6g_firewall')) {
|
||||||
|
$options['aiowps_enable_6g_firewall'] = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['aiowps_enable_6g_firewall'])) {
|
||||||
|
$aiowps_6g_block_request_methods = array_filter(AIOS_Abstracted_Ids::get_firewall_block_request_methods(), function($block_request_method) {
|
||||||
|
return ('PUT' != $block_request_method);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (false === $are_methods_set && false === $are_others_set) {
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_request_methods', $aiowps_6g_block_request_methods);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_query', true);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_request', true);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_referrers', true);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_agents', true);
|
||||||
|
} else {
|
||||||
|
$methods = array();
|
||||||
|
|
||||||
|
foreach ($block_request_methods as $block_request_method) {
|
||||||
|
if (isset($data['aiowps_block_request_method_'.$block_request_method])) {
|
||||||
|
$methods[] = strtoupper($block_request_method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_request_methods', $methods);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_query', isset($data['aiowps_block_query']));
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_request', isset($data['aiowps_block_request']));
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_referrers', isset($data['aiowps_block_refs']));
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_6g_block_agents', isset($data['aiowps_block_agents']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['aiowps_enable_6g_firewall'] = '1';
|
||||||
|
|
||||||
|
//shows the success notice
|
||||||
|
} else {
|
||||||
|
AIOWPSecurity_Configure_Settings::turn_off_all_6g_firewall_configs();
|
||||||
|
$options['aiowps_enable_6g_firewall'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_ban_post_blank_headers', isset($data['aiowps_ban_post_blank_headers']));
|
||||||
|
|
||||||
|
if (isset($data['aiowps_block_fake_googlebots'])) {
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility::get_googlebot_ip_ranges();
|
||||||
|
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$info[] = __('The attempt to save the \'Block fake Googlebots\' settings failed, because it was not possible to validate the Googlebot IP addresses:', 'all-in-one-wp-security-and-firewall') . ' ' . $validated_ip_list_array->get_error_message();
|
||||||
|
} else {
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_block_fake_googlebots', true);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_googlebot_ip_ranges', $validated_ip_list_array);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_block_fake_googlebots', false);
|
||||||
|
}
|
||||||
|
$options['aiowps_disallow_unauthorized_rest_requests'] = isset($data["aiowps_disallow_unauthorized_rest_requests"]) ? '1' : '';
|
||||||
|
|
||||||
|
$aios_whitelisted_rest_routes = array();
|
||||||
|
$route_namespaces = AIOWPSecurity_Utility::get_rest_namespaces();
|
||||||
|
foreach ($route_namespaces as $route_namespace) {
|
||||||
|
if (isset($data['aios_whitelisted_rest_routes_'.str_replace('-', '_', $route_namespace)])) {
|
||||||
|
$aios_whitelisted_rest_routes[] = $route_namespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$options['aios_whitelisted_rest_routes'] = $aios_whitelisted_rest_routes;
|
||||||
|
|
||||||
|
$aios_roles_disallowed_rest_requests = array();
|
||||||
|
$user_roles = AIOWPSecurity_Utility_Permissions::get_user_roles();
|
||||||
|
foreach ($user_roles as $id => $name) {
|
||||||
|
if (!isset($data['aios_allowed_roles_rest_requests_'.$id])) {
|
||||||
|
$aios_roles_disallowed_rest_requests[] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$options['aios_roles_disallowed_rest_requests'] = $aios_roles_disallowed_rest_requests;
|
||||||
|
|
||||||
|
// Commit the config settings
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
|
||||||
|
$methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
|
||||||
|
if (empty($methods)) {
|
||||||
|
$methods = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocked_query = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
|
||||||
|
$blocked_request = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
|
||||||
|
$blocked_referrers = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
|
||||||
|
$blocked_agents = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
|
||||||
|
$content = array('aios-6g-firewall-settings-container .aios-advanced-options-panel' => $aio_wp_security->include_template('wp-admin/firewall/partials/advanced-settings-6g.php', true, compact('methods', 'blocked_query', 'blocked_request', 'blocked_referrers', 'blocked_agents', 'block_request_methods')));
|
||||||
|
|
||||||
|
$features = array(
|
||||||
|
'firewall-pingback-rules',
|
||||||
|
'firewall-disable-rss-and-atom',
|
||||||
|
'firewall-forbid-proxy-comments',
|
||||||
|
'firewall-deny-bad-queries',
|
||||||
|
'firewall-advanced-character-string-filter',
|
||||||
|
'firewall-enable-6g',
|
||||||
|
'firewall-block-fake-googlebots',
|
||||||
|
'firewall-ban-post-blank-headers',
|
||||||
|
'disallow-unauthorised-requests',
|
||||||
|
);
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => $features,
|
||||||
|
'content' => $content,
|
||||||
|
'info' => $info,
|
||||||
|
'extra_args' => array('xmlprc_warning' => $enable_pingback ? $aio_wp_security->include_template('wp-admin/firewall/partials/xmlrpc-warning-notice.php', true) : '')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform saving .htaccess firewall settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains the firewall settings
|
||||||
|
*
|
||||||
|
* @return array - containing a status and message
|
||||||
|
*/
|
||||||
|
public function perform_htaccess_firewall_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
$info = array();
|
||||||
|
$message = '';
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
// Max file upload size in basic rules
|
||||||
|
$upload_size = absint($data['aiowps_max_file_upload_size']);
|
||||||
|
|
||||||
|
$max_allowed = apply_filters('aiowps_max_allowed_upload_config', 250); // Set a filterable limit of 250MB
|
||||||
|
$max_allowed = absint($max_allowed);
|
||||||
|
|
||||||
|
if ($upload_size > $max_allowed) {
|
||||||
|
$upload_size = $max_allowed;
|
||||||
|
} elseif (empty($upload_size) || 0 > $upload_size) {
|
||||||
|
$upload_size = AIOS_FIREWALL_MAX_FILE_UPLOAD_LIMIT_MB;
|
||||||
|
$info[] = __('Max file upload limit was set to default value, because you entered a negative or zero value');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the current value in case the .htaccess write operation fails and we need to revert it
|
||||||
|
$original_options = array(
|
||||||
|
'aiowps_enable_basic_firewall' => $aio_wp_security->configs->get_value("aiowps_enable_basic_firewall"),
|
||||||
|
'aiowps_max_file_upload_size' => $aio_wp_security->configs->get_value('aiowps_max_file_upload_size'),
|
||||||
|
'aiowps_block_debug_log_file_access' => $aio_wp_security->configs->get_value("aiowps_block_debug_log_file_access"),
|
||||||
|
'aiowps_disable_index_views' => $aio_wp_security->configs->get_value('aiowps_disable_index_views'),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$options['aiowps_enable_basic_firewall'] = isset($data["aiowps_enable_basic_firewall"]) ? '1' : '';
|
||||||
|
$options['aiowps_max_file_upload_size'] = $upload_size;
|
||||||
|
$options['aiowps_block_debug_log_file_access'] = isset($data["aiowps_block_debug_log_file_access"]) ? '1' : '';
|
||||||
|
$options['aiowps_disable_index_views'] = isset($data['aiowps_disable_index_views']) ? '1' : '';
|
||||||
|
|
||||||
|
// Commit the config settings
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
//Now let's write the applicable rules to the .htaccess file
|
||||||
|
$res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
|
||||||
|
|
||||||
|
if (!$res) {
|
||||||
|
$success = false;
|
||||||
|
$message = __('Could not write to the .htaccess file', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
$this->save_settings($original_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$features = array(
|
||||||
|
'firewall-basic-rules',
|
||||||
|
'firewall-block-debug-file-access',
|
||||||
|
'firewall-disable-index-views',
|
||||||
|
);
|
||||||
|
|
||||||
|
$values = array('aiowps_max_file_upload_size' => $upload_size);
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => $features,
|
||||||
|
'info' => $info,
|
||||||
|
'values' => $values
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and update the 5G firewall settings, and conditionally update the .htaccess file if needed.
|
||||||
|
*
|
||||||
|
* This function handles the saving of the 5G firewall settings based on user input. It checks if
|
||||||
|
* the 5G firewall setting has been modified and writes the applicable rules to the .htaccess file
|
||||||
|
* if necessary. In case of failure to write to the .htaccess file, it returns an error message.
|
||||||
|
*
|
||||||
|
* @param array $data The data array containing the 5G firewall setting.
|
||||||
|
*
|
||||||
|
* @global object $aio_wp_security The global instance of the All-In-One WP Security & Firewall plugin.
|
||||||
|
*
|
||||||
|
* @return array An array containing the status ('success' or 'error') and a message indicating
|
||||||
|
* the result of the operation.
|
||||||
|
*/
|
||||||
|
public function perform_save_5g_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => __('The settings were successfully updated.', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
// If the user has changed the 5G firewall checkbox settings, then there is a need to write htaccess rules again.
|
||||||
|
$is_5G_firewall_option_changed = ((isset($data['aiowps_enable_5g_firewall']) && '1' != $aio_wp_security->configs->get_value('aiowps_enable_5g_firewall')) || (!isset($data['aiowps_enable_5g_firewall']) && '1' == $aio_wp_security->configs->get_value('aiowps_enable_5g_firewall')));
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$options['aiowps_enable_5g_firewall'] = isset($data['aiowps_enable_5g_firewall']) ? '1' : '';
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$res = true;
|
||||||
|
|
||||||
|
if ($is_5G_firewall_option_changed) {
|
||||||
|
$res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); // let's write the applicable rules to the .htaccess file
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$res) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = __('Could not write to the .htaccess file for the 5G firewall settings, please check the file permissions.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
// revert settings
|
||||||
|
$options['aiowps_enable_5g_firewall'] = '';
|
||||||
|
$this->save_settings($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform saving blacklist settings
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains blacklist settings
|
||||||
|
*
|
||||||
|
* @return array - containing a status, message and feature badge html
|
||||||
|
*/
|
||||||
|
public function perform_save_blacklist_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
$message = '';
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
$result = 1;
|
||||||
|
$aiowps_enable_blacklisting = isset($data["aiowps_enable_blacklisting"]) ? '1' : '';
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_banned_ip_addresses'])) {
|
||||||
|
$ip_addresses = sanitize_textarea_field(stripslashes($data['aiowps_banned_ip_addresses']));
|
||||||
|
$ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'blacklist');
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$result = -1;
|
||||||
|
$success = false;
|
||||||
|
$message = nl2br($validated_ip_list_array->get_error_message());
|
||||||
|
} else {
|
||||||
|
$banned_ip_addresses_list = preg_split('/\R/', $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses')); // Historical settings where the separator may have depended on PHP_EOL.
|
||||||
|
if ($banned_ip_addresses_list !== $validated_ip_list_array) {
|
||||||
|
$banned_ip_data = implode("\n", $validated_ip_list_array);
|
||||||
|
$options['aiowps_banned_ip_addresses'] = $banned_ip_data;
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_blacklist_ips', $validated_ip_list_array);
|
||||||
|
}
|
||||||
|
$data['aiowps_banned_ip_addresses'] = ''; // Clear the post variable for the banned address list.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$options['aiowps_banned_ip_addresses'] = ''; // Clear the IP address config value
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_blacklist_ips', array());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_banned_user_agents'])) {
|
||||||
|
$this->validate_user_agent_list(stripslashes($data['aiowps_banned_user_agents']));
|
||||||
|
} else {
|
||||||
|
// Clear the user agent list
|
||||||
|
$options['aiowps_banned_user_agents'] = '';
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', array());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == $result) {
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enable_blacklisting', $aiowps_enable_blacklisting, true);
|
||||||
|
if ('1' == $aio_wp_security->configs->get_value('aiowps_is_ip_blacklist_settings_notice_on_upgrade')) {
|
||||||
|
$aio_wp_security->configs->delete_value('aiowps_is_ip_blacklist_settings_notice_on_upgrade');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'badges' => array("blacklist-manager-ip-user-agent-blacklisting")
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AJAX function for storing ips in firewall allowlist
|
||||||
|
*
|
||||||
|
* @param array $data - the request data contains data to updated
|
||||||
|
*
|
||||||
|
* @return array - containing a status and message
|
||||||
|
*/
|
||||||
|
public function perform_firewall_allowlist($data) {
|
||||||
|
$aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$success = true;
|
||||||
|
$allowlist = $data['aios_firewall_allowlist'];
|
||||||
|
|
||||||
|
if (empty($allowlist)) {
|
||||||
|
$aiowps_firewall_allow_list::add_ips('');
|
||||||
|
return $this->handle_response(true, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ips = sanitize_textarea_field(wp_unslash($allowlist));
|
||||||
|
$ips = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ips);
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ips, 'firewall_allowlist');
|
||||||
|
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$success = false;
|
||||||
|
$message = nl2br($validated_ip_list_array->get_error_message());
|
||||||
|
} else {
|
||||||
|
$aiowps_firewall_allow_list::add_ips($validated_ip_list_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AJAX function for saving PHP firewall and block and allowlists in UDC.
|
||||||
|
*
|
||||||
|
* @param array $data The data send from UDC.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function perform_save_firewall($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->perform_firewall_allowlist($data);
|
||||||
|
if ('error' === $response['status']) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->perform_save_blacklist_settings($data);
|
||||||
|
if ('error' === $response['status']) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->perform_php_firewall_settings($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the setup process for the firewall.
|
||||||
|
*
|
||||||
|
* This function handles the setup form for the firewall and renders notices accordingly.
|
||||||
|
*
|
||||||
|
* @return array An array containing the content and message for the response.
|
||||||
|
*/
|
||||||
|
public function perform_setup_firewall() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$firewall_setup = AIOWPSecurity_Firewall_Setup_Notice::get_instance();
|
||||||
|
$content = array('aiowps-firewall-status-container' => $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-set-up-button.php', true));
|
||||||
|
|
||||||
|
$firewall_setup->do_setup();
|
||||||
|
ob_start();
|
||||||
|
$firewall_setup->render_notices();
|
||||||
|
$result = ob_get_clean();
|
||||||
|
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'content' => $content,
|
||||||
|
'extra_args' => array('info_box' => $result)
|
||||||
|
);
|
||||||
|
|
||||||
|
$message = false;
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) {
|
||||||
|
$content['aiowps-firewall-status-container'] = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-downgrade-button.php', true);
|
||||||
|
$message = __('Firewall has been setup successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$args['content'] = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response(AIOWPSecurity_Utility_Firewall::is_firewall_setup(), $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the downgrade process for the firewall.
|
||||||
|
*
|
||||||
|
* This function removes the firewall and returns a response indicating success.
|
||||||
|
*
|
||||||
|
* @return array An array containing the status, content, and message for the response.
|
||||||
|
*/
|
||||||
|
public function perform_downgrade_firewall() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
AIOWPSecurity_Utility_Firewall::remove_firewall();
|
||||||
|
|
||||||
|
$message = AIOWPSecurity_Utility_Firewall::is_firewall_setup() ? __('Something went wrong please try again later.', 'all-in-one-wp-security-and-firewall') : __('Firewall has been downgraded successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = true;
|
||||||
|
$downgrade_button = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-set-up-button.php', true);
|
||||||
|
$extra_args = array();
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_Firewall::is_firewall_setup()) {
|
||||||
|
$success = false;
|
||||||
|
$downgrade_button = $aio_wp_security->include_template('wp-admin/firewall/partials/firewall-downgrade-button.php', true);
|
||||||
|
} else {
|
||||||
|
$extra_args['info_box'] = $aio_wp_security->include_template('notices/firewall-setup-notice.php', true, array('show_dismiss' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'content' => array('aiowps-firewall-status-container' => $downgrade_button),
|
||||||
|
'extra_args' => $extra_args
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates posted user agent list and set, save as config.
|
||||||
|
*
|
||||||
|
* @param string $banned_user_agents - List of banned user agents
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function validate_user_agent_list($banned_user_agents) {
|
||||||
|
$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'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$aiowps_firewall_config->set_value('aiowps_blacklist_user_agents', $agents);
|
||||||
|
$this->save_settings(array(
|
||||||
|
'aiowps_banned_user_agents' => implode("\n", $agents)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs save upgrade unsafe http calls settings.
|
||||||
|
*
|
||||||
|
* @param array $data - The request data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function perform_save_upgrade_unsafe_http_calls_settings($data) {
|
||||||
|
$upgrade_unsafe_http_calls_url_exceptions = sanitize_textarea_field(wp_unslash($data['aiowps_upgrade_unsafe_http_calls_url_exceptions']));
|
||||||
|
|
||||||
|
$errors = '';
|
||||||
|
|
||||||
|
if (!empty($upgrade_unsafe_http_calls_url_exceptions)) {
|
||||||
|
foreach (preg_split('/\R/', $upgrade_unsafe_http_calls_url_exceptions) as $url) {
|
||||||
|
$url = sanitize_url($url);
|
||||||
|
|
||||||
|
if (empty($url)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === strpos($url, '#')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed_url = parse_url($url); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- Using the same function as WordPress in order to not preclude URLs that would be allowed by WordPress.
|
||||||
|
|
||||||
|
if (empty($parsed_url['scheme'])) { // The same weak sanity check used by the WordPress wp_remote_* functions.
|
||||||
|
/* translators: %s URL entered by user. */
|
||||||
|
$errors .= "\n" . sprintf(__('%s is not a valid url.', 'all-in-one-wp-security-and-firewall'), $url);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($errors)) {
|
||||||
|
return $this->handle_response(false, nl2br(trim($errors)), array('badges' => array('upgrade-unsafe-http-calls')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings(array(
|
||||||
|
'aiowps_upgrade_unsafe_http_calls' => isset($data['aiowps_upgrade_unsafe_http_calls']) ? '1' : '',
|
||||||
|
'aiowps_upgrade_unsafe_http_calls_url_exceptions' => $upgrade_unsafe_http_calls_url_exceptions
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', array('badges' => array('upgrade-unsafe-http-calls')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the PHP firewall rules for the legacy UDC theme.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_php_firewall_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
|
||||||
|
$php_firewall_data = $this->get_php_firewall_data();
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('/wp-admin/firewall/php-firewall-rules.php', true, compact('php_firewall_data'));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $php_firewall_data['no_firewall'] . $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the .htaccess firewall rules for the legacy UDC theme.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_htaccess_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
|
||||||
|
|
||||||
|
$htaccess_rules_data = $this->get_htaccess_rules_data();
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('/wp-admin/firewall/htaccess-firewall-rules.php', true, compact('htaccess_rules_data'));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the Block & Allow Lists for the legacy UDC theme.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_block_allow_lists_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
/* Needed for submit_button() */
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/template.php');
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
|
||||||
|
|
||||||
|
$block_allowlist_data = $this->get_block_allow_lists_data();
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/firewall/block-and-allow-lists.php', true, $block_allowlist_data);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the Advanced Settings for the legacy UDC theme.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_advanced_settings_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_feature_mgr'] = $this->get_feature_mgr_object();
|
||||||
|
|
||||||
|
$advanced_settings_data = $this->get_firewall_advanced_settings_data();
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/firewall/advanced-settings.php', true, compact('advanced_settings_data'));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data for the advanced firewall.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_firewall_advanced_settings_data() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aiowps_upgrade_unsafe_http_calls = $aio_wp_security->configs->get_value('aiowps_upgrade_unsafe_http_calls');
|
||||||
|
$aiowps_upgrade_unsafe_http_calls_url_exceptions = $aio_wp_security->configs->get_value('aiowps_upgrade_unsafe_http_calls_url_exceptions');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'aiowps_upgrade_unsafe_http_calls' => $aiowps_upgrade_unsafe_http_calls,
|
||||||
|
'aiowps_upgrade_unsafe_http_calls_url_exceptions' => $aiowps_upgrade_unsafe_http_calls_url_exceptions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data for the allow & block lists.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_block_allow_lists_data() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aiowps_enable_blacklisting = $aio_wp_security->configs->get_value('aiowps_enable_blacklisting');
|
||||||
|
$aiowps_banned_ip_addresses = $aio_wp_security->configs->get_value('aiowps_banned_ip_addresses');
|
||||||
|
$aiowps_banned_user_agents = $aio_wp_security->configs->get_value('aiowps_banned_user_agents');
|
||||||
|
|
||||||
|
$aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
|
||||||
|
$allowlist = $aiowps_firewall_allow_list::get_ips();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'aiowps_enable_blacklisting' => $aiowps_enable_blacklisting,
|
||||||
|
'aiowps_banned_ip_addresses' => $aiowps_banned_ip_addresses,
|
||||||
|
'aiowps_banned_user_agents' => $aiowps_banned_user_agents,
|
||||||
|
'allowlist' => $allowlist,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data for the .htaccess rules.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_htaccess_rules_data() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aiowps_enable_basic_firewall = $aio_wp_security->configs->get_value('aiowps_enable_basic_firewall');
|
||||||
|
$aiowps_max_file_upload_size = $aio_wp_security->configs->get_value('aiowps_max_file_upload_size');
|
||||||
|
$aiowps_block_debug_log_file_access = $aio_wp_security->configs->get_value('aiowps_block_debug_log_file_access');
|
||||||
|
$aiowps_disable_index_views = $aio_wp_security->configs->get_value('aiowps_disable_index_views');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'aiowps_enable_basic_firewall' => $aiowps_enable_basic_firewall,
|
||||||
|
'aiowps_max_file_upload_size' => $aiowps_max_file_upload_size,
|
||||||
|
'aiowps_block_debug_log_file_access' => $aiowps_block_debug_log_file_access,
|
||||||
|
'aiowps_disable_index_views' => $aiowps_disable_index_views,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data for the PHP firewall.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_php_firewall_data() {
|
||||||
|
global $aio_wp_security, $aiowps_firewall_config, $aiowps_feature_mgr;
|
||||||
|
|
||||||
|
$is_udc_request = AIOS_Helper::is_updraft_central_request();
|
||||||
|
|
||||||
|
$block_request_methods = array_map('strtolower', AIOS_Abstracted_Ids::get_firewall_block_request_methods());
|
||||||
|
|
||||||
|
$no_firewall_notice = '';
|
||||||
|
$user_roles = array();
|
||||||
|
|
||||||
|
// Load required data from config
|
||||||
|
if (!empty($aiowps_firewall_config)) {
|
||||||
|
// firewall config is available
|
||||||
|
$methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
|
||||||
|
if (empty($methods)) {
|
||||||
|
$methods = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocked_query = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
|
||||||
|
$blocked_request = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
|
||||||
|
$blocked_referrers = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
|
||||||
|
$blocked_agents = (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
|
||||||
|
|
||||||
|
if (empty($methods) && (!$blocked_query && !$blocked_request && !$blocked_referrers && !$blocked_agents) && '1' == $aio_wp_security->configs->get_value('aiowps_enable_6g_firewall')) {
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enable_6g_firewall', '');
|
||||||
|
$aio_wp_security->configs->save_config();
|
||||||
|
$aiowps_feature_mgr->check_feature_status_and_recalculate_points();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if ($is_udc_request) {
|
||||||
|
ob_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="notice notice-error">
|
||||||
|
<p><strong><?php esc_html_e('All-In-One Security', 'all-in-one-wp-security-and-firewall'); ?></strong></p>
|
||||||
|
<p><?php esc_html_e('We were unable to access the firewall\'s configuration file:', '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_firewall_rules_path() . 'settings.php'); ?></pre>
|
||||||
|
<p><?php esc_html_e('As a result, the firewall will be unavailable.', 'all-in-one-wp-security-and-firewall');?></p>
|
||||||
|
<p><?php esc_html_e('Please check your PHP error log for further information.', 'all-in-one-wp-security-and-firewall');?></p>
|
||||||
|
<p><?php esc_html_e('If you\'re unable to locate your PHP log file, please contact your web hosting company to ask them where it can be found on their setup.', 'all-in-one-wp-security-and-firewall');?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if ($is_udc_request) {
|
||||||
|
$no_firewall_notice .= ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
//set default variables
|
||||||
|
$methods = array();
|
||||||
|
$blocked_query = false;
|
||||||
|
$blocked_request = false;
|
||||||
|
$blocked_referrers = false;
|
||||||
|
$blocked_agents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aiowps_enable_6g_firewall = $aio_wp_security->configs->get_value('aiowps_enable_6g_firewall');
|
||||||
|
$advanced_options_disabled = '1' != $aiowps_enable_6g_firewall;
|
||||||
|
|
||||||
|
$settings = array_merge(array('methods' => $methods), compact('aiowps_enable_6g_firewall', 'blocked_query', 'blocked_request', 'blocked_referrers', 'blocked_agents', 'block_request_methods', 'aiowps_firewall_config', 'advanced_options_disabled'));
|
||||||
|
|
||||||
|
$aiowps_enable_pingback_firewall = $aiowps_firewall_config->get_value('aiowps_enable_pingback_firewall');
|
||||||
|
$aiowps_disable_xmlrpc_pingback_methods = $aio_wp_security->configs->get_value('aiowps_disable_xmlrpc_pingback_methods');
|
||||||
|
$aiowps_disable_rss_and_atom_feeds = $aio_wp_security->configs->get_value('aiowps_disable_rss_and_atom_feeds');
|
||||||
|
$aiowps_forbid_proxy_comments = $aiowps_firewall_config->get_value('aiowps_forbid_proxy_comments');
|
||||||
|
$aiowps_deny_bad_query_strings = $aiowps_firewall_config->get_value('aiowps_deny_bad_query_strings');
|
||||||
|
$aiowps_advanced_char_string_filter = $aiowps_firewall_config->get_value('aiowps_advanced_char_string_filter');
|
||||||
|
|
||||||
|
$aiowps_disallow_unauthorized_rest_requests = $aio_wp_security->configs->get_value('aiowps_disallow_unauthorized_rest_requests');
|
||||||
|
$aios_roles_disallowed_rest_requests = $aio_wp_security->configs->get_value('aios_roles_disallowed_rest_requests');
|
||||||
|
$aios_whitelisted_rest_routes = $aio_wp_security->configs->get_value('aios_whitelisted_rest_routes');
|
||||||
|
$aiowps_block_fake_googlebots = $aiowps_firewall_config->get_value('aiowps_block_fake_googlebots');
|
||||||
|
$aiowps_ban_post_blank_headers = $aiowps_firewall_config->get_value('aiowps_ban_post_blank_headers');
|
||||||
|
|
||||||
|
$wp_user_roles = AIOWPSecurity_Utility_Permissions::get_user_roles();
|
||||||
|
foreach ($wp_user_roles as $role => $role_name) {
|
||||||
|
$user_roles[] = $role;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'aiowps_enable_pingback_firewall' => $aiowps_enable_pingback_firewall,
|
||||||
|
'aiowps_disable_xmlrpc_pingback_methods' => $aiowps_disable_xmlrpc_pingback_methods,
|
||||||
|
'aiowps_disable_rss_and_atom_feeds' => $aiowps_disable_rss_and_atom_feeds,
|
||||||
|
'aiowps_forbid_proxy_comments' => $aiowps_forbid_proxy_comments,
|
||||||
|
'aiowps_deny_bad_query_strings' => $aiowps_deny_bad_query_strings,
|
||||||
|
'aiowps_advanced_char_string_filter' => $aiowps_advanced_char_string_filter,
|
||||||
|
'aiowps_disallow_unauthorized_rest_requests' => $aiowps_disallow_unauthorized_rest_requests,
|
||||||
|
'aios_roles_disallowed_rest_requests' => $aios_roles_disallowed_rest_requests,
|
||||||
|
'aios_whitelisted_rest_routes' => $aios_whitelisted_rest_routes,
|
||||||
|
'user_roles' => $user_roles,
|
||||||
|
'aiowps_block_fake_googlebots' => $aiowps_block_fake_googlebots,
|
||||||
|
'aiowps_ban_post_blank_headers' => $aiowps_ban_post_blank_headers,
|
||||||
|
'ng_settings' => $settings,
|
||||||
|
'no_firewall' => $no_firewall_notice,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+133
@@ -0,0 +1,133 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Ip_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Ip_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks an IP.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the IP address to be unlocked.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function unlock_ip($data) {
|
||||||
|
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AIOWPSecurity_Utility::unlock_ip($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('Failed to unlock the selected IP address.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
} else {
|
||||||
|
return $this->handle_response(true, __('The selected IP address was unlocked successfully.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unblacklists an IP.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the IP address to be unblacklisted.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function unblacklist_ip($data) {
|
||||||
|
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AIOWPSecurity_Utility::unblacklist_ip($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('Failed to unblacklist the selected IP address.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
} else {
|
||||||
|
return $this->handle_response(true, __('The selected IP address was unblacklisted successfully.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unblocks an IP by permanent block record ID.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the ID of the entry in the AIOWPSEC_TBL_PERM_BLOCK table.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function blocked_ip_list_unblock_ip($data) {
|
||||||
|
|
||||||
|
if (!isset($data['id'])) {
|
||||||
|
return $this->handle_response(false, __('Invalid blocked IP ID provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/admin/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
|
||||||
|
$result = $blocked_ip_list->unblock_ip_address($data['id']);
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
$message = __('Failed to unblock and delete the selected record(s).', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$message = __('Successfully unblocked and deleted the selected record(s).', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
return $this->handle_response(true, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks an IP.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the IP address to be locked.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function lock_ip($data) {
|
||||||
|
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($data['lock_reason'])) {
|
||||||
|
return $this->handle_response(false, __('No lockout reason provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
AIOWPSecurity_Utility::lock_ip($data['ip'], $data['lock_reason']);
|
||||||
|
|
||||||
|
return $this->handle_response(true, __('The selected IP address is now temporarily locked.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blacklists an IP.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the IP address to be blacklisted.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function blacklist_ip($data) {
|
||||||
|
|
||||||
|
if (!isset($data['ip'])) {
|
||||||
|
return $this->handle_response(false, __('No IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($data['ip'], FILTER_VALIDATE_IP)) {
|
||||||
|
return $this->handle_response(false, __('Invalid IP provided.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = AIOWPSecurity_Utility::blacklist_ip($data['ip']);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) {
|
||||||
|
return $this->handle_response(false, nl2br($result->get_error_message()));
|
||||||
|
} else {
|
||||||
|
return $this->handle_response(true, __('The selected IP address has been added to the blacklist.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-log-commands.php
Executable
+345
@@ -0,0 +1,345 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Log_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Log_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an audit log.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the ID of the log to be deleted.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function delete_audit_log($data) {
|
||||||
|
|
||||||
|
if (!isset($data['id'])) {
|
||||||
|
return $this->handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(__('No audit log ID provided.', 'all-in-one-wp-security-and-firewall'), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php';
|
||||||
|
$audit_log_list = new AIOWPSecurity_List_Audit_Log();
|
||||||
|
|
||||||
|
return $this->handle_response(true, $audit_log_list->delete_audit_event_records($data['id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an IP lockout record.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the ID of the entry in the AIOWPSEC_TBL_LOGIN_LOCKOUT table.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function delete_locked_ip_record($data) {
|
||||||
|
|
||||||
|
if (!isset($data['id'])) {
|
||||||
|
return $this->handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(__('No locked IP record ID provided.', 'all-in-one-wp-security-and-firewall'), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-list-locked-ip.php';
|
||||||
|
|
||||||
|
$locked_ip_list = new AIOWPSecurity_List_Locked_IP();
|
||||||
|
$result = $locked_ip_list->delete_lockout_records($data['id']);
|
||||||
|
return $this->handle_response(true, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear debug logs
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function clear_debug_logs() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$ret = $aio_wp_security->debug_logger->clear_logs();
|
||||||
|
|
||||||
|
if (is_wp_error($ret)) {
|
||||||
|
return $this->handle_response(false, AIOWPSecurity_Admin_Menu::show_msg_error_st(esc_html($ret->get_error_message()).'<p>'.esc_html($ret->get_error_data()).'</p>', true));
|
||||||
|
} else {
|
||||||
|
return $this->handle_response(true, AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The debug logs have been cleared.', 'all-in-one-wp-security-and-firewall'), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the audit log tab content.
|
||||||
|
*
|
||||||
|
* This function handles the rendering of the audit log tab content based on the
|
||||||
|
* provided data via AJAX request. The data is used to filter the audit log or perform actions
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function render_audit_log_tab() {
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. Nonce checked in previous function.
|
||||||
|
if (empty($_POST['data'])) return;
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later.
|
||||||
|
$data = wp_unslash($_POST['data']);
|
||||||
|
|
||||||
|
// Needed for rendering the audit log table
|
||||||
|
include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php');
|
||||||
|
$audit_log_list = new AIOWPSecurity_List_Audit_Log($data);
|
||||||
|
$audit_log_list->ajax_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the audit logs as a CSV file and sends the data as an AJAX response.
|
||||||
|
*
|
||||||
|
* This function retrieves audit log data, prepares it for export, and generates a CSV string.
|
||||||
|
* The CSV data is then sent back as part of an AJAX response, along with the filename for the CSV file.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function export_audit_logs() {
|
||||||
|
|
||||||
|
// Needed for rendering the audit log table
|
||||||
|
include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php');
|
||||||
|
$audit_log_list = new AIOWPSecurity_List_Audit_Log();
|
||||||
|
|
||||||
|
$audit_log_list->prepare_items(true);
|
||||||
|
$export_keys = array(
|
||||||
|
'id' => 'ID',
|
||||||
|
'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')
|
||||||
|
);
|
||||||
|
|
||||||
|
$title = 'audit_event_logs.csv';
|
||||||
|
ob_start();
|
||||||
|
AIOWPSecurity_Admin_Init::aiowps_output_csv($audit_log_list->items, $export_keys, $title);
|
||||||
|
|
||||||
|
$data = ob_get_clean();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'title' => $title,
|
||||||
|
'data' => $data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializing the WP List API, since UDC commands do not load all parts of WP.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function init_wp_list() {
|
||||||
|
if (!function_exists('submit_button')) {
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/template.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('render_screen_reader_content')) {
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/class-wp-screen.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('get_column_headers')) {
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/screen.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data for downloading the audit log.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function process_audit_log_export() {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->init_wp_list();
|
||||||
|
|
||||||
|
return $this->export_audit_logs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTML for the audit log.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_audit_log_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$this->init_wp_list();
|
||||||
|
|
||||||
|
// Needed for rendering the audit log table
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/admin/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($_GET["tab"]) ? sanitize_text_field(wp_unslash($_GET["tab"])) : '';
|
||||||
|
$page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
|
||||||
|
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- PCP warning. Processing form data without nonce verification. No nonce.
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/dashboard/audit-logs.php', true, array('audit_log_list' => $audit_log_list, 'page' => $page, 'tab' => $tab));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes entry from audit log.
|
||||||
|
*
|
||||||
|
* @param array $data Table config data.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function do_delete_audit_log($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->init_wp_list();
|
||||||
|
|
||||||
|
if (!class_exists('AIOWPSecurity_Admin_Menu')) {
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-admin-menu.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->delete_audit_log($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders audit log after actions (delete/orderby, block/unblock, etc.)
|
||||||
|
*
|
||||||
|
* @param array $data Table config data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function do_render_audit_log_tab($data) {
|
||||||
|
$this->init_wp_list();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- PCP warning. Nonce checked in previous function.
|
||||||
|
if (empty($data)) return array();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later.
|
||||||
|
$data = wp_unslash($data);
|
||||||
|
|
||||||
|
if (!class_exists('AIOWPSecurity_Admin_Menu')) {
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/admin/wp-security-admin-menu.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed for rendering the audit log table
|
||||||
|
include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php');
|
||||||
|
$audit_log_list = new AIOWPSecurity_List_Audit_Log($data);
|
||||||
|
|
||||||
|
return $audit_log_list->ajax_response(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses raw audit log data for human-readable output.
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_List_Audit_Log $audit_log_list Audit log object.
|
||||||
|
* @param array $data Raw audit log data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function parse_audit_log_data($audit_log_list, $data) {
|
||||||
|
$items = array();
|
||||||
|
|
||||||
|
foreach ($data as $db_item) {
|
||||||
|
if (empty($db_item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = array();
|
||||||
|
|
||||||
|
foreach ($db_item as $key => $value) {
|
||||||
|
switch ($key) {
|
||||||
|
case 'created':
|
||||||
|
$item[$key] = AIOWPSecurity_Utility::convert_timestamp($value);
|
||||||
|
break;
|
||||||
|
case 'event_type':
|
||||||
|
$item[$key] = $audit_log_list->column_event_type($db_item);
|
||||||
|
break;
|
||||||
|
case 'details':
|
||||||
|
$item[$key] = $audit_log_list->column_details($db_item);
|
||||||
|
break;
|
||||||
|
case 'stacktrace':
|
||||||
|
$item[$key] = $audit_log_list->column_stacktrace($db_item);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$item[$key] = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data for the audit log table.
|
||||||
|
*
|
||||||
|
* @param array $data Configuration data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_audit_log_data($data) {
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- PCP warning. Nonce checked in previous function and sanitization done at later.
|
||||||
|
$data = isset($data) ? wp_unslash($data) : array();
|
||||||
|
|
||||||
|
$data = isset($data['data']) ? $data['data'] : $data;
|
||||||
|
|
||||||
|
$this->init_wp_list();
|
||||||
|
$final_column = array();
|
||||||
|
|
||||||
|
// Needed for rendering the audit log table
|
||||||
|
include_once(AIO_WP_SECURITY_PATH.'/admin/wp-security-list-audit.php');
|
||||||
|
$audit_log_list = new AIOWPSecurity_List_Audit_Log($data);
|
||||||
|
|
||||||
|
$audit_log_list->prepare_items();
|
||||||
|
|
||||||
|
list($columns, $hidden) = $audit_log_list->get_column_info();
|
||||||
|
|
||||||
|
foreach ($columns as $column_key => $column_display_name) {
|
||||||
|
if ('cb' !== $column_key) {
|
||||||
|
if (!in_array($column_key, $hidden, true)) {
|
||||||
|
$final_column[$column_key] = array('label' => $column_display_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$audit_log_items = isset($audit_log_list->items) ? $audit_log_list->items : array();
|
||||||
|
|
||||||
|
foreach ($audit_log_items as $key => $item) {
|
||||||
|
$ip = isset($item['ip']) ? $item['ip'] : '';
|
||||||
|
|
||||||
|
if ('' !== $ip) {
|
||||||
|
$audit_log_items[$key]['is_ip_locked'] = AIOWPSecurity_Utility::check_locked_ip($ip, 'audit-log');
|
||||||
|
$audit_log_items[$key]['is_ip_blacklisted'] = AIOWPSecurity_Utility::check_blacklist_ip($ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = $this->parse_audit_log_data($audit_log_list, $audit_log_items);
|
||||||
|
|
||||||
|
$bulk_actions = $audit_log_list->get_bulk_actions();
|
||||||
|
|
||||||
|
$paged = !empty($data['paged']) ? (int) $data['paged'] : 1;
|
||||||
|
|
||||||
|
AIOWPSecurity_Audit_Events::setup_event_types();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'audit_log_data' => array(
|
||||||
|
'bulk_actions' => $bulk_actions,
|
||||||
|
'event_types' => AIOWPSecurity_Audit_Events::$event_types,
|
||||||
|
'log_levels' => AIOWPSecurity_Audit_Events::$log_levels,
|
||||||
|
'columns' => $final_column,
|
||||||
|
'items' => $items,
|
||||||
|
'is_multisite' => is_multisite(),
|
||||||
|
'pagination' => array('page' => $paged, 'pages' => $audit_log_list->get_pagination_arg('total_pages'), 'results' => $audit_log_list->get_pagination_arg('total_items')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+562
@@ -0,0 +1,562 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Settings_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Settings_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to disable all security features.
|
||||||
|
*
|
||||||
|
* This method disables all security features provided by the AIOWPSecurity_Settings_Tasks class.
|
||||||
|
*
|
||||||
|
* @return array An associative array containing the status and messages of the operation.
|
||||||
|
* - 'status' : (string) The status of the operation, either 'success' or 'error'.
|
||||||
|
* - 'messages' : (array) An array of messages generated during the operation.
|
||||||
|
* Each message is represented as a string.
|
||||||
|
*/
|
||||||
|
public function perform_disable_all_features() {
|
||||||
|
|
||||||
|
$msg = AIOWPSecurity_Settings_Tasks::disable_all_security_features();
|
||||||
|
$success = true;
|
||||||
|
$info = array();
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
if (isset($msg['updated'])) {
|
||||||
|
$message = $msg['updated'];
|
||||||
|
}
|
||||||
|
if (isset($msg['error'])) {
|
||||||
|
$message = __('Some of the security features could not be disabled.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
foreach ($msg['error'] as $error_message) {
|
||||||
|
$info[] = $error_message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, array('info' => $info));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to disable all firewall rules.
|
||||||
|
*
|
||||||
|
* This method disables all firewall rules provided by the AIOWPSecurity_Settings_Tasks class.
|
||||||
|
*
|
||||||
|
* @return array An associative array containing the status and message of the operation.
|
||||||
|
* - 'status' : (string) The status of the operation, either 'success' or 'error'.
|
||||||
|
* - 'message' : (string) A message indicating the outcome of the operation.
|
||||||
|
* If the operation is successful, it contains an update message.
|
||||||
|
* If there is an error, it contains an error message.
|
||||||
|
*/
|
||||||
|
public function perform_disable_all_firewall_rules() {
|
||||||
|
$msg = AIOWPSecurity_Settings_Tasks::disable_all_firewall_rules();
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
if (isset($msg['updated'])) {
|
||||||
|
$message = $msg['updated'];
|
||||||
|
} elseif (isset($msg['error'])) {
|
||||||
|
$message = $msg['error'];
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to reset all settings.
|
||||||
|
*
|
||||||
|
* This method resets all settings provided by the AIOWPSecurity_Settings_Tasks class to their default values.
|
||||||
|
*
|
||||||
|
* @return array An associative array containing the status and message of the operation.
|
||||||
|
* - 'status' : (string) The status of the operation, either 'success' or 'error'.
|
||||||
|
* - 'message' : (string) A message indicating the outcome of the operation.
|
||||||
|
* If the operation is successful, it contains an update message.
|
||||||
|
* If there is an error, it contains an error message.
|
||||||
|
*/
|
||||||
|
public function perform_reset_all_settings() {
|
||||||
|
$msg = AIOWPSecurity_Settings_Tasks::reset_all_settings();
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
if (isset($msg['updated'])) {
|
||||||
|
$message = $msg['updated'];
|
||||||
|
} elseif (isset($msg['error'])) {
|
||||||
|
$message = $msg['error'];
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to save debug settings.
|
||||||
|
*
|
||||||
|
* This method updates the debug settings in the AIOWPSecurity_Configs instance based on the provided data.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the data to update the debug settings.
|
||||||
|
* - 'aiowps_enable_debug': (bool) Indicates whether debug mode should be enabled.
|
||||||
|
* @return array An associative array containing the status and message of the operation.
|
||||||
|
* - 'status' : (string) The status of the operation, which is always 'success'.
|
||||||
|
* - 'message' : (string) A message indicating that the settings have been updated successfully.
|
||||||
|
*/
|
||||||
|
public function perform_save_debug_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enable_debug', '1' === $data["aiowps_enable_debug"] ? '1' : '', true);
|
||||||
|
|
||||||
|
return $this->handle_response(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to backup the .htaccess file.
|
||||||
|
*
|
||||||
|
* This method creates a backup of the .htaccess file and renames it with a random prefix.
|
||||||
|
* It also provides a message indicating the outcome of the backup operation.
|
||||||
|
*
|
||||||
|
* @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin.
|
||||||
|
* @return array An associative array containing the status and message of the backup operation.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success' or 'error'.
|
||||||
|
* - 'message' : (string) A message indicating the outcome of the backup operation.
|
||||||
|
*/
|
||||||
|
public function perform_backup_htaccess_file() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$home_path = AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
$htaccess_path = $home_path . '.htaccess';
|
||||||
|
|
||||||
|
$result = AIOWPSecurity_Utility_File::backup_and_rename_htaccess($htaccess_path); //Backup the htaccess file
|
||||||
|
$extra_args = array();
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$aiowps_backup_dir = WP_CONTENT_DIR.'/'.AIO_WP_SECURITY_BACKUPS_DIR_NAME;
|
||||||
|
$success = true;
|
||||||
|
$message = __('Your .htaccess file was successfully backed up.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$extra_args['data'] = file_get_contents($aiowps_backup_dir.'/'. $result .'.txt');
|
||||||
|
$extra_args['title'] = $result;
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("htaccess - Backup operation failed!", 4);
|
||||||
|
$success = false;
|
||||||
|
$message = __('htaccess backup failed.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, array('extra_args' => $extra_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to restore the .htaccess file.
|
||||||
|
*
|
||||||
|
* This method restores the .htaccess file using the provided data, which includes the contents of the .htaccess file.
|
||||||
|
* It also verifies that the file chosen has valid contents relevant to the .htaccess file.
|
||||||
|
*
|
||||||
|
* @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin.
|
||||||
|
* @param array $data An associative array containing the data needed to restore the .htaccess file.
|
||||||
|
* - 'aiowps_htaccess_file' : (string) The name of the .htaccess file to restore from.
|
||||||
|
* - 'aiowps_htaccess_file_contents' : (string) The contents of the .htaccess file to restore.
|
||||||
|
* @return array An associative array containing the status and message of the restore operation.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success' or 'error'.
|
||||||
|
* - 'message' : (string) A message indicating the outcome of the restore operation.
|
||||||
|
*/
|
||||||
|
public function perform_restore_htaccess_file($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
$home_path = AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
$htaccess_path = $home_path . '.htaccess';
|
||||||
|
|
||||||
|
if (empty($data['aiowps_htaccess_file']) && empty($data['aiowps_htaccess_file_contents'])) {
|
||||||
|
$message = __('Please choose a valid .htaccess to restore from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
} else {
|
||||||
|
$htaccess_file_contents = trim(stripslashes($data['aiowps_htaccess_file_contents']));
|
||||||
|
//Verify that file chosen has contents which are relevant to .htaccess file
|
||||||
|
$is_htaccess = AIOWPSecurity_Utility_Htaccess::check_if_htaccess_contents($htaccess_file_contents);
|
||||||
|
if (1 == $is_htaccess) {
|
||||||
|
if (!file_put_contents($htaccess_path, $htaccess_file_contents)) {
|
||||||
|
//Failed to make a backup copy
|
||||||
|
$aio_wp_security->debug_logger->log_debug("htaccess - Restore from .htaccess operation failed.", 4);
|
||||||
|
$message = __('The restoration of the .htaccess file failed; please attempt to restore the .htaccess file manually using FTP.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
} else {
|
||||||
|
$message = __('Your .htaccess file has successfully been restored.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("htaccess restore failed - Contents of restore file appear invalid.", 4);
|
||||||
|
$success = false;
|
||||||
|
$message = __('The restoration .htaccess file has failed, please check the contents of the file you are trying to restore from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to restore the wp-config.php file.
|
||||||
|
*
|
||||||
|
* This method restores the wp-config.php file using the provided data, which includes the contents of the wp-config.php file.
|
||||||
|
* It also verifies that the file chosen is a valid wp-config.php file.
|
||||||
|
*
|
||||||
|
* @global object $aio_wp_security The global instance of the All-in-One WP Security & Firewall plugin.
|
||||||
|
* @param array $data An associative array containing the data needed to restore the wp-config.php file.
|
||||||
|
* - 'aiowps_wp_config_file' : (string) The name of the wp-config.php file to restore from.
|
||||||
|
* - 'aiowps_wp_config_file_contents' : (string) The contents of the wp-config.php file to restore.
|
||||||
|
* @return array An associative array containing the status and message of the restore operation.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success' or 'error'.
|
||||||
|
* - 'message' : (string) A message indicating the outcome of the restore operation.
|
||||||
|
*/
|
||||||
|
public function perform_restore_wp_config_file($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
if (empty($data['aiowps_wp_config_file']) && empty($data['aiowps_wp_config_file_contents'])) {
|
||||||
|
$message = __('Please choose a wp-config.php file to restore from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
} else {
|
||||||
|
$wp_config_file_contents = trim(stripslashes($data['aiowps_wp_config_file_contents']));
|
||||||
|
|
||||||
|
//Verify that file chosen is a wp-config.file
|
||||||
|
$is_wp_config = AIOWPSecurity_Utility_File::check_if_wp_config_contents($wp_config_file_contents);
|
||||||
|
if ($is_wp_config) {
|
||||||
|
$active_root_wp_config = AIOWPSecurity_Utility_File::get_wp_config_file_path();
|
||||||
|
if (!file_put_contents($active_root_wp_config, $wp_config_file_contents)) {
|
||||||
|
//Failed to make a backup copy
|
||||||
|
$aio_wp_security->debug_logger->log_debug("wp-config.php - Restore from backed up wp-config operation failed.", 4);
|
||||||
|
$message = __('The restoration of the wp-config.php file failed, please attempt to restore this file manually using FTP.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
} else {
|
||||||
|
$message =__('Your wp-config.php file has successfully been restored.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("wp-config.php restore failed - Contents of restore file appear invalid.", 4);
|
||||||
|
$message = __('The restoration of the wp-config.php file failed, please check the contents of the file you are trying to restore from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to delete plugin settings.
|
||||||
|
*
|
||||||
|
* This method deletes specific plugin settings based on the provided data.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the data needed to delete plugin settings.
|
||||||
|
* - 'aiowps_on_uninstall_delete_db_tables' : (string) Indicates whether to delete plugin database tables on uninstallation.
|
||||||
|
* - 'aiowps_on_uninstall_delete_configs' : (string) Indicates whether to delete plugin configuration settings on uninstallation.
|
||||||
|
* @return array An associative array containing the status and message of the delete operation.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success'.
|
||||||
|
* - 'message' : (string) A message indicating that the plugin settings have been successfully deleted.
|
||||||
|
*/
|
||||||
|
public function perform_delete_plugin_settings($data) {
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
//Save settings
|
||||||
|
$options['aiowps_on_uninstall_delete_db_tables'] = isset($data['aiowps_on_uninstall_delete_db_tables']) ? '1' : '';
|
||||||
|
$options['aiowps_on_uninstall_delete_configs'] = isset($data['aiowps_on_uninstall_delete_configs']) ? '1' : '';
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
return $this->handle_response(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to remove WordPress version information settings.
|
||||||
|
*
|
||||||
|
* This method sets the option to remove WordPress version information meta tags based on the provided data.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the data needed to configure the removal of WordPress version information.
|
||||||
|
* - 'aiowps_remove_wp_generator_meta_info' : (string) Indicates whether to remove WordPress version information meta tags.
|
||||||
|
* @return array An associative array containing the status, message, and additional badges related to the removal of WordPress version information.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success'.
|
||||||
|
* - 'message' : (string) A message indicating that the settings have been successfully updated.
|
||||||
|
* - 'badges' : (array) An array containing feature IDs and HTML for additional badges.
|
||||||
|
*/
|
||||||
|
public function perform_remove_wp_version_info_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_remove_wp_generator_meta_info', '1' === $data["aiowps_remove_wp_generator_meta_info"] ? '1' : '', true);
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', array('badges' => array('wp-generator-meta-tag')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to restore AIOWPS settings from an imported file.
|
||||||
|
*
|
||||||
|
* This method restores AIOWPS settings from the provided data representing an imported file.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the data needed to restore AIOWPS settings.
|
||||||
|
* - 'aiowps_import_settings_file' : (string) The name of the file containing the AIOWPS settings.
|
||||||
|
* - 'aiowps_import_settings_file_contents': (string) The contents of the file containing the AIOWPS settings.
|
||||||
|
* @return array An associative array containing the status and messages related to the restoration of AIOWPS settings.
|
||||||
|
* - 'status' : (string) The status of the operation, which can be 'success' or 'error'.
|
||||||
|
* - 'messages' : (array) An array of messages indicating the outcome of the restoration process.
|
||||||
|
* - 'redirect_url' : (string|null) The URL to redirect to after the restoration process, if applicable.
|
||||||
|
*/
|
||||||
|
public function perform_restore_aiowps_settings($data) {
|
||||||
|
global $aio_wp_security, $simba_two_factor_authentication;
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$info = array();
|
||||||
|
$extra_args = array();
|
||||||
|
|
||||||
|
$msg_updated = __('Your AIOS settings were successfully imported.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$msg_error = sprintf(__('Could not write to the %s file.', 'all-in-one-wp-security-and-firewall'), AIOWPSecurity_Utility_File::get_home_path().'.htaccess') . ' ' . __('Please check the file permissions.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
if (empty($data['aiowps_import_settings_file']) && empty($data['aiowps_import_settings_file_contents'])) {
|
||||||
|
$success = false;
|
||||||
|
$message = __('Please choose a file to import your settings from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
// Let's get the uploaded import file contents
|
||||||
|
$import_file_contents = trim($data['aiowps_import_settings_file_contents']); // stripslashes not required wp_unslash applied already AIOWPSecurity_Ajax::set_data
|
||||||
|
|
||||||
|
// Verify that file chosen has valid AIOS settings contents
|
||||||
|
$aiowps_settings_file_contents = AIOWPSecurity_Utility_File::check_if_valid_aiowps_settings_content($import_file_contents);
|
||||||
|
|
||||||
|
if ($aiowps_settings_file_contents) {
|
||||||
|
$is_enabled_cookie_bruteforce_before_import = $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention');
|
||||||
|
// Apply the settings
|
||||||
|
$settings_array = json_decode($import_file_contents, true);
|
||||||
|
if (array_key_exists('general', $settings_array)) {
|
||||||
|
$aiowps_settings_applied = update_option('aio_wp_security_configs', $settings_array['general']);
|
||||||
|
|
||||||
|
if (!$aiowps_settings_applied && get_option('aio_wp_security_configs') === $settings_array['general']) {
|
||||||
|
$aiowps_settings_applied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_main_site() && is_super_admin()) {
|
||||||
|
if (array_key_exists('tfa', $settings_array) && true == $simba_two_factor_authentication->is_tfa_integrated) {
|
||||||
|
$tfa_settings_applied = $simba_two_factor_authentication->set_configs($settings_array['tfa']);
|
||||||
|
|
||||||
|
if (!$tfa_settings_applied && $simba_two_factor_authentication->get_configs() !== $settings_array['tfa']) {
|
||||||
|
$aiowps_settings_applied = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('firewall', $settings_array)) {
|
||||||
|
$aiowps_settings_applied = $aiowps_settings_applied && $aiowps_firewall_config->set_contents($settings_array['firewall']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aiowps_settings_applied = update_option('aio_wp_security_configs', $settings_array);
|
||||||
|
|
||||||
|
if (!$aiowps_settings_applied && get_option('aio_wp_security_configs') === $settings_array) {
|
||||||
|
$aiowps_settings_applied = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$aiowps_settings_applied) {
|
||||||
|
// Failed to import settings
|
||||||
|
$aio_wp_security->debug_logger->log_debug('Import AIOS settings operation failed.', 4);
|
||||||
|
$success = false;
|
||||||
|
$message = __('Import AIOS settings operation failed.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->configs->load_config(); // Refresh the configs global variable
|
||||||
|
|
||||||
|
//Just in case user submits partial config settings
|
||||||
|
//Run add_option_values to make sure any missing config items are at least set to default
|
||||||
|
AIOWPSecurity_Configure_Settings::add_option_values();
|
||||||
|
|
||||||
|
$res = true;
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility::allow_to_write_to_htaccess()) $res = AIOWPSecurity_Utility_Htaccess::write_to_htaccess();
|
||||||
|
|
||||||
|
// Now let's refresh the .htaccess file with any modified rules if applicable
|
||||||
|
|
||||||
|
$is_enabled_cookie_bruteforce = $aio_wp_security->configs->get_value('aiowps_enable_brute_force_attack_prevention');
|
||||||
|
|
||||||
|
if ($is_enabled_cookie_bruteforce_before_import != $is_enabled_cookie_bruteforce && 1 == $is_enabled_cookie_bruteforce) {
|
||||||
|
$url = 'admin.php?page='.AIOWPSEC_SETTINGS_MENU_SLUG."&tab=settings-file-operations&success=import_settings";
|
||||||
|
$url .= empty($aio_wp_security->configs->get_value('aiowps_brute_force_secret_word')) ? '' : '&'.$aio_wp_security->configs->get_value('aiowps_brute_force_secret_word').'=1';
|
||||||
|
$url .= $res ? '' : '&error=write_htaccess';
|
||||||
|
$extra_args['redirect_url'] = admin_url(sanitize_url($url));
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $msg_updated;
|
||||||
|
if (!$res) {
|
||||||
|
$info[] = $msg_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Invalid settings file
|
||||||
|
$aio_wp_security->debug_logger->log_debug("The contents of your settings file are invalid.", 4);
|
||||||
|
$success = false;
|
||||||
|
$message = __('The contents of your settings file are invalid, please check the contents of the file you are trying to import settings from.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'info' => $info,
|
||||||
|
'extra_args' => $extra_args
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to save IP settings.
|
||||||
|
*
|
||||||
|
* This method saves the IP settings based on the provided data.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the data needed to save IP settings.
|
||||||
|
* - 'aiowps_ip_retrieve_method': (string) The ID of the IP retrieval method.
|
||||||
|
* @return array An associative array containing the status and message related to saving IP settings.
|
||||||
|
* - 'status': (string) The status of the operation, which can be 'success' or 'error'.
|
||||||
|
* - 'message': (string|null) A message indicating the outcome of saving IP settings, or null if no message is provided.
|
||||||
|
*/
|
||||||
|
public function perform_save_ip_settings($data) {
|
||||||
|
global $wpdb, $aio_wp_security;
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$ip_retrieve_method_id = sanitize_text_field($data["aiowps_ip_retrieve_method"]);
|
||||||
|
|
||||||
|
$message = false;
|
||||||
|
|
||||||
|
if (in_array($ip_retrieve_method_id, array_keys(AIOS_Abstracted_Ids::get_ip_retrieve_methods()))) {
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_ip_retrieve_method', $ip_retrieve_method_id, true);
|
||||||
|
$aiowps_firewall_config->set_value('aios_ip_retrieve_method', $ip_retrieve_method_id);
|
||||||
|
$logged_in_users_table = AIOWPSEC_TBL_LOGGED_IN_USERS;
|
||||||
|
|
||||||
|
//Clear logged in list because it might be showing wrong addresses
|
||||||
|
if (AIOWPSecurity_Utility::is_multisite_install()) {
|
||||||
|
$current_blog_id = get_current_blog_id();
|
||||||
|
$wpdb->query($wpdb->prepare("DELETE FROM `{$logged_in_users_table}` WHERE site_id = %d", $current_blog_id));
|
||||||
|
}
|
||||||
|
$wpdb->query("DELETE FROM `{$logged_in_users_table}`");
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response(true, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform saving the wp-config.php file.
|
||||||
|
*
|
||||||
|
* This method backs up the wp-config.php file and retrieves its content.
|
||||||
|
* It returns the status of the operation, the file content, and the backup title.
|
||||||
|
*
|
||||||
|
* @return array An array containing the status, file content, and backup title.
|
||||||
|
*/
|
||||||
|
public function perform_save_wp_config() {
|
||||||
|
$wp_config_path = AIOWPSecurity_Utility_File::get_wp_config_file_path();
|
||||||
|
AIOWPSecurity_Utility_File::backup_and_rename_wp_config($wp_config_path); // Backup the wp_config.php file
|
||||||
|
$title = "wp-config-backup.txt";
|
||||||
|
$file_content = file_get_contents($wp_config_path);
|
||||||
|
|
||||||
|
$extra_args = array(
|
||||||
|
'data' => $file_content,
|
||||||
|
'title' => $title
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, array('extra_args' => $extra_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform exporting All-In-One Security settings.
|
||||||
|
*
|
||||||
|
* This method exports general settings, firewall settings, and two-factor authentication settings
|
||||||
|
* if applicable. It then returns the exported data in JSON format along with a title for the export.
|
||||||
|
*
|
||||||
|
* @return array An array containing the status, exported data in JSON format, and a title for the export.
|
||||||
|
*/
|
||||||
|
public function perform_export_aios_settings() {
|
||||||
|
global $simba_two_factor_authentication;
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$config_data = array();
|
||||||
|
$config_data['general'] = get_option('aio_wp_security_configs');
|
||||||
|
|
||||||
|
if (is_main_site() && is_super_admin()) {
|
||||||
|
$config_data['firewall'] = $aiowps_firewall_config->get_contents();
|
||||||
|
|
||||||
|
if (true == $simba_two_factor_authentication->is_tfa_integrated) {
|
||||||
|
$config_data['tfa'] = $simba_two_factor_authentication->get_configs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = json_encode($config_data);
|
||||||
|
|
||||||
|
$extra_args = array(
|
||||||
|
'data' => $output,
|
||||||
|
'title' => 'aiowps_' . current_time('Y-m-d_H-i') . '.txt'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, array('extra_args' => $extra_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the Import/Export settings UI for legacy UDC.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_import_export_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/settings/settings-file-operations.php', true, array());
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the reset settings UI for legacy UDC.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_reset_contents() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$content = $aio_wp_security->include_template('wp-admin/settings/general-settings.php', true, array());
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return ip address detection data for the advanced settings.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_ip_address_detection_data() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$ip_retrieve_methods_postfixes = array(
|
||||||
|
'REMOTE_ADDR' => __('Default - if correct, then this is the best option', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'HTTP_CF_CONNECTING_IP' => __("Only use if you're using Cloudflare.", 'all-in-one-wp-security-and-firewall'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$ip_retrieve_methods = array();
|
||||||
|
|
||||||
|
foreach (AIOS_Abstracted_Ids::get_ip_retrieve_methods() as $id => $ip_method) {
|
||||||
|
$ip_retrieve_methods[$id]['ip_method'] = $ip_method;
|
||||||
|
|
||||||
|
if (isset($_SERVER[$ip_method])) {
|
||||||
|
/* translators: %s: IP Method */
|
||||||
|
$ip_retrieve_methods[$id]['ip_method'] .= ' ' . sprintf(__('(current value: %s)', 'all-in-one-wp-security-and-firewall'), sanitize_text_field(wp_unslash($_SERVER[$ip_method])));
|
||||||
|
$ip_retrieve_methods[$id]['is_enabled'] = true;
|
||||||
|
} else {
|
||||||
|
$ip_retrieve_methods[$id]['ip_method'] .= ' (' . __('no value (i.e. empty) on your server', 'all-in-one-wp-security-and-firewall') . ')';
|
||||||
|
$ip_retrieve_methods[$id]['is_enabled'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($ip_retrieve_methods_postfixes[$ip_method])) {
|
||||||
|
$ip_retrieve_methods[$id]['ip_method'] .= ' (' . $ip_retrieve_methods_postfixes[$ip_method] . ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'is_localhost' => AIOWPSecurity_Utility::is_localhost(),
|
||||||
|
'current_ip_retrieve_method' => $aio_wp_security->configs->get_value('aiowps_ip_retrieve_method'),
|
||||||
|
'ip_retrieve_methods' => $ip_retrieve_methods,
|
||||||
|
'server_suitable_ip_methods' => AIOWPSecurity_Utility_IP::get_server_suitable_ip_methods()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
wp-content/plugins/all-in-one-wp-security-and-firewall/classes/commands/wp-security-tfa-commands.php
Executable
+216
@@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Tfa_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Tfa_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init TFA for UDC.
|
||||||
|
*
|
||||||
|
* @return AIO_WP_Security_Simba_Two_Factor_Authentication_Plugin
|
||||||
|
*/
|
||||||
|
private function init_tfa() {
|
||||||
|
include_once AIO_WP_SECURITY_PATH . '/classes/wp-security-two-factor-login.php';
|
||||||
|
|
||||||
|
$tfa = new AIO_WP_Security_Simba_Two_Factor_Authentication_Plugin();
|
||||||
|
|
||||||
|
/* Needed to run hook-dependent code in TFA, or there are Divide by Zero errors. */
|
||||||
|
do_action('plugins_loaded');
|
||||||
|
|
||||||
|
return $tfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the TFA algorithm setting.
|
||||||
|
*
|
||||||
|
* @param array $data Passed arguments.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function save_algorithm_setting($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
$controller = $tfa->get_controller();
|
||||||
|
|
||||||
|
$old_algorithm = $controller->get_user_otp_algorithm($current_user->ID);
|
||||||
|
|
||||||
|
if ($old_algorithm != $data['tfa_algorithm_type']) {
|
||||||
|
$controller->changeUserAlgorithmTo($current_user->ID, $data['tfa_algorithm_type']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the TFA activation setting.
|
||||||
|
*
|
||||||
|
* @param array $data Passed arguments.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function save_activation_setting($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
$tfa->change_tfa_enabled_status($current_user->ID, $data['tfa_enable_tfa']);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the TFA private key.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function update_private_key() {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$user_id = $current_user->ID;
|
||||||
|
|
||||||
|
delete_user_meta($user_id, 'tfa_priv_key_64');
|
||||||
|
delete_user_meta($user_id, 'simba_tfa_emergency_codes_64');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the TFA OTP Code.
|
||||||
|
*
|
||||||
|
* @param array $data Passed arguments.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function update_otp_code($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
if ('refreshotp' == $data['subaction']) {
|
||||||
|
$code = $tfa->get_controller()->get_current_code($current_user->ID);
|
||||||
|
|
||||||
|
if (false === $code) {
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'code' => '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'code' => $code,
|
||||||
|
);
|
||||||
|
} elseif ('untrust_device' == $data['subaction']) {
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$trusted_devices = $tfa->user_get_trusted_devices();
|
||||||
|
|
||||||
|
$trusted_device = $trusted_devices[wp_unslash($data['device_id'])];
|
||||||
|
|
||||||
|
if (isset($trusted_device)) {
|
||||||
|
unset($trusted_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_user_id = $current_user->ID;
|
||||||
|
|
||||||
|
$tfa->user_set_trusted_devices($current_user_id, $trusted_devices);
|
||||||
|
|
||||||
|
$trusted_list = $tfa->include_template('trusted-devices-inner-box.php', array('trusted_devices' => $tfa->user_get_trusted_devices()), true);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'trusted_list' => $trusted_list,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the TFA UI.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_tfa_contents() {
|
||||||
|
if (!function_exists('submit_button')) {
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/template.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
$content = $tfa->include_template('user-settings.php', array('simba_tfa' => $tfa), true);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => $content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the TFA settings data for the new UDC theme.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_tfa_data() {
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'tfa_required_administrator' => $tfa->get_option('tfa_required_administrator'),
|
||||||
|
'tfa_administrator' => $tfa->get_option('tfa_administrator'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the TFA settings data for the new UDC theme.
|
||||||
|
*
|
||||||
|
* @param array $data The data to save.
|
||||||
|
*
|
||||||
|
* @return array|WP_Error
|
||||||
|
*/
|
||||||
|
public function perform_save_tfa($data) {
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
return new WP_Error(esc_html__('Sorry, you do not have enough privilege to execute the requested action.', 'all-in-one-wp-security-and-firewall'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
$tfa = $this->init_tfa();
|
||||||
|
|
||||||
|
$value = isset($data["tfa_required_administrator"]) ? '1' : '';
|
||||||
|
|
||||||
|
if ($tfa->update_option('tfa_required_administrator', $value)) {
|
||||||
|
$tfa->update_option('tfa_administrator', $value);
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
+253
@@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_Tools_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_Tools_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a WHOIS lookup for the provided IP address or domain.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the IP address or domain for the WHOIS lookup.
|
||||||
|
* The data should include the key 'aiowps_whois_ip_or_domain'.
|
||||||
|
* @return array An array containing the status of the operation and the WHOIS lookup result content.
|
||||||
|
* The 'status' key indicates whether the operation was successful.
|
||||||
|
* The 'content' key contains the result of the WHOIS lookup.
|
||||||
|
*/
|
||||||
|
public function perform_whois_lookup($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$ip_or_domain = trim(stripslashes($data['aiowps_whois_ip_or_domain']));
|
||||||
|
|
||||||
|
$invalid_domain = false;
|
||||||
|
|
||||||
|
if (empty($ip_or_domain)) {
|
||||||
|
$invalid_domain = true;
|
||||||
|
} elseif (version_compare(phpversion(), '5.6', '>')) {
|
||||||
|
if (!(filter_var($ip_or_domain, FILTER_VALIDATE_IP) || filter_var($ip_or_domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME))) $invalid_domain = true; // phpcs:ignore PHPCompatibility.Constants.NewConstants.filter_validate_domainFound -- This code only runs on php 7.0+ so ignore the warning
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invalid_domain) {
|
||||||
|
$result = __('Please enter a valid IP address or domain name to look up.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$result .= __('Nothing to show.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$result = $this->whois_lookup($ip_or_domain);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) {
|
||||||
|
$result = htmlspecialchars($result->get_error_message());
|
||||||
|
$result .= __('Nothing to show.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$result = htmlspecialchars($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'content' => array('aios-who-is-lookup-result-container' => $aio_wp_security->include_template('wp-admin/tools/partials/who-is-lookup-result.php', true, array('result' => $result, 'ip_or_domain' => $ip_or_domain)))
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store custom .htaccess settings provided by the user.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the custom .htaccess settings.
|
||||||
|
* It should include keys 'aiowps_enable_custom_rules', 'aiowps_custom_rules',
|
||||||
|
* and 'aiowps_place_custom_rules_at_top' if applicable.
|
||||||
|
* @return array An array containing the status of the operation and any relevant messages.
|
||||||
|
* The 'status' key indicates whether the operation was successful.
|
||||||
|
* The 'message' key contains any informational or error messages.
|
||||||
|
*/
|
||||||
|
public function perform_store_custom_htaccess_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
// Save settings
|
||||||
|
if (isset($data["aiowps_enable_custom_rules"]) && empty($data['aiowps_custom_rules'])) {
|
||||||
|
$message = __('You must enter some .htaccess directives in the text box below', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $this->handle_response(false, $message);
|
||||||
|
} else {
|
||||||
|
if (!empty($data['aiowps_custom_rules'])) {
|
||||||
|
// Sanitize textarea shoud not be used as <filesMatch "\.(js|css|html)$"> etc rules gets removed.
|
||||||
|
// Escape textarea should not be used the & becomes &.
|
||||||
|
// Here stripslashes as old version 5.3.0 not required, AIOWPSecurity_Ajax::set_data applies wp_unslash for ajax data.
|
||||||
|
// So the .htacces rule having index\.php backslashes removed if used stripslashes below.
|
||||||
|
$options['aiowps_custom_rules'] = $data['aiowps_custom_rules'];
|
||||||
|
} else {
|
||||||
|
$options['aiowps_custom_rules'] = ''; //Clear the custom rules config value
|
||||||
|
}
|
||||||
|
|
||||||
|
$aiowps_custom_rules = $aio_wp_security->configs->get_value('aiowps_custom_rules');
|
||||||
|
$aiowps_place_custom_rules_at_top = $aio_wp_security->configs->get_value('aiowps_place_custom_rules_at_top');
|
||||||
|
|
||||||
|
$options['aiowps_enable_custom_rules'] = isset($data["aiowps_enable_custom_rules"]) ? '1' : '';
|
||||||
|
$options['aiowps_place_custom_rules_at_top'] = isset($data["aiowps_place_custom_rules_at_top"]) ? '1' : '';
|
||||||
|
$this->save_settings($options); // Save the configuration
|
||||||
|
|
||||||
|
$write_result = AIOWPSecurity_Utility_Htaccess::write_to_htaccess(); //now let's write to the .htaccess file
|
||||||
|
if (!$write_result) {
|
||||||
|
$options['aiowps_enable_custom_rules'] = $aiowps_custom_rules;
|
||||||
|
$options['aiowps_place_custom_rules_at_top'] = $aiowps_place_custom_rules_at_top;
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$message = __('The plugin was unable to write to the .htaccess file, please edit file manually.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$aio_wp_security->debug_logger->log_debug("Custom Rules feature - The plugin was unable to write to the .htaccess file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handle_response($success, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the general visitor lockout settings operation.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the general visitor lockout settings.
|
||||||
|
* It should include keys 'aiowps_site_lockout' and 'aiowps_site_lockout_msg'.
|
||||||
|
* @return array An array containing the status of the operation and any relevant messages.
|
||||||
|
* The 'status' key indicates whether the operation was successful.
|
||||||
|
* The 'message' key contains an informational message about the outcome of the operation.
|
||||||
|
*/
|
||||||
|
public function perform_general_visitor_lockout($data) {
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$options['aiowps_site_lockout'] = isset($data["aiowps_site_lockout"]) ? '1' : '';
|
||||||
|
$maint_msg = wp_kses_post(wp_unslash($data['aiowps_site_lockout_msg']));
|
||||||
|
$options['aiowps_site_lockout_msg'] = $maint_msg; // Text area/msg box
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
do_action('aiowps_site_lockout_settings_saved');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the general visitor lockout setting operation for the dashboard widget.
|
||||||
|
*
|
||||||
|
* @param array $data The data containing the general visitor lockout setting.
|
||||||
|
* It should include the 'aiowps_site_lockout' key.
|
||||||
|
* @return array An array containing the status of the operation and any relevant messages.
|
||||||
|
* The 'status' key indicates whether the operation was successful.
|
||||||
|
* The 'message' key contains an informational message about the outcome of the operation.
|
||||||
|
*/
|
||||||
|
public function perform_general_visitor_lockout_dashboard_widget($data) {
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$options['aiowps_site_lockout'] = isset($data["aiowps_site_lockout"]) ? '1' : '';
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
do_action('aiowps_site_lockout_settings_saved');
|
||||||
|
|
||||||
|
return $this->handle_response(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a password against the HIBP database.
|
||||||
|
*
|
||||||
|
* @param array $data Contains the password to be checked.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function hibp_check_password($data) {
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'pwned' => AIOS_HIBP::password_is_pwned($data['password']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does a WHOIS lookup on an IP address or domain name and then returns the result.
|
||||||
|
*
|
||||||
|
* @param String $search - IP address or domain name to do a WHOIS lookup on
|
||||||
|
* @param Integer $timeout - connection timeout for fsockopen
|
||||||
|
*
|
||||||
|
* @return String|WP_Error - returns preformatted WHOIS lookup result or WP_Error
|
||||||
|
*/
|
||||||
|
private function whois_lookup($search, $timeout = 10) {
|
||||||
|
$fp = @fsockopen('whois.iana.org', 43, $errno, $errstr, $timeout);
|
||||||
|
|
||||||
|
if (!$fp) {
|
||||||
|
return new WP_Error('whois_lookup_failed', 'whois.iana.org: Socket Error '.$errno.' - '.$errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
$queries = sprintf(__('Querying %s: %s', 'all-in-one-wp-security-and-firewall'), 'whois.iana.org', $search)."\n";
|
||||||
|
|
||||||
|
fputs($fp, $search."\r\n");
|
||||||
|
$out = '';
|
||||||
|
while (!feof($fp)) {
|
||||||
|
$line = fgets($fp);
|
||||||
|
if (preg_match('/refer: +(\S+)/', $line, $matches)) {
|
||||||
|
$referral_server = $matches[1];
|
||||||
|
$queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$out .= $line;
|
||||||
|
}
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
if (!isset($referral_server) && filter_var($search, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && preg_match('/whois: +(\S+)/', $out, $matches)) {
|
||||||
|
$referral_server = $matches[1];
|
||||||
|
$queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$referrals = array();
|
||||||
|
|
||||||
|
while (isset($referral_server)) {
|
||||||
|
$referrals[] = $referral_server;
|
||||||
|
|
||||||
|
$fp = @fsockopen($referral_server, 43, $errno, $errstr, $timeout);
|
||||||
|
|
||||||
|
if (!$fp) {
|
||||||
|
return new WP_Error('whois_lookup_failed', $referral_server.': Socket Error '.$errno.' - '.$errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('whois.arin.net' == $referral_server) {
|
||||||
|
$formatted_search = 'n + '.$search;
|
||||||
|
} elseif ('whois.denic.de' == $referral_server) {
|
||||||
|
$formatted_search = '-T dn,ace '.$search;
|
||||||
|
} elseif ('whois.dk-hostmaster.dk' == $referral_server) {
|
||||||
|
$formatted_search = '--charset=utf-8 --show-handles '.$search;
|
||||||
|
} elseif ('whois.nic.ad.jp' == $referral_server || 'whois.jprs.jp' == $referral_server) {
|
||||||
|
$formatted_search = $search.'/e';
|
||||||
|
} else {
|
||||||
|
$formatted_search = $search;
|
||||||
|
}
|
||||||
|
|
||||||
|
$queries .= sprintf(__('Querying %s: %s', 'all-in-one-wp-security-and-firewall'), $referral_server, $formatted_search)."\n";
|
||||||
|
|
||||||
|
$referral_server = null;
|
||||||
|
|
||||||
|
fputs($fp, $formatted_search."\r\n");
|
||||||
|
$out = '';
|
||||||
|
while (!feof($fp)) {
|
||||||
|
$line = fgets($fp);
|
||||||
|
if (preg_match('/Registrar WHOIS Server: +(\S+)/', $line, $matches)
|
||||||
|
|| preg_match('/% referto: +whois -h (\S+)/', $line, $matches)
|
||||||
|
|| preg_match('/% referto: +(\S+)/', $line, $matches)
|
||||||
|
|| preg_match('/ReferralServer: +rwhois:\/\/(\S+)/', $line, $matches)
|
||||||
|
|| preg_match('/ReferralServer: +whois:\/\/(\S+)/', $line, $matches)
|
||||||
|
) {
|
||||||
|
if (!in_array($matches[1], $referrals)) {
|
||||||
|
$referral_server = $matches[1];
|
||||||
|
$queries .= sprintf(__('Redirected to %s', 'all-in-one-wp-security-and-firewall'), $referral_server)."\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$out .= $line;
|
||||||
|
}
|
||||||
|
fclose($fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $queries."\n".$out;
|
||||||
|
}
|
||||||
|
}
|
||||||
+716
@@ -0,0 +1,716 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
if (trait_exists('AIOWPSecurity_User_Security_Commands_Trait')) return;
|
||||||
|
|
||||||
|
trait AIOWPSecurity_User_Security_Commands_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves user account security settings.
|
||||||
|
*
|
||||||
|
* This function updates security settings related to user enumeration prevention
|
||||||
|
* and strong password enforcement in the AIO WP Security plugin.
|
||||||
|
*
|
||||||
|
* @param array $data An associative array containing the security settings:
|
||||||
|
* - 'aiowps_prevent_users_enumeration' (optional): Set to '1' to prevent user enumeration.
|
||||||
|
* - 'aiowps_enforce_strong_password' (optional): Set to '1' to enforce strong passwords.
|
||||||
|
*
|
||||||
|
* @return array The response array containing:
|
||||||
|
* - 'badges' (array): A list of applied security badges.
|
||||||
|
*/
|
||||||
|
public function perform_save_user_account_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_prevent_users_enumeration', isset($data["aiowps_prevent_users_enumeration"]) ? '1' : '', true);
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enforce_strong_password', isset($data['aiowps_enforce_strong_password']) ? '1' : '', true);
|
||||||
|
|
||||||
|
$badges = array('enforce-strong-password', 'disable-users-enumeration');
|
||||||
|
|
||||||
|
return $this->handle_response(true, '', array('badges' => $badges));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to change the admin username.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data for changing the admin username.
|
||||||
|
* The array may contain the following keys:
|
||||||
|
* - 'aiowps_new_user_name': The new username to be set for the admin.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* and a message indicating the result of the operation.
|
||||||
|
* If the operation is successful, it also includes a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_change_admin_username($data) {
|
||||||
|
global $wpdb, $aio_wp_security;
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'content' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
if (!empty($data['aiowps_new_user_name'])) {
|
||||||
|
$new_username = sanitize_text_field($data['aiowps_new_user_name']);
|
||||||
|
if (validate_username($new_username)) {
|
||||||
|
if (AIOWPSecurity_Utility::check_user_exists($new_username)) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$error = sprintf(__('Username: %s already exists, please enter another value.', 'all-in-one-wp-security-and-firewall'), $new_username);
|
||||||
|
} else {
|
||||||
|
// let's check if currently logged in username is 'admin'
|
||||||
|
$user = wp_get_current_user();
|
||||||
|
$user_login = $user->user_login;
|
||||||
|
if ('admin' == strtolower($user_login)) {
|
||||||
|
$username_is_admin = true;
|
||||||
|
} else {
|
||||||
|
$username_is_admin = false;
|
||||||
|
}
|
||||||
|
// Now let's change the username
|
||||||
|
$sql = $wpdb->prepare("UPDATE `" . $wpdb->users . "` SET user_login = '" . esc_sql($new_username) . "' WHERE user_login=%s", "admin");
|
||||||
|
$result = $wpdb->query($sql);
|
||||||
|
if (false === $result) {
|
||||||
|
// There was an error updating the users table
|
||||||
|
$user_update_error = __('The database update operation of the user account failed.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = $user_update_error;
|
||||||
|
$aio_wp_security->debug_logger->log_debug($user_update_error . ' ' . $wpdb->last_error, 4);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multisite considerations
|
||||||
|
if (is_multisite()) { // process sitemeta if we're in a multi-site situation
|
||||||
|
$oldAdmins = $wpdb->get_var("SELECT meta_value FROM `" . $wpdb->sitemeta . "` WHERE meta_key = 'site_admins'");
|
||||||
|
$newAdmins = str_replace('5:"admin"', strlen($new_username) . ':"' . esc_sql($new_username) . '"', $oldAdmins);
|
||||||
|
$wpdb->query("UPDATE `" . $wpdb->sitemeta . "` SET meta_value = '" . esc_sql($newAdmins) . "' WHERE meta_key = 'site_admins'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user is logged in with username "admin" then log user out and send to login page so they can login again
|
||||||
|
if ($username_is_admin) {
|
||||||
|
// Lets logout the user
|
||||||
|
$aio_wp_security->debug_logger->log_debug("Logging user out with login ".$user_login. " because they changed their username.");
|
||||||
|
$after_logout_url = AIOWPSecurity_Utility::get_current_page_url();
|
||||||
|
$after_logout_payload = array('redirect_to' => $after_logout_url, 'msg' => $aio_wp_security->user_login_obj->key_login_msg.'=admin_user_changed');
|
||||||
|
//Save some of the logout redirect data to a transient
|
||||||
|
is_multisite() ? set_site_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60) : set_transient('aiowps_logout_payload', $after_logout_payload, 30 * 60);
|
||||||
|
|
||||||
|
$logout_url = AIOWPSEC_WP_URL.'?aiowpsec_do_log_out=1';
|
||||||
|
$logout_url = AIOWPSecurity_Utility::add_query_data_to_url($logout_url, 'al_additional_data', '1');
|
||||||
|
|
||||||
|
$response['logout_user'] = true;
|
||||||
|
$response['logout_url'] = $logout_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // An invalid username was entered
|
||||||
|
$error = __('You entered an invalid username, please enter another value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
} else { // No username value was entered
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$error = __('Please enter a value for your username.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($error)) { // We have some validation or other error
|
||||||
|
$response['message'] = $error;
|
||||||
|
} else {
|
||||||
|
$response['message'] = __('The username has been successfully changed.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('user-accounts-change-admin-user'));
|
||||||
|
$response['content']['change-admin-username-content'] = $aio_wp_security->include_template('wp-admin/user-security/partials/wp-username-content.php', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to save the login lockout settings.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
*
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_save_login_lockout_settings($data) {
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'values' => array(),
|
||||||
|
'info' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$invalid_fields = array();
|
||||||
|
|
||||||
|
$max_login_attempt_val = sanitize_text_field($data['aiowps_max_login_attempts']);
|
||||||
|
if (!is_numeric($max_login_attempt_val) || 1 > $max_login_attempt_val) {
|
||||||
|
$invalid_fields[] = 'max login attempts';
|
||||||
|
$max_login_attempt_val = '3'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
$login_retry_time_period = sanitize_text_field($data['aiowps_retry_time_period']);
|
||||||
|
if (!is_numeric($login_retry_time_period) || 1 > $login_retry_time_period) {
|
||||||
|
$invalid_fields[] = 'login retry time period';
|
||||||
|
$login_retry_time_period = '5'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
$lockout_time_length = sanitize_text_field($data['aiowps_lockout_time_length']);
|
||||||
|
if (!is_numeric($lockout_time_length) || 1 > $lockout_time_length) {
|
||||||
|
$invalid_fields[] = 'minimum lockout time length';
|
||||||
|
$lockout_time_length = '5'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_lockout_time_length = sanitize_text_field($data['aiowps_max_lockout_time_length']);
|
||||||
|
if (!is_numeric($max_lockout_time_length) || 1 > $max_lockout_time_length) {
|
||||||
|
$invalid_fields[] = 'maximum lockout time length';
|
||||||
|
$max_lockout_time_length = '60'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lockout_time_length >= $max_lockout_time_length) {
|
||||||
|
$invalid_fields[] = 'minimum lockout time length';
|
||||||
|
$lockout_time_length = '5'; // Set it to the default value for this field
|
||||||
|
$max_lockout_time_length = '60'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
$email_addresses = isset($data['aiowps_email_address']) ? stripslashes($data['aiowps_email_address']) : get_bloginfo('admin_email');
|
||||||
|
$email_addresses_trimmed = AIOWPSecurity_Utility::explode_trim_filter_empty($email_addresses, "\n");
|
||||||
|
// Read into array, sanitize, filter empty and keep only unique usernames.
|
||||||
|
$email_address_list = array_unique(
|
||||||
|
array_filter(
|
||||||
|
array_map(
|
||||||
|
'sanitize_email',
|
||||||
|
$email_addresses_trimmed
|
||||||
|
),
|
||||||
|
'is_email'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($data['aiowps_enable_email_notify']) && 1 == $data['aiowps_enable_email_notify'] && 0 == count($email_addresses_trimmed)) {
|
||||||
|
$invalid_fields[] = 'email addresses';
|
||||||
|
} elseif (isset($data['aiowps_enable_email_notify']) && 1 == $data['aiowps_enable_email_notify'] && (0 == count($email_address_list) || count($email_address_list) != count($email_addresses_trimmed))) {
|
||||||
|
$invalid_fields[] = 'email addresses';
|
||||||
|
}
|
||||||
|
if (isset($data['aiowps_enable_email_notify']) && 0 == count($email_address_list)) {
|
||||||
|
$email_address_list[] = get_bloginfo('admin_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantly lockout specific usernames
|
||||||
|
$instantly_lockout_specific_usernames = isset($data['aiowps_instantly_lockout_specific_usernames']) ? $data['aiowps_instantly_lockout_specific_usernames'] : '';
|
||||||
|
// Read into array, sanitize, filter empty and keep only unique usernames.
|
||||||
|
$instantly_lockout_specific_usernames = array_unique(
|
||||||
|
array_filter(
|
||||||
|
array_map(
|
||||||
|
'sanitize_user',
|
||||||
|
AIOWPSecurity_Utility::explode_trim_filter_empty($instantly_lockout_specific_usernames)
|
||||||
|
),
|
||||||
|
'strlen'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
if (!empty($invalid_fields)) {
|
||||||
|
$invalid_fields = array_unique($invalid_fields);
|
||||||
|
$invalid_fields = implode(", ", $invalid_fields);
|
||||||
|
$response['info'][] = sprintf(__('The following options had invalid values and have been set to the defaults: %s', 'all-in-one-wp-security-and-firewall'), $invalid_fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$random_20_digit_string = AIOWPSecurity_Utility::generate_alpha_numeric_random_string(20); // Generate random 20 char string for use during CAPTCHA encode/decode
|
||||||
|
$options['aiowps_unlock_request_secret_key'] = $random_20_digit_string;
|
||||||
|
|
||||||
|
$options['aiowps_enable_login_lockdown'] = isset($data["aiowps_enable_login_lockdown"]) ? '1' : '';
|
||||||
|
$options['aiowps_allow_unlock_requests'] = isset($data["aiowps_allow_unlock_requests"]) ? '1' : '';
|
||||||
|
$options['aiowps_max_login_attempts'] = absint($max_login_attempt_val);
|
||||||
|
$options['aiowps_retry_time_period'] = absint($login_retry_time_period);
|
||||||
|
$options['aiowps_lockout_time_length'] = absint($lockout_time_length);
|
||||||
|
$options['aiowps_max_lockout_time_length'] = absint($max_lockout_time_length);
|
||||||
|
$options['aiowps_set_generic_login_msg'] = isset($data["aiowps_set_generic_login_msg"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_invalid_username_lockdown']= isset($data["aiowps_enable_invalid_username_lockdown"]) ? '1' : '';
|
||||||
|
$options['aiowps_instantly_lockout_specific_usernames'] = $instantly_lockout_specific_usernames;
|
||||||
|
$options['aiowps_enable_email_notify'] = isset($data["aiowps_enable_email_notify"]) ? '1' : '';
|
||||||
|
$options['aiowps_enable_php_backtrace_in_email'] = isset($data['aiowps_enable_php_backtrace_in_email']) ? '1' : '';
|
||||||
|
$options['aiowps_email_address'] = $email_address_list;
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$response['values']['aiowps_max_login_attempts'] = absint($max_login_attempt_val);
|
||||||
|
$response['values']['aiowps_retry_time_period'] = absint($login_retry_time_period);
|
||||||
|
$response['values']['aiowps_lockout_time_length'] = absint($lockout_time_length);
|
||||||
|
$response['values']['aiowps_max_lockout_time_length'] = absint($max_lockout_time_length);
|
||||||
|
$response['values']['aiowps_email_address'] = implode("\n", $email_address_list);
|
||||||
|
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('user-login-login-lockdown'));
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to save the login lockout whitelist settings.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
* The array may contain the following keys:
|
||||||
|
* - 'aiowps_lockdown_enable_whitelisting': A boolean indicating whether whitelisting is enabled.
|
||||||
|
* - 'aiowps_lockdown_allowed_ip_addresses': The allowed IP addresses for whitelisting.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_save_login_lockout_whitelist_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success'
|
||||||
|
);
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
$result = 1;
|
||||||
|
|
||||||
|
if (!empty($data['aiowps_lockdown_allowed_ip_addresses'])) {
|
||||||
|
$ip_addresses = sanitize_textarea_field(wp_unslash($data['aiowps_lockdown_allowed_ip_addresses']));
|
||||||
|
$ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($ip_addresses);
|
||||||
|
$validated_ip_list_array = AIOWPSecurity_Utility_IP::validate_ip_list($ip_list_array, 'whitelist');
|
||||||
|
if (is_wp_error($validated_ip_list_array)) {
|
||||||
|
$result = -1;
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = AIOWPSecurity_Admin_Menu::show_msg_error_st(nl2br($validated_ip_list_array->get_error_message()), true);
|
||||||
|
} else {
|
||||||
|
$allowed_ip_data = implode("\n", $validated_ip_list_array);
|
||||||
|
$options['aiowps_lockdown_allowed_ip_addresses'] = $allowed_ip_data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$options['aiowps_lockdown_allowed_ip_addresses'] = ''; //Clear the IP address config value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == $result) {
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_lockdown_enable_whitelisting', isset($data["aiowps_lockdown_enable_whitelisting"]) ? '1' : '', true);
|
||||||
|
$response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('user-login-lockout-ip-whitelisting'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to force logout users.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
* The array may contain the following keys:
|
||||||
|
* - 'aiowps_logout_time_period': The time period (in minutes) for logout.
|
||||||
|
* - 'aiowps_enable_forced_logout': A boolean indicating whether forced logout is enabled.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* an array of messages indicating the result of the operation,
|
||||||
|
* the content representing the logout time period,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_force_logout($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success',
|
||||||
|
'info' => array(),
|
||||||
|
'values' => array()
|
||||||
|
);
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
|
||||||
|
$logout_time_period = sanitize_text_field($data['aiowps_logout_time_period']);
|
||||||
|
if (isset($data["aiowps_enable_forced_logout"]) && (!is_numeric($logout_time_period) || $logout_time_period < 1)) {
|
||||||
|
$response['info'][] = __('You entered a non numeric or negative value for the logout time period field, it has been set to the default value.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$logout_time_period = '60'; // Set it to the default value for this field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$options['aiowps_logout_time_period'] = absint($logout_time_period);
|
||||||
|
$options['aiowps_enable_forced_logout'] = isset($data["aiowps_enable_forced_logout"]) ? '1' : '';
|
||||||
|
$this->save_settings($options);
|
||||||
|
|
||||||
|
$response['values']['aiowps_logout_time_period'] = absint($logout_time_period);
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('user-login-force-logout'));
|
||||||
|
$response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
|
||||||
|
if ('1' === $options['aiowps_enable_forced_logout']) {
|
||||||
|
$response['logout_user'] = $this->check_logout_user();
|
||||||
|
$response['logout_url'] = $aio_wp_security->user_login_obj->aiowps_force_logout_action_handler(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to save the HIBP settings.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
*
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_save_hibp_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_hibp_user_profile_update', isset($data['aiowps_hibp_user_profile_update']) ? '1' : '', true);
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_http_password_reset', isset($data['aiowps_http_password_reset']) ? '1' : '', true);
|
||||||
|
$aio_wp_security->configs->save_config();
|
||||||
|
|
||||||
|
return $this->handle_response(true, false, array('badges' => array('hibp')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to disable application password.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
* The array may contain the following key:
|
||||||
|
* - 'aiowps_disable_application_password': A boolean indicating whether application password is disabled.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_disable_application_password($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
// Save all the form values to the options
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_disable_application_password', isset($data['aiowps_disable_application_password']) ? '1' : '', true);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'badges' => $this->get_features_id_and_html(array('disable-application-password'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to add salt postfix.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
* The array may contain the following key:
|
||||||
|
* - 'aiowps_enable_salt_postfix': A boolean indicating whether salt postfix is enabled.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_add_salt_postfix($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$aiowps_enable_salt_postfix = isset($data['aiowps_enable_salt_postfix']) ? '1' : '';
|
||||||
|
if ($aiowps_enable_salt_postfix == $aio_wp_security->configs->get_value('aiowps_enable_salt_postfix')) {
|
||||||
|
$is_setting_changed = true;
|
||||||
|
} else {
|
||||||
|
$is_setting_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enable_salt_postfix', $aiowps_enable_salt_postfix, true);
|
||||||
|
$ret_schedule = $this->schedule_change_auth_keys_and_salt();
|
||||||
|
|
||||||
|
if (is_wp_error($ret_schedule)) {
|
||||||
|
$aio_wp_security->debug_logger->log_debug($ret_schedule->get_error_message(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('1' == $aiowps_enable_salt_postfix && $is_setting_changed) {
|
||||||
|
AIOWPSecurity_Utility::change_salt_postfixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['message'] = __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['badges'] = $this->get_features_id_and_html(array('enable-salt-postfix'));
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs actions on logged-in users.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data for the action to be performed.
|
||||||
|
* The array may contain the following keys:
|
||||||
|
* - 'action': The action to be performed on logged-in users (e.g., 'force_user_logout').
|
||||||
|
* - 'logged_in_id': The ID of the logged-in user on which the action will be performed.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* and a message indicating the result of the operation.
|
||||||
|
*/
|
||||||
|
public function perform_logged_in_user_action($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-logged-in-users.php'; // For rendering the AIOWPSecurity_List_Table
|
||||||
|
$user_list = new AIOWPSecurity_List_Logged_In_Users();
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (empty($data['action']) || !in_array($data['action'], array('force_user_logout'))) { // more actions can be added
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('Invalid action provided for logged in user.', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('force_user_logout' == $data['action']) {
|
||||||
|
if (empty($data['logged_in_id'])) {
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('No user ID was provided', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$user_id = strip_tags($data['logged_in_id']);
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if (!is_numeric($user_id)) {
|
||||||
|
$error = __("Invalid user ID provided.", 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif (get_current_user_id() == $user_id) {
|
||||||
|
$error = __("You cannot log yourself out", 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif (is_super_admin($user_id)) {
|
||||||
|
$error = __("Super admins cannot be logged out.", 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif (!AIOWPSecurity_Utility::is_user_member_of_blog($user_id)) {
|
||||||
|
$error = __("You cannot log out a user from a different subsite.", 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
if ($error) {
|
||||||
|
return array(
|
||||||
|
'message' => $error,
|
||||||
|
'status' => 'error'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = esc_sql($user_id);
|
||||||
|
$result = $aio_wp_security->user_login_obj->delete_logged_in_user($users);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$user_list->logout_user($users);
|
||||||
|
$response['message'] = __('The selected user has been logged out successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} else {
|
||||||
|
$response['message'] = __('Failed to log out the selected user.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$response['status'] = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the action to configure manual registration approval settings.
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data to be saved.
|
||||||
|
* The array may contain the following key:
|
||||||
|
* - 'aiowps_enable_manual_registration_approval': A boolean indicating whether manual registration approval is enabled.
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_manual_approval_settings($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
$aio_wp_security->configs->set_value('aiowps_enable_manual_registration_approval', isset($data["aiowps_enable_manual_registration_approval"]) ? '1' : '', true);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => __('The settings have been successfully updated.', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'badges' => $this->get_features_id_and_html(array('manually-approve-registrations'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs actions on manual approval items (e.g., approve account, delete account, block IP).
|
||||||
|
*
|
||||||
|
* @param array $data An array containing the data for the action to be performed.
|
||||||
|
* The array may contain the following keys:
|
||||||
|
* - 'action': The action to be performed on the manual approval item (e.g., 'approve_acct', 'delete_acct', 'block_ip').
|
||||||
|
* - 'user_id': The ID of the user for whom the action will be performed (applicable for 'approve_acct' and 'delete_acct' actions).
|
||||||
|
* - 'ip_address': The IP address to be blocked (applicable for 'block_ip' action).
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* and a message indicating the result of the operation.
|
||||||
|
*/
|
||||||
|
public function perform_manual_approval_item_action($data) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
include_once AIO_WP_SECURITY_PATH.'/admin/wp-security-list-registered-users.php'; // For rendering the AIOWPSecurity_List_Table
|
||||||
|
$user_list = new AIOWPSecurity_List_Registered_Users();
|
||||||
|
$status = 'error';
|
||||||
|
|
||||||
|
$valid_actions = array('approve_acct', 'delete_acct', 'block_ip');
|
||||||
|
if (empty($data['action']) || !in_array($data['action'], $valid_actions)) { // more actions can be added
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('Invalid action provided for registered user.', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($data['action']) {
|
||||||
|
case 'approve_acct':
|
||||||
|
if (empty($data['user_id'])) {
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('No valid user ID was provided', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$user_id = esc_sql(strip_tags($data['user_id']));
|
||||||
|
$meta_key = 'aiowps_account_status';
|
||||||
|
$meta_value = 'approved'; // set account status
|
||||||
|
|
||||||
|
// Approve single account
|
||||||
|
$result = update_user_meta($user_id, $meta_key, $meta_value);
|
||||||
|
if ($result) {
|
||||||
|
$user = get_user_by('id', $user_id);
|
||||||
|
$user_list->send_email_upon_account_activation($user);
|
||||||
|
$message = __('The selected account was approved successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$status = 'success';
|
||||||
|
} elseif (false === $result) {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("could not approve account ID: $user_id", 4);
|
||||||
|
$message = __('The selected account could not be approved.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete_acct':
|
||||||
|
if (empty($data['user_id'])) {
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('No valid user ID was provided', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = esc_sql(strip_tags($data['user_id']));
|
||||||
|
// Delete single account
|
||||||
|
$result = wp_delete_user($user_id);
|
||||||
|
if (true === $result) {
|
||||||
|
$message = __('The selected account was deleted successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$status = 'success';
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("could not delete account ID: $user_id", 4);
|
||||||
|
$message = __('The selected account could not be deleted.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'block_ip':
|
||||||
|
if (empty($data['ip_address'])) {
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => __('No valid IP address was provided', 'all-in-one-wp-security-and-firewall')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip = esc_sql(strip_tags($data['ip_address']));
|
||||||
|
|
||||||
|
if (AIOWPSecurity_Utility_IP::get_user_ip_address() == $ip) {
|
||||||
|
$message = __('You cannot block your own IP address:', 'all-in-one-wp-security-and-firewall') . ' ' . $ip;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block single IP
|
||||||
|
$result = AIOWPSecurity_Blocking::add_ip_to_block_list($ip, 'registration_spam');
|
||||||
|
if (true === $result) {
|
||||||
|
$message = __('The selected IP was successfully added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
$message .= ' <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>';
|
||||||
|
$status = 'success';
|
||||||
|
} else {
|
||||||
|
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_List_Registered_Users::block_selected_ips() - could not block IP: $ip", 4);
|
||||||
|
$message = __('The selected IP could not be added to the permanent block list.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => $status,
|
||||||
|
'message' => $message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule weekly aios_change_auth_keys_and_salt cron event.
|
||||||
|
*
|
||||||
|
* @return Boolean|WP_Error True if event successfully scheduled. False or WP_Error on failure.
|
||||||
|
*/
|
||||||
|
private function schedule_change_auth_keys_and_salt() {
|
||||||
|
$previous_time = wp_next_scheduled('aios_change_auth_keys_and_salt');
|
||||||
|
|
||||||
|
if (false !== $previous_time) {
|
||||||
|
// Clear schedule so that we don't stack up scheduled backups
|
||||||
|
wp_clear_scheduled_hook('aios_change_auth_keys_and_salt');
|
||||||
|
}
|
||||||
|
$gmt_offset_in_seconds = floatval(get_option('gmt_offset')) * 3600;
|
||||||
|
$first_time = strtotime('next Sunday '.apply_filters('aios_salt_change_schedule_time', '3:00 am')) + $gmt_offset_in_seconds;
|
||||||
|
return wp_schedule_event($first_time, 'weekly', 'aios_change_auth_keys_and_salt');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current user should be automatically logged out based on last login time.
|
||||||
|
*
|
||||||
|
* This method compares the current time with the last login time of the user and determines
|
||||||
|
* if the user should be logged out based on a configured logout time period.
|
||||||
|
*
|
||||||
|
* @return bool Returns true if the user should be logged out, false otherwise.
|
||||||
|
*/
|
||||||
|
private function check_logout_user() {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
// Get the current user
|
||||||
|
$current_user = wp_get_current_user();
|
||||||
|
$user_id = $current_user->ID;
|
||||||
|
|
||||||
|
// Get the current and last login times
|
||||||
|
$current_time = current_time('mysql', true);
|
||||||
|
$login_time = $aio_wp_security->user_login_obj->get_wp_user_aiowps_last_login_time($user_id);
|
||||||
|
|
||||||
|
// Return false if login time is empty (no last login recorded)
|
||||||
|
if (empty($login_time)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the time difference between current time and last login time
|
||||||
|
$diff = strtotime($current_time) - strtotime($login_time);
|
||||||
|
|
||||||
|
// Get the configured logout time period in seconds
|
||||||
|
$logout_time_interval_value = $aio_wp_security->configs->get_value('aiowps_logout_time_period');
|
||||||
|
$logout_time_interval_val_seconds = $logout_time_interval_value * 60;
|
||||||
|
|
||||||
|
// Return true if the time difference exceeds the logout time interval, indicating the user should be logged out
|
||||||
|
return $diff > $logout_time_interval_val_seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whitelists user's IP address
|
||||||
|
*
|
||||||
|
* @return array Returns an array containing the status of the operation ('success' or 'error'),
|
||||||
|
* a message indicating the result of the operation,
|
||||||
|
* and a badge representing the updated feature details.
|
||||||
|
*/
|
||||||
|
public function perform_whitelist_user_ip() {
|
||||||
|
$response = array(
|
||||||
|
'status' => 'success'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!AIOWPSecurity_Utility_Permissions::has_manage_cap()) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = __('You don\'t have enough permissions to whitelist your IP address.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aiowps_firewall_allow_list = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::ALLOW_LIST);
|
||||||
|
|
||||||
|
$whitelisted_ips = $aiowps_firewall_allow_list::get_ips();
|
||||||
|
$is_whitelisted = $aiowps_firewall_allow_list::is_ip_allowed();
|
||||||
|
|
||||||
|
if ($is_whitelisted) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = __('Your IP address is already whitelisted.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
$user_ip = AIOWPSecurity_Utility_IP::get_user_ip_address();
|
||||||
|
|
||||||
|
if (empty($user_ip)) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = __('Your IP address could not be detected.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$whitelisted_ips .= (empty($whitelisted_ips) ? '' : "\n") . $user_ip;
|
||||||
|
|
||||||
|
if (!$aiowps_firewall_allow_list::add_ips($whitelisted_ips)) {
|
||||||
|
$response['status'] = 'error';
|
||||||
|
$response['message'] = __('There was an error whitelisting your IP address, please try again.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['message'] = __('Your IP address has been whitelisted successfully.', 'all-in-one-wp-security-and-firewall');
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our list of families
|
||||||
|
*/
|
||||||
|
return array(
|
||||||
|
array('name' => '6G', 'priority' => 10),
|
||||||
|
array('name' => 'Blacklist', 'priority' => 1),
|
||||||
|
array('name' => 'Bruteforce', 'priority' => 0),
|
||||||
|
array('name' => 'General', 'priority' => 20),
|
||||||
|
array('name' => 'Bots', 'priority' => 2),
|
||||||
|
);
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds all our families
|
||||||
|
*/
|
||||||
|
class Family_Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get our families sorted by priority
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_families() {
|
||||||
|
|
||||||
|
$family_list = include(AIOWPS_FIREWALL_DIR.'/family/wp-security-firewall-families.php');
|
||||||
|
|
||||||
|
//Prioritise the families
|
||||||
|
usort($family_list, function($member, $member2) {
|
||||||
|
if ($member['priority'] == $member2['priority']) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ($member['priority'] > $member2['priority']) ? 1 : -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
$families = array();
|
||||||
|
foreach ($family_list as $member) {
|
||||||
|
$families[strtolower($member['name'])] = new Family($member['name'], $member['priority']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $families;
|
||||||
|
}
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds all our families
|
||||||
|
*/
|
||||||
|
class Family_Collection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds our families
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $families;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs our family collection object
|
||||||
|
*
|
||||||
|
* @param array $families - The sorted families to contain
|
||||||
|
*/
|
||||||
|
public function __construct($families = array()) {
|
||||||
|
$this->families = $families;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator method to iterate over the families
|
||||||
|
*
|
||||||
|
* @return iterable
|
||||||
|
*/
|
||||||
|
public function get_family() {
|
||||||
|
foreach ($this->families as $family) {
|
||||||
|
yield $family;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new rule to a family member
|
||||||
|
*
|
||||||
|
* @param Rule $rule - an active rule to add to its family
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add_rule_to_member(Rule $rule) {
|
||||||
|
$key = strtolower($rule->family);
|
||||||
|
if (array_key_exists($key, $this->families)) {
|
||||||
|
$this->families[$key]->add_rule($rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a family (a grouping of rules)
|
||||||
|
*/
|
||||||
|
class Family {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the family
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Priority of the family (0 is the highest)
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of rules to apply
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $rules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds our family object
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param integer $priority
|
||||||
|
*/
|
||||||
|
public function __construct($name, $priority = 999999) {
|
||||||
|
$this->name = $name;
|
||||||
|
$this->priority = $priority;
|
||||||
|
$this->rules = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a rule to the family
|
||||||
|
*
|
||||||
|
* @param Rule $rule
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add_rule(Rule $rule) {
|
||||||
|
$this->rules[] = $rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies all the rules in the family
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function apply_all() {
|
||||||
|
|
||||||
|
if (empty($this->rules)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ensure the rules are ordered by priority
|
||||||
|
usort($this->rules, function(Rule $rule, Rule $rule2) {
|
||||||
|
if ($rule->priority == $rule2->priority) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ($rule->priority > $rule2->priority) ? 1 : -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($this->rules as $rule) {
|
||||||
|
$rule->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the family name if used as a string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
trait File_Prefix_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file's prefix content. N.B. Some code assumes that this doesn't change, so review all consumers of this method before changing its output.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_file_content_prefix() {
|
||||||
|
$prefix = "<?php __halt_compiler();\n";
|
||||||
|
$prefix .= "/**\n";
|
||||||
|
$prefix .= " * This file was created by All In One Security (AIOS) plugin.\n";
|
||||||
|
$prefix .= self::get_prefix_description();
|
||||||
|
$prefix .= " */\n";
|
||||||
|
return $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the file
|
||||||
|
* You can override this method for each file that needs a file prefix in order to give it its own description
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_prefix_description() {
|
||||||
|
return " * The file is required for storing and retrieving your firewall's settings.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
class Allow_List {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include a file prefix when the file is created
|
||||||
|
*/
|
||||||
|
use File_Prefix_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the path to the allow list
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite the prefix description from File_Prefix_Trait
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_prefix_description() {
|
||||||
|
return " * The file is required for storing and retrieving your firewall's allow list.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the user's IP address is in the allow list
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function is_ip_allowed() {
|
||||||
|
|
||||||
|
$ips = self::get_ips();
|
||||||
|
|
||||||
|
if (empty($ips)) return false;
|
||||||
|
|
||||||
|
$ips = explode("\n", $ips);
|
||||||
|
|
||||||
|
return \AIOS_Helper::is_user_ip_address_within_list($ips);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of IP addresses in the allow list
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_ips() {
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists(self::$path)) return '';
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Cannot use WP API. Firewall is loaded independent of WP.
|
||||||
|
$contents = file_get_contents(self::$path, false, null, strlen(self::get_file_content_prefix()));
|
||||||
|
|
||||||
|
return (false !== $contents ? trim($contents) : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path of the allow list
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function set_path($path) {
|
||||||
|
self::$path = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add IPs to the allow list
|
||||||
|
* This overwrites the whole allow list with the given IPs
|
||||||
|
*
|
||||||
|
* @param mixed $ips - A string of IPs; one per line or an array of individual IPs
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function add_ips($ips) {
|
||||||
|
|
||||||
|
if (is_array($ips)) $ips = implode("\n", $ips);
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Cannot use WP API. Firewall is loaded independent of WP.
|
||||||
|
return (false !== file_put_contents(self::$path, self::get_file_content_prefix().$ips));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
// phpcs:disable WordPress.WP.AlternativeFunctions -- WP isn't loaded here. WP API is unavailable
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives us access to our firewall's config
|
||||||
|
*/
|
||||||
|
class Config {
|
||||||
|
|
||||||
|
use File_Prefix_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to our config file
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs object
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public function __construct($path) {
|
||||||
|
$this->path = $path;
|
||||||
|
$this->init_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the file if it doesn't exist
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function init_file() {
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists($this->path)) {
|
||||||
|
|
||||||
|
$dir = dirname($this->path);
|
||||||
|
if (!file_exists($dir)) Utility::wp_mkdir_p($dir);
|
||||||
|
|
||||||
|
file_put_contents($this->path, self::get_file_content_prefix() . json_encode(array()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the config file with the new prefix whenever the prefix changes.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function update_prefix() {
|
||||||
|
|
||||||
|
$valid_prefix = self::get_file_content_prefix();
|
||||||
|
$current_prefix = file_get_contents($this->path, false, null, 0, strlen($valid_prefix));
|
||||||
|
|
||||||
|
if ($current_prefix === $valid_prefix) return; // prefix is valid
|
||||||
|
|
||||||
|
$contents = file_get_contents($this->path);
|
||||||
|
|
||||||
|
$matches = array();
|
||||||
|
if (preg_match('/\{.*\}/', $contents, $matches)) {
|
||||||
|
//update settings
|
||||||
|
file_put_contents($this->path, $valid_prefix . $matches[0]);
|
||||||
|
} else {
|
||||||
|
//reset settings
|
||||||
|
file_put_contents($this->path, $valid_prefix . json_encode(array()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value from the config array
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function get_value($key) {
|
||||||
|
|
||||||
|
$contents = $this->get_contents();
|
||||||
|
|
||||||
|
if (null === $contents) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($contents[$key])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contents[$key];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a value in our config array
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function set_value($key, $value) {
|
||||||
|
|
||||||
|
$contents = $this->get_contents();
|
||||||
|
|
||||||
|
if (null === $contents) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents[$key] = $value;
|
||||||
|
|
||||||
|
return (false !== file_put_contents($this->path, self::get_file_content_prefix() . json_encode($contents), LOCK_EX));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the config array from file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists($this->path)) $this->init_file();
|
||||||
|
|
||||||
|
// __COMPILER_HALT_OFFSET__ doesn't define in a few PHP versions. It's a PHP bug.
|
||||||
|
// https://bugs.php.net/bug.php?id=70164
|
||||||
|
$contents = file_get_contents($this->path, false, null, strlen(self::get_file_content_prefix()));
|
||||||
|
|
||||||
|
if (false === $contents) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($contents)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode($contents, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entire firewall config from array.
|
||||||
|
*
|
||||||
|
* @param Array $contents
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public function set_contents($contents) {
|
||||||
|
|
||||||
|
if (null === $contents) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false !== file_put_contents($this->path, self::get_file_content_prefix() . json_encode($contents), LOCK_EX));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:enable WordPress.WP.AlternativeFunctions -- WP isn't loaded here. WP API is unavailable
|
||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for accessing constants (including from wp-config) from the firewall
|
||||||
|
* Only supports parsing 'defines' that have scalar types: int, float, boolean, string and null
|
||||||
|
*/
|
||||||
|
class Constants implements \ArrayAccess, \IteratorAggregate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of constants parsed
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The token part of the token identifier
|
||||||
|
*
|
||||||
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
||||||
|
*/
|
||||||
|
const TOKEN = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string content of the token identifier
|
||||||
|
*
|
||||||
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
||||||
|
*/
|
||||||
|
const CONTENT = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The line number of the token identifier
|
||||||
|
*
|
||||||
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
||||||
|
*/
|
||||||
|
const LINE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset for define's name [ define(NAME, VALUE); ]
|
||||||
|
*/
|
||||||
|
const DEFINE_NAME_OFFSET = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset for define's value [ define(NAME, VALUE); ]
|
||||||
|
*/
|
||||||
|
const DEFINE_VALUE_OFFSET = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs our object
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->constants = array();
|
||||||
|
$this->populate_constants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates our internal constant array with the defines from wp-config
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function populate_constants() {
|
||||||
|
|
||||||
|
$wpconfig = Utility::get_wpconfig_path();
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists($wpconfig)) return;
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- WP isn't loaded. WP_Filesystem cannot be used.
|
||||||
|
$source = file_get_contents($wpconfig);
|
||||||
|
|
||||||
|
if (false === $source) return;
|
||||||
|
|
||||||
|
$tokens = token_get_all($source);
|
||||||
|
|
||||||
|
//Filter out any unwanted tokens
|
||||||
|
$tokens = array_values(array_filter($tokens, function($token) {
|
||||||
|
|
||||||
|
//All tokens that are not arrays are allowed
|
||||||
|
if (!is_array($token)) return true;
|
||||||
|
|
||||||
|
$unwanted_tokens = array(
|
||||||
|
'T_COMMENT',
|
||||||
|
'T_WHITESPACE',
|
||||||
|
'T_DOC_COMMENT',
|
||||||
|
);
|
||||||
|
|
||||||
|
return (!in_array(token_name($token[self::TOKEN]), $unwanted_tokens));
|
||||||
|
}));
|
||||||
|
|
||||||
|
$token_count = count($tokens);
|
||||||
|
for ($i = 0; $i < $token_count; $i++) {
|
||||||
|
|
||||||
|
$current = $tokens[$i];
|
||||||
|
|
||||||
|
if (!is_array($current)) continue;
|
||||||
|
|
||||||
|
if ('T_STRING' === token_name($current[self::TOKEN]) && 'define' === strtolower($current[self::CONTENT])) {
|
||||||
|
|
||||||
|
// Name of the define without the surrounding quotes
|
||||||
|
$name = substr($tokens[$i + self::DEFINE_NAME_OFFSET][self::CONTENT], 1, -1);
|
||||||
|
|
||||||
|
// Grabs the value of the define
|
||||||
|
$value = $tokens[$i + self::DEFINE_VALUE_OFFSET];
|
||||||
|
|
||||||
|
if (!is_array($value)) continue;
|
||||||
|
|
||||||
|
// We need to interpret the data type of the define's value
|
||||||
|
switch (token_name($value[self::TOKEN])) {
|
||||||
|
case 'T_CONSTANT_ENCAPSED_STRING':
|
||||||
|
$this->constants[$name] = substr($value[self::CONTENT], 1, -1);
|
||||||
|
break;
|
||||||
|
case 'T_LNUMBER':
|
||||||
|
$this->constants[$name] = intval($value[self::CONTENT]);
|
||||||
|
break;
|
||||||
|
case 'T_DNUMBER':
|
||||||
|
$this->constants[$name] = floatval($value[self::CONTENT]);
|
||||||
|
break;
|
||||||
|
case 'T_STRING':
|
||||||
|
$this->constants[$name] = filter_var($value[self::CONTENT], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access the constants as properties
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get($name) {
|
||||||
|
return $this[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over the constants
|
||||||
|
*
|
||||||
|
* @return iterable
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function getIterator() {
|
||||||
|
foreach ($this->constants as $name => $value) yield $name => $value;
|
||||||
|
foreach (get_defined_constants() as $name => $value) yield $name => $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives us array access to the constants
|
||||||
|
*
|
||||||
|
* @param mixed $offset
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetGet($offset) {
|
||||||
|
if (defined($offset)) {
|
||||||
|
return constant($offset);
|
||||||
|
} elseif (isset($this->constants[$offset])) {
|
||||||
|
return $this->constants[$offset];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the constant exists
|
||||||
|
*
|
||||||
|
* @param mixed $offset
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetExists($offset) {
|
||||||
|
return defined($offset) || isset($this->constants[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if constant exists
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function __isset($name) {
|
||||||
|
return $this->offsetExists($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the constant. This is disabled as we want it read-only
|
||||||
|
*
|
||||||
|
* @param mixed $offset
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception - Throws an exception if called to ensure it's read-only.
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetSet($offset, $value) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
|
||||||
|
throw new \Exception('Constants are read-only.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsets the constant. This is disabled as we want it read-only
|
||||||
|
*
|
||||||
|
* @param mixed $offset
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception - Throws an exception if called to ensure it's read-only.
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetUnset($offset) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
|
||||||
|
throw new \Exception('Constants are read-only.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to help debug the firewall
|
||||||
|
*/
|
||||||
|
class Debug {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs our object
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
//Capture the events that relate to the firewall's rules
|
||||||
|
Event::capture('rule_triggered', array($this, 'rule_debug'));
|
||||||
|
Event::capture('rule_not_triggered', array($this, 'rule_debug'));
|
||||||
|
Event::capture('rule_active', array($this, 'rule_debug'));
|
||||||
|
Event::capture('rule_not_active', array($this, 'rule_debug'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures the firewall's events for debugging rules
|
||||||
|
*
|
||||||
|
* @global Constants $aiowps_firewall_constants
|
||||||
|
* @global Message_Store $aiowps_firewall_message_store
|
||||||
|
*
|
||||||
|
* @param string $event
|
||||||
|
* @param Rule $rule
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function rule_debug($event, Rule $rule) {
|
||||||
|
global $aiowps_firewall_constants, $aiowps_firewall_message_store;
|
||||||
|
if (!$aiowps_firewall_constants->AIOS_FIREWALL_DEBUG && 'rule_triggered' !== $event) return;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'name' => $rule->name,
|
||||||
|
'family' => $rule->family,
|
||||||
|
'ip' => \AIOS_Helper::get_user_ip_address(),
|
||||||
|
'time' => time(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get any user information
|
||||||
|
foreach ($_COOKIE as $key => $value) {
|
||||||
|
if (preg_match('/^wordpress_logged_in_/', $key)) {
|
||||||
|
$details['potential_user'] = stripslashes($value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$details['request'] = $_SERVER;
|
||||||
|
unset($details['request']['HTTP_COOKIE']);
|
||||||
|
|
||||||
|
// Uncomment when the firewall log issues have been resolved
|
||||||
|
//$aiowps_firewall_message_store->set($event, $details);
|
||||||
|
|
||||||
|
// Remove when the firewall log issues have been resolved
|
||||||
|
$aiowps_firewall_message_store->clear_message_store();
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores our events
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $events = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures an event
|
||||||
|
*
|
||||||
|
* @param string $name - Name of the event
|
||||||
|
* @param callable $callback - Callback to execute when the event is raised
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function capture($name, callable $callback) {
|
||||||
|
$name = strtolower($name);
|
||||||
|
|
||||||
|
if (!isset(self::$events[$name])) {
|
||||||
|
self::$events[$name] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$events[$name][] = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raises the event
|
||||||
|
*
|
||||||
|
* All the callbacks in a given name are executed
|
||||||
|
*
|
||||||
|
* @param string $name - Name of the event to raise
|
||||||
|
* @param array ...$args - Variable list of arguments to pass to the callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function raise($name, ...$args) {
|
||||||
|
$name = strtolower($name);
|
||||||
|
|
||||||
|
if (empty(self::$events[$name])) return;
|
||||||
|
|
||||||
|
array_unshift($args, $name);
|
||||||
|
|
||||||
|
foreach (self::$events[$name] as $event) {
|
||||||
|
call_user_func_array($event, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this when throwing an exception if you want to also exit the request
|
||||||
|
*/
|
||||||
|
class Exit_Exception extends \Exception {
|
||||||
|
}
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
class Message_Store {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this class a singleton
|
||||||
|
*/
|
||||||
|
use Singleton_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal store of the messages
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the name of the message store's table
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $table_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key should only be loaded from the database once per request; this keeps track of them
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $keys_loaded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs our object
|
||||||
|
*/
|
||||||
|
private function __construct() {
|
||||||
|
Event::capture('action_before_exit', array($this, 'dump'));
|
||||||
|
$this->messages = array();
|
||||||
|
$this->keys_loaded = array();
|
||||||
|
$this->table_name = 'aiowps_message_store';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets internal message store
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($key, $value) {
|
||||||
|
|
||||||
|
if (!is_string($key)) return;
|
||||||
|
|
||||||
|
if (!isset($this->messages[$key])) {
|
||||||
|
$this->messages[$key] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->messages[$key][] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the messages associated with a key
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get($key) {
|
||||||
|
|
||||||
|
$is_key_loaded = in_array($key, $this->keys_loaded);
|
||||||
|
$can_check_database = isset($GLOBALS['wpdb']) && !$is_key_loaded && class_exists('Updraft_Semaphore_3_0');
|
||||||
|
|
||||||
|
//Load requested messages from the database
|
||||||
|
if ($can_check_database) {
|
||||||
|
|
||||||
|
$lock = new \Updraft_Semaphore_3_0('aios_message_store_lock_'.$key, 60);
|
||||||
|
$to_delete = array();
|
||||||
|
|
||||||
|
if ($lock->lock()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table = $this->get_table();
|
||||||
|
|
||||||
|
// If we can't get the table to check the DB, still check our internal store for the key
|
||||||
|
if (empty($table)) return isset($this->messages[$key]) ? $this->messages[$key] : array();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
|
||||||
|
$rows = $wpdb->get_results($wpdb->prepare("SELECT id, message_value FROM `{$table}` WHERE message_key = %s", $key));
|
||||||
|
|
||||||
|
if (!empty($rows)) {
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$values = json_decode($row->message_value, true);
|
||||||
|
|
||||||
|
foreach ($values as $value) $this->set($key, $value);
|
||||||
|
|
||||||
|
$to_delete[] = $row->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->keys_loaded[] = $key;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Necessary for AIOS error reporting system.
|
||||||
|
error_log("AIOS: Error getting database entries for key '{$key}': {$e->getMessage()}");
|
||||||
|
|
||||||
|
} catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
|
||||||
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Necessary for AIOS error reporting system.
|
||||||
|
error_log("AIOS: Error getting database entries for key '{$key}': {$e->getMessage()}");
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
//Delete IDs of loaded messages
|
||||||
|
if (!empty($to_delete)) {
|
||||||
|
$ids = implode(',', $to_delete);
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
|
||||||
|
$wpdb->query("DELETE FROM `{$table}` WHERE id IN ({$ids})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$lock->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($this->messages[$key]) ? $this->messages[$key] : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the message store to the database
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function dump() {
|
||||||
|
//No point saving if there are no messages
|
||||||
|
if (empty($this->messages)) return;
|
||||||
|
|
||||||
|
if (!Utility::attempt_to_access_wpdb()) throw new Exit_Exception('Unable to save the message store to the database: wpdb is inaccessible.');
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table = $this->get_table();
|
||||||
|
|
||||||
|
if (empty($table)) throw new Exit_Exception('Unable to save messages store to the database: unable to get the correct table.');
|
||||||
|
|
||||||
|
$statement = "INSERT INTO `{$table}` (message_key, message_value, created) VALUES ";
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
foreach ($this->messages as $key => $value) {
|
||||||
|
$statement .= '(%s, %s, %s),';
|
||||||
|
$values[] = $table;
|
||||||
|
$values[] = $key;
|
||||||
|
$values[] = json_encode($value); // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- This method runs outside the WordPress environment and therefore cannot use WordPress functions.
|
||||||
|
$values[] = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$statement = rtrim($statement, ',');
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Prepared above.
|
||||||
|
$wpdb->query($wpdb->prepare($statement, $values));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the table name if it exists
|
||||||
|
*
|
||||||
|
* @return string - Table name on success; blank string otherwise
|
||||||
|
*/
|
||||||
|
private function get_table() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
if (!$wpdb) return '';
|
||||||
|
|
||||||
|
$table = $wpdb->get_blog_prefix(0).$this->table_name;
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
|
||||||
|
if ($table != $wpdb->get_var("SHOW TABLES LIKE '{$table}'")) return '';
|
||||||
|
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all the messages from the message store table if it contains data.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function clear_message_store() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table = $this->get_table();
|
||||||
|
|
||||||
|
// Check if the table exists and is accessible
|
||||||
|
if (empty($table)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the table has any rows
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Direct query necessary. No caching necessary.
|
||||||
|
$row_exists = $wpdb->get_var(
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- PCP error. Ignore.
|
||||||
|
$wpdb->prepare("SELECT EXISTS (SELECT 1 FROM `{$table}` LIMIT 1)")
|
||||||
|
);
|
||||||
|
|
||||||
|
// If there are no rows, $row_exists will be 0
|
||||||
|
if (!$row_exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the table (delete all records)
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Ignore.
|
||||||
|
$wpdb->query($wpdb->prepare("DELETE FROM `{$table}`"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trait with a basic singleton implementation
|
||||||
|
*/
|
||||||
|
trait Singleton_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internally stores the class's instance
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
private static $instance = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of the class
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public static function instance() {
|
||||||
|
|
||||||
|
if (is_null(self::$instance)) self::$instance = new self();
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We don't want our singleton object to be cloned
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function __clone() {
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait which exits the current request
|
||||||
|
*/
|
||||||
|
trait Action_Exit_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit when the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
Event::raise('action_before_exit');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the forbid and exit trait
|
||||||
|
*/
|
||||||
|
trait Action_Forbid_and_Exit_Trait {
|
||||||
|
|
||||||
|
use Action_Forbid_Trait, Action_Exit_Trait {
|
||||||
|
Action_Forbid_Trait::do_action as protected do_action_forbid;
|
||||||
|
Action_Exit_Trait::do_action as protected do_action_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forbid 403 and Exit when the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
$this->do_action_forbid();
|
||||||
|
$this->do_action_exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait to set the header to forbidden
|
||||||
|
*/
|
||||||
|
trait Action_Forbid_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forbid 403 when the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
header('HTTP/1.1 403 Forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
trait Action_Permblock_and_Exit_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the forbid and exit trait
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait {
|
||||||
|
Action_Forbid_and_Exit_Trait::do_action as protected do_action_forbid_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the reason for the perm. block
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $permblock_reason = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the IP for the perm. block
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $permblock_ip = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reason for the perm. block
|
||||||
|
*
|
||||||
|
* @param string $reason
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set_perm_block_reason($reason) {
|
||||||
|
$this->permblock_reason = $reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the IP for the perm. block
|
||||||
|
*
|
||||||
|
* @param string $ip
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set_perm_block_ip($ip) {
|
||||||
|
$this->permblock_ip = $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permanently ban the IP and exit when the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
|
||||||
|
if (!Utility::attempt_to_access_wpdb()) {
|
||||||
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Part of AIOS error reporting system.
|
||||||
|
error_log('AIOS: Unable to access wpdb to ban IP address.');
|
||||||
|
$this->do_action_forbid_and_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table = $wpdb->prefix.'aiowps_permanent_block';
|
||||||
|
|
||||||
|
$ip = empty($this->permblock_ip) ? \AIOS_Helper::get_user_ip_address() : $this->permblock_ip;
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'blocked_ip' => $ip,
|
||||||
|
'block_reason' => empty($this->permblock_reason) ? 'firewall_generic' : $this->permblock_reason,
|
||||||
|
'blocked_date' => current_time('mysql')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the IP already exists
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
|
||||||
|
$already_exists = $wpdb->get_var($wpdb->prepare("SELECT blocked_ip FROM `{$table}` WHERE blocked_ip = %s", $ip));
|
||||||
|
|
||||||
|
// If it does exist, no point adding it again so just forbid and exit
|
||||||
|
if (!is_null($already_exists)) $this->do_action_forbid_and_exit();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- PCP error. Table name cannot be done via prepare.
|
||||||
|
if (false === $wpdb->query($wpdb->prepare("INSERT INTO " .$table." (blocked_ip, block_reason, blocked_date, created) VALUES (%s, %s, %s, UNIX_TIMESTAMP())", $data['blocked_ip'], $data['block_reason'], $data['blocked_date']))) {
|
||||||
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- PCP warning. Needed for error reporting.
|
||||||
|
error_log('AIOS: Unable to insert IP address into table.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->do_action_forbid_and_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the redirect and exit trait
|
||||||
|
*/
|
||||||
|
trait Action_Redirect_and_Exit_Trait {
|
||||||
|
|
||||||
|
use Action_Redirect_Trait, Action_Exit_Trait {
|
||||||
|
Action_Redirect_Trait::do_action as protected do_action_redirect;
|
||||||
|
Action_Exit_Trait::do_action as protected do_action_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect and Exit when the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
$this->do_action_redirect();
|
||||||
|
$this->do_action_exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait to set the header to redirect
|
||||||
|
*/
|
||||||
|
trait Action_Redirect_Trait {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the location.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $location = '127.0.0.1';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect the rule condition is satisfied.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function do_action() {
|
||||||
|
header("Location: $this->location");
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain kinds of data from the query string
|
||||||
|
*/
|
||||||
|
class Rule_Block_Query_Strings_6g extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Block query strings';
|
||||||
|
$this->family = '6G';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_query');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
//Patterns to match against
|
||||||
|
$patterns = array(
|
||||||
|
'/[a-z0-9]{2000,}/i',
|
||||||
|
'/(eval\()/i',
|
||||||
|
'/(127\.0\.0\.1)/i',
|
||||||
|
'/(javascript:)(.*)(;)/i',
|
||||||
|
'/(base64_encode)(.*)(\()/i',
|
||||||
|
'/(GLOBALS|REQUEST)(=|\[|%)/i',
|
||||||
|
'/(<|%3C)(.*)script(.*)(>|%3)/i',
|
||||||
|
'#(\|\.\.\.|\.\./|~|`|<|>|\|)#i',
|
||||||
|
'#(boot\.ini|etc/passwd|self/environ)#i',
|
||||||
|
'/(thumbs?(_editor|open)?|tim(thumb)?)\.php/i',
|
||||||
|
'/(\'|\")(.*)(drop|insert|md5|select|union)/i',
|
||||||
|
);
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
return Rule_Utils::contains_pattern(rawurldecode($_SERVER['QUERY_STRING']), $patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain referrers recommended by 6G
|
||||||
|
*/
|
||||||
|
class Rule_Block_Refs_6g extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Block referrer strings';
|
||||||
|
$this->family = '6G';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_referrers');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['HTTP_REFERER'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
//Patterns to match against
|
||||||
|
$patterns = array(
|
||||||
|
'/[a-z0-9]{2000,}/i',
|
||||||
|
'/(semalt.com|todaperfeita)/i',
|
||||||
|
);
|
||||||
|
|
||||||
|
return Rule_Utils::contains_pattern($_SERVER['HTTP_REFERER'], $patterns); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain kinds of data from the request string
|
||||||
|
*/
|
||||||
|
class Rule_Block_Request_Strings_6g extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Block request strings';
|
||||||
|
$this->family = '6G';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_request');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
// ensure we get the request uri without the query string
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
$uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||||
|
|
||||||
|
if ('' == $uri) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
//Patterns to match against
|
||||||
|
$patterns = array(
|
||||||
|
'/[a-z0-9]{2000,}/i',
|
||||||
|
'#(https?|ftp|php):/#i',
|
||||||
|
'#(base64_encode)(.*)(\()#i',
|
||||||
|
'#(=\'|=\%27|/\'/?)\.#i',
|
||||||
|
'#/(\$(\&)?|\*|\"|\.|,|&|&?)/?$#i',
|
||||||
|
'#(\{0\}|\(/\(|\.\.\.|\+\+\+|\\"\\")#i',
|
||||||
|
'#(~|`|<|>|:|;|,|%|\|\s|\{|\}|\[|\]|\|)#i',
|
||||||
|
'#/(=|\$&|_mm|cgi-|etc/passwd|muieblack)#i',
|
||||||
|
'#(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)#i',
|
||||||
|
'#\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$#i',
|
||||||
|
'#/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php#i',
|
||||||
|
);
|
||||||
|
|
||||||
|
return Rule_Utils::contains_pattern(rawurldecode($uri), $patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain user-agents recommended by 6G
|
||||||
|
*/
|
||||||
|
class Rule_Block_User_Agents_6g extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Block user-agents';
|
||||||
|
$this->family = '6G';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_6g_block_agents');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['HTTP_USER_AGENT'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
//Patterns to match against
|
||||||
|
$patterns = array(
|
||||||
|
'/[a-z0-9]{2000,}/i',
|
||||||
|
'/(archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune)/i',
|
||||||
|
);
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
return Rule_Utils::contains_pattern($_SERVER['HTTP_USER_AGENT'], $patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain kinds of HTTP request methods (e.g DEBUG or PUT)
|
||||||
|
*/
|
||||||
|
class Rule_Request_Method_6g extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of request methods to block
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $blocked_methods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Block request methods';
|
||||||
|
$this->family = '6G';
|
||||||
|
$this->priority = 0;
|
||||||
|
|
||||||
|
$this->blocked_methods = $aiowps_firewall_config->get_value('aiowps_6g_block_request_methods');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
return !empty($this->blocked_methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
return isset($_SERVER['REQUEST_METHOD']) && in_array(strtoupper($_SERVER['REQUEST_METHOD']), $this->blocked_methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks IPs to access.
|
||||||
|
*/
|
||||||
|
class Rule_Ips_Blacklist extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of IPs / IP range to block
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $blocked_ips;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*
|
||||||
|
* @global Config $aiowps_firewall_config
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Blocked IPs';
|
||||||
|
$this->family = 'Blacklist';
|
||||||
|
$this->priority = 0;
|
||||||
|
$this->blocked_ips = $aiowps_firewall_config->get_value('aiowps_blacklist_ips');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @global Constants $aiowps_firewall_constants
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_constants;
|
||||||
|
if ($aiowps_firewall_constants->AIOS_DISABLE_BLACKLIST_IP_MANAGER) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !empty($this->blocked_ips);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
$user_ip_blocked = \AIOS_Helper::is_user_ip_address_within_list($this->blocked_ips);
|
||||||
|
|
||||||
|
if (true == $user_ip_blocked) return Rule::SATISFIED;
|
||||||
|
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks user agents to access.
|
||||||
|
*/
|
||||||
|
class Rule_User_Agent_Blacklist extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of user agents to block
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $blocked_user_agents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Blocked user agents';
|
||||||
|
$this->family = 'Blacklist';
|
||||||
|
$this->priority = 0;
|
||||||
|
$this->blocked_user_agents = $aiowps_firewall_config->get_value('aiowps_blacklist_user_agents');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
return !empty($this->blocked_user_agents) && isset($_SERVER['HTTP_USER_AGENT']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
foreach ($this->blocked_user_agents as $block_user_agent) {
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
if (isset($_SERVER['HTTP_USER_AGENT']) && !empty($block_user_agent) && false !== stripos($_SERVER['HTTP_USER_AGENT'], $block_user_agent)) {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that bans the IP address if the POST request has a blank user-agent and referer
|
||||||
|
*/
|
||||||
|
class Rule_Ban_Post_Blank_Headers extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Permblock_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Ban POST requests with blank user-agent and referer';
|
||||||
|
$this->family = 'Bots';
|
||||||
|
$this->priority = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_ban_post_blank_headers');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
$this->set_perm_block_reason('firewall_post_blank_user_agent_and_referer');
|
||||||
|
return isset($_SERVER['REQUEST_METHOD']) && (0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST")) && empty($_SERVER['HTTP_USER_AGENT']) && empty($_SERVER['HTTP_REFERER']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is not a WordPress context. Also this only evaluates to a boolean.
|
||||||
|
}
|
||||||
|
}
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks fake Googlebots.
|
||||||
|
*/
|
||||||
|
class Rule_Block_Fake_Googlebots extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken.
|
||||||
|
*/
|
||||||
|
use Action_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule.
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata.
|
||||||
|
$this->name = 'Block fake Googlebots';
|
||||||
|
$this->family = 'Bots';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active.
|
||||||
|
*
|
||||||
|
* @global Config $aiowps_firewall_config
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_block_fake_googlebots');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply.
|
||||||
|
*
|
||||||
|
* @global Config $aiowps_firewall_config
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
|
||||||
|
$user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
|
||||||
|
|
||||||
|
if (preg_match('/Googlebot/i', $user_agent, $matches)) {
|
||||||
|
// If the user agent says it's a Googlebot, start doing checks.
|
||||||
|
|
||||||
|
$ip = \AIOS_Helper::get_user_ip_address();
|
||||||
|
|
||||||
|
if (empty($ip)) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$name = gethostbyaddr($ip); // Let's get the hostname using the IP address.
|
||||||
|
|
||||||
|
if ($name == $ip || false === $name) {
|
||||||
|
// gethostbyaddr failed.
|
||||||
|
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||||
|
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
} else {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$host_ip = gethostbyname($name); // Reverse lookup - let's get the IP address using the hostname.
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// gethostbyaddr or gethostbyname not available on site.
|
||||||
|
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||||
|
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
} else {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
} catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
|
||||||
|
// gethostbyaddr or gethostbyname not available on site.
|
||||||
|
$googlebot_ips = $aiowps_firewall_config->get_value('aiowps_googlebot_ip_ranges');
|
||||||
|
if (\AIOS_Helper::is_user_ip_address_within_list($googlebot_ips)) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
} else {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^(?:.+\.)?googlebot\.com$/i', $name) || preg_match('/^(?:.+\.)?google\.com$/i', $name) || preg_match('/^(?:.+\.)?googleusercontent\.com$/i', $name)) {
|
||||||
|
if ($host_ip == $ip) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
} else {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that uses a cookie to prevent bruteforce attacks.
|
||||||
|
*/
|
||||||
|
class Rule_Cookie_Prevent_Bruteforce extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Redirect_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Cookie based prevent bruteforce';
|
||||||
|
$this->family = 'Bruteforce';
|
||||||
|
$this->priority = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config, $aiowps_firewall_constants;
|
||||||
|
if ($aiowps_firewall_constants->AIOS_DISABLE_COOKIE_BRUTE_FORCE_PREVENTION) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aios_enable_brute_force_attack_prevention');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
/**
|
||||||
|
* This rule is not applied at AIOS plugin activation time.
|
||||||
|
*/
|
||||||
|
$is_plugins_page = isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('#/wp-admin/(network/)?plugins\.php$#i', $_SERVER['SCRIPT_FILENAME']);
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||||
|
$is_activation_action = isset($_GET['action']) && 'activate' === $_GET['action'];
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||||
|
$is_target_plugin = isset($_GET['plugin']) && 'all-in-one-wp-security-and-firewall/wp-security.php' === $_GET['plugin'];
|
||||||
|
|
||||||
|
|
||||||
|
if ($is_plugins_page && $is_activation_action && $is_target_plugin) {
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
$brute_force_secret_word = $aiowps_firewall_config->get_value('aios_brute_force_secret_word');
|
||||||
|
$brute_force_secret_cookie_name = $aiowps_firewall_config->get_value('aios_brute_force_secret_cookie_name');
|
||||||
|
$login_page_slug = $aiowps_firewall_config->get_value('aios_login_page_slug');
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||||
|
if (!isset($_GET[$brute_force_secret_word])) {
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||||
|
$brute_force_secret_cookie_val = isset($_COOKIE[$brute_force_secret_cookie_name]) ? $_COOKIE[$brute_force_secret_cookie_name] : '';
|
||||||
|
$pw_protected_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_pw_protected_exception');
|
||||||
|
$prevent_ajax_exception = $aiowps_firewall_config->get_value('aios_brute_force_attack_prevention_ajax_exception');
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||||
|
if (!empty($_SERVER['REQUEST_URI']) && !hash_equals($brute_force_secret_cookie_val, \AIOS_Helper::get_hash($brute_force_secret_word))) {
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing is not required, as we validate the raw input.
|
||||||
|
$request_uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||||
|
|
||||||
|
// admin section or login page or login custom slug called
|
||||||
|
$is_admin_or_login = (false != strpos($request_uri, 'wp-admin') || false != strpos($request_uri, 'wp-login') || ('' != $login_page_slug && false != strpos($request_uri, $login_page_slug))) ? 1 : 0;
|
||||||
|
|
||||||
|
// admin side ajax called
|
||||||
|
$is_admin_ajax_request = ('1' == $prevent_ajax_exception && isset($_SERVER['SCRIPT_NAME']) && ('admin-ajax.php' === basename($_SERVER['SCRIPT_NAME']))) ? 1 : 0;
|
||||||
|
|
||||||
|
// password protected page called
|
||||||
|
$is_password_protected_access = ('1' == $pw_protected_exception && isset($_GET['action']) && 'postpass' == $_GET['action']) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||||
|
|
||||||
|
// logout, set password, reset password action called
|
||||||
|
$is_logout_resetpassword_action = (isset($_GET['action']) && ('logout' == $_GET['action'] || 'rp' == $_GET['action'] || 'resetpass' == $_GET['action'])) ? 1 : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. A nonce is not available at this point.
|
||||||
|
|
||||||
|
// cookie based brute force on and accessing admin without ajax and password protected then redirect
|
||||||
|
if ($is_admin_or_login && !$is_admin_ajax_request && !$is_password_protected_access && !$is_logout_resetpassword_action) {
|
||||||
|
$redirect_url = $aiowps_firewall_config->get_value('aios_cookie_based_brute_force_redirect_url');
|
||||||
|
$this->location = $redirect_url;
|
||||||
|
return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain kinds of data from the request string
|
||||||
|
*/
|
||||||
|
class Rule_Advanced_Character_Filter extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Advanced character filter';
|
||||||
|
$this->family = 'General';
|
||||||
|
$this->priority = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_advanced_char_string_filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['REQUEST_URI'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
// ensure we get the request uri without the query string
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
$uri = (string) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||||
|
|
||||||
|
return Rule_Utils::contains_pattern($uri, array_merge($this->get_general_characters(), $this->get_common_patterns(), $this->get_specific_exploits()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of 'specific exploits' patterns
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function get_specific_exploits() {
|
||||||
|
return array(
|
||||||
|
'/errors\./i',
|
||||||
|
'/config\./i',
|
||||||
|
'/include\./i',
|
||||||
|
'/display\./i',
|
||||||
|
'/register\./i',
|
||||||
|
'/password\./i',
|
||||||
|
'/maincore\./i',
|
||||||
|
'/authorize\./i',
|
||||||
|
'/macromates\./i',
|
||||||
|
'/head\_auth\./i',
|
||||||
|
'/submit\_links\./i',
|
||||||
|
'/change\_action\./i',
|
||||||
|
'/com\_facileforms\//i',
|
||||||
|
'/admin\_db\_utilities\./i',
|
||||||
|
'/admin\.webring\.docs\./i',
|
||||||
|
'/Table\/Latest\/index\./i',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of common patterns
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function get_common_patterns() {
|
||||||
|
return array(
|
||||||
|
'/\_vpi/i',
|
||||||
|
'/\.inc/i',
|
||||||
|
'/xAou6/i',
|
||||||
|
'/db\_name/i',
|
||||||
|
'/select\(/i',
|
||||||
|
'/convert\(/i',
|
||||||
|
'/\/query\//i',
|
||||||
|
'/ImpEvData/i',
|
||||||
|
'/\.XMLHTTP/i',
|
||||||
|
'/proxydeny/i',
|
||||||
|
'/function\./i',
|
||||||
|
'/remoteFile/i',
|
||||||
|
'/servername/i',
|
||||||
|
'/\&rptmode\=/i',
|
||||||
|
'/sys\_cpanel/i',
|
||||||
|
'/db\_connect/i',
|
||||||
|
'/doeditconfig/i',
|
||||||
|
'/check\_proxy/i',
|
||||||
|
'/system\_user/i',
|
||||||
|
'/\/\(null\)\//i',
|
||||||
|
'/clientrequest/i',
|
||||||
|
'/option\_value/i',
|
||||||
|
'/ref\.outcontrol/i',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of general characters
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function get_general_characters() {
|
||||||
|
return array(
|
||||||
|
'/\,/i',
|
||||||
|
'/\:/i',
|
||||||
|
'/\;/i',
|
||||||
|
'/\=/i',
|
||||||
|
'/\[/i',
|
||||||
|
'/\]/i',
|
||||||
|
'/\^/i',
|
||||||
|
'/\`/i',
|
||||||
|
'/\{/i',
|
||||||
|
'/\}/i',
|
||||||
|
'/\~/i',
|
||||||
|
'/\"/i',
|
||||||
|
'/\$/i',
|
||||||
|
'/\</i',
|
||||||
|
'/\>/i',
|
||||||
|
'/\|/i',
|
||||||
|
'/\.\./i',
|
||||||
|
'/\%0/i',
|
||||||
|
'/\%A/i',
|
||||||
|
'/\%B/i',
|
||||||
|
'/\%C/i',
|
||||||
|
'/\%D/i',
|
||||||
|
'/\%E/i',
|
||||||
|
'/\%F/i',
|
||||||
|
'/\%22/i',
|
||||||
|
'/\%27/i',
|
||||||
|
'/\%28/i',
|
||||||
|
'/\%29/i',
|
||||||
|
'/\%3C/i',
|
||||||
|
'/\%3E/i',
|
||||||
|
'/\%3F/i',
|
||||||
|
'/\%5B/i',
|
||||||
|
'/\%5C/i',
|
||||||
|
'/\%5D/i',
|
||||||
|
'/\%7B/i',
|
||||||
|
'/\%7C/i',
|
||||||
|
'/\%7D/i',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks certain data from the URL's query string
|
||||||
|
*/
|
||||||
|
class Rule_Bad_Query_Strings extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Bad query strings';
|
||||||
|
$this->family = 'General';
|
||||||
|
$this->priority = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_deny_bad_query_strings');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
if (empty($_SERVER['QUERY_STRING'])) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
$patterns = array(
|
||||||
|
'/ftp:/i',
|
||||||
|
'/http:/i',
|
||||||
|
'/https:/i',
|
||||||
|
'/mosConfig/i',
|
||||||
|
'/^.*(globals|encode|loopback).*/i',
|
||||||
|
"/(\;|'|\"|%22).*(request|insert|union|declare|drop)/i",
|
||||||
|
);
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
return Rule_Utils::contains_pattern($_SERVER['QUERY_STRING'], $patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks access to the xmlrpc.php file
|
||||||
|
*/
|
||||||
|
class Rule_Block_Xmlrpc extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Completely block XMLRPC';
|
||||||
|
$this->family = 'General';
|
||||||
|
$this->priority = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_enable_pingback_firewall');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
return (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/xmlrpc\.php$/i', $_SERVER['SCRIPT_FILENAME']));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule that blocks comments being posted if a proxy is detected.
|
||||||
|
*/
|
||||||
|
class Rule_Proxy_Comment_Posting extends Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the action to be taken
|
||||||
|
*/
|
||||||
|
use Action_Forbid_and_Exit_Trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct our rule
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
// Set the rule's metadata
|
||||||
|
$this->name = 'Proxy comment posting';
|
||||||
|
$this->family = 'General';
|
||||||
|
$this->priority = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
global $aiowps_firewall_config;
|
||||||
|
return (bool) $aiowps_firewall_config->get_value('aiowps_forbid_proxy_comments');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The condition to be satisfied for the rule to apply
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_satisfied() {
|
||||||
|
|
||||||
|
//Preconditions for the rule
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
$is_comment_form = (isset($_SERVER['SCRIPT_FILENAME']) && 1 === preg_match('/\/wp-comments-post\.php$/i', $_SERVER['SCRIPT_FILENAME']));
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- PCP warning. Sanitizing will interfere with 6g rules.
|
||||||
|
$is_post = (isset($_SERVER['REQUEST_METHOD']) && 0 === strcasecmp($_SERVER['REQUEST_METHOD'], "POST"));
|
||||||
|
|
||||||
|
if (!$is_post || !$is_comment_form) return Rule::NOT_SATISFIED;
|
||||||
|
|
||||||
|
//Headers that are present if a proxy is being used
|
||||||
|
$headers = array(
|
||||||
|
'HTTP_VIA',
|
||||||
|
'HTTP_FORWARDED',
|
||||||
|
'HTTP_USERAGENT_VIA',
|
||||||
|
'HTTP_X_FORWARDED_FOR',
|
||||||
|
'HTTP_X_FORWARDED_HOST',
|
||||||
|
'HTTP_PROXY_CONNECTION',
|
||||||
|
'HTTP_XPROXY_CONNECTION',
|
||||||
|
'HTTP_PC_REMOTE_ADDR',
|
||||||
|
'HTTP_CLIENT_IP',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
if (!empty($_SERVER[$header])) return Rule::SATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Rule::NOT_SATISFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds our rules
|
||||||
|
*/
|
||||||
|
class Rule_Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets our rule if it's active
|
||||||
|
*
|
||||||
|
* @return iterable
|
||||||
|
*/
|
||||||
|
public static function get_active_rule() {
|
||||||
|
|
||||||
|
foreach (self::get_rule_classname() as $classname) {
|
||||||
|
|
||||||
|
$rule = new $classname();
|
||||||
|
|
||||||
|
if (!$rule->is_active()) {
|
||||||
|
Event::raise('rule_not_active', $rule, $classname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::raise('rule_active', $rule, $classname);
|
||||||
|
yield $rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the classname for each rule
|
||||||
|
*
|
||||||
|
* @return iterable
|
||||||
|
*/
|
||||||
|
private static function get_rule_classname() {
|
||||||
|
$rec_iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(AIOWPS_FIREWALL_DIR.'/rule/rules/', \FilesystemIterator::SKIP_DOTS));
|
||||||
|
|
||||||
|
foreach ($rec_iterator as $dir_iterator) {
|
||||||
|
$matches = array();
|
||||||
|
if (preg_match('/^rule-(?<rule_name>.*)\.php$/', $dir_iterator->getFilename(), $matches)) {
|
||||||
|
yield "AIOWPS\Firewall\Rule_".ucwords(str_replace('-', '_', $matches['rule_name']), '_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods to help with the rules
|
||||||
|
*/
|
||||||
|
class Rule_Utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the subject contains the given pattern or patterns
|
||||||
|
*
|
||||||
|
* @param string $subject - The subject we wish to check the pattern or patterns against.
|
||||||
|
* @param string|array $pattern - Regex pattern. An array for multiple patterns; a string otherwise.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function contains_pattern($subject, $pattern) {
|
||||||
|
|
||||||
|
if (empty($subject)) return false;
|
||||||
|
|
||||||
|
if (is_string($pattern)) return (1 === preg_match($pattern, $subject));
|
||||||
|
|
||||||
|
if (!is_array($pattern)) return false;
|
||||||
|
|
||||||
|
foreach ($pattern as $patt) {
|
||||||
|
if (preg_match($patt, $subject)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for our firewall rules
|
||||||
|
*/
|
||||||
|
abstract class Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the rule
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the family the rule belongs to
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $family;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rule's priority (0 is the highest)
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstraction for when the rule is satisfied
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
const SATISFIED = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstraction for when the rule is not satisfied
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
const NOT_SATISFIED = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the rule's action
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract public function do_action();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the rule is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
abstract public function is_active();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the rule has been satisfied
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
abstract public function is_satisfied();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the rule and execute the action if satisfied
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function apply() {
|
||||||
|
|
||||||
|
if ($this->is_satisfied()) {
|
||||||
|
|
||||||
|
Event::raise('rule_triggered', $this, time());
|
||||||
|
$this->do_action();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::raise('rule_not_triggered', $this, time());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the rule's name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The firewall can be loaded from several different contexts. This class detects from which context the firewall is loaded.
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible contexts where the firewall can be loaded
|
||||||
|
*/
|
||||||
|
const DIRECTIVE = 'directive';
|
||||||
|
const PLUGINS_LOADED = 'plugins_loaded';
|
||||||
|
const WP_CONFIG = 'wp-config';
|
||||||
|
const MU_PLUGIN = 'mu-plugin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current context where the firewall is running
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function current() {
|
||||||
|
|
||||||
|
$incs = get_included_files();
|
||||||
|
$index = self::get_bootstrap_index($incs);
|
||||||
|
|
||||||
|
$is_setup = (-1 !== $index);
|
||||||
|
|
||||||
|
if (!$is_setup) return self::PLUGINS_LOADED;
|
||||||
|
|
||||||
|
if (0 === $index) return self::DIRECTIVE;
|
||||||
|
|
||||||
|
if (preg_match('/wp-config\.php$/i', $incs[$index-1])) {
|
||||||
|
return self::WP_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/aios-firewall-loader\.php$/', $incs[$index-1])) {
|
||||||
|
return self::MU_PLUGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::DIRECTIVE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we're in a context safe to run WordPress functions
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function wordpress_safe() {
|
||||||
|
return (self::plugins_loaded() || self::mu_plugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current context is `plugins_loaded`
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function plugins_loaded() {
|
||||||
|
return (self::PLUGINS_LOADED === self::current());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current context is `directive` (i.e: auto_prepend_file)
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function directive() {
|
||||||
|
return (self::DIRECTIVE === self::current());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current context is `wp_config`
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function wp_config() {
|
||||||
|
return (self::WP_CONFIG === self::current());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current context is `mu_plugin`
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function mu_plugin() {
|
||||||
|
return (self::MU_PLUGIN === self::current());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate the bootstrap file's index
|
||||||
|
*
|
||||||
|
* @param array $incs
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static function get_bootstrap_index(array $incs) {
|
||||||
|
foreach ($incs as $index => $file) {
|
||||||
|
if (preg_match('/aios-bootstrap\.php$/', $file)) {
|
||||||
|
return $index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
+214
@@ -0,0 +1,214 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
if (!defined('AIOWPS_FIREWALL_DIR')) {
|
||||||
|
header('HTTP/1.1 403 Forbidden');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and executes our firewall
|
||||||
|
*/
|
||||||
|
class Loader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to itself
|
||||||
|
*
|
||||||
|
* @var Loader
|
||||||
|
*/
|
||||||
|
protected static $instance = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and builds all the necessary files
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function load_firewall() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The preloader file should not be directly accessed.
|
||||||
|
* It should only be loaded via the bootstrap file or in a WordPress context
|
||||||
|
*/
|
||||||
|
if ($this->is_preloader_directly_accessed()) return;
|
||||||
|
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
global $aiowps_firewall_constants;
|
||||||
|
if ($aiowps_firewall_constants->AIOS_NO_FIREWALL) return;
|
||||||
|
|
||||||
|
//Allow list for bypassing PHP rules
|
||||||
|
if (Allow_List::is_ip_allowed()) return;
|
||||||
|
|
||||||
|
$families = new Family_Collection(Family_Builder::get_families());
|
||||||
|
|
||||||
|
foreach (Rule_Builder::get_active_rule() as $rule) {
|
||||||
|
$families->add_rule_to_member($rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($families->get_family() as $member) {
|
||||||
|
$member->apply_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exit_Exception $e) {
|
||||||
|
$this->log_message($e->getMessage());
|
||||||
|
exit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->log_message($e->getMessage());
|
||||||
|
} catch (\Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound -- this won't run on PHP 5.6 so we still want to catch it on other versions
|
||||||
|
$this->log_message($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs general initialisation
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function init() {
|
||||||
|
|
||||||
|
$this->init_includes();
|
||||||
|
$this->init_services();
|
||||||
|
|
||||||
|
new Debug();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects whether the preloader file (wp-security-firewall.php) was directly accessed
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_preloader_directly_accessed() {
|
||||||
|
return (1 === preg_match('/wp-security-firewall\.php$/', get_included_files()[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log our error messages
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function log_message($message) {
|
||||||
|
if (function_exists('do_action')) {
|
||||||
|
do_action('aios_firewall_loader_log_error', $message, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('AIOS firewall error: ' . $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises our services
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function init_services() {
|
||||||
|
|
||||||
|
$workspace = $this->get_firewall_workspace();
|
||||||
|
|
||||||
|
if (empty($workspace)) {
|
||||||
|
throw new \Exception('unable to locate workspace.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$GLOBALS['aiowps_firewall_config'] = new Config($workspace . 'settings.php');
|
||||||
|
$GLOBALS['aiowps_firewall_message_store'] = Message_Store::instance();
|
||||||
|
$GLOBALS['aiowps_firewall_constants'] = new Constants();
|
||||||
|
Allow_List::set_path($workspace.'allowlist.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get our workspace directory, i.e., where we save and load data to and from.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function get_firewall_workspace() {
|
||||||
|
global $aiowps_firewall_rules_path;
|
||||||
|
|
||||||
|
$workspace = '';
|
||||||
|
|
||||||
|
if (!empty($aiowps_firewall_rules_path)) {
|
||||||
|
$workspace = $aiowps_firewall_rules_path;
|
||||||
|
} elseif (Context::wordpress_safe()) {
|
||||||
|
$workspace = \AIOWPSecurity_Utility_Firewall::get_firewall_rules_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the autoloader
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function init_includes() {
|
||||||
|
|
||||||
|
spl_autoload_register(function($class) {
|
||||||
|
if (0 === strpos($class, "AIOWPS\\Firewall\\")) { //only autoload the firewall's files
|
||||||
|
|
||||||
|
$relative_classname = substr($class, strlen("AIOWPS\\Firewall\\"), strlen($class)-1);
|
||||||
|
|
||||||
|
$classname = str_replace('_', '-', strtolower($relative_classname));
|
||||||
|
|
||||||
|
$file = "wp-security-firewall-{$classname}.php";
|
||||||
|
$rule = "{$classname}.php";
|
||||||
|
|
||||||
|
$paths = array(
|
||||||
|
AIOWPS_FIREWALL_DIR."/{$file}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/family/{$file}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/{$file}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/actions/{$classname}.php",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/6g/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/bruteforce/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/blacklist/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/general/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/rule/rules/bots/{$rule}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/libs/{$file}",
|
||||||
|
AIOWPS_FIREWALL_DIR."/libs/traits/{$classname}.php",
|
||||||
|
);
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
include_once($path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manually include needed files
|
||||||
|
$classes_dir = dirname(AIOWPS_FIREWALL_DIR);
|
||||||
|
|
||||||
|
$manual_files = array(
|
||||||
|
$classes_dir.'/wp-security-firewall-resource-unavailable.php',
|
||||||
|
$classes_dir.'/wp-security-firewall-resource.php',
|
||||||
|
$classes_dir.'/wp-security-helper.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($manual_files as $file) {
|
||||||
|
clearstatcache();
|
||||||
|
if (file_exists($file)) include_once $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Context::wordpress_safe()) {
|
||||||
|
include_once("{$classes_dir}/wp-security-utility-file.php");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets or creates an instance of this object
|
||||||
|
*
|
||||||
|
* @return Loader
|
||||||
|
*/
|
||||||
|
public static function get_instance() {
|
||||||
|
|
||||||
|
if (null === self::$instance) {
|
||||||
|
return new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+218
@@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
namespace AIOWPS\Firewall;
|
||||||
|
|
||||||
|
class Utility {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory of where the WordPress files are installed
|
||||||
|
* This differs from get_root_dir() when WordPress is setup in a subdirectory
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_wordpress_dir() {
|
||||||
|
|
||||||
|
if (Context::wordpress_safe()) {
|
||||||
|
return wp_normalize_path(ABSPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
global $aiowps_firewall_data;
|
||||||
|
|
||||||
|
return isset($aiowps_firewall_data['ABSPATH']) ? $aiowps_firewall_data['ABSPATH'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the root directory of the site
|
||||||
|
* This may be different from where the WordPress files are installed if WordPress is setup in a subdirectory
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function get_root_dir() {
|
||||||
|
|
||||||
|
if (Context::wordpress_safe()) {
|
||||||
|
return \AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're in the firewall context here, so get the root directory from the bootstrap file path
|
||||||
|
$includes = get_included_files();
|
||||||
|
|
||||||
|
foreach ($includes as $file) {
|
||||||
|
if (preg_match('/aios-bootstrap\.php$/', $file)) {
|
||||||
|
return self::normalize_path(dirname($file).'/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the file path
|
||||||
|
*
|
||||||
|
* @see https://developer.wordpress.org/reference/functions/wp_normalize_path/
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function normalize_path($path) {
|
||||||
|
// Standardize all paths to use '/'.
|
||||||
|
$path = str_replace('\\', '/', $path);
|
||||||
|
|
||||||
|
// Replace multiple slashes down to a singular, allowing for network shares having two slashes.
|
||||||
|
$path = preg_replace('|(?<=.)/+|', '/', $path);
|
||||||
|
|
||||||
|
// Windows paths should uppercase the drive letter.
|
||||||
|
if (':' === substr($path, 1, 1)) {
|
||||||
|
$path = ucfirst($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path to wp-config.php
|
||||||
|
*
|
||||||
|
* @param string $root - Where to look for wp-config.php file
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_wpconfig_path($root = '') {
|
||||||
|
|
||||||
|
if (empty($root)) $root = self::get_wordpress_dir();
|
||||||
|
|
||||||
|
$wp_config_file = $root . 'wp-config.php';
|
||||||
|
if (file_exists($wp_config_file)) {
|
||||||
|
return $wp_config_file;
|
||||||
|
} elseif (file_exists(dirname($root) . '/wp-config.php')) {
|
||||||
|
return dirname($root) . '/wp-config.php';
|
||||||
|
}
|
||||||
|
return $wp_config_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive directory creation based on full path
|
||||||
|
*
|
||||||
|
* @see https://developer.wordpress.org/reference/functions/wp_mkdir_p/
|
||||||
|
* @param string $target
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function wp_mkdir_p($target) {
|
||||||
|
$wrapper = null;
|
||||||
|
|
||||||
|
// Strip the protocol.
|
||||||
|
if (self::wp_is_stream($target)) {
|
||||||
|
list($wrapper, $target) = explode('://', $target, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From php.net/mkdir user contributed notes.
|
||||||
|
$target = str_replace('//', '/', $target);
|
||||||
|
|
||||||
|
// Put the wrapper back on the target.
|
||||||
|
if (null !== $wrapper) {
|
||||||
|
$target = $wrapper . '://' . $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Safe mode fails with a trailing slash under certain PHP versions.
|
||||||
|
* Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
|
||||||
|
*/
|
||||||
|
$target = rtrim($target, '/');
|
||||||
|
if (empty($target)) {
|
||||||
|
$target = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($target)) {
|
||||||
|
return @is_dir($target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not allow path traversals.
|
||||||
|
if (false !== strpos($target, '../') || false !== strpos($target, '..' . DIRECTORY_SEPARATOR)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to find the permissions of the parent folder that exists and inherit that.
|
||||||
|
$target_parent = dirname($target);
|
||||||
|
while ('.' !== $target_parent && ! is_dir($target_parent) && dirname($target_parent) !== $target_parent) {
|
||||||
|
$target_parent = dirname($target_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the permission bits
|
||||||
|
$stat = @stat($target_parent);
|
||||||
|
if ($stat) {
|
||||||
|
$dir_perms = $stat['mode'] & 0007777;
|
||||||
|
} else {
|
||||||
|
$dir_perms = 0777;
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- PCP error. WP not loaded. WP API not available.
|
||||||
|
if (@mkdir($target, $dir_perms, true)) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a umask is set that modifies $dir_perms, we'll have to re-set
|
||||||
|
* the $dir_perms correctly with chmod()
|
||||||
|
*/
|
||||||
|
if (($dir_perms & ~umask()) != $dir_perms) {
|
||||||
|
$folder_parts = explode('/', substr($target, strlen($target_parent) + 1));
|
||||||
|
for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) {
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions -- PCP error. WP not loaded. WP API not available.
|
||||||
|
chmod($target_parent . '/' . implode('/', array_slice($folder_parts, 0, $i)), $dir_perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a given path is a stream URL
|
||||||
|
*
|
||||||
|
* @see https://developer.wordpress.org/reference/functions/wp_is_stream/
|
||||||
|
* @param string $path
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function wp_is_stream($path) {
|
||||||
|
$scheme_separator = strpos($path, '://');
|
||||||
|
|
||||||
|
if (false === $scheme_separator) {
|
||||||
|
// $path isn't a stream.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stream = substr($path, 0, $scheme_separator);
|
||||||
|
|
||||||
|
return in_array($stream, stream_get_wrappers(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to give us access to the $wpdb object from the firewall.
|
||||||
|
* This should only be used when you're sure WordPress will not be loading after the firewall.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function attempt_to_access_wpdb() {
|
||||||
|
|
||||||
|
// wpdb is already accessible
|
||||||
|
if (isset($GLOBALS['wpdb'])) return true;
|
||||||
|
|
||||||
|
$wp_path = self::get_wordpress_dir() . 'wp-load.php';
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists($wp_path)) return false;
|
||||||
|
|
||||||
|
define('SHORTINIT', true);
|
||||||
|
|
||||||
|
$included = (bool) include $wp_path;
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// If $wpdb is inaccessible by this point, it means loading wp-settings didn't complete.
|
||||||
|
// So we have to manually include the wp-config (which includes wp-settings) for it to complete.
|
||||||
|
if (empty($wpdb) && $included) include self::get_wpconfig_path();
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
return !empty($wpdb);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This is the file that will be loaded using auto_prepend_file directive
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('AIOWPS_FIREWALL_DIR')) {
|
||||||
|
define('AIOWPS_FIREWALL_DIR', dirname(__FILE__));
|
||||||
|
define('AIOWPS_FIREWALL_DIR_PARENT', dirname(AIOWPS_FIREWALL_DIR));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('AIOWPSEC_FIREWALL_DONE')) {
|
||||||
|
|
||||||
|
//Gracefully handle if the file is unable to be included. (i.e: ensure the user's site does not crash)
|
||||||
|
if (!(@include_once AIOWPS_FIREWALL_DIR . '/wp-security-firewall-loader.php')) {
|
||||||
|
error_log('AIOS firewall error: failed to load the firewall. Unable to include wp-security-firewall-loader.php.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
\AIOWPS\Firewall\Loader::get_instance()->load_firewall();
|
||||||
|
define('AIOWPSEC_FIREWALL_DONE', true);
|
||||||
|
}
|
||||||
+800
@@ -0,0 +1,800 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; // Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Feature_Item_Manager {
|
||||||
|
|
||||||
|
private $feature_list = array();
|
||||||
|
|
||||||
|
public $feature_items = array();
|
||||||
|
|
||||||
|
private $total_points = 0;
|
||||||
|
|
||||||
|
private $total_achievable_points = 0;
|
||||||
|
|
||||||
|
private $feature_point_1 = "5";
|
||||||
|
|
||||||
|
private $feature_point_2 = "10";
|
||||||
|
|
||||||
|
private $feature_point_3 = "15";
|
||||||
|
|
||||||
|
private $feature_point_4 = "20";
|
||||||
|
|
||||||
|
private $sec_level_basic = "1";
|
||||||
|
|
||||||
|
private $sec_level_inter = "2";
|
||||||
|
|
||||||
|
private $sec_level_advanced = "3";
|
||||||
|
|
||||||
|
private $feature_active = "active";
|
||||||
|
|
||||||
|
private $feature_inactive = "inactive";
|
||||||
|
|
||||||
|
private $feature_partial = "partial";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor sets up the feature item manager
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->setup_feature_list();
|
||||||
|
$this->initialize_features();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets up the feature list
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function setup_feature_list() {
|
||||||
|
$feature_list = array(
|
||||||
|
// Settings menu features
|
||||||
|
'wp-generator-meta-tag' => array(
|
||||||
|
'name' => __('Remove WP generator meta tag', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_remove_wp_generator_meta_info'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// User Accounts menu features
|
||||||
|
'user-accounts-change-admin-user' => array(
|
||||||
|
'name' => __('Change admin username', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
''
|
||||||
|
),
|
||||||
|
'callback' => array($this, 'check_user_accounts_change_admin_user_feature')
|
||||||
|
),
|
||||||
|
'user-accounts-display-name' => array(
|
||||||
|
'name' => __('Change display name', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
''
|
||||||
|
),
|
||||||
|
'callback' => array($this, 'check_user_accounts_display_name_feature')
|
||||||
|
),
|
||||||
|
// User Login menu features
|
||||||
|
'user-login-login-lockdown' => array(
|
||||||
|
'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_login_lockdown'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'user-login-force-logout' => array(
|
||||||
|
'name' => __('Force logout', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_forced_logout'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'hibp' => array(
|
||||||
|
'name' => __('HIBP', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_hibp_user_profile_update',
|
||||||
|
'aiowps_http_password_reset',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'disable-application-password' => array(
|
||||||
|
'name' => __('Disable application password', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disable_application_password'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'user-login-lockout-ip-whitelisting' => array(
|
||||||
|
'name' => __('Login Lockout IP whitelisting', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_lockdown_enable_whitelisting'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// User Registration menu features
|
||||||
|
'manually-approve-registrations' => array(
|
||||||
|
'name' => __('Registration approval', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_manual_registration_approval'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'user-registration-captcha' => array(
|
||||||
|
'name' => __('Registration CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_registration_page_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'registration-honeypot' => array(
|
||||||
|
'name' => __('Enable registration honeypot', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_registration_honeypot'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'http-authentication-admin-frontend' => array(
|
||||||
|
'name' => __('HTTP authentication for admin and frontend', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_http_authentication_admin',
|
||||||
|
'aiowps_http_authentication_frontend',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Database Security menu features
|
||||||
|
'db-security-db-prefix' => array(
|
||||||
|
'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
''
|
||||||
|
),
|
||||||
|
'callback' => array($this, 'check_db_security_db_prefix_feature')
|
||||||
|
),
|
||||||
|
// Filesystem Security menu features
|
||||||
|
'filesystem-file-permissions' => array(
|
||||||
|
'name' => __('File permissions', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
''
|
||||||
|
),
|
||||||
|
'callback' => array($this, 'check_filesystem_permissions_feature')
|
||||||
|
),
|
||||||
|
'filesystem-file-editing' => array(
|
||||||
|
'name' => __('File editing', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disable_file_editing'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'auto-delete-wp-files' => array(
|
||||||
|
'name' => __('WordPress files access', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_auto_delete_default_wp_files'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Blacklist Manager menu features
|
||||||
|
'blacklist-manager-ip-user-agent-blacklisting' => array(
|
||||||
|
'name' => __('IP and user agent blacklisting', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_blacklisting'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Firewall menu features
|
||||||
|
'firewall-basic-rules' => array(
|
||||||
|
'name' => __('Enable basic firewall', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_basic_firewall'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
|
||||||
|
),
|
||||||
|
'firewall-pingback-rules' => array(
|
||||||
|
'name' => __('Enable pingback vulnerability protection', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_pingback_firewall'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-block-debug-file-access' => array(
|
||||||
|
'name' => __('Block access to debug log file', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_block_debug_log_file_access'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
|
||||||
|
),
|
||||||
|
'firewall-disable-index-views' => array(
|
||||||
|
'name' => __('Disable index views', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disable_index_views'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
|
||||||
|
),
|
||||||
|
'firewall-disable-trace-track' => array(
|
||||||
|
'name' => __('Disable trace and track', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disable_trace_and_track'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess')
|
||||||
|
),
|
||||||
|
'firewall-forbid-proxy-comments' => array(
|
||||||
|
'name' => __('Forbid proxy comments', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_forbid_proxy_comments'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-deny-bad-queries' => array(
|
||||||
|
'name' => __('Deny bad queries', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_deny_bad_query_strings'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-advanced-character-string-filter' => array(
|
||||||
|
'name' => __('Advanced character string filter', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_advanced_char_string_filter'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-enable-6g' => array(
|
||||||
|
'name' => __('6G firewall', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_6g_firewall',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-block-fake-googlebots' => array(
|
||||||
|
'name' => __('Block fake Googlebots', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_block_fake_googlebots'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'prevent-hotlinking' => array(
|
||||||
|
'name' => __('Prevent image hotlinking', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_prevent_hotlinking'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-enable-404-blocking' => array(
|
||||||
|
'name' => __('Enable IP blocking for 404 detection', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_404_IP_lockout'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-disable-rss-and-atom' => array(
|
||||||
|
'name' => __('Disable RSS and ATOM feeds', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disable_rss_and_atom_feeds'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'upgrade-unsafe-http-calls' => array(
|
||||||
|
'name' => __('Upgrade unsafe HTTP calls', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_upgrade_unsafe_http_calls'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Brute Force menu features
|
||||||
|
'bf-rename-login-page' => array(
|
||||||
|
'name' => __('Enable rename login page', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_rename_login_page'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'firewall-enable-brute-force-attack-prevention' => array(
|
||||||
|
'name' => __('Enable brute force attack prevention', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_brute_force_attack_prevention'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'user-login-captcha' => array(
|
||||||
|
'name' => __('Login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_login_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'lost-password-captcha' => array(
|
||||||
|
'name' => __('Lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_lost_password_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'custom-login-captcha' => array(
|
||||||
|
'name' => __('Custom login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_custom_login_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'password_protected-captcha' => array(
|
||||||
|
'name' => __('Password-protected CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_password_protected_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'whitelist-manager-ip-login-whitelisting' => array(
|
||||||
|
'name' => __('Login IP whitelisting', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_whitelisting'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'login-honeypot' => array(
|
||||||
|
'name' => __('Enable login honeypot', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_login_honeypot'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Spam Prevention menu features
|
||||||
|
'comment-form-captcha' => array(
|
||||||
|
'name' => __('Comment CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_comment_captcha'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'detect-spambots' => array(
|
||||||
|
'name' => __('Detect spambots', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_spambot_detecting'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'auto-block-spam-ips' => array(
|
||||||
|
'name' => __('Auto block spam ips', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_autoblock_spam_ip'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Scanner menu features
|
||||||
|
'scan-file-change-detection' => array(
|
||||||
|
'name' => __('File change detection', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_4,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_automated_fcd_scan'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Miscellaneous menu features
|
||||||
|
'enable-copy-protection' => array(
|
||||||
|
'name' => __('Enable Copy Protection', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_copy_protection'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'enable-frame-protection' => array(
|
||||||
|
'name' => __('Enable iFrame protection', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_prevent_site_display_inside_frame'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'disable-users-enumeration' => array(
|
||||||
|
'name' => __('Disable users enumeration', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_prevent_users_enumeration'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'disallow-unauthorised-requests' => array(
|
||||||
|
'name' => __('Disallow unauthorized REST requests', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_disallow_unauthorized_rest_requests'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'enable-salt-postfix' => array(
|
||||||
|
'name' => __('Enable salt postfix', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_3,
|
||||||
|
'level' => $this->sec_level_advanced,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_salt_postfix'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// conditional features
|
||||||
|
'bp-register-captcha' => array(
|
||||||
|
'name' => __('BuddyPress registration CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_bp_register_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_buddypress_plugin_active'),
|
||||||
|
),
|
||||||
|
'bbp-new-topic-captcha' => array(
|
||||||
|
'name' => __('bbPress new topic CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_bbp_new_topic_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_bbpress_plugin_active'),
|
||||||
|
),
|
||||||
|
'woo-login-captcha' => array(
|
||||||
|
'name' => __('Woo login CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_woo_login_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
|
||||||
|
),
|
||||||
|
'woo-lostpassword-captcha' => array(
|
||||||
|
'name' => __('Woo lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_woo_lostpassword_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
|
||||||
|
),
|
||||||
|
'woo-register-captcha' => array(
|
||||||
|
'name' => __('Woo register CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_woo_register_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
|
||||||
|
),
|
||||||
|
'woo-checkout-captcha' => array(
|
||||||
|
'name' => __('Woo Checkout CAPTCHA', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_woo_checkout_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'),
|
||||||
|
),
|
||||||
|
// Ban POST requests with blank user-agent and referer
|
||||||
|
'firewall-ban-post-blank-headers' => array(
|
||||||
|
'name' => __('Ban POST requests that have blank user-agent and referer headers', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_2,
|
||||||
|
'level' => $this->sec_level_inter,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_ban_post_blank_headers'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'contact-form-7-captcha' => array(
|
||||||
|
/* translators: %s: Plugin name */
|
||||||
|
'name' => sprintf(__('%s CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'Contact Form 7'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enable_contact_form_7_captcha'
|
||||||
|
),
|
||||||
|
'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_contact_form_7_plugin_active'),
|
||||||
|
),
|
||||||
|
'enforce-strong-password' => array(
|
||||||
|
'name' => __('Enforce use of strong passwords by users', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'points' => $this->feature_point_1,
|
||||||
|
'level' => $this->sec_level_basic,
|
||||||
|
'options' => array(
|
||||||
|
'aiowps_enforce_strong_password'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$feature_list = apply_filters('aiowpsecurity_feature_list', $feature_list);
|
||||||
|
$this->feature_list = array_filter($feature_list, array($this, 'should_add_item'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will create a feature item object for each feature in the feature list
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function initialize_features() {
|
||||||
|
foreach ($this->feature_list as $id => $data) {
|
||||||
|
$callback = isset($data['callback']) ? $data['callback'] : array($this, 'is_feature_enabled');
|
||||||
|
$this->feature_items[$id] = new AIOWPSecurity_Feature_Item($id, $data['name'], $data['points'], $data['level'], $data['options'], $callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will return the feature item for the passed in ID
|
||||||
|
*
|
||||||
|
* @param string $feature_id - the id of the feature item we want to return
|
||||||
|
*
|
||||||
|
* @return boolean|AIOWPSecurity_Feature_Item - returns a feature item or false on coding error
|
||||||
|
*/
|
||||||
|
public function get_feature_item_by_id($feature_id) {
|
||||||
|
if (isset($this->feature_items[$feature_id])) return $this->feature_items[$feature_id];
|
||||||
|
error_log("AIOS Feature Manager - Feature ID not found (coding error): $feature_id");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the callback function associated with the feature item.
|
||||||
|
*
|
||||||
|
* @param mixed $feature_item The feature item object.
|
||||||
|
*/
|
||||||
|
private function call_feature_callback($feature_item) {
|
||||||
|
call_user_func($feature_item->callback, $feature_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will output the feature details badge HTML
|
||||||
|
*
|
||||||
|
* @param string $feature_id - the id of the feature we want to get the badge for
|
||||||
|
* @param bool $return_instead_of_echo - whether to return the HTML or echo it
|
||||||
|
*
|
||||||
|
* @return string|void
|
||||||
|
*/
|
||||||
|
public function output_feature_details_badge($feature_id, $return_instead_of_echo = false) {
|
||||||
|
// Retrieve the feature item by ID
|
||||||
|
$feature_item = $this->get_feature_item_by_id($feature_id);
|
||||||
|
|
||||||
|
if (!$feature_item) return;
|
||||||
|
|
||||||
|
$this->call_feature_callback($feature_item);
|
||||||
|
|
||||||
|
// Prepare HTML for the feature badge
|
||||||
|
$max_security_points = $feature_item->item_points;
|
||||||
|
$current_security_points = $feature_item->is_active() ? $max_security_points : 0;
|
||||||
|
$security_level = $feature_item->get_security_level_string();
|
||||||
|
$protection_level = (0 == $current_security_points) ? 'none' : 'full';
|
||||||
|
$status_icon = (0 == $current_security_points) ? 'dashicons-unlock' : 'dashicons-lock';
|
||||||
|
|
||||||
|
$badge_html = '<div class="aiowps_feature_details_badge">';
|
||||||
|
$badge_html .= '<span class="aiowps_feature_details_badge_difficulty aiowps_feature_protection_'.$protection_level.'" title="'.__('Feature difficulty', 'all-in-one-wp-security-and-firewall').'">';
|
||||||
|
$badge_html .= '<span class="dashicons '.$status_icon.'"></span>'.$security_level.'</span>';
|
||||||
|
$badge_html .= '<span class="aiowps_feature_details_badge_points" title="'.__('Security points', 'all-in-one-wp-security-and-firewall').'">';
|
||||||
|
$badge_html .= $current_security_points.'/'.$max_security_points.'</span>';
|
||||||
|
$badge_html .= '</div>';
|
||||||
|
|
||||||
|
if ($return_instead_of_echo) {
|
||||||
|
return $badge_html;
|
||||||
|
} else {
|
||||||
|
echo $badge_html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will calculate the total points for the AJAX save function
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function calculate_total_feature_points() {
|
||||||
|
$this->calculate_total_points();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will setup the feature status and calculate the total points
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function check_feature_status_and_recalculate_points() {
|
||||||
|
$this->check_and_set_feature_status();
|
||||||
|
$this->calculate_total_points();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will calculate the total points for the site
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function calculate_total_points() {
|
||||||
|
foreach ($this->feature_items as $item) {
|
||||||
|
if ($item->is_active()) $this->total_points = $this->total_points + intval($item->item_points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will calculate the total achievable points
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function calculate_total_achievable_points() {
|
||||||
|
foreach ($this->feature_items as $item) {
|
||||||
|
$this->total_achievable_points = $this->total_achievable_points + intval($item->item_points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will return the total points for the site
|
||||||
|
*
|
||||||
|
* @return int - the total points for the site
|
||||||
|
*/
|
||||||
|
public function get_total_site_points() {
|
||||||
|
if (empty($this->total_points)) $this->calculate_total_points();
|
||||||
|
return $this->total_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will return the total achievable points
|
||||||
|
*
|
||||||
|
* @return int - the total achievable points
|
||||||
|
*/
|
||||||
|
public function get_total_achievable_points() {
|
||||||
|
if (empty($this->total_achievable_points)) $this->calculate_total_achievable_points();
|
||||||
|
return $this->total_achievable_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will loop over each feature item, checking if it's enabled and setting it's feature status
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function check_and_set_feature_status() {
|
||||||
|
foreach ($this->feature_items as $item) {
|
||||||
|
call_user_func($item->callback, $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if the feature database value is active and set the feature status
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_Feature_Item $item - the item we want to check is active
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function is_feature_enabled($item) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
$aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG);
|
||||||
|
|
||||||
|
$enabled = false;
|
||||||
|
foreach ($item->feature_options as $option) {
|
||||||
|
if ('1' == $aiowps_firewall_config->get_value($option) || '1' == $aio_wp_security->configs->get_value($option)) $enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($enabled) {
|
||||||
|
$item->set_feature_status($this->feature_active);
|
||||||
|
} else {
|
||||||
|
$item->set_feature_status($this->feature_inactive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if the default admin user exists and set the feature status
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_Feature_Item $item - the item we want to check is active
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function check_user_accounts_change_admin_user_feature($item) {
|
||||||
|
if (AIOWPSecurity_Utility::check_user_exists('admin')) {
|
||||||
|
$item->set_feature_status($this->feature_inactive);
|
||||||
|
} else {
|
||||||
|
$item->set_feature_status($this->feature_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if the username and nicknames are identical and set the feature status
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_Feature_Item $item - the item we want to check is active
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function check_user_accounts_display_name_feature($item) {
|
||||||
|
if (AIOWPSecurity_Utility::check_identical_login_and_nick_names()) {
|
||||||
|
$item->set_feature_status($this->feature_inactive);
|
||||||
|
} else {
|
||||||
|
$item->set_feature_status($this->feature_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if the default database prefix is in use and set the feature status
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_Feature_Item $item - the item we want to check is active
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function check_db_security_db_prefix_feature($item) {
|
||||||
|
global $wpdb;
|
||||||
|
$site_id = get_current_blog_id();
|
||||||
|
$default_prefix = (1 === $site_id) ? 'wp_' : "wp_{$site_id}_";
|
||||||
|
if ($default_prefix === $wpdb->prefix) {
|
||||||
|
$item->set_feature_status($this->feature_inactive);
|
||||||
|
} else {
|
||||||
|
$item->set_feature_status($this->feature_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check the filesystem permissions and set the feature status
|
||||||
|
*
|
||||||
|
* @param AIOWPSecurity_Feature_Item $item - the item we want to check is active
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function check_filesystem_permissions_feature($item) {
|
||||||
|
//TODO
|
||||||
|
$is_secure = 1;
|
||||||
|
$files_dirs_to_check = AIOWPSecurity_Utility_File::get_files_and_dirs_to_check();
|
||||||
|
|
||||||
|
foreach ($files_dirs_to_check as $file_or_dir) {
|
||||||
|
$actual_perm = AIOWPSecurity_Utility_File::get_file_permission($file_or_dir['path']);
|
||||||
|
$is_secure = $is_secure*AIOWPSecurity_Utility_File::is_file_permission_secure($file_or_dir['permissions'], $actual_perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only if all of the files' permissions are deemed secure give this a thumbs up
|
||||||
|
if (1 == $is_secure) {
|
||||||
|
$item->set_feature_status($this->feature_active);
|
||||||
|
} else {
|
||||||
|
$item->set_feature_status($this->feature_inactive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if an item should be added to the feature list
|
||||||
|
*
|
||||||
|
* @param array $item - the item we want to check if it should be added
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function should_add_item($item) {
|
||||||
|
if (empty($item['feature_condition_callback'])) {
|
||||||
|
return true;
|
||||||
|
} elseif (is_callable($item['feature_condition_callback'])) {
|
||||||
|
return call_user_func($item['feature_condition_callback']);
|
||||||
|
} else {
|
||||||
|
error_log("Callback function set but not callable (coding error). Feature: " . $item['name']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; // Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Feature_Item {
|
||||||
|
|
||||||
|
public $feature_id; // Example "user-accounts-tab1-change-admin-user"
|
||||||
|
|
||||||
|
public $feature_name;
|
||||||
|
|
||||||
|
public $item_points;
|
||||||
|
|
||||||
|
public $security_level; // 1, 2, 3
|
||||||
|
|
||||||
|
public $feature_status; // active, inactive, partial
|
||||||
|
|
||||||
|
public $feature_options; // The database options to check if the feature is enabled or not
|
||||||
|
|
||||||
|
public $callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor sets up the feature item
|
||||||
|
*
|
||||||
|
* @param string $feature_id - the id of the feature
|
||||||
|
* @param string $feature_name - the name of the feature
|
||||||
|
* @param string $item_points - the points this feature is worth
|
||||||
|
* @param string $security_level - the level of the feature
|
||||||
|
* @param array $feature_options - the options the feature uses
|
||||||
|
* @param boolean $callback - callback to set feature active status
|
||||||
|
*/
|
||||||
|
public function __construct($feature_id, $feature_name, $item_points, $security_level, $feature_options, $callback) {
|
||||||
|
$this->feature_id = $feature_id;
|
||||||
|
$this->feature_name = $feature_name;
|
||||||
|
$this->item_points = $item_points;
|
||||||
|
$this->security_level = $security_level;
|
||||||
|
$this->feature_options = $feature_options;
|
||||||
|
$this->callback = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will set the status of the feature
|
||||||
|
*
|
||||||
|
* @param string $status - the status of the feature
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set_feature_status($status) {
|
||||||
|
$this->feature_status = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will return the string version of the level
|
||||||
|
*
|
||||||
|
* @return string - the string value of the level
|
||||||
|
*/
|
||||||
|
public function get_security_level_string() {
|
||||||
|
$level_string = "";
|
||||||
|
if ("1" == $this->security_level) {
|
||||||
|
$level_string = __('Basic', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ("2" == $this->security_level) {
|
||||||
|
$level_string = __('Intermediate', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ("3" == $this->security_level) {
|
||||||
|
$level_string = __('Advanced', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
return $level_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will return a boolean to indicate if the feature is on or not
|
||||||
|
*
|
||||||
|
* @return boolean - true if the feature is on otherwise false
|
||||||
|
*/
|
||||||
|
public function is_active() {
|
||||||
|
return ('active' == $this->feature_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Do not modify the files in this folder.
|
||||||
|
*/
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) die('Access denied.');
|
||||||
|
/**
|
||||||
|
* This is a small glue class, which makes available all the commands in AIOWPSecurity_Commands, and translates the response from AIOWPSecurity_Commands (which is either data to return, or a WP_Error) into the format used by UpdraftCentral.
|
||||||
|
*/
|
||||||
|
class UpdraftCentral_WP_Security_Commands extends UpdraftCentral_Commands {
|
||||||
|
|
||||||
|
private $commands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->commands = new AIOWPSecurity_Commands();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic method to pass on the command to AIOWPSecurity_Commands
|
||||||
|
*
|
||||||
|
* @param string $name - command name
|
||||||
|
* @param array $arguments - command parameters
|
||||||
|
*
|
||||||
|
* @return array - response
|
||||||
|
*/
|
||||||
|
public function __call($name, $arguments) {
|
||||||
|
if (!is_callable(array($this->commands, $name))) {
|
||||||
|
return $this->_generic_error_response('aios_no_such_command', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = call_user_func_array(array($this->commands, $name), $arguments);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) {
|
||||||
|
return $this->_generic_error_response($result->get_error_code(), $result->get_error_data());
|
||||||
|
} else {
|
||||||
|
return $this->_response($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) die('Access denied.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is the bootstrapper for UpdraftCentral integration: i.e. it registers what is necessary to deal with commands in the AIOS namespace.
|
||||||
|
*/
|
||||||
|
class WP_Security_UpdraftCentral {
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
add_filter('updraftplus_remotecontrol_command_classes', array($this, 'updraftcentral_remotecontrol_command_classes'));
|
||||||
|
add_filter('updraftcentral_remotecontrol_command_classes', array($this, 'updraftcentral_remotecontrol_command_classes'));
|
||||||
|
add_action('updraftcentral_command_class_wanted', array($this, 'updraftcentral_command_class_wanted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register our class
|
||||||
|
*
|
||||||
|
* @param string $command_classes Passing over an array of command classes.
|
||||||
|
*/
|
||||||
|
public function updraftcentral_remotecontrol_command_classes($command_classes) {
|
||||||
|
if (is_array($command_classes)) $command_classes['aios'] = 'UpdraftCentral_WP_Security_Commands';
|
||||||
|
return $command_classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the class when required
|
||||||
|
*
|
||||||
|
* @param string $command_php_class Passing over if there are any command classes.
|
||||||
|
*/
|
||||||
|
public function updraftcentral_command_class_wanted($command_php_class) {
|
||||||
|
if ('UpdraftCentral_WP_Security_Commands' == $command_php_class) {
|
||||||
|
// This fragment is only needed for compatibility with UD < 1.12.30 - thenceforth, the class can be assumed to exist.
|
||||||
|
if (!class_exists('UpdraftCentral_Commands')) {
|
||||||
|
include_once(apply_filters('updraftcentral_command_base_class_at', UPDRAFTPLUS_DIR.'/central/commands.php'));
|
||||||
|
}
|
||||||
|
include_once(AIO_WP_SECURITY_PATH.'/classes/updraftcentral-wp-security-commands.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
new WP_Security_UpdraftCentral();
|
||||||
Executable
+121
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH') && !defined('AIOWPS_FIREWALL_DIR')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All ids and static names, array.
|
||||||
|
*/
|
||||||
|
if (class_exists('AIOS_Abstracted_Ids')) return;
|
||||||
|
|
||||||
|
class AIOS_Abstracted_Ids {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get firewall block request methods.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_firewall_block_request_methods() {
|
||||||
|
return array('DEBUG','MOVE', 'PUT', 'TRACK');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get IP retrieve methods.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_ip_retrieve_methods() {
|
||||||
|
// The keys are merely for maintaining backward compatibility.
|
||||||
|
return array(
|
||||||
|
'0' => 'REMOTE_ADDR',
|
||||||
|
'1' => 'HTTP_CF_CONNECTING_IP',
|
||||||
|
'2' => 'HTTP_X_FORWARDED_FOR',
|
||||||
|
'3' => 'HTTP_X_FORWARDED',
|
||||||
|
'4' => 'HTTP_CLIENT_IP',
|
||||||
|
'5' => 'HTTP_X_REAL_IP',
|
||||||
|
'6' => 'HTTP_X_CLUSTER_CLIENT_IP',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AIOS custom admin notice ids.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function custom_admin_notice_ids() {
|
||||||
|
return array(
|
||||||
|
'automated-database-backup',
|
||||||
|
'ip-retrieval-settings',
|
||||||
|
'load-firewall-resources-failed',
|
||||||
|
'end-of-support-php-56',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get notice ids for notices that have transformed HTACESS rules to PHP.
|
||||||
|
*
|
||||||
|
* @return array notice ids.
|
||||||
|
*/
|
||||||
|
public static function htaccess_to_php_feature_notice_ids() {
|
||||||
|
return array(
|
||||||
|
'login-whitelist-disabled-on-upgrade',
|
||||||
|
'ip-blacklist-settings-on-upgrade',
|
||||||
|
'upgrade-firewall-tab-rules',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get locale codes that are more than 2 char long supported by Google ReCaptcha.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_google_recaptcha_locale_codes() {
|
||||||
|
/**
|
||||||
|
* Google reCaptcha accepts 2 char language codes and also more than 2 char language codes.
|
||||||
|
* Most are 2 chars in length e.g. 'ar' for Arabic.
|
||||||
|
* Few are more than 2 char in length e.g 'de-AT' for German (Austria)
|
||||||
|
*
|
||||||
|
* Below is the list of more than 2 char language codes supported by Google reCaptcha.
|
||||||
|
* if determine_locale() detects any of the below we return it, otherwise,
|
||||||
|
* we would return the 2 letter code.
|
||||||
|
*/
|
||||||
|
return array(
|
||||||
|
'zh-HK', // Chinese (Hong Kong).
|
||||||
|
'zh-CN', // Chinese (Simplified).
|
||||||
|
'zh-TW', // Chinese (Traditional).
|
||||||
|
'en-GB', // UK.
|
||||||
|
'fr-CA', // French (Canadian).
|
||||||
|
'de-AT', // German (Austria).
|
||||||
|
'de-CH', // German (Switzerland).
|
||||||
|
'pt-BR', // Portuguese (Brazil).
|
||||||
|
'pt-PT', // Portuguese (Portugal).
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get IP Lookup services.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_ip_lookup_services() {
|
||||||
|
return array(
|
||||||
|
'ipify' => 'http://api.ipify.org/',
|
||||||
|
'ipecho' => 'http://ipecho.net/plain',
|
||||||
|
'ident' => 'http://ident.me',
|
||||||
|
'tnedi' => 'http://tnedi.me',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Reverse IP Lookup services.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_reverse_ip_lookup_services() {
|
||||||
|
return array(
|
||||||
|
'ip-api' => 'http://ip-api.com/json/%s',
|
||||||
|
'ipinfo' => 'https://ipinfo.io/%s/json'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+253
@@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('Access denied.');
|
||||||
|
|
||||||
|
if (!class_exists('AIOWPSecurity_Ajax')) :
|
||||||
|
|
||||||
|
class AIOWPSecurity_Ajax {
|
||||||
|
|
||||||
|
private $commands_object;
|
||||||
|
|
||||||
|
private $nonce;
|
||||||
|
|
||||||
|
private $subaction;
|
||||||
|
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
private $results;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
private function __construct() {
|
||||||
|
if (!class_exists('AIOWPSecurity_Commands')) include_once(AIO_WP_SECURITY_PATH.'/classes/wp-security-commands.php');
|
||||||
|
$this->commands_object = new AIOWPSecurity_Commands();
|
||||||
|
|
||||||
|
add_action('wp_ajax_aios_ajax', array($this, 'handle_ajax_requests'));
|
||||||
|
add_action('wp_ajax_nopriv_get_antibot_keys', array($this->commands_object, 'get_antibot_keys'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return singleton instance
|
||||||
|
*
|
||||||
|
* @return AIOWPSecurity_Ajax Returns AIOWPSecurity_Ajax object
|
||||||
|
*/
|
||||||
|
public static function get_instance() {
|
||||||
|
static $instance = null;
|
||||||
|
if (null === $instance) {
|
||||||
|
$instance = new self();
|
||||||
|
}
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles ajax requests
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle_ajax_requests() {
|
||||||
|
$this->set_nonce();
|
||||||
|
$this->set_subaction();
|
||||||
|
$this->set_data();
|
||||||
|
|
||||||
|
$result = AIOWPSecurity_Utility_Permissions::check_nonce_and_user_cap($this->nonce, 'wp-security-ajax-nonce');
|
||||||
|
if (is_wp_error($result)) {
|
||||||
|
wp_send_json(array(
|
||||||
|
'result' => false,
|
||||||
|
'error_code' => $result->get_error_code(),
|
||||||
|
'error_message' => $result->get_error_message(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_multisite() && !current_user_can('manage_network_options')) {
|
||||||
|
if (!$this->is_valid_multisite_command()) {
|
||||||
|
$this->send_invalid_multisite_command_error_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->is_invalid_command()) {
|
||||||
|
$this->add_invalid_command_error_log_entry();
|
||||||
|
$this->set_invalid_command_error_response();
|
||||||
|
} else {
|
||||||
|
$this->execute_command();
|
||||||
|
$this->set_error_response_on_wp_error();
|
||||||
|
$this->maybe_set_results_as_null();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->json_encode_results();
|
||||||
|
|
||||||
|
$json_last_error = json_last_error();
|
||||||
|
if ($json_last_error) {
|
||||||
|
$this->set_error_response_on_json_encode_error($json_last_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $this->results; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Variable is an array containing escaped data.
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets nonce property value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_nonce() {
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput -- It's the actual nonce. It does not need sanitizing.
|
||||||
|
$this->nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets subaction property value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_subaction() {
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce already checked.
|
||||||
|
$this->subaction = empty($_POST['subaction']) ? '' : sanitize_text_field(wp_unslash($_POST['subaction']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets data property value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_data() {
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce already checked.
|
||||||
|
$this->data = isset($_POST['data']) ? wp_unslash($_POST['data']) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether it is multisite setup and command is valid multisite command
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function is_valid_multisite_command() {
|
||||||
|
/**
|
||||||
|
* Filters the commands allowed to the sub site admins. Other commands are only available to network admin. Only used in a multisite context.
|
||||||
|
*/
|
||||||
|
$allowed_commands = apply_filters('aios_multisite_allowed_commands', array(
|
||||||
|
'delete_audit_log',
|
||||||
|
'delete_locked_ip_record',
|
||||||
|
'clear_debug_logs',
|
||||||
|
'unlock_ip',
|
||||||
|
'blocked_ip_list_unblock_ip',
|
||||||
|
'lock_ip',
|
||||||
|
'dismiss_notice',
|
||||||
|
));
|
||||||
|
|
||||||
|
return in_array($this->subaction, $allowed_commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the invalid multisite command error response
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function send_invalid_multisite_command_error_response() {
|
||||||
|
wp_send_json(array(
|
||||||
|
'result' => false,
|
||||||
|
'error_code' => 'update_failed',
|
||||||
|
'error_message' => __('Options can only be saved by network admin', 'all-in-one-wp-security-and-firewall')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if applied ajax command is an invalid command or not
|
||||||
|
*
|
||||||
|
* @return bool Returns true if ajax command is an invalid command, false otherwise
|
||||||
|
*/
|
||||||
|
private function is_invalid_command() {
|
||||||
|
return !is_callable(array($this->commands_object, $this->subaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an error message for invalid ajax command
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function add_invalid_command_error_log_entry() {
|
||||||
|
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Part of error reporting.
|
||||||
|
error_log("AIOS: ajax_handler: no such command (" . $this->subaction . ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set `results` property with error response array for invalid ajax command
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_invalid_command_error_response() {
|
||||||
|
$this->results = array(
|
||||||
|
'result' => false,
|
||||||
|
'error_code' => 'command_not_found',
|
||||||
|
/* translators: %s: Subaction */
|
||||||
|
'error_message' => sprintf(__('The command "%s" was not found', 'all-in-one-wp-security-and-firewall'), $this->subaction)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the ajax command
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function execute_command() {
|
||||||
|
$this->results = call_user_func(array($this->commands_object, $this->subaction), $this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set `results` property with error message
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_error_response_on_wp_error() {
|
||||||
|
if (is_wp_error($this->results)) {
|
||||||
|
$this->results = array(
|
||||||
|
'result' => false,
|
||||||
|
'error_code' => $this->results->get_error_code(),
|
||||||
|
'error_message' => $this->results->get_error_message(),
|
||||||
|
'error_data' => $this->results->get_error_data(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set `results` property to null, if it is not yet set
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function maybe_set_results_as_null() {
|
||||||
|
// if nothing was returned for some reason, set as result null.
|
||||||
|
if (empty($this->results)) {
|
||||||
|
$this->results = array(
|
||||||
|
'result' => null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets `results` property with json encode error
|
||||||
|
*
|
||||||
|
* @param int $json_last_error
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function set_error_response_on_json_encode_error($json_last_error) {
|
||||||
|
$this->results = array(
|
||||||
|
'result' => false,
|
||||||
|
'error_code' => $json_last_error,
|
||||||
|
'error_message' => 'json_encode error : ' . $json_last_error,
|
||||||
|
'error_data' => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->results = wp_json_encode($this->results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json encode the `results` property value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function json_encode_results() {
|
||||||
|
$this->results = wp_json_encode($this->results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endif;
|
||||||
Executable
+159
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
require_once(AIO_WP_SECURITY_PATH.'/classes/wp-security-audit-events.php');
|
||||||
|
require_once(AIO_WP_SECURITY_PATH.'/classes/wp-security-audit-text-handler.php');
|
||||||
|
|
||||||
|
class AIOWPSecurity_Audit_Event_Handler {
|
||||||
|
|
||||||
|
protected static $_instance = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will create and return the only instance of this class.
|
||||||
|
*
|
||||||
|
* @return AIOWPSecurity_Audit_Event_Handler Returns an instance of the class
|
||||||
|
*/
|
||||||
|
public static function instance() {
|
||||||
|
if (empty(self::$_instance)) {
|
||||||
|
self::$_instance = new self();
|
||||||
|
}
|
||||||
|
return self::$_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the class.
|
||||||
|
*/
|
||||||
|
private function __construct() {
|
||||||
|
add_action('aiowps_record_event', array($this, 'record_event'), 10, 4);
|
||||||
|
add_action('aiowps_bulk_record_events', function($events) {
|
||||||
|
$this->add_bulk_events($events);
|
||||||
|
}, 10, 4);
|
||||||
|
add_action('aiowps_clean_old_events', array($this, 'delete_old_events'), 10);
|
||||||
|
|
||||||
|
if (!wp_next_scheduled('aiowps_clean_old_events')) {
|
||||||
|
wp_schedule_event(time(), 'daily', 'aiowps_clean_old_events');
|
||||||
|
}
|
||||||
|
|
||||||
|
AIOWPSecurity_Audit_Events::add_event_actions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function records an event in the audit log
|
||||||
|
*
|
||||||
|
* @global AIO_WP_Security $aio_wp_security
|
||||||
|
*
|
||||||
|
* @param string $event_type - the event type
|
||||||
|
* @param array $details - details about the event
|
||||||
|
* @param string $event_level - the event level
|
||||||
|
* @param string $username - the username, this is only used if there is no user logged in
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function record_event($event_type, $details, $event_level = 'info', $username = '') {
|
||||||
|
|
||||||
|
if (!function_exists('wp_get_current_user')) {
|
||||||
|
global $aio_wp_security;
|
||||||
|
|
||||||
|
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Audit_Event_Handler::record_event() called before plugins_loaded hook has run.", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$record_event = apply_filters('aios_audit_log_record_event', true, $event_type, $details, $event_level, $username);
|
||||||
|
|
||||||
|
if (!$record_event) return;
|
||||||
|
|
||||||
|
$user = wp_get_current_user();
|
||||||
|
$username = (is_a($user, 'WP_User') && 0 !== $user->ID) ? $user->user_login : $username;
|
||||||
|
$ip = apply_filters('aios_audit_log_event_user_ip', AIOWPSecurity_Utility_IP::get_user_ip_address());
|
||||||
|
$data = apply_filters('aios_audit_log_event_user_country_code', array('ip' => $ip));
|
||||||
|
$country_code = isset($data['country_code']) ? $data['country_code'] : '';
|
||||||
|
$stacktrace = maybe_serialize(AIOWPSecurity_Utility::normalise_call_stack_args(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS))); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Required for the stacktrace to work.
|
||||||
|
$network_id = get_current_network_id();
|
||||||
|
$site_id = get_current_blog_id();
|
||||||
|
$details = wp_json_encode($details, true);
|
||||||
|
|
||||||
|
$this->add_new_event($network_id, $site_id, $username, $ip, $event_level, $event_type, $details, $stacktrace, $country_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function adds the event to the audit log database table
|
||||||
|
*
|
||||||
|
* @param integer $network_id - the id of the current network
|
||||||
|
* @param integer $site_id - the id of the current site
|
||||||
|
* @param string $username - the username of the user who triggered the event
|
||||||
|
* @param string $ip - the IP address of the user
|
||||||
|
* @param string $event_level - the event level
|
||||||
|
* @param string $event_type - the event type
|
||||||
|
* @param string $details - details about the event
|
||||||
|
* @param string $stacktrace - the event stacktrace
|
||||||
|
* @param string $country_code - the country code
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function add_new_event($network_id, $site_id, $username, $ip, $event_level, $event_type, $details, $stacktrace, $country_code) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$wpdb->query($wpdb->prepare("INSERT INTO ".AIOWPSEC_TBL_AUDIT_LOG." (network_id, site_id, username, ip, level, event_type, details, stacktrace, created, country_code) VALUES (%d, %d, %s, %s, %s, %s, %s, %s, UNIX_TIMESTAMP(), %s)", $network_id, $site_id, $username, $ip, $event_level, $event_type, $details, $stacktrace, $country_code)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function adds multiple events to the audit log database table
|
||||||
|
*
|
||||||
|
* @param array $events - each event in the array must contain the keys (network_id, site_id, username, ip, level, event_type, details, stacktrace and created)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function add_bulk_events($events) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$sql = "INSERT INTO ".AIOWPSEC_TBL_AUDIT_LOG." (network_id, site_id, username, ip, level, event_type, details, stacktrace, created, country_code) VALUES ";
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$sql .= "(%d, %d, %s, %s, %s, %s, %s, %s, %d, %s),";
|
||||||
|
|
||||||
|
$record_event = apply_filters('aios_audit_log_record_event', true, $event['event_type'], $event['details'], $event['level'], $event['username']);
|
||||||
|
if (!$record_event) continue;
|
||||||
|
|
||||||
|
$event['ip'] = apply_filters('aios_audit_log_event_user_ip', $event['ip']);
|
||||||
|
$data = apply_filters('aios_audit_log_event_user_country_code', array('ip' => $event['ip']));
|
||||||
|
$event['country_code'] = isset($data['country_code']) ? $data['country_code'] : '';
|
||||||
|
$values[] = $event['network_id'];
|
||||||
|
$values[] = $event['site_id'];
|
||||||
|
$values[] = $event['username'];
|
||||||
|
$values[] = $event['ip'];
|
||||||
|
$values[] = $event['level'];
|
||||||
|
$values[] = $event['event_type'];
|
||||||
|
$values[] = $event['details'];
|
||||||
|
$values[] = $event['stacktrace'];
|
||||||
|
$values[] = $event['created'];
|
||||||
|
$values[] = $event['country_code'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove last ',' character from query
|
||||||
|
$sql = rtrim($sql, ',');
|
||||||
|
|
||||||
|
$wpdb->query($wpdb->prepare($sql, $values)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- The sql query is being dynamically built.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will try to delete all audit logs older than 3 months from the database.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function delete_old_events() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$after_days = 90;
|
||||||
|
|
||||||
|
if (defined('AIOWPSEC_PURGE_AUDIT_LOGS_AFTER_DAYS')) {
|
||||||
|
$after_days = abs(AIOWPSEC_PURGE_AUDIT_LOGS_AFTER_DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
$after_days = empty($after_days) ? 90 : $after_days;
|
||||||
|
$older_than_date = strtotime("-{$after_days} days", time());
|
||||||
|
|
||||||
|
$wpdb->query($wpdb->prepare("DELETE FROM ".AIOWPSEC_TBL_AUDIT_LOG." WHERE created < %s", $older_than_date)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- We can't use %i because our plugin supports wordpress < 6.2.
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+641
@@ -0,0 +1,641 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
class AIOWPSecurity_Audit_Events {
|
||||||
|
|
||||||
|
public static $log_levels = array(
|
||||||
|
'info',
|
||||||
|
'warning',
|
||||||
|
'fatal',
|
||||||
|
'error',
|
||||||
|
'debug',
|
||||||
|
'trace',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $event_types = array();
|
||||||
|
|
||||||
|
private static $installed_plugin_info = array();
|
||||||
|
|
||||||
|
private static $removed_plugin_info = array();
|
||||||
|
|
||||||
|
private static $installed_theme_info = array();
|
||||||
|
|
||||||
|
private static $removed_theme_info = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function adds all the event actions we want to capture and record in the audit log
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function add_event_actions() {
|
||||||
|
// Setup event types to display filter dropdown for audit logs list
|
||||||
|
add_action('init', 'AIOWPSecurity_Audit_Events::setup_event_types');
|
||||||
|
|
||||||
|
// Core events
|
||||||
|
add_action('_core_updated_successfully', 'AIOWPSecurity_Audit_Events::core_updated', 10, 2);
|
||||||
|
|
||||||
|
// Plugin events
|
||||||
|
add_action('upgrader_process_complete', 'AIOWPSecurity_Audit_Events::plugin_installed', 10, 2);
|
||||||
|
add_action('activated_plugin', 'AIOWPSecurity_Audit_Events::plugin_activated', 10, 2);
|
||||||
|
add_action('upgrader_process_complete', 'AIOWPSecurity_Audit_Events::plugin_updated', 10, 2);
|
||||||
|
add_action('deactivated_plugin', 'AIOWPSecurity_Audit_Events::plugin_deactivated', 10, 2);
|
||||||
|
add_action('delete_plugin', 'AIOWPSecurity_Audit_Events::plugin_delete', 10, 2);
|
||||||
|
add_action('deleted_plugin', 'AIOWPSecurity_Audit_Events::plugin_deleted', 10, 2);
|
||||||
|
|
||||||
|
// Theme events
|
||||||
|
add_action('upgrader_process_complete', 'AIOWPSecurity_Audit_Events::theme_installed', 10, 2);
|
||||||
|
add_action('switch_theme', 'AIOWPSecurity_Audit_Events::theme_activated', 10, 1);
|
||||||
|
add_action('upgrader_process_complete', 'AIOWPSecurity_Audit_Events::theme_updated', 10, 2);
|
||||||
|
add_action('delete_theme', 'AIOWPSecurity_Audit_Events::theme_delete', 10, 2);
|
||||||
|
add_action('deleted_theme', 'AIOWPSecurity_Audit_Events::theme_deleted', 10, 2);
|
||||||
|
|
||||||
|
// Translation events
|
||||||
|
add_action('upgrader_process_complete', 'AIOWPSecurity_Audit_Events::translation_updated', 10, 2);
|
||||||
|
|
||||||
|
// User events
|
||||||
|
add_action('password_reset', 'AIOWPSecurity_Audit_Events::password_reset', 10, 1);
|
||||||
|
add_action('deleted_user', 'AIOWPSecurity_Audit_Events::user_deleted', 10, 3);
|
||||||
|
add_action('remove_user_from_blog', 'AIOWPSecurity_Audit_Events::user_removed_from_blog', 10, 3);
|
||||||
|
|
||||||
|
// Rule events
|
||||||
|
add_action('plugins_loaded', 'AIOWPSecurity_Audit_Events::rule_event', 10, 2);
|
||||||
|
|
||||||
|
// Attach an URL to the details to show as a link for configuring rules
|
||||||
|
add_filter('aios_audit_filter_details', function($details, $event_type) {
|
||||||
|
|
||||||
|
// Ensure we only process rules from the firewall
|
||||||
|
if (!preg_match('/^rule_/', $event_type)) return $details;
|
||||||
|
|
||||||
|
$key = "{$details['firewall_event']['rule_name']}::{$details['firewall_event']['rule_family']}";
|
||||||
|
|
||||||
|
// Get the URL for the corresponding rule
|
||||||
|
$location = AIOS_Helper::get_firewall_rule_location($key);
|
||||||
|
$can_show_configure = !empty($location);
|
||||||
|
|
||||||
|
// Only the super admin on the main site can configure the firewall, so only show the configure link to them
|
||||||
|
if (is_multisite()) $can_show_configure = $can_show_configure && is_main_site() && is_super_admin();
|
||||||
|
|
||||||
|
if ($can_show_configure) $details['firewall_event']['location'] = admin_url("admin.php?{$location}");
|
||||||
|
|
||||||
|
return $details;
|
||||||
|
}, 10, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function removes event actions that need to be removed when we are removing the plugin
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function remove_event_actions() {
|
||||||
|
remove_action('delete_plugin', 'AIOWPSecurity_Audit_Events::plugin_delete');
|
||||||
|
remove_action('deleted_plugin', 'AIOWPSecurity_Audit_Events::plugin_deleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the event_types array
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function setup_event_types() {
|
||||||
|
self::$event_types = array(
|
||||||
|
'core_updated' => __('Core updated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'plugin_installed' => __('Plugin installed', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'plugin_activated' => __('Plugin activated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'plugin_updated' => __('Plugin updated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'plugin_deactivated' => __('Plugin deactivated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'plugin_deleted' => __('Plugin deleted', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'theme_installed' => __('Theme installed', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'theme_activated' => __('Theme activated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'theme_updated' => __('Theme updated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'theme_deleted' => __('Theme deleted', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'translation_updated' => __('Translation updated', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'entity_changed' => __('Entity changed', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'successful_login' => __('Successful login', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'successful_logout' => __('Successful logout', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'failed_login' => __('Failed login', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'user_registration' => __('User registration', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'user_deleted' => __('User deleted', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'user_removed' => __('User removed from blog', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'table_migration' => __('Table migration', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'rule_triggered' => __('Rule triggered', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'rule_not_triggered' => __('Rule not triggered', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'rule_active' => __('Rule active', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'rule_not_active' => __('Rule not active', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
'password_reset' => __('Password reset', 'all-in-one-wp-security-and-firewall'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a core updated event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $new_version - the wp version we updated to
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function core_updated($new_version) {
|
||||||
|
global $wp_version;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'core_updated' => array(
|
||||||
|
'old_version' => $wp_version,
|
||||||
|
'new_version' => $new_version
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'core_updated', $details, 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a plugin installed event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
* @param array $hook_extra - Array of bulk item update data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_installed($upgrader, $hook_extra) {
|
||||||
|
// If this is empty then we have no way to know if this is a plugin/theme install/update so create an entity changed event
|
||||||
|
if (empty($hook_extra)) {
|
||||||
|
self::event_entity_changed($upgrader);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('plugin' !== $hook_extra['type'] || 'install' !== $hook_extra['action']) return;
|
||||||
|
self::$installed_plugin_info = $upgrader->new_plugin_data;
|
||||||
|
self::event_plugin_changed('installed', '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a plugin activated event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $plugin - Path to the plugin file relative to the plugins directory
|
||||||
|
* @param boolean $network_activation - Whether to enable the plugin for all sites in the network or just the current site
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_activated($plugin, $network_activation) {
|
||||||
|
$network = $network_activation ? 'network' : '';
|
||||||
|
self::event_plugin_changed('activated', $plugin, $network);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a plugin updated event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
* @param array $hook_extra - Array of bulk item update data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_updated($upgrader, $hook_extra) {
|
||||||
|
// If this is empty then we have no way to know if this is a plugin/theme install/update so return as we catch this in plugin_installed()
|
||||||
|
if (empty($hook_extra)) return;
|
||||||
|
if ('plugin' !== $hook_extra['type'] || 'update' !== $hook_extra['action']) return;
|
||||||
|
if (isset($hook_extra['plugin'])) {
|
||||||
|
$plugin = $hook_extra['plugin'];
|
||||||
|
self::event_plugin_changed('updated', $plugin, '');
|
||||||
|
} elseif (isset($hook_extra['plugins'])) {
|
||||||
|
foreach ($hook_extra['plugins'] as $plugin) {
|
||||||
|
self::event_plugin_changed('updated', $plugin, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a plugin deactivated event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $plugin - Path to the plugin file relative to the plugins directory
|
||||||
|
* @param boolean $network_deactivation - Whether to disable the plugin for all sites in the network or just the current site
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_deactivated($plugin, $network_deactivation) {
|
||||||
|
$network = $network_deactivation ? 'network' : '';
|
||||||
|
self::event_plugin_changed('deactivated', $plugin, $network, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the plugin info of the plugin that is about to be deleted
|
||||||
|
*
|
||||||
|
* @param string $plugin - Path to the plugin file relative to the plugins directory
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_delete($plugin) {
|
||||||
|
$filename = WP_PLUGIN_DIR . '/' . $plugin;
|
||||||
|
if (!file_exists($filename)) return;
|
||||||
|
|
||||||
|
self::$removed_plugin_info = get_plugin_data($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a plugin deleted event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $plugin - Path to the plugin file relative to the plugins directory
|
||||||
|
* @param boolean $deleted - Whether the plugin deletion was successful
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function plugin_deleted($plugin, $deleted) {
|
||||||
|
if ($deleted) self::event_plugin_changed('deleted', $plugin, '', 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will construct the event details and send it to be recorded
|
||||||
|
*
|
||||||
|
* @param string $action - the action taken (activated, deactivated)
|
||||||
|
* @param string $plugin - Path to the plugin file relative to the plugins directory
|
||||||
|
* @param string $network - status of if the plugin was network activated/deactivated
|
||||||
|
* @param string $level - the log level
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function event_plugin_changed($action, $plugin, $network, $level = 'info') {
|
||||||
|
if ('deleted' == $action) {
|
||||||
|
$info = self::$removed_plugin_info;
|
||||||
|
} elseif ('installed' == $action) {
|
||||||
|
$info = self::$installed_plugin_info;
|
||||||
|
} else {
|
||||||
|
$filename = WP_PLUGIN_DIR . '/' . $plugin;
|
||||||
|
if (!file_exists($filename)) return;
|
||||||
|
$info = get_plugin_data($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = empty($info['Name']) ? 'Unknown' : $info['Name'];
|
||||||
|
$version = empty($info['Version']) ? '0.0.0' : $info['Version'];
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'plugin' => array(
|
||||||
|
'name' => $name,
|
||||||
|
'version' => $version,
|
||||||
|
'action' => $action,
|
||||||
|
'network' => $network
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'plugin_' . $action, $details, $level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a theme installed event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
* @param array $hook_extra - Array of bulk item update data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function theme_installed($upgrader, $hook_extra) {
|
||||||
|
// If this is empty then we have no way to know if this is a plugin/theme install/update so return as we catch this in plugin_installed()
|
||||||
|
if (empty($hook_extra)) return;
|
||||||
|
if ('theme' !== $hook_extra['type'] || 'install' !== $hook_extra['action']) return;
|
||||||
|
self::$installed_theme_info = $upgrader->new_theme_data;
|
||||||
|
self::event_theme_changed('installed', '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a theme activated event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $new_name - Name of the new active theme
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function theme_activated($new_name) {
|
||||||
|
$details = array(
|
||||||
|
'theme' => array(
|
||||||
|
'name' => $new_name,
|
||||||
|
'action' => 'activated',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'theme_activated', $details);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a theme updated event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
* @param array $hook_extra - Array of bulk item update data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function theme_updated($upgrader, $hook_extra) {
|
||||||
|
// If this is empty then we have no way to know if this is a plugin/theme install/update so return as we catch this in plugin_installed()
|
||||||
|
if (empty($hook_extra)) return;
|
||||||
|
if ('theme' !== $hook_extra['type'] || 'update' !== $hook_extra['action']) return;
|
||||||
|
if (isset($hook_extra['theme'])) {
|
||||||
|
$theme = $hook_extra['theme'];
|
||||||
|
self::event_theme_changed('updated', $theme, '');
|
||||||
|
} elseif (isset($hook_extra['themes'])) {
|
||||||
|
foreach ($hook_extra['themes'] as $theme) {
|
||||||
|
self::event_theme_changed('updated', $theme, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the theme info of the plugin that is about to be deleted
|
||||||
|
*
|
||||||
|
* @param string $theme - Path to the theme file relative to the themes directory
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function theme_delete($theme) {
|
||||||
|
$info_object = wp_get_theme($theme);
|
||||||
|
$info = array(
|
||||||
|
'Name' => $info_object->get('Name'),
|
||||||
|
'Version' => $info_object->get('Version'),
|
||||||
|
);
|
||||||
|
self::$removed_theme_info = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a theme deleted event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $theme - Path to the theme file relative to the themes directory
|
||||||
|
* @param boolean $deleted - Whether the theme deletion was successful
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function theme_deleted($theme, $deleted) {
|
||||||
|
if ($deleted) self::event_theme_changed('deleted', $theme, '', 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will construct the event details and send it to be recorded
|
||||||
|
*
|
||||||
|
* @param string $action - the action taken (activated, deactivated)
|
||||||
|
* @param string $theme - Path to the theme file relative to the themes directory
|
||||||
|
* @param string $network - status of if the theme was network activated/deactivated
|
||||||
|
* @param string $level - the log level
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function event_theme_changed($action, $theme, $network, $level = 'info') {
|
||||||
|
if ('deleted' == $action) {
|
||||||
|
$info = self::$removed_theme_info;
|
||||||
|
} elseif ('installed' == $action) {
|
||||||
|
$info = self::$installed_theme_info;
|
||||||
|
} else {
|
||||||
|
$info_object = wp_get_theme($theme);
|
||||||
|
$info = array(
|
||||||
|
'Name' => $info_object->get('Name'),
|
||||||
|
'Version' => $info_object->get('Version'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = empty($info['Name']) ? 'Unknown' : $info['Name'];
|
||||||
|
$version = empty($info['Version']) ? '0.0.0' : $info['Version'];
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'theme' => array(
|
||||||
|
'name' => $name,
|
||||||
|
'version' => $version,
|
||||||
|
'action' => $action,
|
||||||
|
'network' => $network
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'theme_' . $action, $details, $level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a translation updated event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
* @param array $hook_extra - Array of bulk item update data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function translation_updated($upgrader, $hook_extra) {
|
||||||
|
|
||||||
|
// If this is empty then we have no way to know if this is a plugin/theme/translation install/update so return as we catch this in plugin_installed()
|
||||||
|
if (empty($hook_extra)) return;
|
||||||
|
|
||||||
|
if ('translation' !== $hook_extra['type'] || 'update' !== $hook_extra['action']) return;
|
||||||
|
|
||||||
|
if (!isset($hook_extra['translations']) || empty($hook_extra['translations'])) return;
|
||||||
|
|
||||||
|
foreach ($hook_extra['translations'] as $info) {
|
||||||
|
$details = array(
|
||||||
|
'translation_updated' => $info
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'translation_updated', $details, 'info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a entity changed event to the audit log
|
||||||
|
*
|
||||||
|
* @param WP_Upgrader $upgrader - WP_Upgrader instance
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function event_entity_changed($upgrader) {
|
||||||
|
|
||||||
|
$entity = (isset($upgrader->result) && isset($upgrader->result['destination_name'])) ? $upgrader->result['destination_name'] : false;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'entity_changed' => array(
|
||||||
|
'entity' => $entity,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'entity_changed', $details, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all the firewall rule events to the audit log
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function rule_event() {
|
||||||
|
$aiowps_firewall_message_store = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::MESSAGE_STORE);
|
||||||
|
$events = array();
|
||||||
|
foreach (array('active', 'not_active', 'triggered', 'not_triggered') as $event) {
|
||||||
|
$data = $aiowps_firewall_message_store->get('rule_'.$event);
|
||||||
|
|
||||||
|
if (empty($data)) continue;
|
||||||
|
|
||||||
|
foreach ($data as $rule) {
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'firewall_event' => array(
|
||||||
|
'event' => $event,
|
||||||
|
'rule_name' => $rule['name'],
|
||||||
|
'rule_family' => $rule['family'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$blog_id = AIOWPSecurity_Utility::get_blog_id_from_request($rule['request']);
|
||||||
|
|
||||||
|
$rule['request'] = apply_filters('aios_audit_filter_request', $rule['request'], $event);
|
||||||
|
|
||||||
|
$events[] = array(
|
||||||
|
'network_id' => get_current_network_id(),
|
||||||
|
'site_id' => $blog_id,
|
||||||
|
'username' => (isset($rule['potential_user']) ? AIOWPSecurity_Utility::verify_username($rule['potential_user']) : false),
|
||||||
|
'ip' => $rule['ip'],
|
||||||
|
'level' => 'triggered' === $event ? 'warning' : 'info',
|
||||||
|
'event_type' => 'rule_'.$event,
|
||||||
|
'details' => wp_json_encode($details, true),
|
||||||
|
'stacktrace' => (isset($rule['request']) ? print_r($rule['request'], true) : ''), // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- PCP warning. Part of AOIS error reporting system.
|
||||||
|
'created' => $rule['time']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($events)) return;
|
||||||
|
|
||||||
|
do_action('aiowps_bulk_record_events', $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a password reset event to the audit log
|
||||||
|
*
|
||||||
|
* @param object $user_data - Object containing user's data
|
||||||
|
*/
|
||||||
|
public static function password_reset($user_data) {
|
||||||
|
|
||||||
|
$user_login = (false === $user_data) ? 'unknown' : $user_data->user_login;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'password_reset' => array(
|
||||||
|
'user_login' => $user_login
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'password_reset', $details, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a user deleted event to the audit log
|
||||||
|
*
|
||||||
|
* @param int $user_id - the id of the deleted user
|
||||||
|
* @param int|null $reassign - the id of the user to reassign data to or null
|
||||||
|
* @param object $user_data - Object containing user's data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function user_deleted($user_id, $reassign, $user_data) {
|
||||||
|
|
||||||
|
$user_login = (false === $user_data) ? 'unknown' : $user_data->user_login;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'user_deleted' => array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'reassign' => $reassign,
|
||||||
|
'user_login' => $user_login
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'user_deleted', $details, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a user removed event to the audit log
|
||||||
|
*
|
||||||
|
* @param int $user_id - the id of the removed user
|
||||||
|
* @param int $blog_id - the id of the blog the user was removed from
|
||||||
|
* @param int $reassign - the id of the user to reassign data to or null
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function user_removed_from_blog($user_id, $blog_id, $reassign) {
|
||||||
|
$user_data = get_user_by('ID', $user_id);
|
||||||
|
$user_login = is_a($user_data, 'WP_User') && 0 !== $user_data->ID ? $user_data->user_login : 'unknown';
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'user_removed' => array(
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'blog_id' => $blog_id,
|
||||||
|
'reassign' => $reassign,
|
||||||
|
'user_login' => $user_login
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'user_removed', $details, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a failed login event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $username - the username for the failed login attempt
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function event_failed_login($username) {
|
||||||
|
$user = is_email($username) ? get_user_by('email', $username) : get_user_by('login', $username);
|
||||||
|
$details = array(
|
||||||
|
'failed_login' => array(
|
||||||
|
'imported' => false,
|
||||||
|
'username' => $username,
|
||||||
|
'known' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (is_a($user, 'WP_User')) {
|
||||||
|
do_action('aiowps_record_event', 'failed_login', $details, 'warning', $username);
|
||||||
|
} else {
|
||||||
|
$details['failed_login']['known'] = false;
|
||||||
|
do_action('aiowps_record_event', 'failed_login', $details, 'warning', $username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a user registration event to the audit log
|
||||||
|
*
|
||||||
|
* @param integer $user_id - the user ID of the newly registered user
|
||||||
|
* @param string $type - the type of registration valid values (admin, pending, registered)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function event_user_registration($user_id, $type) {
|
||||||
|
$registered_user = get_user_by('ID', $user_id);
|
||||||
|
$registered_username = is_a($registered_user, 'WP_User') && 0 !== $registered_user->ID ? $registered_user->user_login : '';
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
'user_registration' => array(
|
||||||
|
'registered_username' => $registered_username,
|
||||||
|
'type' => $type,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ('admin' == $type) {
|
||||||
|
$admin_user = wp_get_current_user();
|
||||||
|
$admin_username = is_a($admin_user, 'WP_User') ? $admin_user->user_login : '';
|
||||||
|
$details['user_registration']['admin_username'] = $admin_username;
|
||||||
|
do_action('aiowps_record_event', 'user_registration', $details, 'info');
|
||||||
|
} elseif ('pending' == $type) {
|
||||||
|
do_action('aiowps_record_event', 'user_registration', $details, 'info', $registered_username);
|
||||||
|
} elseif ('registered' == $type) {
|
||||||
|
do_action('aiowps_record_event', 'user_registration', $details, 'info', $registered_username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a successful login event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $username - the username for the successful login
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function event_successful_login($username) {
|
||||||
|
$details = array(
|
||||||
|
'successful_login' => array(
|
||||||
|
'username' => $username,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'successful_login', $details, 'info', $username);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a successful logout event to the audit log
|
||||||
|
*
|
||||||
|
* @param string $username - the username for the successful logout
|
||||||
|
* @param boolean $force_logout - if the logout was a force logout
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function event_successful_logout($username, $force_logout = false) {
|
||||||
|
$details = array(
|
||||||
|
'successful_logout' => array(
|
||||||
|
'username' => $username,
|
||||||
|
'force_logout' => $force_logout ? __('(force logout)', 'all-in-one-wp-security-and-firewall') : ''
|
||||||
|
)
|
||||||
|
);
|
||||||
|
do_action('aiowps_record_event', 'successful_logout', $details, 'info', $username);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+238
@@ -0,0 +1,238 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles converting the audit log's details column to a text representation
|
||||||
|
*/
|
||||||
|
class AIOWPSecurity_Audit_Text_Handler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'successful_login' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function successful_login_to_text($info) {
|
||||||
|
/* translators: %s: User name */
|
||||||
|
return sprintf(__('Successful login with username: %s', 'all-in-one-wp-security-and-firewall'), $info['username']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'successful_logout' event
|
||||||
|
*
|
||||||
|
* @param array $info - contains info used to generate the returned string
|
||||||
|
*
|
||||||
|
* @return string - the text to be shown for details on audit log table
|
||||||
|
*/
|
||||||
|
public static function successful_logout_to_text($info) {
|
||||||
|
return __('Successful logout with username:', 'all-in-one-wp-security-and-firewall') . ' ' . $info['username'] . ' ' . $info['force_logout'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'core_updated' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function core_updated_to_text($info) {
|
||||||
|
/* translators: 1: Old version, 2: New version */
|
||||||
|
return sprintf(__('WordPress updated from version %1$s to %2$s', 'all-in-one-wp-security-and-firewall'), $info['old_version'], $info['new_version']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'plugin' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function plugin_to_text($info) {
|
||||||
|
return sprintf(__('Plugin', 'all-in-one-wp-security-and-firewall').': %s %s %s (v%s)', $info['name'], $info['network'], $info['action'], $info['version']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'theme' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function theme_to_text($info) {
|
||||||
|
if ('activated' == $info['action']) {
|
||||||
|
return sprintf(__('Theme', 'all-in-one-wp-security-and-firewall').': %s %s', $info['name'], $info['action']);
|
||||||
|
} else {
|
||||||
|
return sprintf(__('Theme', 'all-in-one-wp-security-and-firewall').': %s %s %s (v%s)', $info['name'], $info['network'], $info['action'], $info['version']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'entity_changed' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function entity_changed_to_text($info) {
|
||||||
|
if ($info['entity']) {
|
||||||
|
/* translators: %s: Entity name */
|
||||||
|
return sprintf(__('Entity: "%s" has changed, please check the stacktrace for more details', 'all-in-one-wp-security-and-firewall'), $info['entity']);
|
||||||
|
} else {
|
||||||
|
return __('An unknown entity has changed, please check the stacktrace for more details', 'all-in-one-wp-security-and-firewall');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'translation_updated' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function translation_updated_to_text($info) {
|
||||||
|
if ('core' == $info['type']) {
|
||||||
|
/* translators: 1: Language name, 2: Version */
|
||||||
|
return sprintf(__('Core %1$s translations updated to version %2$s', 'all-in-one-wp-security-and-firewall'), $info['language'], $info['version']);
|
||||||
|
} elseif ('plugin' == $info['type']) {
|
||||||
|
/* translators: 1: Slug, 2: Language, 3: Version */
|
||||||
|
return sprintf(__('Plugin "%1$s" %2$s translations updated to version %3$s', 'all-in-one-wp-security-and-firewall'), $info['slug'], $info['language'], $info['version']);
|
||||||
|
} elseif ('theme' == $info['type']) {
|
||||||
|
/* translators: 1: Slug, 2: Language name, 3: Version */
|
||||||
|
return sprintf(__('Theme "%1$s" %2$s translations updated to version %3$s', 'all-in-one-wp-security-and-firewall'), $info['slug'], $info['language'], $info['version']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'failed_login' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function failed_login_to_text($info) {
|
||||||
|
if ($info['imported']) {
|
||||||
|
return __('Event imported from the failed logins table', 'all-in-one-wp-security-and-firewall');
|
||||||
|
} elseif ($info['known']) {
|
||||||
|
/* translators: %s: User name */
|
||||||
|
return sprintf(__('Failed login attempt with a known username: %s', 'all-in-one-wp-security-and-firewall'), $info['username']);
|
||||||
|
} else {
|
||||||
|
/* translators: %s: User name */
|
||||||
|
return sprintf(__('Failed login attempt with a unknown username: %s', 'all-in-one-wp-security-and-firewall'), $info['username']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'user_registration' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function user_registration_to_text($info) {
|
||||||
|
if ('admin' == $info['type']) {
|
||||||
|
/* translators: 1: Admin User name, 2: Registered User name */
|
||||||
|
return sprintf(__('Admin %1$s registered new user: %2$s', 'all-in-one-wp-security-and-firewall'), $info['admin_username'], $info['registered_username']);
|
||||||
|
} elseif ('pending' == $info['type']) {
|
||||||
|
/* translators: %s: Registered User name */
|
||||||
|
return sprintf(__('User %s registered and set to pending', 'all-in-one-wp-security-and-firewall'), $info['registered_username']);
|
||||||
|
} elseif ('registered' == $info['type']) {
|
||||||
|
/* translators: %s: Registered User name */
|
||||||
|
return sprintf(__('User %s registered', 'all-in-one-wp-security-and-firewall'), $info['registered_username']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'table_migration' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function table_migration_to_text($info) {
|
||||||
|
if ($info['success']) {
|
||||||
|
/* translators: 1: From table, 2: To table */
|
||||||
|
return sprintf(__('Successfully migrated the `%1$s` table data to the `%2$s` table', 'all-in-one-wp-security-and-firewall'), $info['from_table'], $info['to_table']);
|
||||||
|
} else {
|
||||||
|
/* translators: 1: From table, 2: To table */
|
||||||
|
return sprintf(__('Failed to migrate the `%1$s` table data to the `%2$s` table', 'all-in-one-wp-security-and-firewall'), $info['from_table'], $info['to_table']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'firewall_event' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function firewall_event_to_text($info) {
|
||||||
|
$output = '';
|
||||||
|
switch ($info['event']) {
|
||||||
|
case 'triggered':
|
||||||
|
/* translators: 1: Rule name, 2: Rule family */
|
||||||
|
$output = sprintf(__('"%1$s [%2$s]" rule has been triggered.', 'all-in-one-wp-security-and-firewall'), $info['rule_name'], $info['rule_family']);
|
||||||
|
break;
|
||||||
|
case 'not_triggered':
|
||||||
|
/* translators: 1: Rule name, 2: Rule family */
|
||||||
|
$output = sprintf(__('"%1$s [%2$s]" rule was not triggered.', 'all-in-one-wp-security-and-firewall'), $info['rule_name'], $info['rule_family']);
|
||||||
|
break;
|
||||||
|
case 'active':
|
||||||
|
/* translators: 1: Rule name, 2: Rule family */
|
||||||
|
$output = sprintf(__('"%1$s [%2$s]" rule is active.', 'all-in-one-wp-security-and-firewall'), $info['rule_name'], $info['rule_family']);
|
||||||
|
break;
|
||||||
|
case 'not_active':
|
||||||
|
/* translators: 1: Rule name, 2: Rule family */
|
||||||
|
$output = sprintf(__('"%1$s [%2$s]" rule is not active.', 'all-in-one-wp-security-and-firewall'), $info['rule_name'], $info['rule_family']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$output = array(
|
||||||
|
'status' => $info['event'],
|
||||||
|
'rule_name' => $info['rule_name'],
|
||||||
|
'rule_family' => $info['rule_family'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a link to the rule, if present
|
||||||
|
if (isset($info['location'])) {
|
||||||
|
$output .= "<br><br><a href='{$info['location']}'target='_blank'>".__('Configure this rule', 'all-in-one-wp-security-and-firewall').'</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_array($output) ? wp_json_encode($output) : $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'password_reset' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function password_reset_to_text($info) {
|
||||||
|
/* translators: %s: User login */
|
||||||
|
return sprintf(__('Password for user account: `%s` successfully changed', 'all-in-one-wp-security-and-firewall'), $info['user_login']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'user_deleted' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function user_deleted_to_text($info) {
|
||||||
|
if (empty($info['reassign'])) {
|
||||||
|
/* translators: 1: User login, 2: User ID */
|
||||||
|
return sprintf(__('User account: %1$s with ID: `%2$s` has been deleted', 'all-in-one-wp-security-and-firewall'), $info['user_login'], $info['user_id']);
|
||||||
|
} else {
|
||||||
|
/* translators: 1: User login, 2: User ID, 3: Reassign */
|
||||||
|
return sprintf(__('User account: `%1$s` with ID: `%2$s` has been deleted and all content has been reassigned to user with ID: `%3$s`', 'all-in-one-wp-security-and-firewall'), $info['user_login'], $info['user_id'], $info['reassign']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the text version of 'user_removed' event
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function user_removed_to_text($info) {
|
||||||
|
if (empty($info['reassign'])) {
|
||||||
|
/* translators: 1: User login, 2: User ID, 3: Blog ID */
|
||||||
|
return sprintf(__('User account: %1$s with ID: `%2$s` has been removed from the blog with ID: `%3$s`', 'all-in-one-wp-security-and-firewall'), $info['user_login'], $info['user_id'], $info['blog_id']);
|
||||||
|
} else {
|
||||||
|
/* translators: 1: User login, 2: User ID, 3: Blog ID, 4: Reassign */
|
||||||
|
return sprintf(__('User account: `%1$s` with ID: `%2$s` has been removed from the blog with ID: `%3$s` and all content has been reassigned to user with ID: `%4$s`', 'all-in-one-wp-security-and-firewall'), $info['user_login'], $info['user_id'], $info['blog_id'], $info['reassign']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; // Exit if accessed directly.
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AIOWPSecurity_Base_Tasks {
|
||||||
|
/**
|
||||||
|
* Runs intended various tasks
|
||||||
|
* Handles single and multi-site (NW activation) cases
|
||||||
|
*
|
||||||
|
* @global type $wpdb
|
||||||
|
*/
|
||||||
|
public static function run() {
|
||||||
|
if (is_multisite()) {
|
||||||
|
global $wpdb;
|
||||||
|
// check if it is a network activation
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery -- PCP warning. Ignore.
|
||||||
|
$blog_ids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
|
||||||
|
foreach ($blog_ids as $blog_id) {
|
||||||
|
switch_to_blog($blog_id);
|
||||||
|
static::run_for_a_site();
|
||||||
|
restore_current_blog();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static::run_for_a_site();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run uninstallation task for a single site.
|
||||||
|
*
|
||||||
|
* This method must be implemented in child classes.
|
||||||
|
* Since static abstract methods are not allowed in PHP, we enforce it at runtime.
|
||||||
|
*
|
||||||
|
* @throws Exception If not overridden in a child class.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected static function run_for_a_site() {
|
||||||
|
throw new Exception(
|
||||||
|
sprintf('%s : Child classes must implement run_for_a_site() method.', get_called_class())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+207
@@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Firewall bootstrap file content block.
|
||||||
|
*/
|
||||||
|
class AIOWPSecurity_Block_Bootstrap extends AIOWPSecurity_Block_File {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of our bootstrap file version
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $version = '1.0.2';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts our code into our bootstrap file.
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error
|
||||||
|
*/
|
||||||
|
public function insert_contents() {
|
||||||
|
|
||||||
|
$info = pathinfo($this->file_path);
|
||||||
|
|
||||||
|
if (!isset($info['dirname'])) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_no_directory',
|
||||||
|
'No directory has been set',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.WP.AlternativeFunctions -- wp_filesystem not recommended for firewall.
|
||||||
|
if (!is_writable($info['dirname'])) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_directory_not_writable',
|
||||||
|
'The directory has incorrect write permissions. Please double check its permissions and try again.',
|
||||||
|
$info['dirname']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false !== @file_put_contents($this->file_path, $this->get_contents())); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
// phpcs:enable WordPress.WP.AlternativeFunctions -- wp_filesystem not recommended for firewall.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the bootstrap contents are valid
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function is_content_valid($contents) {
|
||||||
|
|
||||||
|
//Ensure we're using the correct version of the file
|
||||||
|
$version = $this->get_bootstrap_version();
|
||||||
|
|
||||||
|
if (false === $version) return false;
|
||||||
|
|
||||||
|
if ($version['full_version'] !== $this->version) return false;
|
||||||
|
|
||||||
|
//Ensure the required paths are valid
|
||||||
|
$regexes = array('/file_exists\((?<file_path>\'.*\')\)/isU', '/include_once\((?<file_path>\'.*\')\)/isU');
|
||||||
|
$firewall_path_str = $this->get_firewall_path_str();
|
||||||
|
|
||||||
|
foreach ($regexes as $regex) {
|
||||||
|
|
||||||
|
if (preg_match($regex, $contents, $matches)) {
|
||||||
|
|
||||||
|
if ($firewall_path_str !== $matches['file_path']) return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bootstrap version from file
|
||||||
|
*
|
||||||
|
* @return array|boolean Array with the version information; false otherwise.
|
||||||
|
*/
|
||||||
|
protected function get_bootstrap_version() {
|
||||||
|
|
||||||
|
$contents = @file_get_contents($this->file_path); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
|
||||||
|
if (false === $contents) return false;
|
||||||
|
|
||||||
|
if (preg_match('/@version (?<full_version>(?<major>\d{1,})\.(?<minor>\d{1,})\.(?<patch>\d{1,}))$/m', $contents, $matches)) {
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the firewall path string that contains "__DIR__" for home dir, if plugin dir isn't a symbolic link..
|
||||||
|
*
|
||||||
|
* @return string The firewall path string.
|
||||||
|
*/
|
||||||
|
private function get_firewall_path_str() {
|
||||||
|
$firewall_path = AIOWPSecurity_Utility_Firewall::get_firewall_path();
|
||||||
|
$firewall_path_str = $this->get_path_str_for_given_absolute_path($firewall_path);
|
||||||
|
return $firewall_path_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get path string to write bootstrap file from given path.
|
||||||
|
*
|
||||||
|
* @param string $path a path that we want to write to the bootstrap file.
|
||||||
|
* @return string The path that can be written in the bootstrap file.
|
||||||
|
*/
|
||||||
|
private function get_path_str_for_given_absolute_path($path) {
|
||||||
|
$home_path = AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
// If the plugin is symbolic linked, then the plugin's firewall path is not started with home_path.
|
||||||
|
$path_str = (0 === strpos($path, $home_path)) ? "__DIR__.'/".substr($path, strlen($home_path))."'" : "'".$path."'";
|
||||||
|
return $path_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the firewall rules path string that contains "__DIR__" for home dir, if plugin dir isn't a symbolic link.
|
||||||
|
*
|
||||||
|
* @return string The firewall rule path string.
|
||||||
|
*/
|
||||||
|
private function get_firewall_rules_path_str() {
|
||||||
|
$firewall_rules_path = AIOWPSecurity_Utility_Firewall::get_firewall_rules_path();
|
||||||
|
$firewall_rules_path_str = $this->get_path_str_for_given_absolute_path($firewall_rules_path);
|
||||||
|
return $firewall_rules_path_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The regex pattern that demarcates our contents
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_regex_pattern() {
|
||||||
|
return '#// Begin AIOWPSEC Firewall(.*)// End AIOWPSEC Firewall#isU';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap file contents to insert
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
$firewall_path_str = $this->get_firewall_path_str();
|
||||||
|
$firewall_rules_path_str = $this->get_firewall_rules_path_str();
|
||||||
|
|
||||||
|
// Any extra data we want to have accessible to the firewall
|
||||||
|
$data = array(
|
||||||
|
'ABSPATH' => wp_normalize_path(ABSPATH)
|
||||||
|
);
|
||||||
|
|
||||||
|
$code = "<?php\n";
|
||||||
|
$code .= $this->get_warning_message();
|
||||||
|
|
||||||
|
$directive = AIOWPSecurity_Utility_Firewall::get_already_set_directive();
|
||||||
|
|
||||||
|
if (!empty($directive) && $directive !== $this->file_path) {
|
||||||
|
$directive = wp_normalize_path($directive);
|
||||||
|
$code .= "// Previously set auto_prepend_file\n";
|
||||||
|
$code .= "if (file_exists('{$directive}')) {\n";
|
||||||
|
$code .= "\tinclude_once('{$directive}');\n";
|
||||||
|
$code .= "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$code .= '$GLOBALS[\'aiowps_firewall_rules_path\'] = '.$firewall_rules_path_str.";\n\n";
|
||||||
|
|
||||||
|
// write any other data we need
|
||||||
|
$code .= "\$GLOBALS['aiowps_firewall_data'] = array(\n";
|
||||||
|
foreach ($data as $name => $value) {
|
||||||
|
$code .= "\t'{$name}' => '{$value}',\n";
|
||||||
|
}
|
||||||
|
$code .= ");\n\n"; //close data array
|
||||||
|
|
||||||
|
$code .= "// Begin AIOWPSEC Firewall\n";
|
||||||
|
$code .= "if (file_exists({$firewall_path_str})) {\n";
|
||||||
|
$code .= "\tinclude_once({$firewall_path_str});\n";
|
||||||
|
$code .= "}\n";
|
||||||
|
$code .= "// End AIOWPSEC Firewall\n";
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets our warning message for users
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_warning_message() {
|
||||||
|
|
||||||
|
$warning = "/** \n";
|
||||||
|
$warning .= " * @version {$this->version}\n";
|
||||||
|
$warning .= " * WARNING: Please do not delete this file.\n";
|
||||||
|
$warning .= " * \n";
|
||||||
|
$warning .= " * This will cause PHP to throw a fatal error and render your site unusable.\n";
|
||||||
|
$warning .= " * \n";
|
||||||
|
$warning .= " * To safely delete this file, please check both your .user.ini file and your php.ini file and ensure this file is not set in the auto_prepend_file directive.\n";
|
||||||
|
$warning .= " * \n";
|
||||||
|
$warning .= " * Please ask your web hosting provider if you need guidance with executing the aforementioned steps.\n";
|
||||||
|
$warning .= " */\n";
|
||||||
|
|
||||||
|
return $warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+202
@@ -0,0 +1,202 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AIOWPSecurity_Block_File {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full path to the file we're managing
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $file_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives the full file path
|
||||||
|
*
|
||||||
|
* @param string $file_path
|
||||||
|
*/
|
||||||
|
public function __construct($file_path) {
|
||||||
|
$this->file_path = $file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert the contents to the managed file
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error true if success; false if failed
|
||||||
|
*/
|
||||||
|
abstract public function insert_contents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents to be inserted into the managed file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function get_contents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the regex pattern that separates our contents from others the file may contain
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract protected function get_regex_pattern();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the file's contents are valid
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
abstract protected function is_content_valid($contents);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the contents of the managed file
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error true if updated; false if not updated
|
||||||
|
*/
|
||||||
|
public function update_contents() {
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions -- wp_filesystem not recommended.
|
||||||
|
if (!is_readable($this->file_path) || !is_writable($this->file_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_wrong_permissions',
|
||||||
|
'The file has incorrect read or write permissions. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = @file_get_contents($this->file_path); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
|
||||||
|
if (false === $contents) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_unable_to_read',
|
||||||
|
'Unable to read the file. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$matches = array();
|
||||||
|
$match_count = preg_match_all($this->get_regex_pattern(), $contents, $matches);
|
||||||
|
|
||||||
|
if (empty($matches[1]) || false === $match_count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//checks whether an update is required
|
||||||
|
$requires_update = false;
|
||||||
|
$match = '';
|
||||||
|
foreach ($matches[1] as $match) {
|
||||||
|
|
||||||
|
$requires_update = !$this->is_content_valid($match);
|
||||||
|
|
||||||
|
if (true === $requires_update) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//perform the update
|
||||||
|
if ($requires_update) {
|
||||||
|
|
||||||
|
$block_removed = $this->remove_contents();
|
||||||
|
$block_inserted = $this->insert_contents();
|
||||||
|
|
||||||
|
return (true === $block_removed && true === $block_inserted);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the file contains our contents
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error true if found; false if not found
|
||||||
|
*/
|
||||||
|
public function contains_contents() {
|
||||||
|
|
||||||
|
clearstatcache();
|
||||||
|
if (!file_exists($this->file_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_does_not_exist',
|
||||||
|
'The file does not exist.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_readable($this->file_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_wrong_permissions',
|
||||||
|
'The file has incorrect read permissions. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = @file_get_contents($this->file_path); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
|
||||||
|
if (false === $contents) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_unable_to_read',
|
||||||
|
'Unable to read the file. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1 === preg_match($this->get_regex_pattern(), $contents));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes our contents from the file
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error
|
||||||
|
*/
|
||||||
|
public function remove_contents() {
|
||||||
|
|
||||||
|
if (!is_readable($this->file_path) || !is_writable($this->file_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_wrong_permissions',
|
||||||
|
'The file has incorrect read or write permissions. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = @file_get_contents($this->file_path); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
|
||||||
|
if (false === $contents) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_unable_to_read',
|
||||||
|
'Unable to read the file. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$removed = 0;
|
||||||
|
$contents = preg_replace($this->get_regex_pattern(), "", $contents, -1, $removed);
|
||||||
|
|
||||||
|
if (null === $contents) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_unable_to_alter',
|
||||||
|
'Unable to alter the file.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === @file_put_contents($this->file_path, $contents, LOCK_EX)) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
return new WP_Error(
|
||||||
|
'file_unable_to_write',
|
||||||
|
'Unable to write to the file. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removed > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default returns the full path to the file being managed
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString() {
|
||||||
|
return $this->file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end of class
|
||||||
Executable
+91
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Block_Htaccess extends AIOWPSecurity_Block_File {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to insert our apache directives into the htaccess file
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error true if success; false if failed
|
||||||
|
*/
|
||||||
|
public function insert_contents() {
|
||||||
|
|
||||||
|
$home_path = AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions -- wp_filesystem not recommended.
|
||||||
|
if (!is_writable($home_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_wrong_permissions',
|
||||||
|
'The file has incorrect write permissions. Please double check its permissions and try again.',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false !== @file_put_contents($this->file_path, $this->get_contents(), FILE_APPEND)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the file's contents are valid
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function is_content_valid($contents) {
|
||||||
|
|
||||||
|
$regex = '/php_value auto_prepend_file \'(.*)\'/isU';
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$matches = array();
|
||||||
|
|
||||||
|
if (preg_match_all($regex, $contents, $matches)) {
|
||||||
|
$match = '';
|
||||||
|
foreach ($matches[1] as $match) {
|
||||||
|
|
||||||
|
if ($bootstrap_path !== $match) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The regex pattern that demarcates our contents
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_regex_pattern() {
|
||||||
|
return '/\r?\n?# Begin AIOWPSEC Firewall(.*?)# End AIOWPSEC Firewall/is';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our contents; the required apache directives for auto prepending a file
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$directives = "\n# Begin AIOWPSEC Firewall\n";
|
||||||
|
$directives .= "\t<IfModule mod_php5.c>\n";
|
||||||
|
$directives .= "\t\tphp_value auto_prepend_file '{$bootstrap_path}'\n";
|
||||||
|
$directives .= "\t</IfModule>\n";
|
||||||
|
$directives .= "\t<IfModule mod_php7.c>\n";
|
||||||
|
$directives .= "\t\tphp_value auto_prepend_file '{$bootstrap_path}'\n";
|
||||||
|
$directives .= "\t</IfModule>\n";
|
||||||
|
$directives .= "\t<IfModule mod_php.c>\n";
|
||||||
|
$directives .= "\t\tphp_value auto_prepend_file '{$bootstrap_path}'\n";
|
||||||
|
$directives .= "\t</IfModule>\n";
|
||||||
|
$directives .= "# End AIOWPSEC Firewall";
|
||||||
|
|
||||||
|
return $directives;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} //end of class
|
||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Block_Litespeed extends AIOWPSecurity_Block_Htaccess {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the directives needed for litespeed server
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$directives = "\n# Begin AIOWPSEC Firewall\n";
|
||||||
|
$directives .= "\t<IfModule LiteSpeed>\n";
|
||||||
|
$directives .= "\t\tphp_value auto_prepend_file '{$bootstrap_path}'\n";
|
||||||
|
$directives .= "\t</IfModule>\n";
|
||||||
|
$directives .= "\t<IfModule lsapi_module>\n";
|
||||||
|
$directives .= "\t\tphp_value auto_prepend_file '{$bootstrap_path}'\n";
|
||||||
|
$directives .= "\t</IfModule>\n";
|
||||||
|
$directives .= "# End AIOWPSEC Firewall";
|
||||||
|
|
||||||
|
return $directives;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+93
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Block_Muplugin extends AIOWPSecurity_Block_File {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts our code into our mu-plugin.
|
||||||
|
*
|
||||||
|
* The mu-plugin and the mu-plugin directory will be created if they don't already exists
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error
|
||||||
|
*/
|
||||||
|
public function insert_contents() {
|
||||||
|
$info = pathinfo($this->file_path);
|
||||||
|
|
||||||
|
if (!isset($info['dirname'])) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_no_directory',
|
||||||
|
'No directory has been set',
|
||||||
|
$this->file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === wp_mkdir_p($info['dirname'])) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_no_directory_created',
|
||||||
|
'Unable to create the directory',
|
||||||
|
$info['dirname']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false !== @file_put_contents($this->file_path, $this->get_contents())); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem is not appropriate here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the mu-plugin contents are valid
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function is_content_valid($contents) {
|
||||||
|
|
||||||
|
//The regexes we extract the paths from
|
||||||
|
$regexes = array('/file_exists\(\'(.*)\'\)/isU', '/include_once\(\'(.*)\'\)/isU');
|
||||||
|
$regex = '';
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
foreach ($regexes as $regex) {
|
||||||
|
$matches = array();
|
||||||
|
$result = preg_match($regex, $contents, $matches);
|
||||||
|
|
||||||
|
if (empty($matches[1]) || false === $result) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bootstrap_path !== $matches[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The regex pattern that demarcates our contents
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_regex_pattern() {
|
||||||
|
return '#// Begin AIOWPSEC Firewall(.*)// End AIOWPSEC Firewall#isU';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our firewall code to insert
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$code = "<?php\n";
|
||||||
|
$code .= "// Begin AIOWPSEC Firewall\n";
|
||||||
|
$code .= "if (file_exists('{$bootstrap_path}')) {\n";
|
||||||
|
$code .= "\tinclude_once('{$bootstrap_path}');\n";
|
||||||
|
$code .= "}\n";
|
||||||
|
$code .= "// End AIOWPSEC Firewall\n";
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+98
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; //Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class AIOWPSecurity_Block_Userini extends AIOWPSecurity_Block_File {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts our directive into the user.ini file
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error true if inserted; false if failed
|
||||||
|
*/
|
||||||
|
public function insert_contents() {
|
||||||
|
|
||||||
|
$home_path = AIOWPSecurity_Utility_File::get_home_path();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.WP.AlternativeFunctions -- wp_filesystem not recommended.
|
||||||
|
if (!is_writable($home_path)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'file_directory_not_writable',
|
||||||
|
'The directory has incorrect write permissions. Please double check its permissions and try again.',
|
||||||
|
$home_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false !== @file_put_contents($this->file_path, $this->get_contents(), FILE_APPEND)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the user.ini file contents are valid
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function is_content_valid($contents) {
|
||||||
|
|
||||||
|
$regex = '/auto_prepend_file=\'(.*)\'/isU';
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$match = array();
|
||||||
|
$result = preg_match($regex, $contents, $match);
|
||||||
|
|
||||||
|
if (empty($match[1]) || false === $result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bootstrap_path !== $match[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our regex pattern that demarcates our contents
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_regex_pattern() {
|
||||||
|
return '/\r?\n?# Begin AIOWPSEC Firewall(.*?)# End AIOWPSEC Firewall/is';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directives inserted into user.ini
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_contents() {
|
||||||
|
$bootstrap_path = AIOWPSecurity_Utility_Firewall::get_bootstrap_path();
|
||||||
|
|
||||||
|
$directive = "\n# Begin AIOWPSEC Firewall\n";
|
||||||
|
$directive .= "auto_prepend_file='{$bootstrap_path}'\n";
|
||||||
|
$directive .= "# End AIOWPSEC Firewall";
|
||||||
|
|
||||||
|
return $directive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the contains_contents function to check for already set directives
|
||||||
|
*
|
||||||
|
* @return boolean|WP_Error
|
||||||
|
*/
|
||||||
|
public function contains_contents() {
|
||||||
|
$contains = parent::contains_contents();
|
||||||
|
|
||||||
|
if (false === $contains) {
|
||||||
|
$directive_userini = AIOWPSecurity_Utility_Firewall::get_already_set_directive($this->file_path);
|
||||||
|
$directive = AIOWPSecurity_Utility_Firewall::get_already_set_directive();
|
||||||
|
|
||||||
|
if ((AIOWPSecurity_Utility_Firewall::get_bootstrap_path() === $directive) || (AIOWPSecurity_Utility_Firewall::get_bootstrap_path() === $directive_userini)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $contains;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user