<?php
/**
 * Virtuaria Auth SDK PHAR stub.
 *
 * Loads the Auth class from the PHAR archive.
 * Usage: require 'virtuaria-auth-sdk.phar';
 *
 * @package Virtuaria
 */

Phar::mapPhar( 'virtuaria-auth-sdk.phar' );
require 'phar://virtuaria-auth-sdk.phar/class-auth.php';
__HALT_COMPILER(); ?>
S             virtuaria-auth-sdk.phar       class-auth.php,&      ,&  ρ      <?php
/**
 * SDK to authenticate premium modules from virtuaria.com.br.
 *
 * @author Virtuaria
 * @package Virtuaria
 * @version 1.0.2
 */

namespace Virtuaria\Plugins;

use Exception;
use WC_Log_Levels;

defined( 'ABSPATH' ) || exit;

/**
 * Class to authenticate premium modules from virtuaria.com.br.
 */
class Auth {
	/**
	 * Endpoint to check if the user is premium.
	 */
	private const API_URL = 'https://premium.virtuaria.com.br/wp-json/v1/auth/premium/plugins';

	/**
	 * The single instance of this class.
	 *
	 * @var object
	 */
	private static $instance = null;

	/**
	 * The option name to store the authentication status.
	 *
	 * @var string
	 */
	private const AUTH_OPTION = '_virtuaria_premium_auth_status';

	/**
	 * Flag to indicate if the periodic premium check is RUNNING.
	 *
	 * @var bool
	 */
	private static $is_check_periodic = false;

	/**
	 * Return an instance of this class.
	 *
	 * @return object A single instance of this class.
	 */
	public static function get_instance() {
		// If the single instance hasn't been set, set it now.
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Constructor.
	 *
	 * Hooks into the action to check if the daily event is already scheduled, and if not, schedules it.
	 */
	private function __construct() {
		add_action( 'virtuaria_premium_auth_check', array( $this, 'periodic_premium_check' ) );
	}

	/**
	 * Checks if the premium version is active for the user based on certain criteria.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $domain The domain of the website.
	 * @param string $module The module name.
	 * @param string $version The version of the module.
	 *
	 * @return bool Returns true if the user is premium, false otherwise.
	 */
	public static function is_premium( $serial, $domain, $module, $version = '1.0.0' ) {
		$log = wc_get_logger();
		$tag = $module ? $module : 'Virtuaria Auth SDK';

		if ( ! self::is_valid_params( $serial, $domain, $module, $version ) ) {
			return false;
		}

		$is_premium = self::is_premium_module( $serial, $domain, $module );

		if ( $is_premium && ! self::$is_check_periodic ) {
			return true;
		}

		if ( self::is_serial_locked( $serial, $module ) ) {
			return false;
		}

		self::maybe_schedule_check( $serial, $domain, $module, $version );

		try {
			$is_premium = self::request_premium_auth(
				$serial,
				$domain,
				$module,
				$version,
				$is_premium
			);

			$log->add(
				$tag,
				'Virtuaria Auth SDK: ' . ( $is_premium ? 'Autenticado' : 'Não Autorizado' ),
				$is_premium ? WC_Log_Levels::INFO : WC_Log_Levels::ERROR
			);
			if ( $is_premium ) {
				self::set_authenticate_premium( $serial, $domain, $module, $version );
			} else {
				self::remove_premium_module( $module );
				self::apply_lock_request( $serial, $module );
			}
		} catch ( Exception $e ) {
			$log->add(
				$tag,
				'Virtuaria Auth SDK: ' . $e->getMessage(),
				WC_Log_Levels::ERROR
			);
		}

		return $is_premium;
	}


	/**
	 * Applies a lock on the premium request for the given module serial, so it won't be attempted again for a day.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $module The module name.
	 *
	 * @return void
	 */
	private static function apply_lock_request( $serial, $module ) {
		set_transient(
			'failed_premium_' . $module,
			$serial,
			DAY_IN_SECONDS
		);
	}

	/**
	 * Checks if the serial for a given module is locked.
	 *
	 * This function verifies if the premium request for a module has been locked
	 * by checking if a transient exists for the module's serial number.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $module The module name.
	 *
	 * @return bool True if the serial is locked, false otherwise.
	 */
	private static function is_serial_locked( $serial, $module ) {
		$failed = get_transient( 'failed_premium_' . $module );

		return $failed && $failed === $serial;
	}

	/**
	 * Release locked serial to allow new validation try.
	 *
	 * @param string $module current module.
	 * @return void
	 */
	public static function release_serial_locked( $module ) {
		delete_transient( 'failed_premium_' . $module );
	}

	/**
	 * Set the premium status for a module.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $domain The domain of the website.
	 * @param string $module The module name.
	 * @param string $version The version of the module.
	 *
	 * @return void
	 */
	private static function set_authenticate_premium( $serial, $domain, $module, $version ) {
		$premium = get_option( self::AUTH_OPTION, array() );

		$premium[ $module ] = array(
			'is_premium' => true,
			'serial'     => $serial,
			'domain'     => $domain,
			'version'    => $version,
			'auth_date'  => time(),
		);

		update_option(
			self::AUTH_OPTION,
			$premium
		);
	}

	/**
	 * Checks if a module is premium.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $domain The domain of the website.
	 * @param string $module The module name.
	 *
	 * @return bool True if the module is premium, false otherwise.
	 */
	private static function is_premium_module( $serial, $domain, $module ) {
		$premium = get_option( self::AUTH_OPTION, array() );

		return isset(
			$premium[ $module ]['is_premium'],
			$premium[ $module ]['serial'],
			$premium[ $module ]['domain'],
		)
		&& true === $premium[ $module ]['is_premium']
		&& $serial === $premium[ $module ]['serial']
		&& $domain === $premium[ $module ]['domain'];
	}

	/**
	 * Validate if the given params are valid.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $domain The domain of the website.
	 * @param string $module The module name.
	 * @param string $version The version of the module.
	 *
	 * @return bool True if all params are valid, false otherwise.
	 */
	private static function is_valid_params( $serial, $domain, $module, $version ) {
		return ! empty( $serial ) && ! empty( $domain ) && ! empty( $module ) && ! empty( $version );
	}

	/**
	 * Maybe schedule the daily check for premium auth.
	 *
	 * It checks if the daily event is already scheduled, and if not, schedules it.
	 */
	private static function maybe_schedule_check() {
		if ( ! wp_next_scheduled( 'virtuaria_premium_auth_check' ) ) {
			wp_schedule_event( time(), 'daily', 'virtuaria_premium_auth_check' );
		}
	}

	/**
	 * Unschedule the daily premium authentication check.
	 *
	 * This function clears the scheduled event for the daily check of premium module authentication,
	 * preventing it from running in the future.
	 */
	public static function unshedule_periodic_check() {
		wp_clear_scheduled_hook( 'virtuaria_premium_auth_check' );
	}

	/**
	 * Performs a periodic check for premium modules.
	 *
	 * This function iterates through the stored premium modules and verifies their premium status. If a module is
	 * marked as premium, it is temporarily removed and its status is re-checked through an authentication process.
	 */
	public function periodic_premium_check() {
		$premium_module = get_option( self::AUTH_OPTION, array() );

		if ( $premium_module ) {
			foreach ( $premium_module as $module => $data ) {
				if ( isset( $data['is_premium'], $data['serial'], $data['domain'], $data['version'] )
					&& true === $data['is_premium'] ) {
					self::$is_check_periodic = true;
					self::is_premium(
						$data['serial'],
						$data['domain'],
						$module,
						$data['version']
					);
					self::$is_check_periodic = false;
				}
			}
		}
	}

	/**
	 * Remove a module from the list of premium modules.
	 *
	 * @param string $module The module name to remove.
	 *
	 * @return void
	 */
	private static function remove_premium_module( $module ) {
		$premium = get_option( self::AUTH_OPTION, array() );
		unset( $premium[ $module ] );
		update_option( self::AUTH_OPTION, $premium );
	}

	/**
	 * Makes a request to the Virtuaria Auth API to verify the premium status of a module.
	 *
	 * @param string $serial The serial number of the module.
	 * @param string $domain The domain of the website.
	 * @param string $module The module name.
	 * @param string $version The version of the module.
	 * @param bool   $is_premium True if the module is premium, false if it is free.
	 *
	 * @return bool True if the module is premium, false if it is free.
	 *
	 * @throws Exception If the API request fails or returns an unexpected response code.
	 */
	private static function request_premium_auth( $serial, $domain, $module, $version, $is_premium ) {
		$response = wp_remote_get(
			self::API_URL . '?request_id=' . time(),
			array(
				'headers' => array(
					'domain'         => sanitize_text_field( $domain ),
					'serial'         => sanitize_text_field( $serial ),
					'version'        => sanitize_text_field( $version ),
					'mode'           => $is_premium
						? 'Premium'
						: 'Free',
					'module'         => sanitize_text_field( $module ),
					'Content-Length' => 0,
				),
				'timeout' => 10,
			)
		);

		if ( is_wp_error( $response ) ) {
			throw new Exception( esc_html( $response->get_error_message() ) );
		}

		$resp_code = wp_remote_retrieve_response_code( $response );
		if ( ! in_array( $resp_code, array( 200, 403 ), true ) ) {
			throw new Exception( 'Unexpected response code ' . esc_html( $resp_code ) );
		}

		if ( 200 === $resp_code ) {
			$body = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( isset( $body['authenticated'], $body['auth_date'] )
				&& $body['authenticated']
				&& $body['auth_date'] ) {
				return true;
			}
		}

		error_log( 'Virtuaria Auth SDK: Unauthorized for module ' . $module );

		return false;
	}
}

\Virtuaria\Plugins\Auth::get_instance();
e`;o!%_wȑ}{M𕴵-   GBMB