Completed
Push — add/e2e-mailchimp-block-test ( e217db...6066d0 )
by Yaroslav
98:30 queued 85:55
created

modules/sharedaddy/recaptcha.php (5 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 );
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with 'missing-input-response'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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 );
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with 'invalid-json'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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 );
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with $error_code.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
126
		}
127
128
		if ( true !== $resp_decoded['success'] ) {
129
			return new WP_Error( $error_code, $error_message );
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with $error_code.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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'] );
0 ignored issues
show
The call to WP_Error::__construct() has too many arguments starting with 'unexpected-host'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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