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();