PluginProbe
Contact Forms by Cimatti / 2.3.5
Contact Forms by Cimatti v2.3.5
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / classes / Validation / Captcha3.php

Captcha3.php in Contact Forms by Cimatti 2.3.5, at classes/Validation/Captcha3.php

120 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * reCAPTCHA v3 Validation
4 *
5 * The secret key, the expected action and the per-form spam action live on
6 * the AccuaForm_Validation_CaptchaSpam base (see that class for the spam
7 * action contract and the request-scoped flag registry shared with the
8 * reCAPTCHA v2 validator); the minimum score is added here.
9 *
10 * @package Contact Forms
11 */
12
13 // phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput -- Server-side CAPTCHA validation requires POST data
14
15 class AccuaForm_Validation_Captcha3 extends AccuaForm_Validation_CaptchaSpam {
16 protected $message = 'Error: Spam check failed. Please reload the page and retry.';
17
18 /**
19 * Minimum score a submission must reach, resolved from the field instance
20 * override or the site-wide default before the form is rendered (see
21 * accua_forms_recaptcha3_score_threshold()). Lives on the validator, not
22 * on the Element, so it survives the encrypted-form serialization round
23 * trip.
24 *
25 * @var float
26 */
27 protected $scoreThreshold = 0.5;
28
29 /**
30 * Scores returned by Google during this request, keyed by the flag key
31 * (accuaform_{fid}). Recorded on pass and on fail alike so the submission
32 * handler can store the score of spam submissions too.
33 *
34 * @var array<string, float>
35 */
36 protected static $scores = array();
37
38 /**
39 * The score Google returned for the given form during this request.
40 *
41 * @param string $captcha_action The per-form flag key (accuaform_{fid}).
42 * @return float|null Null when no v3 verification ran, or when Google
43 * answered without a score.
44 */
45 public static function getScore( $captcha_action ) {
46 return isset( self::$scores[ $captcha_action ] ) ? self::$scores[ $captcha_action ] : null;
47 }
48
49 public function isValid( $value ) {
50 if ( isset( $_POST['accua-forms-recaptcha3-response'] ) ) {
51 $response = stripslashes_deep( $_POST['accua-forms-recaptcha3-response'] );
52 } else {
53 $response = (string) $value;
54 }
55
56 if ( '' === $response ) {
57 return $this->failed();
58 }
59
60 $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
61
62 $verify_data = array(
63 'secret' => $this->privateKey,
64 'response' => $response,
65 'remoteip' => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '',
66 );
67
68 $response_obj = wp_remote_post(
69 $verify_url,
70 array(
71 'body' => $verify_data,
72 'timeout' => 20,
73 )
74 );
75
76 if ( is_wp_error( $response_obj ) ) {
77 return $this->failed();
78 }
79
80 $body = wp_remote_retrieve_body( $response_obj );
81 $result = json_decode( $body, true );
82
83 if ( empty( $result['success'] ) ) {
84 return $this->failed();
85 }
86
87 // Reject tokens generated for a different action (token replay from another context).
88 if ( ! isset( $result['action'] ) || $result['action'] !== $this->captchaAction ) {
89 return $this->failed();
90 }
91
92 if ( ! isset( $result['score'] ) ) {
93 return $this->failed();
94 }
95
96 $score = (float) $result['score'];
97
98 // Keep the score for the submission handler, whatever the outcome.
99 self::$scores[ $this->captchaAction ] = $score;
100
101 /**
102 * Filter the minimum reCAPTCHA v3 score required to accept a submission.
103 *
104 * The default is the value configured by the administrator: the field
105 * instance override if it has one, otherwise the site-wide minimum
106 * score from the plugin settings page (0.5 out of the box).
107 *
108 * @param float $threshold Minimum score (0.0 - 1.0).
109 * @param string $action The reCAPTCHA action of the form being validated.
110 */
111 $threshold = (float) apply_filters( 'accua_forms_recaptcha3_score_threshold', (float) $this->scoreThreshold, $this->captchaAction );
112
113 if ( $score < $threshold ) {
114 return $this->failed();
115 }
116
117 return true;
118 }
119 }
120