PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.1
Jetpack – WP Security, Backup, Speed, & Growth v7.1
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
189 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class that handles reCAPTCHA.
5 */
6 class Jetpack_ReCaptcha {
7
8 /**
9 * URL to which requests are POSTed.
10 *
11 * @const string
12 */
13 const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
14
15 /**
16 * Site key to use in HTML code.
17 *
18 * @var string
19 */
20 private $site_key;
21
22 /**
23 * Shared secret for the site.
24 *
25 * @var string
26 */
27 private $secret_key;
28
29 /**
30 * Config for reCAPTCHA instance.
31 *
32 * @var array
33 */
34 private $config;
35
36 /**
37 * Error codes returned from reCAPTCHA API.
38 *
39 * @see https://developers.google.com/recaptcha/docs/verify
40 *
41 * @var array
42 */
43 private $error_codes;
44
45 /**
46 * Create a configured instance to use the reCAPTCHA service.
47 *
48 * @param string $site_key Site key to use in HTML code.
49 * @param string $secret_key Shared secret between site and reCAPTCHA server.
50 * @param array $config Config array to optionally configure reCAPTCHA instance.
51 */
52 public function __construct( $site_key, $secret_key, $config = array() ) {
53 $this->site_key = $site_key;
54 $this->secret_key = $secret_key;
55 $this->config = wp_parse_args( $config, $this->get_default_config() );
56
57 $this->error_codes = array(
58 'missing-input-secret' => __( 'The secret parameter is missing', 'jetpack' ),
59 'invalid-input-secret' => __( 'The secret parameter is invalid or malformed', 'jetpack' ),
60 'missing-input-response' => __( 'The response parameter is missing', 'jetpack' ),
61 'invalid-input-response' => __( 'The response parameter is invalid or malformed', 'jetpack' ),
62 'invalid-json' => __( 'Invalid JSON', 'jetpack' ),
63 'unexpected-response' => __( 'Unexpected response', 'jetpack' ),
64 'unexpected-hostname' => __( 'Unexpected hostname', 'jetpack' ),
65 );
66 }
67
68 /**
69 * Get default config for this reCAPTCHA instance.
70 *
71 * @return array Default config
72 */
73 public function get_default_config() {
74 return array(
75 'language' => get_locale(),
76 'script_async' => true,
77 'tag_class' => 'g-recaptcha',
78 'tag_attributes' => array(
79 'theme' => 'light',
80 'type' => 'image',
81 'tabindex' => 0,
82 ),
83 );
84 }
85
86 /**
87 * Calls the reCAPTCHA siteverify API to verify whether the user passes
88 * CAPTCHA test.
89 *
90 * @param string $response The value of 'g-recaptcha-response' in the submitted
91 * form.
92 * @param string $remote_ip The end user's IP address.
93 *
94 * @return bool|WP_Error Returns true if verified. Otherwise WP_Error is returned.
95 */
96 public function verify( $response, $remote_ip ) {
97 // No need make a request if response is empty.
98 if ( empty( $response ) ) {
99 return new WP_Error( 'missing-input-response', $this->error_codes['missing-input-response'], 400 );
100 }
101
102 $resp = wp_remote_post( self::VERIFY_URL, $this->get_verify_request_params( $response, $remote_ip ) );
103 if ( is_wp_error( $resp ) ) {
104 return $resp;
105 }
106
107 $resp_decoded = json_decode( wp_remote_retrieve_body( $resp ), true );
108 if ( ! $resp_decoded ) {
109 return new WP_Error( 'invalid-json', $this->error_codes['invalid-json'], 400 );
110 }
111
112 // Default error code and message.
113 $error_code = 'unexpected-response';
114 $error_message = $this->error_codes['unexpected-response'];
115
116 // Use the first error code if exists.
117 if ( isset( $resp_decoded['error-codes'] ) && is_array( $resp_decoded['error-codes'] ) ) {
118 if ( isset( $resp_decoded['error-codes'][0] ) && isset( $this->error_codes[ $resp_decoded['error-codes'][0] ] ) ) {
119 $error_message = $this->error_codes[ $resp_decoded['error-codes'][0] ];
120 $error_code = $resp_decoded['error-codes'][0];
121 }
122 }
123
124 if ( ! isset( $resp_decoded['success'] ) ) {
125 return new WP_Error( $error_code, $error_message );
126 }
127
128 if ( true !== $resp_decoded['success'] ) {
129 return new WP_Error( $error_code, $error_message );
130 }
131
132 // Validate the hostname matches expected source
133 if ( isset( $resp_decoded['hostname'] ) ) {
134 $url = wp_parse_url( get_home_url() );
135 if ( $url['host'] !== $resp_decoded['hostname'] ) {
136 return new WP_Error( 'unexpected-host', $this->error_codes['unexpected-hostname'] );
137 }
138 }
139
140 return true;
141 }
142
143 /**
144 * Get siteverify request parameters.
145 *
146 * @param string $response The value of 'g-recaptcha-response' in the submitted
147 * form.
148 * @param string $remote_ip The end user's IP address.
149 *
150 * @return array
151 */
152 public function get_verify_request_params( $response, $remote_ip ) {
153 return array(
154 'body' => array(
155 'secret' => $this->secret_key,
156 'response' => $response,
157 'remoteip' => $remote_ip,
158 ),
159 'sslverify' => true,
160 );
161 }
162
163 /**
164 * Get reCAPTCHA HTML to render.
165 *
166 * @return string
167 */
168 public function get_recaptcha_html() {
169 return sprintf(
170 '
171 <div
172 class="%s"
173 data-sitekey="%s"
174 data-theme="%s"
175 data-type="%s"
176 data-tabindex="%s"></div>
177 <script type="text/javascript" src="https://www.google.com/recaptcha/api.js?hl=%s"%s></script>
178 ',
179 esc_attr( $this->config['tag_class'] ),
180 esc_attr( $this->site_key ),
181 esc_attr( $this->config['tag_attributes']['theme'] ),
182 esc_attr( $this->config['tag_attributes']['type'] ),
183 esc_attr( $this->config['tag_attributes']['tabindex'] ),
184 rawurlencode( $this->config['language'] ),
185 $this->config['script_async'] ? ' async' : ''
186 );
187 }
188 }
189