You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
12 KiB
PHTML
366 lines
12 KiB
PHTML
8 months ago
|
<?php
|
||
|
|
||
|
if ( ! defined( 'ET_CLOUD_SERVER_URL' ) ) {
|
||
|
define( 'ET_CLOUD_SERVER_URL', 'https://cloud.elegantthemes.com' );
|
||
|
}
|
||
|
|
||
|
class ET_Cloud_App {
|
||
|
/**
|
||
|
* @var ET_Cloud_App
|
||
|
*/
|
||
|
private static $_instance;
|
||
|
|
||
|
/**
|
||
|
* Get the class instance.
|
||
|
*
|
||
|
* @since 3.0.99
|
||
|
*
|
||
|
* @return ET_Builder_Library
|
||
|
*/
|
||
|
public static function instance() {
|
||
|
if ( ! self::$_instance ) {
|
||
|
self::$_instance = new self;
|
||
|
}
|
||
|
|
||
|
add_action( 'wp_ajax_et_cloud_update_tokens', array( 'ET_Cloud_App', 'ajaxRefreshTokens' ) );
|
||
|
add_action( 'wp_ajax_et_cloud_remove_tokens', array( 'ET_Cloud_App', 'removeTokens' ) );
|
||
|
|
||
|
add_filter( 'et_builder_load_requests', array( 'ET_Cloud_App', 'updateAjaxCallsList' ) );
|
||
|
|
||
|
return self::$_instance;
|
||
|
}
|
||
|
|
||
|
public static function updateAjaxCallsList() {
|
||
|
return array( 'action' => array( 'et_cloud_update_tokens' ) );
|
||
|
}
|
||
|
|
||
|
public static function removeTokens() {
|
||
|
$nonce = $_POST['et_cloud_token_nonce'];
|
||
|
|
||
|
if ( ! wp_verify_nonce( $nonce, 'et_cloud_remove_token' ) ) {
|
||
|
die();
|
||
|
}
|
||
|
|
||
|
$user_id = (string) get_current_user_id();
|
||
|
$saved_tokens = get_option( 'et_cloud_refresh_token', array() );
|
||
|
|
||
|
$saved_tokens[ $user_id ] = array();
|
||
|
|
||
|
// Save empty refresh token for current user.
|
||
|
update_option( 'et_cloud_refresh_token', $saved_tokens );
|
||
|
|
||
|
wp_send_json_success();
|
||
|
}
|
||
|
|
||
|
public static function ajaxRefreshTokens() {
|
||
|
$nonce = $_POST['et_cloud_token_nonce'];
|
||
|
|
||
|
if ( ! wp_verify_nonce( $nonce, 'et_cloud_refresh_token' ) ) {
|
||
|
die();
|
||
|
}
|
||
|
|
||
|
return ET_Cloud_App::refreshTokens();
|
||
|
}
|
||
|
|
||
|
public static function refreshTokens() {
|
||
|
// Clear options cache to make sure we're using the latest version of the token.
|
||
|
wp_cache_delete( 'et_cloud_refresh_token', 'options' );
|
||
|
|
||
|
$user_id = (string) get_current_user_id();
|
||
|
$saved_tokens = get_option( 'et_cloud_refresh_token', array() );
|
||
|
$access_token = sanitize_text_field( $_POST['et_cloud_access_token'] );
|
||
|
$save_session = wp_validate_boolean( sanitize_text_field( $_POST['et_cloud_save_session'] ) );
|
||
|
$token_part = sanitize_text_field( $_POST['et_cloud_refresh_token_part'] );
|
||
|
$user_token_data = isset( $saved_tokens[ $user_id ] ) ? $saved_tokens[ $user_id ] : array();
|
||
|
$is_refresh = ! $access_token || '' === $access_token;
|
||
|
$url = ET_CLOUD_SERVER_URL . '/wp/wp-json/cloud/v1/activate';
|
||
|
|
||
|
$refresh_token = '';
|
||
|
|
||
|
if ( $is_refresh && is_array( $user_token_data ) && !empty( $user_token_data ) ) {
|
||
|
$refresh_token = $user_token_data['is_full_token'] ? $user_token_data['refresh_token'] : $user_token_data['refresh_token'] . $token_part;
|
||
|
|
||
|
$save_session = $is_refresh ? $user_token_data['is_full_token'] : $save_session;
|
||
|
}
|
||
|
|
||
|
if ( $is_refresh ) {
|
||
|
if ( ! $save_session && ( ! $token_part || '' === $token_part ) ) {
|
||
|
wp_send_json_error( array(
|
||
|
'error' => '401',
|
||
|
'errorType' => 'silent',
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$is_updating_token = 'updating' === get_transient( 'et_cloud_access_token_update_status' );
|
||
|
|
||
|
// Previous request is not finished yet. Try again after 2 seconds.
|
||
|
// Otherwise this request will fail with 401 error.
|
||
|
if ( $is_updating_token ) {
|
||
|
sleep(2);
|
||
|
ET_Cloud_App::refreshTokens();
|
||
|
}
|
||
|
|
||
|
// Set updating token flag with 5 seconds expiration.
|
||
|
set_transient( 'et_cloud_access_token_update_status', 'updating', 5 );
|
||
|
}
|
||
|
|
||
|
if ( ( ! $is_refresh && '' === $access_token ) || ( $is_refresh && '' === $refresh_token ) ) {
|
||
|
wp_send_json_error( array(
|
||
|
'error' => '401',
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( $is_refresh ) {
|
||
|
$token_array = explode('.', $refresh_token);
|
||
|
// Token is a json string of base64 encoded array. Decode it to access the data in token.
|
||
|
$refresh_token_data = json_decode(base64_decode($token_array[1]));
|
||
|
|
||
|
if ( !empty( $refresh_token_data ) && is_object( $refresh_token_data ) && isset( $refresh_token_data->aud ) ) {
|
||
|
$user_cloud_endpoint = $refresh_token_data->aud[1];
|
||
|
} else {
|
||
|
wp_send_json_error( array(
|
||
|
'error' => '401',
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$url = sprintf('%1$s/wp-json/auth/v1/token', $user_cloud_endpoint);
|
||
|
}
|
||
|
|
||
|
if ( ! $is_refresh ) {
|
||
|
update_option( 'et_server_domain_token', $access_token );
|
||
|
}
|
||
|
|
||
|
$request_body = array();
|
||
|
|
||
|
$auth_token = $is_refresh ? $refresh_token : $access_token;
|
||
|
|
||
|
$response = wp_remote_post( $url, array(
|
||
|
'headers' => array(
|
||
|
'Authorization' => 'Bearer ' . $auth_token,
|
||
|
'X-ET-ORIGIN' => site_url(),
|
||
|
),
|
||
|
'body' => $request_body,
|
||
|
) );
|
||
|
|
||
|
if ( is_wp_error( $response ) ) {
|
||
|
// Delete updating token flag.
|
||
|
delete_transient( 'et_cloud_access_token_update_status' );
|
||
|
|
||
|
wp_send_json_error( array(
|
||
|
'error' => 'Cloud Request Failed. Please Try Again Later',
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$response_code = wp_remote_retrieve_response_code( $response );
|
||
|
$response_body = wp_remote_retrieve_body( $response );
|
||
|
$decoded_body = json_decode( $response_body, TRUE );
|
||
|
|
||
|
// Valid response should contain 2 tokens.
|
||
|
if ( !isset( $decoded_body['refresh_token'] ) || !isset( $decoded_body['access_token'] ) || 200 !== $response_code ) {
|
||
|
// Authorization error. Need to reset all tokens and ask user to login again.
|
||
|
if ( 401 === $response_code ) {
|
||
|
$saved_tokens[ $user_id ] = array();
|
||
|
|
||
|
// Save empty refresh token for current user.
|
||
|
update_option( 'et_cloud_refresh_token', $saved_tokens, false );
|
||
|
|
||
|
// Delete updating token flag.
|
||
|
delete_transient( 'et_cloud_access_token_update_status' );
|
||
|
|
||
|
wp_send_json_error( array(
|
||
|
'error' => '401',
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
wp_send_json_error( array(
|
||
|
'error' => wp_remote_retrieve_response_message( $response ),
|
||
|
) );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$refresh_token = $decoded_body['refresh_token'];
|
||
|
$access_token = $decoded_body['access_token'];
|
||
|
$token_to_save = $refresh_token;
|
||
|
$token_part = '';
|
||
|
|
||
|
// We shouldn't save the full token, so user cannot use this token in other browser.
|
||
|
if ( ! $save_session ) {
|
||
|
$token_length = (int) strlen( $refresh_token );
|
||
|
$token_parts = str_split( $refresh_token, ceil( $token_length / 2 ) );
|
||
|
$token_to_save = $token_parts[0];
|
||
|
$token_part = $token_parts[1];
|
||
|
}
|
||
|
|
||
|
$saved_tokens[ $user_id ] = array(
|
||
|
'refresh_token' => sanitize_text_field( $token_to_save ),
|
||
|
'is_full_token' => $save_session,
|
||
|
);
|
||
|
|
||
|
// Save refresh token for current user.
|
||
|
update_option( 'et_cloud_refresh_token', $saved_tokens, false );
|
||
|
|
||
|
// Delete updating token flag.
|
||
|
delete_transient( 'et_cloud_access_token_update_status' );
|
||
|
|
||
|
// Save Access Token for 30 seconds so it can be quickly retrieved by the VB.
|
||
|
set_transient( 'et_cloud_access_token', $access_token, 30);
|
||
|
|
||
|
wp_send_json_success( array(
|
||
|
'accessToken' => $decoded_body['access_token'],
|
||
|
'refreshTokenPart' => $token_part,
|
||
|
'domainToken' => get_option( 'et_server_domain_token', '' ),
|
||
|
'sharedFolders' => self::normalize_shared_cloud_array( $decoded_body['clouds'] ),
|
||
|
) );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Normalize shared cloud array from the server response.
|
||
|
*
|
||
|
* @param array $shared_cloud_array Raw shared clouds array.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function normalize_shared_cloud_array( $shared_cloud_array ) {
|
||
|
if ( empty( $shared_cloud_array ) ) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
$normalized_array = array();
|
||
|
|
||
|
foreach ( $shared_cloud_array as $cloud_id => $shared_cloud ) {
|
||
|
$use_permission = isset( $shared_cloud['permissions']['use_items'] ) ? $shared_cloud['permissions']['use_items'] : false;
|
||
|
$add_permission = isset( $shared_cloud['permissions']['add_items'] ) ? $shared_cloud['permissions']['add_items'] : false;
|
||
|
$edit_permission = isset( $shared_cloud['permissions']['edit_items'] ) ? $shared_cloud['permissions']['edit_items'] : false;
|
||
|
$delete_permission = isset( $shared_cloud['permissions']['delete_items'] ) ? $shared_cloud['permissions']['delete_items'] : false;
|
||
|
|
||
|
// No permission to use this cloud.
|
||
|
if ( ! $use_permission && ! $add_permission && ! $edit_permission && ! $delete_permission ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$normalized_array[] = array(
|
||
|
'id' => $cloud_id,
|
||
|
'name' => $shared_cloud['owner'],
|
||
|
'count' => $shared_cloud['item_counts'],
|
||
|
'endpoint' => $shared_cloud['endpoint'],
|
||
|
'permissions' => array(
|
||
|
'use' => $shared_cloud['permissions']['use_items'],
|
||
|
'add' => $shared_cloud['permissions']['add_items'],
|
||
|
'edit' => $shared_cloud['permissions']['edit_items'],
|
||
|
'delete' => $shared_cloud['permissions']['delete_items'],
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return $normalized_array;
|
||
|
}
|
||
|
|
||
|
public static function hasRefreshToken() {
|
||
|
$user_id = (string) get_current_user_id();
|
||
|
$saved_tokens = get_option( 'et_cloud_refresh_token', array() );
|
||
|
$refresh_token = isset( $saved_tokens[ $user_id ] ) ? $saved_tokens[ $user_id ] : array();
|
||
|
|
||
|
return $refresh_token && ! empty( $refresh_token );
|
||
|
}
|
||
|
|
||
|
public static function get_cloud_helpers() {
|
||
|
if ( !defined( 'ET_CLOUD_PLUGIN_DIR' ) ) {
|
||
|
define( 'ET_CLOUD_PLUGIN_DIR', get_template_directory() . '/cloud' );
|
||
|
}
|
||
|
|
||
|
$home_url = wp_parse_url( get_site_url() );
|
||
|
$etAccount = et_core_get_et_account();
|
||
|
|
||
|
return [
|
||
|
'i18n' => require ET_CLOUD_PLUGIN_DIR . '/i18n/library.php',
|
||
|
'nonces' => [
|
||
|
'et_cloud_download_item' => wp_create_nonce( 'et_cloud_download_item' ),
|
||
|
'et_cloud_refresh_token' => wp_create_nonce( 'et_cloud_refresh_token' ),
|
||
|
'et_cloud_remove_token' => wp_create_nonce( 'et_cloud_remove_token' ),
|
||
|
'et_builder_split_library_item' => wp_create_nonce( 'et_builder_split_library_item' ),
|
||
|
'et_builder_ajax_save_domain_token' => wp_create_nonce( 'et_builder_ajax_save_domain_token' ),
|
||
|
'et_builder_marketplace_api_get_layouts' => wp_create_nonce( 'et_builder_marketplace_api_get_layouts' ),
|
||
|
'et_builder_marketplace_api_get_layout_categories' => wp_create_nonce( 'et_builder_marketplace_api_get_layout_categories' ),
|
||
|
],
|
||
|
'ajaxurl' => is_ssl() ? admin_url( 'admin-ajax.php' ) : admin_url( 'admin-ajax.php', 'http' ),
|
||
|
'home_url' => isset( $home_url['path'] ) ? untrailingslashit( $home_url['path'] ) : '/',
|
||
|
'website_url' => $home_url['host'],
|
||
|
'predefined_items_url' => ET_CLOUD_SERVER_URL . '/wp/wp-json/cloud/v1',
|
||
|
'etAccount' => [
|
||
|
'username' => $etAccount['et_username'],
|
||
|
'apiKey' => $etAccount['et_api_key'],
|
||
|
],
|
||
|
'domainToken' => get_option( 'et_server_domain_token', '' ),
|
||
|
'initialCloudStatus' => self::hasRefreshToken() ? 'on' : 'off',
|
||
|
'localCategoriesEdit' => current_user_can( 'manage_categories' ) ? 'allowed' : 'notAllowed',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load the Cloud App scripts.
|
||
|
*
|
||
|
* @since ??
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public static function load_js( $enqueue_prod_scripts = true, $skip_react_loading = false ) {
|
||
|
if ( !defined( 'ET_CLOUD_PLUGIN_URI' ) ) {
|
||
|
define( 'ET_CLOUD_PLUGIN_URI', get_template_directory_uri() . '/cloud' );
|
||
|
}
|
||
|
|
||
|
if ( !defined( 'ET_CLOUD_PLUGIN_DIR' ) ) {
|
||
|
define( 'ET_CLOUD_PLUGIN_DIR', get_template_directory() . '/cloud' );
|
||
|
}
|
||
|
|
||
|
$CORE_VERSION = defined( 'ET_CORE_VERSION' ) ? ET_CORE_VERSION : '';
|
||
|
$ET_DEBUG = defined( 'ET_DEBUG' ) && ET_DEBUG;
|
||
|
$DEBUG = $ET_DEBUG;
|
||
|
|
||
|
$home_url = wp_parse_url( get_site_url() );
|
||
|
$build_dir_uri = ET_CLOUD_PLUGIN_URI . '/build';
|
||
|
$common_scripts = ET_COMMON_URL . '/scripts';
|
||
|
$cache_buster = $DEBUG ? mt_rand() / mt_getrandmax() : $CORE_VERSION;
|
||
|
$asset_path = ET_CLOUD_PLUGIN_DIR . '/build/et-cloud-app.bundle.js';
|
||
|
|
||
|
if ( file_exists( $asset_path ) ) {
|
||
|
wp_enqueue_style( 'et-cloud-styles', "{$build_dir_uri}/et-cloud-app.bundle.modals.css", [], (string) $cache_buster );
|
||
|
}
|
||
|
|
||
|
wp_enqueue_script( 'es6-promise', "{$common_scripts}/es6-promise.auto.min.js", [], '4.2.2', true );
|
||
|
|
||
|
$BUNDLE_DEPS = [
|
||
|
'jquery',
|
||
|
'react',
|
||
|
'react-dom',
|
||
|
'es6-promise',
|
||
|
];
|
||
|
|
||
|
if ( $DEBUG || $enqueue_prod_scripts || file_exists( $asset_path ) ) {
|
||
|
$BUNDLE_URI = ! file_exists( $asset_path ) ? "{$home_url['scheme']}://{$home_url['host']}:31495/et-cloud-app.bundle.js" : "{$build_dir_uri}/et-cloud-app.bundle.js";
|
||
|
|
||
|
// Skip the React loading if we already have React ( Gutenberg editor for example ) to avoid conflicts.
|
||
|
if ( ! $skip_react_loading ) {
|
||
|
if ( function_exists( 'et_fb_enqueue_react' ) ) {
|
||
|
et_fb_enqueue_react();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wp_enqueue_script( 'et-cloud-app', $BUNDLE_URI, $BUNDLE_DEPS, (string) $cache_buster, true );
|
||
|
wp_localize_script( 'et-cloud-app', 'et_cloud_data', ET_Cloud_App::get_cloud_helpers());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ET_Cloud_App::instance();
|