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

Broken_Token_XmlRpc   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 198
rs 10
c 0
b 0
f 0
wmc 18
lcom 2
cbo 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 2
A enqueue_scripts() 0 14 2
A register_submenu_page() 0 11 1
B render_ui() 0 60 2
A print_current_errors() 0 17 3
A print_verified_errors() 0 14 3
A admin_post_clear_all_xmlrpc_errors() 0 5 1
A admin_post_clear_all_verified_xmlrpc_errors() 0 5 1
A admin_post_refresh_verified_errors_list() 0 5 1
A admin_post_redirect_referrer() 0 7 2
1
<?php // phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_print_r
2
/**
3
 * XMLRPC Brokeness.
4
 *
5
 * @package Jetpack.
6
 */
7
8
use Automattic\Jetpack\Connection\Error_Handler;
9
10
/**
11
 * Class Broken_Token_XmlRpc
12
 */
13
class Broken_Token_XmlRpc {
14
15
	/**
16
	 * Broken_Token_XmlRpc constructor.
17
	 */
18
	public function __construct() {
19
20
		add_action( 'admin_menu', array( $this, 'register_submenu_page' ), 1000 );
21
22
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
23
24
		add_action( 'admin_post_clear_all_xmlrpc_errors', array( $this, 'admin_post_clear_all_xmlrpc_errors' ) );
25
		add_action( 'admin_post_clear_all_verified_xmlrpc_errors', array( $this, 'admin_post_clear_all_verified_xmlrpc_errors' ) );
26
		add_action( 'admin_post_refresh_verified_errors_list', array( $this, 'admin_post_refresh_verified_errors_list' ) );
27
28
		$this->error_manager   = Error_Handler::get_instance();
0 ignored issues
show
Bug introduced by
The property error_manager 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...
29
		$this->stored_errors   = $this->error_manager->get_stored_errors();
0 ignored issues
show
Bug introduced by
The property stored_errors 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...
30
		$this->verified_errors = $this->error_manager->get_verified_errors();
0 ignored issues
show
Bug introduced by
The property verified_errors 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...
31
		$this->dev_debug_on    = defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG;
0 ignored issues
show
Bug introduced by
The property dev_debug_on 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...
32
	}
33
34
	/**
35
	 * Enqueue scripts.
36
	 *
37
	 * @param string $hook Called hook.
38
	 */
39
	public function enqueue_scripts( $hook ) {
40
		if ( 'jetpack_page_broken-token-xmlrpc-errors' === $hook ) {
41
			wp_enqueue_script( 'broken_token_xmlrpc_errors', plugin_dir_url( __FILE__ ) . 'js/xmlrpc-errors.js', array( 'jquery' ), JETPACK_DEBUG_HELPER_VERSION, true );
42
			wp_localize_script(
43
				'broken_token_xmlrpc_errors',
44
				'jetpack_broken_token_xmlrpc_errors',
45
				array(
46
					'verify_error_url'              => get_rest_url() . 'jetpack/v4/verify_xmlrpc_error',
47
					'admin_post_url'                => admin_url( 'admin-post.php' ),
48
					'refresh_verified_errors_nonce' => wp_create_nonce( 'refresh-verified-errors' ),
49
				)
50
			);
51
		}
52
	}
53
54
	/**
55
	 * Register submenu page.
56
	 */
57
	public function register_submenu_page() {
58
		add_submenu_page(
59
			'jetpack',
60
			'XML-RPC Errors',
61
			'XML-RPC Errors',
62
			'manage_options',
63
			'broken-token-xmlrpc-errors',
64
			array( $this, 'render_ui' ),
65
			99
66
		);
67
	}
68
69
	/**
70
	 * Render UI.
71
	 */
72
	public function render_ui() {
73
		?>
74
			<h1>XML-RPC errors</h1>
75
			<p>
76
				This page helps you to trigger XML-RPC requests with invalid signatures.
77
			</p>
78
			<?php if ( $this->dev_debug_on ) : ?>
79
				<div class="notice notice-success">
80
					<p>JETPACK_DEV_DEBUG constant is ON. This means every xml-rpc error will be reported. You're good to test.</p>
81
				</div>
82
			<?php else : ?>
83
				<div class="notice notice-warning">
84
					<p>JETPACK_DEV_DEBUG constant is OFF. This means xml-rpc error will only be reported once evey hour. Set it to true so you can test it.</p>
85
				</div>
86
			<?php endif; ?>
87
88
			<p>
89
				Now head to <a href="https://jetpack.com/debug/?url=<?php echo esc_url_raw( get_home_url() ); ?>">Jetpack Debugger</a> and trigger some requests!
90
			</p>
91
92
			<div id="current_xmlrpc_errors">
93
94
95
				<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
96
					<input type="hidden" name="action" value="clear_all_xmlrpc_errors">
97
					<?php wp_nonce_field( 'clear-xmlrpc-errors' ); ?>
98
					<h2>
99
						Current Unverified Errors
100
						<input type="submit" value="Clear all unverified errors" class="button button-primary">
101
					</h2>
102
				</form>
103
				<p>
104
					Unverified errors are errors that were detected but that we don't know if they are legit and came from WP.com
105
				</p>
106
				<p>
107
					After an error is detected, we send a request to WP.COM and ask it to reach back to us with a nonce to confirm the error is legit. They do this by sending a request to the verify error API endpoint. You can simulate this request clicking on the "Verify error" buttons below.
108
				</p>
109
				<div id="stored-xmlrpc-error">
110
					<?php $this->print_current_errors(); ?>
111
				</div>
112
				<div id="verified-xmlrpc-error">
113
					<form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
114
						<input type="hidden" name="action" value="clear_all_verified_xmlrpc_errors">
115
						<?php wp_nonce_field( 'clear-verified-xmlrpc-errors' ); ?>
116
						<h2>
117
							Current Verified Errors
118
							<input type="submit" value="Clear all verified errors" class="button button-primary">
119
						</h2>
120
					</form>
121
					<p>
122
						Verified errors are errors we know are legit and now we will display them to the user or do some self healing, depending on the error.
123
					</p>
124
					<div id="verified_errors_list">
125
						<?php $this->print_verified_errors(); ?>
126
					</div>
127
				</div>
128
			</div>
129
130
		<?php
131
	}
132
133
	/**
134
	 * Print current errors.
135
	 */
136
	public function print_current_errors() {
137
		foreach ( $this->stored_errors as $error_code => $error_group ) {
138
139
			echo '<h4>' . esc_html( $error_code ) . '</h4>';
140
141
			foreach ( $error_group as $user_id => $error ) {
142
				?>
143
				<b>User: <?php echo esc_html( $user_id ); ?></b>
144
				<pre><?php print_r( $error ); ?></pre>
145
146
				<input type="button" value="Verify error (via API)" data-nonce="<?php echo esc_attr( $error['nonce'] ); ?>" class="button button-primary verify-error">
147
148
				<hr />
149
				<?php
150
			}
151
		}
152
	}
153
154
	/**
155
	 * Print verified errors.
156
	 */
157
	public function print_verified_errors() {
158
		foreach ( $this->verified_errors as $error_code => $error_group ) {
159
160
			echo '<h4>' . esc_html( $error_code ) . '</h4>';
161
162
			foreach ( $error_group as $user_id => $error ) {
163
				?>
164
				<b>User: <?php echo esc_html( $user_id ); ?></b>
165
				<pre><?php print_r( $error ); ?></pre>
166
				<hr />
167
				<?php
168
			}
169
		}
170
	}
171
172
	/**
173
	 * Clear all XMLRPC Errors.
174
	 */
175
	public function admin_post_clear_all_xmlrpc_errors() {
176
		check_admin_referer( 'clear-xmlrpc-errors' );
177
		$this->error_manager->delete_stored_errors();
178
		$this->admin_post_redirect_referrer();
179
	}
180
181
	/**
182
	 * Clear all verified XMLRPC Errors.
183
	 */
184
	public function admin_post_clear_all_verified_xmlrpc_errors() {
185
		check_admin_referer( 'clear-verified-xmlrpc-errors' );
186
		$this->error_manager->delete_verified_errors();
187
		$this->admin_post_redirect_referrer();
188
	}
189
190
	/**
191
	 * Return the list of verified errors to dynamically refresh the interface
192
	 */
193
	public function admin_post_refresh_verified_errors_list() {
194
		check_admin_referer( 'refresh-verified-errors' );
195
		$this->print_verified_errors();
196
		exit;
197
	}
198
199
	/**
200
	 * Just redirects back to the referrer. Keeping it DRY.
201
	 */
202
	public function admin_post_redirect_referrer() {
203
		if ( wp_get_referer() ) {
204
			wp_safe_redirect( wp_get_referer() );
205
		} else {
206
			wp_safe_redirect( get_home_url() );
207
		}
208
	}
209
210
}
211
212
// phpcs:enable
213