Completed
Push — add/multiple-blog-tokens ( b8ed3a...820dca )
by
unknown
31:56 queued 25:11
created

class.jetpack-data.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
class Jetpack_Data {
4
	/**
5
	 * Gets locally stored token
6
	 *
7
	 * @param int|false $user_id false: Return the Blog Token. int: Return that user's User Token.
8
	 * @param string|false $token_key: If provided, check that the stored token matches the provided input.
0 ignored issues
show
There is no parameter named $token_key:. Did you maybe mean $token_key?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
9
	 *                                 false           : Use first token. Default.
10
	 *                                 ';stored;'      : Use first stored token. (Stored tokens are the normal kind.)
11
	 *                                 non-empty string: Use matching token
12
	 * @return object|false
13
	 */
14
	public static function get_access_token( $user_id = false, $token_key = false ) {
15
		if ( $user_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $user_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
16
			if ( !$user_tokens = Jetpack_Options::get_option( 'user_tokens' ) ) {
17
				return false;
18
			}
19
			if ( $user_id === JETPACK_MASTER_USER ) {
20
				if ( !$user_id = Jetpack_Options::get_option( 'master_user' ) ) {
21
					return false;
22
				}
23
			}
24
			if ( !isset( $user_tokens[$user_id] ) || ! $user_tokens[$user_id] ) {
25
				return false;
26
			}
27
			$user_token_chunks = explode( '.', $user_tokens[$user_id] );
28
			if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) {
29
				return false;
30
			}
31
			if ( $user_id != $user_token_chunks[2] ) {
32
				return false;
33
			}
34
			$possible_tokens = array( "{$user_token_chunks[0]}.{$user_token_chunks[1]}" );
35
		} else {
36
			$possible_tokens = Jetpack_Constants::is_defined( 'JETPACK_BLOG_TOKEN' ) && ';stored;' !== $token_key
37
				? explode( ',', Jetpack_Constants::get_constant( 'JETPACK_BLOG_TOKEN' ) )
38
				: array();
39
40
			$stored_blog_token = Jetpack_Options::get_option( 'blog_token' );
41
			if ( $stored_blog_token ) {
42
				$possible_tokens[] = $stored_blog_token;
43
			}
44
45
			if ( ! $possible_tokens ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $possible_tokens of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
46
				return false;
47
			}
48
		}
49
50
		$valid_token = false;
51
52
		if ( false === $token_key ) {
53
			// Use first token.
54
			$valid_token = $possible_tokens[0];
55
		} elseif ( ';stored;' === $token_key ) {
56
			// Use first stored token.
57
			$valid_token = $possible_tokens[0]; // $tokens only contains stored tokens because of earlier check.
58
		} else {
59
			// Use the token matching $token_key or false if none.
60
			// Ensure we check the full key.
61
			$token_check = rtrim( $token_key, '.' ) . '.';
62
63
			foreach ( $possible_tokens as $possible_token ) {
64
				if ( hash_equals( substr( $possible_token, 0, strlen( $token_check ) ), $token_check ) ) {
65
					$valid_token = $possible_token;
66
					break;
67
				}
68
			}
69
		}
70
71
		if ( ! $valid_token ) {
72
			return false;
73
		}
74
75
		return (object) array(
76
			'secret' => $valid_token,
77
			'external_user_id' => (int) $user_id,
78
		);
79
	}
80
81
	/**
82
	 * This function mirrors Jetpack_Data::is_usable_domain() in the WPCOM codebase.
83
	 *
84
	 * @param $domain
85
	 * @param array $extra
86
	 *
87
	 * @return bool|WP_Error
88
	 */
89
	public static function is_usable_domain( $domain, $extra = array() ) {
90
91
		// If it's empty, just fail out.
92
		if ( ! $domain ) {
93
			return new WP_Error( 'fail_domain_empty', sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it is empty.', 'jetpack' ), $domain ) );
94
		}
95
96
		/**
97
		 * Skips the usuable domain check when connecting a site.
98
		 *
99
		 * Allows site administrators with domains that fail gethostname-based checks to pass the request to WP.com
100
		 *
101
		 * @since 4.1.0
102
		 *
103
		 * @param bool If the check should be skipped. Default false.
104
		 */
105
		if ( apply_filters( 'jetpack_skip_usuable_domain_check', false ) ) {
106
			return true;
107
		}
108
109
		// None of the explicit localhosts.
110
		$forbidden_domains = array(
111
			'wordpress.com',
112
			'localhost',
113
			'localhost.localdomain',
114
			'127.0.0.1',
115
			'local.wordpress.test',         // VVV
116
			'local.wordpress-trunk.test',   // VVV
117
			'src.wordpress-develop.test',   // VVV
118
			'build.wordpress-develop.test', // VVV
119
		);
120 View Code Duplication
		if ( in_array( $domain, $forbidden_domains ) ) {
121
			return new WP_Error( 'fail_domain_forbidden', sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it is in the forbidden array.', 'jetpack' ), $domain ) );
122
		}
123
124
		// No .test or .local domains
125 View Code Duplication
		if ( preg_match( '#\.(test|local)$#i', $domain ) ) {
126
			return new WP_Error( 'fail_domain_tld', sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it uses an invalid top level domain.', 'jetpack' ), $domain ) );
127
		}
128
129
		// No WPCOM subdomains
130 View Code Duplication
		if ( preg_match( '#\.wordpress\.com$#i', $domain ) ) {
131
			return new WP_Error( 'fail_subdomain_wpcom', sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it is a subdomain of WordPress.com.', 'jetpack' ), $domain ) );
132
		}
133
134
		// If PHP was compiled without support for the Filter module (very edge case)
135
		if ( ! function_exists( 'filter_var' ) ) {
136
			// Just pass back true for now, and let wpcom sort it out.
137
			return true;
138
		}
139
140
		return true;
141
	}
142
143
	/**
144
	 * Returns true if the IP address passed in should not be in a reserved range, even if PHP says that it is.
145
	 * See: https://bugs.php.net/bug.php?id=66229 and https://github.com/php/php-src/commit/d1314893fd1325ca6aa0831101896e31135a2658
146
	 *
147
	 * This function mirrors Jetpack_Data::php_bug_66229_check() in the WPCOM codebase.
148
	 */
149
	public static function php_bug_66229_check( $ip ) {
150
		if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
151
			return false;
152
		}
153
154
		$ip_arr = array_map( 'intval', explode( '.', $ip ) );
155
156
		if ( 128 == $ip_arr[0] && 0 == $ip_arr[1] ) {
157
			return true;
158
		}
159
160
		if ( 191 == $ip_arr[0] && 255 == $ip_arr[1] ) {
161
			return true;
162
		}
163
164
		return false;
165
	}
166
}
167