Completed
Push — fix/rest-authentication-infini... ( e97eef )
by
unknown
14:15 queued 03:20
created

Rest_Authentication::wp_rest_authenticate()   D

Complexity

Conditions 16
Paths 8

Size

Total Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
nc 8
nop 1
dl 0
loc 78
rs 4.9333
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 Manager object.
25
	 *
26
	 * @since 8.9.0
27
	 * @var Object
28
	 */
29
	private $connection_manager = null;
30
31
	/**
32
	 * Holds the singleton instance of this class
33
	 *
34
	 * @since 8.9.0
35
	 * @var Object
36
	 */
37
	private static $instance = false;
38
39
	/**
40
	 * Flag used to avoid determine_current_user filter to enter an infinite loop
41
	 *
42
	 * @since 9.7.0
43
	 * @var boolean
44
	 */
45
	private $doing_determine_current_user_filter = false;
46
47
	/**
48
	 * The constructor.
49
	 */
50
	private function __construct() {
51
		$this->connection_manager = new Manager();
52
	}
53
54
	/**
55
	 * Controls the single instance of this class.
56
	 *
57
	 * @static
58
	 */
59
	public static function init() {
60
		if ( ! self::$instance ) {
61
			self::$instance = new self();
62
63
			add_filter( 'determine_current_user', array( self::$instance, 'wp_rest_authenticate' ) );
64
			add_filter( 'rest_authentication_errors', array( self::$instance, 'wp_rest_authentication_errors' ) );
65
		}
66
67
		return self::$instance;
68
	}
69
70
	/**
71
	 * Authenticates requests from Jetpack server to WP REST API endpoints.
72
	 * Uses the existing XMLRPC request signing implementation.
73
	 *
74
	 * @param int|bool $user User ID if one has been determined, false otherwise.
75
	 *
76
	 * @return int|null The user id or null if the request was not authenticated.
77
	 */
78
	public function wp_rest_authenticate( $user ) {
79
		if ( $this->doing_determine_current_user_filter || ! empty( $user ) ) {
80
			// Another authentication method is in effect.
81
			return $user;
82
		}
83
84
		$this->initialize_determine_current_user_filter();
85
86
		add_filter(
87
			'jetpack_constant_default_value',
88
			__NAMESPACE__ . '\Utils::jetpack_api_constant_filter',
89
			10,
90
			2
91
		);
92
93
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
94
		if ( ! isset( $_GET['_for'] ) || 'jetpack' !== $_GET['_for'] ) {
95
			// Nothing to do for this authentication method.
96
			return $this->return_determine_current_user_filter();
97
		}
98
99
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
100
		if ( ! isset( $_GET['token'] ) && ! isset( $_GET['signature'] ) ) {
101
			// Nothing to do for this authentication method.
102
			return $this->return_determine_current_user_filter();
103
		}
104
105
		if ( ! isset( $_SERVER['REQUEST_METHOD'] ) ) {
106
			$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...
107
				'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...
108
				__( 'The request method is missing.', 'jetpack' ),
109
				array( 'status' => 400 )
110
			);
111
			return $this->return_determine_current_user_filter();
112
		}
113
114
		// Only support specific request parameters that have been tested and
115
		// are known to work with signature verification.  A different method
116
		// can be passed to the WP REST API via the '?_method=' parameter if
117
		// needed.
118
		if ( 'GET' !== $_SERVER['REQUEST_METHOD'] && 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
119
			$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...
120
				'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...
121
				__( 'This request method is not supported.', 'jetpack' ),
122
				array( 'status' => 400 )
123
			);
124
			return $this->return_determine_current_user_filter();
125
		}
126
		if ( 'POST' !== $_SERVER['REQUEST_METHOD'] && ! empty( file_get_contents( 'php://input' ) ) ) {
127
			$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...
128
				'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...
129
				__( 'This request method does not support body parameters.', 'jetpack' ),
130
				array( 'status' => 400 )
131
			);
132
			return $this->return_determine_current_user_filter();
133
		}
134
135
		$verified = $this->connection_manager->verify_xml_rpc_signature();
136
137
		if (
138
			$verified &&
139
			isset( $verified['type'] ) &&
140
			'user' === $verified['type'] &&
141
			! empty( $verified['user_id'] )
142
		) {
143
			// Authentication successful.
144
			$this->rest_authentication_status = true;
145
			return $this->return_determine_current_user_filter( $verified['user_id'] );
146
		}
147
148
		// Something else went wrong.  Probably a signature error.
149
		$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...
150
			'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...
151
			__( 'The request is not signed correctly.', 'jetpack' ),
152
			array( 'status' => 400 )
153
		);
154
		return $this->return_determine_current_user_filter();
155
	}
156
157
	/**
158
	 * Resets determine_current_user filter infinite loop control and returns the value
159
	 *
160
	 * @since 9.7.0
161
	 *
162
	 * @param mixed $value The value to be returned.
163
	 * @return mixed
164
	 */
165
	private function return_determine_current_user_filter( $value = null ) {
166
		$this->doing_determine_current_user_filter = false;
167
		return $value;
168
	}
169
170
	/**
171
	 * Initializes determine_current_user filter infinite loop control
172
	 *
173
	 * @since 9.7.0
174
	 *
175
	 * @return void
176
	 */
177
	private function initialize_determine_current_user_filter() {
178
		$this->doing_determine_current_user_filter = true;
179
	}
180
181
	/**
182
	 * Report authentication status to the WP REST API.
183
	 *
184
	 * @param  WP_Error|mixed $value Error from another authentication handler, null if we should handle it, or another value if not.
185
	 * @return WP_Error|boolean|null {@see WP_JSON_Server::check_authentication}
186
	 */
187
	public function wp_rest_authentication_errors( $value ) {
188
		if ( null !== $value ) {
189
			return $value;
190
		}
191
		return $this->rest_authentication_status;
192
	}
193
194
	/**
195
	 * Resets the saved authentication state in between testing requests.
196
	 */
197
	public function reset_saved_auth_state() {
198
		$this->rest_authentication_status = null;
199
		$this->connection_manager->reset_saved_auth_state();
200
	}
201
}
202