HEX
Server: Apache
System: Linux efa57bbe-abb1-400d-2985-3b056fbc2701.secureserver.net 6.1.147-1.el9.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 24 12:33:32 EDT 2025 x86_64
User: root (0)
PHP: 8.0.30.4
Disabled: NONE
Upload Files
File: /var/www/wp-content/mu-plugins/gd-system-plugin/includes/class-api.php
<?php

namespace WPaaS;

use \WP_Error;

if ( ! defined( 'ABSPATH' ) ) {

	exit;

}

interface API_Interface {

	public function get_disallowed_plugins();

	public function is_valid_sso_hash( $hash );

	public function user_changed_domain( $domain = '' );

	public function get_woocommerce_products( $product_type );

	public function refresh_blog_title( $blogname = null );

	public function refresh_nextgen_compatibility( $is_nextgen_compat = false );

	public function toggle_rum( $enabled = true );

	public function flush_cdn();

	public function get_failed_smart_updates();

	public function smart_update_notice_dismiss( $dismiss_id );

	public function hmt_register( $key );

}

final class API implements API_Interface {

	/**
	 * Return an array of disallowed plugins.
	 *
	 * Note: The transient used here is persistent, meaning it
	 * will not be short-circuited by object cache and it will
	 * always be set to a non-false value regardless of the API
	 * response.
	 *
	 * @return array
	 */
	public function get_disallowed_plugins() {

		$transient = Plugin::get_persistent_site_transient( 'gd_system_disallowed_plugins' );

		if ( false !== $transient ) {

			return (array) $transient;

		}

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );

		$response = $this->call( 'disallowPlugins/' );

		$body               = json_decode( wp_remote_retrieve_body( $response ), true );
		$disallowed_plugins = ! empty( $body['disallowPlugins'] ) ? (array) $body['disallowPlugins'] : [];

		Plugin::set_persistent_site_transient( 'gd_system_disallowed_plugins', $disallowed_plugins, HOUR_IN_SECONDS );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );

		return $disallowed_plugins;

	}

	/**
	 * Validate an SSO hash.
	 *
	 * @param string $hash
	 *
	 * @return bool
	 */
	public function is_valid_sso_hash( $hash ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$method_args = [
			'token'    => $hash,
			'database' => DB_NAME
		];

		$response = $this->call(
			"sso/allowLogin/",
			$method_args,
			'POST'
		);

		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		return isset( $body['allow'] ) ? $body['allow'] : false;

	}

	/**
	 * Check if a user has changed their domain.
	 *
	 * It isn't reflected here yet because we're waiting on the
	 * DNS TTL to take effect.
	 *
	 * Note: The transient used here is persistent, meaning it
	 * will not be short-circuited by object cache and it will
	 * always be set to a non-false value regardless of the API
	 * response.
	 *
	 * @param string $cname (optional)
	 *
	 * @return bool
	 */
	public function user_changed_domain( $cname = '' ) {

		$transient = Plugin::get_persistent_site_transient( 'gd_system_domain_changed' );

		if ( false !== $transient ) {

			return (
				1 === (int) $transient
				||
				'Y' === $transient // Back compat
			);

		}

		$cname = ( $cname ) ? $cname : Plugin::domain();

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );

		$response = $this->call( 'domains/' . $cname );
		$body     = json_decode( wp_remote_retrieve_body( $response ), true );
		$changed  = ! empty( $body['domainChanged'] ) ? 1 : 0;
		$timeout  = 300;

		Plugin::set_persistent_site_transient( 'gd_system_domain_changed', $changed, absint( $timeout ) );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );

		return ( 1 === $changed );

	}

	/**
	 * Retreive WooCommerce product
	 *
	 * @param string $product_type The type of product to achieve.
	 *
	 * @return array $products The retreived products from the WooCommerce API.
	 */
	public function get_woocommerce_products( $product_type ) {

		$product_cache = get_transient( 'wpaas_woocommerce_' . $product_type );

		if ( ! WP_DEBUG && false !== $product_cache ) {

			return $product_cache;

		}

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		$request = $this->call( $this->wp_public_api_accountuid( "automattic/%s/woocommerce/info" ) );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		if ( 200 !== wp_remote_retrieve_response_code( $request ) || is_wp_error( $request ) ) {

			set_transient( 'wpaas_woocommerce_' . $product_type, [], 15 * MINUTE_IN_SECONDS );

			return [];

		}

		$products = json_decode( wp_remote_retrieve_body( $request ), true );

		if ( empty( $products ) || ! is_array( $products ) || ! isset( $products['products'] ) ) {

			set_transient( 'wpaas_woocommerce_' . $product_type, [], 15 * MINUTE_IN_SECONDS );

			return [];

		}

		$type = 'extensions' === $product_type ? 'plugin' : 'theme';

		// Return the proper product type only.
		$products = array_filter(
			$products['products'],
			function ( $extension ) use ( $type ) {
				return $type === $extension['type'];
			}
		);

		set_transient( 'wpaas_woocommerce_' . $product_type, $products, 8 * HOUR_IN_SECONDS );

		return $products;

	}

	/**
	 * Request that the API refresh its copy of the blog title.
	 *
	 * @param string $blogname (optional)
	 *
	 * @return void
	 */
	public function refresh_blog_title( $blogname = null ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$method_args = $blogname ? [ 'blogname' => htmlspecialchars_decode( $blogname, ENT_QUOTES ) ] : [];

		$this->call( $this->wp_public_api_accountuid( "v3-proxy/%s/refreshBlogTitle" ), $method_args, 'POST' );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

	}

	/**
	 * Request that the API refresh wether or not the site is nextgen compatible.
	 *
	 * @param boolean $is_nextgen_compat (optional)
	 *
	 * @return void
	 */
	public function refresh_nextgen_compatibility( $is_nextgen_compat = false ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$method_args = [ 'nextgenEnabled' => (bool) $is_nextgen_compat ];

		$this->call( $this->wp_public_api_accountuid( "v3-proxy/%s/nextgen" ), $method_args, 'POST' );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

	}

	/**
	 * Send RAD data to the API.
	 *
	 * @param string $name
	 * @param array $metadata (optional)
	 *
	 * @return void
	 */
	public function log_rad_event( $name, $metadata = [] ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$method_args = [
			'datetime' => current_time( 'mysql', 1 ),
			'metadata' => (array) $metadata,
			'name'     => $name,
		];


		$this->call( $this->wp_public_api_accountuid( "rad/%s/event" ), $method_args, 'POST' );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

	}

	/**
	 * Toggle RUM for this site.
	 *
	 * @param bool $enabled True or false
	 *
	 * @return void
	 */
	public function toggle_rum( $enabled = true ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$method_args = [
			'rumEnabled' => (bool) $enabled,
		];

		$this->call( $this->wp_public_api_accountuid( "v3-proxy/%s/rum" ), $method_args, 'POST' );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'non_blocking_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

	}

	/**
	 * Flush full page cdn
	 *
	 *
	 * @return string|null
	 */
	public function flush_cdn() {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		$accountUid = defined( 'GD_ACCOUNT_UID' ) ? GD_ACCOUNT_UID : '';
		try {
			$response       = $this->call( 'cdn/cache/' . $accountUid, [], 'DELETE' );
			$body           = json_decode( wp_remote_retrieve_body( $response ), true );
			$invalidationId = ! empty( $body['invalidationId'] ) ? $body['invalidationId'] : null;
		} catch ( WP_Error $e ) {
			return null;
		}

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		return $invalidationId;
	}

	/**
	 * Get CDN cache clear status
	 *
	 * @returns string|null
	 */
	public function flush_cache_cdn_status( $invalidation_id ) {
		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		try {
			$accountUid = defined( 'GD_ACCOUNT_UID' ) ? GD_ACCOUNT_UID : '';
			$response   = $this->call( 'cdn/' . $accountUid . '/cache/' . $invalidation_id );
			$body       = json_decode( wp_remote_retrieve_body( $response ), true );
		} catch ( WP_Error $e ) {
			return null;
		}

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		return $body;
	}


	/**
	 * Get feature flags
	 *
	 * @param string $api_url
	 *
	 * @returns array|null
	 */
	public function fetch_feature_flag( $api_url ) {
		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'timeout_3s_http_args' ] );

		/** Logg user action */
		$GLOBALS['wpaas_activity_logger']->log_sp_action( get_current_user_id(), 'Fetch feature flags from API' );

		try {
			$response = $this->call( $api_url );
			$body     = json_decode( wp_remote_retrieve_body( $response ), true );
		} catch ( WP_Error $e ) {
			return null;
		}

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'timeout_3s_http_args' ] );

		return $body;
	}

	/**
	 * Filter the API URL when using the V3 API.
	 *
	 * @param string $api_url
	 *
	 * @return string
	 */
	public function v3_api_url( $api_url ) {

		if ( ! defined( 'GD_ACCOUNT_UID' ) || ! GD_ACCOUNT_UID ) {

			return;

		}

		$env    = Plugin::get_env();
		$prefix = ( 'prod' === $env ) ? '' : "{$env}-";

		return sprintf(
			"https://mwp.api.phx3.{$prefix}godaddy.com/api/v1/mwp/sites/%s/",
			GD_ACCOUNT_UID
		);

	}

	/**
	 * Filter the API URL when using the WP Public API.
	 *
	 * @return string
	 */
	public function wp_public_api_url() {
		$env = Plugin::get_env();
		if ( in_array( $env, array( 'myh.test' ) ) ) {
			$env = 'test';
		}

		if ( in_array( $env, [ 'dev', 'test' ], true ) ) {
			return "https://wp-api.wpsecurity.{$env}-godaddy.com/api/v1/";
		}

		return "https://wp-api.wpsecurity.godaddy.com/api/v1/";
	}

	/**
	 * Filter the HTTP request args when using the V3 API.
	 *
	 * @param array $http_args
	 *
	 * @return array
	 */
	public function v3_api_http_args( $http_args ) {

		$body = apply_filters( 'wpaas_v3_api_body_signage', [] );

		$http_args['headers'] = array_merge( $http_args['headers'], Plugin::sign_http_request( wp_json_encode( $body ) ) );

		return $http_args;

	}


	/**
	 * Filter the HTTP request args to use a 30s timeout.
	 *
	 * @param array $http_args
	 *
	 * @return array
	 */
	public function timeout_30s_http_args( $http_args ) {

		$http_args['timeout'] = 30;

		return $http_args;

	}

	/**
	 * Filter the HTTP request args to use a 3s timeout.
	 *
	 * @param array $http_args
	 *
	 * @return array
	 */
	public function timeout_3s_http_args( $http_args ) {

		$http_args['timeout'] = 3;

		return $http_args;

	}

	/**
	 * Filter the HTTP request args to make calls non-blocking.
	 *
	 * @param array $http_args
	 *
	 * @return array
	 */
	public function non_blocking_http_args( $http_args ) {

		$http_args['blocking'] = false;
		$http_args['timeout']  = 5;

		return $http_args;

	}

	/**
	 * Make an API call.
	 *
	 * @param string $method
	 * @param array|string $method_args (optional)
	 * @param string $http_verb (optional)
	 *
	 * @return array|WP_Error
	 */
	private function call( $method, $method_args = [], $http_verb = 'GET' ) {

		$api_url = (string) apply_filters( 'wpaas_api_url', '' );
		if ( ! $api_url ) {
			/** Logg user action */
			$GLOBALS['wpaas_activity_logger']->log_sp_action( get_current_user_id(), sprintf( 'API call fail URL: %s', $api_url ) );

			return new WP_Error( 'wpaas_api_url_not_found' );

		}

		add_filter( 'wpaas_v3_api_body_signage', function () use ( $method_args ) {
			return $method_args;
		} );

		$http_args = (array) apply_filters(
			'wpaas_api_http_args',
			[
				'headers' => [
					'Content-Type' => 'application/json',
				],
			]
		);

		$url = trailingslashit( $api_url ) . $method;

		$retries     = 0;
		$max_retries = 1;

		add_filter( 'https_ssl_verify', '__return_false' );

		while ( $retries <= $max_retries ) {

			$retries ++;

			switch ( $http_verb ) {

				case 'GET':
					if ( ! empty( $method_args ) ) {

						$url .= '?' . build_query( $method_args );

					}

					$response = wp_remote_get( $url, $http_args );
					break;

				case 'POST':
					$http_args['body'] = (bool) apply_filters( 'wpaas_api_http_post_body_json', false ) ? json_encode( $method_args, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) : $method_args;

					$response = wp_remote_post( $url, $http_args );

					break;
				case "DELETE":
					$http_args['body'] = (bool) apply_filters( 'wpaas_api_http_post_body_json', false ) ? json_encode( $method_args, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) : $method_args;
					$response          = wp_remote_request( $url, array_merge( $http_args, [
						'method' => 'DELETE'
					] ) );
					break;

				default:
					return new WP_Error( 'wpaas_api_invalid_http_verb' );

			}

			$response_code = wp_remote_retrieve_response_code( $response );

			// Check if we aren't on the last iteration and we can try the request again
			if (
				$retries <= $max_retries
				&&
				$this->is_retryable( $response, $response_code )
			) {

				// Give some time for the API to recover
				sleep( (int) apply_filters( 'wpaas_api_retry_delay', 1 ) );

				continue;

			}

			break;

		}

		remove_filter( 'https_ssl_verify', '__return_false' );


		if ( 200 !== $response_code && 204 !== $response_code ) {
			/** Logg user action */
			$GLOBALS['wpaas_activity_logger']->log_sp_action( get_current_user_id(),
				sprintf( 'API call fail URL: %s status_code: %s', $url, $response_code )
			);

			return new WP_Error( 'wpaas_api_bad_status', $response_code );

		}

		/** Logg user action */
		$GLOBALS['wpaas_activity_logger']->log_sp_action( get_current_user_id(),
			sprintf( 'API call success URL: %s status_code: %s', $url, $response_code )
		);

		return $response;

	}

	/**
	 * Check if a response is an error and retryable.
	 *
	 * @param array|WP_Error $response
	 * @param int $response_code
	 *
	 * @return bool
	 */
	private function is_retryable( $response, $response_code ) {

		if ( 200 === $response_code ) {

			return false;

		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		if (
			isset( $body['status'], $body['type'], $body['code'] )
			&&
			503 === absint( $body['status'] )
			&&
			'error' === $body['type']
			&&
			'RetryRequest' === $body['code']
		) {

			return true;

		}

		return false;

	}

	public function get_failed_smart_updates() {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		$response = $this->call( 'smart-updates' );

		if ( is_wp_error( $response ) ) {
			return [];
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );

		return $body;
	}

	public function smart_update_notice_dismiss( $dismiss_id ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$response = $this->call( 'smart-updates/dismiss', [ 'dismissId' => $dismiss_id ], 'POST' );

		if ( is_wp_error( $response ) ) {
			return false;
		}

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		return true;
	}

	public function hmt_register( $key ) {

		add_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		add_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		add_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		$accountUid = defined( 'GD_ACCOUNT_UID' ) ? GD_ACCOUNT_UID : '';

		$data = [
			'mwp_potential_key' => $key
		];
		try {
			$response = $this->call( 'backup/' . $accountUid . '/register', $data, 'POST' );
			$body     = json_decode( wp_remote_retrieve_body( $response ), true );
			$success  = ! empty( $body['success'] ) ? $body['success'] : null;
		} catch ( WP_Error $e ) {
			return null;
		}

		remove_filter( 'wpaas_api_url', [ $this, 'wp_public_api_url' ] );
		remove_filter( 'wpaas_api_http_args', [ $this, 'v3_api_http_args' ] );
		remove_filter( 'wpaas_api_http_post_body_json', '__return_true' );

		return $success;
	}

	private function wp_public_api_accountuid( $path ) {

		$accountUid = defined( 'GD_ACCOUNT_UID' ) ? GD_ACCOUNT_UID : '';

		return sprintf(
			$path,
			$accountUid
		);

	}

}