PluginProbe
QuadMenu – Mega Menu / 3.3.8
QuadMenu – Mega Menu v3.3.8
3.3.8 3.3.7 3.3.6 trunk 1.8.4 1.8.5 1.8.7 1.8.8 1.8.9 1.9.0 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 88 releases
← All changes | jetpack_vendor/automattic/jetpack-status/src/class-visitor.php +73 -5 3.3.6 → 3.3.8 View file →
@@ -6,8 +6,10 @@
6 6 */
7 7
8 8 namespace Automattic\Jetpack\Status;
9 9
10 +use Automattic\Jetpack\IP\Utils as IP_Utils;
11 +
10 12 /**
11 13 * Visitor class.
12 14 */
13 15 class Visitor {
@@ -14,14 +16,42 @@
14 16
15 17 /**
16 18 * Gets current user IP address.
17 19 *
20 + * Only a value that parses as an IP address is returned. With `$check_all_headers`, the
21 + * forwarded headers are tried in order, a comma-separated list yields its first valid entry,
22 + * and a header holding no valid address is skipped.
23 + *
24 + * A site with a trusted header configured does not use that sweep at all. Brute force
25 + * protection stores which header carries the visitor address, how far back to count in its
26 + * list, and whether that list runs in reverse, all worked out for this site's own proxy
27 + * setup. Once that answer exists it is the answer, including when the request did not carry
28 + * the header — `IP\Utils::get_ip()` falls back to `REMOTE_ADDR` itself in that case. Reading
29 + * the sweep afterwards would let a request that simply omits the trusted header pick its own
30 + * address out of a header it fully controls, and would hand Jetpack two answers for one
31 + * request, since brute force protection resolves the same visitor through `IP\Utils`.
32 + *
33 + * That is a guarantee about which source is consulted, not about the address itself: it
34 + * still assumes the proxy named in the stored configuration rewrites the header. A request
35 + * reaching the origin directly can present that header itself.
36 + *
37 + * The address is normalized by `IP\Utils::clean_ip()`: it is lowercased, anything following an
38 + * " unless " separator is dropped, and a port suffix, IPv6 brackets, or an `::ffff:` IPv4
39 + * mapping are reduced to the bare address. Code comparing this value against a stored or
40 + * configured address should normalize that address the same way.
41 + *
18 42 * @param bool $check_all_headers Check all headers? Default is `false`.
19 43 *
20 - * @return string Current user IP address.
44 + * @return string Current user IP address, or an empty string if no valid address could be determined.
21 45 */
22 46 public function get_ip( $check_all_headers = false ) {
23 47 if ( $check_all_headers ) {
48 + $trusted_header_data = get_site_option( 'trusted_ip_header' );
49 + if ( isset( $trusted_header_data->trusted_header ) ) {
50 + $trusted_ip = IP_Utils::get_ip();
51 + return false !== $trusted_ip ? $trusted_ip : '';
52 + }
53 +
24 54 foreach ( array(
25 55 'HTTP_CF_CONNECTING_IP',
26 56 'HTTP_CLIENT_IP',
27 57 'HTTP_X_FORWARDED_FOR',
@@ -30,16 +60,23 @@
30 60 'HTTP_FORWARDED_FOR',
31 61 'HTTP_FORWARDED',
32 62 'HTTP_VIA',
33 63 ) as $key ) {
34 - if ( ! empty( $_SERVER[ $key ] ) ) {
35 - // @todo Some of these might actually be lists of IPs (e.g. HTTP_X_FORWARDED_FOR) or something else entirely (HTTP_VIA).
36 - return filter_var( wp_unslash( $_SERVER[ $key ] ) );
64 + if ( empty( $_SERVER[ $key ] ) ) {
65 + continue;
37 66 }
67 + // Proxies append to the list, so the leftmost entry is the client.
68 + foreach ( explode( ',', (string) wp_unslash( $_SERVER[ $key ] ) ) as $candidate ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each entry is validated by clean_ip() below.
69 + $ip = IP_Utils::clean_ip( $candidate );
70 + if ( false !== $ip ) {
71 + return $ip;
72 + }
73 + }
38 74 }
39 75 }
40 76
41 - return ! empty( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
77 + $ip = empty( $_SERVER['REMOTE_ADDR'] ) ? false : IP_Utils::clean_ip( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- clean_ip() validates it.
78 + return false !== $ip ? $ip : '';
42 79 }
43 80
44 81 /**
45 82 * Simple gate check for a11n feature testing purposes using AT_PROXIED_REQUEST constant.
@@ -51,6 +88,37 @@
51 88 * @return bool True if the current request is PROXIED, false otherwise.
52 89 */
53 90 public function is_automattician_feature_flags_only() {
54 91 return ( defined( 'AT_PROXIED_REQUEST' ) && AT_PROXIED_REQUEST );
92 + }
93 +
94 + /**
95 + * Whether the current request should be attributed to an Automattician in analytics.
96 + *
97 + * True for an identified Automattician on WordPress.com Simple, and for A8C-proxied
98 + * requests on both Simple and WoA. Use it to tag Tracks events as internal traffic so
99 + * it can be filtered out of product reporting — this matters most for newly launched
100 + * features, where a small amount of internal testing is a large share of the totals
101 + * and there is no way to separate it after the fact.
102 + *
103 + * IMPORTANT: Reporting signal only, never authorization. A proxied request says
104 + * something about where the request came from, not who the user is.
105 + *
106 + * @since 6.4.0
107 + *
108 + * @return bool True if the request looks like Automattician traffic, false otherwise.
109 + */
110 + public function is_tracking_automattician() {
111 + // Identified Automattician on WordPress.com Simple.
112 + if ( function_exists( 'is_automattician' ) && \is_automattician() ) {
113 + return true;
114 + }
115 +
116 + // Proxied A8C request on WordPress.com Simple.
117 + if ( function_exists( 'wpcom_is_proxied_request' ) && \wpcom_is_proxied_request() ) {
118 + return true;
119 + }
120 +
121 + // Proxied A8C request on WoA.
122 + return $this->is_automattician_feature_flags_only();
55 123 }
56 124 }