PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.1.3
Jetpack – WP Security, Backup, Speed, & Growth v16.1.3
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / sharedaddy / recaptcha.php
recaptcha.php
235 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Google reCAPTCHA utilities, for use in the sharing feature.
4 *
5 * @package automattic/jetpack
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit( 0 );
10 }
11
12 /**
13 * Class that handles reCAPTCHA.
14 *
15 * @deprecated 11.0
16 */
17 class Jetpack_ReCaptcha {
18
19 /**
20 * URL to which requests are POSTed.
21 *
22 * @const string
23 */
24 const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
25
26 /**
27 * Site key to use in HTML code.
28 *
29 * @var string
30 */
31 private $site_key;
32
33 /**
34 * Shared secret for the site.
35 *
36 * @var string
37 */
38 private $secret_key;
39
40 /**
41 * Config for reCAPTCHA instance.
42 *
43 * @var array
44 */
45 private $config;
46
47 /**
48 * Error codes returned from reCAPTCHA API.
49 *
50 * @see https://developers.google.com/recaptcha/docs/verify
51 *
52 * @var array
53 */
54 private $error_codes;
55
56 /**
57 * Create a configured instance to use the reCAPTCHA service.
58 *
59 * @param string $site_key Site key to use in HTML code.
60 * @param string $secret_key Shared secret between site and reCAPTCHA server.
61 * @param array $config Config array to optionally configure reCAPTCHA instance.
62 */
63 public function __construct( $site_key, $secret_key, $config = array() ) {
64 $this->site_key = $site_key;
65 $this->secret_key = $secret_key;
66 $this->config = wp_parse_args( $config, $this->get_default_config() );
67
68 $this->error_codes = array(
69 'missing-input-secret' => __( 'The secret parameter is missing', 'jetpack' ),
70 'invalid-input-secret' => __( 'The secret parameter is invalid or malformed', 'jetpack' ),
71 'missing-input-response' => __( 'The response parameter is missing', 'jetpack' ),
72 'invalid-input-response' => __( 'The response parameter is invalid or malformed', 'jetpack' ),
73 'invalid-json' => __( 'Invalid JSON', 'jetpack' ),
74 'unexpected-response' => __( 'Unexpected response', 'jetpack' ),
75 'unexpected-hostname' => __( 'Unexpected hostname', 'jetpack' ),
76 );
77 }
78
79 /**
80 * Get default config for this reCAPTCHA instance.
81 *
82 * @return array Default config
83 */
84 public function get_default_config() {
85 return array(
86 'language' => get_locale(),
87 'script_async' => false,
88 'script_defer' => true,
89 'script_lazy' => false,
90 'tag_class' => 'g-recaptcha',
91 'tag_attributes' => array(
92 'theme' => 'light',
93 'type' => 'image',
94 'tabindex' => 0,
95 ),
96 );
97 }
98
99 /**
100 * Calls the reCAPTCHA siteverify API to verify whether the user passes
101 * CAPTCHA test.
102 *
103 * @param string $response The value of 'g-recaptcha-response' in the submitted
104 * form.
105 * @param string $remote_ip The end user's IP address.
106 *
107 * @return bool|WP_Error Returns true if verified. Otherwise WP_Error is returned.
108 */
109 public function verify( $response, $remote_ip ) {
110 // No need make a request if response is empty.
111 if ( empty( $response ) ) {
112 return new WP_Error( 'missing-input-response', $this->error_codes['missing-input-response'], 400 );
113 }
114
115 $resp = wp_remote_post( self::VERIFY_URL, $this->get_verify_request_params( $response, $remote_ip ) );
116 if ( is_wp_error( $resp ) ) {
117 return $resp;
118 }
119
120 $resp_decoded = json_decode( wp_remote_retrieve_body( $resp ), true );
121 if ( ! $resp_decoded ) {
122 return new WP_Error( 'invalid-json', $this->error_codes['invalid-json'], 400 );
123 }
124
125 // Default error code and message.
126 $error_code = 'unexpected-response';
127 $error_message = $this->error_codes['unexpected-response'];
128
129 // Use the first error code if exists.
130 if ( isset( $resp_decoded['error-codes'] ) && is_array( $resp_decoded['error-codes'] ) ) {
131 if ( isset( $resp_decoded['error-codes'][0] ) && isset( $this->error_codes[ $resp_decoded['error-codes'][0] ] ) ) {
132 $error_message = $this->error_codes[ $resp_decoded['error-codes'][0] ];
133 $error_code = $resp_decoded['error-codes'][0];
134 }
135 }
136
137 if ( ! isset( $resp_decoded['success'] ) ) {
138 return new WP_Error( $error_code, $error_message );
139 }
140
141 if ( true !== $resp_decoded['success'] ) {
142 return new WP_Error( $error_code, $error_message );
143 }
144 // Validate the hostname matches expected source
145 if ( isset( $resp_decoded['hostname'] ) ) {
146 $url = wp_parse_url( get_home_url() );
147
148 /**
149 * Allow other valid hostnames.
150 *
151 * This can be useful in cases where the token hostname is expected to be
152 * different from the get_home_url (ex. AMP recaptcha token contains a different hostname)
153 *
154 * @module sharedaddy
155 *
156 * @since 9.1.0
157 *
158 * @param array [ $url['host'] ] List of the valid hostnames to check against.
159 */
160 $valid_hostnames = apply_filters( 'jetpack_recaptcha_valid_hostnames', array( $url['host'] ) );
161
162 if ( ! in_array( $resp_decoded['hostname'], $valid_hostnames, true ) ) {
163 return new WP_Error( 'unexpected-host', $this->error_codes['unexpected-hostname'] );
164 }
165 }
166
167 return true;
168 }
169
170 /**
171 * Get siteverify request parameters.
172 *
173 * @param string $response The value of 'g-recaptcha-response' in the submitted
174 * form.
175 * @param string $remote_ip The end user's IP address.
176 *
177 * @return array
178 */
179 public function get_verify_request_params( $response, $remote_ip ) {
180 return array(
181 'body' => array(
182 'secret' => $this->secret_key,
183 'response' => $response,
184 'remoteip' => $remote_ip,
185 ),
186 'sslverify' => true,
187 );
188 }
189
190 /**
191 * Get reCAPTCHA HTML to render.
192 *
193 * @return string
194 */
195 public function get_recaptcha_html() {
196 $url = sprintf(
197 'https://www.google.com/recaptcha/api.js?hl=%s',
198 rawurlencode( $this->config['language'] )
199 );
200
201 $html = sprintf(
202 '
203 <div
204 class="%s"
205 data-sitekey="%s"
206 data-theme="%s"
207 data-type="%s"
208 data-tabindex="%s"
209 data-lazy="%s"
210 data-url="%s"></div>
211 ',
212 esc_attr( $this->config['tag_class'] ),
213 esc_attr( $this->site_key ),
214 esc_attr( $this->config['tag_attributes']['theme'] ),
215 esc_attr( $this->config['tag_attributes']['type'] ),
216 esc_attr( $this->config['tag_attributes']['tabindex'] ),
217 $this->config['script_lazy'] ? 'true' : 'false',
218 esc_attr( $url )
219 );
220
221 if ( ! $this->config['script_lazy'] ) {
222 $html .= sprintf(
223 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
224 '<script src="%s"%s%s></script>
225 ',
226 $url,
227 $this->config['script_async'] && ! $this->config['script_defer'] ? ' async' : '',
228 $this->config['script_defer'] ? ' defer' : ''
229 );
230 }
231
232 return $html;
233 }
234 }
235