Advertisement
Guest User

Untitled

a guest
Nov 30th, 2022
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.70 KB | None | 0 0
  1. <?php
  2. /**
  3. * Base class to handle Google reCAPTCHA API functionality.
  4. *
  5. * @tutorial https://developers.google.com/recaptcha/docs/faq
  6. * @since 4.5.3
  7. * @since 4.5.7.2 refactored by Günter
  8. */
  9. if( ! defined('AVIA_FW') ) { exit( 'No direct script access allowed' ); }
  10.  
  11.  
  12. if( ! class_exists( 'av_google_recaptcha' ) )
  13. {
  14. class av_google_recaptcha
  15. {
  16. const API_URL = 'https://www.google.com/recaptcha/api.js';
  17. const API_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
  18. const API_URL_LANG = '?hl=fr';
  19.  
  20. const AJAX_VERIFY_NONCE = 'av_google_recaptcha_verify_nonce';
  21. const TRANSIENT_PREFIX = 'av_google_recaptcha_';
  22.  
  23. /**
  24. *
  25. * @since 4.5.7.2
  26. * @var av_google_recaptcha
  27. */
  28. static protected $_instance = null;
  29.  
  30. /**
  31. * Version of reCAPTCHA
  32. *
  33. * @since 4.5.7.2
  34. * @var string
  35. */
  36. protected $version;
  37.  
  38. /**
  39. *
  40. * @since 4.5.7.2
  41. * @var array
  42. */
  43. protected $site_keys;
  44.  
  45. /**
  46. *
  47. * @since 4.5.7.2
  48. * @var array
  49. */
  50. protected $secret_keys;
  51.  
  52. /**
  53. * Stores the last verified keys (user might change keys and save without verifying)
  54. *
  55. * @since 4.5.7.2
  56. * @var array '' | 'string combination to verify' | 'verify_error'
  57. */
  58. protected $verified_keys;
  59.  
  60. /**
  61. * V3 score threshold (0.0 - 1.0)
  62. *
  63. * @since 4.5.7.2
  64. * @var float
  65. */
  66. protected $score;
  67.  
  68. /**
  69. * Backend theme color for V2
  70. *
  71. * @since 4.5.7.2
  72. * @var string
  73. */
  74. protected $theme;
  75.  
  76. /**
  77. * Contains the option value
  78. *
  79. * @since 4.5.7.2
  80. * @var string
  81. */
  82. protected $display_badge;
  83.  
  84. /**
  85. * Contains the HTML for replacement text
  86. *
  87. * @since 4.6.2
  88. * @var string
  89. */
  90. protected $display_badge_html;
  91.  
  92. /**
  93. *
  94. * @since 4.5.7.2
  95. * @var boolean|null
  96. */
  97. protected $loading_prohibited;
  98.  
  99. /**
  100. * Return the instance of this class
  101. *
  102. * @since 4.5.7.2
  103. * @return av_google_recaptcha
  104. */
  105. static public function instance()
  106. {
  107. if( is_null( av_google_recaptcha::$_instance ) )
  108. {
  109. av_google_recaptcha::$_instance = new av_google_recaptcha();
  110. }
  111.  
  112. return av_google_recaptcha::$_instance;
  113. }
  114.  
  115. /**
  116. *
  117. * @since 4.5.7.2
  118. */
  119. protected function __construct()
  120. {
  121. $this->loading_prohibited = null;
  122. $this->version = '';
  123. $this->site_keys = array();
  124. $this->secret_keys = array();
  125. $this->verified_keys = array();
  126. $this->score = 0.5;
  127. $this->theme = 'light';
  128. $this->display_badge = '';
  129. $this->display_badge_html = '';
  130.  
  131.  
  132. // needed because not all framework functions are loaded at this point
  133. add_action( 'after_setup_theme', array( $this, 'handler_after_setup_theme' ), 10 );
  134.  
  135. add_action( 'init', array( $this, 'handler_wp_register_scripts' ), 20 );
  136. add_action( 'wp_enqueue_scripts', array( $this, 'handler_wp_enqueue_scripts' ), 500 );
  137. add_action( 'admin_enqueue_scripts', array( $this, 'handler_wp_admin_enqueue_scripts' ), 500 );
  138.  
  139. add_filter( 'body_class', array( $this, 'handler_body_class' ), 500, 2 );
  140.  
  141. // We hook with low priority as reCAPTCHA verification should overrule other positive checks
  142. add_filter( 'avf_form_send', array( $this, 'handler_avf_form_send' ), 999999, 4 );
  143.  
  144. add_action( 'wp_ajax_avia_recaptcha_verify_frontend', array( $this, 'handler_recaptcha_verify_frontend' ), 10 );
  145. add_action( 'wp_ajax_nopriv_avia_recaptcha_verify_frontend', array( $this, 'handler_recaptcha_verify_frontend' ), 10 );
  146. }
  147.  
  148. /**
  149. *
  150. * @since 4.5.7.2
  151. */
  152. public function __destruct()
  153. {
  154. unset( $this->site_keys );
  155. unset( $this->secret_keys );
  156. unset( $this->verified_keys );
  157. }
  158.  
  159. /**
  160. * @since 4.5.7.2
  161. */
  162. public function handler_after_setup_theme()
  163. {
  164. $this->version = avia_get_option( 'avia_recaptcha_version', '' );
  165.  
  166. $this->site_keys['avia_recaptcha_v2'] = avia_get_option( 'avia_recaptcha_pkey_v2', '' );
  167. $this->site_keys['avia_recaptcha_v3'] = avia_get_option( 'avia_recaptcha_pkey_v3', '' );
  168.  
  169. $this->secret_keys['avia_recaptcha_v2'] = avia_get_option( 'avia_recaptcha_skey_v2', '' );
  170. $this->secret_keys['avia_recaptcha_v3'] = avia_get_option( 'avia_recaptcha_skey_v3', '' );
  171.  
  172. $this->verified_keys['avia_recaptcha_v2'] = avia_get_option( 'recaptcha_verified_keys_v2', '' );
  173. $this->verified_keys['avia_recaptcha_v3'] = avia_get_option( 'recaptcha_verified_keys_v3', '' );
  174.  
  175. $this->score = avia_get_option( 'avia_recaptcha_score', 5 );
  176. $this->score = is_numeric( $this->score ) ? $this->score / 10.0 : 0.5;
  177.  
  178. $this->display_badge = avia_get_option( 'avia_recaptcha_badge', '' );
  179. if( ! current_theme_supports( 'avia_recaptcha_show_legal_information' ) )
  180. {
  181. $this->display_badge = 'contact_only_message';
  182. }
  183.  
  184. /**
  185. * see https://developers.google.com/recaptcha/docs/faq#id-like-to-hide-the-recaptcha-badge-what-is-allowed
  186. *
  187. * @since 4.5.7.2
  188. * @param string
  189. * @return string
  190. */
  191. $badge = '<div class="av-google-badge-message hidden">';
  192. $badge .= __( 'This site is protected by reCAPTCHA and the Google <a href="https://policies.google.com/privacy">Privacy Policy</a> and <a href="https://policies.google.com/terms">Terms of Service</a> apply.', 'avia_framework' );
  193. $badge .= '</div>';
  194.  
  195. $this->display_badge_html = apply_filters( 'avf_google_recaptcha_badge_content', $badge );
  196. }
  197.  
  198. /**
  199. * @since 4.5.7.2
  200. */
  201. public function handler_wp_register_scripts()
  202. {
  203. $vn = avia_get_theme_version();
  204. $min_js = avia_minify_extension( 'js' );
  205.  
  206. wp_register_script( 'avia_google_recaptcha_front_script' , AVIA_JS_URL . "conditional_load/avia_google_recaptcha_front{$min_js}.js", array( 'jquery' ), $vn, true );
  207. wp_register_script( 'avia_google_recaptcha_api_script' , AVIA_JS_URL . "conditional_load/avia_google_recaptcha_api{$min_js}.js", array( 'jquery' ), $vn, true );
  208. }
  209.  
  210. /**
  211. * Frontend we load conditionally. This script checks after pageload if loading of main scripts are necessary.
  212. *
  213. * @since 4.5.7.2
  214. */
  215. public function handler_wp_enqueue_scripts()
  216. {
  217. if( $this->is_loading_prohibited() )
  218. {
  219. return;
  220. }
  221.  
  222. wp_enqueue_script( 'avia_google_recaptcha_front_script' );
  223.  
  224. /**
  225. * @since 5.3
  226. * @param string $api_url
  227. * @param string $context 'backend' | 'frontend'
  228. * @return string
  229. */
  230. $api_url = apply_filters( 'avf_google_recaptcha_apiurl', av_google_recaptcha::API_URL, 'frontend' );
  231.  
  232. $args = array(
  233. 'version' => $this->get_version(),
  234. 'site_key2' => $this->get_site_key( 'avia_recaptcha_v2' ),
  235. 'site_key3' => $this->get_site_key( 'avia_recaptcha_v3' ),
  236. 'api' => $api_url,
  237. 'avia_api_script' => AVIA_JS_URL . 'conditional_load/avia_google_recaptcha_api.js',
  238. 'theme' => $this->get_theme(),
  239. 'score' => $this->get_score(),
  240. 'verify_nonce' => wp_create_nonce( av_google_recaptcha::AJAX_VERIFY_NONCE ),
  241. // 'submission_nonce' => wp_create_nonce( av_google_recaptcha::AJAX_SUBMISSION_NONCE ),
  242. 'cannot_use' => '<h3 class="av-recaptcha-error-main">' . __( 'Sorry, a problem occurred trying to communicate with Google reCAPTCHA API. You are currently not able to submit the contact form. Please try again later - reload the page and also check your internet connection.', 'avia_framework' ) . '</h3>',
  243. 'init_error_msg' => __( 'Initial setting failed. Sitekey 2 and/or sitekey 3 missing in frontend.', 'avia_framework' ),
  244. 'v3_timeout_pageload' => __( 'Timeout occurred connecting to V3 API on initial pageload', 'avia_framework' ),
  245. 'v3_timeout_verify' => __( 'Timeout occurred connecting to V3 API on verifying submit', 'avia_framework' ),
  246. 'v2_timeout_verify' => __( 'Timeout occurred connecting to V2 API on verifying you as human. Please try again and check your internet connection. It might be necessary to reload the page.', 'avia_framework' ),
  247. 'verify_msg' => __( 'Verify....', 'avia_framework' ),
  248. 'connection_error' => __( 'Could not connect to the internet. Please reload the page and try again.', 'avia_framework' ),
  249. 'validate_first' => __( 'Please validate that you are a human first', 'avia_framework' ),
  250. 'validate_submit' => __( 'Before submitting we validate that you are a human first.', 'avia_framework' ),
  251. 'no_token' => __( 'Missing internal token on valid submit - unable to proceed.', 'avia_framework' ),
  252. 'invalid_version' => __( 'Invalid reCAPTCHA version found.', 'avia_framework' ),
  253. 'api_load_error' => __( 'Google reCAPTCHA API could not be loaded.', 'avia_framework' ),
  254. );
  255.  
  256. wp_localize_script( 'avia_google_recaptcha_front_script', 'AviaReCAPTCHA_front', $args );
  257. }
  258.  
  259. /**
  260. *
  261. * @since 4.5.7.2
  262. */
  263. public function handler_wp_admin_enqueue_scripts()
  264. {
  265. /**
  266. * Some 3rd party plugins need to supress loading scripts
  267. * Not loading the scripts might result in breaking backend !!!
  268. * Check if everything is working as expected.
  269. *
  270. * @since 4.7.5.1
  271. * @param boolean
  272. * @return string return 'skip_loading' to prohibit loading of backend scripts
  273. */
  274. $skip_loading = apply_filters( 'avf_skip_enqueue_scripts_backend_grecaptcha', '' );
  275.  
  276. if( 'skip_loading' === $skip_loading )
  277. {
  278. return;
  279. }
  280.  
  281. /**
  282. * In backend we must enqueue to validate keys and localize script
  283. */
  284. wp_enqueue_script( 'avia_google_recaptcha_front_script' );
  285.  
  286. /**
  287. * @since 5.3
  288. * @param string $api_url
  289. * @param string $context 'backend' | 'frontend'
  290. * @return string
  291. */
  292. $api_url = apply_filters( 'avf_google_recaptcha_apiurl', av_google_recaptcha::API_URL, 'backend' );
  293.  
  294. $args = array(
  295. 'version' => $this->get_version(),
  296. // 'site_key' => $this->get_site_key(),
  297. 'api' => $api_url,
  298. 'theme' => $this->get_theme(),
  299. 'api_load_error' => __( 'Google reCAPTCHA API could not be loaded. We are not able to verify keys. Check your internet connection and try again.', 'avia_framework' ),
  300. 'invalid_version' => __( 'Please select Version 2 or 3 for reCAPTCHA', 'avia_framework' ),
  301. 'invalid_keys' => __( 'You have to enter a site key and a secret key to verify it.', 'avia_framework' ),
  302. 'v3_timeout' => __( 'A network timeout problem occurred. Could be caused by an invalid V3 sitekey. Please recheck the key and try again.', 'avia_framework' )
  303. );
  304.  
  305. wp_localize_script( 'avia_google_recaptcha_front_script', 'AviaReCAPTCHA_data', $args );
  306. }
  307.  
  308. /**
  309. * We add classes to allow js script to decide what to load
  310. *
  311. * @since 4.5.7.2
  312. * @param array $classes
  313. * @param array $class
  314. * @return array
  315. */
  316. public function handler_body_class( array $classes, array $class )
  317. {
  318. if( $this->is_loading_prohibited() )
  319. {
  320. return $classes;
  321. }
  322.  
  323. /**
  324. * Allows to disable recaptcha for special pages.
  325. * Only makes sense for V3 as V2 is only loaded if needed on page/post.
  326. * Be careful not to disable it on pages where you need it !!!
  327. *
  328. * @since 4.5.7.2
  329. * @param boolean
  330. * @return boolean
  331. */
  332. $disable = apply_filters( 'avf_disable_recaptchaV3_for_post', false );
  333.  
  334. if( false === $disable )
  335. {
  336. $classes[] = 'av-recaptcha-enabled';
  337. }
  338.  
  339. if( $this->show_extended_errors() )
  340. {
  341. $classes[] = 'av-recaptcha-extended-errors';
  342. }
  343.  
  344. if( in_array( $this->display_badge, array( 'contact_only_message', 'hide' ) ) )
  345. {
  346. $classes[] = 'av-google-badge-hide';
  347. }
  348.  
  349. return $classes;
  350. }
  351.  
  352. /**
  353. * Returns the selected version for the recaptcha
  354. *
  355. * @since 4.5.7.2
  356. * @return string '' | 'avia_recaptcha_v2' | 'avia_recaptcha_v3'
  357. */
  358. public function get_version()
  359. {
  360. return $this->version;
  361. }
  362.  
  363. /**
  364. * Returns the site key for the selected version
  365. *
  366. * @since 4.5.7.2
  367. * @param string $version
  368. * @return string
  369. */
  370. public function get_site_key( $version = null )
  371. {
  372. if( is_null( $version ) )
  373. {
  374. $version = $this->get_version();
  375. }
  376.  
  377. return isset( $this->site_keys[ $version ] ) ? $this->site_keys[ $version ] : '';
  378. }
  379.  
  380. /**
  381. * Returns the secret key for the selected version
  382. *
  383. * @since 4.5.7.2
  384. * @param string $version
  385. * @return string
  386. */
  387. public function get_secret_key( $version = null )
  388. {
  389. if( is_null( $version ) )
  390. {
  391. $version = $this->get_version();
  392. }
  393.  
  394. return isset( $this->secret_keys[ $version ] ) ? $this->secret_keys[ $version ] : '';
  395. }
  396.  
  397. /**
  398. * Returns the last saved verified key string:
  399. * "version site_key secret_key"
  400. *
  401. * @since 4.5.7.2
  402. * @param string $version
  403. * @return string
  404. */
  405. public function get_verified_keys( $version = null )
  406. {
  407. if( is_null( $version ) )
  408. {
  409. $version = $this->get_version();
  410. }
  411.  
  412. return isset( $this->verified_keys[ $version ] ) ? $this->verified_keys[ $version ] : '';
  413. }
  414.  
  415. /**
  416. * Returns the float value for selected score threshold (0.0 - 1.0)
  417. *
  418. * @since 4.5.7.2
  419. * @return float
  420. */
  421. public function get_score()
  422. {
  423. return $this->score;
  424. }
  425.  
  426. /**
  427. * Returns the necessary HTML if user selected to use
  428. *
  429. * @since 4.5.7.2
  430. * @return string
  431. */
  432. public function get_display_badge_html()
  433. {
  434. if( ! in_array( $this->display_badge, array( 'message', 'contact_only_message' ) ) )
  435. {
  436. return '';
  437. }
  438.  
  439. return $this->display_badge_html;
  440. }
  441.  
  442. /**
  443. * Returns the selected backend theme style
  444. *
  445. * @since 4.5.7.2
  446. * @return string 'light' | 'dark'
  447. */
  448. public function get_theme()
  449. {
  450. if( ! in_array( $this->theme, array( 'light', 'dark' ) ) )
  451. {
  452. $this->theme = 'light';
  453. }
  454.  
  455. return $this->theme;
  456. }
  457.  
  458. /**
  459. *
  460. * @since 4.5.7.2
  461. * @return boolean
  462. */
  463. public function is_loading_prohibited()
  464. {
  465. if( is_null( $this->loading_prohibited ) )
  466. {
  467. // Check backend setting
  468. $prohibited = ! $this->is_activated() || ! $this->are_keys_set();
  469.  
  470. /**
  471. * Filter allows to supress loading of script on desired pages
  472. *
  473. * @since 4.5.7.2
  474. * @param boolean
  475. * @return boolean
  476. */
  477. $prohibited = apply_filters( 'avf_load_google_recaptcha_api_prohibited', $prohibited );
  478.  
  479. $this->loading_prohibited = is_bool( $prohibited ) ? $prohibited : true;
  480. }
  481.  
  482. return $this->loading_prohibited;
  483. }
  484.  
  485. /**
  486. * Checks if the version activates gRECAPTCHA
  487. *
  488. * @since 4.5.7.2
  489. * @param string $version
  490. * @return boolean
  491. */
  492. public function is_activated( $version = null )
  493. {
  494. if( is_null( $version ) )
  495. {
  496. $version = $this->get_version();
  497. }
  498.  
  499. return in_array( $version, array( 'avia_recaptcha_v2', 'avia_recaptcha_v3' ) );
  500. }
  501.  
  502. /**
  503. * Checks if all necessary keys are set for a version.
  504. * Returns false if an invalid version or if disabled
  505. *
  506. * @since 4.5.7.2
  507. * @param string $version
  508. * @return boolean
  509. */
  510. public function are_keys_set( $version = null )
  511. {
  512. if( is_null( $version ) )
  513. {
  514. $version = $this->get_version();
  515. }
  516.  
  517. $keys2 = ! empty( $this->get_site_key( 'avia_recaptcha_v2' ) ) && ! empty( $this->get_secret_key( 'avia_recaptcha_v2' ) );
  518. $keys3 = ! empty( $this->get_site_key( 'avia_recaptcha_v3' ) ) && ! empty( $this->get_secret_key( 'avia_recaptcha_v3' ) );
  519.  
  520. if( 'avia_recaptcha_v2' == $version )
  521. {
  522. return $keys2;
  523. }
  524.  
  525. if( 'avia_recaptcha_v3' == $version )
  526. {
  527. return $keys2 && $keys3;
  528. }
  529.  
  530. return false;
  531. }
  532.  
  533. /**
  534. * Allow admins to see more detailed error messages
  535. *
  536. * @since 4.5.7.2
  537. * @return boolean
  538. */
  539. protected function show_extended_errors()
  540. {
  541. $show_extended_errors = current_user_can( 'manage_options' );
  542.  
  543. /**
  544. *
  545. *
  546. * @since 4.5.7.2
  547. * @param boolean
  548. * @return boolean return true to show extended messages
  549. */
  550. return apply_filters( 'avf_recaptcha_show_extended_error_messages', $show_extended_errors );
  551. }
  552.  
  553. /**
  554. * Verify a token with gRECAPTCHA.
  555. *
  556. * @since 4.5.7.2
  557. * @param string $token
  558. * @param string|null $secretkey if null -> verification of key
  559. * @return array|\WP_Error check $result['success'] = true
  560. */
  561. protected function verify_token( $token, $secretkey = null )
  562. {
  563. if( is_null( $secretkey ) )
  564. {
  565. $secretkey = $this->get_secret_key();
  566. }
  567.  
  568. $params = array(
  569. 'body' => array(
  570. 'secret' => $secretkey,
  571. 'response' => $token,
  572. 'remoteip' => $_SERVER['REMOTE_ADDR'],
  573. )
  574. );
  575.  
  576. $response = wp_safe_remote_post( av_google_recaptcha::API_VERIFY_URL, $params );
  577.  
  578. if( $response instanceof WP_Error )
  579. {
  580. $msg = $response->get_error_messages();
  581. $msg = implode( '<br />', $msg );
  582.  
  583. return new WP_Error( 'site_down', sprintf( __( 'Unable to communicate with gRECAPTCHA: <br /><br />%s', 'avia_framework' ), $msg ) );
  584. }
  585.  
  586. $code = wp_remote_retrieve_response_code( $response );
  587. if ( 200 != $code )
  588. {
  589. $msg = wp_remote_retrieve_response_message( $response );
  590. if( empty( $msg ) )
  591. {
  592. $msg = __( 'Unknown error code', 'avia_framework' );
  593. }
  594. return new WP_Error( 'invalid_response', sprintf( __( 'gRECAPTCHA returned error %d (= %s).', 'avia_framework' ), $code, $msg ) );
  595. }
  596.  
  597.  
  598. $body = wp_remote_retrieve_body( $response );
  599. $result = json_decode( $body, true );
  600.  
  601. if( true === $result['success'] )
  602. {
  603. return $result;
  604. }
  605.  
  606. if( isset( $result['error-codes'] ) && is_array( $result['error-codes'] ) )
  607. {
  608. foreach( $result['error-codes'] as $key => $value )
  609. {
  610. switch( $value )
  611. {
  612. case 'missing-input-secret':
  613. $result['error-codes'][ $key ] = __( 'The secret parameter is missing.', 'avia_framework' );
  614. break;
  615. case 'invalid-input-secret':
  616. $result['error-codes'][ $key ] = __( 'The secret parameter is invalid or malformed.', 'avia_framework' );
  617. break;
  618. case 'missing-input-response':
  619. $result['error-codes'][ $key ] = __( 'The response parameter is missing.', 'avia_framework' );
  620. break;
  621. case 'invalid-input-response':
  622. $result['error-codes'][ $key ] = __( 'The response parameter is invalid or malformed.', 'avia_framework' );
  623. break;
  624. case 'bad-request':
  625. $result['error-codes'][ $key ] = __( 'The request is invalid or malformed.', 'avia_framework' );
  626. break;
  627. case 'timeout-or-duplicate':
  628. $result['error-codes'][ $key ] = __( 'The response is no longer valid: either is too old or has been used previously.', 'avia_framework' );
  629. break;
  630. default:
  631. $result['error-codes'][ $key ] = sprintf( __( '%s - unknown error code', 'avia_framework' ), $value );
  632. }
  633. }
  634. }
  635.  
  636. return $result;
  637. }
  638.  
  639. /**
  640. * Callback - verifies the token and creates a transient if valid.
  641. * In case of a false score returns
  642. *
  643. * @since 4.5.7.2
  644. */
  645. public function handler_recaptcha_verify_frontend()
  646. {
  647. header( "Content-Type: application/json" );
  648. $response = array(
  649. 'success' => false,
  650. 'alert' => '',
  651. 'score_failed' => false,
  652. 'transient' => ''
  653. );
  654.  
  655. $show_extended_errors = $this->show_extended_errors();
  656.  
  657. /**
  658. * Nonce check removed with 4.7.4.1
  659. *
  660. * Makes problems with caching plugins.
  661. * As reCaptcha is bound to a site verifying the reCaptcha should be enough to verify a valid callback.
  662. *
  663. */
  664. // $nonce = isset( $_REQUEST['_wpnonce'] ) ? $_REQUEST['_wpnonce'] : '';
  665. // $result = wp_verify_nonce( $nonce, av_google_recaptcha::AJAX_VERIFY_NONCE );
  666. //
  667. // if( 1 !== $result )
  668. // {
  669. // $response['alert'] = __( 'Sorry, but the session time for this page has expired. Please reload the page.', 'avia_framework' );
  670. // if( true === $show_extended_errors )
  671. // {
  672. // $response['alert'] .= '<br />' . __( 'WP Nonce check failed.', 'avia_framework' );
  673. // }
  674. //
  675. // echo json_encode( $response );
  676. // exit;
  677. // }
  678.  
  679. $version = isset( $_REQUEST['version'] ) ? $_REQUEST['version'] : '';
  680. $token = isset( $_REQUEST['token'] ) ? $_REQUEST['token'] : '';
  681. $score = isset( $_REQUEST['score'] ) ? $_REQUEST['score'] : -1;
  682. $action = isset( $_REQUEST['recaptcha_action'] ) ? $_REQUEST['recaptcha_action'] : '';
  683. $secret_key = $this->get_secret_key( $version );
  684.  
  685.  
  686. $check = $this->verify_token( $token, $secret_key );
  687.  
  688. $validate_error = __( 'Sorry, but the verification failed. Please reload the page and try again.', 'avia_framework' );
  689.  
  690. if( true !== $check['success'] )
  691. {
  692. $response['alert'] = $validate_error;
  693. if( true === $show_extended_errors )
  694. {
  695. $response['alert'] .= '<br />' . __( 'API check returned false.', 'avia_framework' );
  696. }
  697.  
  698. echo json_encode( $response );
  699. exit;
  700. }
  701.  
  702. if( 'avia_recaptcha_v3' == $version )
  703. {
  704. if( ! isset( $check['score'] ) || ! isset( $check['action'] ) || ( $check['action'] != $action ) )
  705. {
  706. $response['alert'] = $validate_error;
  707. if( true === $show_extended_errors )
  708. {
  709. $response['alert'] .= '<br />' . __( 'Invalid V3 response. Actions:', 'avia_framework' ) . $check['action'] . '/' . $action;
  710. }
  711.  
  712. echo json_encode( $response );
  713. exit;
  714. }
  715.  
  716. if( (float) $score >= (float)$check['score'] )
  717. {
  718. if( true === $show_extended_errors )
  719. {
  720. $response['score_failed'] = sprintf( __( 'Score requested %s - returned %s', 'avia_framework' ), $score, $check['score'] );
  721. }
  722. else
  723. {
  724. $response['score_failed'] = true;
  725. }
  726.  
  727. echo json_encode( $response );
  728. exit;
  729. }
  730. }
  731.  
  732. $transient = uniqid( av_google_recaptcha::TRANSIENT_PREFIX, true );
  733.  
  734. /**
  735. * @since 4.5.7.2
  736. * @param int
  737. * @return int
  738. */
  739. $expiration = 30 * MINUTE_IN_SECONDS;
  740. $expiration = apply_filters( 'avf_recaptcha_transient_expiration', $expiration );
  741. if( ! is_numeric( $expiration ) )
  742. {
  743. $expiration = 30 * MINUTE_IN_SECONDS;
  744. }
  745.  
  746. set_transient( $transient, $version, $expiration );
  747.  
  748. $response['success'] = true;
  749. $response['transient'] = $transient;
  750.  
  751. echo json_encode( $response );
  752. exit;
  753. }
  754.  
  755. /**
  756. * Check if we have a valid token.
  757. * This is also a fallback to prevent bots using same token several times.
  758. * In case $proceed !== true we also remove the transient to clean up.
  759. *
  760. * @since 4.5.7.2
  761. * @param boolean $proceed
  762. * @param array $new_post
  763. * @param array $form_params
  764. * @param avia_form $form_class
  765. * @return boolean|null true if you want to continue | null for error message
  766. */
  767. public function handler_avf_form_send( $proceed, array $new_post, array $form_params, avia_form $form_class )
  768. {
  769. $use_recaptcha = false;
  770.  
  771. foreach( $form_class->form_elements as $element )
  772. {
  773. if( isset( $element['type'] ) && ( 'grecaptcha' == $element['type'] ) )
  774. {
  775. $use_recaptcha = $element;
  776. break;
  777. }
  778. }
  779.  
  780. if( false === $use_recaptcha )
  781. {
  782. return $proceed;
  783. }
  784.  
  785. $show_extended_errors = $this->show_extended_errors();
  786. $token = isset( $element['token_input'] ) ? $element['token_input'] : '';
  787. $token_value = ( isset( $_REQUEST[ $token ] ) ) ? trim( $_REQUEST[ $token ] ) : '';
  788. $requested_version = ( isset( $_REQUEST[ $token . '-version' ] ) ) ? trim( $_REQUEST[ $token . '-version' ] ) : $element['version'];
  789.  
  790. if( true !== $proceed )
  791. {
  792. if( ! empty( $token_value ) )
  793. {
  794. delete_transient( $token_value );
  795. }
  796.  
  797. return $proceed;
  798. }
  799.  
  800. $reload_msg = '<br />' . __( 'Form could not be submitted. Please reload page and try again.', 'avia_framework' );
  801.  
  802. if( empty( $token_value ) )
  803. {
  804. $form_class->submit_error .= __( 'Invalid form for reCAPTCHA sent.', 'avia_framework' ) . $reload_msg;
  805. if( $show_extended_errors )
  806. {
  807. $form_class->submit_error .= '<br />' . __( 'Name for token field was missing.', 'avia_framework' );
  808. }
  809. return null;
  810. }
  811.  
  812. $version = get_transient( $token_value );
  813.  
  814. if( false === $version )
  815. {
  816. $form_class->submit_error .= __( 'Token to validate form already expired.', 'avia_framework' ) . $reload_msg;
  817. if( $show_extended_errors )
  818. {
  819. $form_class->submit_error .= '<br />' . __( 'Transient to verify form was missing or expired.', 'avia_framework' );
  820. }
  821. return null;
  822. }
  823.  
  824. delete_transient( $token_value );
  825.  
  826. if( $version != $requested_version )
  827. {
  828. $form_class->submit_error .= __( 'Token to validate form is not valid.', 'avia_framework' ) . $reload_msg;
  829. if( $show_extended_errors )
  830. {
  831. $form_class->submit_error .= '<br />' . __( 'reCAPTCHA version in transient differs from selected version in element.', 'avia_framework' );
  832. }
  833. return null;
  834. }
  835.  
  836. return $proceed;
  837. }
  838.  
  839. /**
  840. * Output options page backend HTML or perform the key verification and return HTML message
  841. *
  842. * @since 4.5.7.2
  843. * @param string $api_key
  844. * @param boolean $ajax
  845. * @param array|boolean|null $check_keys
  846. * @param array $element used in backend for output of key verification
  847. * @return string|array
  848. */
  849. public function backend_html( $api_key = '', $ajax = true, $check_keys = false, $element = array() )
  850. {
  851. $return = array(
  852. 'html' => '',
  853. 'update_input_fields' => array()
  854. );
  855.  
  856. $api_key = trim( $api_key );
  857. $valid_key = false;
  858.  
  859. $response_text = __( 'Could not connect and verify these API Keys with Google reCAPTCHA.', 'avia_framework' );
  860. $response_class = "av-notice-error";
  861.  
  862. $content_default = '<h4>' . esc_html__( 'Troubleshooting:', 'avia_framework' ) . '</h4>';
  863. $content_default .= '<ol>';
  864. $content_default .= '<li>';
  865. $content_default .= esc_html__( 'Check if you typed the keys correctly.', 'avia_framework' );
  866. $content_default .= '</li>';
  867. $content_default .= '<li>';
  868. $content_default .= esc_html__( 'If you use the restriction setting on Google try to remove that, wait a few minutes for google to apply your changes and then check again if the keys work here. If it does, you probably have a syntax error in your referrer url', 'avia_framework' );
  869. $content_default .= '</li>';
  870. $content_default .= '<li>';
  871. $content_default .= esc_html__( 'If none of this helps: deactivate all plugins and then check if the API works by using the button above. If thats the case then one of your plugins is interfering.', 'avia_framework' );
  872. $content_default .= '</li>';
  873. $content_default .= '</ol>';
  874.  
  875.  
  876. if( $ajax )
  877. {
  878. /**
  879. * called by user pressing the ajax check button
  880. */
  881. $token = isset( $check_keys['token'] ) ? trim( $check_keys['token'] ) : '';
  882. $secretkey = isset( $check_keys['secretkey'] ) ? trim( $check_keys['secretkey'] ) : '';
  883. $version = isset( $check_keys['version'] ) ? trim( $check_keys['version'] ) : '';
  884. switch( $version )
  885. {
  886. case 'avia_recaptcha_v2':
  887. $verify_field = 'recaptcha_verified_keys_v2';
  888. break;
  889. case 'avia_recaptcha_v3':
  890. $verify_field = 'recaptcha_verified_keys_v3';
  891. break;
  892. default:
  893. $verify_field = '';
  894. break;
  895. }
  896.  
  897. $check = $this->verify_token( $token, $secretkey );
  898.  
  899. if( true === $check['success'] )
  900. {
  901. $valid_key = true;
  902. $response_class = '';
  903. $response_text = __( 'We were able to properly connect and verify your API keys with Google reCAPTCHA', 'avia_framework' );
  904.  
  905. //will be stripped from the final output but tells the ajax script to save the page after the check was performed
  906. $response_text .= ' avia_trigger_save';
  907.  
  908. $keys = array(
  909. $check_keys['version'],
  910. $check_keys['sitekey'],
  911. $check_keys['secretkey']
  912. );
  913. if( ! empty( $verify_field ) )
  914. {
  915. $return['update_input_fields'][ $verify_field ] = implode( ' ', $keys );
  916. }
  917. }
  918. else
  919. {
  920. $content_default = '';
  921. if( $check instanceof WP_Error )
  922. {
  923. $response_text = $check->get_error_message();
  924. }
  925. else
  926. {
  927. $msg = '';
  928.  
  929. if( is_array( $check['error-codes'] ) && count( $check['error-codes'] ) > 0 )
  930. {
  931. $msg = implode( '<br />', $check['error-codes'] );
  932. }
  933.  
  934. $response_text = __( 'Error on connecting to Google reCAPTCHA - please retry.', 'avia_framework' );
  935.  
  936. if( ! empty( $msg) )
  937. {
  938. $response_text .= '<br /><br />' . $msg;
  939. }
  940. }
  941.  
  942. if( ! empty( $verify_field ) )
  943. {
  944. $return['update_input_fields'][ $verify_field ] = 'verify_error';
  945. }
  946. }
  947. }
  948. else
  949. {
  950. /**
  951. * called on a normal page load. in this case we either show the stored result or if we got no stored result we show nothing
  952. */
  953. if( $this->is_activated() )
  954. {
  955. switch( $element['id'] )
  956. {
  957. case 'avia_recaptcha_key_verify_v2':
  958. $version = 'avia_recaptcha_v2';
  959. break;
  960. case 'avia_recaptcha_key_verify_v3':
  961. $version = 'avia_recaptcha_v3';
  962. break;
  963. default:
  964. $version = '';
  965. break;
  966. }
  967.  
  968. $keys = array(
  969. $version,
  970. $this->get_site_key( $version ),
  971. $this->get_secret_key( $version )
  972. );
  973.  
  974. $check = implode( ' ', $keys );
  975.  
  976. if( $this->get_verified_keys( $version ) == $check )
  977. {
  978. $valid_key = true;
  979. }
  980. else if( '' == $this->get_site_key( $version ) && '' == $this->get_secret_key( $version ) )
  981. {
  982. $response_class = '';
  983. $response_text = '';
  984. }
  985. else if( 'verify_error' == $this->get_verified_keys() )
  986. {
  987. $response_text = __( 'A connection error occurred last time we tried verify your keys with Google reCAPTCHA - please revalidate the keys.', 'avia_framework' );
  988. }
  989. else if( '' == $this->get_verified_keys( $version ) )
  990. {
  991. $response_text = __( 'Please verify the keys', 'avia_framework' );
  992. }
  993. else
  994. {
  995. $response_text = __( 'Please verify the keys - the last verified keys are different.', 'avia_framework' );
  996. }
  997.  
  998. $content_default = '';
  999. }
  1000.  
  1001. if( $valid_key )
  1002. {
  1003. $response_class = '';
  1004. $response_text = __( 'Last time we checked we were able to connected to Google reCAPTCHA with your API keys', 'avia_framework' );
  1005. }
  1006. }
  1007.  
  1008. if( $valid_key )
  1009. {
  1010. $content_default = __( 'If you ever change your API key or the URL restrictions of the key please verify the key here again, to test if it works properly','avia_framework');
  1011. }
  1012.  
  1013. $output = '';
  1014.  
  1015. if( ! empty( $response_text ) )
  1016. {
  1017. $output = "<div class='av-verification-response-wrapper'>";
  1018. $output .= "<div class='av-text-notice {$response_class}'>";
  1019. $output .= $response_text;
  1020. $output .= "</div>";
  1021. $output .= "<div class='av-verification-cell'>{$content_default}</div>";
  1022. $output .= "</div>";
  1023. }
  1024.  
  1025. if( $ajax )
  1026. {
  1027. $return['html'] = $output;
  1028. }
  1029. else
  1030. {
  1031. $return = $output;
  1032. }
  1033.  
  1034. return $return;
  1035. }
  1036.  
  1037. }
  1038.  
  1039. /**
  1040. * Returns the main instance of av_google_recaptcha to prevent the need to use globals.
  1041. *
  1042. * @since 4.5.7.2
  1043. * @return av_google_recaptcha
  1044. */
  1045. function Avia_Google_reCAPTCHA()
  1046. {
  1047. return av_google_recaptcha::instance();
  1048. }
  1049. }
  1050.  
  1051. Avia_Google_reCAPTCHA();
  1052.  
  1053.  
  1054. if( ! function_exists( 'av_recaptcha_api_check' ) )
  1055. {
  1056. /**
  1057. * Callback function:
  1058. * - ajax callback from verification button
  1059. * - php callback when creating output on option page
  1060. *
  1061. * @since 4.5.7.2
  1062. * @param string $value
  1063. * @param boolean $ajax
  1064. * @param array|null $js_value
  1065. * @param array $element
  1066. * @return string
  1067. */
  1068. function av_recaptcha_api_check( $value, $ajax = true, $js_value = null, $element = array() )
  1069. {
  1070. $api = Avia_Google_reCAPTCHA();
  1071. return $api->backend_html( $value, $ajax, $js_value, $element );
  1072. }
  1073.  
  1074. }
  1075.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement