Completed
Push — renovate/url-polyfill-1.x ( 01368d...f2aaf6 )
by
unknown
114:05 queued 106:27
created

Broken_Token   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 414
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 414
rs 9.76
c 0
b 0
f 0
wmc 33
lcom 1
cbo 1

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 30 3
A enqueue_scripts() 0 5 2
A broken_token_register_submenu_page() 0 11 1
B render_ui() 0 99 4
A admin_post_store_current_options() 0 7 1
A admin_post_clear_stored_options() 0 6 1
A admin_post_restore_from_stored_options() 0 12 3
A admin_post_set_invalid_blog_token() 0 7 1
A admin_post_set_invalid_user_tokens() 0 9 2
A admin_post_clear_blog_token() 0 6 1
A admin_post_clear_user_tokens() 0 6 1
A admin_post_randomize_master_user() 0 7 1
A admin_post_clear_master_user() 0 6 1
A admin_post_randomize_blog_id() 0 6 1
A admin_post_clear_blog_id() 0 6 1
A store_current_options() 0 11 1
A get_stored_connection_options() 0 3 1
A clear_stored_options() 0 3 1
A admin_post_redirect_referrer() 0 15 2
A render_admin_notice() 0 18 4
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
	 * Options.
58
	 *
59
	 * PHP 7.1+
60
	 */
61
	public const STORED_OPTIONS_KEY = 'broken_token_stored_options'; // phpcs:ignore PHPCompatibility.Classes.NewConstVisibility.Found
62
63
	/**
64
	 * Token name.
65
	 *
66
	 * @var string
67
	 */
68
	public $invalid_blog_token = 'broken.token';
69
70
	/**
71
	 * User token name.
72
	 *
73
	 * @var string
74
	 */
75
	public $invalid_user_token = 'broken.token.1';
76
77
	/**
78
	 * Broken_Token constructor.
79
	 */
80
	public function __construct() {
81
		add_action( 'admin_menu', array( $this, 'broken_token_register_submenu_page' ), 1000 );
82
83
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
84
85
		// Stored options.
86
		add_action( 'admin_post_clear_stored_options', array( $this, 'admin_post_clear_stored_options' ) );
87
		add_action( 'admin_post_store_current_options', array( $this, 'admin_post_store_current_options' ) );
88
		add_action( 'admin_post_restore_from_stored_options', array( $this, 'admin_post_restore_from_stored_options' ) );
89
90
		// Break stuff.
91
		add_action( 'admin_post_set_invalid_blog_token', array( $this, 'admin_post_set_invalid_blog_token' ) );
92
		add_action( 'admin_post_set_invalid_user_tokens', array( $this, 'admin_post_set_invalid_user_tokens' ) );
93
		add_action( 'admin_post_clear_blog_token', array( $this, 'admin_post_clear_blog_token' ) );
94
		add_action( 'admin_post_clear_user_tokens', array( $this, 'admin_post_clear_user_tokens' ) );
95
		add_action( 'admin_post_randomize_master_user', array( $this, 'admin_post_randomize_master_user' ) );
96
		add_action( 'admin_post_clear_master_user', array( $this, 'admin_post_clear_master_user' ) );
97
		add_action( 'admin_post_randomize_blog_id', array( $this, 'admin_post_randomize_blog_id' ) );
98
		add_action( 'admin_post_clear_blog_id', array( $this, 'admin_post_clear_blog_id' ) );
99
100
		$this->blog_token  = Jetpack_Options::get_option( 'blog_token' );
101
		$this->user_tokens = Jetpack_Options::get_option( 'user_tokens' );
102
		$this->master_user = Jetpack_Options::get_option( 'master_user' );
103
		$this->id          = Jetpack_Options::get_option( 'id' );
104
105
		if ( isset( $_GET['notice'] ) && check_admin_referer( 'jetpack_debug_broken_token_admin_notice', 'nonce' ) ) {
106
			$this->notice_type = $_GET['notice'];
107
			add_action( 'admin_notices', array( $this, 'render_admin_notice' ) );
108
		}
109
	}
110
111
	/**
112
	 * Enqueue scripts.
113
	 *
114
	 * @param string $hook Called hook.
115
	 */
116
	public function enqueue_scripts( $hook ) {
117
		if ( strpos( $hook, 'jetpack_page_broken-token' ) === 0 ) {
118
			wp_enqueue_style( 'broken_token_style', plugin_dir_url( __FILE__ ) . '/css/style.css', array(), JETPACK_DEBUG_HELPER_VERSION );
119
		}
120
	}
121
122
	/**
123
	 * Register's submenu.
124
	 */
125
	public function broken_token_register_submenu_page() {
126
		add_submenu_page(
127
			'jetpack',
128
			'Broken Token',
129
			'Broken Token',
130
			'manage_options',
131
			'broken-token',
132
			array( $this, 'render_ui' ),
133
			99
134
		);
135
	}
136
137
	/**
138
	 * Render UI.
139
	 */
140
	public function render_ui() {
141
		$stored_options = $this->get_stored_connection_options();
142
		?>
143
		<h1>Broken Token 😱!</h1>
144
		<p>This plugin will help you break the Jetpack connection in various ways.</p>
145
		<p>All instances of breaking only involve modifying the local DB options. Nothing done here will alter tokens stored in wp.com</p>
146
		<hr>
147
148
		<h2>Current token options being used by Jetpack:</h2>
149
		<p>Blog Token: <?php echo esc_html( $this->blog_token ); ?></p>
150
		<p>User Tokens: <?php print_r( $this->user_tokens ); ?></p>
151
		<p>Primary User: <?php echo esc_html( $this->master_user ); ?></p>
152
		<p>Blog ID: <?php echo esc_html( $this->id ); ?></p>
153
154
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
155
			<input type="hidden" name="action" value="store_current_options">
156
			<?php wp_nonce_field( 'store-current-options' ); ?>
157
			<input type="submit" value="Store these options" class="button button-primary">
158
		</form>
159
		<br>
160
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
161
			<input type="hidden" name="action" value="restore_from_stored_options">
162
			<?php wp_nonce_field( 'restore-stored-options' ); ?>
163
			<input type="submit" value="Restore from stored options" class="button button-primary <?php echo empty( $stored_options ) ? 'disabled' : ''; ?>">
164
		</form>
165
166
		<?php
167
		echo '<h2>Stored connection options.</h2>';
168
		echo '<p>Might be useful to store valid connection options before breaking it, so you can restore later.</p>';
169
		if ( empty( $stored_options ) ) {
170
			echo '<p>No connection options are currently stored!</p>';
171
		} else {
172
			echo '<pre>';
173
			print_r( $stored_options );
174
			echo '</pre>';
175
		}
176
		?>
177
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
178
			<input type="hidden" name="action" value="clear_stored_options">
179
			<?php wp_nonce_field( 'clear-stored-options' ); ?>
180
			<input type="submit" value="Clear stored options" class="button button-primary <?php echo empty( $stored_options ) ? 'disabled' : ''; ?>">
181
		</form>
182
183
		<hr>
184
185
		<h2>Break some stuff:</h2>
186
		<p><strong>Break the blog token:</strong></p>
187
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
188
			<input type="hidden" name="action" value="set_invalid_blog_token">
189
			<?php wp_nonce_field( 'set-invalid-blog-token' ); ?>
190
			<input type="submit" value="Set invalid blog token" class="button button-primary button-break-it">
191
		</form>
192
		<br>
193
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
194
			<input type="hidden" name="action" value="clear_blog_token">
195
			<?php wp_nonce_field( 'clear-blog-token' ); ?>
196
			<input type="submit" value="Clear blog token" class="button button-primary button-break-it">
197
		</form>
198
199
		<p><strong>Break the user tokens:</strong></p>
200
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
201
			<input type="hidden" name="action" value="clear_user_tokens">
202
			<?php wp_nonce_field( 'clear-user-tokens' ); ?>
203
			<input type="submit" value="Clear user tokens" class="button button-primary button-break-it">
204
		</form>
205
		<br>
206
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
207
			<input type="hidden" name="action" value="set_invalid_user_tokens">
208
			<?php wp_nonce_field( 'set-invalid-user-tokens' ); ?>
209
			<input type="submit" value="Set invalid user tokens" class="button button-primary button-break-it">
210
		</form>
211
212
		<p><strong>Break the Primary User:</strong></p>
213
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
214
			<input type="hidden" name="action" value="randomize_master_user">
215
			<?php wp_nonce_field( 'randomize-master-user' ); ?>
216
			<input type="submit" value="Randomize Primary User ID" class="button button-primary button-break-it">
217
		</form>
218
		<br>
219
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
220
			<input type="hidden" name="action" value="clear_master_user">
221
			<?php wp_nonce_field( 'clear-master-user' ); ?>
222
			<input type="submit" value="Clear the Primary User" class="button button-primary button-break-it">
223
		</form>
224
225
		<p><strong>Break the blog ID:</strong></p>
226
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
227
			<input type="hidden" name="action" value="randomize_blog_id">
228
			<?php wp_nonce_field( 'randomize-blog-id' ); ?>
229
			<input type="submit" value="Randomize Blog ID" class="button button-primary button-break-it">
230
		</form>
231
		<br>
232
		<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
233
			<input type="hidden" name="action" value="clear_blog_id">
234
			<?php wp_nonce_field( 'clear-blog-id' ); ?>
235
			<input type="submit" value="Clear the Blog ID" class="button button-primary button-break-it">
236
		</form>
237
		<?php
238
	}
239
240
	/**
241
	 * Store options.
242
	 */
243
	public function admin_post_store_current_options() {
244
		check_admin_referer( 'store-current-options' );
245
		$this->notice_type = 'store-options';
246
		$this->store_current_options();
247
248
		$this->admin_post_redirect_referrer();
249
	}
250
251
	/**
252
	 * Clear options.
253
	 */
254
	public function admin_post_clear_stored_options() {
255
		check_admin_referer( 'clear-stored-options' );
256
		$this->clear_stored_options();
257
258
		$this->admin_post_redirect_referrer();
259
	}
260
261
	/**
262
	 * Restore from options.
263
	 */
264
	public function admin_post_restore_from_stored_options() {
265
		check_admin_referer( 'restore-stored-options' );
266
		$this->notice_type = 'restore-options';
267
		foreach ( $this->get_stored_connection_options() as $key => $value ) {
268
			if ( empty( $value ) ) {
269
				continue;
270
			}
271
			Jetpack_Options::update_option( $key, $value );
272
		}
273
274
		$this->admin_post_redirect_referrer();
275
	}
276
277
	/**
278
	 * Set invalid blog token.
279
	 */
280
	public function admin_post_set_invalid_blog_token() {
281
		check_admin_referer( 'set-invalid-blog-token' );
282
		$this->notice_type = 'jetpack-broken';
283
		Jetpack_Options::update_option( 'blog_token', $this->invalid_blog_token );
284
285
		$this->admin_post_redirect_referrer();
286
	}
287
288
	/**
289
	 * Set invalid user token.
290
	 */
291
	public function admin_post_set_invalid_user_tokens() {
292
		check_admin_referer( 'set-invalid-user-tokens' );
293
		$this->notice_type = 'jetpack-broken';
294
		foreach ( Jetpack_Options::get_option( 'user_tokens', array() ) as $id => $token ) {
295
			Jetpack_Options::update_option( 'user_tokens', array( $id => $this->invalid_user_token ) );
296
		}
297
298
		$this->admin_post_redirect_referrer();
299
	}
300
301
	/**
302
	 * Clear blog token.
303
	 */
304
	public function admin_post_clear_blog_token() {
305
		check_admin_referer( 'clear-blog-token' );
306
		$this->notice_type = 'jetpack-broken';
307
		Jetpack_Options::delete_option( 'blog_token' );
308
		$this->admin_post_redirect_referrer();
309
	}
310
311
	/**
312
	 * Clear user token.
313
	 */
314
	public function admin_post_clear_user_tokens() {
315
		check_admin_referer( 'clear-user-tokens' );
316
		$this->notice_type = 'jetpack-broken';
317
		Jetpack_Options::delete_option( 'user_tokens' );
318
		$this->admin_post_redirect_referrer();
319
	}
320
321
	/**
322
	 * Randomize master user.
323
	 */
324
	public function admin_post_randomize_master_user() {
325
		check_admin_referer( 'randomize-master-user' );
326
		$this->notice_type = 'jetpack-broken';
327
		$current_id        = Jetpack_Options::get_option( 'master_user' );
328
		Jetpack_Options::update_option( 'master_user', wp_rand( $current_id + 1, $current_id + 100 ) );
329
		$this->admin_post_redirect_referrer();
330
	}
331
332
	/**
333
	 * Clear master user.
334
	 */
335
	public function admin_post_clear_master_user() {
336
		check_admin_referer( 'clear-master-user' );
337
		$this->notice_type = 'jetpack-broken';
338
		Jetpack_Options::delete_option( 'master_user' );
339
		$this->admin_post_redirect_referrer();
340
	}
341
342
	/**
343
	 * Randomize blog ID.
344
	 */
345
	public function admin_post_randomize_blog_id() {
346
		check_admin_referer( 'randomize-blog-id' );
347
		$this->notice_type = 'jetpack-broken';
348
		Jetpack_Options::update_option( 'id', wp_rand( 100, 10000 ) );
349
		$this->admin_post_redirect_referrer();
350
	}
351
352
	/**
353
	 * Clear blog ID.
354
	 */
355
	public function admin_post_clear_blog_id() {
356
		check_admin_referer( 'clear-blog-id' );
357
		$this->notice_type = 'jetpack-broken';
358
		Jetpack_Options::delete_option( 'id' );
359
		$this->admin_post_redirect_referrer();
360
	}
361
362
	/**
363
	 * Stores a backup of the current Jetpack connection options.
364
	 */
365
	public function store_current_options() {
366
		update_option(
367
			$this::STORED_OPTIONS_KEY,
368
			array(
369
				'blog_token'  => $this->blog_token,
370
				'user_tokens' => $this->user_tokens,
371
				'master_user' => $this->master_user,
372
				'id'          => $this->id,
373
			)
374
		);
375
	}
376
377
	/**
378
	 * Retrieves the stored connection options.
379
	 *
380
	 * @return array
381
	 */
382
	public function get_stored_connection_options() {
383
		return get_option( $this::STORED_OPTIONS_KEY );
384
	}
385
386
	/**
387
	 * Clears all stored connection option values.
388
	 */
389
	public function clear_stored_options() {
390
		delete_option( $this::STORED_OPTIONS_KEY );
391
	}
392
393
	/**
394
	 * Just redirects back to the referrer. Keeping it DRY.
395
	 */
396
	public function admin_post_redirect_referrer() {
397
		if ( wp_get_referer() ) {
398
			wp_safe_redirect(
399
				add_query_arg(
400
					array(
401
						'notice' => $this->notice_type,
402
						'nonce'  => wp_create_nonce( 'jetpack_debug_broken_token_admin_notice' ),
403
					),
404
					wp_get_referer()
405
				)
406
			);
407
		} else {
408
			wp_safe_redirect( get_home_url() );
409
		}
410
	}
411
412
	/**
413
	 * Displays an admin notice...
414
	 */
415
	public function render_admin_notice() {
416
		switch ( $this->notice_type ) {
417
			case 'jetpack-broken':
418
				$message = 'Nice! You broke Jetpack!';
419
				break;
420
			case 'store-options':
421
				$message = 'Success! Backup of the connection options stored safely.';
422
				break;
423
			case 'restore-options':
424
				$message = 'Success! You\'ve restored the connection options. I hope things are working well now.';
425
				break;
426
			default:
427
				$message = 'Setting saved!';
428
				break;
429
		}
430
431
		printf( '<div class="notice notice-success"><p>%s</p></div>', esc_html( $message ) );
432
	}
433
}
434
435
add_action( 'plugins_loaded', 'register_broken_token', 1000 );
436
437
438
/**
439
 * Load the brokenness.
440
 */
441
function register_broken_token() {
442
	if ( class_exists( 'Jetpack' ) ) {
443
		new Broken_Token();
444
		if ( class_exists( 'Automattic\Jetpack\Connection\Error_Handler' ) ) {
445
			new Broken_Token_XmlRpc();
446
		}
447
	} else {
448
		add_action( 'admin_notices', 'broken_token_jetpack_not_active' );
449
	}
450
}
451
452
/**
453
 * Notice for if Jetpack is not active.
454
 */
455
function broken_token_jetpack_not_active() {
456
	echo '<div class="notice info"><p>Jetpack needs to be active and installed for the Broken Token plugin.</p></div>';
457
}
458
459
// phpcs:enable
460