Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
34.34% covered (danger)
34.34%
34 / 99
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
REST_Controller
34.34% covered (danger)
34.34%
34 / 99
40.00% covered (danger)
40.00%
2 / 5
321.82
0.00% covered (danger)
0.00%
0 / 1
 register_rest_routes
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
6
 update_rules
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 waf
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 update_waf
35.71% covered (danger)
35.71%
15 / 42
0.00% covered (danger)
0.00%
0 / 1
191.04
 waf_permissions_callback
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Class use to register REST API endpoints used by the WAF
4 *
5 * @package automattic/jetpack-waf
6 */
7
8namespace Automattic\Jetpack\Waf;
9
10use Automattic\Jetpack\Connection\REST_Connector;
11use Automattic\Jetpack\Waf\Brute_Force_Protection\Brute_Force_Protection;
12use WP_Error;
13use WP_REST_Request;
14use WP_REST_Response;
15use WP_REST_Server;
16
17/**
18 * Defines our endponts.
19 */
20class REST_Controller {
21    /**
22     * Register REST API endpoints.
23     *
24     * @return void
25     */
26    public static function register_rest_routes() {
27        // Ensure routes are only initialized once.
28        static $routes_registered = false;
29        if ( $routes_registered ) {
30            return;
31        }
32
33        register_rest_route(
34            'jetpack/v4',
35            '/waf',
36            array(
37                'methods'             => WP_REST_Server::READABLE,
38                'callback'            => __CLASS__ . '::waf',
39                'permission_callback' => __CLASS__ . '::waf_permissions_callback',
40            )
41        );
42
43        register_rest_route(
44            'jetpack/v4',
45            '/waf',
46            array(
47                'methods'             => WP_REST_Server::EDITABLE,
48                'callback'            => __CLASS__ . '::update_waf',
49                'permission_callback' => __CLASS__ . '::waf_permissions_callback',
50            )
51        );
52
53        register_rest_route(
54            'jetpack/v4',
55            '/waf/update-rules',
56            array(
57                'methods'             => WP_REST_Server::EDITABLE,
58                'callback'            => __CLASS__ . '::update_rules',
59                'permission_callback' => __CLASS__ . '::waf_permissions_callback',
60            )
61        );
62
63        $routes_registered = true;
64    }
65
66    /**
67     * Update rules endpoint
68     *
69     * @return WP_REST_Response|WP_Error
70     */
71    public static function update_rules() {
72        try {
73            Waf_Rules_Manager::generate_automatic_rules();
74            Waf_Rules_Manager::generate_rules();
75        } catch ( Waf_Exception $e ) {
76            return $e->get_wp_error();
77        }
78
79        return rest_ensure_response(
80            array(
81                'success' => true,
82                'message' => __( 'Rules updated successfully', 'jetpack-waf' ),
83            )
84        );
85    }
86
87    /**
88     * WAF Endpoint
89     *
90     * @return WP_REST_Response
91     */
92    public static function waf() {
93        return rest_ensure_response(
94            array_merge(
95                Waf_Runner::get_config(),
96                array(
97                    'waf_supported'                => Waf_Runner::is_supported_environment(),
98                    'automatic_rules_last_updated' => Waf_Stats::get_automatic_rules_last_updated(),
99                )
100            )
101        );
102    }
103
104    /**
105     * Update WAF Endpoint
106     *
107     * @param WP_REST_Request $request The API request.
108     *
109     * @return WP_REST_Response|WP_Error
110     */
111    public static function update_waf( $request ) {
112        // Automatic Rules Enabled
113        if ( isset( $request[ Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ] ) ) {
114            update_option( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME, $request->get_param( Waf_Rules_Manager::AUTOMATIC_RULES_ENABLED_OPTION_NAME ) ? '1' : '' );
115        }
116
117        /**
118         * IP Lists Enabled
119         *
120         * @deprecated 0.17.0 This is a legacy option maintained here for backwards compatibility.
121         */
122        if ( isset( $request['jetpack_waf_ip_list'] ) ) {
123            update_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME, $request['jetpack_waf_ip_list'] ? '1' : '' );
124            update_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, $request['jetpack_waf_ip_list'] ? '1' : '' );
125        }
126
127        // IP Block List
128        if ( isset( $request[ Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME ] ) ) {
129            update_option( Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME, $request[ Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME ] );
130        }
131        if ( isset( $request[ Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ] ) ) {
132            update_option( Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME, $request[ Waf_Rules_Manager::IP_BLOCK_LIST_ENABLED_OPTION_NAME ] ? '1' : '' );
133        }
134
135        // IP Allow List
136        if ( isset( $request[ Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ] ) ) {
137            update_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME, $request[ Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME ] );
138        }
139        if ( isset( $request[ Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ] ) ) {
140            update_option( Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME, $request[ Waf_Rules_Manager::IP_ALLOW_LIST_ENABLED_OPTION_NAME ] ? '1' : '' );
141        }
142
143        // Share Data
144        if ( isset( $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) ) {
145            // If a user disabled the regular share we should disable the debug share data option.
146            if ( ! $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ) {
147                update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, '' );
148            }
149
150            update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, $request[ Waf_Runner::SHARE_DATA_OPTION_NAME ] ? '1' : '' );
151        }
152
153        // Share Debug Data
154        if ( isset( $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ) ) {
155            // If a user toggles the debug share we should enable the regular share data option.
156            if ( $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ) {
157                update_option( Waf_Runner::SHARE_DATA_OPTION_NAME, 1 );
158            }
159
160            update_option( Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME, $request[ Waf_Runner::SHARE_DEBUG_DATA_OPTION_NAME ] ? '1' : '' );
161        }
162
163        // Brute Force Protection
164        if ( isset( $request['brute_force_protection'] ) ) {
165            $enable_brute_force             = (bool) $request['brute_force_protection'];
166            $brute_force_protection_toggled =
167                $enable_brute_force
168                    ? Brute_Force_Protection::enable()
169                    : Brute_Force_Protection::disable();
170
171            if ( ! $brute_force_protection_toggled ) {
172                return new WP_Error(
173                    $enable_brute_force
174                        ? 'brute_force_protection_activation_failed'
175                        : 'brute_force_protection_deactivation_failed',
176                    $enable_brute_force
177                        ? __( 'Brute force protection could not be activated.', 'jetpack-waf' )
178                        : __( 'Brute force protection could not be deactivated.', 'jetpack-waf' ),
179                    array( 'status' => 500 )
180                );
181            }
182        }
183
184        // Only attempt to update the WAF if the module is supported
185        if ( Waf_Runner::is_supported_environment() ) {
186            try {
187                Waf_Runner::update_waf();
188            } catch ( Waf_Exception $e ) {
189                return $e->get_wp_error();
190            }
191        }
192
193        return self::waf();
194    }
195
196    /**
197     * WAF Endpoint Permissions Callback
198     *
199     * @return bool|WP_Error True if user can view the Jetpack admin page.
200     */
201    public static function waf_permissions_callback() {
202        if ( current_user_can( 'manage_options' ) ) {
203            return true;
204        }
205
206        return new WP_Error(
207            'invalid_user_permission_manage_options',
208            REST_Connector::get_user_permissions_error_msg(),
209            array( 'status' => rest_authorization_required_code() )
210        );
211    }
212}