setup_feature_list(); $this->initialize_features(); } /** * This function sets up the feature list * * @return void */ private function setup_feature_list() { $feature_list = array( // Settings menu features 'wp-generator-meta-tag' => array( 'name' => __('Remove WP generator meta tag', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_remove_wp_generator_meta_info' ) ), // User Accounts menu features 'user-accounts-change-admin-user' => array( 'name' => __('Change admin username', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_basic, 'options' => array( '' ), 'callback' => array($this, 'check_user_accounts_change_admin_user_feature') ), 'user-accounts-display-name' => array( 'name' => __('Change display name', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( '' ), 'callback' => array($this, 'check_user_accounts_display_name_feature') ), // User Login menu features 'user-login-login-lockdown' => array( 'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_login_lockdown' ) ), 'user-login-force-logout' => array( 'name' => __('Force logout', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_forced_logout' ) ), 'hibp' => array( 'name' => __('HIBP', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_hibp_user_profile_update', 'aiowps_http_password_reset', ) ), 'disable-application-password' => array( 'name' => __('Disable application password', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_disable_application_password' ) ), 'user-login-lockout-ip-whitelisting' => array( 'name' => __('Login Lockout IP whitelisting', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_lockdown_enable_whitelisting' ) ), // User Registration menu features 'manually-approve-registrations' => array( 'name' => __('Registration approval', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_manual_registration_approval' ) ), 'user-registration-captcha' => array( 'name' => __('Registration CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_registration_page_captcha' ) ), 'registration-honeypot' => array( 'name' => __('Enable registration honeypot', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_registration_honeypot' ) ), 'http-authentication-admin-frontend' => array( 'name' => __('HTTP authentication for admin and frontend', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_http_authentication_admin', 'aiowps_http_authentication_frontend', ) ), // Database Security menu features 'db-security-db-prefix' => array( 'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( '' ), 'callback' => array($this, 'check_db_security_db_prefix_feature') ), // Filesystem Security menu features 'filesystem-file-permissions' => array( 'name' => __('File permissions', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( '' ), 'callback' => array($this, 'check_filesystem_permissions_feature') ), 'filesystem-file-editing' => array( 'name' => __('File editing', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_disable_file_editing' ) ), 'auto-delete-wp-files' => array( 'name' => __('WordPress files access', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_auto_delete_default_wp_files' ) ), // Blacklist Manager menu features 'blacklist-manager-ip-user-agent-blacklisting' => array( 'name' => __('IP and user agent blacklisting', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_enable_blacklisting' ) ), // Firewall menu features 'firewall-basic-rules' => array( 'name' => __('Enable basic firewall', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_basic_firewall' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') ), 'firewall-pingback-rules' => array( 'name' => __('Enable pingback vulnerability protection', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_pingback_firewall' ) ), 'firewall-block-debug-file-access' => array( 'name' => __('Block access to debug log file', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_block_debug_log_file_access' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') ), 'firewall-disable-index-views' => array( 'name' => __('Disable index views', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_disable_index_views' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') ), 'firewall-disable-trace-track' => array( 'name' => __('Disable trace and track', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_disable_trace_and_track' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') ), 'firewall-forbid-proxy-comments' => array( 'name' => __('Forbid proxy comments', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_forbid_proxy_comments' ) ), 'firewall-deny-bad-queries' => array( 'name' => __('Deny bad queries', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_deny_bad_query_strings' ) ), 'firewall-advanced-character-string-filter' => array( 'name' => __('Advanced character string filter', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_advanced_char_string_filter' ) ), 'firewall-enable-6g' => array( 'name' => __('6G firewall', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_enable_6g_firewall', ) ), 'firewall-block-fake-googlebots' => array( 'name' => __('Block fake Googlebots', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_block_fake_googlebots' ) ), 'prevent-hotlinking' => array( 'name' => __('Prevent image hotlinking', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_prevent_hotlinking' ) ), 'firewall-enable-404-blocking' => array( 'name' => __('Enable IP blocking for 404 detection', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_404_IP_lockout' ) ), 'firewall-disable-rss-and-atom' => array( 'name' => __('Disable RSS and ATOM feeds', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_disable_rss_and_atom_feeds' ) ), 'upgrade-unsafe-http-calls' => array( 'name' => __('Upgrade unsafe HTTP calls', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_upgrade_unsafe_http_calls' ) ), // Brute Force menu features 'bf-rename-login-page' => array( 'name' => __('Enable rename login page', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_rename_login_page' ) ), 'firewall-enable-brute-force-attack-prevention' => array( 'name' => __('Enable brute force attack prevention', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_enable_brute_force_attack_prevention' ) ), 'user-login-captcha' => array( 'name' => __('Login CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_login_captcha' ) ), 'lost-password-captcha' => array( 'name' => __('Lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_lost_password_captcha' ) ), 'custom-login-captcha' => array( 'name' => __('Custom login CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_custom_login_captcha' ) ), 'password_protected-captcha' => array( 'name' => __('Password-protected CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_password_protected_captcha' ) ), 'whitelist-manager-ip-login-whitelisting' => array( 'name' => __('Login IP whitelisting', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_whitelisting' ) ), 'login-honeypot' => array( 'name' => __('Enable login honeypot', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_login_honeypot' ) ), // Spam Prevention menu features 'comment-form-captcha' => array( 'name' => __('Comment CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_comment_captcha' ) ), 'detect-spambots' => array( 'name' => __('Detect spambots', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_spambot_detecting' ) ), 'auto-block-spam-ips' => array( 'name' => __('Auto block spam ips', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_autoblock_spam_ip' ) ), // Scanner menu features 'scan-file-change-detection' => array( 'name' => __('File change detection', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_4, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_enable_automated_fcd_scan' ) ), // Miscellaneous menu features 'enable-copy-protection' => array( 'name' => __('Enable Copy Protection', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_copy_protection' ) ), 'enable-frame-protection' => array( 'name' => __('Enable iFrame protection', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_prevent_site_display_inside_frame' ) ), 'disable-users-enumeration' => array( 'name' => __('Disable users enumeration', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_prevent_users_enumeration' ) ), 'disallow-unauthorised-requests' => array( 'name' => __('Disallow unauthorized REST requests', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_disallow_unauthorized_rest_requests' ) ), 'enable-salt-postfix' => array( 'name' => __('Enable salt postfix', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_3, 'level' => $this->sec_level_advanced, 'options' => array( 'aiowps_enable_salt_postfix' ) ), // conditional features 'bp-register-captcha' => array( 'name' => __('BuddyPress registration CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_bp_register_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_buddypress_plugin_active'), ), 'bbp-new-topic-captcha' => array( 'name' => __('bbPress new topic CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_bbp_new_topic_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_bbpress_plugin_active'), ), 'woo-login-captcha' => array( 'name' => __('Woo login CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_woo_login_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'), ), 'woo-lostpassword-captcha' => array( 'name' => __('Woo lost password CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_woo_lostpassword_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'), ), 'woo-register-captcha' => array( 'name' => __('Woo register CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_woo_register_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'), ), 'woo-checkout-captcha' => array( 'name' => __('Woo Checkout CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_woo_checkout_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_woocommerce_plugin_active'), ), // Ban POST requests with blank user-agent and referer 'firewall-ban-post-blank-headers' => array( 'name' => __('Ban POST requests that have blank user-agent and referer headers', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_2, 'level' => $this->sec_level_inter, 'options' => array( 'aiowps_ban_post_blank_headers' ) ), 'contact-form-7-captcha' => array( /* translators: %s: Plugin name */ 'name' => sprintf(__('%s CAPTCHA', 'all-in-one-wp-security-and-firewall'), 'Contact Form 7'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enable_contact_form_7_captcha' ), 'feature_condition_callback' => array('AIOWPSecurity_Utility', 'is_contact_form_7_plugin_active'), ), 'enforce-strong-password' => array( 'name' => __('Enforce use of strong passwords by users', 'all-in-one-wp-security-and-firewall'), 'points' => $this->feature_point_1, 'level' => $this->sec_level_basic, 'options' => array( 'aiowps_enforce_strong_password' ), ) ); $feature_list = apply_filters('aiowpsecurity_feature_list', $feature_list); $this->feature_list = array_filter($feature_list, array($this, 'should_add_item')); } /** * This function will create a feature item object for each feature in the feature list * * @return void */ private function initialize_features() { foreach ($this->feature_list as $id => $data) { $callback = isset($data['callback']) ? $data['callback'] : array($this, 'is_feature_enabled'); $this->feature_items[$id] = new AIOWPSecurity_Feature_Item($id, $data['name'], $data['points'], $data['level'], $data['options'], $callback); } } /** * This function will return the feature item for the passed in ID * * @param string $feature_id - the id of the feature item we want to return * * @return boolean|AIOWPSecurity_Feature_Item - returns a feature item or false on coding error */ public function get_feature_item_by_id($feature_id) { if (isset($this->feature_items[$feature_id])) return $this->feature_items[$feature_id]; error_log("AIOS Feature Manager - Feature ID not found (coding error): $feature_id"); return false; } /** * Call the callback function associated with the feature item. * * @param mixed $feature_item The feature item object. */ private function call_feature_callback($feature_item) { call_user_func($feature_item->callback, $feature_item); } /** * This function will output the feature details badge HTML * * @param string $feature_id - the id of the feature we want to get the badge for * @param bool $return_instead_of_echo - whether to return the HTML or echo it * * @return string|void */ public function output_feature_details_badge($feature_id, $return_instead_of_echo = false) { // Retrieve the feature item by ID $feature_item = $this->get_feature_item_by_id($feature_id); if (!$feature_item) return; $this->call_feature_callback($feature_item); // Prepare HTML for the feature badge $max_security_points = $feature_item->item_points; $current_security_points = $feature_item->is_active() ? $max_security_points : 0; $security_level = $feature_item->get_security_level_string(); $protection_level = (0 == $current_security_points) ? 'none' : 'full'; $status_icon = (0 == $current_security_points) ? 'dashicons-unlock' : 'dashicons-lock'; $badge_html = '
'; $badge_html .= ''; $badge_html .= ''.$security_level.''; $badge_html .= ''; $badge_html .= $current_security_points.'/'.$max_security_points.''; $badge_html .= '
'; if ($return_instead_of_echo) { return $badge_html; } else { echo $badge_html; } } /** * This function will calculate the total points for the AJAX save function * * @return void */ public function calculate_total_feature_points() { $this->calculate_total_points(); } /** * This function will setup the feature status and calculate the total points * * @return void */ public function check_feature_status_and_recalculate_points() { $this->check_and_set_feature_status(); $this->calculate_total_points(); } /** * This function will calculate the total points for the site * * @return void */ private function calculate_total_points() { foreach ($this->feature_items as $item) { if ($item->is_active()) $this->total_points = $this->total_points + intval($item->item_points); } } /** * This function will calculate the total achievable points * * @return void */ private function calculate_total_achievable_points() { foreach ($this->feature_items as $item) { $this->total_achievable_points = $this->total_achievable_points + intval($item->item_points); } } /** * This function will return the total points for the site * * @return int - the total points for the site */ public function get_total_site_points() { if (empty($this->total_points)) $this->calculate_total_points(); return $this->total_points; } /** * This function will return the total achievable points * * @return int - the total achievable points */ public function get_total_achievable_points() { if (empty($this->total_achievable_points)) $this->calculate_total_achievable_points(); return $this->total_achievable_points; } /** * This function will loop over each feature item, checking if it's enabled and setting it's feature status * * @return void */ private function check_and_set_feature_status() { foreach ($this->feature_items as $item) { call_user_func($item->callback, $item); } } /** * This function will check if the feature database value is active and set the feature status * * @param AIOWPSecurity_Feature_Item $item - the item we want to check is active * * @return void */ private function is_feature_enabled($item) { global $aio_wp_security; $aiowps_firewall_config = AIOS_Firewall_Resource::request(AIOS_Firewall_Resource::CONFIG); $enabled = false; foreach ($item->feature_options as $option) { if ('1' == $aiowps_firewall_config->get_value($option) || '1' == $aio_wp_security->configs->get_value($option)) $enabled = true; } if ($enabled) { $item->set_feature_status($this->feature_active); } else { $item->set_feature_status($this->feature_inactive); } } /** * This function will check if the default admin user exists and set the feature status * * @param AIOWPSecurity_Feature_Item $item - the item we want to check is active * * @return void */ private function check_user_accounts_change_admin_user_feature($item) { if (AIOWPSecurity_Utility::check_user_exists('admin')) { $item->set_feature_status($this->feature_inactive); } else { $item->set_feature_status($this->feature_active); } } /** * This function will check if the username and nicknames are identical and set the feature status * * @param AIOWPSecurity_Feature_Item $item - the item we want to check is active * * @return void */ private function check_user_accounts_display_name_feature($item) { if (AIOWPSecurity_Utility::check_identical_login_and_nick_names()) { $item->set_feature_status($this->feature_inactive); } else { $item->set_feature_status($this->feature_active); } } /** * This function will check if the default database prefix is in use and set the feature status * * @param AIOWPSecurity_Feature_Item $item - the item we want to check is active * * @return void */ private function check_db_security_db_prefix_feature($item) { global $wpdb; $site_id = get_current_blog_id(); $default_prefix = (1 === $site_id) ? 'wp_' : "wp_{$site_id}_"; if ($default_prefix === $wpdb->prefix) { $item->set_feature_status($this->feature_inactive); } else { $item->set_feature_status($this->feature_active); } } /** * This function will check the filesystem permissions and set the feature status * * @param AIOWPSecurity_Feature_Item $item - the item we want to check is active * * @return void */ private function check_filesystem_permissions_feature($item) { //TODO $is_secure = 1; $files_dirs_to_check = AIOWPSecurity_Utility_File::get_files_and_dirs_to_check(); foreach ($files_dirs_to_check as $file_or_dir) { $actual_perm = AIOWPSecurity_Utility_File::get_file_permission($file_or_dir['path']); $is_secure = $is_secure*AIOWPSecurity_Utility_File::is_file_permission_secure($file_or_dir['permissions'], $actual_perm); } //Only if all of the files' permissions are deemed secure give this a thumbs up if (1 == $is_secure) { $item->set_feature_status($this->feature_active); } else { $item->set_feature_status($this->feature_inactive); } } /** * This function will check if an item should be added to the feature list * * @param array $item - the item we want to check if it should be added * @return bool */ public static function should_add_item($item) { if (empty($item['feature_condition_callback'])) { return true; } elseif (is_callable($item['feature_condition_callback'])) { return call_user_func($item['feature_condition_callback']); } else { error_log("Callback function set but not callable (coding error). Feature: " . $item['name']); return false; } } /** * Get the critical features. * * @return array */ public static function get_critical_features() { $critical_features = array( 'user-accounts-change-admin-user' => array( 'name' => __('Admin username', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG, ), 'user-login-login-lockdown' => array( 'name' => __('Login lockout', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_USER_SECURITY_MENU_SLUG . '&tab=login-lockout', ), 'filesystem-file-permissions' => array( 'name' => __('File permission', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG, 'feature_callback' => 'is_main_site' ), 'firewall-basic-rules' => array( 'name' => __('Basic firewall', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_FIREWALL_MENU_SLUG . '&tab=htaccess-rules', 'feature_callback' => array('AIOWPSecurity_Utility', 'allow_to_write_to_htaccess') ), 'db-security-db-prefix' => array( 'name' => __('Database prefix', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_DB_SEC_MENU_SLUG, 'feature_callback' => 'is_main_site' ), 'filesystem-file-editing' => array( 'name' => __('PHP file editing', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_FILESYSTEM_MENU_SLUG . '&tab=file-protection', 'feature_callback' => array('AIOWPSecurity_Utility_Permissions', 'is_main_site_and_super_admin') ), 'bf-rename-login-page' => array( 'name' => __('Renamed login page', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_BRUTE_FORCE_MENU_SLUG, ), 'wp-generator-meta-tag' => array( 'name' => __('Hidden WP meta info', 'all-in-one-wp-security-and-firewall'), 'url' => AIOWPSEC_SETTINGS_MENU_SLUG . '&tab=wp-version-info', ), ); $critical_features = apply_filters('aiowps_filter_critical_features_array', $critical_features); $critical_features = array_filter($critical_features, array(self::class, 'should_add_feature')); return $critical_features; } /** * Determines whether a security feature should be activated based on its callback. * * This method checks if a feature should be added by evaluating its callback function. * If no callback is set, the feature is added by default. If a callback is set, * it must be callable and return a boolean value. * * @param array $feature An array containing feature details with the following keys: * 'name' => (string) Name of the feature * 'feature_callback' => (callable|null) Optional callback to determine if feature should be added * * @return bool True if the feature should be added, false otherwise */ public static function should_add_feature($feature) { if (empty($feature['feature_callback'])) { return true; } elseif (is_callable($feature['feature_callback'])) { return call_user_func($feature['feature_callback']); } else { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Part of internal error reporting system. error_log("Callback function set but not callable (coding error). Feature: " . $feature['name']); return false; } } }