Completed
Push — fix/full-sync-without-queue ( 3caf30...83adca )
by
unknown
88:14 queued 77:44
created

Jetpack_SSO::admin_enqueue_scripts()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 2
nop 0
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
require_once( JETPACK__PLUGIN_DIR . 'modules/sso/class.jetpack-sso-helpers.php' );
3
4
/**
5
 * Module Name: Single Sign On
6
 * Module Description: Secure user authentication with WordPress.com.
7
 * Jumpstart Description: Lets you log in to all your Jetpack-enabled sites with one click using your WordPress.com account.
8
 * Sort Order: 30
9
 * Recommendation Order: 5
10
 * First Introduced: 2.6
11
 * Requires Connection: Yes
12
 * Auto Activate: No
13
 * Module Tags: Developers
14
 * Feature: Security, Jumpstart
15
 * Additional Search Queries: sso, single sign on, login, log in
16
 */
17
18
class Jetpack_SSO {
19
	static $instance = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $instance.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
20
21
	private function __construct() {
22
23
		self::$instance = $this;
24
25
		add_action( 'admin_init',             array( $this, 'maybe_authorize_user_after_sso' ), 1 );
26
		add_action( 'admin_init',             array( $this, 'register_settings' ) );
27
		add_action( 'login_init',             array( $this, 'login_init' ) );
28
		add_action( 'delete_user',            array( $this, 'delete_connection_for_user' ) );
29
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
30
		add_action( 'init',                   array( $this, 'maybe_logout_user' ), 5 );
31
		add_action( 'jetpack_modules_loaded', array( $this, 'module_configure_button' ) );
32
		add_action( 'login_form_logout',      array( $this, 'store_wpcom_profile_cookies_on_logout' ) );
33
		add_action( 'wp_login',               array( 'Jetpack_SSO', 'clear_wpcom_profile_cookies' ) );
34
		add_action( 'jetpack_unlinked_user',  array( $this, 'delete_connection_for_user') );
35
36
		// Adding this action so that on login_init, the action won't be sanitized out of the $action global.
37
		add_action( 'login_form_jetpack-sso', '__return_true' );
38
	}
39
40
	/**
41
	 * Returns the single instance of the Jetpack_SSO object
42
	 *
43
	 * @since 2.8
44
	 * @return Jetpack_SSO
45
	 **/
46
	public static function get_instance() {
47
		if ( ! is_null( self::$instance ) ) {
48
			return self::$instance;
49
		}
50
51
		return self::$instance = new Jetpack_SSO;
52
	}
53
54
	/**
55
	 * Add configure button and functionality to the module card on the Jetpack screen
56
	 **/
57
	public static function module_configure_button() {
58
		Jetpack::enable_module_configurable( __FILE__ );
59
		Jetpack::module_configuration_load( __FILE__, array( __CLASS__, 'module_configuration_load' ) );
60
		Jetpack::module_configuration_head( __FILE__, array( __CLASS__, 'module_configuration_head' ) );
61
		Jetpack::module_configuration_screen( __FILE__, array( __CLASS__, 'module_configuration_screen' ) );
62
	}
63
64
	public static function module_configuration_load() {}
65
66
	public static function module_configuration_head() {}
67
68
	public static function module_configuration_screen() {
69
		?>
70
		<form method="post" action="options.php">
71
			<?php settings_fields( 'jetpack-sso' ); ?>
72
			<?php do_settings_sections( 'jetpack-sso' ); ?>
73
			<?php submit_button(); ?>
74
		</form>
75
		<?php
76
	}
77
78
	/**
79
	 * When the default login form is hidden, this method is called on the 'authenticate' filter with a priority of 30.
80
	 * This method disables the ability to submit the default login form.
81
	 *
82
	 * @param $user
83
	 *
84
	 * @return WP_Error
85
	 */
86
	public function disable_default_login_form( $user ) {
87
		if ( is_wp_error( $user ) ) {
88
			return $user;
89
		}
90
91
		/**
92
		 * Since we're returning an error that will be shown as a red notice, let's remove the
93
		 * informational "blue" notice.
94
		 */
95
		remove_filter( 'login_message', array( $this, 'msg_login_by_jetpack' ) );
96
		return new WP_Error( 'jetpack_sso_required', $this->get_sso_required_message() );
97
	}
98
99
	/**
100
	 * If jetpack_force_logout == 1 in current user meta the user will be forced
101
	 * to logout and reauthenticate with the site.
102
	 **/
103
	public function maybe_logout_user() {
104
		global $current_user;
105
106
		if ( 1 == $current_user->jetpack_force_logout ) {
107
			delete_user_meta( $current_user->ID, 'jetpack_force_logout' );
108
			self::delete_connection_for_user( $current_user->ID );
109
			wp_logout();
110
			wp_safe_redirect( wp_login_url() );
111
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method maybe_logout_user() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
112
		}
113
	}
114
115
	/**
116
	 * Adds additional methods the WordPress xmlrpc API for handling SSO specific features
117
	 *
118
	 * @param array $methods
119
	 * @return array
120
	 **/
121
	public function xmlrpc_methods( $methods ) {
122
		$methods['jetpack.userDisconnect'] = array( $this, 'xmlrpc_user_disconnect' );
123
		return $methods;
124
	}
125
126
	/**
127
	 * Marks a user's profile for disconnect from WordPress.com and forces a logout
128
	 * the next time the user visits the site.
129
	 **/
130
	public function xmlrpc_user_disconnect( $user_id ) {
131
		$user_query = new WP_User_Query(
132
			array(
133
				'meta_key' => 'wpcom_user_id',
134
				'meta_value' => $user_id,
135
			)
136
		);
137
		$user = $user_query->get_results();
138
		$user = $user[0];
139
140
		if ( $user instanceof WP_User ) {
0 ignored issues
show
Bug introduced by
The class WP_User 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...
141
			$user = wp_set_current_user( $user->ID );
142
			update_user_meta( $user->ID, 'jetpack_force_logout', '1' );
143
			self::delete_connection_for_user( $user->ID );
144
			return true;
145
		}
146
		return false;
147
	}
148
149
	/**
150
	 * Enqueues scripts and styles necessary for SSO login.
151
	 */
152
	public function login_enqueue_scripts() {
153
		global $action;
154
155
		if ( ! in_array( $action, array( 'jetpack-sso', 'login' ) ) ) {
156
			return;
157
		}
158
159
		if ( is_rtl() ) {
160
			wp_enqueue_style( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login-rtl.css', JETPACK__PLUGIN_FILE ), array( 'login', 'genericons' ), JETPACK__VERSION );
161
		} else {
162
			wp_enqueue_style( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.css', JETPACK__PLUGIN_FILE ), array( 'login', 'genericons' ), JETPACK__VERSION );
163
		}
164
165
		wp_enqueue_script( 'jetpack-sso-login', plugins_url( 'modules/sso/jetpack-sso-login.js', JETPACK__PLUGIN_FILE ), array( 'jquery' ), JETPACK__VERSION );
166
	}
167
168
	/**
169
	 * Adds Jetpack SSO classes to login body
170
	 *
171
	 * @param  array $classes Array of classes to add to body tag
172
	 * @return array          Array of classes to add to body tag
173
	 */
174
	public function login_body_class( $classes ) {
175
		global $action;
176
177
		if ( ! in_array( $action, array( 'jetpack-sso', 'login' ) ) ) {
178
			return $classes;
179
		}
180
181
		// Always add the jetpack-sso class so that we can add SSO specific styling even when the SSO form isn't being displayed.
182
		$classes[] = 'jetpack-sso';
183
184
		/**
185
		 * Should we show the SSO login form?
186
		 *
187
		 * $_GET['jetpack-sso-default-form'] is used to provide a fallback in case JavaScript is not enabled.
188
		 *
189
		 * The default_to_sso_login() method allows us to dynamically decide whether we show the SSO login form or not.
190
		 * The SSO module uses the method to display the default login form if we can not find a user to log in via SSO.
191
		 * But, the method could be filtered by a site admin to always show the default login form if that is preferred.
192
		 */
193
		if ( empty( $_GET['jetpack-sso-show-default-form'] ) && Jetpack_SSO_Helpers::show_sso_login() ) {
194
			$classes[] = 'jetpack-sso-form-display';
195
		}
196
197
		return $classes;
198
	}
199
200
	/**
201
	 * Adds settings fields to Settings > General > Single Sign On that allows users to
202
	 * turn off the login form on wp-login.php
203
	 *
204
	 * @since 2.7
205
	 **/
206
	public function register_settings() {
207
208
		add_settings_section(
209
			'jetpack_sso_settings',
210
			__( 'Single Sign On' , 'jetpack' ),
211
			'__return_false',
212
			'jetpack-sso'
213
		);
214
215
		/*
216
		 * Settings > General > Single Sign On
217
		 * Require two step authentication
218
		 */
219
		register_setting(
220
			'jetpack-sso',
221
			'jetpack_sso_require_two_step',
222
			array( $this, 'validate_jetpack_sso_require_two_step' )
223
		);
224
225
		add_settings_field(
226
			'jetpack_sso_require_two_step',
227
			'', // __( 'Require Two-Step Authentication' , 'jetpack' ),
228
			array( $this, 'render_require_two_step' ),
229
			'jetpack-sso',
230
			'jetpack_sso_settings'
231
		);
232
233
		/*
234
		 * Settings > General > Single Sign On
235
		 */
236
		register_setting(
237
			'jetpack-sso',
238
			'jetpack_sso_match_by_email',
239
			array( $this, 'validate_jetpack_sso_match_by_email' )
240
		);
241
242
		add_settings_field(
243
			'jetpack_sso_match_by_email',
244
			'', // __( 'Match by Email' , 'jetpack' ),
245
			array( $this, 'render_match_by_email' ),
246
			'jetpack-sso',
247
			'jetpack_sso_settings'
248
		);
249
	}
250
251
	/**
252
	 * Builds the display for the checkbox allowing user to require two step
253
	 * auth be enabled on WordPress.com accounts before login. Displays in Settings > General
254
	 *
255
	 * @since 2.7
256
	 **/
257
	public function render_require_two_step() {
258
		?>
259
		<label>
260
			<input
261
				type="checkbox"
262
				name="jetpack_sso_require_two_step"
263
				<?php checked( Jetpack_SSO_Helpers::is_two_step_required() ); ?>
264
				<?php disabled( Jetpack_SSO_Helpers::is_require_two_step_checkbox_disabled() ); ?>
265
			>
266
			<?php esc_html_e( 'Require Two-Step Authentication' , 'jetpack' ); ?>
267
		</label>
268
		<?php
269
	}
270
271
	/**
272
	 * Validate the require  two step checkbox in Settings > General
273
	 *
274
	 * @since 2.7
275
	 * @return boolean
276
	 **/
277
	public function validate_jetpack_sso_require_two_step( $input ) {
278
		return ( ! empty( $input ) ) ? 1 : 0;
279
	}
280
281
	/**
282
	 * Builds the display for the checkbox allowing the user to allow matching logins by email
283
	 * Displays in Settings > General
284
	 *
285
	 * @since 2.9
286
	 **/
287
	public function render_match_by_email() {
288
		?>
289
			<label>
290
				<input
291
					type="checkbox"
292
					name="jetpack_sso_match_by_email"
293
					<?php checked( Jetpack_SSO_Helpers::match_by_email() ); ?>
294
					<?php disabled( Jetpack_SSO_Helpers::is_match_by_email_checkbox_disabled() ); ?>
295
				>
296
				<?php esc_html_e( 'Match by Email', 'jetpack' ); ?>
297
			</label>
298
		<?php
299
	}
300
301
	/**
302
	 * Validate the match by email check in Settings > General
303
	 *
304
	 * @since 2.9
305
	 * @return boolean
306
	 **/
307
	public function validate_jetpack_sso_match_by_email( $input ) {
308
		return ( ! empty( $input ) ) ? 1 : 0;
309
	}
310
311
	/**
312
	 * Checks to determine if the user wants to login on wp-login
313
	 *
314
	 * This function mostly exists to cover the exceptions to login
315
	 * that may exist as other parameters to $_GET[action] as $_GET[action]
316
	 * does not have to exist. By default WordPress assumes login if an action
317
	 * is not set, however this may not be true, as in the case of logout
318
	 * where $_GET[loggedout] is instead set
319
	 *
320
	 * @return boolean
321
	 **/
322
	private function wants_to_login() {
323
		$wants_to_login = false;
324
325
		// Cover default WordPress behavior
326
		$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
327
328
		// And now the exceptions
329
		$action = isset( $_GET['loggedout'] ) ? 'loggedout' : $action;
330
331
		if ( 'login' == $action ) {
332
			$wants_to_login = true;
333
		}
334
335
		return $wants_to_login;
336
	}
337
338
	function login_init() {
339
		global $action;
340
341
		if ( Jetpack_SSO_Helpers::should_hide_login_form() ) {
342
			/**
343
			 * Since the default authenticate filters fire at priority 20 for checking username and password,
344
			 * let's fire at priority 30. wp_authenticate_spam_check is fired at priority 99, but since we return a
345
			 * WP_Error in disable_default_login_form, then we won't trigger spam processing logic.
346
			 */
347
			add_filter( 'authenticate', array( $this, 'disable_default_login_form' ), 30 );
348
349
			/**
350
			 * Filter the display of the disclaimer message appearing when default WordPress login form is disabled.
351
			 *
352
			 * @module sso
353
			 *
354
			 * @since 2.8.0
355
			 *
356
			 * @param bool true Should the disclaimer be displayed. Default to true.
357
			 */
358
			$display_sso_disclaimer = apply_filters( 'jetpack_sso_display_disclaimer', true );
359
			if ( $display_sso_disclaimer ) {
360
				add_filter( 'login_message', array( $this, 'msg_login_by_jetpack' ) );
361
			}
362
		}
363
364
		/**
365
		 * If the user is attempting to logout AND the auto-forward to WordPress.com
366
		 * login is set then we need to ensure we do not auto-forward the user and get
367
		 * them stuck in an infinite logout loop.
368
		 */
369
		if ( isset( $_GET['loggedout'] ) && Jetpack_SSO_Helpers::bypass_login_forward_wpcom() ) {
370
			add_filter( 'jetpack_remove_login_form', '__return_true' );
371
		}
372
373
		/**
374
		 * Check to see if the site admin wants to automagically forward the user
375
		 * to the WordPress.com login page AND  that the request to wp-login.php
376
		 * is not something other than login (Like logout!)
377
		 */
378 View Code Duplication
		if (
379
			$this->wants_to_login()
380
			&& Jetpack_SSO_Helpers::bypass_login_forward_wpcom()
381
		) {
382
			add_filter( 'allowed_redirect_hosts', array( 'Jetpack_SSO_Helpers', 'allowed_redirect_hosts' ) );
383
			$this->maybe_save_cookie_redirect();
384
			$reauth = ! empty( $_GET['force_reauth'] );
385
			$sso_url = $this->get_sso_url_or_die( $reauth );
386
			JetpackTracking::record_user_event( 'sso_login_redirect_bypass_success' );
387
			wp_safe_redirect( $sso_url );
388
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method login_init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
389
		}
390
391
		if ( 'login' === $action ) {
392
			$this->display_sso_login_form();
393
		} elseif ( 'jetpack-sso' === $action ) {
394
			if ( isset( $_GET['result'], $_GET['user_id'], $_GET['sso_nonce'] ) && 'success' == $_GET['result'] ) {
395
				$this->handle_login();
396
				$this->display_sso_login_form();
397
			} else {
398
				if ( Jetpack::check_identity_crisis() ) {
399
					JetpackTracking::record_user_event( 'sso_login_redirect_failed', array(
400
						'error_message' => 'identity_crisis'
401
					) );
402
					add_filter( 'login_message', array( $this, 'error_msg_identity_crisis' ) );
403 View Code Duplication
				} else {
404
					$this->maybe_save_cookie_redirect();
405
					// Is it wiser to just use wp_redirect than do this runaround to wp_safe_redirect?
406
					add_filter( 'allowed_redirect_hosts', array( 'Jetpack_SSO_Helpers', 'allowed_redirect_hosts' ) );
407
					$reauth = ! empty( $_GET['force_reauth'] );
408
					$sso_url = $this->get_sso_url_or_die( $reauth );
409
					JetpackTracking::record_user_event( 'sso_login_redirect_success' );
410
					wp_safe_redirect( $sso_url );
411
					exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method login_init() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
412
				}
413
			}
414
		}
415
	}
416
417
	/**
418
	 * Ensures that we can get a nonce from WordPress.com via XML-RPC before setting
419
	 * up the hooks required to display the SSO form.
420
	 */
421
	public function display_sso_login_form() {
422
		if ( Jetpack::check_identity_crisis() ) {
423
			add_filter( 'login_message', array( $this, 'error_msg_identity_crisis' ) );
424
			return;
425
		}
426
427
		$sso_nonce = self::request_initial_nonce();
428
		if ( is_wp_error( $sso_nonce ) ) {
429
			return;
430
		}
431
432
		add_action( 'login_form',            array( $this, 'login_form' ) );
433
		add_filter( 'login_body_class',      array( $this, 'login_body_class' ) );
434
		add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts' ) );
435
	}
436
437
	/**
438
	 * Conditionally save the redirect_to url as a cookie.
439
	 */
440
	public static function maybe_save_cookie_redirect() {
441
		if ( headers_sent() ) {
442
			return new WP_Error( 'headers_sent', __( 'Cannot deal with cookie redirects, as headers are already sent.', 'jetpack' ) );
443
		}
444
445
		if ( ! empty( $_GET['redirect_to'] ) ) {
446
			// If we have something to redirect to
447
			$url = esc_url_raw( $_GET['redirect_to'] );
448
			setcookie( 'jetpack_sso_redirect_to', $url, time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true );
449
450
		} elseif ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
451
			// Otherwise, if it's already set, purge it.
452
			setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
453
		}
454
	}
455
456
	/**
457
	 * Outputs the Jetpack SSO button and description as well as the toggle link
458
	 * for switching between Jetpack SSO and default login.
459
	 */
460
	function login_form() {
461
		$site_name = get_bloginfo( 'name' );
462
		if ( ! $site_name ) {
463
			$site_name = get_bloginfo( 'url' );
464
		}
465
466
		$display_name = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] )
467
			? $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ]
468
			: false;
469
		$gravatar = ! empty( $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] )
470
			? $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ]
471
			: false;
472
473
		?>
474
		<div id="jetpack-sso-wrap">
475
			<?php if ( $display_name && $gravatar ) : ?>
476
				<div id="jetpack-sso-wrap__user">
477
					<img width="72" height="72" src="<?php echo esc_html( $gravatar ); ?>" />
478
479
					<h2>
480
						<?php
481
							echo wp_kses(
482
								sprintf( __( 'Log in as <span>%s</span>', 'jetpack' ), esc_html( $display_name ) ),
483
								array( 'span' => true )
484
							);
485
						?>
486
					</h2>
487
				</div>
488
489
			<?php endif; ?>
490
491
492
			<div id="jetpack-sso-wrap__action">
493
				<?php echo $this->build_sso_button( array(), 'is_primary' ); ?>
0 ignored issues
show
Documentation introduced by
'is_primary' is of type string, 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...
494
495
				<?php if ( $display_name && $gravatar ) : ?>
496
					<a rel="nofollow" class="jetpack-sso-wrap__reauth" href="<?php echo esc_url( $this->build_sso_button_url( array( 'force_reauth' => '1' ) ) ); ?>">
497
						<?php esc_html_e( 'Log in as a different WordPress.com user', 'jetpack' ); ?>
498
					</a>
499
				<?php else : ?>
500
					<p>
501
						<?php
502
							echo esc_html(
503
								sprintf(
504
									__( 'You can now save time spent logging in by connecting your WordPress.com account to %s.', 'jetpack' ),
505
									esc_html( $site_name )
506
								)
507
							);
508
						?>
509
					</p>
510
				<?php endif; ?>
511
			</div>
512
513
			<?php if ( ! Jetpack_SSO_Helpers::should_hide_login_form() ) : ?>
514
				<div class="jetpack-sso-or">
515
					<span><?php esc_html_e( 'Or', 'jetpack' ); ?></span>
516
				</div>
517
518
				<a href="<?php echo esc_url( add_query_arg( 'jetpack-sso-show-default-form', '1' ) ); ?>" class="jetpack-sso-toggle wpcom">
519
					<?php
520
						esc_html_e( 'Log in with username and password', 'jetpack' )
521
					?>
522
				</a>
523
524
				<a href="<?php echo esc_url( add_query_arg( 'jetpack-sso-show-default-form', '0' ) ); ?>" class="jetpack-sso-toggle default">
525
					<?php
526
						esc_html_e( 'Log in with WordPress.com', 'jetpack' )
527
					?>
528
				</a>
529
			<?php endif; ?>
530
		</div>
531
		<?php
532
	}
533
534
	/**
535
	 * Clear the cookies that store the profile information for the last
536
	 * WPCOM user to connect.
537
	 */
538
	static function clear_wpcom_profile_cookies() {
539 View Code Duplication
		if ( isset( $_COOKIE[ 'jetpack_sso_wpcom_name_' . COOKIEHASH ] ) ) {
540
			setcookie(
541
				'jetpack_sso_wpcom_name_' . COOKIEHASH,
542
				' ',
543
				time() - YEAR_IN_SECONDS,
544
				COOKIEPATH,
545
				COOKIE_DOMAIN
546
			);
547
		}
548
549 View Code Duplication
		if ( isset( $_COOKIE[ 'jetpack_sso_wpcom_gravatar_' . COOKIEHASH ] ) ) {
550
			setcookie(
551
				'jetpack_sso_wpcom_gravatar_' . COOKIEHASH,
552
				' ',
553
				time() - YEAR_IN_SECONDS,
554
				COOKIEPATH,
555
				COOKIE_DOMAIN
556
			);
557
		}
558
	}
559
560
	static function delete_connection_for_user( $user_id ) {
561
		if ( ! $wpcom_user_id = get_user_meta( $user_id, 'wpcom_user_id', true ) ) {
562
			return;
563
		}
564
		Jetpack::load_xml_rpc_client();
565
		$xml = new Jetpack_IXR_Client( array(
566
			'wpcom_user_id' => $user_id,
567
		) );
568
		$xml->query( 'jetpack.sso.removeUser', $wpcom_user_id );
569
570
		if ( $xml->isError() ) {
571
			return false;
572
		}
573
574
		// Clean up local data stored for SSO
575
		delete_user_meta( $user_id, 'wpcom_user_id' );
576
		delete_user_meta( $user_id, 'wpcom_user_data'  );
577
		self::clear_wpcom_profile_cookies();
578
579
		return $xml->getResponse();
580
	}
581
582 View Code Duplication
	static function request_initial_nonce() {
583
		Jetpack::load_xml_rpc_client();
584
		$xml = new Jetpack_IXR_Client( array(
585
			'user_id' => get_current_user_id(),
586
		) );
587
		$xml->query( 'jetpack.sso.requestNonce' );
588
589
		if ( $xml->isError() ) {
590
			return new WP_Error( $xml->getErrorCode(), $xml->getErrorMessage() );
591
		}
592
593
		return $xml->getResponse();
594
	}
595
596
	/**
597
	 * The function that actually handles the login!
598
	 */
599
	function handle_login() {
600
		$wpcom_nonce   = sanitize_key( $_GET['sso_nonce'] );
601
		$wpcom_user_id = (int) $_GET['user_id'];
602
603
		Jetpack::load_xml_rpc_client();
604
		$xml = new Jetpack_IXR_Client( array(
605
			'user_id' => get_current_user_id(),
606
		) );
607
		$xml->query( 'jetpack.sso.validateResult', $wpcom_nonce, $wpcom_user_id );
608
609
		$user_data = $xml->isError() ? false : $xml->getResponse();
610
		if ( empty( $user_data ) ) {
611
			add_filter( 'jetpack_sso_default_to_sso_login', '__return_false' );
612
			add_filter( 'login_message', array( $this, 'error_invalid_response_data' ) );
613
			return;
614
		}
615
616
		$user_data = (object) $user_data;
617
		$user = null;
618
619
		/**
620
		 * Fires before Jetpack's SSO modifies the log in form.
621
		 *
622
		 * @module sso
623
		 *
624
		 * @since 2.6.0
625
		 *
626
		 * @param object $user_data WordPress.com User information.
627
		 */
628
		do_action( 'jetpack_sso_pre_handle_login', $user_data );
629
630
		if ( Jetpack_SSO_Helpers::is_two_step_required() && 0 === (int) $user_data->two_step_enabled ) {
631
			$this->user_data = $user_data;
0 ignored issues
show
Bug introduced by
The property user_data does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
632
633
			JetpackTracking::record_user_event( 'sso_login_failed', array(
634
				'error_message' => 'error_msg_enable_two_step'
635
			) );
636
637
			/** This filter is documented in core/src/wp-includes/pluggable.php */
638
			do_action( 'wp_login_failed', $user_data->login );
639
			add_filter( 'login_message', array( $this, 'error_msg_enable_two_step' ) );
640
			return;
641
		}
642
643
		$user_found_with = '';
644
		if ( empty( $user ) && isset( $user_data->external_user_id ) ) {
645
			$user_found_with = 'external_user_id';
646
			$user = get_user_by( 'id', intval( $user_data->external_user_id ) );
647
			if ( $user ) {
648
				update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
649
			}
650
		}
651
652
		// If we don't have one by wpcom_user_id, try by the email?
653
		if ( empty( $user ) && Jetpack_SSO_Helpers::match_by_email() ) {
654
			$user_found_with = 'match_by_email';
655
			$user = get_user_by( 'email', $user_data->email );
656
			if ( $user ) {
657
				update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
658
			}
659
		}
660
661
		// If we've still got nothing, create the user.
662
		if ( empty( $user ) && ( get_option( 'users_can_register' ) || Jetpack_SSO_Helpers::new_user_override() ) ) {
663
			/**
664
			 * If not matching by email we still need to verify the email does not exist
665
			 * or this blows up
666
			 *
667
			 * If match_by_email is true, we know the email doesn't exist, as it would have
668
			 * been found in the first pass.  If get_user_by( 'email' ) doesn't find the
669
			 * user, then we know that email is unused, so it's safe to add.
670
			 */
671
			if ( Jetpack_SSO_Helpers::match_by_email() || ! get_user_by( 'email', $user_data->email ) ) {
672
				$user = Jetpack_SSO_Helpers::generate_user( $user_data );
673
				if ( ! $user ) {
674
					JetpackTracking::record_user_event( 'sso_login_failed', array(
675
						'error_message' => 'could_not_create_username'
676
					) );
677
					add_filter( 'login_message', array( $this, 'error_unable_to_create_user' ) );
678
					return;
679
				}
680
681
				$user_found_with = Jetpack_SSO_Helpers::new_user_override()
682
					? 'user_created_new_user_override'
683
					: 'user_created_users_can_register';
684
			} else {
685
				JetpackTracking::record_user_event( 'sso_login_failed', array(
686
					'error_message' => 'error_msg_email_already_exists'
687
				) );
688
689
				$this->user_data = $user_data;
690
				add_action( 'login_message', array( $this, 'error_msg_email_already_exists' ) );
691
				return;
692
			}
693
		}
694
695
		/**
696
		 * Fires after we got login information from WordPress.com.
697
		 *
698
		 * @module sso
699
		 *
700
		 * @since 2.6.0
701
		 *
702
		 * @param array  $user      Local User information.
703
		 * @param object $user_data WordPress.com User Login information.
704
		 */
705
		do_action( 'jetpack_sso_handle_login', $user, $user_data );
706
707
		if ( $user ) {
708
			// Cache the user's details, so we can present it back to them on their user screen
709
			update_user_meta( $user->ID, 'wpcom_user_data', $user_data );
710
711
			add_filter( 'auth_cookie_expiration',    array( 'Jetpack_SSO_Helpers', 'extend_auth_cookie_expiration_for_sso' ) );
712
			wp_set_auth_cookie( $user->ID, true );
713
			remove_filter( 'auth_cookie_expiration', array( 'Jetpack_SSO_Helpers', 'extend_auth_cookie_expiration_for_sso' ) );
714
715
			/** This filter is documented in core/src/wp-includes/user.php */
716
			do_action( 'wp_login', $user->user_login, $user );
717
718
			wp_set_current_user( $user->ID );
719
720
			$_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( $_REQUEST['redirect_to'] ) : '';
721
			$redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : self::profile_page_url();
722
723
			// If we have a saved redirect to request in a cookie
724
			if ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
725
				// Set that as the requested redirect to
726
				$redirect_to = $_request_redirect_to = esc_url_raw( $_COOKIE['jetpack_sso_redirect_to'] );
727
				// And then purge it
728
				setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
729
			}
730
731
			$is_user_connected = Jetpack::is_user_connected( $user->ID );
732
			JetpackTracking::record_user_event( 'sso_user_logged_in', array(
733
				'user_found_with' => $user_found_with,
734
				'user_connected'  => (bool) $is_user_connected,
735
				'user_role'       => Jetpack::translate_current_user_to_role()
736
			) );
737
738
			if ( ! $is_user_connected ) {
739
				$calypso_env = ! empty( $_GET['calypso_env'] )
740
					? sanitize_key( $_GET['calypso_env'] )
741
					: '';
742
743
				wp_safe_redirect(
744
					add_query_arg(
745
						array(
746
							'redirect_to'               => $redirect_to,
747
							'request_redirect_to'       => $_request_redirect_to,
748
							'calypso_env'               => $calypso_env,
749
							'jetpack-sso-auth-redirect' => '1',
750
						),
751
						admin_url()
752
					)
753
				);
754
				exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method handle_login() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
755
			}
756
757
			wp_safe_redirect(
758
				/** This filter is documented in core/src/wp-login.php */
759
				apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user )
760
			);
761
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method handle_login() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
762
		}
763
764
		add_filter( 'jetpack_sso_default_to_sso_login', '__return_false' );
765
766
		JetpackTracking::record_user_event( 'sso_login_failed', array(
767
			'error_message' => 'cant_find_user'
768
		) );
769
770
		$this->user_data = $user_data;
771
		/** This filter is documented in core/src/wp-includes/pluggable.php */
772
		do_action( 'wp_login_failed', $user_data->login );
773
		add_filter( 'login_message', array( $this, 'cant_find_user' ) );
774
	}
775
776
	static function profile_page_url() {
777
		return admin_url( 'profile.php' );
778
	}
779
780
	/**
781
	 * Builds the "Login to WordPress.com" button that is displayed on the login page as well as user profile page.
782
	 *
783
	 * @param  array   $args       An array of arguments to add to the SSO URL.
784
	 * @param  boolean $is_primary Should the button have the `button-primary` class?
785
	 * @return string              Returns the HTML markup for the button.
786
	 */
787
	function build_sso_button( $args = array(), $is_primary = false ) {
788
		$url = $this->build_sso_button_url( $args );
789
		$classes = $is_primary
790
			? 'jetpack-sso button button-primary'
791
			: 'jetpack-sso button';
792
793
		return sprintf(
794
			'<a rel="nofollow" href="%1$s" class="%2$s"><span>%3$s %4$s</span></a>',
795
			esc_url( $url ),
796
			$classes,
797
			'<span class="genericon genericon-wordpress"></span>',
798
			esc_html__( 'Log in with WordPress.com', 'jetpack' )
799
		);
800
	}
801
802
	/**
803
	 * Builds a URL with `jetpack-sso` action and option args which is used to setup SSO.
804
	 *
805
	 * @param  array  $args An array of arguments to add to the SSO URL.
806
	 * @return string       The URL used for SSO.
807
	 */
808
	function build_sso_button_url( $args = array() ) {
809
		$defaults = array(
810
			'action'  => 'jetpack-sso',
811
		);
812
813
		$args = wp_parse_args( $args, $defaults );
814
815
		if ( ! empty( $_GET['redirect_to'] ) ) {
816
			$args['redirect_to'] = urlencode( esc_url_raw( $_GET['redirect_to'] ) );
817
		}
818
819
		return add_query_arg( $args, wp_login_url() );
820
	}
821
822
	/**
823
	 * Retrieves a WordPress.com SSO URL with appropriate query parameters or dies.
824
	 *
825
	 * @param  boolean  $reauth  Should the user be forced to reauthenticate on WordPress.com?
826
	 * @param  array    $args    Optional query parameters.
827
	 * @return string            The WordPress.com SSO URL.
828
	 */
829
	function get_sso_url_or_die( $reauth = false, $args = array() ) {
830
		if ( empty( $reauth ) ) {
831
			$sso_redirect = $this->build_sso_url( $args );
832
		} else {
833
			self::clear_wpcom_profile_cookies();
834
			$sso_redirect = $this->build_reauth_and_sso_url( $args );
835
		}
836
837
		// If there was an error retrieving the SSO URL, then error.
838
		if ( is_wp_error( $sso_redirect ) ) {
839
			$error_message = sanitize_text_field(
840
				sprintf( '%s: %s', $sso_redirect->get_error_code(), $sso_redirect->get_error_message() )
0 ignored issues
show
Bug introduced by
The method get_error_code cannot be called on $sso_redirect (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug introduced by
The method get_error_message cannot be called on $sso_redirect (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
841
			);
842
			JetpackTracking::record_user_event( 'sso_login_redirect_failed', array(
843
				'error_message' => $error_message
844
			) );
845
			wp_die( $error_message );
846
		}
847
848
		return $sso_redirect;
849
	}
850
851
	/**
852
	 * Build WordPress.com SSO URL with appropriate query parameters.
853
	 *
854
	 * @param  array  $args Optional query parameters.
855
	 * @return string       WordPress.com SSO URL
856
	 */
857
	function build_sso_url( $args = array() ) {
858
		$sso_nonce = ! empty( $args['sso_nonce'] ) ? $args['sso_nonce'] : self::request_initial_nonce();
859
		$defaults = array(
860
			'action'       => 'jetpack-sso',
861
			'site_id'      => Jetpack_Options::get_option( 'id' ),
862
			'sso_nonce'    => $sso_nonce,
863
			'calypso_auth' => '1',
864
		);
865
866
		$args = wp_parse_args( $args, $defaults );
867
868
		if ( is_wp_error( $args['sso_nonce'] ) ) {
869
			return $args['sso_nonce'];
870
		}
871
872
		return add_query_arg( $args, 'https://wordpress.com/wp-login.php' );
873
	}
874
875
	/**
876
	 * Build WordPress.com SSO URL with appropriate query parameters,
877
	 * including the parameters necessary to force the user to reauthenticate
878
	 * on WordPress.com.
879
	 *
880
	 * @param  array  $args Optional query parameters.
881
	 * @return string       WordPress.com SSO URL
882
	 */
883
	function build_reauth_and_sso_url( $args = array() ) {
884
		$sso_nonce = ! empty( $args['sso_nonce'] ) ? $args['sso_nonce'] : self::request_initial_nonce();
885
		$redirect = $this->build_sso_url( array( 'force_auth' => '1', 'sso_nonce' => $sso_nonce ) );
886
887
		if ( is_wp_error( $redirect ) ) {
888
			return $redirect;
889
		}
890
891
		$defaults = array(
892
			'action'       => 'jetpack-sso',
893
			'site_id'      => Jetpack_Options::get_option( 'id' ),
894
			'sso_nonce'    => $sso_nonce,
895
			'reauth'       => '1',
896
			'redirect_to'  => urlencode( $redirect ),
897
			'calypso_auth' => '1',
898
		);
899
900
		$args = wp_parse_args( $args, $defaults );
901
902
		if ( is_wp_error( $args['sso_nonce'] ) ) {
903
			return $args['sso_nonce'];
904
		}
905
906
		return add_query_arg( $args, 'https://wordpress.com/wp-login.php' );
907
	}
908
909
	/**
910
	 * Determines local user associated with a given WordPress.com user ID.
911
	 *
912
	 * @since 2.6.0
913
	 *
914
	 * @param int $wpcom_user_id User ID from WordPress.com
915
	 * @return object Local user object if found, null if not.
916
	 */
917
	static function get_user_by_wpcom_id( $wpcom_user_id ) {
918
		$user_query = new WP_User_Query( array(
919
			'meta_key'   => 'wpcom_user_id',
920
			'meta_value' => intval( $wpcom_user_id ),
921
			'number'     => 1,
922
		) );
923
924
		$users = $user_query->get_results();
925
		return $users ? array_shift( $users ) : null;
926
	}
927
928
	/**
929
	 * Error message displayed on the login form when two step is required and
930
	 * the user's account on WordPress.com does not have two step enabled.
931
	 *
932
	 * @since 2.7
933
	 * @param string $message
934
	 * @return string
935
	 **/
936
	public function error_msg_enable_two_step( $message ) {
937
		$error = sprintf(
938
			wp_kses(
939
				__(
940
					'Two-Step Authentication is required to access this site. Please visit your <a href="%1$s" target="_blank">Security Settings</a> to configure <a href="%2$s" target="_blank">Two-step Authentication</a> for your account.',
941
					'jetpack'
942
				),
943
				array(  'a' => array( 'href' => array() ) )
944
			),
945
			'https://wordpress.com/me/security/two-step',
946
			'https://support.wordpress.com/security/two-step-authentication/'
947
		);
948
949
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
950
951
		return $message;
952
	}
953
954
	/**
955
	 * Error message displayed when the user tries to SSO, but match by email
956
	 * is off and they already have an account with their email address on
957
	 * this site.
958
	 *
959
	 * @param string $message
960
	 * @return string
961
	 */
962
	public function error_msg_email_already_exists( $message ) {
963
		$error = sprintf(
964
			wp_kses(
965
				__(
966
					'You already have an account on this site. Please <a href="%1$s">sign in</a> with your username and password and then connect to WordPress.com.',
967
					'jetpack'
968
				),
969
				array(  'a' => array( 'href' => array() ) )
970
			),
971
			esc_url_raw( add_query_arg( 'jetpack-sso-show-default-form', '1', wp_login_url() ) )
972
		);
973
974
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
975
976
		return $message;
977
	}
978
979
	/**
980
	 * Error message that is displayed when the current site is in an identity crisis and SSO can not be used.
981
	 *
982
	 * @since 4.3.2
983
	 *
984
	 * @param string $message All other notices that will be displayed in the login form.
985
	 *
986
	 * @return string         An HTML string that includes the identity crisis error notice.
987
	 */
988
	public function error_msg_identity_crisis( $message ) {
989
		$error = esc_html__( 'Logging in with WordPress.com is not currently available because this site is experiencing connection problems.', 'jetpack' );
990
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
991
		return $message;
992
	}
993
994
	/**
995
	 * Error message that is displayed when we are not able to verify the SSO nonce due to an XML error or
996
	 * failed validation. In either case, we prompt the user to try again or log in with username and password.
997
	 *
998
	 * @since 4.3.2
999
	 *
1000
	 * @param string $message All other notices that will be displayed in the login form.
1001
	 *
1002
	 * @return string         An HTML string that includes the invalid response data error notice.
1003
	 */
1004
	public function error_invalid_response_data( $message ) {
1005
		$error = esc_html__(
1006
			'There was an error logging you in via WordPress.com, please try again or try logging in with your username and password.',
1007
			'jetpack'
1008
		);
1009
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
1010
		return $message;
1011
	}
1012
1013
	/**
1014
	 * Error message that is displayed when we were not able to automatically create an account for a user
1015
	 * after a user has logged in via SSO. By default, this message is triggered after trying to create an account 5 times.
1016
	 *
1017
	 * @since 4.3.2
1018
	 *
1019
	 * @param string $message All other notices that will be displayed in the login form.
1020
	 *
1021
	 * @return string         An HTML string that includes the unable to create user error notice.
1022
	 */
1023
	public function error_unable_to_create_user( $message ) {
1024
		$error = esc_html__(
1025
			'There was an error creating a user for you. Please contact the administrator of your site.',
1026
			'jetpack'
1027
		);
1028
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
1029
		return $message;
1030
	}
1031
1032
	/**
1033
	 * Builds the translation ready string that is to be used when the site hides the default login form.
1034
	 *
1035
	 * @since 4.1.0
1036
	 * @return string
1037
	 */
1038
	public function get_sso_required_message() {
1039
		$msg = esc_html__( 'A WordPress.com account is required to access this site. Click the button below to sign in or create a free WordPress.com account.', 'jetpack' );
1040
1041
		/**
1042
		 * Filter the message displayed when the default WordPress login form is disabled.
1043
		 *
1044
		 * @module sso
1045
		 *
1046
		 * @since 2.8.0
1047
		 *
1048
		 * @param string $msg Disclaimer when default WordPress login form is disabled.
1049
		 */
1050
		return apply_filters( 'jetpack_sso_disclaimer_message', $msg );
1051
	}
1052
1053
	/**
1054
	 * Message displayed when the site admin has disabled the default WordPress
1055
	 * login form in Settings > General > Single Sign On
1056
	 *
1057
	 * @since 2.7
1058
	 * @param string $message
1059
	 *
1060
	 * @return string
1061
	 **/
1062
	public function msg_login_by_jetpack( $message ) {
1063
		$msg = $this->get_sso_required_message();
1064
1065
		if ( empty( $msg ) ) {
1066
			return $message;
1067
		}
1068
1069
		$message .= sprintf( '<p class="message">%s</p>', $msg );
1070
		return $message;
1071
	}
1072
1073
	/**
1074
	 * Message displayed when the user can not be found after approving the SSO process on WordPress.com
1075
	 *
1076
	 * @param string $message
1077
	 * @return string
1078
	 */
1079
	function cant_find_user( $message ) {
1080
		$error = esc_html__(
1081
			"We couldn't find your account. If you already have an account, make sure you have connected to WordPress.com.",
1082
			'jetpack'
1083
		);
1084
		$message .= sprintf( '<p class="message" id="login_error">%s</p>', $error );
1085
1086
		return $message;
1087
	}
1088
1089
	/**
1090
	 * When jetpack-sso-auth-redirect query parameter is set, will redirect user to
1091
	 * WordPress.com authorization flow.
1092
	 *
1093
	 * We redirect here instead of in handle_login() because Jetpack::init()->build_connect_url
1094
	 * calls menu_page_url() which doesn't work properly until admin menus are registered.
1095
	 */
1096
	function maybe_authorize_user_after_sso() {
1097
		if ( empty( $_GET['jetpack-sso-auth-redirect'] ) ) {
1098
			return;
1099
		}
1100
1101
		$redirect_to = ! empty( $_GET['redirect_to'] ) ? esc_url_raw( $_GET['redirect_to'] ) : admin_url();
1102
		$request_redirect_to = ! empty( $_GET['request_redirect_to'] ) ? esc_url_raw( $_GET['request_redirect_to'] ) : $redirect_to;
1103
1104
		/** This filter is documented in core/src/wp-login.php */
1105
		$redirect_after_auth = apply_filters( 'login_redirect', $redirect_to, $request_redirect_to, wp_get_current_user() );
1106
1107
		/**
1108
		 * Since we are passing this redirect to WordPress.com and therefore can not use wp_safe_redirect(),
1109
		 * let's sanitize it here to make sure it's safe. If the redirect is not safe, then use admin_url().
1110
		 */
1111
		$redirect_after_auth = wp_sanitize_redirect( $redirect_after_auth );
1112
		$redirect_after_auth = wp_validate_redirect( $redirect_after_auth, admin_url() );
1113
1114
		/**
1115
		 * Return the raw connect URL with our redirect and attribute connection to SSO.
1116
		 */
1117
		$connect_url = Jetpack::init()->build_connect_url( true, $redirect_after_auth, 'sso' );
1118
1119
		add_filter( 'allowed_redirect_hosts', array( 'Jetpack_SSO_Helpers', 'allowed_redirect_hosts' ) );
1120
		wp_safe_redirect( $connect_url );
1121
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method maybe_authorize_user_after_sso() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1122
	}
1123
1124
	/**
1125
	 * Cache user's display name and Gravatar so it can be displayed on the login screen. These cookies are
1126
	 * stored when the user logs out, and then deleted when the user logs in.
1127
	 */
1128
	function store_wpcom_profile_cookies_on_logout() {
1129
		if ( ! Jetpack::is_user_connected( get_current_user_id() ) ) {
1130
			return;
1131
		}
1132
1133
		$user_data = $this->get_user_data( get_current_user_id() );
1134
		if ( ! $user_data ) {
1135
			return;
1136
		}
1137
1138
		setcookie(
1139
			'jetpack_sso_wpcom_name_' . COOKIEHASH,
1140
			$user_data->display_name,
1141
			time() + WEEK_IN_SECONDS,
1142
			COOKIEPATH,
1143
			COOKIE_DOMAIN
1144
		);
1145
1146
		setcookie(
1147
			'jetpack_sso_wpcom_gravatar_' . COOKIEHASH,
1148
			get_avatar_url(
1149
				$user_data->email,
1150
				array( 'size' => 144, 'default' => 'mystery' )
1151
			),
1152
			time() + WEEK_IN_SECONDS,
1153
			COOKIEPATH,
1154
			COOKIE_DOMAIN
1155
		);
1156
	}
1157
1158
	/**
1159
	 * Determines if a local user is connected to WordPress.com
1160
	 *
1161
	 * @since 2.8
1162
	 * @param integer $user_id - Local user id
1163
	 * @return boolean
1164
	 **/
1165
	public function is_user_connected( $user_id ) {
1166
		return $this->get_user_data( $user_id );
1167
	}
1168
1169
	/**
1170
	 * Retrieves a user's WordPress.com data
1171
	 *
1172
	 * @since 2.8
1173
	 * @param integer $user_id - Local user id
1174
	 * @return mixed null or stdClass
1175
	 **/
1176
	public function get_user_data( $user_id ) {
1177
		return get_user_meta( $user_id, 'wpcom_user_data', true );
1178
	}
1179
}
1180
1181
Jetpack_SSO::get_instance();
1182