defined( 'WPINC' ) || exit();
* Handles QUIC.cloud communication, node detection, activation, and related utilities.
class Cloud extends Base {
private $_cloud_server = 'https://api.quic.cloud';
private $_cloud_ips = 'https://quic.cloud/ips';
private $_cloud_server_dash = 'https://my.quic.cloud';
* Cloud WP API server URL.
protected $_cloud_server_wp = 'https://wpapi.quic.cloud';
const SVC_D_ACTIVATE = 'd/activate';
const SVC_U_ACTIVATE = 'u/wp3/activate';
const SVC_D_ENABLE_CDN = 'd/enable_cdn';
const SVC_D_LINK = 'd/link';
const SVC_D_API = 'd/api';
const SVC_D_DASH = 'd/dash';
const SVC_D_V3UPGRADE = 'd/v3upgrade';
const SVC_U_LINK = 'u/wp3/link';
const SVC_U_ENABLE_CDN = 'u/wp3/enablecdn';
const SVC_D_STATUS_CDN_CLI = 'd/status/cdn_cli';
const SVC_D_NODES = 'd/nodes';
const SVC_D_SYNC_CONF = 'd/sync_conf';
const SVC_D_USAGE = 'd/usage';
const SVC_D_SETUP_TOKEN = 'd/get_token';
const SVC_D_DEL_CDN_DNS = 'd/del_cdn_dns';
const SVC_PAGE_OPTM = 'page_optm';
const SVC_QUEUE = 'queue';
const SVC_IMG_OPTM = 'img_optm';
const SVC_HEALTH = 'health';
const IMG_OPTM_DEFAULT_GROUP = 200;
const IMGOPTM_TAKEN = 'img_optm-taken';
const TTL_NODE = 3; // Days before node expired
const EXPIRATION_REQ = 300; // Seconds of min interval between two unfinished requests
const TTL_IPS = 3; // Days for node ip list cache
const API_REPORT = 'wp/report';
const API_VER = 'ver_check';
const API_BETA_TEST = 'beta_test';
const API_REST_ECHO = 'tool/wp_rest_echo';
const API_SERVER_KEY_SIGN = 'key_sign';
* Center services hosted at the central API server.
private static $center_svc_set = [
self::SVC_D_STATUS_CDN_CLI,
* Services hosted on the WP API server.
private static $wp_svc_set = [ self::API_NEWS, self::API_VER, self::API_BETA_TEST, self::API_REST_ECHO ];
* Public services that do not require an API key.
private static $_pub_svc_set = [ self::API_NEWS, self::API_REPORT, self::API_VER, self::API_BETA_TEST, self::API_REST_ECHO, self::SVC_D_V3UPGRADE, self::SVC_D_DASH ];
* Services that should go through the queue.
private static $_queue_svc_set = [ self::SVC_CCSS, self::SVC_UCSS, self::SVC_VPI ];
* Services that need load check.
public static $services_load_check = [
* All supported services.
public static $services = [
const TYPE_CLEAR_PROMO = 'clear_promo';
const TYPE_REDETECT_CLOUD = 'redetect_cloud';
const TYPE_CLEAR_CLOUD = 'clear_cloud';
const TYPE_ACTIVATE = 'activate';
const TYPE_LINK = 'link';
const TYPE_ENABLE_CDN = 'enablecdn';
const TYPE_SYNC_USAGE = 'sync_usage';
const TYPE_RESET = 'reset';
const TYPE_SYNC_STATUS = 'sync_status';
* Summary data for cloud interactions.
* @var array<string,mixed>
public function __construct() {
$allowed_hosts = [ 'wpapi.quic.cloud' ];
if ( defined( 'LITESPEED_DEV' ) && constant( 'LITESPEED_DEV' ) ) {
$allowed_hosts[] = 'my.preview.quic.cloud';
$allowed_hosts[] = 'api.preview.quic.cloud';
$this->_cloud_server = 'https://api.preview.quic.cloud';
$this->_cloud_ips = 'https://api.preview.quic.cloud/ips';
$this->_cloud_server_dash = 'https://my.preview.quic.cloud';
$this->_cloud_server_wp = 'https://wpapi.quic.cloud';
$allowed_hosts[] = 'my.quic.cloud';
$allowed_hosts[] = 'api.quic.cloud';
add_filter( 'allowed_redirect_hosts', function( $hosts ) use ( $allowed_hosts ) {
if ( ! is_array ( $hosts ) ) {
return array_merge( $hosts, $allowed_hosts );
$this->_summary = self::get_summary();
* Init QC setup preparation
public function init_qc_prepare() {
if ( empty( $this->_summary['sk_b64'] ) ) {
$keypair = sodium_crypto_sign_keypair();
$pk = base64_encode( sodium_crypto_sign_publickey( $keypair ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$sk = base64_encode( sodium_crypto_sign_secretkey( $keypair ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$this->_summary['pk_b64'] = $pk;
$this->_summary['sk_b64'] = $sk;
// ATM `qc_activated` = null
public function init_qc() {
$this->init_qc_prepare();
$ref = $this->_get_ref_url();
// WPAPI REST echo dryrun
$echobox = self::post( self::API_REST_ECHO, false, 60 );
if ( false === $echobox ) {
self::debugErr( 'REST Echo Failed!' );
$msg = __( "QUIC.cloud's access to your WP REST API seems to be blocked.", 'litespeed-cache' );
Admin_Display::error( $msg );
wp_safe_redirect( $ref );
self::debug( 'echo succeeded' );
// Load separate thread echoed data from storage
if ( empty( $echobox['wpapi_ts'] ) || empty( $echobox['wpapi_signature_b64'] ) ) {
Admin_Display::error( __( 'Failed to get echo data from WPAPI', 'litespeed-cache' ) );
wp_safe_redirect( $ref );
'wp_pk_b64' => $this->_summary['pk_b64'],
'wpapi_ts' => $echobox['wpapi_ts'],
'wpapi_signature_b64' => $echobox['wpapi_signature_b64'],
$server_ip = $this->conf( self::O_SERVER_IP );
$data['server_ip'] = $server_ip;
'site_url' => site_url(),
wp_safe_redirect( $this->_cloud_server_dash . '/' . self::SVC_U_ACTIVATE . '?data=' . rawurlencode( Utility::arr2str( $param ) ) );
* @param string|false $ref Ref slug.
private function _get_ref_url( $ref = false ) {
$link = 'admin.php?page=litespeed';
$link = 'admin.php?page=litespeed-cdn';
if ( 'online' === $ref ) {
$link = 'admin.php?page=litespeed-general';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$ref_get = ! empty( $_GET['ref'] ) ? sanitize_text_field( wp_unslash( $_GET['ref'] ) ) : '';
if ( $ref_get && 'cdn' === $ref_get ) {
$link = 'admin.php?page=litespeed-cdn';
if ( $ref_get && 'online' === $ref_get ) {
$link = 'admin.php?page=litespeed-general';
return get_admin_url( null, $link );
public function init_qc_cli() {
$this->init_qc_prepare();
$server_ip = $this->conf( self::O_SERVER_IP );
self::debugErr( 'Server IP needs to be set first!' );
__( 'You need to set the %1$s first. Please use the command %2$s to set.', 'litespeed-cache' ),
'`' . __( 'Server IP', 'litespeed-cache' ) . '`',
'`wp litespeed-option set server_ip __your_ip_value__`'
Admin_Display::error( $msg );
// WPAPI REST echo dryrun
$echobox = self::post( self::API_REST_ECHO, false, 60 );
if ( false === $echobox ) {
self::debugErr( 'REST Echo Failed!' );
$msg = __( "QUIC.cloud's access to your WP REST API seems to be blocked.", 'litespeed-cache' );
Admin_Display::error( $msg );
self::debug( 'echo succeeded' );
// Load separate thread echoed data from storage
if ( empty( $echobox['wpapi_ts'] ) || empty( $echobox['wpapi_signature_b64'] ) ) {
self::debug( 'Resp: ', $echobox );
Admin_Display::error( __( 'Failed to get echo data from WPAPI', 'litespeed-cache' ) );
'wp_pk_b64' => $this->_summary['pk_b64'],
'wpapi_ts' => $echobox['wpapi_ts'],
'wpapi_signature_b64' => $echobox['wpapi_signature_b64'],
'server_ip' => $server_ip,
$res = $this->post( self::SVC_D_ACTIVATE, $data );
* Init QC CDN setup (CLI)
* @param string $method Method.
* @param string|bool $cert Cert path.
* @param string|bool $key Key path.
* @param string|bool $cf_token Cloudflare token.
public function init_qc_cdn_cli( $method, $cert = false, $key = false, $cf_token = false ) {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );
$server_ip = $this->conf( self::O_SERVER_IP );
self::debugErr( 'Server IP needs to be set first!' );
__( 'You need to set the %1$s first. Please use the command %2$s to set.', 'litespeed-cache' ),
'`' . __( 'Server IP', 'litespeed-cache' ) . '`',
'`wp litespeed-option set server_ip __your_ip_value__`'
Admin_Display::error( $msg );
if ( ! file_exists( $cert ) || ! file_exists( $key ) ) {
Admin_Display::error( __( 'Cert or key file does not exist.', 'litespeed-cache' ) );
'server_ip' => $server_ip,
$data['cert'] = File::read( $cert );
$data['key'] = File::read( $key );
$data['cf_token'] = $cf_token;
$res = $this->post( self::SVC_D_ENABLE_CDN, $data );
public function link_qc() {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );
$data['wp_signature_b64'] = $this->_sign_b64( $data['wp_ts'] );
'site_url' => site_url(),
'ref' => $this->_get_ref_url(),
wp_safe_redirect( $this->_cloud_server_dash . '/' . self::SVC_U_LINK . '?data=' . rawurlencode( Utility::arr2str( $param ) ) );
* Show QC Account CDN status
public function cdn_status_cli() {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );
$res = $this->post( self::SVC_D_STATUS_CDN_CLI, $data );
* Link to QC Account for CLI
* @param string $email Account email.
* @param string $key API key.
public function link_qc_cli( $email, $key ) {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );
'qc_acct_email' => $email,
$res = $this->post( self::SVC_D_LINK, $data );
* API link parsed call to QC
* @param string $action2 Action slug.
public function api_link_call( $action2 ) {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );
$res = $this->post( self::SVC_D_API, $data );
self::debug( 'API link call result: ', $res );
public function enable_cdn() {
if ( ! $this->activated() ) {
Admin_Display::error( __( 'You need to activate QC first.', 'litespeed-cache' ) );