updated plugin Jetpack Protect version 3.0.2

This commit is contained in:
2024-10-09 12:44:31 +00:00
committed by Gitium
parent a35dc419bc
commit f970470c59
283 changed files with 6970 additions and 2338 deletions

View File

@ -0,0 +1,44 @@
<?php
/**
* Package description here
*
* @package automattic/jetpack-explat
*/
namespace Automattic\Jetpack;
use Automattic\Jetpack\Connection\Rest_Authentication;
use Automattic\Jetpack\ExPlat\REST_Controller;
/**
* Class description.
*/
class ExPlat {
/**
* ExPlat package version
*
* @var string
*/
const PACKAGE_VERSION = '0.1.7';
/**
* Initializer.
* Used to configure the ExPlat package
*
* @return void
*/
public static function init() {
if ( did_action( 'jetpack_explat_initialized' ) ) {
return;
}
// Set up the REST authentication hooks.
Rest_Authentication::init();
add_action( 'rest_api_init', array( new REST_Controller(), 'register_rest_routes' ) );
// Runs right after the Jetpack ExPlat package is initialized.
do_action( 'jetpack_explat_initialized' );
}
}

View File

@ -0,0 +1,118 @@
<?php
/**
* The ExPlat Rest Controller class.
* Registers the REST routes for ExPlat backend
*
* @package automattic/jetpack-explat
*/
namespace Automattic\Jetpack\ExPlat;
use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
use WP_Error;
use WP_REST_Server;
/**
* Registers general REST routes for ExPlat.
*/
class REST_Controller {
/**
* Namespace for the REST API.
*
* @var string
*/
public static $namespace = 'jetpack/v4/explat';
/**
* Current version of the ExPlat API and components
*
* @var string
*/
const EXPLAT_API_VERSION = '0.1.0';
/**
* Base API URI for WordPress.com
*
* @var string
*/
const WPCOM_API_BASE_URL = 'https://public-api.wordpress.com/wpcom/v2';
/**
* Registers the REST routes.
*
* @access public
* @static
*/
public function register_rest_routes() {
register_rest_route(
static::$namespace,
'assignments',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_assignments' ),
'permission_callback' => '__return_true',
'args' => array(
'experiment_name' => array(
'type' => 'string',
),
'anon_id' => array(
'type' => 'string',
),
'as_connected_user' => array(
'type' => 'boolean',
),
),
)
);
}
/**
* Get the assignments for a given experiment and anon_id
*
* @param WP_REST_Request $request The REST request object.
* @return WP_REST_Response
*/
public function get_assignments( $request ) {
$response = null;
$is_user_connected = ( new Jetpack_Connection() )->is_user_connected();
$request_path = '/experiments/' . self::EXPLAT_API_VERSION . '/assignments/jetpack';
$args = array(
'experiment_name' => $request['experiment_name'],
'anon_id' => $request['anon_id'],
);
if ( $request['as_connected_user'] && $is_user_connected ) {
$response = Client::wpcom_json_api_request_as_user(
add_query_arg( $args, $request_path ),
'v2'
);
} else {
$response = wp_remote_get(
add_query_arg( $args, self::WPCOM_API_BASE_URL . $request_path )
);
}
if ( is_wp_error( $response ) ) {
return new WP_Error(
'wp_error_fetching_assignment',
$response->get_error_message(),
array( 'status' => 500 )
);
}
$response_code = wp_remote_retrieve_response_code( $response );
if ( 200 !== $response_code ) {
return new WP_Error(
'http_error_fetching_assignment',
wp_remote_retrieve_response_message( $response ),
array( 'status' => $response_code )
);
}
return rest_ensure_response(
json_decode( wp_remote_retrieve_body( $response ), true )
);
}
}

View File

@ -0,0 +1,61 @@
/**
* External dependencies
*/
import cookie from 'cookie';
let initializeAnonIdPromise: Promise< string | null > | null = null;
const anonIdPollingIntervalMilliseconds = 50;
const anonIdPollingIntervalMaxAttempts = 100; // 50 * 100 = 5000 = 5 seconds
/**
* Gather w.js anonymous cookie, tk_ai
*
* @return {?string} The anonymous cookie value, or null if it doesn't exist
*/
export const readAnonCookie = (): string | null => {
return cookie.parse( document.cookie ).tk_ai || null;
};
/**
* Initializes the anonId:
* - Polls for AnonId receival
* - Should only be called once at startup
* - Happens to be safe to call multiple times if it is necessary to reset the anonId - something like this was necessary for testing.
*
* This purely for boot-time initialization, in usual circumstances it will be retrieved within 100-300ms, it happens in parallel booting
* so should only delay experiment loading that much for boot-time experiments. In some circumstances such as a very slow connection this
* can take a lot longer.
*
* The state of initializeAnonIdPromise should be used rather than the return of this function.
* The return is only avaliable to make this easier to test.
*
* Throws on error.
*
* @return {Promise<string | null>} The anonymous cookie value, or null if it doesn't exist
*/
export const initializeAnonId = async (): Promise< string | null > => {
let attempt = 0;
initializeAnonIdPromise = new Promise( res => {
const poll = () => {
const anonId = readAnonCookie();
if ( typeof anonId === 'string' && anonId !== '' ) {
res( anonId );
return;
}
if ( anonIdPollingIntervalMaxAttempts - 1 <= attempt ) {
res( null );
return;
}
attempt += 1;
setTimeout( poll, anonIdPollingIntervalMilliseconds );
};
poll();
} );
return initializeAnonIdPromise;
};
export const getAnonId = async (): Promise< string | null > => {
return await initializeAnonIdPromise;
};

View File

@ -0,0 +1,29 @@
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
const fetchExperimentAssignment =
( asConnectedUser = false ) =>
async ( {
experimentName,
anonId,
}: {
experimentName: string;
anonId: string | null;
} ): Promise< unknown > => {
if ( ! anonId ) {
throw new Error( `Tracking is disabled, can't fetch experimentAssignment` );
}
const params = {
experiment_name: experimentName,
anon_id: anonId ?? undefined,
as_connected_user: asConnectedUser,
};
const assignmentsRequestUrl = addQueryArgs( 'jetpack/v4/explat/assignments', params );
return await apiFetch( { path: assignmentsRequestUrl } );
};
export const fetchExperimentAssignmentAnonymously = fetchExperimentAssignment( false );
export const fetchExperimentAssignmentWithAuth = fetchExperimentAssignment( true );

View File

@ -0,0 +1,39 @@
/**
* Internal dependencies
*/
import { isDevelopmentMode } from './utils';
export const logError = ( error: Record< string, string > & { message: string } ): void => {
const onLoggingError = ( e: unknown ) => {
if ( isDevelopmentMode ) {
console.error( '[ExPlat] Unable to send error to server:', e ); // eslint-disable-line no-console
}
};
try {
const { message, ...properties } = error;
const logStashError = {
message,
properties: {
...properties,
context: 'explat',
explat_client: 'jetpack',
},
};
if ( isDevelopmentMode ) {
console.error( '[ExPlat] ', error.message, error ); // eslint-disable-line no-console
} else {
const body = new window.FormData();
body.append( 'error', JSON.stringify( logStashError ) );
window
.fetch( 'https://public-api.wordpress.com/rest/v1.1/js-error', {
method: 'POST',
body,
} )
.catch( onLoggingError );
}
} catch ( e ) {
onLoggingError( e );
}
};

View File

@ -0,0 +1,51 @@
/**
* External dependencies
*/
import { createExPlatClient } from '@automattic/explat-client';
import createExPlatClientReactHelpers from '@automattic/explat-client-react-helpers';
/**
* Internal dependencies
*/
import { getAnonId, initializeAnonId } from './anon';
import {
fetchExperimentAssignmentAnonymously,
fetchExperimentAssignmentWithAuth,
} from './assignment';
import { logError } from './error';
import { isDevelopmentMode } from './utils';
export const initializeExPlat = (): void => {
initializeAnonId().catch( e => logError( { message: e.message } ) );
};
initializeExPlat();
const exPlatClient = createExPlatClient( {
fetchExperimentAssignment: fetchExperimentAssignmentAnonymously,
getAnonId,
logError,
isDevelopmentMode,
} );
export const { loadExperimentAssignment, dangerouslyGetExperimentAssignment } = exPlatClient;
export const { useExperiment, Experiment, ProvideExperimentData } =
createExPlatClientReactHelpers( exPlatClient );
const exPlatClientWithAuth = createExPlatClient( {
fetchExperimentAssignment: fetchExperimentAssignmentWithAuth,
getAnonId,
logError,
isDevelopmentMode,
} );
export const {
loadExperimentAssignment: loadExperimentAssignmentWithAuth,
dangerouslyGetExperimentAssignment: dangerouslyGetExperimentAssignmentWithAuth,
} = exPlatClientWithAuth;
export const {
useExperiment: useExperimentWithAuth,
Experiment: ExperimentWithAuth,
ProvideExperimentData: ProvideExperimentDataWithAuth,
} = createExPlatClientReactHelpers( exPlatClientWithAuth );

View File

@ -0,0 +1,4 @@
/**
* Boolean determining if environment is development.
*/
export const isDevelopmentMode = process.env.NODE_ENV === 'development';