diff --git a/config/whitelist.conf b/config/whitelist.conf new file mode 100644 index 0000000..63ed191 --- /dev/null +++ b/config/whitelist.conf @@ -0,0 +1,14 @@ +# InformatiQ Toolkit – Global IP/UA Whitelist +# Entries in this file bypass ALL plugin restrictions (bot blocker, WAF, honeypot, protection). +# +# IP/CIDR entries (one per line): +# 1.2.3.4 +# 10.0.0.0/8 +# 192.168.1.0/24 +# +# User-Agent substring entries (prefix with ua:): +# ua:Googlebot +# ua:Bingbot +# ua:MyMonitoringTool +# +# Lines starting with # are comments. Blank lines are ignored. diff --git a/includes/class-itk-admin.php b/includes/class-itk-admin.php index 6f870e3..d066d31 100644 --- a/includes/class-itk-admin.php +++ b/includes/class-itk-admin.php @@ -285,6 +285,7 @@ class ITK_Admin { 'referrers' => ITK_PATH . 'config/referrers.conf', 'networks' => ITK_PATH . 'config/networks.conf', 'allowed-ips'=> ITK_PATH . 'config/allowed-ips.conf', + 'whitelist' => ITK_PATH . 'config/whitelist.conf', ]; if (!isset($allowed[$file])) wp_send_json_error('invalid file'); @@ -299,6 +300,7 @@ class ITK_Admin { delete_transient('itk_referrers_list'); delete_transient('itk_networks_list'); delete_transient('itk_goodbots_list'); + ITK_Whitelist::invalidate_cache(); wp_send_json_success(); } @@ -1395,6 +1397,7 @@ class ITK_Admin { 'referrers' => ['Bad Referrers', 'config/referrers.conf', 'One domain substring per line.'], 'networks' => ['Bad Networks', 'config/networks.conf', 'One IP or CIDR range per line (e.g. 1.2.3.0/24).'], 'allowed-ips' => ['Allowed IPs', 'config/allowed-ips.conf','IPs/CIDRs allowed to access wp-login.php (one per line).'], + 'whitelist' => ['Whitelist', 'config/whitelist.conf', 'IPs, CIDRs, or UA substrings (ua:...) that bypass all restrictions. One per line.'], ]; $active_file = sanitize_key($_GET['file'] ?? 'badbots'); diff --git a/includes/class-itk-bot-blocker.php b/includes/class-itk-bot-blocker.php index 2489c73..85bd9e1 100644 --- a/includes/class-itk-bot-blocker.php +++ b/includes/class-itk-bot-blocker.php @@ -37,6 +37,9 @@ class ITK_Bot_Blocker { return; } + // Skip all checks for whitelisted IPs/UAs. + if (ITK_Whitelist::allowed()) return; + $options = get_option('itk_security', []); $ua = $_SERVER['HTTP_USER_AGENT'] ?? ''; $referrer = $_SERVER['HTTP_REFERER'] ?? ''; diff --git a/includes/class-itk-honeypot.php b/includes/class-itk-honeypot.php index 5a5c876..b5cbc3e 100644 --- a/includes/class-itk-honeypot.php +++ b/includes/class-itk-honeypot.php @@ -146,6 +146,9 @@ class ITK_Honeypot { /* ── Validators ───────────────────────────────────────────── */ private function check_honeypot(string $form_type): bool { + // Whitelisted IPs/UAs always pass honeypot validation. + if (ITK_Whitelist::allowed()) return true; + // 1. Honeypot field must be empty foreach ($_POST as $key => $val) { if (strpos($key, self::FIELD_PREFIX) === 0 && !empty($val)) { diff --git a/includes/class-itk-protection.php b/includes/class-itk-protection.php index c46be67..be66240 100644 --- a/includes/class-itk-protection.php +++ b/includes/class-itk-protection.php @@ -37,6 +37,7 @@ class ITK_Protection { /* ── wp-login protection ──────────────────────────────────── */ public function protect_wp_login(): void { + if (ITK_Whitelist::allowed()) return; $options = get_option('itk_security', []); if (empty($options['protect_wp_login'])) return; @@ -80,6 +81,7 @@ class ITK_Protection { /* ── Sensitive file blocking ──────────────────────────────── */ public function block_sensitive_files(): void { + if (ITK_Whitelist::allowed()) return; $options = get_option('itk_security', []); $uri = $_SERVER['REQUEST_URI'] ?? ''; @@ -120,6 +122,7 @@ class ITK_Protection { /* ── Malicious query blocking ─────────────────────────────── */ public function block_malicious_queries(): void { + if (ITK_Whitelist::allowed()) return; $options = get_option('itk_security', []); if (empty($options['block_malicious_queries'])) return; @@ -154,6 +157,7 @@ class ITK_Protection { /* ── Author scan blocking ─────────────────────────────────── */ public function block_author_scans(): void { + if (ITK_Whitelist::allowed()) return; $options = get_option('itk_security', []); if (empty($options['block_author_scans'])) return; diff --git a/includes/class-itk-waf.php b/includes/class-itk-waf.php index afc91a5..b3d45b4 100644 --- a/includes/class-itk-waf.php +++ b/includes/class-itk-waf.php @@ -54,6 +54,9 @@ class ITK_WAF { if (is_admin() && !wp_doing_ajax()) return; if (function_exists('current_user_can') && current_user_can('manage_options')) return; + // Skip all WAF checks for whitelisted IPs/UAs. + if (ITK_Whitelist::allowed()) return; + $options = get_option('itk_waf', []); $rules = $this->load_rules(); if (empty($rules)) return; diff --git a/includes/class-itk-whitelist.php b/includes/class-itk-whitelist.php new file mode 100644 index 0000000..0717476 --- /dev/null +++ b/includes/class-itk-whitelist.php @@ -0,0 +1,90 @@ +