esc_html__( 'reCAPTCHA verification failed. Please try again.', 'defender-security' ), 'turnstile_message' => esc_html__( 'Turnstile verification failed. Please try again.', 'defender-security' ), ); } /** * Load default values. * * @return void */ protected function before_load(): void { $default_values = $this->get_default_values(); $this->provider = 'recaptcha'; $this->message = $default_values['message']; $this->language = 'automatic'; $this->data_v2_checkbox = array( 'key' => '', 'secret' => '', 'verified' => false, 'size' => 'normal', 'style' => 'light', ); $this->data_v2_invisible = array( 'key' => '', 'secret' => '', 'verified' => false, ); $this->data_v3_recaptcha = array( 'key' => '', 'secret' => '', 'verified' => false, 'threshold' => '0.5', ); $this->data_turnstile = array( 'key' => '', 'secret' => '', 'verified' => false, 'size' => 'normal', 'style' => 'auto', 'message' => $default_values['turnstile_message'], 'language' => 'auto', ); } /** * Backfill new keys (e.g. 'verified') into data arrays loaded from settings saved by an older version. * * @return void */ protected function after_load(): void { $this->data_v2_checkbox = wp_parse_args( $this->data_v2_checkbox, array( 'verified' => false ) ); $this->data_v2_invisible = wp_parse_args( $this->data_v2_invisible, array( 'verified' => false ) ); $this->data_v3_recaptcha = wp_parse_args( $this->data_v3_recaptcha, array( 'verified' => false ) ); $this->data_turnstile = wp_parse_args( $this->data_turnstile, array( 'verified' => false ) ); } /** * Checks if the given Captcha type is valid and has all the necessary data. * * @param string $active_type The Captcha type to check. * * @return bool Returns true if the Captcha type is valid and has all the necessary data, false otherwise. */ private function check_captcha_type( string $active_type ): bool { if ( 'v2_checkbox' === $active_type && '' !== $this->data_v2_checkbox['key'] && '' !== $this->data_v2_checkbox['secret'] ) { return true; } elseif ( 'v2_invisible' === $active_type && '' !== $this->data_v2_invisible['key'] && '' !== $this->data_v2_invisible['secret'] ) { return true; } elseif ( 'v3_recaptcha' === $active_type && '' !== $this->data_v3_recaptcha['key'] && '' !== $this->data_v3_recaptcha['secret'] ) { return true; } elseif ( self::TURNSTILE === $active_type && '' !== $this->data_turnstile['key'] && '' !== $this->data_turnstile['secret'] ) { return true; } else { return false; } } /** * Checks if the CAPTCHA is active. * * @return bool Returns true if the CAPTCHA is active, false otherwise. */ public function is_active(): bool { $hook_name = self::TURNSTILE === $this->active_type ? 'wd_turnstile_enable' : 'wd_recaptcha_enable'; $enable = apply_filters( $hook_name, $this->enabled && '' !== $this->active_type && '' !== $this->language // For each Captcha type. && $this->check_captcha_type( $this->active_type ) ); return is_bool( $enable ) ? $enable : (bool) $enable; } /** * Is activated any default location? * * @return bool */ public function enable_default_location(): bool { return array() !== $this->locations; } /** * Level#2 check by any activated location. Only if the plugin is enabled. * * @return bool */ public function enable_woo_location(): bool { return $this->detect_woo && array() !== $this->woo_checked_locations; } /** * Level#2 check by deactivated locations. Only if the plugin is enabled. * * @return bool */ public function is_unchecked_woo_locations(): bool { return $this->detect_woo && array() === $this->woo_checked_locations; } /** * Level#1 check. If the plugin is disabled, there is no point further. * * @param bool $is_woo_activated Whether WooCommerce is activated or not. * * @return bool */ public function check_woo_locations( $is_woo_activated ): bool { if ( ! $is_woo_activated ) { return false; } return $this->enable_woo_location(); } /** * Level#2 check by any activated location. Only if the plugin is enabled. * * @return bool */ public function enable_buddypress_location(): bool { return $this->detect_buddypress && array() !== $this->buddypress_checked_locations; } /** * Level#2 check by deactivated locations. Only if the plugin is enabled. * * @return bool */ public function is_unchecked_buddypress_locations(): bool { return $this->detect_buddypress && array() === $this->buddypress_checked_locations; } /** * Level#1 Checks if the BuddyPress locations are valid and have all the necessary data. * * @param bool $is_buddypress_activated Whether BuddyPress is activated or not. * * @return bool Returns true if the BuddyPress locations are valid and have all the necessary data, false otherwise. */ public function check_buddypress_locations( $is_buddypress_activated ): bool { if ( ! $is_buddypress_activated ) { return false; } return $this->enable_buddypress_location(); } /** * Define settings labels. * * @return array */ public function labels(): array { return array( 'enabled' => self::get_module_name(), 'active_type' => esc_html__( 'Configure CAPTCHA', 'defender-security' ), 'v2_checkbox' => esc_html__( 'V2 Checkbox', 'defender-security' ), 'v2_invisible' => esc_html__( 'V2 Invisible', 'defender-security' ), 'v3_recaptcha' => esc_html__( 'reCAPTCHA V3', 'defender-security' ), 'language' => esc_html__( 'Language', 'defender-security' ), 'message' => esc_html__( 'Error Message', 'defender-security' ), 'locations' => esc_html__( 'CAPTCHA Locations', 'defender-security' ), 'detect_woo' => esc_html__( 'WooCommerce', 'defender-security' ), 'detect_buddypress' => esc_html__( 'BuddyPress', 'defender-security' ), 'disable_for_known_users' => esc_html__( 'Disable for logged in users', 'defender-security' ), ); } /** * Disable for logged in users or enable. * * @return bool */ public function display_for_known_users(): bool { return ! ( $this->disable_for_known_users && is_user_logged_in() ); } /** * Get module name. * * @return string */ public static function get_module_name(): string { return esc_html__( 'CAPTCHA', 'defender-security' ); } /** * Get active captcha data based on provider and active type. * * @param string|null $provider The provider name. * @param string|null $active_type The active type. * * @return array The captcha data for the specified provider. */ public function get_active_captcha_data( ?string $provider = null, ?string $active_type = null ): array { $provider = $provider ?? $this->provider; $active_type = $active_type ?? $this->active_type; if ( self::TURNSTILE === $provider ) { return $this->data_turnstile; } return match ( $active_type ) { 'v2_checkbox' => $this->data_v2_checkbox, 'v2_invisible' => $this->data_v2_invisible, 'v3_recaptcha' => $this->data_v3_recaptcha, default => array(), }; } }