Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Threats
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 7
702
0.00% covered (danger)
0.00%
0 / 1
 get_api_base
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 update_threat
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 ignore_threat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 unignore_threat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 fix_threats
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
 fix_threats_status
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
42
 scan
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * Class to handle Threats
4 *
5 * @package automattic/jetpack-protect-plugin
6 */
7
8namespace Automattic\Jetpack\Protect;
9
10use Automattic\Jetpack\Connection\Client;
11use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12use Automattic\Jetpack\Protect_Status\Scan_Status;
13use Jetpack_Options;
14use WP_Error;
15
16/**
17 * Class that handles management of individual threats.
18 */
19class Threats {
20    /**
21     * Gets the base "Alerts" (Threats) endpoint.
22     *
23     * @return WP_Error|string
24     */
25    private static function get_api_base() {
26        $blog_id      = Jetpack_Options::get_option( 'id' );
27        $is_connected = ( new Connection_Manager() )->is_connected();
28
29        if ( ! $blog_id || ! $is_connected ) {
30            return new WP_Error( 'site_not_connected' );
31        }
32
33        $api_url = sprintf( '/sites/%d/alerts', $blog_id );
34
35        return $api_url;
36    }
37
38    /**
39     * Update Threat
40     *
41     * @param string $threat_id The threat ID.
42     * @param array  $updates   The keys/values to update.
43     *
44     * @return bool
45     */
46    public static function update_threat( $threat_id, $updates ) {
47        $api_base = self::get_api_base();
48        if ( is_wp_error( $api_base ) ) {
49            return false;
50        }
51
52        $response = Client::wpcom_json_api_request_as_user(
53            "$api_base/$threat_id",
54            '2',
55            array( 'method' => 'POST' ),
56            wp_json_encode( $updates, JSON_UNESCAPED_SLASHES ),
57            'wpcom'
58        );
59
60        $response_code = wp_remote_retrieve_response_code( $response );
61
62        if ( is_wp_error( $response ) || 200 !== $response_code ) {
63            return false;
64        }
65
66        // clear the now out-of-date cache
67        Scan_Status::delete_option();
68        Scan_History::delete_option();
69
70        return true;
71    }
72
73    /**
74     * Ignore Threat
75     *
76     * @param string $threat_id The threat ID.
77     *
78     * @return bool
79     */
80    public static function ignore_threat( $threat_id ) {
81        return self::update_threat( $threat_id, array( 'ignore' => true ) );
82    }
83
84    /**
85     * Unignore Threat
86     *
87     * @param string $threat_id The threat ID.
88     *
89     * @return bool
90     */
91    public static function unignore_threat( $threat_id ) {
92        return self::update_threat( $threat_id, array( 'unignore' => true ) );
93    }
94
95    /**
96     * Fix Threats
97     *
98     * @param array<string> $threat_ids Threat IDs.
99     *
100     * @return bool|array
101     */
102    public static function fix_threats( $threat_ids ) {
103        $api_base = self::get_api_base();
104        if ( is_wp_error( $api_base ) ) {
105            return false;
106        }
107
108        $response = Client::wpcom_json_api_request_as_user(
109            "$api_base/fix",
110            '2',
111            array( 'method' => 'POST' ),
112            wp_json_encode(
113                array(
114                    'threat_ids' => $threat_ids,
115                ),
116                JSON_UNESCAPED_SLASHES
117            ),
118            'wpcom'
119        );
120
121        $response_code = wp_remote_retrieve_response_code( $response );
122
123        if ( is_wp_error( $response ) || 200 !== $response_code ) {
124            return false;
125        }
126
127        // clear the now out-of-date cache
128        Scan_Status::delete_option();
129        Scan_History::delete_option();
130
131        $parsed_response = json_decode( $response['body'] );
132
133        if ( ! $parsed_response ) {
134            return false;
135        }
136
137        return $parsed_response;
138    }
139
140    /**
141     * Fix Threats Status
142     *
143     * @param array<string> $threat_ids Threat IDs.
144     *
145     * @return bool|array
146     */
147    public static function fix_threats_status( $threat_ids ) {
148        if ( empty( $threat_ids ) ) {
149            return false;
150        }
151
152        $api_base = self::get_api_base();
153        if ( is_wp_error( $api_base ) ) {
154            return false;
155        }
156
157        $response = Client::wpcom_json_api_request_as_user(
158            add_query_arg( 'threat_ids', $threat_ids, "$api_base/fix" ),
159            '2',
160            array( 'method' => 'GET' ),
161            null,
162            'wpcom'
163        );
164
165        $response_code = wp_remote_retrieve_response_code( $response );
166
167        if ( is_wp_error( $response ) || 200 !== $response_code ) {
168            return false;
169        }
170
171        $parsed_response = json_decode( $response['body'] );
172
173        if ( ! $parsed_response ) {
174            return false;
175        }
176
177        // clear the potentially out-of-date cache
178        Scan_Status::delete_option();
179        Scan_History::delete_option();
180
181        return $parsed_response;
182    }
183
184    /**
185     * Scan enqueue
186     *
187     * @return bool
188     */
189    public static function scan() {
190        $blog_id      = Jetpack_Options::get_option( 'id' );
191        $is_connected = ( new Connection_Manager() )->is_connected();
192
193        if ( ! $blog_id || ! $is_connected ) {
194            return false;
195        }
196
197        $api_base = sprintf( '/sites/%d/scan', $blog_id );
198
199        if ( is_wp_error( $api_base ) ) {
200            return false;
201        }
202
203        $response = Client::wpcom_json_api_request_as_blog(
204            "$api_base/enqueue",
205            '2',
206            array( 'method' => 'POST' ),
207            null,
208            'wpcom'
209        );
210
211        $response_code = wp_remote_retrieve_response_code( $response );
212
213        if ( is_wp_error( $response ) || 200 !== $response_code ) {
214            return false;
215        }
216
217        // clear the now out-of-date cache
218        Scan_Status::delete_option();
219        Scan_History::delete_option();
220
221        return true;
222    }
223}