Completed
Push — feature/reorg ( 71bcbc...165e99 )
by
unknown
153:12 queued 137:15
created

class-broken-token.php ➔ broken_token_jetpack_not_active()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php // phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_print_r
2
/**
3
 * Plugin Name: Broken Token
4
 * Description: Give me a Jetpack connection, and I'll break it every way possible.
5
 * Author: Bestpack
6
 * Version: 1.0
7
 * Text Domain: jetpack
8
 *
9
 * @package Jetpack
10
 */
11
12
/**
13
 * Require the XMLRPC functionality.
14
 */
15
require 'inc/class-broken-token-xmlrpc.php';
16
17
/**
18
 * Class Broken_Token
19
 */
20
class Broken_Token {
21
	/**
22
	 * Notice type.
23
	 *
24
	 * @var mixed|string
25
	 */
26
	public $notice_type = '';
27
28
	/**
29
	 * Blog token.
30
	 *
31
	 * @var bool|mixed
32
	 */
33
	public $blog_token;
34
35
	/**
36
	 * User token.
37
	 *
38
	 * @var bool|mixed
39
	 */
40
	public $user_tokens;
41
42
	/**
43
	 * Jetpack Primary User.
44
	 *
45
	 * @var bool|mixed
46
	 */
47
	public $master_user;
48
49
	/**
50
	 * Site ID.
51
	 *
52
	 * @var bool|mixed
53
	 */
54
	public $id;
55
56
	/**
57
	 * Whether the user has agreed to the TOS.
58
	 *
59
	 * @var bool
60
	 */
61
	public $tos_agreed;
62
63
	/**
64
	 * Options.
65
	 */
66
	const STORED_OPTIONS_KEY = 'broken_token_stored_options';
67
68
	/**
69
	 * Token name.
70
	 *
71
	 * @var string
72
	 */
73
	public $invalid_blog_token = 'broken.token';
74
75
	/**
76
	 * User token name.
77
	 *
78
	 * @var string
79
	 */
80
	public $invalid_user_token = 'broken.token.%d';
81
82
	/**
83
	 * Broken_Token constructor.
84
	 */
85
	public function __construct() {
86
		add_action( 'admin_menu', array( $this, 'broken_token_register_submenu_page' ), 1000 );
87
88
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
89
90
		// Stored options.
91
		add_action( 'admin_post_clear_stored_options', array( $this, 'admin_post_clear_stored_options' ) );
92
		add_action( 'admin_post_store_current_options', array( $this, 'admin_post_store_current_options' ) );
93
		add_action( 'admin_post_restore_from_stored_options', array( $this, 'admin_post_restore_from_stored_options' ) );
94
		add_action( 'admin_post_clear_tos', array( $this, 'admin_post_clear_tos' ) );
95
96
		// Break stuff.
97
		add_action( 'admin_post_set_invalid_blog_token', array( $this, 'admin_post_set_invalid_blog_token' ) );
98
		add_action( 'admin_post_set_invalid_user_tokens', array( $this, 'admin_post_set_invalid_user_tokens' ) );
99
		add_action( 'admin_post_set_invalid_current_user_token', array( $this, 'admin_post_set_invalid_current_user_token' ) );
100
		add_action( 'admin_post_clear_blog_token', array( $this, 'admin_post_clear_blog_token' ) );
101
		add_action( 'admin_post_clear_user_tokens', array( $this, 'admin_post_clear_user_tokens' ) );
102
		add_action( 'admin_post_randomize_master_user', array( $this, 'admin_post_randomize_master_user' ) );
103
		add_action( 'admin_post_randomize_master_user_and_token', array( $this, 'admin_post_randomize_master_user_and_token' ) );
104
		add_action( 'admin_post_clear_master_user', array( $this, 'admin_post_clear_master_user' ) );
105
		add_action( 'admin_post_randomize_blog_id', array( $this, 'admin_post_randomize_blog_id' ) );
106
		add_action( 'admin_post_clear_blog_id', array( $this, 'admin_post_clear_blog_id' ) );
107
108
		$this->blog_token  = Jetpack_Options::get_option( 'blog_token' );
109
		$this->user_tokens = Jetpack_Options::get_option( 'user_tokens' );
110
		$this->master_user = Jetpack_Options::get_option( 'master_user' );
111
		$this->id          = Jetpack_Options::get_option( 'id' );
112
		$this->tos_agreed  = Jetpack_Options::get_option( 'tos_agreed' );
113
114
		if ( isset( $_GET['notice'] ) && check_admin_referer( 'jetpack_debug_broken_token_admin_notice', 'nonce' ) ) {
115
			$this->notice_type = $_GET['notice'];
116
			add_action( 'admin_notices', array( $this, 'render_admin_notice' ) );
117
		}
118
	}
119
120
	/**
121
	 * Enqueue scripts.
122
	 *
123
	 * @param string $hook Called hook.
124
	 */
125
	public function enqueue_scripts( $hook ) {
126
		if ( strpos( $hook, 'jetpack_page_broken-token' ) === 0 ) {
127
			wp_enqueue_style( 'broken_token_style', plugin_dir_url( __FILE__ ) . '/css/style.css', array(), JETPACK_DEBUG_HELPER_VERSION );
128
		}
129
	}
130
131
	/**
132
	 * Register's submenu.
133
	 */
134
	public function broken_token_register_submenu_page() {
135
		add_submenu_page(
136
			'jetpack-debug-tools',
137
			'Broken Token',
138
			'Broken Token',
139
			'manage_options',
140
			'broken-token',
141
			array( $this, 'render_ui' ),
142
			99
143
		);
144
	}
145
146
	/**
147
	 * Render UI.
148
	 */
149
	public function render_ui() {
150
		$stored_options = $this->get_stored_connection_options();
151
		?>
152
		<h1>Broken Token 😱!</h1>
153
		<p>This plugin will help you break the Jetpack connection in various ways.</p>
154
		<p>All instances of breaking only involve modifying the local DB options. Nothing done here will alter tokens stored in wp.com</p>
155
		<hr>
156
157
		<h2>Current token options being used by Jetpack:</h2>
158
		<p>Blog Token: <?php echo esc_html( $this->blog_token ); ?></p>
159
		<p>User Tokens: <?php print_r( $this->user_tokens ); ?></p>
160
		<p>Primary User: <?php echo esc_html( $this->master_user ); ?></p>
161
		<p>Blog ID: <?php echo esc_html( $this->id ); ?></p>
162
163
		<?php
164
		if ( $this->tos_agreed ) {
165
			?>
166
			<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
167
				<p>TOS Accepted: ✅ &nbsp;
168
				<input type="hidden" name="action" value="clear_tos">
169
				<?php wp_nonce_field( 'clear-tos' ); ?>
170
				<input type="submit" value="Clear" class="button button-secondary button-small">
171
				</p>
172
			</form>
173
			<?php
174
		} else {
175
			?>
176
			<p>TOS Accepted: ❌</p>
177
			<?php
178
		}
179
		?>
180
181
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
182
			<input type="hidden" name="action" value="store_current_options">
183
			<?php wp_nonce_field( 'store-current-options' ); ?>
184
			<input type="submit" value="Store these options" class="button button-primary">
185
		</form>
186
		<br>
187
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
188
			<input type="hidden" name="action" value="restore_from_stored_options">
189
			<?php wp_nonce_field( 'restore-stored-options' ); ?>
190
			<input type="submit" value="Restore from stored options" class="button button-primary <?php echo empty( $stored_options ) ? 'disabled' : ''; ?>">
191
		</form>
192
193
		<?php
194
		echo '<h2>Stored connection options.</h2>';
195
		echo '<p>Might be useful to store valid connection options before breaking it, so you can restore later.</p>';
196
		if ( empty( $stored_options ) ) {
197
			echo '<p>No connection options are currently stored!</p>';
198
		} else {
199
			echo '<pre>';
200
			print_r( $stored_options );
201
			echo '</pre>';
202
		}
203
		?>
204
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
205
			<input type="hidden" name="action" value="clear_stored_options">
206
			<?php wp_nonce_field( 'clear-stored-options' ); ?>
207
			<input type="submit" value="Clear stored options" class="button button-primary <?php echo empty( $stored_options ) ? 'disabled' : ''; ?>">
208
		</form>
209
210
		<hr>
211
212
		<h2>Break some stuff:</h2>
213
		<p><strong>Break the blog token:</strong></p>
214
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
215
			<input type="hidden" name="action" value="set_invalid_blog_token">
216
			<?php wp_nonce_field( 'set-invalid-blog-token' ); ?>
217
			<input type="submit" value="Set invalid blog token" class="button button-primary button-break-it">
218
		</form>
219
		<br>
220
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
221
			<input type="hidden" name="action" value="clear_blog_token">
222
			<?php wp_nonce_field( 'clear-blog-token' ); ?>
223
			<input type="submit" value="Clear blog token" class="button button-primary button-break-it">
224
		</form>
225
226
		<p><strong>Break the user tokens:</strong></p>
227
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
228
			<input type="hidden" name="action" value="clear_user_tokens">
229
			<?php wp_nonce_field( 'clear-user-tokens' ); ?>
230
			<input type="submit" value="Clear user tokens" class="button button-primary button-break-it">
231
		</form>
232
		<br>
233
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
234
			<input type="hidden" name="action" value="set_invalid_user_tokens">
235
			<?php wp_nonce_field( 'set-invalid-user-tokens' ); ?>
236
			<input type="submit" value="Set invalid user tokens" class="button button-primary button-break-it">
237
		</form>
238
		<br>
239
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
240
			<input type="hidden" name="action" value="set_invalid_current_user_token">
241
			<?php wp_nonce_field( 'set-invalid-current-user-token' ); ?>
242
			<input type="submit" value="Set invalid user token (current user)" class="button button-primary button-break-it">
243
		</form>
244
245
		<p><strong>Break the Primary User:</strong></p>
246
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
247
			<input type="hidden" name="action" value="randomize_master_user">
248
			<?php wp_nonce_field( 'randomize-master-user' ); ?>
249
			<input type="submit" value="Randomize Primary User ID" class="button button-primary button-break-it">
250
		</form>
251
		<br>
252
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
253
			<input type="hidden" name="action" value="randomize_master_user_and_token">
254
			<?php wp_nonce_field( 'randomize-master-user-and-token' ); ?>
255
			<input type="submit" value="Randomize Primary User ID and move the user token together" class="button button-primary button-break-it">
256
		</form>
257
		<br>
258
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
259
			<input type="hidden" name="action" value="clear_master_user">
260
			<?php wp_nonce_field( 'clear-master-user' ); ?>
261
			<input type="submit" value="Clear the Primary User" class="button button-primary button-break-it">
262
		</form>
263
264
		<p><strong>Break the blog ID:</strong></p>
265
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
266
			<input type="hidden" name="action" value="randomize_blog_id">
267
			<?php wp_nonce_field( 'randomize-blog-id' ); ?>
268
			<input type="submit" value="Randomize Blog ID" class="button button-primary button-break-it">
269
		</form>
270
		<br>
271
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
272
			<input type="hidden" name="action" value="clear_blog_id">
273
			<?php wp_nonce_field( 'clear-blog-id' ); ?>
274
			<input type="submit" value="Clear the Blog ID" class="button button-primary button-break-it">
275
		</form>
276
		<?php
277
	}
278
279
	/**
280
	 * Store options.
281
	 */
282
	public function admin_post_store_current_options() {
283
		check_admin_referer( 'store-current-options' );
284
		$this->notice_type = 'store-options';
285
		$this->store_current_options();
286
287
		$this->admin_post_redirect_referrer();
288
	}
289
290
	/**
291
	 * Clear options.
292
	 */
293
	public function admin_post_clear_stored_options() {
294
		check_admin_referer( 'clear-stored-options' );
295
		$this->clear_stored_options();
296
297
		$this->admin_post_redirect_referrer();
298
	}
299
300
	/**
301
	 * Restore from options.
302
	 */
303
	public function admin_post_restore_from_stored_options() {
304
		check_admin_referer( 'restore-stored-options' );
305
		$this->notice_type = 'restore-options';
306
		foreach ( $this->get_stored_connection_options() as $key => $value ) {
307
			if ( empty( $value ) ) {
308
				if ( 'tos_agreed' === $key ) {
309
					Jetpack_Options::delete_option( 'tos_agreed' );
310
				}
311
312
				continue;
313
			}
314
			Jetpack_Options::update_option( $key, $value );
315
		}
316
317
		$this->admin_post_redirect_referrer();
318
	}
319
320
	/**
321
	 * Set invalid blog token.
322
	 */
323
	public function admin_post_set_invalid_blog_token() {
324
		check_admin_referer( 'set-invalid-blog-token' );
325
		$this->notice_type = 'jetpack-broken';
326
		Jetpack_Options::update_option( 'blog_token', $this->invalid_blog_token );
327
328
		$this->admin_post_redirect_referrer();
329
	}
330
331
	/**
332
	 * Set invalid user token.
333
	 */
334 View Code Duplication
	public function admin_post_set_invalid_user_tokens() {
335
		check_admin_referer( 'set-invalid-user-tokens' );
336
		$this->notice_type = 'jetpack-broken';
337
338
		$new_tokens = array();
339
340
		foreach ( Jetpack_Options::get_option( 'user_tokens' ) as $id => $token ) {
341
			$new_tokens[ $id ] = sprintf( $this->invalid_user_token, $id );
342
		}
343
344
		Jetpack_Options::update_option( 'user_tokens', $new_tokens );
345
346
		$this->admin_post_redirect_referrer();
347
	}
348
349
	/**
350
	 * Set invalid current user token.
351
	 */
352 View Code Duplication
	public function admin_post_set_invalid_current_user_token() {
353
		check_admin_referer( 'set-invalid-current-user-token' );
354
		$this->notice_type = 'jetpack-broken';
355
356
		$tokens = Jetpack_Options::get_option( 'user_tokens' );
357
358
		$id            = get_current_user_id();
359
		$tokens[ $id ] = sprintf( $this->invalid_user_token, $id );
360
361
		Jetpack_Options::update_option( 'user_tokens', $tokens );
362
363
		$this->admin_post_redirect_referrer();
364
	}
365
366
	/**
367
	 * Clear blog token.
368
	 */
369
	public function admin_post_clear_blog_token() {
370
		check_admin_referer( 'clear-blog-token' );
371
		$this->notice_type = 'jetpack-broken';
372
		Jetpack_Options::delete_option( 'blog_token' );
373
		$this->admin_post_redirect_referrer();
374
	}
375
376
	/**
377
	 * Clear user token.
378
	 */
379
	public function admin_post_clear_user_tokens() {
380
		check_admin_referer( 'clear-user-tokens' );
381
		$this->notice_type = 'jetpack-broken';
382
		Jetpack_Options::delete_option( 'user_tokens' );
383
		$this->admin_post_redirect_referrer();
384
	}
385
386
	/**
387
	 * Randomize master user.
388
	 */
389
	public function admin_post_randomize_master_user() {
390
		check_admin_referer( 'randomize-master-user' );
391
		$this->notice_type = 'jetpack-broken';
392
		$current_id        = Jetpack_Options::get_option( 'master_user' );
393
		Jetpack_Options::update_option( 'master_user', wp_rand( $current_id + 1, $current_id + 100 ) );
394
		$this->admin_post_redirect_referrer();
395
	}
396
397
	/**
398
	 * Randomize master user and its token.
399
	 */
400
	public function admin_post_randomize_master_user_and_token() {
401
		check_admin_referer( 'randomize-master-user-and-token' );
402
		$this->notice_type = 'jetpack-broken';
403
		$current_id        = Jetpack_Options::get_option( 'master_user' );
404
		$random_id         = wp_rand( $current_id + 1, $current_id + 100 );
405
		Jetpack_Options::update_option( 'master_user', $random_id );
406
		$user_tokens = Jetpack_Options::get_option( 'user_tokens', array() );
407
		if ( isset( $user_tokens[ $current_id ] ) ) {
408
			$user_tokens[ $random_id ] = substr( $user_tokens[ $current_id ], 0, strrpos( $user_tokens[ $current_id ], '.' ) ) . ".$random_id";
409
			unset( $user_tokens[ $current_id ] );
410
		}
411
		Jetpack_Options::update_option( 'user_tokens', $user_tokens );
412
		$this->admin_post_redirect_referrer();
413
	}
414
415
	/**
416
	 * Clear master user.
417
	 */
418
	public function admin_post_clear_master_user() {
419
		check_admin_referer( 'clear-master-user' );
420
		$this->notice_type = 'jetpack-broken';
421
		Jetpack_Options::delete_option( 'master_user' );
422
		$this->admin_post_redirect_referrer();
423
	}
424
425
	/**
426
	 * Randomize blog ID.
427
	 */
428
	public function admin_post_randomize_blog_id() {
429
		check_admin_referer( 'randomize-blog-id' );
430
		$this->notice_type = 'jetpack-broken';
431
		Jetpack_Options::update_option( 'id', wp_rand( 100, 10000 ) );
432
		$this->admin_post_redirect_referrer();
433
	}
434
435
	/**
436
	 * Clear blog ID.
437
	 */
438
	public function admin_post_clear_blog_id() {
439
		check_admin_referer( 'clear-blog-id' );
440
		$this->notice_type = 'jetpack-broken';
441
		Jetpack_Options::delete_option( 'id' );
442
		$this->admin_post_redirect_referrer();
443
	}
444
445
	/**
446
	 * Stores a backup of the current Jetpack connection options.
447
	 */
448
	public function store_current_options() {
449
		update_option(
450
			self::STORED_OPTIONS_KEY,
451
			array(
452
				'blog_token'  => $this->blog_token,
453
				'user_tokens' => $this->user_tokens,
454
				'master_user' => $this->master_user,
455
				'id'          => $this->id,
456
				'tos_agreed'  => $this->tos_agreed,
457
			)
458
		);
459
	}
460
461
	/**
462
	 * Retrieves the stored connection options.
463
	 *
464
	 * @return array
465
	 */
466
	public function get_stored_connection_options() {
467
		return get_option( self::STORED_OPTIONS_KEY );
468
	}
469
470
	/**
471
	 * Clears all stored connection option values.
472
	 */
473
	public function clear_stored_options() {
474
		delete_option( self::STORED_OPTIONS_KEY );
475
	}
476
477
	/**
478
	 * Just redirects back to the referrer. Keeping it DRY.
479
	 */
480
	public function admin_post_redirect_referrer() {
481
		if ( wp_get_referer() ) {
482
			wp_safe_redirect(
483
				add_query_arg(
484
					array(
485
						'notice' => $this->notice_type,
486
						'nonce'  => wp_create_nonce( 'jetpack_debug_broken_token_admin_notice' ),
487
					),
488
					wp_get_referer()
489
				)
490
			);
491
		} else {
492
			wp_safe_redirect( get_home_url() );
493
		}
494
	}
495
496
	/**
497
	 * Displays an admin notice...
498
	 */
499
	public function render_admin_notice() {
500
		switch ( $this->notice_type ) {
501
			case 'jetpack-broken':
502
				$message = 'Nice! You broke Jetpack!';
503
				break;
504
			case 'store-options':
505
				$message = 'Success! Backup of the connection options stored safely.';
506
				break;
507
			case 'restore-options':
508
				$message = 'Success! You\'ve restored the connection options. I hope things are working well now.';
509
				break;
510
			case 'clear-tos':
511
				$message = 'You cleared the TOS option! Nicely done!';
512
				break;
513
			default:
514
				$message = 'Setting saved!';
515
				break;
516
		}
517
518
		printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html( $message ) );
519
	}
520
521
	/**
522
	 * Clear TOS action.
523
	 */
524
	public function admin_post_clear_tos() {
525
		check_admin_referer( 'clear-tos' );
526
		$this->notice_type = 'clear-tos';
527
		$this->clear_tos();
528
529
		$this->admin_post_redirect_referrer();
530
	}
531
532
	/**
533
	 * Clear the TOS option.
534
	 */
535
	public function clear_tos() {
536
		Jetpack_Options::delete_option( 'tos_agreed' );
537
	}
538
}
539
540
add_action( 'plugins_loaded', 'register_broken_token', 1000 );
541
542
/**
543
 * Load the brokenness.
544
 */
545
function register_broken_token() {
546
	if ( class_exists( 'Jetpack_Options' ) ) {
547
		new Broken_Token();
548
		if ( class_exists( 'Automattic\Jetpack\Connection\Error_Handler' ) ) {
549
			new Broken_Token_XmlRpc();
550
		}
551
	} else {
552
		add_action( 'admin_notices', 'broken_token_jetpack_not_active' );
553
	}
554
}
555
556
/**
557
 * Notice for if Jetpack is not active.
558
 */
559
function broken_token_jetpack_not_active() {
560
	echo '<div class="notice info"><p>Jetpack Debug tools: Jetpack_Options package must be present for the Broken Token to work.</p></div>';
561
}
562
563
// phpcs:enable
564