HEX
Server: LiteSpeed
System: Linux cde2.duelhost.dk 4.18.0-553.34.1.lve.el8.x86_64 #1 SMP Thu Jan 9 16:30:32 UTC 2025 x86_64
User: dtptviut (1121)
PHP: 8.0.30
Disabled: exec,system,passthru,shell_exec,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: /home/dtptviut/public_html/wp-content/plugins/nitropack/classes/WordPress/Webhooks.php
<?php

namespace NitroPack\WordPress;

/**
 * Handle NitroPack webhooks
 */
class Webhooks {
	/**
	 * @var string The name of the option used to store the webhook token.
	 */
	public $option_name;

	public function __construct() {
		$this->option_name = 'nitropack-webhookToken';
		add_action( 'wp_ajax_nitropack_reconfigure_webhooks', [ $this, 'nitropack_reconfigure_webhooks' ] );
	}

	/**
	 * Generate the webhook token with a CSPRNG.
	 */
	public function generate_webhook_token() {
		if ( defined( "NITROPACK_WEBHOOK_TOKEN" ) && ! empty( NITROPACK_WEBHOOK_TOKEN ) ) {
			return NITROPACK_WEBHOOK_TOKEN;
		}

		if ( function_exists( "wp_generate_password" ) ) {
			$generatedToken = wp_generate_password( 32, false );
			if ( ! empty( $generatedToken ) && $this->validate_webhook_token( $generatedToken ) ) {
				return $generatedToken;
			}
		}

		if ( function_exists( "random_bytes" ) ) {
			return bin2hex( random_bytes( 16 ) );
		}

		return "";
	}

	/**
	 * Handles the NitroPack webhook request.
	 * 3 types of webhooks are handled:
	 * 1. config - Fetches the latest configuration from NitroPack and resets the SDK instances.
	 * 2. cache_ready - Downloads the new cache file for the specified URLs and purges the proxy cache.
	 * 3. cache_clear - Clears the cache for the specified URLs or the entire cache, depending on the request parameters.
	 *
	 * @return void
	 */
	public function handle_webhook() {
		if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
			do_action( 'nitropack_debug_webhook', $_REQUEST );
		}
		if ( ! defined( "NITROPACK_WEBHOOK_HANDLED" ) ) {
			define( "NITROPACK_WEBHOOK_HANDLED", 1 );
		} else {
			return;
		}

		$siteConfig = nitropack_get_site_config();
		$incomingToken = isset( $_GET["token"] ) ? (string) $_GET["token"] : "";
		$storedToken = ( $siteConfig && ! empty( $siteConfig["webhookToken"] ) ) ? (string) $siteConfig["webhookToken"] : "";
		$isValidWebhookToken = $storedToken !== "" && ( function_exists( "hash_equals" ) ? hash_equals( $storedToken, $incomingToken ) : $storedToken === $incomingToken );

		if ( $siteConfig && $isValidWebhookToken ) {
			switch ( $_GET["nitroWebhook"] ) {
				case "config":
					nitropack_fetch_config();
					get_nitropack()->resetSdkInstances(); // This is needed in order to obtain a new SDK instance with the fresh config
					nitropack_set_htaccess_rules( true );
					if ( null !== $nitro = get_nitropack_sdk() ) {
						$nitro->purgeProxyCache();
					}
					do_action( 'nitropack_integration_purge_all' );
					break;
				case "cache_ready":
					if ( isset( $_POST['url'] ) ) {
						$urls = array( $_POST['url'] );
					} elseif ( isset( $_POST['urls'] ) ) {
						$urls = $_POST['urls'];
					} else {
						$urls = array();
					}
					if ( ! empty( $urls ) ) {
						$readyUrls = [];
						foreach ( $urls as $url ) {
							$readyUrl = nitropack_sanitize_url_input( $url );
							if ( $readyUrl ) {
								$readyUrls[] = $readyUrl;
							}
						}

						if ( $readyUrls && null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"], $readyUrls[0] ) ) {
							$hasCache = $nitro->hasRemoteCacheMulti( $readyUrls, "default", false ); // Download the new cache file
							foreach ( $readyUrls as $readyUrl ) {
								$nitro->purgeProxyCache( $readyUrl );
								do_action( 'nitropack_integration_purge_url', $readyUrl );
							}
						}
					}
					break;
				case "cache_clear":
					if ( isset( $_POST['url'] ) ) {
						$urls = array( $_POST['url'] );
					} elseif ( isset( $_POST['urls'] ) ) {
						$urls = $_POST['urls'];
					}

					$proxyPurgeOnly = ! empty( $_POST["proxyPurgeOnly"] );
					$doAction = ! empty( $_POST['useInvalidate'] )
						? static function ( $url = null ) {
							nitropack_sdk_invalidate_local( $url );
						}
						: static function ( $url = null ) {
							nitropack_sdk_purge_local( $url );
						};

					if ( ! empty( $_POST["url"] ) ) {
						$urls = is_array( $_POST["url"] ) ? $_POST["url"] : array( $_POST["url"] );
						foreach ( $urls as $url ) {
							$sanitizedUrl = nitropack_sanitize_url_input( $url );
							if ( $proxyPurgeOnly ) {
								if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
									$nitro->purgeProxyCache( $sanitizedUrl );
								}
								do_action( 'nitropack_integration_purge_url', $sanitizedUrl );
							} else {
								$doAction( $sanitizedUrl );
							}
						}
					} else {
						if ( $proxyPurgeOnly ) {
							if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
								$nitro->purgeProxyCache();
							}
							do_action( 'nitropack_integration_purge_all' );
						} else {
							$doAction();
							nitropack_sdk_delete_backlog();
						}
					}
					break;
			}
		}
		\NitroPack\ModuleHandler::onCriticalInit( function () {
			nitropack_json_and_exit( array(
				"type" => "success",
			) );
		} );
	}

	/**
	 * AJAX handler to reconfigure the NitroPack webhooks by generating a new token and setting up the webhooks in the NitroPack SDK.
	 * Used on a notification called "Reconfigure Webhooks" and the user confirms the action.
	 * @return void
	 */
	public function nitropack_reconfigure_webhooks() {
		nitropack_verify_ajax_nonce( $_REQUEST );
		$siteConfig = nitropack_get_site_config();

		if ( $siteConfig && ! empty( $siteConfig["siteId"] ) ) {
			if ( null !== $nitro = get_nitropack_sdk() ) {
				$token = $this->generate_webhook_token();
				try {
					$this->nitropack_setup_webhooks( $nitro, $token );
					update_option( $this->option_name, $token );
					nitropack_json_and_exit( array( "status" => "success", 'message' => __( 'Connection reconfigured successfully', 'nitropack' ) ) );
				} catch (\NitroPack\SDK\WebhookException $e) {
					NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Webhook Error: ' . $e );
					nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Webhook Error: ', 'nitropack' ) . $e->getMessage() ) );
				}
			} else {
				NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Unable to get SDK instance' );
				nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Unable to get SDK instance', 'nitropack' ) ) );
			}
		} else {
			NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Incomplete site config. Please reinstall the plugin' );
			nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Incomplete site config. Please reinstall the plugin!', 'nitropack' ) ) );
		}
	}

	/**
	 * Set up all NitroPack webhooks by registering them in the NitroPack SDK.
	 * @param object $nitro
	 * @param string | null $token
	 * @throws \NitroPack\SDK\WebhookException
	 * @return void
	 */
	public function nitropack_setup_webhooks( $nitro, $token = null ) {
		if ( ! $nitro || ! $token ) {
			throw new \NitroPack\SDK\WebhookException( 'Webhook token cannot be empty.' );
		}

		$homeUrl = strtolower( get_home_url() );
		$configUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=config&token=$token" );
		$cacheClearUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_clear&token=$token" );
		$cacheReadyUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_ready&token=$token" );

		$nitro->getApi()->setWebhook( "config", $configUrl );
		$nitro->getApi()->setWebhook( "cache_clear", $cacheClearUrl );
		$nitro->getApi()->setWebhook( "cache_ready", $cacheReadyUrl );
	}

	/**
	 * Reset all NitroPack webhooks by unsetting them in the NitroPack SDK.
	 * @param object $nitroSDK
	 * @return void
	 */
	public function reset_webhooks( $nitroSDK ) {
		$nitroSDK->getApi()->unsetWebhook( "config" );
		$nitroSDK->getApi()->unsetWebhook( "cache_clear" );
		$nitroSDK->getApi()->unsetWebhook( "cache_ready" );

		delete_option( $this->option_name );
	}
	/**
	 * Check if the current request is a valid NitroPack webhook.
	 * @return bool
	 */
	public function is_valid_webhook() {
		return ! empty( $_GET["nitroWebhook"] ) && ! empty( $_GET["token"] ) && $this->validate_webhook_token( $_GET["token"] );
	}

	/**
	 * Validate a NitroPack webhook token.
	 * @param string $token
	 * @return bool
	 */
	public function validate_webhook_token( $token ) {
		return preg_match( "/^([a-zA-Z0-9]{32})$/", $token );
	}
	public function get_token() {
		return get_option( $this->option_name );
	}

}