Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace RSSSL\Security\Includes\Check404;
|
||||
|
||||
class Rsssl_Simple_404_Interceptor {
|
||||
|
||||
private $attempts = 10; // Default attempts threshold
|
||||
private $time_span = 5; // Time span in seconds (5 seconds)
|
||||
private $option_name = 'rsssl_404_cache';
|
||||
private $notice_option = 'rsssl_404_notice_shown';
|
||||
|
||||
public function __construct() {
|
||||
// Load the 404 test class only if the firewall has been enabled
|
||||
if ( rsssl_get_option('enable_firewall') == '1' ) {
|
||||
add_action( 'admin_init', array( $this, 'maybe_load_class_404_test' ), 20, 4 );
|
||||
}
|
||||
|
||||
add_filter( 'rsssl_notices', array( $this, 'show_help_notices' ) );
|
||||
|
||||
if ( defined( 'rsssl_pro' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'template_redirect', array( $this, 'detect_404' ) );
|
||||
}
|
||||
/**
|
||||
* Detect and handle 404 errors.
|
||||
*/
|
||||
public function detect_404(): void {
|
||||
if (is_404()) {
|
||||
if ( get_option( $this->notice_option ) ) {
|
||||
return;
|
||||
}
|
||||
$ip_address = $this->get_ip_address();
|
||||
$current_time = time();
|
||||
|
||||
// Prevent the option from becoming too large
|
||||
$cache = get_option($this->option_name, []);
|
||||
|
||||
if (!isset($cache[$ip_address])) {
|
||||
$cache[$ip_address] = [];
|
||||
}
|
||||
|
||||
$cache[$ip_address][] = $current_time;
|
||||
$cache[$ip_address] = $this->clean_up_old_entries($cache[$ip_address]);
|
||||
|
||||
if (count($cache[$ip_address]) > $this->attempts && !get_option($this->notice_option)) {
|
||||
update_option($this->notice_option, true, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
update_option($this->option_name, $cache, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up old entries based on the given timestamps.
|
||||
*
|
||||
* This method filters the given timestamps array and only keeps the entries where the difference between the current time
|
||||
* and the timestamp is less than the specified time span.
|
||||
*
|
||||
* @param array $timestamps An array of timestamps.
|
||||
*
|
||||
* @return array The cleaned up timestamps array.
|
||||
*/
|
||||
private function clean_up_old_entries($timestamps): array {
|
||||
$current_time = time();
|
||||
return array_filter($timestamps, function($timestamp) use ($current_time) {
|
||||
return ($current_time - $timestamp) < $this->time_span;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the IP address of the client.
|
||||
*
|
||||
* This method checks for the IP address in the following order:
|
||||
* 1. HTTP_CLIENT_IP: Represents the IP address of the client if the client is a shared internet device.
|
||||
* 2. HTTP_X_FORWARDED_FOR: Represents the IP address of the client if the client is accessing the server through a proxy server.
|
||||
* 3. REMOTE_ADDR: Represents the IP address of the client if the client is accessing the server directly.
|
||||
*
|
||||
* @return string The IP address of the client.
|
||||
*/
|
||||
private function get_ip_address(): string {
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
return $_SERVER['HTTP_CLIENT_IP'];
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
return $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
}
|
||||
|
||||
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
return $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a help notice for 404 detection warning.
|
||||
*
|
||||
* @param array $notices The existing notices array.
|
||||
*
|
||||
* @return array Updated notices array with 404 detection warning notice.
|
||||
*/
|
||||
public function show_help_notices(array $notices): array {
|
||||
if (get_option($this->notice_option)) {
|
||||
$message = __('We detected suspected bots triggering large numbers of 404 errors on your site.', 'really-simple-ssl');
|
||||
$notice = [
|
||||
'callback' => '_true_',
|
||||
'score' => 1,
|
||||
'show_with_options' => ['enable_404_detection'],
|
||||
'output' => [
|
||||
'true' => [
|
||||
'msg' => $message,
|
||||
'icon' => 'warning',
|
||||
'type' => 'warning',
|
||||
'dismissible' => true,
|
||||
'admin_notice' => false,
|
||||
'highlight_field_id' => 'enable_firewall',
|
||||
'plusone' => true,
|
||||
'url' => 'https://really-simple-ssl.com/suspected-bots-causing-404-errors/',
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$notices['404_detection_warning'] = $notice;
|
||||
}
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @param $value
|
||||
* @param $old_value
|
||||
* @param $option_name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_load_class_404_test() {
|
||||
if ( ! get_option( 'rsssl_homepage_contains_404_resources' ) ) {
|
||||
Rsssl_Test_404::get_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Rsssl_Simple_404_Interceptor();
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace RSSSL\Security\Includes\Check404;
|
||||
|
||||
class Rsssl_Test_404 {
|
||||
// Static instance property
|
||||
public static $instance = null;
|
||||
|
||||
// Private constructor to prevent direct instantiation
|
||||
private function __construct() {
|
||||
// Immediately check if there are resources to process and handle them
|
||||
$resources = get_option( 'rsssl_404_resources_to_check' );
|
||||
$found_404_option_value = get_option( 'rsssl_homepage_contains_404_resources', false );
|
||||
$found_404s = $found_404_option_value === true || $found_404_option_value === "true";
|
||||
|
||||
if ( ! empty( $resources ) && ! $found_404s ) {
|
||||
// Trigger chunk processing if resources are pending
|
||||
$this->process_404_resources_chunk();
|
||||
}
|
||||
|
||||
$this->fetch_and_check_homepage_resources();
|
||||
|
||||
}
|
||||
|
||||
// Static method to get the single instance of the class
|
||||
public static function get_instance() {
|
||||
if ( self::$instance === null ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
// Process resources in chunks
|
||||
public function process_404_resources_chunk() {
|
||||
$resources = get_option( 'rsssl_404_resources_to_check' );
|
||||
if ( empty( $resources ) ) {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', 'false' );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process a chunk of the resources (e.g., 2 at a time)
|
||||
$chunk_size = 2;
|
||||
$resources_chunk = array_splice( $resources, 0, $chunk_size );
|
||||
|
||||
$result = $this->process_404_resources( $resources_chunk );
|
||||
|
||||
// Update the remaining resources back to the option
|
||||
if ( ! empty( $resources ) ) {
|
||||
update_option( 'rsssl_404_resources_to_check', $resources );
|
||||
return 'processing';
|
||||
} else {
|
||||
// All resources have been processed
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check homepage and handle 404s
|
||||
public static function homepage_contains_404_resources() {
|
||||
$found_404_option_value = get_option( 'rsssl_homepage_contains_404_resources', false );
|
||||
if ( $found_404_option_value === true || $found_404_option_value === "true" ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$resources = get_option( 'rsssl_404_resources_to_check' );
|
||||
if ( ! empty( $resources ) ) {
|
||||
// If resources are available to check, process them immediately
|
||||
return self::get_instance()->process_404_resources_chunk();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Function to fetch homepage resources and check for 404 errors
|
||||
public function fetch_and_check_homepage_resources() {
|
||||
|
||||
if ( get_option('rsssl_homepage_contains_404_resources') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$site_url = trailingslashit( site_url() );
|
||||
|
||||
$response = wp_remote_get( $site_url );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', false );
|
||||
return false;
|
||||
}
|
||||
|
||||
$status_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( $status_code == 404 ) {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', true );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Patterns to match img, script, link tags
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$patterns = array(
|
||||
'/<img[^>]+src=([\'"])?((.*?)\1)/i',
|
||||
'/<script[^>]+src=([\'"])?((.*?)\1)/i',
|
||||
'/<link[^>]+href=([\'"])?((.*?)\1)/i'
|
||||
);
|
||||
|
||||
$resources = array();
|
||||
foreach ( $patterns as $pattern ) {
|
||||
if ( preg_match_all( $pattern, $body, $matches ) ) {
|
||||
foreach ( $matches[2] as $resource_url ) {
|
||||
$resource_url = esc_url_raw( $resource_url );
|
||||
if ( strpos( $resource_url, $site_url ) !== false ) {
|
||||
$resources[] = $resource_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $resources ) > 2 ) {
|
||||
update_option( 'rsssl_404_resources_to_check', $resources );
|
||||
return $this->process_404_resources_chunk();
|
||||
} else {
|
||||
if ( empty( $resources ) ) {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', 'false' );
|
||||
return false;
|
||||
}
|
||||
|
||||
update_option( 'rsssl_404_resources_to_check', $resources );
|
||||
// Process all resources if fewer than 5
|
||||
return $this->process_404_resources( $resources );
|
||||
}
|
||||
}
|
||||
|
||||
// Function to process a list of resources and check for 404 errors
|
||||
private function process_404_resources( $resources ) {
|
||||
$not_found_resources = array();
|
||||
|
||||
foreach ( $resources as $resource_url ) {
|
||||
$resource_response = wp_remote_head( $resource_url );
|
||||
if ( is_wp_error( $resource_response ) ) {
|
||||
$not_found_resources[] = $resource_url . ' (Error: ' . $resource_response->get_error_message() . ')';
|
||||
} else {
|
||||
$resource_status = wp_remote_retrieve_response_code( $resource_response );
|
||||
if ( $resource_status == 404 ) {
|
||||
$not_found_resources[] = $resource_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $not_found_resources ) ) {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', 'false' );
|
||||
return false;
|
||||
} else {
|
||||
update_option( 'rsssl_homepage_contains_404_resources', 'true' );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user