Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 261
0.00% covered (danger)
0.00%
0 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
REST_Controller
0.00% covered (danger)
0.00%
0 / 261
0.00% covered (danger)
0.00%
0 / 17
1332
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 register_rest_endpoints
0.00% covered (danger)
0.00%
0 / 166
0.00% covered (danger)
0.00%
0 / 1
2
 api_ignore_threat
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 api_unignore_threat
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 api_fix_threats
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 api_fix_threats_status
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 api_check_credentials
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 api_scan
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 api_toggle_account_protection
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 api_get_account_protection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 api_toggle_waf
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 api_get_waf
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 api_get_waf_upgrade_seen_status
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 api_set_waf_upgrade_seen_status
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 api_get_onboarding_progress
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 api_complete_onboarding_steps
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 api_get_scan_history
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Class file for managing REST API endpoints for Jetpack Protect.
4 *
5 * @since 1.2.2
6 *
7 * @package automattic/jetpack-protect-plugin
8 */
9
10namespace Automattic\Jetpack\Protect;
11
12use Automattic\Jetpack\Account_Protection\Account_Protection;
13use Automattic\Jetpack\Account_Protection\Settings as Account_Protection_Settings;
14use Automattic\Jetpack\Connection\Rest_Authentication as Connection_Rest_Authentication;
15use Automattic\Jetpack\IP\Utils as IP_Utils;
16use Automattic\Jetpack\Protect_Status\REST_Controller as Protect_Status_REST_Controller;
17use Automattic\Jetpack\Waf\Waf_Runner;
18use Automattic\Jetpack\Waf\Waf_Stats;
19use Jetpack_Protect;
20use WP_Error;
21use WP_REST_Request;
22use WP_REST_Response;
23
24/**
25 * Class REST_Controller
26 */
27class REST_Controller {
28
29    /**
30     * Initialize the plugin's REST API.
31     *
32     * @return void
33     */
34    public static function init() {
35        // Set up the REST authentication hooks.
36        Connection_Rest_Authentication::init();
37
38        // Add custom WP REST API endoints.
39        add_action( 'rest_api_init', array( __CLASS__, 'register_rest_endpoints' ) );
40    }
41
42    /**
43     * Register the REST API routes.
44     *
45     * @return void
46     */
47    public static function register_rest_endpoints() {
48        Protect_Status_REST_Controller::register_rest_endpoints();
49
50        register_rest_route(
51            'jetpack-protect/v1',
52            'ignore-threat',
53            array(
54                'methods'             => \WP_REST_Server::EDITABLE,
55                'callback'            => __CLASS__ . '::api_ignore_threat',
56                'permission_callback' => function () {
57                    return current_user_can( 'manage_options' );
58                },
59            )
60        );
61
62        register_rest_route(
63            'jetpack-protect/v1',
64            'unignore-threat',
65            array(
66                'methods'             => \WP_REST_Server::EDITABLE,
67                'callback'            => __CLASS__ . '::api_unignore_threat',
68                'permission_callback' => function () {
69                    return current_user_can( 'manage_options' );
70                },
71            )
72        );
73
74        register_rest_route(
75            'jetpack-protect/v1',
76            'fix-threats',
77            array(
78                'methods'             => \WP_REST_Server::EDITABLE,
79                'callback'            => __CLASS__ . '::api_fix_threats',
80                'permission_callback' => function () {
81                    return current_user_can( 'manage_options' );
82                },
83            )
84        );
85
86        register_rest_route(
87            'jetpack-protect/v1',
88            'fix-threats-status',
89            array(
90                'methods'             => \WP_REST_Server::READABLE,
91                'callback'            => __CLASS__ . '::api_fix_threats_status',
92                'permission_callback' => function () {
93                    return current_user_can( 'manage_options' );
94                },
95            )
96        );
97
98        register_rest_route(
99            'jetpack-protect/v1',
100            'check-credentials',
101            array(
102                'methods'             => \WP_REST_Server::EDITABLE,
103                'callback'            => __CLASS__ . '::api_check_credentials',
104                'permission_callback' => function () {
105                    return current_user_can( 'manage_options' );
106                },
107            )
108        );
109
110        register_rest_route(
111            'jetpack-protect/v1',
112            'scan',
113            array(
114                'methods'             => \WP_REST_Server::EDITABLE,
115                'callback'            => __CLASS__ . '::api_scan',
116                'permission_callback' => function () {
117                    return current_user_can( 'manage_options' );
118                },
119            )
120        );
121
122        register_rest_route(
123            'jetpack-protect/v1',
124            'toggle-account-protection',
125            array(
126                'methods'             => \WP_REST_Server::EDITABLE,
127                'callback'            => __CLASS__ . '::api_toggle_account_protection',
128                'permission_callback' => function () {
129                    return current_user_can( 'manage_options' );
130                },
131            )
132        );
133
134        register_rest_route(
135            'jetpack-protect/v1',
136            'account-protection',
137            array(
138                'methods'             => \WP_REST_Server::READABLE,
139                'callback'            => __CLASS__ . '::api_get_account_protection',
140                'permission_callback' => function () {
141                    return current_user_can( 'manage_options' );
142                },
143            )
144        );
145
146        register_rest_route(
147            'jetpack-protect/v1',
148            'toggle-waf',
149            array(
150                'methods'             => \WP_REST_Server::EDITABLE,
151                'callback'            => __CLASS__ . '::api_toggle_waf',
152                'permission_callback' => function () {
153                    return current_user_can( 'manage_options' );
154                },
155            )
156        );
157
158        register_rest_route(
159            'jetpack-protect/v1',
160            'waf',
161            array(
162                'methods'             => \WP_REST_Server::READABLE,
163                'callback'            => __CLASS__ . '::api_get_waf',
164                'permission_callback' => function () {
165                    return current_user_can( 'manage_options' );
166                },
167            )
168        );
169
170        register_rest_route(
171            'jetpack-protect/v1',
172            'waf-upgrade-seen',
173            array(
174                'methods'             => \WP_REST_Server::READABLE,
175                'callback'            => __CLASS__ . '::api_get_waf_upgrade_seen_status',
176                'permission_callback' => function () {
177                    return current_user_can( 'manage_options' );
178                },
179            )
180        );
181
182        register_rest_route(
183            'jetpack-protect/v1',
184            'waf-upgrade-seen',
185            array(
186                'methods'             => \WP_REST_Server::EDITABLE,
187                'callback'            => __CLASS__ . '::api_set_waf_upgrade_seen_status',
188                'permission_callback' => function () {
189                    return current_user_can( 'manage_options' );
190                },
191            )
192        );
193
194        register_rest_route(
195            'jetpack-protect/v1',
196            'onboarding-progress',
197            array(
198                'methods'             => \WP_REST_Server::READABLE,
199                'callback'            => __CLASS__ . '::api_get_onboarding_progress',
200                'permission_callback' => function () {
201                    return current_user_can( 'manage_options' );
202                },
203            )
204        );
205
206        register_rest_route(
207            'jetpack-protect/v1',
208            'onboarding-progress',
209            array(
210                'methods'             => \WP_REST_Server::EDITABLE,
211                'callback'            => __CLASS__ . '::api_complete_onboarding_steps',
212                'permission_callback' => function () {
213                    return current_user_can( 'manage_options' );
214                },
215            )
216        );
217
218        register_rest_route(
219            'jetpack-protect/v1',
220            'scan-history',
221            array(
222                'methods'             => \WP_REST_Server::READABLE,
223                'callback'            => __CLASS__ . '::api_get_scan_history',
224                'permission_callback' => function () {
225                    return current_user_can( 'manage_options' );
226                },
227            )
228        );
229    }
230
231    /**
232     * Ignores a threat for the API endpoint
233     *
234     * @param WP_REST_Request $request The request object.
235     *
236     * @return WP_REST_Response
237     */
238    public static function api_ignore_threat( $request ) {
239        if ( ! $request['threat_id'] ) {
240            return new WP_REST_Response( 'Missing threat ID.', 400 );
241        }
242
243        $threat_ignored = Threats::ignore_threat( $request['threat_id'] );
244
245        if ( ! $threat_ignored ) {
246            return new WP_REST_Response( 'An error occurred while attempting to ignore the threat.', 500 );
247        }
248
249        return new WP_REST_Response( 'Threat ignored.' );
250    }
251
252    /**
253     * Unignores a threat for the API endpoint
254     *
255     * @param WP_REST_Request $request The request object.
256     *
257     * @return WP_REST_Response
258     */
259    public static function api_unignore_threat( $request ) {
260        if ( ! $request['threat_id'] ) {
261            return new WP_REST_Response( 'Missing threat ID.', 400 );
262        }
263
264        $threat_ignored = Threats::unignore_threat( $request['threat_id'] );
265
266        if ( ! $threat_ignored ) {
267            return new WP_REST_Response( 'An error occurred while attempting to unignore the threat.', 500 );
268        }
269
270        return new WP_REST_Response( 'Threat unignored.' );
271    }
272
273    /**
274     * Fixes threats for the API endpoint
275     *
276     * @param WP_REST_Request $request The request object.
277     *
278     * @return WP_REST_Response
279     */
280    public static function api_fix_threats( $request ) {
281        if ( empty( $request['threat_ids'] ) ) {
282            return new WP_REST_Response( 'Missing threat IDs.', 400 );
283        }
284
285        $threats_fixed = Threats::fix_threats( $request['threat_ids'] );
286
287        if ( ! $threats_fixed ) {
288            return new WP_REST_Response( 'An error occurred while attempting to fix the threat.', 500 );
289        }
290
291        return new WP_REST_Response( $threats_fixed );
292    }
293
294    /**
295     * Fixes threats for the API endpoint
296     *
297     * @param WP_REST_Request $request The request object.
298     *
299     * @return WP_REST_Response
300     */
301    public static function api_fix_threats_status( $request ) {
302        if ( empty( $request['threat_ids'] ) ) {
303            return new WP_REST_Response( 'Missing threat IDs.', 400 );
304        }
305
306        $threats_fixed = Threats::fix_threats_status( $request['threat_ids'] );
307
308        if ( ! $threats_fixed ) {
309            return new WP_REST_Response( 'An error occurred while attempting to get the fixer status of the threats.', 500 );
310        }
311
312        return new WP_REST_Response( $threats_fixed );
313    }
314
315    /**
316     * Checks if the site has credentials configured
317     *
318     * @return WP_REST_Response
319     */
320    public static function api_check_credentials() {
321        $credential_array = Credentials::get_credential_array();
322
323        if ( ! isset( $credential_array ) ) {
324            return new WP_REST_Response( 'An error occurred while attempting to fetch the credentials array', 500 );
325        }
326
327        return new WP_REST_Response( $credential_array );
328    }
329
330    /**
331     * Enqueues a scan for the API endpoint
332     *
333     * @return WP_REST_Response
334     */
335    public static function api_scan() {
336        $scan_enqueued = Threats::scan();
337
338        if ( ! $scan_enqueued ) {
339            return new WP_REST_Response( 'An error occurred while attempting to enqueue the scan.', 500 );
340        }
341
342        return new WP_REST_Response( 'Scan enqueued.' );
343    }
344
345    /**
346     * Toggles the Account Protection module on or off for the API endpoint
347     *
348     * @return WP_REST_Response|WP_Error
349     */
350    public static function api_toggle_account_protection() {
351        $account_protection = Account_Protection::instance();
352        if ( $account_protection->is_enabled() ) {
353            $disabled = $account_protection->disable();
354            if ( ! $disabled ) {
355                return new WP_Error(
356                    'account_protection_disable_failed',
357                    __( 'An error occurred disabling account protection.', 'jetpack-protect' ),
358                    array( 'status' => 500 )
359                );
360            }
361
362            return rest_ensure_response( true );
363        }
364
365        $enabled = $account_protection->enable();
366        if ( ! $enabled ) {
367            return new WP_Error(
368                'account_protection_enable_failed',
369                __( 'An error occurred enabling account protection.', 'jetpack-protect' ),
370                array( 'status' => 500 )
371            );
372        }
373
374        return rest_ensure_response( true );
375    }
376
377    /**
378     * Get Account Protection data for the API endpoint
379     *
380     * @return WP_Rest_Response
381     */
382    public static function api_get_account_protection() {
383        return new WP_REST_Response( ( new Account_Protection_Settings() )->get() );
384    }
385
386    /**
387     * Toggles the WAF module on or off for the API endpoint
388     *
389     * @return WP_REST_Response|WP_Error
390     */
391    public static function api_toggle_waf() {
392        if ( Waf_Runner::is_enabled() ) {
393            $disabled = Waf_Runner::disable();
394            if ( ! $disabled ) {
395                return new WP_Error(
396                    'waf_disable_failed',
397                    __( 'An error occurred disabling the firewall.', 'jetpack-protect' ),
398                    array( 'status' => 500 )
399                );
400            }
401
402            return rest_ensure_response( true );
403        }
404
405        $enabled = Waf_Runner::enable();
406        if ( ! $enabled ) {
407            return new WP_Error(
408                'waf_enable_failed',
409                __( 'An error occurred enabling the firewall.', 'jetpack-protect' ),
410                array( 'status' => 500 )
411            );
412        }
413
414        return rest_ensure_response( true );
415    }
416
417    /**
418     * Get WAF data for the API endpoint
419     *
420     * @return WP_Rest_Response
421     */
422    public static function api_get_waf() {
423        // Ensure plugin activation has been performed so WAF module is available.
424        Jetpack_Protect::do_plugin_activation_activities();
425
426        return new WP_REST_Response(
427            array(
428                'wafSupported'        => Waf_Runner::is_supported_environment(),
429                'currentIp'           => IP_Utils::get_ip(),
430                'upgradeIsSeen'       => Jetpack_Protect::get_waf_upgrade_seen_status(),
431                'displayUpgradeBadge' => Jetpack_Protect::get_waf_upgrade_badge_display_status(),
432                'isEnabled'           => Waf_Runner::is_enabled(),
433                'config'              => Waf_Runner::get_config(),
434                'stats'               => Jetpack_Protect::get_waf_stats(),
435                'globalStats'         => Waf_Stats::get_global_stats(),
436            )
437        );
438    }
439
440    /**
441     * Get WAF Upgrade "Seen" Status for the API endpoint
442     *
443     * @return bool Whether the current user has dismissed the upgrade popover or enabled the automatic rules feature.
444     */
445    public static function api_get_waf_upgrade_seen_status() {
446        return Jetpack_Protect::get_waf_upgrade_seen_status();
447    }
448
449    /**
450     * Set WAF Upgrade "Seen" Status for the API endpoint
451     *
452     * @return bool True if upgrade seen status updated to true, false on failure.
453     */
454    public static function api_set_waf_upgrade_seen_status() {
455        return Jetpack_Protect::set_waf_upgrade_seen_status();
456    }
457
458    /**
459     * Gets the current user's onboarding progress for the API endpoint
460     *
461     * @return WP_REST_Response
462     */
463    public static function api_get_onboarding_progress() {
464        $progress = Onboarding::get_current_user_progress();
465        return rest_ensure_response( $progress );
466    }
467
468    /**
469     * Set an onboarding step as completed for the API endpoint
470     *
471     * @param WP_REST_Request $request The request object.
472     *
473     * @return WP_REST_Response
474     */
475    public static function api_complete_onboarding_steps( $request ) {
476        if ( empty( $request['step_ids'] ) || ! is_array( $request['step_ids'] ) ) {
477            return new WP_REST_Response( 'Missing or invalid onboarding step IDs.', 400 );
478        }
479
480        $completed = Onboarding::complete_steps( $request['step_ids'] );
481
482        if ( ! $completed ) {
483            return new WP_REST_Response( 'An error occurred completing the onboarding step(s).', 500 );
484        }
485
486        return new WP_REST_Response( 'Onboarding step(s) completed.' );
487    }
488
489    /**
490     * Return Scan History for the API endpoint
491     *
492     * @return WP_REST_Response
493     */
494    public static function api_get_scan_history() {
495        $scan_history = Scan_History::get_scan_history( false );
496        return rest_ensure_response( $scan_history );
497    }
498}