Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
3.45% covered (danger)
3.45%
1 / 29
14.29% covered (danger)
14.29%
1 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Waf_Stats
3.45% covered (danger)
3.45%
1 / 29
14.29% covered (danger)
14.29%
1 / 7
499.14
0.00% covered (danger)
0.00%
0 / 1
 get_blocked_requests
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 get_ip_allow_list_count
n/a
0 / 0
n/a
0 / 0
2
 get_ip_block_list_count
n/a
0 / 0
n/a
0 / 0
2
 get_rules_version
n/a
0 / 0
n/a
0 / 0
1
 get_automatic_rules_last_updated
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_global_stats_cache_expired
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 should_use_global_stats_cache
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 fetch_global_stats_from_api
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 get_global_stats_from_options
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_global_stats
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/**
3 * Class used to retrieve WAF stats
4 *
5 * @package automattic/jetpack-waf
6 */
7
8namespace Automattic\Jetpack\Waf;
9
10use Automattic\Jetpack\IP\Utils as IP_Utils;
11
12/**
13 * Retrieves WAF stats.
14 */
15class Waf_Stats {
16
17    /**
18     * Retrieve blocked requests from database
19     *
20     * @return array
21     */
22    public static function get_blocked_requests() {
23        return array(
24            'current_day' => Waf_Blocklog_Manager::get_current_day_block_count(),
25            'thirty_days' => Waf_Blocklog_Manager::get_thirty_days_block_counts(),
26            'all_time'    => Waf_Blocklog_Manager::get_all_time_block_count(),
27        );
28    }
29
30    /**
31     * Get IP allow list count
32     *
33     * @return int The number of valid IP addresses in the allow list
34     *
35     * @deprecated 0.20.1 Use Automattic\Jetpack\Waf\Waf_Blocklog_Manager API instead.
36     */
37    public static function get_ip_allow_list_count() {
38        _deprecated_function( __METHOD__, 'waf-0.20.1', 'Automattic\Jetpack\Waf\Waf_Blocklog_Manager' );
39
40        $ip_allow_list = get_option( Waf_Rules_Manager::IP_ALLOW_LIST_OPTION_NAME );
41
42        if ( ! $ip_allow_list ) {
43            return 0;
44        }
45
46        $results = IP_Utils::get_ip_addresses_from_string( $ip_allow_list );
47
48        return count( $results );
49    }
50
51    /**
52     * Get IP block list count
53     *
54     * @return int The number of valid IP addresses in the block list
55     *
56     * @deprecated 0.20.1 Use Automattic\Jetpack\Waf\Waf_Blocklog_Manager API instead.
57     */
58    public static function get_ip_block_list_count() {
59        _deprecated_function( __METHOD__, 'waf-0.20.1', 'Automattic\Jetpack\Waf\Waf_Blocklog_Manager' );
60
61        $ip_block_list = get_option( Waf_Rules_Manager::IP_BLOCK_LIST_OPTION_NAME );
62
63        if ( ! $ip_block_list ) {
64            return 0;
65        }
66
67        $results = IP_Utils::get_ip_addresses_from_string( $ip_block_list );
68
69        return count( $results );
70    }
71
72    /** The global stats cache
73     *
74     * @var array|null
75     */
76    public static $global_stats = null;
77
78    /**
79     * Get Rules version
80     *
81     * @return bool|string False if value is not found. The current stored rules version if cache is found.
82     *
83     * @deprecated 0.12.3 Use Automattic\Jetpack\Waf\Waf_Stats::get_automatic_rules_last_updated() to version the rules instead.
84     */
85    public static function get_rules_version() {
86        _deprecated_function( __METHOD__, 'waf-0.12.3', 'Automattic\Jetpack\Waf\Waf_Stats::get_automatic_rules_last_updated' );
87
88        return get_option( Waf_Rules_Manager::VERSION_OPTION_NAME );
89    }
90
91    /**
92     * Get Automatic Rules last updated timestamp
93     *
94     * @return bool|string False if value is not found. The timestamp the current stored rules was last updated if cache is found.
95     */
96    public static function get_automatic_rules_last_updated() {
97        return get_option( Waf_Rules_Manager::AUTOMATIC_RULES_LAST_UPDATED_OPTION_NAME );
98    }
99
100    /**
101     * Checks if the current cached global stats is expired and should be renewed
102     *
103     * @return boolean
104     */
105    public static function is_global_stats_cache_expired() {
106        $option_timestamp = get_option( 'jetpack_protect_global_stats_timestamp' );
107
108        if ( ! $option_timestamp ) {
109            return true;
110        }
111
112        return time() > (int) $option_timestamp;
113    }
114
115    /**
116     * Checks if we should consider the stored cache or bypass it
117     *
118     * @return boolean
119     */
120    public static function should_use_global_stats_cache() {
121        return ! ( defined( 'JETPACK_PROTECT_DEV__BYPASS_CACHE' ) && JETPACK_PROTECT_DEV__BYPASS_CACHE );
122    }
123
124    /**
125     * Get the global stats from the API endpoint
126     */
127    public static function fetch_global_stats_from_api() {
128        $url      = esc_url_raw( 'https://public-api.wordpress.com/wpcom/v2/jetpack-protect-global-stats' );
129        $response = wp_remote_get( $url );
130
131        $response_code = wp_remote_retrieve_response_code( $response );
132
133        if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
134            return new \WP_Error( 'failed_fetching_global_stats', 'Failed to fetch global stats data from the server', array( 'status' => $response_code ) );
135        }
136
137        $body = json_decode( wp_remote_retrieve_body( $response ) );
138
139        update_option( 'jetpack_protect_global_stats', maybe_serialize( $body ) );
140        update_option( 'jetpack_protect_global_stats_timestamp', time() + 86400 ); // Caches expires after 24 hours.
141
142        return $body;
143    }
144
145    /**
146     * Gets the current cached global stats
147     *
148     * @return bool|array False if value is not found. Array with values if cache is found.
149     */
150    public static function get_global_stats_from_options() {
151        return maybe_unserialize( get_option( 'jetpack_protect_global_stats' ) );
152    }
153
154    /**
155     * Get the global stats
156     * If the cache is expired, it will fetch the data from the API
157     * If the cache is not expired, it will return the cached data
158     *
159     * @param bool $refresh_from_wpcom Whether to refresh the data from the API.
160     * @return array|\WP_Error
161     */
162    public static function get_global_stats( $refresh_from_wpcom = false ) {
163        if ( self::$global_stats !== null ) {
164            return self::$global_stats;
165        }
166
167        if ( $refresh_from_wpcom || ! self::should_use_global_stats_cache() || self::is_global_stats_cache_expired() ) {
168            $global_stats = self::fetch_global_stats_from_api();
169        } else {
170            $global_stats = self::get_global_stats_from_options();
171        }
172
173        // Ensure that $global_stats is of the correct type
174        if ( ( ! is_object( $global_stats ) && ! ( $global_stats instanceof \WP_Error ) ) ) {
175            return new \WP_Error( 'unexpected_type', 'Unexpected type or null returned for global stats' );
176        }
177
178        return $global_stats;
179    }
180}