Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 4 additions & 217 deletions class.jetpack-data.php
Original file line number Diff line number Diff line change
@@ -1,226 +1,13 @@
<?php

use Automattic\Jetpack\Constants\Manager as Constants_Manager;
use \Automattic\Jetpack\Connection\Manager as Connection_Manager;

class Jetpack_Data {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like it is possible to @deprecate classes, should we?

/*
* Used internally when we want to look for the Normal Blog Token
* without knowing its token key ahead of time.
*/
const MAGIC_NORMAL_TOKEN_KEY = ';normal;';

/**
* Gets the requested token.
*
* Tokens are one of two types:
* 1. Blog Tokens: These are the "main" tokens. Each site typically has one Blog Token,
* though some sites can have multiple "Special" Blog Tokens (see below). These tokens
* are not associated with a user account. They represent the site's connection with
* the Jetpack servers.
* 2. User Tokens: These are "sub-"tokens. Each connected user account has one User Token.
*
* All tokens look like "{$token_key}.{$private}". $token_key is a public ID for the
* token, and $private is a secret that should never be displayed anywhere or sent
* over the network; it's used only for signing things.
*
* Blog Tokens can be "Normal" or "Special".
* * Normal: The result of a normal connection flow. They look like
* "{$random_string_1}.{$random_string_2}"
* That is, $token_key and $private are both random strings.
* Sites only have one Normal Blog Token. Normal Tokens are found in either
* Jetpack_Options::get_option( 'blog_token' ) (usual) or the JETPACK_BLOG_TOKEN
* constant (rare).
* * Special: A connection token for sites that have gone through an alternative
* connection flow. They look like:
* ";{$special_id}{$special_version};{$wpcom_blog_id};.{$random_string}"
* That is, $private is a random string and $token_key has a special structure with
* lots of semicolons.
* Most sites have zero Special Blog Tokens. Special tokens are only found in the
* JETPACK_BLOG_TOKEN constant.
*
* In particular, note that Normal Blog Tokens never start with ";" and that
* Special Blog Tokens always do.
*
* When searching for a matching Blog Tokens, Blog Tokens are examined in the following
* order:
* 1. Defined Special Blog Tokens (via the JETPACK_BLOG_TOKEN constant)
* 2. Stored Normal Tokens (via Jetpack_Options::get_option( 'blog_token' ))
* 3. Defined Normal Tokens (via the JETPACK_BLOG_TOKEN constant)
*
* @param int|false $user_id false: Return the Blog Token. int: Return that user's User Token.
* @param string|false $token_key If provided, check that the token matches the provided input.
* false : Use first token. Default.
* Jetpack_Data::MAGIC_NORMAL_TOKEN_KEY : Use first Normal Token.
* non-empty string : Use matching token
* @return object|false
* @deprecated 7.5 Use Connection_Manager instead.
*/
public static function get_access_token( $user_id = false, $token_key = false ) {
$possible_special_tokens = array();
$possible_normal_tokens = array();

if ( $user_id ) {
if ( !$user_tokens = Jetpack_Options::get_option( 'user_tokens' ) ) {
return false;
}
if ( $user_id === JETPACK_MASTER_USER ) {
if ( !$user_id = Jetpack_Options::get_option( 'master_user' ) ) {
return false;
}
}
if ( !isset( $user_tokens[$user_id] ) || ! $user_tokens[$user_id] ) {
return false;
}
$user_token_chunks = explode( '.', $user_tokens[$user_id] );
if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) {
return false;
}
if ( $user_id != $user_token_chunks[2] ) {
return false;
}
$possible_normal_tokens[] = "{$user_token_chunks[0]}.{$user_token_chunks[1]}";
} else {
$stored_blog_token = Jetpack_Options::get_option( 'blog_token' );
if ( $stored_blog_token ) {
$possible_normal_tokens[] = $stored_blog_token;
}

$defined_tokens = Constants_Manager::is_defined( 'JETPACK_BLOG_TOKEN' )
? explode( ',', Constants_Manager::get_constant( 'JETPACK_BLOG_TOKEN' ) )
: array();

foreach ( $defined_tokens as $defined_token ) {
if ( ';' === $defined_token[0] ) {
$possible_special_tokens[] = $defined_token;
} else {
$possible_normal_tokens[] = $defined_token;
}
}
}

if ( self::MAGIC_NORMAL_TOKEN_KEY === $token_key ) {
$possible_tokens = $possible_normal_tokens;
} else {
$possible_tokens = array_merge( $possible_special_tokens, $possible_normal_tokens );
}

if ( ! $possible_tokens ) {
return false;
}

$valid_token = false;

if ( false === $token_key ) {
// Use first token.
$valid_token = $possible_tokens[0];
} elseif ( self::MAGIC_NORMAL_TOKEN_KEY === $token_key ) {
// Use first normal token.
$valid_token = $possible_tokens[0]; // $possible_tokens only contains normal tokens because of earlier check.
} else {
// Use the token matching $token_key or false if none.
// Ensure we check the full key.
$token_check = rtrim( $token_key, '.' ) . '.';

foreach ( $possible_tokens as $possible_token ) {
if ( hash_equals( substr( $possible_token, 0, strlen( $token_check ) ), $token_check ) ) {
$valid_token = $possible_token;
break;
}
}
}

if ( ! $valid_token ) {
return false;
}

return (object) array(
'secret' => $valid_token,
'external_user_id' => (int) $user_id,
);
}

/**
* This function mirrors Jetpack_Data::is_usable_domain() in the WPCOM codebase.
*
* @param $domain
* @param array $extra
*
* @return bool|WP_Error
*/
public static function is_usable_domain( $domain, $extra = array() ) {

// If it's empty, just fail out.
if ( ! $domain ) {
return new WP_Error( 'fail_domain_empty', sprintf( __( 'Domain `%1$s` just failed is_usable_domain check as it is empty.', 'jetpack' ), $domain ) );
}

/**
* Skips the usuable domain check when connecting a site.
*
* Allows site administrators with domains that fail gethostname-based checks to pass the request to WP.com
*
* @since 4.1.0
*
* @param bool If the check should be skipped. Default false.
*/
if ( apply_filters( 'jetpack_skip_usuable_domain_check', false ) ) {
return true;
}

// None of the explicit localhosts.
$forbidden_domains = array(
'wordpress.com',
'localhost',
'localhost.localdomain',
'127.0.0.1',
'local.wordpress.test', // VVV
'local.wordpress-trunk.test', // VVV
'src.wordpress-develop.test', // VVV
'build.wordpress-develop.test', // VVV
);
if ( in_array( $domain, $forbidden_domains ) ) {
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 ) );
}

// No .test or .local domains
if ( preg_match( '#\.(test|local)$#i', $domain ) ) {
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 ) );
}

// No WPCOM subdomains
if ( preg_match( '#\.wordpress\.com$#i', $domain ) ) {
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 ) );
}

// If PHP was compiled without support for the Filter module (very edge case)
if ( ! function_exists( 'filter_var' ) ) {
// Just pass back true for now, and let wpcom sort it out.
return true;
}

return true;
}

/**
* Returns true if the IP address passed in should not be in a reserved range, even if PHP says that it is.
* See: https://bugs.php.net/bug.php?id=66229 and https://github.com/php/php-src/commit/d1314893fd1325ca6aa0831101896e31135a2658
*
* This function mirrors Jetpack_Data::php_bug_66229_check() in the WPCOM codebase.
*/
public static function php_bug_66229_check( $ip ) {
if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return false;
}

$ip_arr = array_map( 'intval', explode( '.', $ip ) );

if ( 128 == $ip_arr[0] && 0 == $ip_arr[1] ) {
return true;
}

if ( 191 == $ip_arr[0] && 255 == $ip_arr[1] ) {
return true;
}

return false;
$connection = new Connection_Manager();
return $connection->get_access_token( $user_id, $token_key );
}
}
18 changes: 14 additions & 4 deletions class.jetpack.php
Original file line number Diff line number Diff line change
Expand Up @@ -3355,7 +3355,7 @@ public static function try_registration() {
'homeurl' => parse_url( get_home_url(), PHP_URL_HOST ),
) );
foreach ( $domains_to_check as $domain ) {
$result = Jetpack_Data::is_usable_domain( $domain );
$result = self::connection()->is_usable_domain( $domain );
if ( is_wp_error( $result ) ) {
return $result;
}
Expand Down Expand Up @@ -4878,6 +4878,10 @@ public static function xmlrpc_api_url() {
return untrailingslashit( $base ) . '/xmlrpc.php';
}

public static function connection() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some indentation weirdness in this method

return self::init()->connection_manager;
}

/**
* Creates two secret tokens and the end of life timestamp for them.
*
Expand All @@ -4891,11 +4895,11 @@ public static function generate_secrets( $action, $user_id = false, $exp = 600 )
$user_id = get_current_user_id();
}

return self::init()->connection_manager->generate_secrets( $action, $user_id, $exp );
return self::connection()->generate_secrets( $action, $user_id, $exp );
}

public static function get_secrets( $action, $user_id ) {
$secrets = self::init()->connection_manager->get_secrets( $action, $user_id );
$secrets = self::connection()->get_secrets( $action, $user_id );

if ( Connection_Manager::SECRETS_MISSING === $secrets ) {
return new WP_Error( 'verify_secrets_missing', 'Verification secrets not found' );
Expand All @@ -4908,8 +4912,14 @@ public static function get_secrets( $action, $user_id ) {
return $secrets;
}

/**
* @deprecated 7.5 Use Connection_Manager instead.
*
* @param $action
* @param $user_id
*/
public static function delete_secrets( $action, $user_id ) {
return self::init()->connection_manager->delete_secrets( $action, $user_id );
return self::connection()->delete_secrets( $action, $user_id );
}

/**
Expand Down
3 changes: 2 additions & 1 deletion modules/comments/comments.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

require dirname( __FILE__ ) . '/base.php';
use Automattic\Jetpack\Connection\Manager as Connection_Manager;

/**
* Main Comments class
Expand Down Expand Up @@ -291,7 +292,7 @@ public function comment_form_after() {
* one Normal Token per site, avoid concern by
* sending the magic "use the Normal Token" token key.
*/
$params['token_key'] = Jetpack_Data::MAGIC_NORMAL_TOKEN_KEY;
$params['token_key'] = Connection_Manager::MAGIC_NORMAL_TOKEN_KEY;
}
}

Expand Down
Loading