Completed
Push — try/inline-connect ( 8d5d81...1de650 )
by
unknown
611:01 queued 599:40
created

Rest_Authentication::wp_rest_authenticate()   F

Complexity

Conditions 19
Paths 22

Size

Total Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
nc 22
nop 1
dl 0
loc 98
rs 3.6569
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * The Jetpack Connection Rest Authentication file.
4
 *
5
 * @package automattic/jetpack-connection
6
 */
7
8
namespace Automattic\Jetpack\Connection;
9
10
/**
11
 * The Jetpack Connection Rest Authentication class.
12
 */
13
class Rest_Authentication {
14
15
	/**
16
	 * The rest authentication status.
17
	 *
18
	 * @since 8.9.0
19
	 * @var boolean
20
	 */
21
	private $rest_authentication_status = null;
22
23
	/**
24
	 * The rest authentication type.
25
	 * Can be either 'user' or 'blog' depending on whether the request
26
	 * is signed with a user or a blog token.
27
	 *
28
	 * @since 9.9.0
29
	 * @var string
30
	 */
31
	private $rest_authentication_type = null;
32
33
	/**
34
	 * The Manager object.
35
	 *
36
	 * @since 8.9.0
37
	 * @var Object
38
	 */
39
	private $connection_manager = null;
40
41
	/**
42
	 * Holds the singleton instance of this class
43
	 *
44
	 * @since 8.9.0
45
	 * @var Object
46
	 */
47
	private static $instance = false;
48
49
	/**
50
	 * Flag used to avoid determine_current_user filter to enter an infinite loop
51
	 *
52
	 * @since 9.7.0
53
	 * @var boolean
54
	 */
55
	private $doing_determine_current_user_filter = false;
56
57
	/**
58
	 * The constructor.
59
	 */
60
	private function __construct() {
61
		$this->connection_manager = new Manager();
62
	}
63
64
	/**
65
	 * Controls the single instance of this class.
66
	 *
67
	 * @static
68
	 */
69
	public static function init() {
70
		if ( ! self::$instance ) {
71
			self::$instance = new self();
72
73
			add_filter( 'determine_current_user', array( self::$instance, 'wp_rest_authenticate' ) );
74
			add_filter( 'rest_authentication_errors', array( self::$instance, 'wp_rest_authentication_errors' ) );
75
		}
76
77
		return self::$instance;
78
	}
79
80
	/**
81
	 * Authenticates requests from Jetpack server to WP REST API endpoints.
82
	 * Uses the existing XMLRPC request signing implementation.
83
	 *
84
	 * @param int|bool $user User ID if one has been determined, false otherwise.
85
	 *
86
	 * @return int|null The user id or null if the request was not authenticated.
87
	 */
88
	public function wp_rest_authenticate( $user ) {
89
		if ( $this->doing_determine_current_user_filter ) {
90
			return $user;
91
		}
92
93
		$this->doing_determine_current_user_filter = true;
94
95
		try {
96
			if ( ! empty( $user ) ) {
97
				// Another authentication method is in effect.
98
				return $user;
99
			}
100
101
			add_filter(
102
				'jetpack_constant_default_value',
103
				__NAMESPACE__ . '\Utils::jetpack_api_constant_filter',
104
				10,
105
				2
106
			);
107
108
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
109
			if ( ! isset( $_GET['_for'] ) || 'jetpack' !== $_GET['_for'] ) {
110
				// Nothing to do for this authentication method.
111
				return null;
112
			}
113
114
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
115
			if ( ! isset( $_GET['token'] ) && ! isset( $_GET['signature'] ) ) {
116
				// Nothing to do for this authentication method.
117
				return null;
118
			}
119
120
			if ( ! isset( $_SERVER['REQUEST_METHOD'] ) ) {
121
				$this->rest_authentication_status = new \WP_Error(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \WP_Error('rest_inva...array('status' => 400)) of type object<WP_Error> is incompatible with the declared type boolean of property $rest_authentication_status.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
122
					'rest_invalid_request',
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'rest_invalid_request'.

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...
123
					__( 'The request method is missing.', 'jetpack' ),
124
					array( 'status' => 400 )
125
				);
126
				return null;
127
			}
128
129
			// Only support specific request parameters that have been tested and
130
			// are known to work with signature verification.  A different method
131
			// can be passed to the WP REST API via the '?_method=' parameter if
132
			// needed.
133
			if ( 'GET' !== $_SERVER['REQUEST_METHOD'] && 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
134
				$this->rest_authentication_status = new \WP_Error(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \WP_Error('rest_inva...array('status' => 400)) of type object<WP_Error> is incompatible with the declared type boolean of property $rest_authentication_status.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
135
					'rest_invalid_request',
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'rest_invalid_request'.

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...
136
					__( 'This request method is not supported.', 'jetpack' ),
137
					array( 'status' => 400 )
138
				);
139
				return null;
140
			}
141
			if ( 'POST' !== $_SERVER['REQUEST_METHOD'] && ! empty( file_get_contents( 'php://input' ) ) ) {
142
				$this->rest_authentication_status = new \WP_Error(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \WP_Error('rest_inva...array('status' => 400)) of type object<WP_Error> is incompatible with the declared type boolean of property $rest_authentication_status.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
143
					'rest_invalid_request',
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'rest_invalid_request'.

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...
144
					__( 'This request method does not support body parameters.', 'jetpack' ),
145
					array( 'status' => 400 )
146
				);
147
				return null;
148
			}
149
150
			$verified = $this->connection_manager->verify_xml_rpc_signature();
151
152
			if (
153
				$verified &&
154
				isset( $verified['type'] ) &&
155
				'blog' === $verified['type']
156
			) {
157
				// Site-level authentication successful.
158
				$this->rest_authentication_status = true;
159
				$this->rest_authentication_type   = 'blog';
160
				return null;
161
			}
162
163
			if (
164
				$verified &&
165
				isset( $verified['type'] ) &&
166
				'user' === $verified['type'] &&
167
				! empty( $verified['user_id'] )
168
			) {
169
				// User-level authentication successful.
170
				$this->rest_authentication_status = true;
171
				$this->rest_authentication_type   = 'user';
172
				return $verified['user_id'];
173
			}
174
175
			// Something else went wrong.  Probably a signature error.
176
			$this->rest_authentication_status = new \WP_Error(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \WP_Error('rest_inva...array('status' => 400)) of type object<WP_Error> is incompatible with the declared type boolean of property $rest_authentication_status.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
177
				'rest_invalid_signature',
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'rest_invalid_signature'.

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...
178
				__( 'The request is not signed correctly.', 'jetpack' ),
179
				array( 'status' => 400 )
180
			);
181
			return null;
182
		} finally {
183
			$this->doing_determine_current_user_filter = false;
184
		}
185
	}
186
187
	/**
188
	 * Report authentication status to the WP REST API.
189
	 *
190
	 * @param  WP_Error|mixed $value Error from another authentication handler, null if we should handle it, or another value if not.
191
	 * @return WP_Error|boolean|null {@see WP_JSON_Server::check_authentication}
192
	 */
193
	public function wp_rest_authentication_errors( $value ) {
194
		if ( null !== $value ) {
195
			return $value;
196
		}
197
		return $this->rest_authentication_status;
198
	}
199
200
	/**
201
	 * Resets the saved authentication state in between testing requests.
202
	 */
203
	public function reset_saved_auth_state() {
204
		$this->rest_authentication_status = null;
205
		$this->connection_manager->reset_saved_auth_state();
206
	}
207
208
	/**
209
	 * Whether the request was signed with a blog token.
210
	 *
211
	 * @since 9.9.0
212
	 *
213
	 * @return bool True if the request was signed with a valid blog token, false otherwise.
214
	 */
215
	public static function is_signed_with_blog_token() {
216
		$instance = self::init();
217
218
		return true === $instance->rest_authentication_status && 'blog' === $instance->rest_authentication_type;
219
	}
220
}
221