plugin = $plugin_instance; $this->admin_pages = $admin_pages_instance; add_action('admin_notices', [$this, 'display_captcha_keys_warning']); add_action('update_option_' . ADVAIPBL_Main::OPTION_SETTINGS, [$this, 'handle_fim_settings_update'], 10, 2); } /** * Handles dynamic cleanup of FIM signatures DB options when FIM settings change. */ public function handle_fim_settings_update($old_value, $new_value) { $old_value = is_array($old_value) ? $old_value : []; $new_value = is_array($new_value) ? $new_value : []; $modules = [ 'fim_enable_raw' => 'raw', 'fim_enable_regex' => 'regex', 'fim_enable_domains' => 'domains', 'fim_enable_md5' => 'md5', 'fim_enable_sha256' => 'sha256', ]; $needs_sync = false; foreach ($modules as $setting_key => $db_suffix) { $default_on = in_array($setting_key, ['fim_enable_raw', 'fim_enable_domains']); $was_on = isset($old_value[$setting_key]) ? !empty($old_value[$setting_key]) : $default_on; $is_on = isset($new_value[$setting_key]) ? !empty($new_value[$setting_key]) : $default_on; if ($was_on && !$is_on) { delete_option('advaipbl_fim_signatures_' . $db_suffix); } elseif (!$was_on && $is_on) { $needs_sync = true; } } if ($needs_sync) { delete_option('advaipbl_fim_signatures_version'); } } public function register_settings() { $page = 'advaipbl_settings_page'; register_setting('advaipbl_settings_group', ADVAIPBL_Main::OPTION_SETTINGS, [$this, 'sanitize_settings']); register_setting('advaipbl_waf_rules_group', ADVAIPBL_Main::OPTION_WAF_RULES, ['sanitize_callback' => [$this, 'sanitize_waf_rules']]); add_settings_section('advaipbl_general_settings_section', null, null, $page); add_settings_field('advaipbl_enable_logging', __('Enable Logging', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'enable_logging', 'label' => __('Enable logging of events to the database.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_enable_payload_logging', __('Enable Advanced Payload Logging (Opt-in)', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'enable_payload_logging', 'label' => __('Capture POST/GET payloads of blocked requests.', 'advanced-ip-blocker'), 'description' => __('Privacy Warning: This securely logs request parameters to help identify attacks. Passwords are redacted, and payloads are limited to 2KB.
We highly recommend setting "Log Retention" to 7 or 14 days if enabled to prevent database bloat.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_log_retention_days', __('Log Retention (days)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'log_retention_days', 'default' => 30, 'description' => __('Number of days to keep logs in the DB. 0 to disable automatic purging.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_log_timezone', __('Timezone for Logs', 'advanced-ip-blocker'), [$this, 'timezone_select_callback'], $page, 'advaipbl_general_settings_section'); add_settings_field('advaipbl_custom_block_message', __('Block Message', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'custom_block_message', 'label' => __('Message for blocked users. Leave blank for default messages.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_excluded_error_urls', __('Global URL Exclusions', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'excluded_error_urls', 'label' => __('Add one URL path or fragment per line. Requests containing these strings will bypass 404/403 error logging and all JavaScript challenges (Signature, Geo, and Endpoint).', 'advanced-ip-blocker')]); add_settings_field('advaipbl_show_admin_bar_menu', __('Admin Bar Menu', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'show_admin_bar_menu', 'label' => __('Show security menu in the WordPress admin bar', 'advanced-ip-blocker')]); add_settings_field('advaipbl_global_challenge_cookie_duration', __('Global Challenge Duration (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'global_challenge_cookie_duration', 'default' => 4, 'description' => __('How long a visitor can access the site after passing a JS challenge (e.g. from Lockdowns, Login Page, XML-RPC or Advanced Rules). Set to 0 for the browser session only.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_revoke_vip_passes_button', __('Global VIP Revocation', 'advanced-ip-blocker'), [$this, 'revoke_vip_passes_button_callback'], $page, 'advaipbl_general_settings_section'); add_settings_section('advaipbl_general_settings_section', null, null, $page); add_settings_field( 'advaipbl_allow_telemetry', __('Usage Tracking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', [ 'name' => 'allow_telemetry', 'id' => 'advaipbl_allow_telemetry', 'label' => __('Share anonymous usage data to help us improve the plugin.', 'advanced-ip-blocker'), 'description' => __('Learn More about what we collect.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_email_notifications_section', null, null, $page); add_settings_field('advaipbl_enable_email_notifications', __('Enable Email Notifications', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_email_notifications_section', ['name' => 'enable_email_notifications', 'label' => __('Send email alerts for blocked IPs and security system events.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_notification_frequency', __('Notification Frequency', 'advanced-ip-blocker'), [$this, 'notification_frequency_callback'], $page, 'advaipbl_email_notifications_section'); add_settings_field('advaipbl_notification_email', __('Notification Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_email_notifications_section', ['name' => 'notification_email', 'label' => __('Leave empty to use the admin email.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_send_test_email_button', __('Send Test Email', 'advanced-ip-blocker'), [ $this, 'send_test_email_button_callback' ], $page, 'advaipbl_email_notifications_section'); add_settings_section('advaipbl_push_notifications_section', null, null, $page); add_settings_field('advaipbl_enable_push_notifications', __('Enable Push Notifications', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'enable_push_notifications', 'label' => __('Send real-time alerts via webhooks.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_push_webhook_urls', __('Push Webhook URLs', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_webhook_urls', 'description' => __('One URL per line.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_push_mentions', __('Mentions to Trigger Push', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_mentions', 'rows' => 3, 'class' => 'regular-text', 'description' => __('Optional. To force a push notification on Slack/Discord, add a mention like @here, @channel, or a specific @username. Add one per line if needed.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_push_critical_only', __('Send Critical Alerts Only', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_critical_only', 'label' => __('Only send alerts for instant blocks (WAF, Honeypot, etc.), not for threshold-based blocks (404, Login).', 'advanced-ip-blocker')]); add_settings_field('advaipbl_send_test_push_button', __('Send Test Notification', 'advanced-ip-blocker'), [ $this, 'send_test_push_button_callback' ], $page, 'advaipbl_push_notifications_section'); $is_imagick_active = extension_loaded('imagick') || class_exists('Imagick'); $imagick_status_msg = $is_imagick_active ? '
' . __('We have detected that Imagick is active on your server. We strongly recommend enabling this option to force the use of GD and prevent image processing vulnerabilities.', 'advanced-ip-blocker') . '' : '
' . __('Your server already has Imagick disabled at the system level. You are protected by default.', 'advanced-ip-blocker') . ''; add_settings_section('advaipbl_hardening_settings_section', __('Hardening & Core Protection', 'advanced-ip-blocker'), null, $page); add_settings_field( 'advaipbl_disable_imagick', __('Disable Imagick', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'disable_imagick', 'label' => __('Disable Imagick and force GD Library for image processing.', 'advanced-ip-blocker'), 'description' => __('Mitigates critical Remote Code Execution (RCE) vulnerabilities in ImageMagick/Ghostscript (like CVE-2026-65640).', 'advanced-ip-blocker') . $imagick_status_msg ] ); add_settings_field( 'advaipbl_hide_wp_version', __('Hide WordPress Version', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'hide_wp_version', 'label' => __('Remove WordPress version generator meta tag and query strings from scripts/styles.', 'advanced-ip-blocker'), 'description' => __('Prevents automated scanners from easily detecting outdated/vulnerable WordPress versions.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_disable_app_passwords', __('Disable Application Passwords', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'disable_app_passwords', 'label' => __('Disable the REST API Application Passwords feature.', 'advanced-ip-blocker'), 'description' => __('Closes a common vector for brute-force attacks via the WP REST API if you do not use them.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_disable_file_editor', __('Disable File Editor', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'disable_file_editor', 'label' => __('Disable the built-in WordPress theme and plugin editor.', 'advanced-ip-blocker'), 'description' => __('Prevents attackers from injecting malicious PHP code directly from the dashboard if an admin account is compromised.', 'advanced-ip-blocker') ] ); $server_software = isset($_SERVER['SERVER_SOFTWARE']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE'])) : ''; $is_apache_ls = (stripos($server_software, 'Apache') !== false || stripos($server_software, 'LiteSpeed') !== false); $is_nginx_only = (stripos($server_software, 'nginx') !== false && !$is_apache_ls); $block_php_desc = __('Creates an isolated .htaccess file to immunize your media folder against PHP shell execution.', 'advanced-ip-blocker'); if ($is_nginx_only) { $block_php_desc .= '
' . esc_html__('Disabled: Nginx server detected. .htaccess is not supported.', 'advanced-ip-blocker') . ''; } add_settings_field( 'advaipbl_block_php_uploads', __('Block PHP in Uploads', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'block_php_uploads', 'label' => __('Block execution of PHP files in the `/wp-content/uploads/` directory.', 'advanced-ip-blocker'), 'description' => $block_php_desc, 'disabled' => $is_nginx_only ] ); add_settings_field( 'advaipbl_remove_x_powered_by', __('Remove powered by HTTP header', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'remove_x_powered_by', 'label' => __('Remove information about software used by your site. E.g., X-Powered-By: PHP/7.4.1', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_allowed_admin_users', __('Authorized Administrators', 'advanced-ip-blocker'), [$this, 'admin_users_select_callback'], $page, 'advaipbl_hardening_settings_section', [ 'name' => 'allowed_admin_users', 'label' => __('Select which Administrators are allowed to view and configure this plugin.', 'advanced-ip-blocker'), 'description' => __('By default, all administrators can manage the plugin. The primary admin (ID 1) can never be locked out.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_scanner_settings_section', __('Site Scanner Automation', 'advanced-ip-blocker'), null, $page); add_settings_field( 'advaipbl_enable_scheduled_scans', __('Enable Scheduled Scans', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', [ 'name' => 'enable_scheduled_scans', 'label' => __('Automatically run Deep Scans and email the report.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_scan_frequency', __('Scan Frequency', 'advanced-ip-blocker'), [$this, 'scan_frequency_callback'], $page, 'advaipbl_scanner_settings_section' ); add_settings_field( 'advaipbl_scan_notification_email', __('Notification Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_scanner_settings_section', [ 'name' => 'scan_notification_email', 'label' => __('Where to send the scan reports (leave blank for admin email).', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_send_test_scan_button', __('Run Manual Scan & Email', 'advanced-ip-blocker'), [$this, 'send_test_scan_button_callback'], $page, 'advaipbl_scanner_settings_section' ); add_settings_field( 'advaipbl_scan_email_trigger', __('Alert Trigger Rule', 'advanced-ip-blocker'), [$this, 'select_field_callback'], $page, 'advaipbl_scanner_settings_section', [ 'name' => 'scan_email_trigger', 'options' => [ 'any_issue' => __('Send email when ANY issue is found (Updates, Vulnerabilities, Env Errors)', 'advanced-ip-blocker'), 'vulnerabilities_only' => __('Agency Mode: ONLY send email if Critical Vulnerabilities (CVEs) or Blacklists are detected. (Ignores standard updates)', 'advanced-ip-blocker'), 'always' => __('Always send report, even if the site is completely clean.', 'advanced-ip-blocker') ], 'default' => 'any_issue', 'label' => __('Choose when the automatic scan should notify you.', 'advanced-ip-blocker') ] ); add_settings_field('advaipbl_scan_check_vulnerabilities', __('Check Vulnerabilities (CVE)', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_vulnerabilities', 'default' => '1', 'label' => __('Enable scanning active plugins and themes against the known vulnerabilities database.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_scan_check_ssl', __('Check SSL Certificate', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_ssl', 'default' => '1', 'label' => __('Enable SSL/TLS certificate validation.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_scan_check_updates', __('Check Updates', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_updates', 'default' => '1', 'label' => __('Enable core, plugin, and theme update checks.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_scan_check_php', __('Check PHP Version', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_php', 'default' => '1', 'label' => __('Enable PHP version compatibility checks.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_scan_check_wp', __('Check WordPress Version', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_wp', 'default' => '1', 'label' => __('Enable WordPress core version checks.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_scan_check_debug', __('Check Debug Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_debug', 'default' => '1', 'label' => __('Enable WP_DEBUG status checks.', 'advanced-ip-blocker')]); add_settings_section( 'advaipbl_ip_detection_section', null, null, $page ); add_settings_field( 'advaipbl_trusted_proxies', __('Trusted Proxies', 'advanced-ip-blocker'), [$this, 'trusted_proxies_callback'], $page, 'advaipbl_ip_detection_section', [ 'name' => 'trusted_proxies', 'rows' => 10, 'label' => __('Define which proxy servers you trust to provide the real visitor IP address. The plugin will only trust headers like X-Forwarded-For if the request comes from one of these IPs, preventing IP spoofing.', 'advanced-ip-blocker'), 'description' => __('Enter one IP, CIDR range, or ASN per line. Use # for comments. Example:
# Cloudflare
AS13335
# Varnish Server
192.168.0.1
# Nginx Proxy
127.0.0.1
', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/ip-detection-trusted-proxies-guide/' ] ); add_settings_section( 'advaipbl_geolocation_section', null, null, $page ); add_settings_field( 'advaipbl_geolocation_method', __('Geolocation Method', 'advanced-ip-blocker'), [$this, 'geolocation_method_callback'], $page, 'advaipbl_geolocation_section' ); add_settings_section('advaipbl_abuseipdb_section', null, null, $page); add_settings_field( 'advaipbl_enable_abuseipdb', __('Enable AbuseIPDB Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_abuseipdb_section', [ 'name' => 'enable_abuseipdb', 'label' => __('Activate real-time IP reputation checking.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/abuseipdb-integration-guide/' ] ); add_settings_field( 'advaipbl_abuseipdb_api_key', __('AbuseIPDB API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_abuseipdb_section', [ 'name' => 'abuseipdb_api_key', 'class' => 'regular-text', 'data_provider' => 'abuseipdb' ] ); add_settings_field( 'advaipbl_abuseipdb_threshold', __('Blocking Confidence Score', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_abuseipdb_section', [ 'name' => 'abuseipdb_threshold', 'default' => 90, 'description' => __('Block IPs with an abuse confidence score of this value or higher (0-100). Recommended: 90 or 100.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_abuseipdb_action', __('Action on High Score', 'advanced-ip-blocker'), [$this, 'action_select_callback'], $page, 'advaipbl_abuseipdb_section', [ 'name' => 'abuseipdb_action', 'description' => __('Choose whether to block high-risk IPs immediately or to present them with a JavaScript challenge.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_duration_abuseipdb', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_abuseipdb_section', [ 'name' => 'duration_abuseipdb', 'default' => 1440, 'description' => __('How long to block an IP flagged by AbuseIPDB. Set to 0 for a permanent block.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_community_network_section', null, null, $page); add_settings_field( 'advaipbl_api_connection_status', __('AIB Account Connection', 'advanced-ip-blocker'), [$this, 'api_connection_status_callback'], $page, 'advaipbl_community_network_section' ); add_settings_field( 'advaipbl_api_token_v3', __('API Token', 'advanced-ip-blocker'), [$this, 'api_token_field_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'api_token_v3', 'description' => __('Connecting to the Advanced IP Blocker cloud network gives you access to the community blocklist and deep site scanning.', 'advanced-ip-blocker'), ] ); add_settings_field( 'advaipbl_enable_community_network', __('Join Community Defense Network', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'enable_community_network', 'label' => __('Enable Community Defense', 'advanced-ip-blocker'), 'description' => __('Participate in the global defense network. Your plugin will share anonymized attack data (Verified IPs) to help build the AIB Community Blocklist.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/aib-community-defense-network/' ] ); add_settings_field( 'advaipbl_enable_community_blocking', __('Enable Community Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'enable_community_blocking', 'label' => __('Block visitors found in the global AIB Community Blocklist.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_community_blocking_action', __('Action', 'advanced-ip-blocker'), [$this, 'action_select_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'community_blocking_action', 'description' => __('Decide how to handle IPs listed in the community database.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_duration_aib_network', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'duration_aib_network', 'default' => 1440, 'description' => __('How long to block an IP listed in the community database. Set to 0 for a permanent block.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_community_min_score', __('Minimum Threat Score', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_community_network_section', [ 'name' => 'community_min_score', 'default' => 3, 'description' => __('Only import IPs that have been reported by at least this many unique community members. (Default: 3)', 'advanced-ip-blocker') ] ); // API PROVIDER (solo para el método 'api') add_settings_field( 'advaipbl_geolocation_provider', __('API Provider', 'advanced-ip-blocker'), [$this, 'geolocation_provider_callback'], $page, 'advaipbl_geolocation_section', ['class' => 'advaipbl-geolocation-api-option'] ); // API KEYS (solo para el método 'api') add_settings_field('advaipbl_api_key_ip_apicom', 'ip-api.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ip_apicom', 'description' => __('Optional key for HTTPS access.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ip-api.com']); add_settings_field('advaipbl_api_key_ipinfocom', 'ipinfo.io ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipinfocom', 'description' => __('API key is recommended for higher limits.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipinfo.io']); add_settings_field('advaipbl_api_key_ipapicom', 'ipapi.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipapicom', 'description' => __('API Key is required.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipapi.com']); add_settings_field('advaipbl_api_key_ipstackcom', 'ipstack.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipstackcom', 'description' => __('API Key is required.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipstack.com']); // MAXMIND (solo para el método 'local_db') add_settings_field('advaipbl_maxmind_license_key', __('MaxMind License Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'maxmind_license_key', 'class' => 'advaipbl-geolocation-db-option', 'description' => sprintf(wp_kses(/* translators: %s is a placeholder */ __('Required for the Local Database method. Get a free key from the MaxMind website.', 'advanced-ip-blocker'), ['a' => ['href' => [], 'target' => []]]), 'https://www.maxmind.com/en/geolite2/signup')]); add_settings_field('advaipbl_geoip_db_status', __('Local Database Status', 'advanced-ip-blocker'), [$this, 'geoip_db_status_callback'], $page, 'advaipbl_geolocation_section', ['class' => 'advaipbl-geolocation-db-option']); add_settings_field('advaipbl_clear_location_cache_button', __('Geolocation Cache', 'advanced-ip-blocker'), [$this, 'clear_cache_button_callback'], $page, 'advaipbl_geolocation_section'); add_settings_field('advaipbl_geoblock_separator', '', [$this, 'geoblock_separator_callback'], $page, 'advaipbl_geolocation_section'); add_settings_field('advaipbl_enable_geoblocking', __('Enable Geoblocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'enable_geoblocking', 'label' => __('Activate country-based blocking.', 'advanced-ip-blocker'), 'description' => sprintf(__('Block access from entire countries. This feature requires a working Geolocation Provider to be configured above.', 'advanced-ip-blocker'))]); add_settings_field('advaipbl_geoblock_countries', __('Blocked Countries', 'advanced-ip-blocker'), [ $this, 'geoblock_countries_callback' ], $page, 'advaipbl_geolocation_section'); add_settings_field('advaipbl_duration_geoblock', __('Geoblock Duration (min)', 'advanced-ip-blocker'), [ $this, 'text_field_callback' ], $page, 'advaipbl_geolocation_section', ['name' => 'duration_geoblock', 'default' => 1440, 'description' => __('How long an IP from a blocked country will be blocked. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_geochallenge_separator', '', [$this, 'geochallenge_separator_callback'], $page, 'advaipbl_geolocation_section'); add_settings_field( 'advaipbl_enable_geo_challenge', __('Enable Geo-Challenge', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_geolocation_section', [ 'name' => 'enable_geo_challenge', 'label' => __('Activate country-based JavaScript challenge.', 'advanced-ip-blocker'), 'description' => __('Instead of a hard block, this presents a quick, invisible JavaScript challenge...', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_geo_challenge_countries', __('Challenged Countries', 'advanced-ip-blocker'), [ $this, 'geoblock_countries_callback' ], $page, 'advaipbl_geolocation_section', ['type' => 'geo_challenge'] ); add_settings_field( 'advaipbl_geo_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [ $this, 'challenge_mode_callback' ], $page, 'advaipbl_geolocation_section', [ 'name' => 'geo_challenge_mode', 'default' => 'managed', 'description' => __('Automatic (Transparent) vs Managed (User must interact).', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_honeypot_settings_section', null, null, $page); add_settings_field( 'advaipbl_enable_honeypot_blocking', __('Enable Honeypot Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_honeypot_settings_section', [ 'name' => 'enable_honeypot_blocking', 'label' => __('Activate Honeypot trap protection.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('Manage Honeypot URLs in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=honeypot')), 'help_url' => 'https://advaipbl.com/honeypot-guide/' ] ); add_settings_field('advaipbl_duration_honeypot', __('Honeypot Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_honeypot_settings_section', ['name' => 'duration_honeypot', 'default' => 1440, 'description' => __('Block duration for IPs that fall into a honeypot URL. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_user_agent_settings_section', null, null, $page); add_settings_field('advaipbl_enable_user_agent_blocking', __('Enable User-Agent Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_user_agent_settings_section', ['name' => 'enable_user_agent_blocking', 'label' => __('Activate User-Agent based blocking.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('Manage User-Agent lists in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=user_agents'))]); add_settings_field('advaipbl_duration_user_agent', __('User-Agent Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_user_agent_settings_section', ['name' => 'duration_user_agent', 'default' => 1440, 'description' => __('Block duration for IPs with a malicious User-Agent. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_ua_excluded_urls', __('User-Agent URI Exclusions', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_user_agent_settings_section', ['name' => 'ua_excluded_urls', 'label' => __('Add one URL path or fragment per line. Requests containing these strings will completely bypass User-Agent blocking and scoring.', 'advanced-ip-blocker'), 'description' => __('Warning: Be as specific as possible to avoid inadvertently exposing your site to scraping and scanning.', 'advanced-ip-blocker')]); add_settings_field( 'advaipbl_enable_bot_verification', __('Verify Known Bots', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_user_agent_settings_section', [ 'name' => 'enable_bot_verification', 'label' => __('Enable reverse DNS verification for known crawlers (e.g., Googlebot, Bingbot).', 'advanced-ip-blocker'), 'description' => __('This prevents attackers from bypassing rules by faking their User-Agent. If an IP claims to be Googlebot but fails verification, it will be treated as a threat.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/verify-known-bots-rdns-guide/' ] ); add_settings_field( 'advaipbl_enable_ai_bot_verification', __('Verify AI Bots (CIDR)', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_user_agent_settings_section', [ 'name' => 'enable_ai_bot_verification', 'label' => __('Enable IP CIDR verification for AI crawlers (e.g., OpenAI, ChatGPT).', 'advanced-ip-blocker'), 'description' => __('Downloads official JSON IP lists from AI providers to verify their crawlers reliably, bypassing rDNS limitations.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/verify-ai-bots-cidr-guide/' ] ); add_settings_field( 'advaipbl_enable_monitoring_bot_verification', __('Verify Monitoring Bots (IP List)', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_user_agent_settings_section', [ 'name' => 'enable_monitoring_bot_verification', 'label' => __('Enable IP verification for Monitoring Bots (e.g., Uptime Robot, Pingdom).', 'advanced-ip-blocker'), 'description' => __('Downloads official IP lists from monitoring services to allow legitimate pings and block impersonators.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/verify-monitoring-bots-ip-list-complete-guide/' ] ); add_settings_section('advaipbl_asn_protection_section', __('ASN Protection', 'advanced-ip-blocker'), null, $page); add_settings_field( 'advaipbl_enable_spamhaus_asn', __('Spamhaus ASN Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_asn_protection_section', [ 'name' => 'enable_spamhaus_asn', 'label' => __('Enable automatic blocking using the Spamhaus ASN DROP list.', 'advanced-ip-blocker'), 'description' => __('Provides a powerful, auto-updating layer of protection against the worst networks on the internet. The list is refreshed daily.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/asn-blocking-guide/' ] ); add_settings_field('advaipbl_enable_manual_asn', __('Manual ASN Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_asn_protection_section', ['name' => 'enable_manual_asn', 'label' => __('Enable blocking based on your custom Manual ASN Blocklist.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('Manage your custom list in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=asn_blocking'))]); add_settings_field('advaipbl_duration_asn', __('ASN Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_asn_protection_section', ['name' => 'duration_asn', 'default' => 1440, 'description' => __('Duration to block IPs from both manual and automated ASN lists. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_field( 'advaipbl_block_ghost_ips', __('Block Ghost IPs', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_asn_protection_section', [ 'name' => 'block_ghost_ips', 'label' => __('Automatically block IPs without ASN and Reverse DNS (Warning: Could cause false positives if rDNS is misconfigured by ISPs).', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/block-ghost-ips-rdns-asn/' ] ); add_settings_section('advaipbl_under_attack_section', __('Distributed Attack Protection (Auto-Panic)', 'advanced-ip-blocker'), null, $page); add_settings_field( 'advaipbl_under_attack_mode', __('Under Attack Mode', 'advanced-ip-blocker'), [$this, 'select_field_callback'], $page, 'advaipbl_under_attack_section', [ 'name' => 'under_attack_mode', 'options' => [ 'off' => __('Off (Normal Operation)', 'advanced-ip-blocker'), 'auto' => __('Auto (Trigger on attack spikes)', 'advanced-ip-blocker'), 'manual' => __('Manual (Always On / Panic Mode)', 'advanced-ip-blocker') ], 'default' => 'off', 'label' => __('Activates a global JS Challenge for all non-whitelisted visitors to protect the server.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/distributed-attack-protection-auto-panic/' ] ); add_settings_field('advaipbl_under_attack_threshold', __('Trigger Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_threshold', 'default' => 100, 'description' => __('Total blocks (from any module) required to auto-trigger the Panic Mode.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_under_attack_window', __('Detection Window (sec)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_window', 'default' => 60, 'description' => __('The time window in seconds in which the block threshold must be reached.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_under_attack_duration', __('Panic Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_duration', 'default' => 15, 'description' => __('How long the Global Challenge will stay active after being auto-triggered.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_under_attack_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_challenge_mode', 'default' => 'automatic', 'description' => __('Choose the type of JS challenge to serve during the Panic Mode.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_under_attack_notification_email', __('Emergency Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_notification_email', 'label' => __('Leave empty to use the standard admin email.', 'advanced-ip-blocker')]); add_settings_field( 'advaipbl_under_attack_alerts', __('Panic Alerts', 'advanced-ip-blocker'), [$this, 'select_field_callback'], $page, 'advaipbl_under_attack_section', [ 'name' => 'under_attack_alerts', 'options' => [ 'always' => __('Send Always (Email & Push)', 'advanced-ip-blocker'), 'push_only' => __('Send Push Only (No Email)', 'advanced-ip-blocker'), 'disabled' => __('Disabled (Silent Mode)', 'advanced-ip-blocker') ], 'default' => 'always', 'description' => __('Choose how you want to be notified when Auto-Panic triggers.', 'advanced-ip-blocker') ] ); add_settings_field('advaipbl_under_attack_excluded_urls', __('Panic Mode Exclusions', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_excluded_urls', 'label' => __('Add one URI path or fragment per line (e.g., /wp-json/wc/v3/*). These URLs will NEVER be challenged during Panic Mode. Global Exclusions and WAF Exclusions are also automatically respected.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_waf_settings_section', null, null, $page); add_settings_field( 'advaipbl_enable_waf', __('Enable WAF', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_waf_settings_section', [ 'name' => 'enable_waf', 'label' => __('Activate the WAF to scan requests against your custom rules.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('Manage WAF rules in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=waf')), 'help_url' => 'https://advaipbl.com/waf-rules-guide/' ] ); add_settings_field('advaipbl_enable_intelligent_waf', __('Intelligent Zero-Day Sync', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'enable_intelligent_waf', 'label' => __('Automatically download and apply critical WAF zero-day signatures from the AIB Central Server (Daily).', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/intelligent-zero-day-waf-sync/']); add_settings_field('advaipbl_enable_cloud_advanced_rules', __('Cloud Advanced Rules Sync', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'enable_cloud_advanced_rules', 'label' => __('Automatically download and apply Advanced JSON Rules from the AIB Central Server.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_duration_waf', __('WAF Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'duration_waf', 'default' => 1440, 'description' => __('Duration to block IPs that trigger a WAF rule. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_waf_excluded_urls', __('Excluded URLs for WAF', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'waf_excluded_urls', 'label' => __('Add one URL fragment per line. Requests to URLs containing these strings will not be scanned by the WAF. Use this for payment gateway webhooks or problematic AJAX actions.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_404_settings_section', null, null, $page); add_settings_field('advaipbl_404_separator', '', [$this, 'separator_callback'], $page, 'advaipbl_404_settings_section'); add_settings_field('advaipbl_enable_404_lockdown', __('Enable 404 Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'enable_404_lockdown', 'label' => __('Activate Distributed Attack Protection', 'advanced-ip-blocker'), 'description' => __('If enabled, a global "Lockdown" will be triggered when too many 404 errors occur from multiple IPs. During lockdown, ALL 404 visitors must solve a JS Challenge.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_404_event_threshold', __('Lockdown Trigger: Max Errors', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_event_threshold', 'default' => 50, 'description' => __('Total 404 errors allowed across the entire site...', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_404_ip_threshold', __('Lockdown Trigger: Min Unique IPs', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_ip_threshold', 'default' => 5, 'description' => __('...originating from at least this many unique IPs...', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_404_window', __('Lockdown Trigger: Time Window', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_window', 'default' => 10, 'description' => __('...within this many minutes.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_404_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_duration', 'default' => 60, 'description' => __('How long the Lockdown Mode stays active.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_404_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_challenge_mode', 'description' => __('Choose the type of JS challenge to serve during a 404 Lockdown.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_404_separator', '', [$this, 'separator_callback'], $page, 'advaipbl_404_settings_section'); add_settings_field('advaipbl_threshold_404', __('Single IP: Block Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'threshold_404', 'default' => 10, 'description' => __('Block a specific IP if it generates this many 404 errors.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_transient_expiration_404', __('404 Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'transient_expiration_404', 'default' => 60, 'description' => __('Time period in which the error count must be reached.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_duration_404', __('404 Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'duration_404', 'default' => 120, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_403_settings_section', null, null, $page); add_settings_field('advaipbl_enable_403_lockdown', __('Enable 403 Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'enable_403_lockdown', 'label' => __('Activate Distributed Attack Protection', 'advanced-ip-blocker'), 'description' => __('If enabled, a global "Lockdown" will be triggered when too many 403 errors occur. During lockdown, ALL 403 visitors must solve a JS Challenge.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_403_event_threshold', __('Lockdown Trigger: Max Errors', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_event_threshold', 'default' => 50, 'description' => __('Total 403 errors allowed across the entire site...', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_403_ip_threshold', __('Lockdown Trigger: Min Unique IPs', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_ip_threshold', 'default' => 5, 'description' => __('...originating from at least this many unique IPs...', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_403_window', __('Lockdown Trigger: Time Window', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_window', 'default' => 10, 'description' => __('...within this many minutes.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_403_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_duration', 'default' => 60, 'description' => __('How long the Lockdown Mode stays active.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_lockdown_403_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_challenge_mode', 'description' => __('Choose the type of JS challenge to serve during a 403 Lockdown.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_403_separator', '', [$this, 'separator_callback'], $page, 'advaipbl_403_settings_section'); add_settings_field('advaipbl_threshold_403', __('Single IP: Block Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'threshold_403', 'default' => 5, 'description' => __('Block a specific IP if it generates this many 403 errors.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_transient_expiration_403', __('403 Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'transient_expiration_403', 'default' => 30, 'description' => __('Time period in which the error count must be reached.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_duration_403', __('403 Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'duration_403', 'default' => 60, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_rate_limiting_section', null, null, $page); add_settings_field('advaipbl_rate_limiting_enable', __('Enable Rate Limiting', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_enable', 'label' => __('Temporarily block IPs that make too many requests.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_rate_limiting_limit', __('Request Limit', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_limit', 'default' => 120, 'description' => __('Number of requests to allow within the time window.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_rate_limiting_window', __('Time Window (seconds)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_window', 'default' => 60, 'description' => __('The time period in which the request count is measured.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_duration_rate_limit', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'duration_rate_limit', 'default' => 5, 'description' => __('How long the IP will be blocked after reaching the limit.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_rate_limiting_advanced_rules', __('Advanced Rules', 'advanced-ip-blocker'), [$this, 'rate_limiting_advanced_rules_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_advanced_rules', 'description' => __('Define specific limits for different endpoints.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_login_settings_section', null, null, $page); add_settings_field('advaipbl_threshold_login', __('Login Failure Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'threshold_login', 'default' => 5, 'description' => __('Number of failed logins to trigger a block.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_transient_expiration_login', __('Login Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'transient_expiration_login', 'default' => 60, 'description' => __('Time period in which the failure count must be reached.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_duration_login', __('Login Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'duration_login', 'default' => 120, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_advanced_login_section', null, null, $page); add_settings_field('advaipbl_auto_whitelist_admin', __('Auto-Whitelist Admins', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'auto_whitelist_admin', 'label' => __('Automatically add administrator IPs to the whitelist on successful login.', 'advanced-ip-blocker'), 'description' => __('Ideal for admins who travel or have dynamic IP addresses.', 'advanced-ip-blocker')]); add_settings_field('advaipbl_disable_user_enumeration', __('REST API User Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'disable_user_enumeration', 'label' => __('Disable User Enumeration via REST API', 'advanced-ip-blocker')]); add_settings_field('advaipbl_prevent_author_scanning', __('Author Scan Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'prevent_author_scanning', 'label' => __('Prevent user enumeration via author scans', 'advanced-ip-blocker')]); add_settings_field('advaipbl_block_author_scanning_403', __('Strict Author Scan Block', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', [ 'name' => 'block_author_scanning_403', 'label' => __('Block author scans with 403 Error', 'advanced-ip-blocker'), 'description' => __('Instead of a 301 redirect, return a 403 Access Denied error. This will log the event and sum Threat Score points (as a 403 Error).', 'advanced-ip-blocker') ]); add_settings_field( 'advaipbl_prevent_login_hinting', __('Prevent Login Hinting', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', [ 'name' => 'prevent_login_hinting', 'label' => __('Prevent WordPress from revealing whether a username or email exists on login failure.', 'advanced-ip-blocker'), 'description' => __('Shows a generic error message for all login and "lost password" failures to prevent user enumeration.', 'advanced-ip-blocker') ] ); add_settings_field('advaipbl_restrict_login_page', __('Whitelist Login Access', 'advanced-ip-blocker'), [ $this, 'restrict_login_page_callback' ], $page, 'advaipbl_advanced_login_section'); add_settings_field('advaipbl_login_restrict_countries', __('Whitelist Login Countries', 'advanced-ip-blocker'), [ $this, 'geoblock_countries_callback' ], $page, 'advaipbl_advanced_login_section', [ 'type' => 'login_restrict', 'description' => __('Select one or more countries that are allowed to access wp-login.php. If empty, all countries are allowed.', 'advanced-ip-blocker') ]); add_settings_section('advaipbl_advanced_xmlrpc_section', null, null, $page); add_settings_field('advaipbl_xmlrpc_protection_mode', __('XML-RPC Protection Mode', 'advanced-ip-blocker'), [$this, 'xmlrpc_protection_mode_callback'], $page, 'advaipbl_advanced_xmlrpc_section'); add_settings_field('advaipbl_duration_xmlrpc_block', __('XML-RPC Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_advanced_xmlrpc_section', ['name' => 'duration_xmlrpc_block', 'default' => 1440, 'description' => __('How long to block IPs that make suspicious XML-RPC requests. Set to 0 for a permanent block.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_advanced_xmlrpc_protection_section', null, null, $page); add_settings_field( 'advaipbl_enable_xmlrpc_lockdown', __('XML-RPC Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_xmlrpc_protection_section', [ 'name' => 'enable_xmlrpc_lockdown', 'label' => __('Enable automated protection against distributed XML-RPC attacks.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('When a sustained attack is detected, this mode will temporarily challenge all non-whitelisted traffic to xmlrpc.php with a JavaScript verifier, stopping the attack without flooding your block list. Manage endpoints that are currently in "Lockdown Mode" in the Blocked Endpoints tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=ip_management&sub-tab=blocked_endpoints')) ] ); add_settings_field( 'advaipbl_xmlrpc_lockdown_threshold', __('Lockdown Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_advanced_xmlrpc_protection_section', [ 'name' => 'xmlrpc_lockdown_threshold', 'default' => 10, 'description' => __('Number of unique IP blocks on xmlrpc.php needed to trigger the lockdown.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_xmlrpc_lockdown_window', __('Lockdown Detection Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_advanced_xmlrpc_protection_section', [ 'name' => 'xmlrpc_lockdown_window', 'default' => 15, 'description' => __('The time frame (in minutes) in which the threshold must be reached.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_xmlrpc_lockdown_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_advanced_xmlrpc_protection_section', [ 'name' => 'xmlrpc_lockdown_duration', 'default' => 60, 'description' => __('How long the lockdown mode will remain active (in minutes).', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_xmlrpc_lockdown_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_advanced_xmlrpc_protection_section', [ 'name' => 'xmlrpc_lockdown_challenge_mode', 'description' => __('Choose the type of JS challenge to serve to non-whitelisted XML-RPC traffic during lockdown.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_login_lockdown_section', null, null, $page); add_settings_field( 'advaipbl_enable_login_lockdown', __('Login Page Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'enable_login_lockdown', 'label' => __('Enable automated protection against distributed brute-force attacks.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('When a sustained brute-force attack is detected, this mode will temporarily challenge all non-whitelisted traffic to wp-login.php with a JavaScript verifier.Manage endpoints that are currently in "Lockdown Mode" in the Blocked Endpoints tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=ip_management&sub-tab=blocked_endpoints')) ] ); add_settings_field( 'advaipbl_login_lockdown_event_threshold', __('Lockdown Event Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'login_lockdown_event_threshold', 'default' => 50, 'description' => __('Total number of failed login attempts needed to trigger the lockdown.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_login_lockdown_ip_threshold', __('Lockdown Unique IP Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'login_lockdown_ip_threshold', 'default' => 10, 'description' => __('Minimum number of unique IPs that must contribute to the failed logins.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_login_lockdown_window', __('Lockdown Detection Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'login_lockdown_window', 'default' => 5, 'description' => __('The time frame (in minutes) in which the thresholds must be reached.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_login_lockdown_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'login_lockdown_duration', 'default' => 60, 'description' => __('How long the lockdown mode will remain active (in minutes).', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_login_lockdown_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_login_lockdown_section', [ 'name' => 'login_lockdown_challenge_mode', 'description' => __('Choose the type of JS challenge to serve during a Login Page Lockdown.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_recaptcha_section', null, null, $page); add_settings_field('advaipbl_recaptcha_enable', __('Enable reCAPTCHA', 'advanced-ip-blocker'), [$this, 'recaptcha_enable_callback'], $page, 'advaipbl_recaptcha_section', ['help_url' => 'https://advaipbl.com/setup-google-recaptcha-protection/']); add_settings_field('advaipbl_recaptcha_version', __('reCAPTCHA Version', 'advanced-ip-blocker'), [$this, 'recaptcha_version_callback'], $page, 'advaipbl_recaptcha_section'); add_settings_field('advaipbl_recaptcha_site_key', __('Site Key', 'advanced-ip-blocker'), [$this, 'recaptcha_site_key_callback'], $page, 'advaipbl_recaptcha_section'); add_settings_field('advaipbl_recaptcha_secret_key', __('Secret Key', 'advanced-ip-blocker'), [$this, 'recaptcha_secret_key_callback'], $page, 'advaipbl_recaptcha_section'); add_settings_field('advaipbl_recaptcha_score_threshold', __('v3 Score Threshold', 'advanced-ip-blocker'), [$this, 'recaptcha_score_callback'], $page, 'advaipbl_recaptcha_section'); add_settings_section('advaipbl_captcha_integrations_section', null, null, $page); add_settings_field('advaipbl_default_challenge_engine', __('Default Challenge Engine', 'advanced-ip-blocker'), [$this, 'select_field_callback'], $page, 'advaipbl_captcha_integrations_section', [ 'name' => 'default_challenge_engine', 'options' => [ 'js_managed' => __('JS Challenge (Managed / Checkbox)', 'advanced-ip-blocker'), 'js_automatic' => __('JS Challenge (Automatic / Transparent)', 'advanced-ip-blocker'), 'turnstile' => __('Cloudflare Turnstile', 'advanced-ip-blocker'), 'hcaptcha' => __('hCaptcha', 'advanced-ip-blocker') ], 'description' => __('Select the default engine used when serving challenges (e.g. Rate Limiting, Under Attack Mode, Lockdowns). Note: Geo Challenge remains separate.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/captcha-integrations-advanced-ip-blocker/' ]); add_settings_field('advaipbl_turnstile_site_key', __('Turnstile Site Key', 'advanced-ip-blocker'), [$this, 'password_field_callback'], $page, 'advaipbl_captcha_integrations_section', [ 'name' => 'turnstile_site_key', 'class' => 'regular-text advaipbl-turnstile-field', 'default' => '', 'description' => sprintf( /* translators: %s is a placeholder */ __('You can get your Turnstile keys from the Cloudflare Dashboard.', 'advanced-ip-blocker'), // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent 'https://dash.cloudflare.com/?to=/:account/turnstile' ) ]); add_settings_field('advaipbl_turnstile_secret_key', __('Turnstile Secret Key', 'advanced-ip-blocker'), [$this, 'password_field_callback'], $page, 'advaipbl_captcha_integrations_section', [ 'name' => 'turnstile_secret_key', 'class' => 'regular-text advaipbl-turnstile-field', 'default' => '' ]); add_settings_field('advaipbl_hcaptcha_site_key', __('hCaptcha Site Key', 'advanced-ip-blocker'), [$this, 'password_field_callback'], $page, 'advaipbl_captcha_integrations_section', [ 'name' => 'hcaptcha_site_key', 'class' => 'regular-text advaipbl-hcaptcha-field', 'default' => '', 'description' => sprintf( /* translators: %s is a placeholder */ __('You can get your hCaptcha keys from the hCaptcha Dashboard.', 'advanced-ip-blocker'), 'https://dashboard.hcaptcha.com/' ) ]); add_settings_field('advaipbl_hcaptcha_secret_key', __('hCaptcha Secret Key', 'advanced-ip-blocker'), [$this, 'password_field_callback'], $page, 'advaipbl_captcha_integrations_section', [ 'name' => 'hcaptcha_secret_key', 'class' => 'regular-text advaipbl-hcaptcha-field', 'default' => '' ]); add_settings_section( 'advaipbl_2fa_settings_section', null, null, $page ); add_settings_field( 'advaipbl_enable_2fa', __('Enable Two-Factor Authentication', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_2fa_settings_section', [ 'name' => 'enable_2fa', 'label' => __('Enable the 2FA feature for all users on this site.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: %s is a placeholder */ __('When enabled, users will see the 2FA setup section in their Profile.', 'advanced-ip-blocker'), admin_url('profile.php')) ] ); add_settings_field( 'advaipbl_tfa_force_roles', __('Force 2FA for Roles', 'advanced-ip-blocker'), [$this, 'tfa_force_roles_callback'], $page, 'advaipbl_2fa_settings_section' ); add_settings_field( 'advaipbl_2fa_max_failures', __('Max 2FA Failures', 'advanced-ip-blocker'), [$this, 'number_field_callback'], $page, 'advaipbl_2fa_settings_section', [ 'name' => '2fa_max_failures', 'description' => __('Number of failed 2FA attempts before the account is temporarily locked.', 'advanced-ip-blocker'), 'min' => 1, 'max' => 50, 'default' => 5 ] ); add_settings_field( 'advaipbl_2fa_lockout_duration', __('2FA Lockout Duration (Minutes)', 'advanced-ip-blocker'), [$this, 'number_field_callback'], $page, 'advaipbl_2fa_settings_section', [ 'name' => '2fa_lockout_duration', 'description' => __('How long the account will remain locked after reaching the maximum failed 2FA attempts.', 'advanced-ip-blocker'), 'min' => 1, 'max' => 1440, 'default' => 15 ] ); add_settings_section('advaipbl_htaccess_settings_section', null, null, $page); $server_software = isset($_SERVER['SERVER_SOFTWARE']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE'])) : ''; $is_nginx = (stripos($server_software, 'nginx') !== false); $is_apache_ls = (stripos($server_software, 'Apache') !== false || stripos($server_software, 'LiteSpeed') !== false); $is_nginx_only = ($is_nginx && !$is_apache_ls); $htaccess_desc = __('This is required for all server-level blocking features. The plugin creates a backup before every write operation.', 'advanced-ip-blocker'); if ($is_nginx_only) { $htaccess_desc .= '
' . esc_html__('Disabled: Nginx server detected. .htaccess is not supported.', 'advanced-ip-blocker') . ''; } add_settings_field( 'advaipbl_enable_htaccess_write', __('Enable Htaccess Writer', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'enable_htaccess_write', 'label' => __('Allow the plugin to modify the .htaccess file.', 'advanced-ip-blocker'), 'description' => $htaccess_desc, 'help_url' => 'https://advaipbl.com/high-performance-server-level-firewall-htaccess/', 'disabled' => $is_nginx_only ] ); add_settings_field( 'advaipbl_enable_htaccess_ip_blocking', __('Sync Blocked IPs', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'enable_htaccess_ip_blocking', 'label' => __('Automatically write "Manually Blocked" and "Permanent" IPs to the .htaccess file.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_enable_htaccess_all_ips', __('Include Temporary Blocks', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'enable_htaccess_all_ips', 'label' => __('Write ALL blocked IPs (including temporary ones like 404/Login) to .htaccess.', 'advanced-ip-blocker'), 'description' => __('Advanced Performance: Offloads temporary blocks to the server. The file updates automatically when IPs expire. Requires "Sync Blocked IPs" to be enabled.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_htaccess_protect_system_files', __('Block System Files', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'htaccess_protect_system_files', 'label' => __('Block access to sensitive files (.git, .svn, .log, .sql, backups, etc.)', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_htaccess_protect_wp_config', __('Block wp-config.php', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'htaccess_protect_wp_config', 'label' => __('Block direct access to wp-config.php and wp-config-sample.php', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_htaccess_protect_readme', __('Block Readme Files', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_htaccess_settings_section', [ 'name' => 'htaccess_protect_readme', 'label' => __('Block access to readme.html and license.txt (prevents version enumeration)', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_cloudflare_section', null, null, $page); add_settings_field( 'advaipbl_enable_cloudflare', __('Enable Cloudflare Integration', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'enable_cloudflare', 'label' => __('Activate synchronization with Cloudflare Firewall.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/cloud-edge-defense-setup/' ] ); add_settings_field( 'advaipbl_cf_safe_guard', __('Cloudflare Safe-Guard', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'cf_safe_guard', 'label' => __('Protect official Cloudflare infrastructure, CDN perimeter nodes, and internal scanners (e.g., CloudflareWebScanner) from being blacklisted by local WAF rules, User-Agent pattern matching, or Threat Scoring.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_cf_api_token', __('Cloudflare API Token', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'cf_api_token', 'class' => 'regular-text', // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent 'description' => sprintf(/* translators: %s is a placeholder */ __('Create a token with Zone > Firewall > Edit permissions. Get Token', 'advanced-ip-blocker'), 'https://dash.cloudflare.com/profile/api-tokens'), 'data_provider' => 'cloudflare' ] ); add_settings_field( 'advaipbl_cf_zone_id', __('Zone ID', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'cf_zone_id', 'class' => 'regular-text', 'description' => __('Found on the "Overview" page of your domain in Cloudflare (bottom right).', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_cf_sync_manual', __('Sync Manual Blocks', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'cf_sync_manual', 'label' => __('Push "Manually Blocked" IPs to Cloudflare.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_cf_sync_temporary', __('Sync Temporary Blocks', 'advanced-ip-blocker'), [$this, 'checkbox_field_callback'], $page, 'advaipbl_cloudflare_section', [ 'name' => 'cf_sync_temporary', 'label' => __('Push temporary blocks (WAF, Login attempts, etc.) to Cloudflare.', 'advanced-ip-blocker'), 'description' => __('Recommended for High Security. Offload all bad traffic to the cloud.', 'advanced-ip-blocker') ] ); add_settings_section('advaipbl_uninstall_section', null, null, $page); add_settings_field('advaipbl_delete_data_on_uninstall', __('Delete Data on Uninstall', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_uninstall_section', ['name' => 'delete_data_on_uninstall', 'label' => __('Check to delete all data from this plugin when it is deleted.', 'advanced-ip-blocker')]); add_settings_section('advaipbl_threat_scoring_section', null, null, $page); add_settings_field( 'advaipbl_enable_threat_scoring', __('Enable Threat Scoring System', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_threat_scoring_section', [ 'name' => 'enable_threat_scoring', 'label' => __('Activate the dynamic IP threat scoring system.', 'advanced-ip-blocker'), 'description' => __('When enabled, the plugin will assign threat points to IPs for malicious actions instead of using simple thresholds. An IP will be blocked only when its total score reaches the configured threshold.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/threat-scoring-system-guide/' ] ); add_settings_field('advaipbl_threat_score_threshold', __('Blocking Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [ 'name' => 'threat_score_threshold', 'default' => 100, 'description' => __('An IP will be blocked when its threat score reaches or exceeds this value.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_duration_threat_score', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [ 'name' => 'duration_threat_score', 'default' => 360, 'description' => __('How long an IP will be blocked after reaching the threshold. Set to 0 for a permanent block.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_threat_scores', __('Threat Event Points', 'advanced-ip-blocker'), [$this, 'threat_scores_callback'], $page, 'advaipbl_threat_scoring_section'); add_settings_field('advaipbl_score_decay_points', __('Score Decay Rate', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [ 'name' => 'score_decay_points', 'default' => 1, 'description' => __('Number of points to subtract from an inactive IP\'s score during each decay cycle.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_score_decay_frequency', __('Score Decay Frequency (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [ 'name' => 'score_decay_frequency', 'default' => 1, 'description' => __('How often (in hours) to run the decay process. The score of an IP will only decay if it has been inactive for at least this period.', 'advanced-ip-blocker') ]); add_settings_section('advaipbl_signature_engine_section', null, null, $page); add_settings_field( 'advaipbl_enable_signature_engine', __('Enable Signature Logging', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'enable_signature_engine', 'label' => __('Activate the experimental request fingerprinting engine.', 'advanced-ip-blocker'), 'description' => __('Warning: This is an advanced feature for data collection. Activating it will log details of incoming requests to a new database table. Use only if you are aware of the potential performance impact on high-traffic sites.', 'advanced-ip-blocker'), 'help_url' => 'https://advaipbl.com/beyond-the-blocklist-introducing-the-intelligent-ip-trust-attack-signature-engines/' ] ); add_settings_field('advaipbl_enable_signature_analysis', __('Enable Signature Analysis', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'enable_signature_analysis', 'label' => __('Activate automatic analysis of request signatures.', 'advanced-ip-blocker'), 'description' => __('When enabled, a background process will analyze the collected logs to find patterns of a distributed attack.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_enable_signature_blocking', __('Enable Signature Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'enable_signature_blocking', 'label' => __('Activate blocking based on malicious signatures.', 'advanced-ip-blocker'), 'description' => __('Enable this to activate protection. When a request matches a known malicious signature, the plugin will present a JavaScript challenge to filter out bots.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_challenge_mode', 'description' => __('Choose the type of JS challenge to serve when defending against distributed attacks.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_ip_threshold', __('Signature IP Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_ip_threshold', 'default' => 5, 'description' => __('The minimum number of different IPs that must use the same attack signature to be flagged as malicious.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_analysis_window', __('Analysis Window (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_analysis_window', 'default' => 1, 'description' => __('How far back (in hours) the analysis process should look for patterns.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_rule_ttl', __('Signature Rule Lifetime (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_rule_ttl', 'default' => 24, 'description' => __('How long a malicious signature will remain active before it expires.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_notification_frequency', __('Notification Frequency', 'advanced-ip-blocker'), [$this, 'signature_notification_frequency_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_notification_frequency', 'label' => __('How often to send alerts for detected signatures.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_notification_recipient', __('Notification Recipient', 'advanced-ip-blocker'), [$this, 'signature_notification_recipient_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_notification_recipient', 'label' => __('Who should receive these specific alerts.', 'advanced-ip-blocker') ]); add_settings_field('advaipbl_signature_notification_custom_email', __('Custom Recipient Email', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [ 'name' => 'signature_notification_custom_email', 'class' => 'regular-text', 'description' => __('Required if "Custom Email" is selected above.', 'advanced-ip-blocker') ]); add_settings_section('advaipbl_trusted_signatures_section', __('Trusted Signatures (Whitelist)', 'advanced-ip-blocker'), [$this, 'trusted_signatures_section_callback'], $page); add_settings_field('advaipbl_trusted_signature_hashes', __('Trusted Signature Hashes', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_trusted_signatures_section', [ 'name' => 'trusted_signature_hashes', 'label' => __('Add known legitimate signature hashes here (one per line). Requests matching these exact fingerprints will always be allowed and never logged by the Signature Engine. Use this for services like Googlebot, Facebook Crawler, etc., to prevent false positives. Find hashes in the "Blocked Signatures" page by clicking "View Details".', 'advanced-ip-blocker') ]); // --- INTERNAL SECURITY & FORENSICS (v8.7.1) --- add_settings_section('advaipbl_internal_security_section', __('Internal Security & Forensics', 'advanced-ip-blocker'), null, $page); add_settings_field( 'advaipbl_enable_audit_log', __('Enable Activity Audit Log', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'enable_audit_log', 'label' => __('Record critical administrative actions.', 'advanced-ip-blocker'), 'description' => __('Logs plugin rule changes, setting updates, and other critical admin events to a separate audit table.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_enable_fim', __('Enable File Integrity Monitor', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'enable_fim', 'fim_scan_uploads', 'fim_enable_raw', 'fim_enable_regex', 'fim_enable_domains', 'fim_enable_md5', 'fim_enable_sha256', 'label' => __('Monitor critical WordPress files for unauthorized changes.', 'advanced-ip-blocker'), 'description' => __('Automatically scans core files (wp-config.php, .htaccess, index.php) daily for modifications.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_scan_uploads', __('Scan Uploads Directory', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_scan_uploads', 'label' => __('Scan the wp-content/uploads directory for suspicious executable files (.php). Legitimate index.php files are safely ignored.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_enable_raw', __('Enable Raw String Signatures', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_enable_raw', 'label' => __('Detect malware using ultra-fast exact string matching.', 'advanced-ip-blocker'), 'description' => __('Recommended. This is the fastest and most common method for detecting known malware strings.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_enable_regex', __('Enable RegEx Signatures', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_enable_regex', 'label' => __('Detect highly obfuscated malware using Regular Expressions.', 'advanced-ip-blocker'), 'description' => __('Advanced. Uses more CPU but detects polymorphic backdoors.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_chunk_size', __('Deep Scan Chunk Size', 'advanced-ip-blocker'), [$this, 'number_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_chunk_size', 'label' => __('Number of files to process per batch (Max 100)', 'advanced-ip-blocker'), 'description' => __('Lower this value (e.g. 50 or 25) if your server times out during a Deep Scan.', 'advanced-ip-blocker'), 'default' => 100, 'min' => 10, 'max' => 100 ] ); add_settings_field( 'advaipbl_fim_enable_domains', __('Enable Domain Signatures', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_enable_domains', 'label' => __('Detect malicious domains, APIs, and C2 servers inside files.', 'advanced-ip-blocker'), 'description' => __('Recommended. Very fast check for external malicious requests.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_enable_md5', __('Enable MD5 Hash Signatures', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_enable_md5', 'label' => __('Identify known malware files instantly using MD5 hashes.', 'advanced-ip-blocker'), 'description' => __('Recommended. Skips reading file contents if the hash matches known malware.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_enable_sha256', __('Enable SHA256 Hash Signatures', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_enable_sha256', 'label' => __('Identify known malware files using SHA256 hashes.', 'advanced-ip-blocker'), 'description' => __('Slower than MD5 but highly accurate.', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_excluded_paths', __('Excluded Paths for FIM', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_excluded_paths', 'description' => __('Add one path fragment per line. If a scanned file\'s path contains any of these strings, it will be ignored by the FIM. Example: wp-content/uploads/cache/', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_alert_email', __('FIM Alert Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_alert_email', 'label' => __('Where to send critical file change alerts (leave blank for admin email).', 'advanced-ip-blocker') ] ); add_settings_field( 'advaipbl_fim_scan_frequency', __('Scan Frequency', 'advanced-ip-blocker'), [$this, 'select_field_callback'], $page, 'advaipbl_internal_security_section', [ 'name' => 'fim_scan_frequency', 'options' => [ 'daily' => __('Daily (Recommended)', 'advanced-ip-blocker'), 'twicedaily' => __('Twice a day (Every 12 hours)', 'advanced-ip-blocker'), 'advaipbl_6_hours' => __('High Security (Every 6 hours - Warning: Consumes more resources)', 'advanced-ip-blocker') ] ] ); add_settings_field( 'advaipbl_fim_manual_scan_button', __('Manual Scan', 'advanced-ip-blocker'), [$this, 'fim_manual_scan_button_callback'], $page, 'advaipbl_internal_security_section' ); add_settings_field( 'advaipbl_fim_reset_baseline_button', __('Reset Baseline Hashes', 'advanced-ip-blocker'), [$this, 'fim_reset_baseline_button_callback'], $page, 'advaipbl_internal_security_section' ); } public function sanitize_settings($input) { $new_input = get_option(ADVAIPBL_Main::OPTION_SETTINGS, []); $defaults = $this->plugin->get_default_settings(); $existing_options = get_option(ADVAIPBL_Main::OPTION_SETTINGS, []); if (! is_array($existing_options)) { $existing_options = []; } $new_input = $existing_options; $numeric_fields = [ '2fa_max_failures', '2fa_lockout_duration', 'threshold_404', 'duration_404', 'transient_expiration_404', 'threshold_403', 'duration_403', 'transient_expiration_403', 'threshold_login', 'duration_login', 'transient_expiration_login', 'duration_geoblock', 'duration_honeypot', 'duration_user_agent', 'duration_waf', 'duration_rate_limit', 'rate_limiting_limit', 'rate_limiting_window', 'duration_asn', 'duration_xmlrpc_block', 'rows_per_page', 'log_retention_days', 'threat_score_threshold', 'duration_threat_score', 'score_404', 'score_403', 'score_login', 'score_login_geoblock', 'score_login_whitelist_block', 'score_user_agent', 'score_waf', 'score_honeypot', 'score_asn', 'score_impersonation', 'score_decay_points', 'score_decay_frequency', 'signature_ip_threshold', 'signature_analysis_window', 'signature_rule_ttl', 'xmlrpc_lockdown_threshold', 'xmlrpc_lockdown_window', 'xmlrpc_lockdown_duration', 'login_lockdown_event_threshold', 'login_lockdown_ip_threshold', 'login_lockdown_window', 'login_lockdown_duration', 'lockdown_404_event_threshold', 'lockdown_404_ip_threshold', 'lockdown_404_window', 'lockdown_404_duration', 'lockdown_403_event_threshold', 'lockdown_403_ip_threshold', 'lockdown_403_window', 'lockdown_403_duration', 'global_challenge_cookie_duration', 'geo_challenge_cookie_duration', 'abuseipdb_threshold', 'duration_abuseipdb', 'duration_aib_network', 'community_min_score', 'under_attack_threshold', 'under_attack_window', 'under_attack_duration' ]; foreach ($numeric_fields as $field) { if (isset($input[$field])) { $new_input[$field] = absint($input[$field]); } } if (isset($input['fim_chunk_size'])) { $chunk_size = absint($input['fim_chunk_size']); $new_input['fim_chunk_size'] = max(10, min(100, $chunk_size)); } $checkbox_fields = [ 'prevent_author_scanning', 'block_author_scanning_403', 'disable_user_enumeration', 'restrict_login_page', 'enable_logging', 'enable_payload_logging', 'delete_data_on_uninstall', 'enable_email_notifications', 'enable_waf', 'enable_intelligent_waf', 'enable_cloud_advanced_rules', 'enable_geoblocking', 'enable_honeypot_blocking', 'enable_user_agent_blocking', 'rate_limiting_enable', 'show_admin_bar_menu', 'enable_spamhaus_asn', 'enable_manual_asn', 'enable_push_notifications', 'push_critical_only', 'auto_whitelist_admin', 'allow_telemetry', 'enable_threat_scoring', 'enable_signature_engine', 'enable_signature_blocking', 'enable_signature_analysis', 'enable_2fa', 'recaptcha_enable', 'prevent_login_hinting', 'enable_xmlrpc_lockdown', 'enable_login_lockdown', 'enable_404_lockdown', 'enable_403_lockdown', 'enable_geo_challenge', 'enable_bot_verification', 'enable_ai_bot_verification', 'enable_monitoring_bot_verification', 'enable_community_blocking', 'enable_abuseipdb', 'enable_community_network', 'enable_htaccess_write', 'enable_cloudflare', 'cf_safe_guard', 'cf_sync_manual', 'cf_sync_temporary', 'enable_htaccess_ip_blocking', 'enable_htaccess_all_ips', 'htaccess_protect_system_files', 'htaccess_protect_wp_config', 'htaccess_protect_readme', 'htaccess_protect_readme', 'enable_scheduled_scans', 'enable_audit_log', 'enable_fim', 'fim_scan_uploads', 'fim_enable_raw', 'fim_enable_regex', 'fim_enable_domains', 'fim_enable_md5', 'fim_enable_sha256', 'scan_check_ssl', 'scan_check_updates', 'scan_check_php', 'scan_check_wp', 'scan_check_debug', 'block_ghost_ips', 'disable_imagick', 'hide_wp_version', 'disable_app_passwords', 'disable_file_editor', 'block_php_uploads', 'remove_x_powered_by' ]; foreach ($checkbox_fields as $field) { if (isset($input[$field])) { $new_input[$field] = ($input[$field] === '1') ? '1' : '0'; } } if (isset($input['tfa_force_roles'])) { $new_input['tfa_force_roles'] = is_array($input['tfa_force_roles']) ? array_map('sanitize_key', $input['tfa_force_roles']) : []; } else { $new_input['tfa_force_roles'] = []; } if (isset($input['allowed_admin_users'])) { $new_input['allowed_admin_users'] = is_array($input['allowed_admin_users']) ? array_map('sanitize_text_field', $input['allowed_admin_users']) : []; } else { $new_input['allowed_admin_users'] = []; } $text_fields = [ 'notification_frequency', 'custom_block_message', 'excluded_error_urls', 'waf_excluded_urls', 'ua_excluded_urls', 'push_webhook_urls', 'push_mentions', 'trusted_signature_hashes', 'notification_email', 'signature_notification_frequency', 'signature_notification_recipient', 'signature_notification_custom_email', 'api_key_ipapicom', 'api_key_ipstackcom', 'api_key_ipinfocom', 'api_key_ip_apicom', 'maxmind_license_key', 'geolocation_provider', 'log_timezone', 'recaptcha_version', 'recaptcha_site_key', 'recaptcha_secret_key', 'xmlrpc_protection_mode', 'geolocation_method', 'trusted_proxies', 'abuseipdb_api_key', 'abuseipdb_action', 'cf_api_token', 'cf_zone_id', 'community_blocking_action', 'scan_frequency', 'scan_notification_email', 'fim_alert_email', 'api_token_v3', 'fim_excluded_paths', 'fim_scan_frequency', 'geo_challenge_mode', 'lockdown_404_challenge_mode', 'lockdown_403_challenge_mode', 'xmlrpc_lockdown_challenge_mode', 'login_lockdown_challenge_mode', 'signature_challenge_mode', 'under_attack_mode', 'under_attack_challenge_mode', 'under_attack_notification_email', 'under_attack_excluded_urls', 'under_attack_alerts', 'default_challenge_engine', 'turnstile_site_key', 'turnstile_secret_key', 'hcaptcha_site_key', 'hcaptcha_secret_key' ]; foreach ($text_fields as $field) { if (isset($input[$field])) { if ($field === 'custom_block_message') { $allowed_html = [ 'h1' => [], 'br' => [], ]; $new_input[$field] = wp_kses($input[$field], $allowed_html); } elseif (strpos($field, 'email') !== false) { $new_input[$field] = sanitize_email($input[$field]); } elseif (strpos($field, 'urls') !== false || strpos($field, 'proxies') !== false || strpos($field, 'hashes') !== false || strpos($field, 'mentions') !== false || strpos($field, 'paths') !== false) { $new_input[$field] = sanitize_textarea_field($input[$field]); } else { $new_input[$field] = sanitize_text_field($input[$field]); } } } if (isset($new_input['api_token_v3']) && $new_input['api_token_v3'] !== ($this->plugin->options['api_token_v3'] ?? '')) { if (!empty($new_input['api_token_v3'])) { $response = wp_remote_get('https://advaipbl.com/wp-json/aib-api/v3/verify-token?v=' . ADVAIPBL_VERSION, [ 'headers' => [ 'Authorization' => 'Bearer ' . $new_input['api_token_v3'], 'X-AIB-Auth' => 'Bearer ' . $new_input['api_token_v3'], 'Accept' => 'application/json' ], 'timeout' => 15 ]); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { add_settings_error('advaipbl_settings_messages', 'invalid_v3_token', __('Invalid AIB Cloud Network Token. Connection failed.', 'advanced-ip-blocker'), 'error'); $new_input['api_token_v3'] = $this->plugin->options['api_token_v3'] ?? ''; } } } if (isset($new_input['maxmind_license_key']) && $new_input['maxmind_license_key'] !== ($this->plugin->options['maxmind_license_key'] ?? '')) { if (!empty($new_input['maxmind_license_key'])) { wp_clear_scheduled_hook('advaipbl_update_geoip_db_event'); wp_schedule_event(time() + 60, 'advaipbl_3_days', 'advaipbl_update_geoip_db_event'); } } if (isset($input['geoblock_countries'])) { $countries = (array) $input['geoblock_countries']; $all_country_codes = array_keys($this->plugin->get_country_list()); $new_input['geoblock_countries'] = array_values(array_intersect($countries, $all_country_codes)); } else { $new_input['geoblock_countries'] = []; } if (isset($input['geo_challenge_countries'])) { $countries = (array) $input['geo_challenge_countries']; $all_country_codes = array_keys($this->plugin->get_country_list()); $new_input['geo_challenge_countries'] = array_values(array_intersect($countries, $all_country_codes)); } else { $new_input['geo_challenge_countries'] = []; } if (isset($input['login_restrict_countries'])) { $countries = (array) $input['login_restrict_countries']; $all_country_codes = array_keys($this->plugin->get_country_list()); $new_input['login_restrict_countries'] = array_values(array_intersect($countries, $all_country_codes)); } else { $new_input['login_restrict_countries'] = []; } if (isset($input['recaptcha_score_threshold'])) { $new_input['recaptcha_score_threshold'] = $this->plugin->sanitize_score_threshold($input['recaptcha_score_threshold']); } if (isset($input['rate_limiting_advanced_rules'])) { $json_string = wp_unslash($input['rate_limiting_advanced_rules']); $decoded = json_decode($json_string, true); if (is_array($decoded)) { $clean_rules = []; foreach ($decoded as $rule) { if (isset($rule['endpoint'])) { $clean_rules[] = [ 'endpoint' => sanitize_text_field($rule['endpoint']), 'limit' => absint($rule['limit']), 'window' => absint($rule['window']), 'action' => sanitize_text_field($rule['action']) ]; } } $new_input['rate_limiting_advanced_rules'] = wp_json_encode($clean_rules); } else { $new_input['rate_limiting_advanced_rules'] = '[]'; } } // Purge page caches when security settings are updated $this->plugin->purge_all_page_caches(); return $new_input; } public function text_field_callback($args) { $value = $this->plugin->options[$args['name']] ?? $args['default'] ?? ''; $class = $args['class'] ?? ''; $data_attr = ! empty($args['data_provider']) ? 'data-provider="' . esc_attr($args['data_provider']) . '"' : ''; if ((isset($args['name']) && substr($args['name'], -8) === '_api_key') || !empty($args['data_provider'])) { printf( ' ', esc_attr($args['name']), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($value), esc_attr($class), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $data_attr, esc_attr($args['data_provider']), esc_html__('Verify', 'advanced-ip-blocker') ); } else { $is_numeric = false; if (isset($args['name']) && is_string($args['name'])) { $numeric_keywords = ['duration', 'threshold', 'retention', 'score', 'points', 'frequency', 'limit', 'window', 'expiration', 'ttl']; foreach ($numeric_keywords as $keyword) { if (strpos($args['name'], $keyword) !== false) { $is_numeric = true; break; } } } $type = $is_numeric ? 'number' : 'text'; $min_attr = ('number' === $type) ? 'min="0"' : ''; printf( '', esc_attr($type), esc_attr($args['name']), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($value), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $min_attr, esc_attr($class) ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if (isset($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } } public function number_field_callback($args) { $value = $this->plugin->options[$args['name']] ?? $args['default'] ?? ''; $class = $args['class'] ?? ''; $min = isset($args['min']) ? 'min="' . esc_attr($args['min']) . '"' : ''; $max = isset($args['max']) ? 'max="' . esc_attr($args['max']) . '"' : ''; printf( '', esc_attr($args['name']), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($value), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $min, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $max, esc_attr($class) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if (isset($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } } public function password_field_callback($args) { $value = $this->plugin->options[$args['name']] ?? $args['default'] ?? ''; $class = $args['class'] ?? ''; printf( '', esc_attr($args['name']), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($value), esc_attr($class) ); if (isset($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } } public function checkbox_field_callback($args) { $checked = checked('1', $this->plugin->options[$args['name']] ?? '0', false); $id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : ''; $html = sprintf( '', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr('advaipbl_settings[' . $args['name'] . ']'), $checked, $id_attr, esc_html($args['label']) ); $html .= $this->get_help_link_html($args); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; if (! empty($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } } public function rate_limiting_advanced_rules_callback($args) { $options = get_option(ADVAIPBL_Main::OPTION_SETTINGS); $name = $args['name']; $val = isset($options[$name]) ? $options[$name] : '[]'; echo ''; echo '
'; echo ''; if (isset($args['description'])) { echo '

' . esc_html($args['description']) . '

'; } ?> plugin->options[$args['name']] ?? []; $id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : 'advaipbl_' . esc_attr($args['name']); $admin_users = get_users(['role' => 'administrator']); $html = '
'; $hidden_inputs = ''; foreach ($admin_users as $user) { $is_super = ($user->ID == 1 || (is_multisite() && is_super_admin($user->ID))); $is_selected = in_array((string)$user->ID, $selected_users, true) || in_array($user->ID, $selected_users, true) || empty($selected_users); $disabled_attr = $is_super ? 'disabled="disabled"' : ''; if ($is_super) { $is_selected = true; $hidden_inputs .= sprintf('', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($user->ID)); } $checked_attr = $is_selected ? 'checked="checked"' : ''; $label = esc_html($user->user_login . ' (' . $user->user_email . ')'); if ($is_super) { $label .= ' - ' . __('Protected', 'advanced-ip-blocker') . ''; } $html .= sprintf( '', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($user->ID), $checked_attr, $disabled_attr, $label ); } $html .= '
'; $html .= $hidden_inputs; if (!empty($args['description'])) { $html .= '

' . wp_kses_post($args['description']) . '

'; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; } public function switch_field_callback($args) { $default = $args['default'] ?? '0'; $value = $this->plugin->options[$args['name']] ?? $default; // If the field is forcefully disabled (e.g., due to Nginx), it must visually appear OFF if (!empty($args['disabled'])) { $value = '0'; } $id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : 'advaipbl_switch_' . esc_attr($args['name']); $disabled_attr = !empty($args['disabled']) ? 'disabled="disabled"' : ''; $html = sprintf( ' ', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($id_attr), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($id_attr), checked('1', $value, false), $disabled_attr ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; if (! empty($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } elseif (! empty($args['label'])) { echo ''; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); } public function textarea_field_callback($args) { $value = isset($args['value']) ? $args['value'] : ($this->plugin->options[$args['name']] ?? ''); $rows = $args['rows'] ?? 5; $class = $args['class'] ?? 'large-text'; $readonly_attr = !empty($args['readonly']) ? 'readonly' : ''; printf( '', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($rows), esc_textarea($value), esc_attr($class), esc_attr($readonly_attr) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if (isset($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } elseif (isset($args['label'])) { echo '

' . esc_html($args['label']) . '

'; } } public function trusted_proxies_callback($args) { $value = isset($args['value']) ? $args['value'] : ($this->plugin->options[$args['name']] ?? ''); $rows = $args['rows'] ?? 10; $class = $args['class'] ?? 'large-text'; $textarea_id = 'advaipbl_settings_' . $args['name']; printf( '', esc_attr($textarea_id), esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($rows), esc_attr($class), esc_textarea($value) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if (isset($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } $presets = $this->plugin->cdn_manager->get_presets(); echo '
'; echo '' . esc_html__('Quick Add CDN/Proxy:', 'advanced-ip-blocker') . '
'; echo ' '; echo ''; echo '

' . esc_html__('Select a service to automatically append its known IP ranges/ASNs to your trusted list.', 'advanced-ip-blocker') . '

'; echo '
'; ?> plugin->options[$args['name']] ?? ''; printf( '', esc_attr('advaipbl_settings[' . $args['name'] . ']'), esc_attr($value), esc_attr(get_option('admin_email')) ); if (isset($args['label'])) { printf( '

%s

', esc_html($args['label']) ); } } public function select_field_callback($args) { $name = $args['name']; $options_list = $args['options'] ?? []; $default_val = $args['default'] ?? ''; $value = $this->plugin->options[$name] ?? $default_val; echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if (isset($args['label'])) { printf( '

%s

', wp_kses_post($args['label']) ); } } public function timezone_select_callback() { $name_attr = 'advaipbl_settings[log_timezone]'; $current_timezone = $this->plugin->options['log_timezone'] ?? wp_timezone_string(); echo ''; echo '

' . esc_html__('Select the timezone to display in the logs.', 'advanced-ip-blocker') . '

'; } public function notification_frequency_callback() { $value = $this->plugin->options['notification_frequency'] ?? 'disabled'; $frequencies = [ 'disabled' => __('Disabled', 'advanced-ip-blocker'), 'instant' => __('Instant', 'advanced-ip-blocker'), 'daily' => __('Daily Summary', 'advanced-ip-blocker'), 'weekly' => __('Weekly Summary', 'advanced-ip-blocker') ]; echo ''; echo '

' . esc_html__('Choose how often you want to receive alert emails.', 'advanced-ip-blocker') . '

'; } public function signature_notification_frequency_callback() { $value = $this->plugin->options['signature_notification_frequency'] ?? 'instant'; $frequencies = [ 'instant' => __('Instant (Batch per hour)', 'advanced-ip-blocker'), 'daily' => __('Daily Digest', 'advanced-ip-blocker'), 'weekly' => __('Weekly Digest', 'advanced-ip-blocker'), 'disabled' => __('Disabled', 'advanced-ip-blocker') ]; echo ''; echo '

' . esc_html__('Instant mode sends one email per detection cycle (hourly). Digests accumulate signatures.', 'advanced-ip-blocker') . '

'; } public function signature_notification_recipient_callback() { $value = $this->plugin->options['signature_notification_recipient'] ?? 'default'; $recipients = [ 'default' => __('Default (Use Plugin Recipient)', 'advanced-ip-blocker'), 'admin' => __('Administrator Email', 'advanced-ip-blocker'), 'custom' => __('Custom Email', 'advanced-ip-blocker') ]; echo ''; } public function scan_frequency_callback() { $value = $this->plugin->options['scan_frequency'] ?? 'weekly'; $frequencies = [ 'daily' => __('Daily', 'advanced-ip-blocker'), 'weekly' => __('Weekly', 'advanced-ip-blocker') ]; echo ''; echo '

' . esc_html__('How often to run the automated security audit.', 'advanced-ip-blocker') . '

'; } public function send_test_scan_button_callback() { $nonce_url = wp_nonce_url( admin_url('admin-post.php?action=advaipbl_run_manual_scan'), 'advaipbl_run_manual_scan_nonce' ); ?>

['label' => __('404 Error', 'advanced-ip-blocker'), 'default' => 5], 'score_403' => ['label' => __('403 Error', 'advanced-ip-blocker'), 'default' => 10], 'score_login' => ['label' => __('Failed Login', 'advanced-ip-blocker'), 'default' => 15], 'score_login_geoblock' => ['label' => __('Login Geoblock', 'advanced-ip-blocker'), 'default' => 25], 'score_login_whitelist_block' => ['label' => __('Login Whitelist Block', 'advanced-ip-blocker'), 'default' => 25], 'score_user_agent' => ['label' => __('Blocked User-Agent', 'advanced-ip-blocker'), 'default' => 60], 'score_waf' => ['label' => __('WAF Rule Triggered', 'advanced-ip-blocker'), 'default' => 60], 'score_impersonation' => ['label' => __('Bot Impersonation', 'advanced-ip-blocker'), 'default' => 75], 'score_honeypot' => ['label' => __('Honeypot Accessed', 'advanced-ip-blocker'), 'default' => 100], 'score_asn' => ['label' => __('Blocked ASN (Spamhaus)', 'advanced-ip-blocker'), 'default' => 100], ]; ?>
$details) : ?> plugin->options[$name] ?? $details['default']; ?>

plugin->options['geolocation_provider'] ?? 'ip-api.com'; $providers = [ 'ip-api.com' => __('ip-api.com (Default, no key for HTTP)', 'advanced-ip-blocker'), 'geoiplookup.net' => __('geoiplookup.net (Free, no key)', 'advanced-ip-blocker'), 'ipinfo.io' => __('ipinfo.io (API Key recommended)', 'advanced-ip-blocker'), 'ipapi.com' => __('ipapi.com (API Key required)', 'advanced-ip-blocker'), 'ipstack.com' => __('ipstack.com (API Key required)', 'advanced-ip-blocker') ]; printf(''; } /** * Renders the checkbox for the Whitelist Login Access feature, including security checks. */ public function restrict_login_page_callback() { $args = [ 'name' => 'restrict_login_page', 'label' => __('Restrict access to wp-login.php to whitelisted IPs only', 'advanced-ip-blocker') ]; $client_ip = $this->plugin->get_client_ip(); $is_whitelisted = $this->plugin->is_whitelisted($client_ip); $this->checkbox_field_callback($args); echo '

' . esc_html__('WARNING: This is a highly restrictive feature. Only enable it if you have a static IP address and public user registration is disabled on your site.', 'advanced-ip-blocker') . '

'; if (! $is_whitelisted) { echo '

'; echo '' . sprintf(/* translators: %s is a placeholder */ esc_html__('Your current IP address (%s) is NOT whitelisted.', 'advanced-ip-blocker'), esc_html($client_ip)) . ' ' . esc_html__('You MUST add it to the whitelist before enabling this feature, or you will be locked out.', 'advanced-ip-blocker'); echo ''; echo '

'; } } /** * Callback to show the V3 API connection status. */ public function api_connection_status_callback() { $token = $this->plugin->options['api_token_v3'] ?? ''; if (empty($token)) { echo ' ' . esc_html__('Not Connected', 'advanced-ip-blocker') . ''; echo '

' . esc_html__('Get a Free API Key below to connect your site to the AIB Cloud Network.', 'advanced-ip-blocker') . '

'; } else { echo '
'; echo ' ' . esc_html__('Connected', 'advanced-ip-blocker') . ''; echo ' ' . esc_html__('AIB Cloud Network', 'advanced-ip-blocker') . ''; echo '

'; echo ''; echo ''; echo '

'; echo '
'; } } /** * Specific callback for the API Token field with obfuscation. */ public function api_token_field_callback($args) { $name = $args['name']; $value = isset($this->plugin->options[$name]) ? $this->plugin->options[$name] : ''; $display_val = $value; if (!empty($value) && strlen($value) > 8) { $display_val = substr($value, 0, 4) . str_repeat('•', 24) . substr($value, -4); } echo '
'; echo '
'; echo ''; echo ''; echo ''; } else { echo 'name="' . esc_attr(ADVAIPBL_Main::OPTION_SETTINGS) . '[' . esc_attr($name) . ']" id="advaipbl_' . esc_attr($name) . '" value="" placeholder="AIB_xxxxxxxxxxxxxxxxxxxxxxxxxx">'; echo ''; echo ''; } echo '
'; if (isset($args['description']) && empty($value)) { echo '

' . wp_kses_post($args['description']) . '

'; } elseif (!empty($value)) { echo '

' . esc_html__('Your API key is hidden for security.', 'advanced-ip-blocker') . '

'; } ?> field for the XML-RPC protection mode. */ public function xmlrpc_protection_mode_callback() { $current_mode = $this->plugin->options['xmlrpc_protection_mode'] ?? 'smart'; $modes = [ 'enabled' => __('Enabled (Not Recommended)', 'advanced-ip-blocker'), 'smart' => __('Smart Protection (Recommended)', 'advanced-ip-blocker'), 'disabled' => __('Completely Disabled', 'advanced-ip-blocker'), ]; ?>


-
-

' . esc_html__('Block access from entire countries. This feature requires a working Geolocation Provider to be configured above.', 'advanced-ip-blocker') . '

'; echo '

' . esc_html__('Warning:', 'advanced-ip-blocker') . ' ' . esc_html__('Blocking countries can prevent legitimate users and services (like payment gateways) from accessing your site. Use with caution.', 'advanced-ip-blocker') . '

'; } /** * Displays the multi-select field for countries, reusable for Geoblocking and Geo-Challenge. * @param array $args Arguments passed from add_settings_field. */ public function geoblock_countries_callback($args) { $type = $args['type'] ?? 'geoblock'; if ($type === 'geo_challenge') { $option_name = 'geo_challenge_countries'; $placeholder_text = __('Search for a country to challenge...', 'advanced-ip-blocker'); } elseif ($type === 'login_restrict') { $option_name = 'login_restrict_countries'; $placeholder_text = __('Search for an allowed country...', 'advanced-ip-blocker'); } else { $option_name = 'geoblock_countries'; $placeholder_text = __('Search for a country to block...', 'advanced-ip-blocker'); } $select_id = 'advaipbl_' . $option_name; $selected_countries = $this->plugin->options[$option_name] ?? []; $all_countries = $this->plugin->get_country_list(); ?>

plugin->options['enable_fim'])) { echo '

' . esc_html__('Enable the File Integrity Monitor to run scans.', 'advanced-ip-blocker') . '

'; return; } $nonce = wp_create_nonce('advaipbl_run_fim_scan_nonce'); ?>

plugin->options['enable_fim'])) { echo '

' . esc_html__('Enable the File Integrity Monitor to manage baseline hashes.', 'advanced-ip-blocker') . '

'; return; } $nonce = wp_create_nonce('advaipbl_reset_fim_baseline_nonce'); ?>

plugin->options['geolocation_method'] ?? 'api'; ?>

plugin->geoip_manager instanceof ADVAIPBL_GeoIP_Manager) { echo '

' . esc_html__('This status is only available when the "Local Database" method is selected and active.', 'advanced-ip-blocker') . '

'; return; } $status = $this->plugin->geoip_manager->get_database_status(); ?>

: ()

: ()

: ()

plugin->options['tfa_force_roles'] ?? []; $editable_roles = get_editable_roles(); ?>
$role_details) : ?>

plugin->options['recaptcha_enable'] ?? '0'; ?> >

get_help_link_html($args); ?>

plugin->options['recaptcha_version'] ?? 'v3'; ?> plugin->options['recaptcha_site_key'] ?? ''; ?> plugin->options['recaptcha_secret_key'] ?? ''; ?> plugin->options['recaptcha_score_threshold'] ?? '0.5'; ?>

0) { $message = sprintf( /* translators: %s is a placeholder */ _n( '%d invalid regular expression was found and has been discarded.', '%d invalid regular expressions were found and have been discarded.', $invalid_rules, 'advanced-ip-blocker' ), $invalid_rules ); add_settings_error('advaipbl_waf_rules', 'invalid_regex', $message, 'warning'); } return implode("\n", $unique_lines); } /** * Generic callback for action selectors (Block vs Challenge). * Accepts the field name dynamically. */ public function action_select_callback($args) { $name = $args['name']; $current_action = $this->plugin->options[$name] ?? 'block'; printf(''; if (! empty($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); } /** * Displays the selection field for the AbuseIPDB action. */ public function abuseipdb_action_callback() { $options = $this->plugin->options; $current_action = $options['abuseipdb_action'] ?? 'block'; ?>

plugin->options[$name] ?? 'default'; if ($current_mode === 'managed' || $current_mode === 'automatic') { $current_mode = 'default'; } printf(''; if (! empty($args['description'])) { echo '

' . wp_kses_post($args['description']) . '

'; } } /** * Helper to generate the help icon if a URL exists. * * @param array $args Field arguments. * @return string Help link HTML or empty string. */ private function get_help_link_html($args) { if (empty($args['help_url'])) { return ''; } return sprintf( ' ', esc_url($args['help_url']), esc_attr__('Read Documentation', 'advanced-ip-blocker') ); } /** * Callback for visual separator. */ public function separator_callback() { echo '
'; } public function geoblock_separator_callback() { echo '
'; echo '

' . esc_html__('Geoblocking Protections', 'advanced-ip-blocker') . '

'; } public function geochallenge_separator_callback() { echo '
'; echo '

' . esc_html__('Geo-Challenge', 'advanced-ip-blocker') . '

'; } public function display_captcha_keys_warning() { static $displayed = false; if ($displayed) { return; } $options = $this->plugin->options; $global_engine = $options['default_challenge_engine'] ?? 'js_automatic'; $engines_in_use = []; if ($global_engine === 'turnstile' || $global_engine === 'hcaptcha') { $engines_in_use[] = $global_engine; } $granular_modes = [ 'lockdown_404_challenge_mode', 'lockdown_403_challenge_mode', 'login_lockdown_challenge_mode', 'xmlrpc_lockdown_challenge_mode', 'under_attack_challenge_mode', 'geo_challenge_mode', 'signature_challenge_mode', 'abuseipdb_challenge_mode', 'aib_network_challenge_mode' ]; foreach ($granular_modes as $mode_key) { $mode = $options[$mode_key] ?? 'default'; if ($mode === 'default' || $mode === 'managed' || $mode === 'automatic') { $mode = $global_engine; } if ($mode === 'turnstile' || $mode === 'hcaptcha') { if (!in_array($mode, $engines_in_use)) { $engines_in_use[] = $mode; } } } $advanced_rules = get_option('advaipbl_advanced_rules', []); if (is_array($advanced_rules)) { foreach ($advanced_rules as $rule) { if (isset($rule['action'])) { if ($rule['action'] === 'challenge_turnstile' && !in_array('turnstile', $engines_in_use)) { $engines_in_use[] = 'turnstile'; } elseif ($rule['action'] === 'challenge_hcaptcha' && !in_array('hcaptcha', $engines_in_use)) { $engines_in_use[] = 'hcaptcha'; } } } } $missing_keys_engines = []; foreach ($engines_in_use as $engine) { $site_key = $options[$engine . '_site_key'] ?? ''; $secret_key = $options[$engine . '_secret_key'] ?? ''; if (empty($site_key) || empty($secret_key)) { $missing_keys_engines[] = ucfirst($engine); } } if (!empty($missing_keys_engines)) { $displayed = true; $engines_str = implode(' and ', array_unique($missing_keys_engines)); $settings_url = admin_url('admin.php?page=advaipbl_settings_page#sub-section-captcha'); echo '
'; echo '

' . esc_html__('Advanced IP Blocker Warning:', 'advanced-ip-blocker') . ' '; echo sprintf( /* translators: %s is a placeholder */ esc_html__('You have selected %1$s as a challenge method but the API keys are missing. The system will automatically fall back to the JS Challenge to prevent locking out legitimate users. Please %2$sconfigure your keys%3$s.', 'advanced-ip-blocker'), esc_html($engines_str), '', '' ); echo '

'; echo '
'; } } }