PluginProbe
Plugin Detective – Troubleshooting Conflicts / 1.2.31
Plugin Detective – Troubleshooting Conflicts v1.2.31
1.2.35 1.2.33 1.2.32 1.2.31 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2 1.2.1 1.2.10 1.2.12 1.2.13 1.2.14 1.2.16 1.2.19 1.2.20 1.2.22 1.2.23 1.2.24 All 54 releases
plugin-detective / troubleshoot / includes / class-api.php

class-api.php in Plugin Detective – Troubleshooting Conflicts 1.2.31, at troubleshoot/includes/class-api.php

257 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Troubleshoot Api.
4 *
5 * @since 0.0.0
6 * @package Troubleshoot
7 */
8
9 /**
10 * Troubleshoot Api.
11 *
12 * @since 0.0.0
13 */
14 class PDT_Api {
15 /**
16 * Parent plugin class.
17 *
18 * @since 0.0.0
19 *
20 * @var Troubleshoot
21 */
22 protected $plugin = null;
23
24 public $params = array();
25 public $args = array();
26 public $errors = array();
27 public $data = array();
28
29
30 /**
31 * Constructor.
32 *
33 * @since 0.0.0
34 *
35 * @param Troubleshoot $plugin Main plugin object.
36 */
37 public function __construct( $plugin ) {
38 $this->plugin = $plugin;
39 $this->hooks();
40 }
41
42 /**
43 * Initiate our hooks.
44 *
45 * @since 0.0.0
46 */
47 public function hooks() {
48
49 }
50
51 public function process_params() {
52 $param_keys = array(
53 'nonce' => array(
54 'is_required' => false,
55 'escape_callback' => 'esc_attr',
56 'validation_callback' => '__return_true',
57 ),
58
59 'controller' => array(
60 'is_required' => false,
61 'escape_callback' => 'esc_attr',
62 'validation_callback' => '__return_true',
63 ),
64
65 'action' => array(
66 'is_required' => true,
67 'escape_callback' => 'esc_attr',
68 'validation_callback' => array( 'PDT_Api', 'is_string' ),
69 ),
70
71 'username' => array(
72 'is_required' => false,
73 'escape_callback' => 'esc_attr',
74 'validation_callback' => '__return_true',
75 ),
76
77 'password' => array(
78 'is_required' => false,
79 'escape_callback' => 'esc_attr',
80 'validation_callback' => '__return_true',
81 ),
82 );
83
84 foreach ($param_keys as $param_key => $param_options) {
85 if ( !isset( $this->request[$param_key] ) ) {
86 if ( $param_options['is_required'] ) {
87 $this->errors[$param_key] = 'Required parameter';
88 }
89
90 $this->params[$param_key] = null;
91 continue;
92 }
93
94 $param_value = call_user_func( $param_options['escape_callback'], $this->request[$param_key] );
95
96 $validation_response = call_user_func( $param_options['validation_callback'], $param_value );
97 if ( true !== $validation_response ) {
98 $this->errors[$param_key] = $validation_response;
99 continue;
100 }
101
102 $this->params[$param_key] = $param_value;
103 }
104
105 if ( empty( $this->params['nonce'] ) && $this->params['action'] == 'authenticate' ) {
106 if ( empty( $this->params['username'] ) ) {
107 $this->errors['username'] = 'Required for authentication';
108 }
109
110 if ( empty( $this->params['password'] ) ) {
111 $this->errors['password'] = 'Required for authentication';
112 }
113 }
114 }
115
116 public function process_input() {
117 $this->request = array();
118
119 if ( ! empty( $_REQUEST ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Custom troubleshooter API authenticated via PDT_Auth nonce; runs standalone when the WP REST API is unavailable.
120 $this->request = $_REQUEST; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- See above; params validated downstream in process_params().
121 }
122
123 $json = file_get_contents("php://input");
124 if ( empty( $json ) ) {
125 return;
126 }
127
128 $array = json_decode( $json, true );
129 if ( empty( $array ) ) {
130 if ( empty( $this->request ) ) {
131 $this->errors['no_input'] = __( 'No input detected, possibly due to a malformed request or server setting. Please contact support', 'plugin-detective' );
132 }
133
134 return;
135 }
136
137 $this->request = array_merge( $this->request, $array );
138 }
139
140 public function process_args() {
141 $args = $this->request;
142 foreach ($this->params as $key => $value) {
143 unset( $args[$key] );
144 }
145 $this->args = $args;
146 }
147
148 public function process_request() {
149 if ( empty( $this->request ) ) {
150 $this->process_input();
151 }
152
153 if ( empty( $this->params ) ) {
154 $this->process_params();
155 }
156
157 if ( empty( $this->args ) ) {
158 $this->process_args();
159 }
160
161 if ( !empty( $this->errors ) ) {
162 $this->return_response();
163 }
164
165 // Authentication Request
166 if ( $this->params['action'] == 'authenticate' ) {
167 $user = $this->plugin->auth->authenticate( $this->params['username'], $this->params['password'] );
168
169 if ( is_a( $user, 'WP_Error' ) ) {
170 // Single, fixed error code for every failure mode — never echo a
171 // code that distinguishes a valid username from an invalid one.
172 $this->errors['authentication'] = $user->get_error_code();
173 } else {
174 $this->data['nonce'] = $this->plugin->auth->create_nonce( 'pd_api' );
175 }
176
177 $this->return_response();
178 }
179
180
181 // Verify nonce value
182 if ( empty( $this->params['nonce'] ) ) {
183 $this->errors['nonce'] = 'Required for authenticated requests';
184 $this->return_response();
185 }
186
187 if ( ! $this->plugin->auth->verify_nonce( $this->params['nonce'], 'pd_api' ) ) {
188 $this->errors['nonce'] = 'Invalid';
189 $this->return_response();
190 }
191
192
193 // Process request
194 $object = $this;
195 if ( !empty( $this->params['controller'] ) ) {
196 if ( !in_array( $this->params['controller'], array(
197 'plugins',
198 'installed',
199 'cases',
200 'clues',
201 ) ) ) {
202 $this->errors['controller'] = 'Trying to access a disallowed controller';
203 $this->return_response();
204 }
205
206 if ( !property_exists( $this->plugin, $this->params['controller'] ) ) {
207 $this->errors['controller'] = 'Controller not found';
208 $this->return_response();
209 }
210 $controller = $this->params['controller'];
211 $object = $this->plugin->$controller;
212 }
213
214 if ( !method_exists( $object, $this->params['action'] ) ) {
215 $this->errors['action'] = 'Action not found';
216 $this->return_response();
217 }
218
219 $action = $this->params['action'];
220
221 $response = $object->$action( $this->args );
222 if ( is_a( $response, 'WP_Error' ) ) {
223 $this->errors[$response->get_error_code()] = $response->get_error_message();
224 } else {
225 $this->data = $response;
226 }
227
228 $this->return_response();
229 }
230
231 public function test() {
232 return array( 'test' => 'value',);
233 }
234
235 public function return_response() {
236 header( 'Content-type: application/json' );
237 echo json_encode( array(
238 'data' => $this->data,
239 'errors' => $this->errors,
240 ) );
241
242 exit();
243 }
244
245 public static function is_string( $string ) {
246 if ( !is_string( $string ) ) {
247 return 'String value required';
248 }
249
250 if ( (string)(int)$string === (string)$string ) {
251 return 'Non-numeric value';
252 }
253
254 return true;
255 }
256 }
257