Completed
Push — instant-search-master ( 95535d...2c1eb1 )
by
unknown
22:37 queued 16:04
created

Jetpack_WPCOM_Block_Editor   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 566
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 566
rs 3.52
c 0
b 0
f 0
wmc 61
lcom 1
cbo 5

22 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 9 2
A enqueue_block_assets() 0 5 1
A has_justified_block() 0 12 3
A add_tinymce_plugins() 0 15 4
A __construct() 0 13 2
A is_iframed_block_editor() 0 6 3
A disable_send_frame_options_header() 0 6 2
A add_iframed_body_class() 0 8 2
B allow_block_editor_login() 0 29 6
A add_login_message() 0 6 1
A add_login_html() 0 11 1
A do_redirect() 0 4 1
A framing_allowed() 0 13 4
B verify_frame_nonce() 0 46 8
A filter_salt() 0 11 3
B enqueue_block_editor_assets() 0 87 8
A enable_cross_site_auth_cookies() 0 17 2
A get_samesite_attr_for_auth_cookies() 0 14 2
A set_samesite_auth_cookies() 0 36 2
A set_samesite_logged_in_cookies() 0 32 2
A disable_core_auth_cookies() 0 3 1
A clear_auth_cookies() 0 28 1

How to fix   Complexity   

Complex Class

Complex classes like Jetpack_WPCOM_Block_Editor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Jetpack_WPCOM_Block_Editor, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * WordPress.com Block Editor
4
 * Allow new block editor posts to be composed on WordPress.com.
5
 * This is auto-loaded as of Jetpack v7.4 for sites connected to WordPress.com only.
6
 *
7
 * @package Jetpack
8
 */
9
10
/**
11
 * WordPress.com Block editor for Jetpack
12
 */
13
class Jetpack_WPCOM_Block_Editor {
14
	/**
15
	 * ID of the user who signed the nonce.
16
	 *
17
	 * @var int
18
	 */
19
	private $nonce_user_id;
20
21
	/**
22
	 * Singleton
23
	 */
24
	public static function init() {
25
		static $instance = false;
26
27
		if ( ! $instance ) {
28
			$instance = new Jetpack_WPCOM_Block_Editor();
29
		}
30
31
		return $instance;
32
	}
33
34
	/**
35
	 * Jetpack_WPCOM_Block_Editor constructor.
36
	 */
37
	private function __construct() {
38
		if ( $this->is_iframed_block_editor() ) {
39
			add_action( 'admin_init', array( $this, 'disable_send_frame_options_header' ), 9 );
40
			add_filter( 'admin_body_class', array( $this, 'add_iframed_body_class' ) );
41
		}
42
43
		add_action( 'login_init', array( $this, 'allow_block_editor_login' ), 1 );
44
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ), 9 );
45
		add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_assets' ) );
46
		add_filter( 'mce_external_plugins', array( $this, 'add_tinymce_plugins' ) );
47
48
		$this->enable_cross_site_auth_cookies();
49
	}
50
51
	/**
52
	 * Checks if we are embedding the block editor in an iframe in WordPress.com.
53
	 *
54
	 * @return bool Whether the current request is from the iframed block editor.
55
	 */
56
	public function is_iframed_block_editor() {
57
		global $pagenow;
58
59
		// phpcs:ignore WordPress.Security.NonceVerification
60
		return ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) && ! empty( $_GET['frame-nonce'] );
61
	}
62
63
	/**
64
	 * Prevents frame options header from firing if this is a whitelisted iframe request.
65
	 */
66
	public function disable_send_frame_options_header() {
67
		// phpcs:ignore WordPress.Security.NonceVerification
68
		if ( $this->framing_allowed( $_GET['frame-nonce'] ) ) {
69
			remove_action( 'admin_init', 'send_frame_options_header' );
70
		}
71
	}
72
73
	/**
74
	 * Adds custom admin body class if this is a whitelisted iframe request.
75
	 *
76
	 * @param string $classes Admin body classes.
77
	 * @return string
78
	 */
79
	public function add_iframed_body_class( $classes ) {
80
		// phpcs:ignore WordPress.Security.NonceVerification
81
		if ( $this->framing_allowed( $_GET['frame-nonce'] ) ) {
82
			$classes .= ' is-iframed ';
83
		}
84
85
		return $classes;
86
	}
87
88
	/**
89
	 * Allows to iframe the login page if a user is logged out
90
	 * while trying to access the block editor from wordpress.com.
91
	 */
92
	public function allow_block_editor_login() {
93
		// phpcs:ignore WordPress.Security.NonceVerification
94
		if ( empty( $_REQUEST['redirect_to'] ) ) {
95
			return;
96
		}
97
98
		// phpcs:ignore WordPress.Security.NonceVerification
99
		$query = wp_parse_url( urldecode( $_REQUEST['redirect_to'] ), PHP_URL_QUERY );
100
		$args  = wp_parse_args( $query );
101
102
		// Check nonce and make sure this is a Gutenframe request.
103
		if ( ! empty( $args['frame-nonce'] ) && $this->framing_allowed( $args['frame-nonce'] ) ) {
104
105
			// If SSO is active, we'll let WordPress.com handle authentication...
106
			if ( Jetpack::is_module_active( 'sso' ) ) {
107
				// ...but only if it's not an Atomic site. They already do that.
108
				if ( ! jetpack_is_atomic_site() ) {
109
					add_filter( 'jetpack_sso_bypass_login_forward_wpcom', '__return_true' );
110
				}
111
			} else {
112
				$_REQUEST['interim-login'] = true;
113
				add_action( 'wp_login', array( $this, 'do_redirect' ) );
114
				add_action( 'login_form', array( $this, 'add_login_html' ) );
115
				add_filter( 'wp_login_errors', array( $this, 'add_login_message' ) );
116
				remove_action( 'login_init', 'send_frame_options_header' );
117
				wp_add_inline_style( 'login', '.interim-login #login{padding-top:8%}' );
118
			}
119
		}
120
	}
121
122
	/**
123
	 * Adds a login message.
124
	 *
125
	 * Intended to soften the expectation mismatch of ending up with a login screen rather than the editor.
126
	 *
127
	 * @param WP_Error $errors WP Error object.
128
	 * @return \WP_Error
129
	 */
130
	public function add_login_message( $errors ) {
131
		$errors->remove( 'expired' );
0 ignored issues
show
Bug introduced by
The method remove() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
132
		$errors->add( 'info', __( 'Before we continue, please log in to your Jetpack site.', 'jetpack' ), 'message' );
0 ignored issues
show
Bug introduced by
The method add() does not seem to exist on object<WP_Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
133
134
		return $errors;
135
	}
136
137
	/**
138
	 * Maintains the `redirect_to` parameter in login form links.
139
	 * Adds visual feedback of login in progress.
140
	 */
141
	public function add_login_html() {
142
		?>
143
		<input type="hidden" name="redirect_to" value="<?php echo esc_url( $_REQUEST['redirect_to'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>" />
144
		<script type="application/javascript">
145
			document.getElementById( 'loginform' ).addEventListener( 'submit' , function() {
146
				document.getElementById( 'wp-submit' ).setAttribute( 'disabled', 'disabled' );
147
				document.getElementById( 'wp-submit' ).value = '<?php echo esc_js( __( 'Logging In...', 'jetpack' ) ); ?>';
148
			} );
149
		</script>
150
		<?php
151
	}
152
153
	/**
154
	 * Does the redirect to the block editor.
155
	 */
156
	public function do_redirect() {
157
		wp_safe_redirect( $GLOBALS['redirect_to'] );
158
		exit;
159
	}
160
161
	/**
162
	 * Checks whether this is a whitelisted iframe request.
163
	 *
164
	 * @param string $nonce Nonce to verify.
165
	 * @return bool
166
	 */
167
	public function framing_allowed( $nonce ) {
168
		$verified = $this->verify_frame_nonce( $nonce, 'frame-' . Jetpack_Options::get_option( 'id' ) );
169
170
		if ( is_wp_error( $verified ) ) {
171
			wp_die( $verified ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
172
		}
173
174
		if ( $verified && ! defined( 'IFRAME_REQUEST' ) ) {
175
			define( 'IFRAME_REQUEST', true );
176
		}
177
178
		return (bool) $verified;
179
	}
180
181
	/**
182
	 * Verify that correct nonce was used with time limit.
183
	 *
184
	 * The user is given an amount of time to use the token, so therefore, since the
185
	 * UID and $action remain the same, the independent variable is the time.
186
	 *
187
	 * @param string $nonce Nonce that was used in the form to verify.
188
	 * @param string $action Should give context to what is taking place and be the same when nonce was created.
189
	 * @return boolean|WP_Error Whether the nonce is valid.
190
	 */
191
	public function verify_frame_nonce( $nonce, $action ) {
192
		if ( empty( $nonce ) ) {
193
			return false;
194
		}
195
196
		list( $expiration, $user_id, $hash ) = explode( ':', $nonce, 3 );
197
198
		$this->nonce_user_id = (int) $user_id;
199
		if ( ! $this->nonce_user_id ) {
200
			return false;
201
		}
202
203
		$token = Jetpack_Data::get_access_token( $this->nonce_user_id );
0 ignored issues
show
Documentation introduced by
$this->nonce_user_id is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
204
		if ( ! $token ) {
205
			return false;
206
		}
207
208
		/*
209
		 * Failures must return `false` (blocking the iframe) prior to the
210
		 * signature verification.
211
		 */
212
213
		add_filter( 'salt', array( $this, 'filter_salt' ), 10, 2 );
214
		$expected_hash = wp_hash( "$expiration|$action|{$this->nonce_user_id}", 'jetpack_frame_nonce' );
215
		remove_filter( 'salt', array( $this, 'filter_salt' ) );
216
217
		if ( ! hash_equals( $hash, $expected_hash ) ) {
218
			return false;
219
		}
220
221
		/*
222
		 * Failures may return `WP_Error` (showing an error in the iframe) after the
223
		 * signature verification passes.
224
		 */
225
226
		if ( time() > $expiration ) {
227
			return new WP_Error( 'nonce_invalid_expired', 'Expired nonce.', array( 'status' => 401 ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'nonce_invalid_expired'.

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...
228
		}
229
230
		// Check if it matches the current user, unless they're trying to log in.
231
		if ( get_current_user_id() !== $this->nonce_user_id && ! doing_action( 'login_init' ) ) {
232
			return new WP_Error( 'nonce_invalid_user_mismatch', 'User ID mismatch.', array( 'status' => 401 ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'nonce_invalid_user_mismatch'.

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...
233
		}
234
235
		return true;
236
	}
237
238
	/**
239
	 * Filters the WordPress salt.
240
	 *
241
	 * @param string $salt Salt for the given scheme.
242
	 * @param string $scheme Authentication scheme.
243
	 * @return string
244
	 */
245
	public function filter_salt( $salt, $scheme ) {
246
		if ( 'jetpack_frame_nonce' === $scheme ) {
247
			$token = Jetpack_Data::get_access_token( $this->nonce_user_id );
0 ignored issues
show
Documentation introduced by
$this->nonce_user_id is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
248
249
			if ( $token ) {
250
				$salt = $token->secret;
251
			}
252
		}
253
254
		return $salt;
255
	}
256
257
	/**
258
	 * Enqueues the WordPress.com block editor integration assets for the editor.
259
	 */
260
	public function enqueue_block_editor_assets() {
261
		$debug   = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
262
		$version = gmdate( 'Ymd' );
263
264
		wp_enqueue_script(
265
			'wpcom-block-editor-default-editor-script',
266
			$debug
267
				? '//widgets.wp.com/wpcom-block-editor/default.editor.js?minify=false'
268
				: '//widgets.wp.com/wpcom-block-editor/default.editor.min.js',
269
			array(
270
				'jquery',
271
				'lodash',
272
				'wp-compose',
273
				'wp-data',
274
				'wp-editor',
275
				'wp-element',
276
				'wp-rich-text',
277
			),
278
			$version,
279
			true
280
		);
281
282
		wp_localize_script(
283
			'wpcom-block-editor-default-editor-script',
284
			'wpcomGutenberg',
285
			array(
286
				'switchToClassic' => array(
287
					'isVisible' => $this->is_iframed_block_editor(),
288
					'label'     => __( 'Switch to Classic Editor', 'jetpack' ),
289
					'url'       => Jetpack_Calypsoify::getInstance()->get_switch_to_classic_editor_url(),
290
				),
291
				'richTextToolbar' => array(
292
					'justify'   => __( 'Justify', 'jetpack' ),
293
					'underline' => __( 'Underline', 'jetpack' ),
294
				),
295
			)
296
		);
297
298
		if ( jetpack_is_atomic_site() ) {
299
			wp_enqueue_script(
300
				'wpcom-block-editor-wpcom-editor-script',
301
				$debug
302
					? '//widgets.wp.com/wpcom-block-editor/wpcom.editor.js?minify=false'
303
					: '//widgets.wp.com/wpcom-block-editor/wpcom.editor.min.js',
304
				array(
305
					'lodash',
306
					'wp-blocks',
307
					'wp-data',
308
					'wp-dom-ready',
309
					'wp-plugins',
310
				),
311
				$version,
312
				true
313
			);
314
		}
315
316
		if ( $this->is_iframed_block_editor() ) {
317
			wp_enqueue_script(
318
				'wpcom-block-editor-calypso-editor-script',
319
				$debug
320
					? '//widgets.wp.com/wpcom-block-editor/calypso.editor.js?minify=false'
321
					: '//widgets.wp.com/wpcom-block-editor/calypso.editor.min.js',
322
				array(
323
					'calypsoify_wpadminmods_js',
324
					'jquery',
325
					'lodash',
326
					'react',
327
					'wp-blocks',
328
					'wp-data',
329
					'wp-hooks',
330
					'wp-tinymce',
331
					'wp-url',
332
				),
333
				$version,
334
				true
335
			);
336
337
			wp_enqueue_style(
338
				'wpcom-block-editor-calypso-editor-styles',
339
				$debug
340
					? '//widgets.wp.com/wpcom-block-editor/calypso.editor.css?minify=false'
341
					: '//widgets.wp.com/wpcom-block-editor/calypso.editor.min.css',
342
				array(),
343
				$version
344
			);
345
		}
346
	}
347
348
	/**
349
	 * Enqueues the WordPress.com block editor integration assets for both editor and front-end.
350
	 */
351
	public function enqueue_block_assets() {
352
		// These styles are manually copied from //widgets.wp.com/wpcom-block-editor/default.view.css in order to
353
		// improve the performance by avoiding an extra network request to download the CSS file on every page.
354
		wp_add_inline_style( 'wp-block-library', '.has-text-align-justify{text-align:justify;}' );
355
	}
356
357
	/**
358
	 * Determines if the current $post contains a justified paragraph block.
359
	 *
360
	 * @return boolean true if justified paragraph is found, false otherwise.
361
	 */
362
	public function has_justified_block() {
363
		global $post;
364
		if ( ! $post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
365
			return false;
366
		};
367
368
		if ( ! has_blocks( $post ) ) {
369
			return false;
370
		}
371
372
		return false !== strpos( $post->post_content, '<!-- wp:paragraph {"align":"justify"' );
373
	}
374
375
	/**
376
	 * Register the Tiny MCE plugins for the WordPress.com block editor integration.
377
	 *
378
	 * @param array $plugin_array An array of external Tiny MCE plugins.
379
	 * @return array External TinyMCE plugins.
380
	 */
381
	public function add_tinymce_plugins( $plugin_array ) {
382
		if ( $this->is_iframed_block_editor() ) {
383
			$debug = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
384
385
			$plugin_array['gutenberg-wpcom-iframe-media-modal'] = add_query_arg(
386
				'v',
387
				gmdate( 'YW' ),
388
				$debug
389
					? '//widgets.wp.com/wpcom-block-editor/calypso.tinymce.js?minify=false'
390
					: '//widgets.wp.com/wpcom-block-editor/calypso.tinymce.min.js'
391
			);
392
		}
393
394
		return $plugin_array;
395
	}
396
397
	/**
398
	 * Ensures the authentication cookies are designated for cross-site access.
399
	 */
400
	private function enable_cross_site_auth_cookies() {
401
		/**
402
		 * Allow plugins to disable the cross-site auth cookies.
403
		 *
404
		 * @since 8.1.1
405
		 *
406
		 * @param false bool Whether auth cookies should be disabled for cross-site access. False by default.
407
		 */
408
		if ( apply_filters( 'jetpack_disable_cross_site_auth_cookies', false ) ) {
409
			return;
410
		}
411
412
		add_action( 'set_auth_cookie', array( $this, 'set_samesite_auth_cookies' ), 10, 6 );
413
		add_action( 'set_logged_in_cookie', array( $this, 'set_samesite_logged_in_cookies' ), 10, 6 );
414
		add_action( 'clear_auth_cookie', array( $this, 'clear_auth_cookies' ) );
415
		add_filter( 'send_auth_cookies', array( $this, 'disable_core_auth_cookies' ) );
416
	}
417
418
	/**
419
	 * Gets the SameSite attribute to use in auth cookies.
420
	 *
421
	 * @param  int $user_id User ID.
422
	 * @return string SameSite attribute to use on auth cookies.
423
	 */
424
	public function get_samesite_attr_for_auth_cookies( $user_id ) {
425
		$secure   = apply_filters( 'secure_auth_cookie', is_ssl(), $user_id );
426
		$samesite = $secure ? 'None' : 'Lax';
427
		/**
428
		 * Filters the SameSite attribute to use in auth cookies.
429
		 *
430
		 * @param string $samesite SameSite attribute to use in auth cookies.
431
		 *
432
		 * @since 8.1.1
433
		 */
434
		$samesite = apply_filters( 'jetpack_auth_cookie_samesite', $samesite );
435
436
		return $samesite;
437
	}
438
439
	/**
440
	 * Generates cross-site auth cookies so they can be accessed by WordPress.com.
441
	 *
442
	 * @param string $auth_cookie Authentication cookie value.
443
	 * @param int    $expire      The time the login grace period expires as a UNIX timestamp.
444
	 *                            Default is 12 hours past the cookie's expiration time.
445
	 * @param int    $expiration  The time when the authentication cookie expires as a UNIX timestamp.
446
	 *                            Default is 14 days from now.
447
	 * @param int    $user_id     User ID.
448
	 * @param string $scheme      Authentication scheme. Values include 'auth' or 'secure_auth'.
449
	 * @param string $token       User's session token to use for this cookie.
450
	 */
451
	public function set_samesite_auth_cookies( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
452
		if ( wp_startswith( $scheme, 'secure_' ) ) {
453
			$secure           = true;
454
			$auth_cookie_name = SECURE_AUTH_COOKIE;
455
		} else {
456
			$secure           = false;
457
			$auth_cookie_name = AUTH_COOKIE;
458
		}
459
		$samesite = $this->get_samesite_attr_for_auth_cookies( $user_id );
460
461
		jetpack_shim_setcookie(
462
			$auth_cookie_name,
463
			$auth_cookie,
464
			array(
465
				'expires'  => $expire,
466
				'path'     => PLUGINS_COOKIE_PATH,
467
				'domain'   => COOKIE_DOMAIN,
468
				'secure'   => $secure,
469
				'httponly' => true,
470
				'samesite' => $samesite,
471
			)
472
		);
473
474
		jetpack_shim_setcookie(
475
			$auth_cookie_name,
476
			$auth_cookie,
477
			array(
478
				'expires'  => $expire,
479
				'path'     => ADMIN_COOKIE_PATH,
480
				'domain'   => COOKIE_DOMAIN,
481
				'secure'   => $secure,
482
				'httponly' => true,
483
				'samesite' => $samesite,
484
			)
485
		);
486
	}
487
488
	/**
489
	 * Generates cross-site logged in cookies so they can be accessed by WordPress.com.
490
	 *
491
	 * @param string $logged_in_cookie The logged-in cookie value.
492
	 * @param int    $expire           The time the login grace period expires as a UNIX timestamp.
493
	 *                                 Default is 12 hours past the cookie's expiration time.
494
	 * @param int    $expiration       The time when the logged-in cookie expires as a UNIX timestamp.
495
	 *                                 Default is 14 days from now.
496
	 * @param int    $user_id          User ID.
497
	 * @param string $scheme           Authentication scheme. Default 'logged_in'.
498
	 * @param string $token            User's session token to use for this cookie.
499
	 */
500
	public function set_samesite_logged_in_cookies( $logged_in_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
501
		$secure   = apply_filters( 'secure_auth_cookie', is_ssl(), $user_id );
502
		$samesite = $this->get_samesite_attr_for_auth_cookies( $user_id );
503
504
		jetpack_shim_setcookie(
505
			LOGGED_IN_COOKIE,
506
			$logged_in_cookie,
507
			array(
508
				'expires'  => $expire,
509
				'path'     => COOKIEPATH,
510
				'domain'   => COOKIE_DOMAIN,
511
				'secure'   => $secure,
512
				'httponly' => true,
513
				'samesite' => $samesite,
514
			)
515
		);
516
517
		if ( COOKIEPATH !== SITECOOKIEPATH ) {
518
			jetpack_shim_setcookie(
519
				LOGGED_IN_COOKIE,
520
				$logged_in_cookie,
521
				array(
522
					'expires'  => $expire,
523
					'path'     => SITECOOKIEPATH,
524
					'domain'   => COOKIE_DOMAIN,
525
					'secure'   => $secure,
526
					'httponly' => true,
527
					'samesite' => $samesite,
528
				)
529
			);
530
		}
531
	}
532
533
	/**
534
	 * Prevents the default core auth cookies from being generated so they don't collide with our cross-site cookies.
535
	 *
536
	 * @return bool Whether the default core auth cookies should be generated.
537
	 */
538
	public function disable_core_auth_cookies() {
539
		return false;
540
	}
541
542
	/**
543
	 * Removes all of the cookies associated with authentication.
544
	 *
545
	 * This is copied from core's `wp_clear_auth_cookie` since disabling the core auth cookies prevents also the auth
546
	 * cookies from being cleared.
547
	 *
548
	 * @see wp_clear_auth_cookie
549
	 */
550
	public function clear_auth_cookies() {
551
		// Auth cookies.
552
		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
553
		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
554
		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
555
		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
556
		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
557
		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
558
559
		// Settings cookies.
560
		setcookie( 'wp-settings-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
561
		setcookie( 'wp-settings-time-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
562
563
		// Old cookies.
564
		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
565
		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
566
		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
567
		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
568
569
		// Even older cookies.
570
		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
571
		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
572
		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
573
		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
574
575
		// Post password cookie.
576
		setcookie( 'wp-postpass_' . COOKIEHASH, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
577
	}
578
}
579
580
Jetpack_WPCOM_Block_Editor::init();
581