sprintf('%s', self::SGR_PAGE_OPTIONS_QUERY, __('Settings', self::SGR_TEXT_DOMAIN))], $links); } public function activation($plugin) { if ($plugin === plugin_basename(__FILE__) && (!get_option(self::SGR_OPTION_SITE_KEY) || !get_option(self::SGR_OPTION_SECRET_KEY))) { exit(wp_redirect(admin_url(sprintf('options-general.php%s', self::SGR_PAGE_OPTIONS_QUERY)))); } } public function options_page() { echo sprintf('

%s - %s

', $this->pluginName, __('Settings', self::SGR_TEXT_DOMAIN), self::SGR_PAGE_OPTIONS_QUERY); settings_fields('sgr_header_section'); do_settings_sections('sgr_options'); submit_button(); echo sprintf('%s
%s
', self::SGR_ACTION, self::UPDATE, PHP_EOL, $this->messageProtectionStatus()); } public function menu() { $this->enqueue_main(); add_submenu_page('options-general.php', $this->pluginName, 'Google reCAPTCHA', 'manage_options', 'sgr_options', [$this, 'options_page']); add_action('admin_init', [$this, 'display_options']); } public function display_sgr_site_key() { echo sprintf('', self::SGR_OPTION_SITE_KEY, $this->siteKey); } public function display_sgr_secret_key() { echo sprintf('', self::SGR_OPTION_SECRET_KEY, $this->secretKey); } public function display_sgr_login_disable() { echo sprintf('', self::SGR_OPTION_LOGIN_DISABLE, checked(1, $this->loginDisable, false)); } public function display_sgr_version() { echo sprintf('', self::SGR_OPTION_VERSION, checked(3, $this->version, false)); } public function display_sgr_badge_hide() { echo sprintf('', self::SGR_OPTION_BADGE_HIDE, checked(1, $this->badgeHide, false)); } public function display_options() { $fields = [ ['id' => self::SGR_OPTION_SITE_KEY, 'label' => __('Site Key', self::SGR_TEXT_DOMAIN)], ['id' => self::SGR_OPTION_SECRET_KEY, 'label' => __('Secret Key', self::SGR_TEXT_DOMAIN)], ['id' => self::SGR_OPTION_LOGIN_DISABLE, 'label' => __('Disable on login form', self::SGR_TEXT_DOMAIN)], ['id' => self::SGR_OPTION_VERSION, 'label' => __('Enable reCAPTCHA v3', self::SGR_TEXT_DOMAIN)], ['id' => self::SGR_OPTION_BADGE_HIDE, 'label' => __('Hide reCAPTCHA v3 badge', self::SGR_TEXT_DOMAIN)], ]; add_settings_section('sgr_header_section', __('Google reCAPTCHA keys', self::SGR_TEXT_DOMAIN), [], 'sgr_options'); foreach ($fields as $field) { add_settings_field($field['id'], $field['label'], [$this, sprintf('display_%s', $field['id'])], 'sgr_options', 'sgr_header_section'); register_setting('sgr_header_section', $field['id']); } } public function enqueue_main() { $jsName = 'sgr.js'; $jsPath = plugin_dir_path(__FILE__) . $jsName; wp_enqueue_script(self::SGR_MAIN, plugin_dir_url(__FILE__) . $jsName, [], filemtime($jsPath)); wp_localize_script(self::SGR_MAIN, self::SGR_MAIN, [self::SGR_OPTION_SITE_KEY => $this->siteKey]); $cssName = 'sgr.css'; $cssPath = plugin_dir_path(__FILE__) . $cssName; wp_enqueue_style(self::SGR_MAIN, plugin_dir_url(__FILE__) . $cssName, [], filemtime($cssPath)); } public function enqueue_scripts() { $apiUrlBase = sprintf('https://www.recaptcha.net/recaptcha/api.js?hl=%s', get_locale()); $jsUrl = sprintf('%s&onload=sgr_2&render=explicit', $apiUrlBase); if ($this->version === 3) { $jsUrl = sprintf('%s&render=%s&onload=sgr_3', $apiUrlBase, $this->siteKey); } wp_enqueue_script('sgr_recaptcha', $jsUrl, [], time()); } public function frontend() { $this->enqueue_main(); $sgr_display_list = [ 'comment_form_after_fields', 'register_form', 'lostpassword_form', 'woocommerce_register_form', 'woocommerce_lostpassword_form', 'bp_after_signup_profile_fields', ]; $sgr_verify_list = [ 'preprocess_comment', 'registration_errors', 'lostpassword_post', 'woocommerce_register_post', 'bp_signup_validate' ]; if (!$this->loginDisable) { array_push($sgr_display_list, 'login_form', 'woocommerce_login_form'); array_push($sgr_verify_list, 'wp_authenticate_user'); } $sgrDisplay = $this->version === 3 ? 'v3_display' : 'v2_display'; foreach ($sgr_display_list as $sgr_display) { add_action($sgr_display, [$this, 'enqueue_scripts']); add_action($sgr_display, [$this, $sgrDisplay]); } foreach ($sgr_verify_list as $sgr_verify) { add_action($sgr_verify, [$this, 'verify']); } } public function v2_display() { $this->displayDisableProtection(); echo '
'; } public function v3_display() { $badgeText = null; if ($this->badgeHide) { $cssName = 'sgr_hide.css'; $cssPath = plugin_dir_path(__FILE__) . $cssName; $cssVersion = filemtime($cssPath); wp_enqueue_style('sgr_hide', plugin_dir_url(__FILE__) . $cssName, [], $cssVersion); $badgeText = sprintf('%s

%s

', PHP_EOL, __('This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.', self::SGR_TEXT_DOMAIN)); } $this->displayDisableProtection(); echo sprintf('%s', $badgeText); } private function displayDisableProtection() { if ($this->adminCookieHash()) { echo sprintf('

%s

', self::SGR_ACTION, self::DISABLE, __('Emergency reCAPTCHA deactivate', self::SGR_TEXT_DOMAIN)); } } private function disableProtection() { if ($this->adminCookieHash()) { delete_option(self::SGR_OPTION_SITE_KEY); delete_option(self::SGR_OPTION_SECRET_KEY); $this->siteKey = $this->secretKey = null; } } /** * @param $error_code * @return string|void|null */ private function errorMessage($error_code) { $error_message = null; switch ($error_code) { case 'missing-input-secret': $error_message = __('The secret parameter is missing.', self::SGR_TEXT_DOMAIN); break; case 'missing-input-response': $error_message = __('The response parameter is missing.', self::SGR_TEXT_DOMAIN); break; case 'invalid-input-secret': $error_message = __('The secret parameter is invalid or malformed.', self::SGR_TEXT_DOMAIN); break; case 'invalid-input-response': $error_message = __('The response parameter is invalid or malformed.', self::SGR_TEXT_DOMAIN); break; case 'bad-request': $error_message = __('The request is invalid or malformed.', self::SGR_TEXT_DOMAIN); break; case 'timeout-or-duplicate': $error_message = __('The response is no longer valid: either is too old or has been used previously.', self::SGR_TEXT_DOMAIN); break; } return $error_message; } private function recaptchaResponse() { $recaptchaResponse = filter_input(INPUT_POST, 'g-recaptcha-response', FILTER_SANITIZE_FULL_SPECIAL_CHARS); $response = (array)wp_remote_get(sprintf('https://www.recaptcha.net/recaptcha/api/siteverify?secret=%s&response=%s', $this->secretKey, $recaptchaResponse)); $this->recaptchaResponse = isset($response['body']) ? json_decode($response['body'], 1) : ['success' => false, 'error-codes' => ['general-fail']]; } /** * @param $input * @return mixed */ public function verify($input) { $this->recaptchaResponse(); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['g-recaptcha-response'])) { $recaptcha_error_code = isset($this->recaptchaResponse['error-codes'][0]) ? $this->recaptchaResponse['error-codes'][0] : null; $error_message = $this->errorMessage($recaptcha_error_code); if ((int)$this->recaptchaResponse['success'] === 1) { return $input; } else { wp_die(sprintf('

%s Google reCAPTCHA %s. %s

', __('Error:', self::SGR_TEXT_DOMAIN), __('verification failed', self::SGR_TEXT_DOMAIN), $error_message), 'reCAPTCHA', ['response' => 403, 'back_link' => 1]); } } else { wp_die(sprintf('

%s Google reCAPTCHA %s. %s

', __('Error:', self::SGR_TEXT_DOMAIN), __('verification failed', self::SGR_TEXT_DOMAIN), __('Do you have JavaScript enabled?', self::SGR_TEXT_DOMAIN)), 'reCAPTCHA', ['response' => 403, 'back_link' => 1]); } } /** * @return string */ public function messageProtectionStatus() { $type = $this->version === 3 ? self::SGR_V3 : self::SGR_V2; if (!$this->siteKey || !$this->secretKey) { return sprintf('

%s Google reCAPTCHA %s!

%s

', __('Warning:', self::SGR_TEXT_DOMAIN), __('is disabled', self::SGR_TEXT_DOMAIN), sprintf(__('You have to register your domain, get required Google reCAPTCHA keys %s and save them bellow.', self::SGR_TEXT_DOMAIN), $type)); } else { return sprintf('

%s Google reCAPTCHA %s!

%s

', __('Notice:', self::SGR_TEXT_DOMAIN), __('is enabled', self::SGR_TEXT_DOMAIN), __('Keep on mind, that in case of emergency, you can disable this plugin via FTP access, just rename the plugin folder.', self::SGR_TEXT_DOMAIN)); } } /** * @return bool */ public function adminCookieHash() { $cookieHash = filter_input(INPUT_COOKIE, self::SGR_OPTION_HASH, FILTER_SANITIZE_SPECIAL_CHARS); if ($cookieHash === md5($this->siteKey . $this->secretKey)) { return true; } else { return false; } } public function run() { $this->pluginName = get_file_data(__FILE__, ['Name' => 'Plugin Name'])['Name']; $postAction = filter_input(INPUT_POST, self::SGR_ACTION, FILTER_SANITIZE_SPECIAL_CHARS); if ($postAction === self::UPDATE) { $this->updateSettings(); } $this->siteKey = filter_var(get_option(self::SGR_OPTION_SITE_KEY), FILTER_SANITIZE_FULL_SPECIAL_CHARS); $this->secretKey = filter_var(get_option(self::SGR_OPTION_SECRET_KEY), FILTER_SANITIZE_FULL_SPECIAL_CHARS); $this->version = (int)filter_var(get_option(self::SGR_OPTION_VERSION), FILTER_SANITIZE_NUMBER_INT); $this->loginDisable = (int)filter_var(get_option(self::SGR_OPTION_LOGIN_DISABLE), FILTER_SANITIZE_NUMBER_INT); $this->badgeHide = (int)filter_var(get_option(self::SGR_OPTION_BADGE_HIDE), FILTER_SANITIZE_NUMBER_INT); $getAction = filter_input(INPUT_GET, self::SGR_ACTION, FILTER_SANITIZE_SPECIAL_CHARS); if ($getAction === self::DISABLE) { $this->disableProtection(); } add_filter(sprintf('plugin_action_links_%s', plugin_basename(__FILE__)), [$this, 'action_links']); add_action('admin_menu', [$this, 'menu']); if (!is_user_logged_in() && !wp_doing_ajax() && !function_exists('wpcf7_contact_form_shortcode') && $this->siteKey && $this->secretKey) { $this->frontend(); } } } new SimpleGoogleRecaptcha();