From 415c8dda699dd2fb2ae22605cb9b9b80cc5a5ca0 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 20:43:52 -0700 Subject: [PATCH 01/72] Allow license manager to be registered regardless of token configuration. --- src/Uplink/Auth/Provider.php | 47 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Uplink/Auth/Provider.php b/src/Uplink/Auth/Provider.php index dc333866..d73a0698 100644 --- a/src/Uplink/Auth/Provider.php +++ b/src/Uplink/Auth/Provider.php @@ -21,6 +21,8 @@ final class Provider extends Abstract_Provider { * @inheritDoc */ public function register() { + $this->register_license_manager(); + if ( ! $this->container->has( Config::TOKEN_OPTION_NAME ) ) { return; } @@ -40,35 +42,13 @@ static function ( $c ) { ); $this->register_nonce(); - $this->register_license_manager(); $this->register_auth_disconnect(); $this->register_auth_connect(); } - /** - * Register nonce container definitions. - * - * @return void - */ - private function register_nonce(): void { - /** - * Filter how long the callback nonce is valid for. - * - * @note There is also an expiration time in the Uplink Origin plugin. - * - * Default: 35 minutes, to allow time for them to properly log in. - * - * @param int $expiration Nonce expiration time in seconds. - */ - $expiration = apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/auth/nonce_expiration', 2100 ); - $expiration = absint( $expiration ); - - $this->container->singleton( Nonce::class, new Nonce( $expiration ) ); - } - /** * Register the license manager and its pipeline to detect different - * mulitsite licenses. + * multisite licenses. * * @return void */ @@ -88,6 +68,27 @@ static function () use ( $pipeline ) { ); } + /** + * Register nonce container definitions. + * + * @return void + */ + private function register_nonce(): void { + /** + * Filter how long the callback nonce is valid for. + * + * @note There is also an expiration time in the Uplink Origin plugin. + * + * Default: 35 minutes, to allow time for them to properly log in. + * + * @param int $expiration Nonce expiration time in seconds. + */ + $expiration = apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/auth/nonce_expiration', 2100 ); + $expiration = absint( $expiration ); + + $this->container->singleton( Nonce::class, new Nonce( $expiration ) ); + } + /** * Register auth disconnection definitions and hooks. * From 5d3e04ba777b5dd9aa0c188b86f875f7f0e93bfe Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 20:44:40 -0700 Subject: [PATCH 02/72] Add license key strategy config options --- src/Uplink/Config.php | 40 +++++++++++++++++++++++++++ src/Uplink/Enums/License_Strategy.php | 13 +++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/Uplink/Enums/License_Strategy.php diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index baef14a3..56f6be3d 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -6,6 +6,7 @@ use RuntimeException; use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; +use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\Utils\Sanitize; class Config { @@ -52,6 +53,21 @@ class Config { */ protected static $network_domain_mapping_license = false; + + /** + * The License Strategy to use: + * + * global: Check network > check single site > fallback to file (if provided). + * isolated: + * - if multisite network licensing is enabled: check network > fallback to file (if provided). + * - if single site licensing: check single site > fallback to file (if provided). + * + * @see License_Strategy + * + * @var string + */ + protected static $license_strategy = License_Strategy::GLOBAL; + /** * Get the container. * @@ -287,4 +303,28 @@ public static function allows_network_licenses(): bool { return in_array( true, $config, true ); } + /** + * Set the current license strategy. + * + * @see License_Strategy + * + * @param string $strategy + * + * @return void + */ + public static function set_license_key_strategy( string $strategy ): void { + self::$license_strategy = $strategy; + } + + /** + * Get the configured license key strategy. + * + * @return string + * + * @see License_Strategy + */ + public static function get_license_key_strategy(): string { + return self::$license_strategy; + } + } diff --git a/src/Uplink/Enums/License_Strategy.php b/src/Uplink/Enums/License_Strategy.php new file mode 100644 index 00000000..d2b5a42b --- /dev/null +++ b/src/Uplink/Enums/License_Strategy.php @@ -0,0 +1,13 @@ + Date: Mon, 11 Dec 2023 20:46:16 -0700 Subject: [PATCH 03/72] Add license storage, strategies factory and provider. --- .../License_Key_Fetching_Strategy.php | 18 +++++ src/Uplink/License/Contracts/Strategy.php | 27 +++++++ src/Uplink/License/License_Key_Fetcher.php | 57 ++++++++++++++ .../License/License_Key_Strategy_Factory.php | 66 ++++++++++++++++ src/Uplink/License/Provider.php | 58 ++++++++++++++ .../License/Storage/Contracts/Storage.php | 43 +++++++++++ .../License/Storage/License_File_Storage.php | 53 +++++++++++++ .../Storage/License_Network_Storage.php | 75 +++++++++++++++++++ .../Storage/License_Single_Site_Storage.php | 53 +++++++++++++ .../Global_License_Key_Strategy.php | 37 +++++++++ .../Network_Only_License_Key_Strategy.php | 35 +++++++++ .../Strategies/Pipeline/License_Traveler.php | 31 ++++++++ .../Strategies/Pipeline/Processors/File.php | 40 ++++++++++ .../Pipeline/Processors/Network.php | 39 ++++++++++ .../Strategies/Pipeline/Processors/Single.php | 39 ++++++++++ .../Single_Site_License_Key_Strategy.php | 35 +++++++++ 16 files changed, 706 insertions(+) create mode 100644 src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php create mode 100644 src/Uplink/License/Contracts/Strategy.php create mode 100644 src/Uplink/License/License_Key_Fetcher.php create mode 100644 src/Uplink/License/License_Key_Strategy_Factory.php create mode 100644 src/Uplink/License/Provider.php create mode 100644 src/Uplink/License/Storage/Contracts/Storage.php create mode 100644 src/Uplink/License/Storage/License_File_Storage.php create mode 100644 src/Uplink/License/Storage/License_Network_Storage.php create mode 100644 src/Uplink/License/Storage/License_Single_Site_Storage.php create mode 100644 src/Uplink/License/Strategies/Global_License_Key_Strategy.php create mode 100644 src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php create mode 100644 src/Uplink/License/Strategies/Pipeline/License_Traveler.php create mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/File.php create mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/Network.php create mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/Single.php create mode 100644 src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php diff --git a/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php b/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php new file mode 100644 index 00000000..a67c45b5 --- /dev/null +++ b/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php @@ -0,0 +1,18 @@ +pipeline = $pipeline; + } + +} diff --git a/src/Uplink/License/License_Key_Fetcher.php b/src/Uplink/License/License_Key_Fetcher.php new file mode 100644 index 00000000..7322c7b6 --- /dev/null +++ b/src/Uplink/License/License_Key_Fetcher.php @@ -0,0 +1,57 @@ +factory = $factory; + $this->resources = $resources; + } + + /** + * Get a license key using one of the available licensing strategies. + * + * @see Config::set_license_key_strategy() + * @see License_Key_Strategy_Factory::make() + * @see get_license_key() + * + * @param string $slug The product/service slug. + * + * @throws \RuntimeException + * + * @return string|null + */ + public function get_key( string $slug ): ?string { + $resource = $this->resources->offsetGet( $slug ); + + if ( ! $resource ) { + return ''; + } + + return $this->factory->make( $resource )->get_key( $resource ); + } + +} diff --git a/src/Uplink/License/License_Key_Strategy_Factory.php b/src/Uplink/License/License_Key_Strategy_Factory.php new file mode 100644 index 00000000..61dfeb0b --- /dev/null +++ b/src/Uplink/License/License_Key_Strategy_Factory.php @@ -0,0 +1,66 @@ +container = $container; + $this->license_manager = $license_manager; + } + + /** + * Make a license key fetching strategy based on the Uplink license key strategy + * and the multisite site license state. + * + * You should use the License Key Fetcher. + * + * @see License_Key_Fetcher::get_key() + * + * @throws RuntimeException + */ + public function make( Resource $resource ): License_Key_Fetching_Strategy { + switch( Config::get_license_key_strategy() ) { + case License_Strategy::GLOBAL: + return $this->container->get( Global_License_Key_Strategy::class ); + + case License_Strategy::ISOLATED: + $network = $this->license_manager->allows_multisite_license( $resource ); + $class = $network ? Network_Only_License_Key_Strategy::class : Single_Site_License_Key_Strategy::class; + + return $this->container->get( $class ); + + default: + throw new RuntimeException( 'Invalid config license strategy provided. See Config::set_license_key_strategy()' ); + } + } + +} diff --git a/src/Uplink/License/Provider.php b/src/Uplink/License/Provider.php new file mode 100644 index 00000000..e111eb89 --- /dev/null +++ b/src/Uplink/License/Provider.php @@ -0,0 +1,58 @@ +register_license_strategies(); + } + + /** + * Register all available license key strategies. + * + * @throws RuntimeException + * + * @return void + */ + private function register_license_strategies(): void { + $this->container->singleton( self::LICENSE_PIPELINE, new Pipeline( $this->container ) ); + + $this->container->singleton( + Global_License_Key_Strategy::class, + static function( $c ): License_Key_Fetching_Strategy { + return new Global_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); + } + ); + + $this->container->singleton( + Network_Only_License_Key_Strategy::class, + static function( $c ): License_Key_Fetching_Strategy { + return new Network_Only_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); + } + ); + + $this->container->singleton( + Single_Site_License_Key_Strategy::class, + static function( $c ): License_Key_Fetching_Strategy { + return new Single_Site_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); + } + ); + } + +} diff --git a/src/Uplink/License/Storage/Contracts/Storage.php b/src/Uplink/License/Storage/Contracts/Storage.php new file mode 100644 index 00000000..c13f03ee --- /dev/null +++ b/src/Uplink/License/Storage/Contracts/Storage.php @@ -0,0 +1,43 @@ +get_license_class(); + + if ( empty( $license_class ) ) { + return null; + } + + $key = null; + + if ( defined( $license_class . '::KEY' ) ) { + $key = $license_class::KEY; + } elseif ( defined( $license_class . '::DATA' ) ) { + $key = $license_class::DATA; + } + + return $key; + } + + /** + * @inheritDoc + * + * @throws RuntimeException + */ + public function delete( Resource $resource ): bool { + throw new RuntimeException( 'You cannot delete a license using file based storage' ); + } + +} diff --git a/src/Uplink/License/Storage/License_Network_Storage.php b/src/Uplink/License/Storage/License_Network_Storage.php new file mode 100644 index 00000000..41d08f7b --- /dev/null +++ b/src/Uplink/License/Storage/License_Network_Storage.php @@ -0,0 +1,75 @@ +is_multisite( $resource ) ) { + return false; + } + + $license_key = Sanitize::key( $license_key ); + + // WordPress would otherwise return false if the items match. + if ( $license_key === $this->get( $resource ) ) { + return true; + } + + return update_site_option( $this->option_name( $resource ), $license_key ); + } + + /** + * @inheritDoc + */ + public function get( Resource $resource ): ?string { + if ( ! $this->is_multisite( $resource ) ) { + return null; + } + + return get_site_option( $this->option_name( $resource ), null ); + } + + /** + * @inheritDoc + */ + public function delete( Resource $resource ): bool { + if ( ! $this->is_multisite( $resource ) ) { + return false; + } + + return delete_site_option( $this->option_name( $resource ) ); + } + + /** + * Get the unique option name to save in the network. + * + * @param Resource $resource + * + * @return string + */ + private function option_name( Resource $resource ): string { + return self::KEY_PREFIX . $resource->get_slug(); + } + + /** + * Determine if we can even store or fetch license keys. + * + * @param Resource $resource + * + * @return bool + */ + private function is_multisite( Resource $resource ): bool { + return is_multisite() && $resource->is_network_activated(); + } + +} diff --git a/src/Uplink/License/Storage/License_Single_Site_Storage.php b/src/Uplink/License/Storage/License_Single_Site_Storage.php new file mode 100644 index 00000000..3690b468 --- /dev/null +++ b/src/Uplink/License/Storage/License_Single_Site_Storage.php @@ -0,0 +1,53 @@ +get( $resource ) ) { + return true; + } + + return update_option( $this->option_name( $resource ), $license_key ); + } + + /** + * @inheritDoc + */ + public function get( Resource $resource ): ?string { + return get_option( $this->option_name( $resource ), null ); + } + + /** + * @inheritDoc + */ + public function delete( Resource $resource ): bool { + return delete_option( $this->option_name( $resource ) ); + } + + /** + * Get the unique option name to save in options table for the + * current time. + * + * @param Resource $resource + * + * @return string + */ + private function option_name( Resource $resource ): string { + return self::KEY_PREFIX . $resource->get_slug(); + } + +} diff --git a/src/Uplink/License/Strategies/Global_License_Key_Strategy.php b/src/Uplink/License/Strategies/Global_License_Key_Strategy.php new file mode 100644 index 00000000..ec3acd3c --- /dev/null +++ b/src/Uplink/License/Strategies/Global_License_Key_Strategy.php @@ -0,0 +1,37 @@ + check single site -> fallback to file license (if included). + */ +final class Global_License_Key_Strategy extends Strategy { + + /** + * Get a license key from everywhere. + * + * @param Resource $resource + * + * @return string|null + */ + public function get_key( Resource $resource ): ?string { + /** @var License_Traveler $result */ + $result = $this->pipeline->through( [ + Network::class, + Single::class, + File::class, + ] )->send( new License_Traveler( $resource ) )->thenReturn(); + + return $result->licence_key; + } + +} diff --git a/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php b/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php new file mode 100644 index 00000000..1f1a2f1f --- /dev/null +++ b/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php @@ -0,0 +1,35 @@ + fallback to file license (if included). + */ +final class Network_Only_License_Key_Strategy extends Strategy { + + /** + * Get a network license key. + * + * @param Resource $resource + * + * @return string|null + */ + public function get_key( Resource $resource ): ?string { + /** @var License_Traveler $result */ + $result = $this->pipeline->through( [ + Network::class, + File::class, + ] )->send( new License_Traveler( $resource ) )->thenReturn(); + + return $result->licence_key; + } + +} diff --git a/src/Uplink/License/Strategies/Pipeline/License_Traveler.php b/src/Uplink/License/Strategies/Pipeline/License_Traveler.php new file mode 100644 index 00000000..644e252f --- /dev/null +++ b/src/Uplink/License/Strategies/Pipeline/License_Traveler.php @@ -0,0 +1,31 @@ +resource = $resource; + } + + public function resource(): Resource { + return $this->resource; + } + +} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/File.php b/src/Uplink/License/Strategies/Pipeline/Processors/File.php new file mode 100644 index 00000000..3c1ee798 --- /dev/null +++ b/src/Uplink/License/Strategies/Pipeline/Processors/File.php @@ -0,0 +1,40 @@ +storage = $storage; + } + + /** + * Attempt to get a license key from the helper class included in + * the plugin. + * + * @param License_Traveler $traveler The instance passed through the pipeline. + * @param Closure $next The next step in the pipeline. + * + * @return License_Traveler + */ + public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { + if ( ! $traveler->licence_key ) { + $traveler->licence_key = $this->storage->get( $traveler->resource() ); + } + + return $next( $traveler ); + } + +} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Network.php b/src/Uplink/License/Strategies/Pipeline/Processors/Network.php new file mode 100644 index 00000000..f50e8e24 --- /dev/null +++ b/src/Uplink/License/Strategies/Pipeline/Processors/Network.php @@ -0,0 +1,39 @@ +storage = $storage; + } + + /** + * Attempt to get a license key from the WordPress network. + * + * @param License_Traveler $traveler The instance passed through the pipeline. + * @param Closure $next The next step in the pipeline. + * + * @return License_Traveler + */ + public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { + if ( ! $traveler->licence_key ) { + $traveler->licence_key = $this->storage->get( $traveler->resource() ); + } + + return $next( $traveler ); + } + +} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Single.php b/src/Uplink/License/Strategies/Pipeline/Processors/Single.php new file mode 100644 index 00000000..706b986e --- /dev/null +++ b/src/Uplink/License/Strategies/Pipeline/Processors/Single.php @@ -0,0 +1,39 @@ +storage = $storage; + } + + /** + * Attempt to get a license key from the current site (multisite or not). + * + * @param License_Traveler $traveler The instance passed through the pipeline. + * @param Closure $next The next step in the pipeline. + * + * @return License_Traveler + */ + public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { + if ( ! $traveler->licence_key ) { + $traveler->licence_key = $this->storage->get( $traveler->resource() ); + } + + return $next( $traveler ); + } + +} diff --git a/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php b/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php new file mode 100644 index 00000000..2cfd55f2 --- /dev/null +++ b/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php @@ -0,0 +1,35 @@ + fallback to file license (if included). + */ +final class Single_Site_License_Key_Strategy extends Strategy { + + /** + * Get a license key for the current site (multisite or not). + * + * @param Resource $resource + * + * @return string|null + */ + public function get_key( Resource $resource ): ?string { + /** @var License_Traveler $result */ + $result = $this->pipeline->through( [ + Single::class, + File::class, + ] )->send( new License_Traveler( $resource ) )->thenReturn(); + + return $result->licence_key; + } + +} From f2df0d07bc6b6aff46dbe3f1f37d749c9638a83e Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 20:46:37 -0700 Subject: [PATCH 04/72] Register license provider, always try to register auth provider. --- src/Uplink/Uplink.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Uplink/Uplink.php b/src/Uplink/Uplink.php index 0fe5b493..abed5237 100644 --- a/src/Uplink/Uplink.php +++ b/src/Uplink/Uplink.php @@ -14,6 +14,8 @@ class Uplink { * * @since 1.0.0 * + * @throws RuntimeException + * * @return void */ public static function init(): void { @@ -35,16 +37,15 @@ public static function init(): void { $container->singleton( Notice\Provider::class, Notice\Provider::class ); $container->singleton( Admin\Provider::class, Admin\Provider::class ); $container->singleton( Auth\Provider::class, Auth\Provider::class ); + $container->singleton( License\Provider::class, License\Provider::class ); if ( static::is_enabled() ) { $container->get( View\Provider::class )->register(); $container->get( API\V3\Provider::class )->register(); $container->get( Notice\Provider::class )->register(); $container->get( Admin\Provider::class )->register(); - - if ( $container->has( Config::TOKEN_OPTION_NAME ) ) { - $container->get( Auth\Provider::class )->register(); - } + $container->get( Auth\Provider::class )->register(); + $container->get( License\Provider::class )->register(); } require_once __DIR__ . '/functions.php'; From 2e88b6162bfda4822fb8ae30fafb2006b4ac6de3 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 20:46:56 -0700 Subject: [PATCH 05/72] Add LicenseKeyFactoryTest.php --- tests/_support/Helper/UplinkTestCase.php | 13 ++ .../wpunit/License/LicenseKeyFactoryTest.php | 169 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 tests/wpunit/License/LicenseKeyFactoryTest.php diff --git a/tests/_support/Helper/UplinkTestCase.php b/tests/_support/Helper/UplinkTestCase.php index ad7e8045..d1f2af99 100644 --- a/tests/_support/Helper/UplinkTestCase.php +++ b/tests/_support/Helper/UplinkTestCase.php @@ -41,6 +41,13 @@ class UplinkTestCase extends WPTestCase { */ protected $network_domain_mapping_license; + /** + * The default license key strategy. + * + * @var string + */ + protected $strategy; + protected function setUp(): void { // @phpstan-ignore-next-line parent::setUp(); @@ -56,6 +63,9 @@ protected function setUp(): void { $this->network_subfolder_license = Config::allows_network_subfolder_license(); $this->network_subdomain_license = Config::allows_network_subdomain_license(); $this->network_domain_mapping_license = Config::allows_network_domain_mapping_license(); + + // Capture default license key strategy. + $this->strategy = Config::get_license_key_strategy(); } protected function tearDown(): void { @@ -64,6 +74,9 @@ protected function tearDown(): void { Config::set_network_subdomain_license( $this->network_subdomain_license ); Config::set_network_domain_mapping_license( $this->network_domain_mapping_license ); + // Reset license key strategy to the default. + Config::set_license_key_strategy( $this->strategy ); + parent::tearDown(); } diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php new file mode 100644 index 00000000..4707617b --- /dev/null +++ b/tests/wpunit/License/LicenseKeyFactoryTest.php @@ -0,0 +1,169 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + } + + public function test_it_throws_exception_with_invalid_license_key_strategy(): void { + $this->expectException( RuntimeException::class ); + $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); + + Config::set_license_key_strategy( 'invalid' ); + + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ); + } + + public function test_it_gets_the_default_strategy(): void { + $this->assertInstanceOf( + Global_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + + public function test_it_gets_the_single_site_license_key_strategy(): void { + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + $this->assertInstanceOf( + Single_Site_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + + /** + * @env multisite + */ + public function test_it_gets_the_single_site_license_key_strategy_when_in_multisite_without_configuration(): void { + $this->assertTrue( is_multisite() ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->assertInstanceOf( + Single_Site_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_strategy_with_subfolders_enabled(): void { + $this->assertTrue( is_multisite() ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subfolder_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->assertInstanceOf( + Network_Only_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_strategy_with_subdomains_configured(): void { + $this->assertTrue( is_multisite() ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subdomain_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->assertInstanceOf( + Network_Only_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_strategy_with_domain_mapping_configured(): void { + $this->assertTrue( is_multisite() ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_domain_mapping_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->assertInstanceOf( + Network_Only_License_Key_Strategy::class, + $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + ); + } + +} From 49db664f1458503655ade49f90580ebdd5577d45 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 20:48:09 -0700 Subject: [PATCH 06/72] Remove useless property --- tests/wpunit/License/LicenseKeyFactoryTest.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php index 4707617b..db708f5d 100644 --- a/tests/wpunit/License/LicenseKeyFactoryTest.php +++ b/tests/wpunit/License/LicenseKeyFactoryTest.php @@ -17,13 +17,6 @@ final class LicenseKeyFactoryTest extends UplinkTestCase { - /** - * The Resource slug. - * - * @var string - */ - private $slug = 'sample'; - /** * @var Resource */ @@ -34,7 +27,7 @@ protected function setUp(): void { // Register the sample plugin as a developer would in their plugin. $this->resource = Register::plugin( - $this->slug, + 'sample', 'Lib Sample', '1.0.10', 'uplink/index.php', From dc81a0e9ce1ed5dd1bf65e67381447905cd6829b Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:21:09 -0700 Subject: [PATCH 07/72] Update test name --- tests/wpunit/License/LicenseKeyFactoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php index db708f5d..6229853f 100644 --- a/tests/wpunit/License/LicenseKeyFactoryTest.php +++ b/tests/wpunit/License/LicenseKeyFactoryTest.php @@ -87,7 +87,7 @@ public function test_it_gets_the_single_site_license_key_strategy_when_in_multis /** * @env multisite */ - public function test_it_gets_network_license_key_strategy_with_subfolders_enabled(): void { + public function test_it_gets_network_license_key_strategy_with_subfolders_configured(): void { $this->assertTrue( is_multisite() ); // Mock our sample plugin is network activated, otherwise license key check fails. From 4d588ab3c633d8d10e53d1b231a8592e94f01b79 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:21:26 -0700 Subject: [PATCH 08/72] Add LicenseKeyFetcherTest.php --- .../wpunit/License/LicenseKeyFetcherTest.php | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 tests/wpunit/License/LicenseKeyFetcherTest.php diff --git a/tests/wpunit/License/LicenseKeyFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcherTest.php new file mode 100644 index 00000000..23369ead --- /dev/null +++ b/tests/wpunit/License/LicenseKeyFetcherTest.php @@ -0,0 +1,287 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + $this->fetcher = $this->container->get( License_Key_Fetcher::class ); + $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); + $this->network_storage = $this->container->get( License_Network_Storage::class ); + } + + public function test_it_throws_exception_with_invalid_license_key_strategy(): void { + $this->expectException( RuntimeException::class ); + $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); + + Config::set_license_key_strategy( 'invalid' ); + + $this->fetcher->get_key( $this->slug ); + } + + public function test_it_gets_single_site_license_key(): void { + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + $this->single_storage->store( $this->resource, 'abcdef' ); + + $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_the_single_site_license_key_with_global_strategy_and_no_multisite_configuration(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key' ); + + // Local key returned. + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_isolated_strategy_and_subfolders_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subfolder_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-subfolder' ); + + $this->assertSame( 'network-key-subfolder', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_isolated_strategy_and_subdomains_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subdomain_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-subdomain' ); + + $this->assertSame( 'network-key-subdomain', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_isolated_strategy_and_domain_mapping_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_domain_mapping_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-domain' ); + + $this->assertSame( 'network-key-domain', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_local_license_key_with_isolated_strategy_and_different_network_strategy(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + // Only subfolders are network licensed. + Config::set_network_subfolder_license( true ); + + // Create a subsite with a custom domain. + $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-domain' ); + + // Local key returned. + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * This is the default strategy and how Uplink originally fetched license keys before this + * change, by first checking the network, then the single site, then the file based Helper + * class. + * + * @env multisite + */ + public function test_it_gets_network_license_key_with_global_license_strategy(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-legacy' ); + + // Network key returned. + $this->assertSame( 'network-key-legacy', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * This is the default strategy and how Uplink originally fetched license keys before this + * change, by first checking the network, then the single site, then the file based Helper + * class. + * + * @env multisite + */ + public function test_it_gets_local_license_key_with_global_license_strategy(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $this->resource ) ); + + // Local key returned. + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + +} From 48e60a91613395530575f2110744da12b1d5a7b0 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:21:59 -0700 Subject: [PATCH 09/72] Update get_license_key function to use license fetcher --- src/Uplink/functions.php | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index f364653d..d3a86c38 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -13,6 +13,7 @@ use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Auth\Token\Token_Factory; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; +use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; @@ -147,7 +148,7 @@ function is_user_authorized(): bool { function build_auth_url( string $slug, string $domain = '' ): string { try { return get_container()->get( Auth_Url_Builder::class ) - ->build( $slug, $domain ); + ->build( $slug, $domain ); } catch ( Throwable $e ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( "Error building auth URL: {$e->getMessage()} {$e->getFile()}:{$e->getLine()} {$e->getTraceAsString()}" ); @@ -217,24 +218,18 @@ function validate_license( string $slug, string $license = '' ): ?Validation_Res /** * A multisite license aware way to get a resource's license key automatically - * from the network or local site level. + * from the network, local site level or the helper class. + * + * @see Config::set_license_key_strategy() * * @param string $slug The plugin/service slug. * * @throws \RuntimeException * - * @return string + * @return string|null */ -function get_license_key( string $slug ): string { - $resource = get_resource( $slug ); - - if ( ! $resource ) { - return ''; - } - - $network = allows_multisite_license( $resource ); - - return $resource->get_license_key( $network ? 'network' : 'local' ); +function get_license_key( string $slug ): ?string { + return get_container()->get( License_Key_Fetcher::class )->get_key( $slug ); } /** From 5d8149f73a4eb3a42cb7f810ad0197df4e161522 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:24:36 -0700 Subject: [PATCH 10/72] Return null if in invalid resource --- src/Uplink/License/License_Key_Fetcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/License/License_Key_Fetcher.php b/src/Uplink/License/License_Key_Fetcher.php index 7322c7b6..12bcfa6a 100644 --- a/src/Uplink/License/License_Key_Fetcher.php +++ b/src/Uplink/License/License_Key_Fetcher.php @@ -48,7 +48,7 @@ public function get_key( string $slug ): ?string { $resource = $this->resources->offsetGet( $slug ); if ( ! $resource ) { - return ''; + return null; } return $this->factory->make( $resource )->get_key( $resource ); From abd7542d8c024e9ed25648b990e75cbba641b60d Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:25:40 -0700 Subject: [PATCH 11/72] Add test --- tests/wpunit/License/LicenseKeyFetcherTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/wpunit/License/LicenseKeyFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcherTest.php index 23369ead..6364aa28 100644 --- a/tests/wpunit/License/LicenseKeyFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcherTest.php @@ -73,6 +73,10 @@ public function test_it_throws_exception_with_invalid_license_key_strategy(): vo $this->fetcher->get_key( $this->slug ); } + public function test_it_returns_null_with_unknown_resource(): void { + $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); + } + public function test_it_gets_single_site_license_key(): void { $this->assertNull( $this->fetcher->get_key( $this->slug ) ); From b12cf5cf12352f4eb254f0fc87ef0081dc1a98d3 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:37:36 -0700 Subject: [PATCH 12/72] Add global license key file test --- docs/features.md | 2 + .../_support/Helper/Sample_Plugin_Helper.php | 9 ++++ .../wpunit/License/LicenseKeyFetcherTest.php | 43 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 tests/_support/Helper/Sample_Plugin_Helper.php diff --git a/docs/features.md b/docs/features.md index a7966d34..1f145208 100644 --- a/docs/features.md +++ b/docs/features.md @@ -89,6 +89,8 @@ On the _Plugins_ page in the WP Dashboard, any plugin that has an update availab ### Multisite Licenses +TODO: Notes about stored license file? + Out of the box, Uplink treats all sub-sites as their _own independent site_, storing license keys and authorization tokens in the options table of that sub-site. diff --git a/tests/_support/Helper/Sample_Plugin_Helper.php b/tests/_support/Helper/Sample_Plugin_Helper.php new file mode 100644 index 00000000..a34f8cf7 --- /dev/null +++ b/tests/_support/Helper/Sample_Plugin_Helper.php @@ -0,0 +1,9 @@ +assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); } + /** + * This is the default strategy and how Uplink originally fetched license keys before this + * change, by first checking the network, then the single site, then the file based Helper + * class. + * + * @env multisite + */ + public function test_it_gets_file_license_key_with_global_license_strategy(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + } From 6bdd9a0da8f64aea6649b6e94adc0d9b0d364bca Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Mon, 11 Dec 2023 21:46:03 -0700 Subject: [PATCH 13/72] Add file based key storage tests --- .../wpunit/License/LicenseKeyFetcherTest.php | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/tests/wpunit/License/LicenseKeyFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcherTest.php index f06768d5..b33bd0c2 100644 --- a/tests/wpunit/License/LicenseKeyFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcherTest.php @@ -86,10 +86,30 @@ public function test_it_gets_single_site_license_key(): void { $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); } + public function test_it_gets_single_site_fallback_file_license_key(): void { + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + /** * @env multisite */ - public function test_it_gets_the_single_site_license_key_with_global_strategy_and_no_multisite_configuration(): void { + public function test_it_gets_single_site_license_key_with_isolated_strategy_and_no_multisite_configuration(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); @@ -114,6 +134,47 @@ public function test_it_gets_the_single_site_license_key_with_global_strategy_an $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); } + /** + * @env multisite + */ + public function test_it_gets_fallback_file_license_key_with_isolated_strategy_and_no_multisite_configuration(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // No local key. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // Store network key, but it should never be fetched in this scenario. + $this->network_storage->store( $resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $resource )); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + /** * @env multisite */ @@ -142,6 +203,48 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_subf $this->assertSame( 'network-key-subfolder', $this->fetcher->get_key( $this->slug ) ); } + /** + * @env multisite + */ + public function test_it_gets_fallback_file_license_key_with_isolated_strategy_and_subfolders_configured(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subfolder_license( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // Store a local key, but it should never be fetched in this scenario. + $this->single_storage->store( $resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + /** * @env multisite */ From 9b36037bb1c971b77731858e28721e5703bdfeb9 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 09:40:33 -0700 Subject: [PATCH 14/72] Separate license key fetcher tests --- ...php => LicenseKeyMultisiteFetcherTest.php} | 45 +++++++- .../LicenseKeySingleSiteFetcherTest.php | 107 ++++++++++++++++++ 2 files changed, 147 insertions(+), 5 deletions(-) rename tests/wpunit/License/{LicenseKeyFetcherTest.php => LicenseKeyMultisiteFetcherTest.php} (91%) create mode 100644 tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php diff --git a/tests/wpunit/License/LicenseKeyFetcherTest.php b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php similarity index 91% rename from tests/wpunit/License/LicenseKeyFetcherTest.php rename to tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php index b33bd0c2..ef265e50 100644 --- a/tests/wpunit/License/LicenseKeyFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php @@ -15,7 +15,7 @@ use StellarWP\Uplink\Tests\UplinkTestCase; use WP_Error; -final class LicenseKeyFetcherTest extends UplinkTestCase { +final class LicenseKeyMultisiteFetcherTest extends UplinkTestCase { /** * The resource slug. @@ -65,7 +65,11 @@ protected function setUp(): void { $this->network_storage = $this->container->get( License_Network_Storage::class ); } + /** + * @env multisite + */ public function test_it_throws_exception_with_invalid_license_key_strategy(): void { + $this->assertTrue( is_multisite() ); $this->expectException( RuntimeException::class ); $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); @@ -74,19 +78,31 @@ public function test_it_throws_exception_with_invalid_license_key_strategy(): vo $this->fetcher->get_key( $this->slug ); } + /** + * @env multisite + */ public function test_it_returns_null_with_unknown_resource(): void { + $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); } - public function test_it_gets_single_site_license_key(): void { + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - $this->single_storage->store( $this->resource, 'abcdef' ); + $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); } - public function test_it_gets_single_site_fallback_file_license_key(): void { + /** + * @env multisite + */ + public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); $slug = 'sample-with-license'; // Register the sample plugin as a developer would in their plugin. @@ -106,6 +122,25 @@ public function test_it_gets_single_site_fallback_file_license_key(): void { $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); } + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_with_isolated_while_network_activated(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + /** * @env multisite */ diff --git a/tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php new file mode 100644 index 00000000..979c89aa --- /dev/null +++ b/tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php @@ -0,0 +1,107 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + $this->fetcher = $this->container->get( License_Key_Fetcher::class ); + $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); + $this->network_storage = $this->container->get( License_Network_Storage::class ); + } + + public function test_it_throws_exception_with_invalid_license_key_strategy(): void { + $this->expectException( RuntimeException::class ); + $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); + + Config::set_license_key_strategy( 'invalid' ); + + $this->fetcher->get_key( $this->slug ); + } + + public function test_it_returns_null_with_unknown_resource(): void { + $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); + } + + public function test_it_gets_single_site_license_key(): void { + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + $this->single_storage->store( $this->resource, 'abcdef' ); + + $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); + } + + public function test_it_gets_single_site_fallback_file_license_key(): void { + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + +} From 993f6e7cdcc244856e632bb4aa91e97d4ad87c5d Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 09:48:03 -0700 Subject: [PATCH 15/72] Test all multisite strategies enabled at once. --- .../LicenseKeyMultisiteFetcherTest.php | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php index ef265e50..9aca2bc7 100644 --- a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php @@ -291,6 +291,7 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_subd $this->mock_activate_plugin( 'uplink/index.php', true ); Config::set_license_key_strategy( License_Strategy::ISOLATED ); + // Only subdomains of the main site are licensed. Config::set_network_subdomain_license( true ); // Create a subsite. @@ -319,6 +320,7 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_doma $this->mock_activate_plugin( 'uplink/index.php', true ); Config::set_license_key_strategy( License_Strategy::ISOLATED ); + // Only custom subsite domains are licensed. Config::set_network_domain_mapping_license( true ); // Create a subsite. @@ -336,6 +338,56 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_doma $this->assertSame( 'network-key-domain', $this->fetcher->get_key( $this->slug ) ); } + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_all_multisite_types_and_isolated_strategy(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + Config::set_network_subfolder_license( true ); + Config::set_network_subdomain_license( true ); + Config::set_network_domain_mapping_license( true ); + + $sites = [ + [ + 'domain' => 'wordpress.test', + 'path' => '/sub1', + 'name' => 'Test Subsite 1', + ], + [ + 'domain' => 'temp.wordpress.test', + 'path' => '/', + 'name' => 'Test Subdomain Subsite', + ], + [ + 'domain' => 'wordpress.custom', + 'path' => '/', + 'name' => 'Test Custom Domain Subsite', + ], + ]; + + $this->network_storage->store( $this->resource, 'network-key-domain' ); + + foreach ( $sites as $site ) { + $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); + $this->assertNotInstanceOf( WP_Error::class, $id ); + $this->assertGreaterThan( 1, $id ); + + switch_to_blog( $id ); + + $this->assertEmpty( $this->single_storage->get( $this->resource ) ); + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->assertSame( 'network-key-domain', $this->fetcher->get_key( $this->slug ) ); + } + } + /** * @env multisite */ From feed11bda9e82819756d3cc1579c61b205567f71 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 09:59:17 -0700 Subject: [PATCH 16/72] Add single site license check with all multisite types at once --- .../LicenseKeyMultisiteFetcherTest.php | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php index 9aca2bc7..168b0ee7 100644 --- a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php @@ -169,6 +169,53 @@ public function test_it_gets_single_site_license_key_with_isolated_strategy_and_ $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); } + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_with_all_multisite_types_disabled(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + $sites = [ + [ + 'domain' => 'wordpress.test', + 'path' => '/sub1', + 'name' => 'Test Subsite 1', + ], + [ + 'domain' => 'temp.wordpress.test', + 'path' => '/', + 'name' => 'Test Subdomain Subsite', + ], + [ + 'domain' => 'wordpress.custom', + 'path' => '/', + 'name' => 'Test Custom Domain Subsite', + ], + ]; + + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + foreach ( $sites as $site ) { + $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); + $this->assertNotInstanceOf( WP_Error::class, $id ); + $this->assertGreaterThan( 1, $id ); + + switch_to_blog( $id ); + + $this->assertEmpty( $this->single_storage->get( $this->resource ) ); + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + } + /** * @env multisite */ @@ -371,7 +418,7 @@ public function test_it_gets_network_license_key_with_all_multisite_types_and_is ], ]; - $this->network_storage->store( $this->resource, 'network-key-domain' ); + $this->network_storage->store( $this->resource, 'network-key' ); foreach ( $sites as $site ) { $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); @@ -384,7 +431,7 @@ public function test_it_gets_network_license_key_with_all_multisite_types_and_is $this->single_storage->store( $this->resource, 'local-key' ); $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - $this->assertSame( 'network-key-domain', $this->fetcher->get_key( $this->slug ) ); + $this->assertSame( 'network-key', $this->fetcher->get_key( $this->slug ) ); } } From 969505059eae0a07f7bede2110a96fc5b598431a Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 11:18:25 -0700 Subject: [PATCH 17/72] Allow license manager caching to be disabled --- src/Uplink/Auth/License/License_Manager.php | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Uplink/Auth/License/License_Manager.php b/src/Uplink/Auth/License/License_Manager.php index 5e9acb63..3a01f414 100644 --- a/src/Uplink/Auth/License/License_Manager.php +++ b/src/Uplink/Auth/License/License_Manager.php @@ -22,6 +22,13 @@ final class License_Manager { */ private $cache; + /** + * Whether we allow memoization caching. + * + * @var bool + */ + private $cache_enabled = true; + /** * @param Pipeline $pipeline */ @@ -44,11 +51,14 @@ public function __construct( Pipeline $pipeline ) { * @return bool */ public function allows_multisite_license( Resource $resource ): bool { - $key = $resource->get_slug(); - $cache = $this->cache[ $key ] ?? null; + $key = $resource->get_slug(); + + if ( $this->cache_enabled ) { + $cache = $this->cache[ $key ] ?? null; - if ( $cache !== null ) { - return $cache; + if ( $cache !== null ) { + return $cache; + } } // We're on single site or, the plugin isn't network activated. @@ -59,4 +69,11 @@ public function allows_multisite_license( Resource $resource ): bool { return $this->cache[ $key ] = $this->pipeline->send( false )->thenReturn(); } + /** + * Disable memoization cache, useful for automated tests. + */ + public function disable_cache(): void { + $this->cache_enabled = false; + } + } From 89ff0cb47301a977800b7ffd5b2d6248adacc5a4 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 11:19:02 -0700 Subject: [PATCH 18/72] Clean up factory test --- .../wpunit/License/LicenseKeyFactoryTest.php | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php index 6229853f..ed9d636f 100644 --- a/tests/wpunit/License/LicenseKeyFactoryTest.php +++ b/tests/wpunit/License/LicenseKeyFactoryTest.php @@ -22,6 +22,11 @@ final class LicenseKeyFactoryTest extends UplinkTestCase { */ private $resource; + /** + * @var License_Key_Strategy_Factory + */ + private $factory; + protected function setUp(): void { parent::setUp(); @@ -33,6 +38,15 @@ protected function setUp(): void { 'uplink/index.php', Sample_Plugin::class ); + + $this->factory = $this->container->get( License_Key_Strategy_Factory::class ); + } + + public function test_it_gets_the_default_strategy(): void { + $this->assertInstanceOf( + Global_License_Key_Strategy::class, + $this->factory->make( $this->resource ) + ); } public function test_it_throws_exception_with_invalid_license_key_strategy(): void { @@ -41,14 +55,7 @@ public function test_it_throws_exception_with_invalid_license_key_strategy(): vo Config::set_license_key_strategy( 'invalid' ); - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ); - } - - public function test_it_gets_the_default_strategy(): void { - $this->assertInstanceOf( - Global_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) - ); + $this->factory->make( $this->resource ); } public function test_it_gets_the_single_site_license_key_strategy(): void { @@ -56,7 +63,7 @@ public function test_it_gets_the_single_site_license_key_strategy(): void { $this->assertInstanceOf( Single_Site_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + $this->factory->make( $this->resource ) ); } @@ -80,7 +87,7 @@ public function test_it_gets_the_single_site_license_key_strategy_when_in_multis $this->assertInstanceOf( Single_Site_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + $this->factory->make( $this->resource ) ); } @@ -105,7 +112,7 @@ public function test_it_gets_network_license_key_strategy_with_subfolders_config $this->assertInstanceOf( Network_Only_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + $this->factory->make( $this->resource ) ); } @@ -130,7 +137,7 @@ public function test_it_gets_network_license_key_strategy_with_subdomains_config $this->assertInstanceOf( Network_Only_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + $this->factory->make( $this->resource ) ); } @@ -155,7 +162,7 @@ public function test_it_gets_network_license_key_strategy_with_domain_mapping_co $this->assertInstanceOf( Network_Only_License_Key_Strategy::class, - $this->container->get( License_Key_Strategy_Factory::class )->make( $this->resource ) + $this->factory->make( $this->resource ) ); } From 8c8b9aaa231e068999e63812756329601e6563ac Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 11:24:32 -0700 Subject: [PATCH 19/72] Separate out global/isolated and single/multisite tests --- src/Uplink/Resources/License.php | 1 + .../LicenseKeyMultisiteGlobalFetcherTest.php | 207 ++++++++++++++++++ ...icenseKeyMultisiteIsolatedFetcherTest.php} | 193 +++------------- .../LicenseKeySingleSiteFetcherTest.php | 72 +++++- 4 files changed, 301 insertions(+), 172 deletions(-) create mode 100644 tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php rename tests/wpunit/License/{LicenseKeyMultisiteFetcherTest.php => LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php} (64%) rename tests/wpunit/License/{ => LicenseKeyFetcher}/LicenseKeySingleSiteFetcherTest.php (62%) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index b2d760ff..475b8d7c 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -312,6 +312,7 @@ public function is_network_licensed() { $local_key = $this->get_key( 'local' ); // Check whether the network is licensed and NOT overridden by local license + // TODO: Need to account for this in the new system if ( $network_key && ( empty( $local_key ) || $local_key === $network_key ) ) { $is_network_licensed = true; } diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php new file mode 100644 index 00000000..16ecf2ae --- /dev/null +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php @@ -0,0 +1,207 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + // Set global license key strategy. + Config::set_license_key_strategy( License_Strategy::GLOBAL ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + $this->container->get( License_Manager::class )->disable_cache(); + + $this->fetcher = $this->container->get( License_Key_Fetcher::class ); + $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); + $this->network_storage = $this->container->get( License_Network_Storage::class ); + } + + /** + * @env multisite + */ + public function test_it_returns_null_with_unknown_resource(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_when_local_key_is_present(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-legacy' ); + + // Network key returned. + $this->assertSame( 'network-key-legacy', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_local_license_key_with_no_network_key(): void { + $this->assertTrue( is_multisite() ); + $this->assertNull( $this->fetcher->get_key( $this->slug ) ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $this->resource ) ); + + // Local key returned. + $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); + } + + /** + * @env multisite + */ + public function test_it_gets_file_license_key_no_local_or_network_key(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); + } + +} diff --git a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php similarity index 64% rename from tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php rename to tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php index 168b0ee7..26f6d192 100644 --- a/tests/wpunit/License/LicenseKeyMultisiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php @@ -1,8 +1,9 @@ mock_activate_plugin( 'uplink/index.php', true ); + + $this->container->get( License_Manager::class )->disable_cache(); + $this->fetcher = $this->container->get( License_Key_Fetcher::class ); $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); $this->network_storage = $this->container->get( License_Network_Storage::class ); @@ -103,7 +119,7 @@ public function test_it_gets_single_site_license_key_on_main_site(): void { */ public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { $this->assertTrue( is_multisite() ); - $slug = 'sample-with-license'; + $slug = 'sample-isolated-with-license'; // Register the sample plugin as a developer would in their plugin. $resource = Register::plugin( @@ -125,15 +141,10 @@ public function test_it_gets_single_site_fallback_file_license_key_on_main_site( /** * @env multisite */ - public function test_it_gets_single_site_license_key_with_isolated_while_network_activated(): void { + public function test_it_gets_single_site_license_key_while_network_activated(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - $this->single_storage->store( $this->resource, 'local-key' ); $this->network_storage->store( $this->resource, 'network-key' ); $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); @@ -144,15 +155,10 @@ public function test_it_gets_single_site_license_key_with_isolated_while_network /** * @env multisite */ - public function test_it_gets_single_site_license_key_with_isolated_strategy_and_no_multisite_configuration(): void { + public function test_it_gets_single_site_license_key_with_no_multisite_configuration(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); @@ -172,15 +178,10 @@ public function test_it_gets_single_site_license_key_with_isolated_strategy_and_ /** * @env multisite */ - public function test_it_gets_single_site_license_key_with_all_multisite_types_disabled(): void { + public function test_it_gets_single_site_license_key_with_all_multisite_types(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - $sites = [ [ 'domain' => 'wordpress.test', @@ -219,7 +220,7 @@ public function test_it_gets_single_site_license_key_with_all_multisite_types_di /** * @env multisite */ - public function test_it_gets_fallback_file_license_key_with_isolated_strategy_and_no_multisite_configuration(): void { + public function test_it_gets_fallback_file_license_key_with_no_multisite_configuration(): void { $this->assertTrue( is_multisite() ); $slug = 'sample-with-license'; @@ -234,11 +235,6 @@ public function test_it_gets_fallback_file_license_key_with_isolated_strategy_an Sample_Plugin_Helper::class ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); @@ -260,14 +256,10 @@ public function test_it_gets_fallback_file_license_key_with_isolated_strategy_an /** * @env multisite */ - public function test_it_gets_network_license_key_with_isolated_strategy_and_subfolders_configured(): void { + public function test_it_gets_network_license_key_with_subfolders_configured(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); Config::set_network_subfolder_license( true ); // Create a subsite. @@ -288,7 +280,7 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_subf /** * @env multisite */ - public function test_it_gets_fallback_file_license_key_with_isolated_strategy_and_subfolders_configured(): void { + public function test_it_gets_fallback_file_license_key_with_subfolders_configured(): void { $this->assertTrue( is_multisite() ); $slug = 'sample-with-license'; @@ -303,10 +295,6 @@ public function test_it_gets_fallback_file_license_key_with_isolated_strategy_an Sample_Plugin_Helper::class ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); Config::set_network_subfolder_license( true ); // Create a subsite. @@ -330,14 +318,10 @@ public function test_it_gets_fallback_file_license_key_with_isolated_strategy_an /** * @env multisite */ - public function test_it_gets_network_license_key_with_isolated_strategy_and_subdomains_configured(): void { + public function test_it_gets_network_license_key_with_subdomains_configured(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); // Only subdomains of the main site are licensed. Config::set_network_subdomain_license( true ); @@ -359,14 +343,10 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_subd /** * @env multisite */ - public function test_it_gets_network_license_key_with_isolated_strategy_and_domain_mapping_configured(): void { + public function test_it_gets_network_license_key_with_domain_mapping_configured(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); // Only custom subsite domains are licensed. Config::set_network_domain_mapping_license( true ); @@ -388,14 +368,10 @@ public function test_it_gets_network_license_key_with_isolated_strategy_and_doma /** * @env multisite */ - public function test_it_gets_network_license_key_with_all_multisite_types_and_isolated_strategy(): void { + public function test_it_gets_network_license_key_with_all_multisite_types_enabled(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); Config::set_network_subfolder_license( true ); Config::set_network_subdomain_license( true ); Config::set_network_domain_mapping_license( true ); @@ -436,16 +412,14 @@ public function test_it_gets_network_license_key_with_all_multisite_types_and_is } /** + * We allow only subfolder network licensing, but we check the license on a subsite with a custom domain. + * * @env multisite */ - public function test_it_gets_local_license_key_with_isolated_strategy_and_different_network_strategy(): void { + public function test_it_gets_local_license_key_when_from_a_multisite_type_that_is_not_enabled(): void { $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); // Only subfolders are network licensed. Config::set_network_subfolder_license( true ); @@ -465,107 +439,4 @@ public function test_it_gets_local_license_key_with_isolated_strategy_and_differ $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); } - /** - * This is the default strategy and how Uplink originally fetched license keys before this - * change, by first checking the network, then the single site, then the file based Helper - * class. - * - * @env multisite - */ - public function test_it_gets_network_license_key_with_global_license_strategy(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-legacy' ); - - // Network key returned. - $this->assertSame( 'network-key-legacy', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * This is the default strategy and how Uplink originally fetched license keys before this - * change, by first checking the network, then the single site, then the file based Helper - * class. - * - * @env multisite - */ - public function test_it_gets_local_license_key_with_global_license_strategy(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - // No network key stored. - $this->assertEmpty( $this->network_storage->get( $this->resource ) ); - - // Local key returned. - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * This is the default strategy and how Uplink originally fetched license keys before this - * change, by first checking the network, then the single site, then the file based Helper - * class. - * - * @env multisite - */ - public function test_it_gets_file_license_key_with_global_license_strategy(): void { - $this->assertTrue( is_multisite() ); - - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - // No local key stored. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // No network key stored. - $this->assertEmpty( $this->network_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - } diff --git a/tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php similarity index 62% rename from tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php rename to tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php index 979c89aa..0f0b924d 100644 --- a/tests/wpunit/License/LicenseKeySingleSiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php @@ -1,11 +1,12 @@ container->get( License_Manager::class )->disable_cache(); + $this->fetcher = $this->container->get( License_Key_Fetcher::class ); $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); - $this->network_storage = $this->container->get( License_Network_Storage::class ); } - public function test_it_throws_exception_with_invalid_license_key_strategy(): void { + /** + * Data Providers must return something, but we are just using them to switch + * the config for each test. + * + * WARNING: Due to the way data Providers run, ensure "global" or whatever the default is + * in Config::$license_strategy is the last item, otherwise it doesn't get reset back. + * + * @see Config::$license_strategy + * + * @return array + */ + public function configDataProvider(): array { + $isolated = static function (): string { + Config::set_license_key_strategy( License_Strategy::ISOLATED ); + + return License_Strategy::ISOLATED; + }; + + $global = static function (): string { + Config::set_license_key_strategy( License_Strategy::GLOBAL ); + + return License_Strategy::GLOBAL; + }; + + return [ + [ + $isolated(), + ], + [ + $global(), + ], + ]; + } + + /** + * @dataProvider configDataProvider + */ + public function test_it_throws_exception_with_invalid_license_key_strategy( string $config ): void { + // Ensure the data provider is working just once. + $this->assertThat( $config, $this->logicalOr( + $this->equalTo( License_Strategy::ISOLATED ), + $this->equalTo( License_Strategy::GLOBAL ) + ) ); + $this->expectException( RuntimeException::class ); $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); @@ -72,10 +113,16 @@ public function test_it_throws_exception_with_invalid_license_key_strategy(): vo $this->fetcher->get_key( $this->slug ); } + /** + * @dataProvider configDataProvider + */ public function test_it_returns_null_with_unknown_resource(): void { $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); } + /** + * @dataProvider configDataProvider + */ public function test_it_gets_single_site_license_key(): void { $this->assertNull( $this->fetcher->get_key( $this->slug ) ); @@ -84,6 +131,9 @@ public function test_it_gets_single_site_license_key(): void { $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); } + /** + * @dataProvider configDataProvider + */ public function test_it_gets_single_site_fallback_file_license_key(): void { $slug = 'sample-with-license'; From 4a37e11026c6aafe68382ec76dcc33c020b0d4a7 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 11:44:03 -0700 Subject: [PATCH 20/72] Add filter to key fetcher --- src/Uplink/License/License_Key_Fetcher.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Uplink/License/License_Key_Fetcher.php b/src/Uplink/License/License_Key_Fetcher.php index 12bcfa6a..61b035e7 100644 --- a/src/Uplink/License/License_Key_Fetcher.php +++ b/src/Uplink/License/License_Key_Fetcher.php @@ -5,6 +5,8 @@ use StellarWP\Uplink\Config; use StellarWP\Uplink\Resources\Collection; +use StellarWP\Uplink\Resources\Resource; + use function StellarWP\Uplink\get_license_key; final class License_Key_Fetcher { @@ -51,7 +53,17 @@ public function get_key( string $slug ): ?string { return null; } - return $this->factory->make( $resource )->get_key( $resource ); + $key = $this->factory->make( $resource )->get_key( $resource ); + + /** + * Filter the license key. + * + * @since 1.0.0 + * + * @param string|null $key The license key. + * @param Resource $resource The resource associated with the license key. + */ + return apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/license_get_key', $key, $resource ); } } From 0b2ba7a09936d0b2490bf69dac9ef271fafabc5b Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 11:44:30 -0700 Subject: [PATCH 21/72] add get_default_license_key and is_default_license_key functions --- src/Uplink/functions.php | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index d3a86c38..66ef6074 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -14,6 +14,7 @@ use StellarWP\Uplink\Auth\Token\Token_Factory; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\License\License_Key_Fetcher; +use StellarWP\Uplink\License\Storage\License_File_Storage; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; @@ -218,7 +219,8 @@ function validate_license( string $slug, string $license = '' ): ?Validation_Res /** * A multisite license aware way to get a resource's license key automatically - * from the network, local site level or the helper class. + * from the network, local site level or the file helper class which + * respects the configured license key strategy. * * @see Config::set_license_key_strategy() * @@ -232,6 +234,45 @@ function get_license_key( string $slug ): ?string { return get_container()->get( License_Key_Fetcher::class )->get_key( $slug ); } +/** + * Get the embedded license key provided by the plugin's helper class. + * + * @param string $slug The plugin/service slug. + * + * @throws \RuntimeException + * + * @return string|null + */ +function get_default_license_key( string $slug ): ?string { + $resource = get_resource( $slug ); + + if ( ! $resource ) { + return null; + } + + return get_container()->get( License_File_Storage::class )->get( $resource ); +} + +/** + * Check if the current license key is the default key. + * + * @param string $slug The plugin/service slug. + * + * @throws \RuntimeException + * + * @return bool + */ +function is_default_license_key( string $slug ): bool { + $key = get_license_key( $slug ); + $file_key = get_default_license_key( $slug ); + + if ( $key === null && $file_key === null ) { + return false; + } + + return $key === $file_key; +} + /** * A multisite license aware way to set a resource's license key automatically * from the network or local site level. From e98088977d77a2da65cd15151ce9eab0504ecbbb Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 13:45:00 -0700 Subject: [PATCH 22/72] Add get_raw_single_site_license_key and get_raw_network_license_key functions --- src/Uplink/functions.php | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 66ef6074..fe38e618 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -15,6 +15,8 @@ use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Storage\License_File_Storage; +use StellarWP\Uplink\License\Storage\License_Network_Storage; +use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; @@ -234,6 +236,45 @@ function get_license_key( string $slug ): ?string { return get_container()->get( License_Key_Fetcher::class )->get_key( $slug ); } +/** + * Get the raw license key from the network, ignoring any Uplink/multisite configuration. + * + * @param string $slug The plugin/service slug. + * + * @throws \RuntimeException + * + * @return string|null + */ +function get_raw_network_license_key( string $slug ): ?string { + $resource = get_resource( $slug ); + + if ( ! $resource ) { + return null; + } + + return get_container()->get( License_Network_Storage::class )->get( $resource ); +} + +/** + * Get the raw license key from the current single site, ignoring any Uplink/multisite + * configuration. + * + * @param string $slug The plugin/service slug. + * + * @throws \RuntimeException + * + * @return string|null + */ +function get_raw_single_site_license_key( string $slug ): ?string { + $resource = get_resource( $slug ); + + if ( ! $resource ) { + return null; + } + + return get_container()->get( License_Single_Site_Storage::class )->get( $resource ); +} + /** * Get the embedded license key provided by the plugin's helper class. * From df859ed5fb4a4063a16f7dd42e2e7dfe1ef3baa6 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 13:53:34 -0700 Subject: [PATCH 23/72] Add get_license_network_storage and get_license_single_site_storage functions --- src/Uplink/functions.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index fe38e618..581de9f7 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -236,6 +236,32 @@ function get_license_key( string $slug ): ?string { return get_container()->get( License_Key_Fetcher::class )->get_key( $slug ); } +/** + * Get the underlying Network storage object to manipulate license keys directly. + * Prefer get_license_key() were possible, but if you need to manipulate the + * license keys without respecting Uplink Configuration/multisite, use this. + * + * @throws \RuntimeException + * + * @return License_Network_Storage + */ +function get_license_network_storage(): License_Network_Storage { + return get_container()->get( License_Network_Storage::class ); +} + +/** + * Get the underlying Single Site storage object to manipulate license keys directly. + * Prefer get_license_key() were possible, but if you need to manipulate the + * but if you need to manipulate the + * license keys without respecting Uplink Configuration/multisite, use this. + * + * @throws \RuntimeException + * @return License_Single_Site_Storage + */ +function get_license_single_site_storage(): License_Single_Site_Storage { + return get_container()->get( License_Single_Site_Storage::class ); +} + /** * Get the raw license key from the network, ignoring any Uplink/multisite configuration. * @@ -252,7 +278,7 @@ function get_raw_network_license_key( string $slug ): ?string { return null; } - return get_container()->get( License_Network_Storage::class )->get( $resource ); + return get_license_network_storage()->get( $resource ); } /** @@ -272,7 +298,7 @@ function get_raw_single_site_license_key( string $slug ): ?string { return null; } - return get_container()->get( License_Single_Site_Storage::class )->get( $resource ); + return get_license_single_site_storage()->get( $resource ); } /** From bdb44861a0bcf35e914683e398ff5322a53beac7 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 13:58:16 -0700 Subject: [PATCH 24/72] formatting --- src/Uplink/functions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 581de9f7..0f8cb07b 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -256,6 +256,7 @@ function get_license_network_storage(): License_Network_Storage { * license keys without respecting Uplink Configuration/multisite, use this. * * @throws \RuntimeException + * * @return License_Single_Site_Storage */ function get_license_single_site_storage(): License_Single_Site_Storage { From 79024d5d08546faa9f2b90e7041ee09a1fc06594 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 14:17:17 -0700 Subject: [PATCH 25/72] Add delete_license_key function --- src/Uplink/functions.php | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 0f8cb07b..89f95fd6 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -251,9 +251,8 @@ function get_license_network_storage(): License_Network_Storage { /** * Get the underlying Single Site storage object to manipulate license keys directly. - * Prefer get_license_key() were possible, but if you need to manipulate the - * but if you need to manipulate the - * license keys without respecting Uplink Configuration/multisite, use this. + * Prefer get_license_key() were possible, but if you need to manipulate the license + * keys without respecting Uplink Configuration/multisite, use this. * * @throws \RuntimeException * @@ -343,7 +342,7 @@ function is_default_license_key( string $slug ): bool { /** * A multisite license aware way to set a resource's license key automatically - * from the network or local site level. + * from the network or local site level. * * @param string $slug The plugin/service slug. * @param string $license The license key to store. @@ -368,6 +367,28 @@ function set_license_key( string $slug, string $license ): bool { return $result; } +/** + * A multisite license aware way to delete a resource's license key automatically + * from the network or local site level which respects the configured license key strategy. + * + * @param string $slug The plugin/service slug. + * + * @throws \RuntimeException + * + * @return bool + */ +function delete_license_key( string $slug ): bool { + $resource = get_resource( $slug ); + + if ( ! $resource ) { + return false; + } + + $network = allows_multisite_license( $resource ); + + return $network ? get_license_network_storage()->delete( $resource ) : get_license_single_site_storage()->delete( $resource ); +} + /** * Get the current site's license domain without any hash suffix. * From 8f921a7a389fd43834109bd0632c91872eeb2b5f Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 14:35:46 -0700 Subject: [PATCH 26/72] Make storage option name static, move into trait --- .../Storage/License_Network_Storage.php | 20 +++++---------- .../Storage/License_Single_Site_Storage.php | 21 +++++----------- .../Storage/Traits/Option_Name_Trait.php | 25 +++++++++++++++++++ 3 files changed, 37 insertions(+), 29 deletions(-) create mode 100644 src/Uplink/License/Storage/Traits/Option_Name_Trait.php diff --git a/src/Uplink/License/Storage/License_Network_Storage.php b/src/Uplink/License/Storage/License_Network_Storage.php index 41d08f7b..ac5a1a18 100644 --- a/src/Uplink/License/Storage/License_Network_Storage.php +++ b/src/Uplink/License/Storage/License_Network_Storage.php @@ -2,6 +2,7 @@ namespace StellarWP\Uplink\License\Storage; +use StellarWP\Uplink\License\Storage\Traits\Option_Name_Trait; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Utils\Sanitize; @@ -10,6 +11,8 @@ */ final class License_Network_Storage implements Contracts\Storage { + use Option_Name_Trait; + /** * @inheritDoc */ @@ -25,7 +28,7 @@ public function store( Resource $resource, string $license_key ): bool { return true; } - return update_site_option( $this->option_name( $resource ), $license_key ); + return update_site_option( self::option_name( $resource ), $license_key ); } /** @@ -36,7 +39,7 @@ public function get( Resource $resource ): ?string { return null; } - return get_site_option( $this->option_name( $resource ), null ); + return get_site_option( self::option_name( $resource ), null ); } /** @@ -47,18 +50,7 @@ public function delete( Resource $resource ): bool { return false; } - return delete_site_option( $this->option_name( $resource ) ); - } - - /** - * Get the unique option name to save in the network. - * - * @param Resource $resource - * - * @return string - */ - private function option_name( Resource $resource ): string { - return self::KEY_PREFIX . $resource->get_slug(); + return delete_site_option( self::option_name( $resource ) ); } /** diff --git a/src/Uplink/License/Storage/License_Single_Site_Storage.php b/src/Uplink/License/Storage/License_Single_Site_Storage.php index 3690b468..ab2bff55 100644 --- a/src/Uplink/License/Storage/License_Single_Site_Storage.php +++ b/src/Uplink/License/Storage/License_Single_Site_Storage.php @@ -2,6 +2,7 @@ namespace StellarWP\Uplink\License\Storage; +use StellarWP\Uplink\License\Storage\Traits\Option_Name_Trait; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Utils\Sanitize; @@ -10,6 +11,8 @@ */ final class License_Single_Site_Storage implements Contracts\Storage { + use Option_Name_Trait; + /** * @inheritDoc */ @@ -21,33 +24,21 @@ public function store( Resource $resource, string $license_key ): bool { return true; } - return update_option( $this->option_name( $resource ), $license_key ); + return update_option( self::option_name( $resource ), $license_key ); } /** * @inheritDoc */ public function get( Resource $resource ): ?string { - return get_option( $this->option_name( $resource ), null ); + return get_option( self::option_name( $resource ), null ); } /** * @inheritDoc */ public function delete( Resource $resource ): bool { - return delete_option( $this->option_name( $resource ) ); - } - - /** - * Get the unique option name to save in options table for the - * current time. - * - * @param Resource $resource - * - * @return string - */ - private function option_name( Resource $resource ): string { - return self::KEY_PREFIX . $resource->get_slug(); + return delete_option( self::option_name( $resource ) ); } } diff --git a/src/Uplink/License/Storage/Traits/Option_Name_Trait.php b/src/Uplink/License/Storage/Traits/Option_Name_Trait.php new file mode 100644 index 00000000..255f2bbf --- /dev/null +++ b/src/Uplink/License/Storage/Traits/Option_Name_Trait.php @@ -0,0 +1,25 @@ +get_slug(); + } + +} From 750912ea6a88c516de6733b63f791f550a909ac9 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 14:37:19 -0700 Subject: [PATCH 27/72] Use storage option name and get_license_key function for license field --- src/Uplink/Admin/License_Field.php | 36 ++++++++++++------------------ 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/Uplink/Admin/License_Field.php b/src/Uplink/Admin/License_Field.php index 6b8b0d70..8ff6e163 100644 --- a/src/Uplink/Admin/License_Field.php +++ b/src/Uplink/Admin/License_Field.php @@ -2,13 +2,15 @@ namespace StellarWP\Uplink\Admin; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; +use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Resources\Service; use StellarWP\Uplink\Uplink; +use function StellarWP\Uplink\get_license_key; + class License_Field extends Field { public const LICENSE_FIELD_ID = 'stellarwp_uplink_license'; @@ -18,13 +20,6 @@ class License_Field extends Field { */ protected $path = '/admin-views/fields/settings.php'; - /** - * The license manager. - * - * @var License_Manager - */ - private $license_manager; - /** * The script and style handle when registering assets for this field. * @@ -34,14 +29,9 @@ class License_Field extends Field { /** * Constructor. - * - * @param License_Manager $license_manager - * - * @throws \RuntimeException */ - public function __construct( License_Manager $license_manager ) { - $this->license_manager = $license_manager; - $this->handle = sprintf( 'stellarwp-uplink-license-admin-%s', Config::get_hook_prefix() ); + public function __construct() { + $this->handle = sprintf( 'stellarwp-uplink-license-admin-%s', Config::get_hook_prefix() ); } /** @@ -56,10 +46,14 @@ public static function get_section_name( $plugin ) : string { /** * @since 1.0.0 * + * @throws \RuntimeException + * * @return void */ public function register_settings(): void { foreach ( $this->get_resources() as $resource ) { + $id = License_Single_Site_Storage::option_name( $resource ); + add_settings_section( self::get_section_name( $resource ), '', @@ -69,23 +63,21 @@ public function register_settings(): void { register_setting( $this->get_group_name( sanitize_title( $resource->get_slug() ) ), - $resource->get_license_object()->get_key_option_name() + $id ); - $network = $this->license_manager->allows_multisite_license( $resource ); - add_settings_field( - $resource->get_license_object()->get_key_option_name(), + $id, __( 'License Key', '%TEXTDOMAIN%' ), [ $this, 'field_html' ], $this->get_group_name( sanitize_title( $resource->get_slug() ) ), self::get_section_name( $resource ), [ - 'id' => $resource->get_license_object()->get_key_option_name(), - 'label_for' => $resource->get_license_object()->get_key_option_name(), + 'id' => $id, + 'label_for' => $id, 'type' => 'text', 'path' => $resource->get_path(), - 'value' => $resource->get_license_key( $network ? 'network' : 'local' ), + 'value' => get_license_key( $resource->get_slug() ), 'placeholder' => __( 'License Number', '%TEXTDOMAIN%' ), 'html' => $this->get_field_html( $resource ), 'html_classes' => 'stellarwp-uplink-license-key-field', From 0658c2cabfd1585aa1f704bc32f80f80e9131b3a Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 14:38:55 -0700 Subject: [PATCH 28/72] Fix return time for autocompletion --- src/Uplink/API/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/API/Client.php b/src/Uplink/API/Client.php index fe178aa7..1189347f 100644 --- a/src/Uplink/API/Client.php +++ b/src/Uplink/API/Client.php @@ -194,7 +194,7 @@ protected function request( $method, $endpoint, $args ) { * * @throws \RuntimeException * - * @return mixed + * @return Validation_Response|mixed */ public function validate_license( Resource $resource, ?string $key = null, string $validation_type = 'local', bool $force = false ) { /** @var Data */ From eed2773387208da9eeeb755b7e80c738f96d968c Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Tue, 12 Dec 2023 14:45:42 -0700 Subject: [PATCH 29/72] Move License_Manager under License namespace + update providers --- src/Uplink/Admin/Ajax.php | 2 +- src/Uplink/Auth/Admin/Connect_Controller.php | 4 +-- src/Uplink/Auth/Provider.php | 30 ------------------- src/Uplink/Auth/Token/Token_Factory.php | 2 +- .../License/License_Key_Strategy_Factory.php | 2 +- .../Manager}/License_Manager.php | 2 +- .../Processors/Multisite_Domain_Mapping.php | 4 +-- .../Processors/Multisite_Main_Site.php | 2 +- .../Processors/Multisite_Subdomain.php | 4 +-- .../Processors/Multisite_Subfolder.php | 4 +-- .../Pipeline/Traits/Multisite_Trait.php | 2 +- src/Uplink/License/Provider.php | 28 +++++++++++++++++ src/Uplink/Resources/License.php | 2 +- src/Uplink/Uplink.php | 4 +-- src/Uplink/functions.php | 2 +- .../LicenseKeyMultisiteGlobalFetcherTest.php | 2 +- ...LicenseKeyMultisiteIsolatedFetcherTest.php | 2 +- .../LicenseKeySingleSiteFetcherTest.php | 2 +- 18 files changed, 49 insertions(+), 51 deletions(-) rename src/Uplink/{Auth/License => License/Manager}/License_Manager.php (97%) rename src/Uplink/{Auth/License => License/Manager}/Pipeline/Processors/Multisite_Domain_Mapping.php (83%) rename src/Uplink/{Auth/License => License/Manager}/Pipeline/Processors/Multisite_Main_Site.php (90%) rename src/Uplink/{Auth/License => License/Manager}/Pipeline/Processors/Multisite_Subdomain.php (83%) rename src/Uplink/{Auth/License => License/Manager}/Pipeline/Processors/Multisite_Subfolder.php (82%) rename src/Uplink/{Auth/License => License/Manager}/Pipeline/Traits/Multisite_Trait.php (96%) diff --git a/src/Uplink/Admin/Ajax.php b/src/Uplink/Admin/Ajax.php index 8f30ab25..4807e493 100644 --- a/src/Uplink/Admin/Ajax.php +++ b/src/Uplink/Admin/Ajax.php @@ -2,7 +2,7 @@ namespace StellarWP\Uplink\Admin; -use StellarWP\Uplink\Auth\License\License_Manager; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Utils; diff --git a/src/Uplink/Auth/Admin/Connect_Controller.php b/src/Uplink/Auth/Admin/Connect_Controller.php index 4df6bd3d..8b959d95 100644 --- a/src/Uplink/Auth/Admin/Connect_Controller.php +++ b/src/Uplink/Auth/Admin/Connect_Controller.php @@ -3,12 +3,12 @@ namespace StellarWP\Uplink\Auth\Admin; use StellarWP\Uplink\Auth\Authorizer; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Auth\Nonce; use StellarWP\Uplink\Auth\Token\Connector; use StellarWP\Uplink\Auth\Token\Exceptions\InvalidTokenException; -use StellarWP\Uplink\Notice\Notice_Handler; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\Notice\Notice; +use StellarWP\Uplink\Notice\Notice_Handler; use StellarWP\Uplink\Resources\Collection; /** diff --git a/src/Uplink/Auth/Provider.php b/src/Uplink/Auth/Provider.php index d73a0698..a412ee62 100644 --- a/src/Uplink/Auth/Provider.php +++ b/src/Uplink/Auth/Provider.php @@ -4,16 +4,10 @@ use StellarWP\Uplink\Auth\Admin\Connect_Controller; use StellarWP\Uplink\Auth\Admin\Disconnect_Controller; -use StellarWP\Uplink\Auth\License\License_Manager; -use StellarWP\Uplink\Auth\License\Pipeline\Processors\Multisite_Domain_Mapping; -use StellarWP\Uplink\Auth\License\Pipeline\Processors\Multisite_Main_Site; -use StellarWP\Uplink\Auth\License\Pipeline\Processors\Multisite_Subdomain; -use StellarWP\Uplink\Auth\License\Pipeline\Processors\Multisite_Subfolder; use StellarWP\Uplink\Auth\Token\Managers\Network_Token_Manager; use StellarWP\Uplink\Auth\Token\Managers\Token_Manager; use StellarWP\Uplink\Config; use StellarWP\Uplink\Contracts\Abstract_Provider; -use StellarWP\Uplink\Pipeline\Pipeline; final class Provider extends Abstract_Provider { @@ -21,8 +15,6 @@ final class Provider extends Abstract_Provider { * @inheritDoc */ public function register() { - $this->register_license_manager(); - if ( ! $this->container->has( Config::TOKEN_OPTION_NAME ) ) { return; } @@ -46,28 +38,6 @@ static function ( $c ) { $this->register_auth_connect(); } - /** - * Register the license manager and its pipeline to detect different - * multisite licenses. - * - * @return void - */ - private function register_license_manager(): void { - $pipeline = ( new Pipeline( $this->container ) )->through( [ - Multisite_Main_Site::class, - Multisite_Subfolder::class, - Multisite_Subdomain::class, - Multisite_Domain_Mapping::class, - ] ); - - $this->container->singleton( - License_Manager::class, - static function () use ( $pipeline ) { - return new License_Manager( $pipeline ); - } - ); - } - /** * Register nonce container definitions. * diff --git a/src/Uplink/Auth/Token/Token_Factory.php b/src/Uplink/Auth/Token/Token_Factory.php index 4843dc92..030e6da0 100644 --- a/src/Uplink/Auth/Token/Token_Factory.php +++ b/src/Uplink/Auth/Token/Token_Factory.php @@ -3,9 +3,9 @@ namespace StellarWP\Uplink\Auth\Token; use StellarWP\ContainerContract\ContainerInterface; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; use StellarWP\Uplink\Auth\Token\Managers\Network_Token_Manager; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\Resources\Resource; final class Token_Factory { diff --git a/src/Uplink/License/License_Key_Strategy_Factory.php b/src/Uplink/License/License_Key_Strategy_Factory.php index 61dfeb0b..1d47fbe6 100644 --- a/src/Uplink/License/License_Key_Strategy_Factory.php +++ b/src/Uplink/License/License_Key_Strategy_Factory.php @@ -4,10 +4,10 @@ use RuntimeException; use StellarWP\ContainerContract\ContainerInterface; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\Contracts\License_Key_Fetching_Strategy; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Strategies\Global_License_Key_Strategy; use StellarWP\Uplink\License\Strategies\Network_Only_License_Key_Strategy; use StellarWP\Uplink\License\Strategies\Single_Site_License_Key_Strategy; diff --git a/src/Uplink/Auth/License/License_Manager.php b/src/Uplink/License/Manager/License_Manager.php similarity index 97% rename from src/Uplink/Auth/License/License_Manager.php rename to src/Uplink/License/Manager/License_Manager.php index 3a01f414..35aabee5 100644 --- a/src/Uplink/Auth/License/License_Manager.php +++ b/src/Uplink/License/Manager/License_Manager.php @@ -1,6 +1,6 @@ register_license_manager(); $this->register_license_strategies(); } + /** + * Register the license manager and its pipeline to detect different + * multisite licenses. + * + * @return void + */ + private function register_license_manager(): void { + $pipeline = ( new Pipeline( $this->container ) )->through( [ + Multisite_Main_Site::class, + Multisite_Subfolder::class, + Multisite_Subdomain::class, + Multisite_Domain_Mapping::class, + ] ); + + $this->container->singleton( + License_Manager::class, + static function () use ( $pipeline ) { + return new License_Manager( $pipeline ); + } + ); + } + /** * Register all available license key strategies. * diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 475b8d7c..c2a341c8 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -3,8 +3,8 @@ namespace StellarWP\Uplink\Resources; use StellarWP\ContainerContract\ContainerInterface; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\Site\Data; use StellarWP\Uplink\Utils; diff --git a/src/Uplink/Uplink.php b/src/Uplink/Uplink.php index abed5237..76c31085 100644 --- a/src/Uplink/Uplink.php +++ b/src/Uplink/Uplink.php @@ -36,16 +36,16 @@ public static function init(): void { $container->singleton( Site\Data::class, Site\Data::class ); $container->singleton( Notice\Provider::class, Notice\Provider::class ); $container->singleton( Admin\Provider::class, Admin\Provider::class ); - $container->singleton( Auth\Provider::class, Auth\Provider::class ); $container->singleton( License\Provider::class, License\Provider::class ); + $container->singleton( Auth\Provider::class, Auth\Provider::class ); if ( static::is_enabled() ) { $container->get( View\Provider::class )->register(); $container->get( API\V3\Provider::class )->register(); $container->get( Notice\Provider::class )->register(); $container->get( Admin\Provider::class )->register(); - $container->get( Auth\Provider::class )->register(); $container->get( License\Provider::class )->register(); + $container->get( Auth\Provider::class )->register(); } require_once __DIR__ . '/functions.php'; diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 89f95fd6..b38d250d 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -10,10 +10,10 @@ use StellarWP\Uplink\Auth\Admin\Disconnect_Controller; use StellarWP\Uplink\Auth\Auth_Url_Builder; use StellarWP\Uplink\Auth\Authorizer; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Auth\Token\Token_Factory; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\License\License_Key_Fetcher; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Storage\License_File_Storage; use StellarWP\Uplink\License\Storage\License_Network_Storage; use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php index 16ecf2ae..3c54fcbf 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php @@ -2,10 +2,10 @@ namespace StellarWP\Uplink\Tests\License\LicenseKeyFetcher; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Storage\License_Network_Storage; use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; use StellarWP\Uplink\Register; diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php index 26f6d192..3a0fa4ee 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php @@ -3,10 +3,10 @@ namespace StellarWP\Uplink\Tests\License\LicenseKeyFetcher; use RuntimeException; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Storage\License_Network_Storage; use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; use StellarWP\Uplink\Register; diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php index 0f0b924d..4989c47a 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php @@ -3,10 +3,10 @@ namespace StellarWP\Uplink\Tests\License\LicenseKeyFetcher; use RuntimeException; -use StellarWP\Uplink\Auth\License\License_Manager; use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; +use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; use StellarWP\Uplink\Register; use StellarWP\Uplink\Resources\Resource; From 37829099c0aa02201645c7a6057cd4e676e7bbaf Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 14 Dec 2023 10:25:49 -0700 Subject: [PATCH 30/72] Add allow_site_level_override_for_multisite_license config --- src/Uplink/Config.php | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index 56f6be3d..db6a6b26 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -1,4 +1,4 @@ - Date: Thu, 14 Dec 2023 10:57:50 -0700 Subject: [PATCH 31/72] Rename multisite config names/filters --- docs/features.md | 30 +++--- src/Uplink/Config.php | 100 +++++++++--------- .../License/Manager/License_Manager.php | 6 +- .../Processors/Multisite_Domain_Mapping.php | 2 +- .../Processors/Multisite_Main_Site.php | 2 +- .../Processors/Multisite_Subdomain.php | 2 +- .../Processors/Multisite_Subfolder.php | 2 +- src/Uplink/Site/Data.php | 14 +-- src/Uplink/functions.php | 2 +- tests/_support/Helper/UplinkTestCase.php | 12 +-- .../CustomDomainMultisiteTokenMangerTest.php | 2 +- .../SubDomainMultisiteTokenMangerTest.php | 2 +- .../SubfolderMultisiteTokenMangerTest.php | 2 +- tests/wpunit/ConfigTest.php | 18 ++-- .../wpunit/License/LicenseKeyFactoryTest.php | 6 +- ...LicenseKeyMultisiteIsolatedFetcherTest.php | 16 +-- tests/wpunit/Site/DataTest.php | 10 +- 17 files changed, 114 insertions(+), 114 deletions(-) diff --git a/docs/features.md b/docs/features.md index 1f145208..b6d0061d 100644 --- a/docs/features.md +++ b/docs/features.md @@ -99,15 +99,15 @@ multisite network across multiple situations. > 💡 To operate at the network level, your plugin **must be network activated** and the proper configuration options enabled. -| Install Type | Network Activated? | Clause | Uplink Config Option (default is false) | License & Token Storage Location | -|----------------------------|--------------------|--------|-----------------------------------------------------|----------------------------------| -| Standard | – | – | – | Site level | -| Multisite (subfolders) | Yes | AND | `Config::set_network_subfolder_license(true)` | Network level | -| Multisite (subfolders) | No | OR | `Config::set_network_subfolder_license(false)` | Site Level | -| Multisite (subdomains) | Yes | AND | `Config::set_network_subdomain_license(true)` | Network level | -| Multisite (subdomains) | No | OR | `Config::set_network_subdomain_license(false)` | Site Level | -| Multisite (domain mapping) | Yes | AND | `Config::set_network_domain_mapping_license(true)` | Network level | -| Multisite (domain mapping) | No | OR | `Config::set_network_domain_mapping_license(false)` | Site Level | +| Install Type | Network Activated? | Clause | Uplink Config Option (default is false) | License & Token Storage Location | +|----------------------------|--------------------|--------|------------------------------------------------------------------------|----------------------------------| +| Standard | – | – | – | Site level | +| Multisite (subfolders) | Yes | AND | `Config::allow_site_level_licenses_for_subfolder_multisite(true)` | Network level | +| Multisite (subfolders) | No | OR | `Config::allow_site_level_licenses_for_subfolder_multisite(false)` | Site Level | +| Multisite (subdomains) | Yes | AND | `Config::allow_site_level_licenses_for_subdomain_multisite(true)` | Network level | +| Multisite (subdomains) | No | OR | `Config::allow_site_level_licenses_for_subdomain_multisite(false)` | Site Level | +| Multisite (domain mapping) | Yes | AND | `Config::allow_site_level_licenses_for_mapped_domain_multisite(true)` | Network level | +| Multisite (domain mapping) | No | OR | `Config::allow_site_level_licenses_for_mapped_domain_multisite(false)` | Site Level | #### Examples @@ -120,13 +120,13 @@ use StellarWP\Uplink\Uplink; // ...other config above // Allow a single network license for multisite subfolders. -Config::set_network_subfolder_license( true ); +Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Allow a single network license for multisite using subdomains. -Config::set_network_subdomain_license( true ); +Config::allow_site_level_licenses_for_subdomain_multisite( true ); // Allow a single network license for custom domains/mapped domains. -Config::set_network_domain_mapping_license( true ); +Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); Uplink::init(); ``` @@ -142,17 +142,17 @@ add_action( 'init', static function(): void { // Replace with a call to your own plugin's config/option to check whether it should be managed in the network. $network_enabled = true; - add_filter( 'stellarwp/uplink/my-plugin-slug/allows_network_subfolder_license', + add_filter( 'stellarwp/uplink/my-plugin-slug/supports_site_level_licenses_for_subfolder_multisite', static function () use ( $network_enabled ): bool { return $network_enabled; }, 10 ); - add_filter( 'stellarwp/uplink/my-plugin-slug/allows_network_subdomain_license', + add_filter( 'stellarwp/uplink/my-plugin-slug/supports_site_level_licenses_for_subdomain_multisite', static function () use ( $network_enabled ): bool { return $network_enabled; }, 10 ); - add_filter( 'stellarwp/uplink/my-plugin-slug/allows_network_domain_mapping_license', + add_filter( 'stellarwp/uplink/my-plugin-slug/supports_site_level_licenses_for_mapped_domain_multisite', static function () use ( $network_enabled ): bool { return $network_enabled; }, 10 ); diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index db6a6b26..c3625db5 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -37,21 +37,21 @@ class Config { * * @var bool */ - protected static $network_subfolder_license = false; + protected static $supports_site_level_licenses_for_subfolder_multisite = false; /** * Whether your plugin allows multisite subdomain licenses. * * @var bool */ - protected static $network_subdomain_license = false; + protected static $supports_site_level_licenses_for_subdomain_multisite = false; /** * Whether your plugin allows multisite domain mapping licenses. * * @var bool */ - protected static $network_domain_mapping_license = false; + protected static $supports_site_level_licenses_for_mapped_domain_multisite = false; /** * If true, enables a checkbox in the License Field so that you can use a local license key @@ -59,7 +59,7 @@ class Config { * * @var bool */ - protected static $has_site_level_override_for_multisite_license = false; + protected static $supports_site_level_override_for_multisite_license = false; /** * The License Strategy to use: @@ -225,58 +225,58 @@ public static function set_token_auth_prefix( string $prefix ): void { * * @return void */ - public static function set_network_subfolder_license( bool $allowed ): void { - self::$network_subfolder_license = $allowed; + public static function allow_site_level_licenses_for_subfolder_multisite( bool $allowed ): void { + self::$supports_site_level_licenses_for_subfolder_multisite = $allowed; } /** - * Whether your plugin allows multisite network subfolder licenses. + * Allow or disallow multisite subdomain licenses at the network level. * - * @throws RuntimeException + * @param bool $allowed * - * @return bool + * @return void */ - public static function allows_network_subfolder_license(): bool { - return (bool) apply_filters( - 'stellarwp/uplink/' . Config::get_hook_prefix() . '/allows_network_subfolder_license', - self::$network_subfolder_license - ); + public static function allow_site_level_licenses_for_subdomain_multisite( bool $allowed ): void { + self::$supports_site_level_licenses_for_subdomain_multisite = $allowed; } /** - * Allow or disallow multisite subdomain licenses at the network level. + * Allow or disallow multisite domain mapping licenses at the network level. * * @param bool $allowed * * @return void */ - public static function set_network_subdomain_license( bool $allowed ): void { - self::$network_subdomain_license = $allowed; + public static function allow_site_level_licenses_for_mapped_domain_multisite( bool $allowed ): void { + self::$supports_site_level_licenses_for_mapped_domain_multisite = $allowed; } /** - * Whether your plugin allows multisite network subdomain licenses. + * Whether your plugin allows multisite network subfolder licenses. * * @throws RuntimeException * * @return bool */ - public static function allows_network_subdomain_license(): bool { + public static function supports_site_level_licenses_for_subfolder_multisite(): bool { return (bool) apply_filters( - 'stellarwp/uplink/' . Config::get_hook_prefix() . '/allows_network_subdomain_license', - self::$network_subdomain_license + 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_subfolder_multisite', + self::$supports_site_level_licenses_for_subfolder_multisite ); } /** - * Allow or disallow multisite domain mapping licenses at the network level. + * Whether your plugin allows multisite network subdomain licenses. * - * @param bool $allowed + * @throws RuntimeException * - * @return void + * @return bool */ - public static function set_network_domain_mapping_license( bool $allowed ): void { - self::$network_domain_mapping_license = $allowed; + public static function supports_site_level_licenses_for_subdomain_multisite(): bool { + return (bool) apply_filters( + 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_subdomain_multisite', + self::$supports_site_level_licenses_for_subdomain_multisite + ); } /** @@ -286,13 +286,30 @@ public static function set_network_domain_mapping_license( bool $allowed ): void * * @return bool */ - public static function allows_network_domain_mapping_license(): bool { + public static function supports_site_level_licenses_for_mapped_domain_multisite(): bool { return (bool) apply_filters( - 'stellarwp/uplink/' . Config::get_hook_prefix() . '/allows_network_domain_mapping_license', - self::$network_domain_mapping_license + 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_mapped_domain_multisite', + self::$supports_site_level_licenses_for_mapped_domain_multisite ); } + /** + * Check if any of the network licencing options are enabled. + * + * @throws RuntimeException + * + * @return bool + */ + public static function supports_network_licenses(): bool { + $config = [ + self::supports_site_level_licenses_for_subfolder_multisite(), + self::supports_site_level_licenses_for_subdomain_multisite(), + self::supports_site_level_licenses_for_mapped_domain_multisite(), + ]; + + return in_array( true, $config, true ); + } + /** * Enables a checkbox in the License Field so that you can use a local license key in place of * the network key. @@ -302,7 +319,7 @@ public static function allows_network_domain_mapping_license(): bool { * @return void */ public static function allow_site_level_override_for_multisite_license( bool $allowed ): void { - self::$has_site_level_override_for_multisite_license = $allowed; + self::$supports_site_level_override_for_multisite_license = $allowed; } /** @@ -310,30 +327,13 @@ public static function allow_site_level_override_for_multisite_license( bool $al * * @return bool */ - public static function has_site_level_override_for_multisite_license(): bool { + public static function supports_site_level_override_for_multisite_license(): bool { return (bool) apply_filters( - 'stellarwp/uplink/' . Config::get_hook_prefix() . '/has_site_level_override_for_multisite_license', - self::$has_site_level_override_for_multisite_license + 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_override_for_multisite_license', + self::$supports_site_level_override_for_multisite_license ); } - /** - * Check if any of the network license options are enabled. - * - * @throws RuntimeException - * - * @return bool - */ - public static function allows_network_licenses(): bool { - $config = [ - self::allows_network_subfolder_license(), - self::allows_network_subdomain_license(), - self::allows_network_domain_mapping_license(), - ]; - - return in_array( true, $config, true ); - } - /** * Set the current license strategy. * diff --git a/src/Uplink/License/Manager/License_Manager.php b/src/Uplink/License/Manager/License_Manager.php index 35aabee5..c3c6d856 100644 --- a/src/Uplink/License/Manager/License_Manager.php +++ b/src/Uplink/License/Manager/License_Manager.php @@ -42,9 +42,9 @@ public function __construct( Pipeline $pipeline ) { * * Out of the box, sub-sites act independently of the network. * - * @see Config::set_network_subfolder_license() - * @see Config::set_network_subdomain_license() - * @see Config::set_network_domain_mapping_license() + * @see Config::allow_site_level_licenses_for_subfolder_multisite() + * @see Config::allow_site_level_licenses_for_subdomain_multisite() + * @see Config::allow_site_level_licenses_for_mapped_domain_multisite() * * @param Resource $resource The current resource to check against. * diff --git a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Domain_Mapping.php b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Domain_Mapping.php index eff66508..5509f8f0 100644 --- a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Domain_Mapping.php +++ b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Domain_Mapping.php @@ -26,7 +26,7 @@ public function __invoke( bool $is_multisite_license, Closure $next ): bool { try { if ( $this->is_unique_domain() ) { - return Config::allows_network_domain_mapping_license(); + return Config::supports_site_level_licenses_for_mapped_domain_multisite(); } } catch ( Throwable $e ) { return false; diff --git a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Main_Site.php b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Main_Site.php index 04168bb6..21ba67d0 100644 --- a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Main_Site.php +++ b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Main_Site.php @@ -19,7 +19,7 @@ final class Multisite_Main_Site { * @return bool */ public function __invoke( bool $is_multisite_license, Closure $next ): bool { - if ( is_main_site() && Config::allows_network_licenses() ) { + if ( is_main_site() && Config::supports_network_licenses() ) { $is_multisite_license = true; } diff --git a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subdomain.php b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subdomain.php index e6114f76..b8862bcf 100644 --- a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subdomain.php +++ b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subdomain.php @@ -26,7 +26,7 @@ public function __invoke( bool $is_multisite_license, Closure $next ): bool { try { if ( $this->is_subdomain() ) { - return Config::allows_network_subdomain_license(); + return Config::supports_site_level_licenses_for_subdomain_multisite(); } } catch ( Throwable $e ) { return false; diff --git a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subfolder.php b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subfolder.php index d7fda3bb..178270b0 100644 --- a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subfolder.php +++ b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Subfolder.php @@ -24,7 +24,7 @@ public function __invoke( bool $is_multisite_license, Closure $next ): bool { } if ( $this->is_subfolder_install() ) { - return Config::allows_network_subfolder_license(); + return Config::supports_site_level_licenses_for_subfolder_multisite(); } return $next( $is_multisite_license ); diff --git a/src/Uplink/Site/Data.php b/src/Uplink/Site/Data.php index 0a02f68e..1dc357c2 100644 --- a/src/Uplink/Site/Data.php +++ b/src/Uplink/Site/Data.php @@ -106,13 +106,13 @@ public function get_db_version(): string { * @return string */ public function get_domain( bool $original = false ): string { - $cache_key = 'stellarwp_uplink_domain'; - $domain = $this->container->has( $cache_key ) ? $this->container->get( $cache_key ) : null; - $allows_network_subfolder_license = Config::allows_network_subfolder_license(); + $cache_key = 'stellarwp_uplink_domain'; + $domain = $this->container->has( $cache_key ) ? $this->container->get( $cache_key ) : null; + $supports_ms_subfolders = Config::supports_site_level_licenses_for_subfolder_multisite(); if ( is_multisite() ) { // Ensure subsite also contains its path and don't cache. - if ( ! $allows_network_subfolder_license ) { + if ( ! $supports_ms_subfolders ) { $domain = $this->get_domain_multisite_subsite_subfolder(); } elseif ( $domain === null ) { $domain = $this->get_domain_multisite_option(); @@ -126,7 +126,7 @@ public function get_domain( bool $original = false ): string { * This prevents the main site from refreshing the token on the Licensing server * when multisite is off or network licenses aren't enabled. */ - if ( ! $original && Config::allows_network_licenses() ) { + if ( ! $original && Config::supports_network_licenses() ) { $domain .= '/' . hash( 'crc32c', $domain ); } } elseif ( $domain === null ) { @@ -140,9 +140,9 @@ public function get_domain( bool $original = false ): string { * @since 1.0.0 * * @param string $domain Domain. - * @param bool $allows_network_subfolder_license Whether network subfolder licenses are allowed. + * @param bool $supports_ms_subfolders Whether network subfolder licenses are allowed. */ - $domain = apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix(). '/get_domain', $domain, $allows_network_subfolder_license ); + $domain = apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix(). '/get_domain', $domain, $supports_ms_subfolders ); return sanitize_text_field( $domain ); } diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index b38d250d..806aa397 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -178,7 +178,7 @@ function get_resource( string $slug ) { * Compares the Uplink configuration to the current site this function is called on, * e.g. a sub-site to determine if the product supports multisite licenses. * - * Not to be confused with Config::allows_network_licenses(). + * Not to be confused with Config::supports_network_licenses(). * * @param string|Resource|Plugin|Service $slug_or_resource The product/service slug or a Resource object. * diff --git a/tests/_support/Helper/UplinkTestCase.php b/tests/_support/Helper/UplinkTestCase.php index d1f2af99..0b65f102 100644 --- a/tests/_support/Helper/UplinkTestCase.php +++ b/tests/_support/Helper/UplinkTestCase.php @@ -60,9 +60,9 @@ protected function setUp(): void { $this->container = Config::get_container(); - $this->network_subfolder_license = Config::allows_network_subfolder_license(); - $this->network_subdomain_license = Config::allows_network_subdomain_license(); - $this->network_domain_mapping_license = Config::allows_network_domain_mapping_license(); + $this->network_subfolder_license = Config::supports_site_level_licenses_for_subfolder_multisite(); + $this->network_subdomain_license = Config::supports_site_level_licenses_for_subdomain_multisite(); + $this->network_domain_mapping_license = Config::supports_site_level_licenses_for_mapped_domain_multisite(); // Capture default license key strategy. $this->strategy = Config::get_license_key_strategy(); @@ -70,9 +70,9 @@ protected function setUp(): void { protected function tearDown(): void { // Reset back to default config, in case any tests changed them. - Config::set_network_subfolder_license( $this->network_subfolder_license ); - Config::set_network_subdomain_license( $this->network_subdomain_license ); - Config::set_network_domain_mapping_license( $this->network_domain_mapping_license ); + Config::allow_site_level_licenses_for_subfolder_multisite( $this->network_subfolder_license ); + Config::allow_site_level_licenses_for_subdomain_multisite( $this->network_subdomain_license ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( $this->network_domain_mapping_license ); // Reset license key strategy to the default. Config::set_license_key_strategy( $this->strategy ); diff --git a/tests/wpunit/Auth/Token/CustomDomainMultisiteTokenMangerTest.php b/tests/wpunit/Auth/Token/CustomDomainMultisiteTokenMangerTest.php index c0db1dbc..139fcf18 100644 --- a/tests/wpunit/Auth/Token/CustomDomainMultisiteTokenMangerTest.php +++ b/tests/wpunit/Auth/Token/CustomDomainMultisiteTokenMangerTest.php @@ -24,7 +24,7 @@ protected function setUp(): void { parent::setUp(); Config::set_token_auth_prefix( 'kadence_' ); - Config::set_network_domain_mapping_license( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); // Run init again to reload the Token/Provider. Uplink::init(); diff --git a/tests/wpunit/Auth/Token/SubDomainMultisiteTokenMangerTest.php b/tests/wpunit/Auth/Token/SubDomainMultisiteTokenMangerTest.php index 9f7b17f5..1212f650 100644 --- a/tests/wpunit/Auth/Token/SubDomainMultisiteTokenMangerTest.php +++ b/tests/wpunit/Auth/Token/SubDomainMultisiteTokenMangerTest.php @@ -24,7 +24,7 @@ protected function setUp(): void { parent::setUp(); Config::set_token_auth_prefix( 'kadence_' ); - Config::set_network_subdomain_license( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); // Run init again to reload the Token/Provider. Uplink::init(); diff --git a/tests/wpunit/Auth/Token/SubfolderMultisiteTokenMangerTest.php b/tests/wpunit/Auth/Token/SubfolderMultisiteTokenMangerTest.php index 2e8878b2..db3f6459 100644 --- a/tests/wpunit/Auth/Token/SubfolderMultisiteTokenMangerTest.php +++ b/tests/wpunit/Auth/Token/SubfolderMultisiteTokenMangerTest.php @@ -24,7 +24,7 @@ protected function setUp(): void { parent::setUp(); Config::set_token_auth_prefix( 'kadence_' ); - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Run init again to reload the Token/Provider. Uplink::init(); diff --git a/tests/wpunit/ConfigTest.php b/tests/wpunit/ConfigTest.php index 7654870d..b228a4cd 100644 --- a/tests/wpunit/ConfigTest.php +++ b/tests/wpunit/ConfigTest.php @@ -55,21 +55,21 @@ public function test_it_throws_exception_with_long_prefix(): void { } public function test_it_detects_allowed_network_licenses_subfolder(): void { - $this->assertFalse( Config::allows_network_licenses() ); - Config::set_network_subfolder_license( true ); - $this->assertTrue( Config::allows_network_licenses() ); + $this->assertFalse( Config::supports_network_licenses() ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + $this->assertTrue( Config::supports_network_licenses() ); } public function test_it_detects_allowed_network_licenses_subdomain(): void { - $this->assertFalse( Config::allows_network_licenses() ); - Config::set_network_subdomain_license( true ); - $this->assertTrue( Config::allows_network_licenses() ); + $this->assertFalse( Config::supports_network_licenses() ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); + $this->assertTrue( Config::supports_network_licenses() ); } public function test_it_detects_allowed_network_licenses_domain_mapping(): void { - $this->assertFalse( Config::allows_network_licenses() ); - Config::set_network_domain_mapping_license( true ); - $this->assertTrue( Config::allows_network_licenses() ); + $this->assertFalse( Config::supports_network_licenses() ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); + $this->assertTrue( Config::supports_network_licenses() ); } } diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php index ed9d636f..ee68d99c 100644 --- a/tests/wpunit/License/LicenseKeyFactoryTest.php +++ b/tests/wpunit/License/LicenseKeyFactoryTest.php @@ -101,7 +101,7 @@ public function test_it_gets_network_license_key_strategy_with_subfolders_config $this->mock_activate_plugin( 'uplink/index.php', true ); Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); @@ -126,7 +126,7 @@ public function test_it_gets_network_license_key_strategy_with_subdomains_config $this->mock_activate_plugin( 'uplink/index.php', true ); Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::set_network_subdomain_license( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); @@ -151,7 +151,7 @@ public function test_it_gets_network_license_key_strategy_with_domain_mapping_co $this->mock_activate_plugin( 'uplink/index.php', true ); Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::set_network_domain_mapping_license( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php index 3a0fa4ee..b24e09b6 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php @@ -260,7 +260,7 @@ public function test_it_gets_network_license_key_with_subfolders_configured(): v $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); @@ -295,7 +295,7 @@ public function test_it_gets_fallback_file_license_key_with_subfolders_configure Sample_Plugin_Helper::class ); - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); @@ -323,7 +323,7 @@ public function test_it_gets_network_license_key_with_subdomains_configured(): v $this->assertNull( $this->fetcher->get_key( $this->slug ) ); // Only subdomains of the main site are licensed. - Config::set_network_subdomain_license( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); @@ -348,7 +348,7 @@ public function test_it_gets_network_license_key_with_domain_mapping_configured( $this->assertNull( $this->fetcher->get_key( $this->slug ) ); // Only custom subsite domains are licensed. - Config::set_network_domain_mapping_license( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); // Create a subsite. $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); @@ -372,9 +372,9 @@ public function test_it_gets_network_license_key_with_all_multisite_types_enable $this->assertTrue( is_multisite() ); $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - Config::set_network_subfolder_license( true ); - Config::set_network_subdomain_license( true ); - Config::set_network_domain_mapping_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); $sites = [ [ @@ -421,7 +421,7 @@ public function test_it_gets_local_license_key_when_from_a_multisite_type_that_i $this->assertNull( $this->fetcher->get_key( $this->slug ) ); // Only subfolders are network licensed. - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); // Create a subsite with a custom domain. $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); diff --git a/tests/wpunit/Site/DataTest.php b/tests/wpunit/Site/DataTest.php index 3a38ec3f..ea8c12a5 100644 --- a/tests/wpunit/Site/DataTest.php +++ b/tests/wpunit/Site/DataTest.php @@ -75,10 +75,10 @@ public function test_it_gets_single_site_domain(): void { } /** - * If Config::allows_network_subfolder_license() is not enabled, subsites in subfolder + * If Config::supports_site_level_licenses_for_subfolder_multisite() is not enabled, subsites in subfolder * mode must be unique, so include their subfolder path in the domain. * - * @see Config::allows_network_subfolder_license() + * @see Config::supports_site_level_licenses_for_subfolder_multisite() * * @env multisite */ @@ -116,7 +116,7 @@ public function test_it_should_get_multisite_subsite_domain_with_path(): void { * @env multisite */ public function test_it_returns_main_site_url_when_network_subfolders_are_allowed(): void { - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); Uplink\Uplink::init(); $this->assertTrue( is_multisite() ); @@ -172,7 +172,7 @@ public function test_it_gets_domain_with_custom_subsite_domain(): void { * @env multisite */ public function test_it_gets_main_domain_with_custom_subsite_domain_and_network_subfolders_enabled(): void { - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); Uplink\Uplink::init(); $this->assertTrue( is_multisite() ); @@ -217,7 +217,7 @@ public function test_it_gets_domain_with_subdomain(): void { * @env multisite */ public function test_it_gets_main_domain_with_subdomain_and_network_subfolders_enabled(): void { - Config::set_network_subfolder_license( true ); + Config::allow_site_level_licenses_for_subfolder_multisite( true ); Uplink\Uplink::init(); $this->assertTrue( is_multisite() ); From e1df461d82b9c7cc4680ade840bb2eda649af5f9 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 14 Dec 2023 13:55:31 -0700 Subject: [PATCH 32/72] Add checkbox and description components and render_component function --- .../Settings/Description_Controller.php | 34 +++++++++++++ .../Settings/Fields/Checkbox_Controller.php | 51 +++++++++++++++++++ src/Uplink/functions.php | 18 +++++++ src/views/settings/description.php | 9 ++++ src/views/settings/fields/checkbox.php | 33 ++++++++++++ src/views/settings/fields/index.php | 1 + src/views/settings/index.php | 1 + 7 files changed, 147 insertions(+) create mode 100644 src/Uplink/Components/Settings/Description_Controller.php create mode 100644 src/Uplink/Components/Settings/Fields/Checkbox_Controller.php create mode 100644 src/views/settings/description.php create mode 100644 src/views/settings/fields/checkbox.php create mode 100644 src/views/settings/fields/index.php create mode 100644 src/views/settings/index.php diff --git a/src/Uplink/Components/Settings/Description_Controller.php b/src/Uplink/Components/Settings/Description_Controller.php new file mode 100644 index 00000000..1884e0a8 --- /dev/null +++ b/src/Uplink/Components/Settings/Description_Controller.php @@ -0,0 +1,34 @@ +view->render( self::VIEW, [ + 'description' => $description, + ] ); + } + +} diff --git a/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php new file mode 100644 index 00000000..3bb1a9ac --- /dev/null +++ b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php @@ -0,0 +1,51 @@ +view->render( self::VIEW, [ + 'id' => $id, + 'label' => $label, + 'description' => $description, + 'value' => $this->get_value( $id, $default ), + ] ); + } + + /** + * Get the value from the options table. This should automatically be stored by + * WordPress via register_setting(). + * + * @see register_setting() + * + * @param string $id The ID that matches the $option_name in register_setting(). + * @param bool $default The default value if never saved before. + * + * @return bool + */ + private function get_value( string $id, bool $default ): bool { + return (bool) get_option( $id, $default ); + } + +} diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 806aa397..f277ea65 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -12,6 +12,7 @@ use StellarWP\Uplink\Auth\Authorizer; use StellarWP\Uplink\Auth\Token\Token_Factory; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; +use StellarWP\Uplink\Components\Controller; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Manager\License_Manager; use StellarWP\Uplink\License\Storage\License_File_Storage; @@ -446,3 +447,20 @@ function get_license_field(): License_Field { function get_auth_url( string $slug ): string { return get_container()->get( Auth_Url::class )->get( $slug ); } + +/** + * Renders a component. + * + * @param class-string|string $controller The controller's class name. + * @param array $args The arguments to pass to the controller's render method. + * + * @throws \RuntimeException + * + * @return void + */ +function render_component( string $controller, array $args ): void { + /** @var Controller $component */ + $component = get_container()->get( $controller ); + + $component->render( $args ); +} diff --git a/src/views/settings/description.php b/src/views/settings/description.php new file mode 100644 index 00000000..8cf70519 --- /dev/null +++ b/src/views/settings/description.php @@ -0,0 +1,9 @@ + +

diff --git a/src/views/settings/fields/checkbox.php b/src/views/settings/fields/checkbox.php new file mode 100644 index 00000000..72714424 --- /dev/null +++ b/src/views/settings/fields/checkbox.php @@ -0,0 +1,33 @@ + +
+ + + + +
diff --git a/src/views/settings/fields/index.php b/src/views/settings/fields/index.php new file mode 100644 index 00000000..9170000d --- /dev/null +++ b/src/views/settings/fields/index.php @@ -0,0 +1 @@ + Date: Thu, 14 Dec 2023 14:48:32 -0700 Subject: [PATCH 33/72] Add data attributes and classes to checkbox --- src/Uplink/Components/Controller.php | 25 +++++++++++++++++++ .../Settings/Fields/Checkbox_Controller.php | 5 +++- src/views/settings/fields/checkbox.php | 4 ++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Uplink/Components/Controller.php b/src/Uplink/Components/Controller.php index e5538e05..bd7bd839 100644 --- a/src/Uplink/Components/Controller.php +++ b/src/Uplink/Components/Controller.php @@ -48,4 +48,29 @@ protected function classes( array $classes ): string { return implode( ' ', $classes ); } + /** + * Format data attributes, escaped and ready for output in the view. + * + * @param array $attributes An array of attributes indexed by their name. + * + * @return string + */ + protected function data_attr( array $attributes ): string { + if ( ! $attributes ) { + return ''; + } + + $formatted = []; + + foreach ( $attributes as $name => $value ) { + $formatted[] = sprintf( + 'data-%s="%s"', + esc_html( sanitize_html_class( $name ) ), + esc_attr( $value ) + ); + } + + return implode( ' ', $formatted ); + } + } diff --git a/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php index 3bb1a9ac..94d4f659 100644 --- a/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php +++ b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php @@ -15,7 +15,7 @@ final class Checkbox_Controller extends Controller { /** * Render a WordPress settings checkbox field. * - * @param array{id?: string, label?: string, description?: string, default?: bool} $args + * @param array{id?: string, label?: string, description?: string, default?: bool, data_attr?: array, classes?: string[]} $args * * @throws FileNotFoundException */ @@ -24,11 +24,14 @@ public function render( array $args = [] ): void { $label = $args['label'] ?? ''; $description = $args['description'] ?? ''; $default = $args['default'] ?? false; + $classes = $args['classes'] ?? [ $id ]; echo $this->view->render( self::VIEW, [ 'id' => $id, 'label' => $label, 'description' => $description, + 'data_attr' => $this->data_attr( $args['data_attr'] ?? [] ), + 'classes' => $this->classes( $classes ), 'value' => $this->get_value( $id, $default ), ] ); } diff --git a/src/views/settings/fields/checkbox.php b/src/views/settings/fields/checkbox.php index 72714424..8bb2243f 100644 --- a/src/views/settings/fields/checkbox.php +++ b/src/views/settings/fields/checkbox.php @@ -4,6 +4,8 @@ * @var string $id The unique field ID. * @var string $label The label to display. * @var string $description The description to display. + * @var string $data_attr Escaped and formatted data attributes. + * @var string $classes The CSS classes added to the fieldset. * @var bool $value The current value. */ defined( 'ABSPATH' ) || exit; @@ -13,7 +15,7 @@ use function StellarWP\Uplink\render_component; ?> -
+
> From c9722c80790d0b6a3b9bb8856552b84fa71bf55b Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Fri, 15 Dec 2023 10:36:51 -0700 Subject: [PATCH 34/72] Add Get_Value_Trait, make the checkbox value fetching network aware. Remove final --- .../Settings/Fields/Checkbox_Controller.php | 20 ++++--------------- .../Settings/Traits/Get_Value_Trait.php | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 src/Uplink/Components/Settings/Traits/Get_Value_Trait.php diff --git a/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php index 94d4f659..0dc2d695 100644 --- a/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php +++ b/src/Uplink/Components/Settings/Fields/Checkbox_Controller.php @@ -3,9 +3,12 @@ namespace StellarWP\Uplink\Components\Settings\Fields; use StellarWP\Uplink\Components\Controller; +use StellarWP\Uplink\Components\Settings\Traits\Get_Value_Trait; use StellarWP\Uplink\View\Exceptions\FileNotFoundException; -final class Checkbox_Controller extends Controller { +class Checkbox_Controller extends Controller { + + use Get_Value_Trait; /** * The view file, without ext, relative to the root views directory. @@ -36,19 +39,4 @@ public function render( array $args = [] ): void { ] ); } - /** - * Get the value from the options table. This should automatically be stored by - * WordPress via register_setting(). - * - * @see register_setting() - * - * @param string $id The ID that matches the $option_name in register_setting(). - * @param bool $default The default value if never saved before. - * - * @return bool - */ - private function get_value( string $id, bool $default ): bool { - return (bool) get_option( $id, $default ); - } - } diff --git a/src/Uplink/Components/Settings/Traits/Get_Value_Trait.php b/src/Uplink/Components/Settings/Traits/Get_Value_Trait.php new file mode 100644 index 00000000..342bf07a --- /dev/null +++ b/src/Uplink/Components/Settings/Traits/Get_Value_Trait.php @@ -0,0 +1,20 @@ + Date: Wed, 20 Dec 2023 13:52:38 -0700 Subject: [PATCH 35/72] First phase of storage refactor --- src/Uplink/Admin/License_Field.php | 4 +- ...ense_File_Storage.php => File_Storage.php} | 2 +- ...gle_Site_Storage.php => Local_Storage.php} | 2 +- ...etwork_Storage.php => Network_Storage.php} | 2 +- .../License/Storage/Storage_Factory.php | 40 ++++++++++ .../License/Storage/Storage_Handler.php | 79 +++++++++++++++++++ .../Strategies/Pipeline/Processors/File.php | 8 +- .../Pipeline/Processors/Network.php | 8 +- .../Strategies/Pipeline/Processors/Single.php | 8 +- src/Uplink/Resources/Resource.php | 19 +++++ src/Uplink/functions.php | 20 ++--- .../LicenseKeyMultisiteGlobalFetcherTest.php | 12 +-- ...LicenseKeyMultisiteIsolatedFetcherTest.php | 12 +-- .../LicenseKeySingleSiteFetcherTest.php | 6 +- 14 files changed, 180 insertions(+), 42 deletions(-) rename src/Uplink/License/Storage/{License_File_Storage.php => File_Storage.php} (94%) rename src/Uplink/License/Storage/{License_Single_Site_Storage.php => Local_Storage.php} (93%) rename src/Uplink/License/Storage/{License_Network_Storage.php => Network_Storage.php} (95%) create mode 100644 src/Uplink/License/Storage/Storage_Factory.php create mode 100644 src/Uplink/License/Storage/Storage_Handler.php diff --git a/src/Uplink/Admin/License_Field.php b/src/Uplink/Admin/License_Field.php index 8ff6e163..1f4a1ed2 100644 --- a/src/Uplink/Admin/License_Field.php +++ b/src/Uplink/Admin/License_Field.php @@ -3,7 +3,7 @@ namespace StellarWP\Uplink\Admin; use StellarWP\Uplink\Config; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Resources\Service; @@ -52,7 +52,7 @@ public static function get_section_name( $plugin ) : string { */ public function register_settings(): void { foreach ( $this->get_resources() as $resource ) { - $id = License_Single_Site_Storage::option_name( $resource ); + $id = Local_Storage::option_name( $resource ); add_settings_section( self::get_section_name( $resource ), diff --git a/src/Uplink/License/Storage/License_File_Storage.php b/src/Uplink/License/Storage/File_Storage.php similarity index 94% rename from src/Uplink/License/Storage/License_File_Storage.php rename to src/Uplink/License/Storage/File_Storage.php index dd83de65..9de1a3e7 100644 --- a/src/Uplink/License/Storage/License_File_Storage.php +++ b/src/Uplink/License/Storage/File_Storage.php @@ -9,7 +9,7 @@ * Manages licenses when included inside the plugin, via the * defined helper class. */ -final class License_File_Storage implements Contracts\Storage { +final class File_Storage implements Contracts\Storage { /** * @inheritDoc diff --git a/src/Uplink/License/Storage/License_Single_Site_Storage.php b/src/Uplink/License/Storage/Local_Storage.php similarity index 93% rename from src/Uplink/License/Storage/License_Single_Site_Storage.php rename to src/Uplink/License/Storage/Local_Storage.php index ab2bff55..3f871e9d 100644 --- a/src/Uplink/License/Storage/License_Single_Site_Storage.php +++ b/src/Uplink/License/Storage/Local_Storage.php @@ -9,7 +9,7 @@ /** * Manages license keys for the current site. */ -final class License_Single_Site_Storage implements Contracts\Storage { +final class Local_Storage implements Contracts\Storage { use Option_Name_Trait; diff --git a/src/Uplink/License/Storage/License_Network_Storage.php b/src/Uplink/License/Storage/Network_Storage.php similarity index 95% rename from src/Uplink/License/Storage/License_Network_Storage.php rename to src/Uplink/License/Storage/Network_Storage.php index ac5a1a18..f2bc4c13 100644 --- a/src/Uplink/License/Storage/License_Network_Storage.php +++ b/src/Uplink/License/Storage/Network_Storage.php @@ -9,7 +9,7 @@ /** * Manages license keys in a WordPress network. */ -final class License_Network_Storage implements Contracts\Storage { +final class Network_Storage implements Contracts\Storage { use Option_Name_Trait; diff --git a/src/Uplink/License/Storage/Storage_Factory.php b/src/Uplink/License/Storage/Storage_Factory.php new file mode 100644 index 00000000..86300643 --- /dev/null +++ b/src/Uplink/License/Storage/Storage_Factory.php @@ -0,0 +1,40 @@ +container = $container; + } + + /** + * Make a storage instance that either stores in site_options or the local options tables. + * + * @param Resource $resource + * + * @return Storage + */ + public function make( Resource $resource ): Storage { + $class = $resource->uses_network_licensing() ? Network_Storage::class : Local_Storage::class; + + return $this->container->get( $class ); + } + +} diff --git a/src/Uplink/License/Storage/Storage_Handler.php b/src/Uplink/License/Storage/Storage_Handler.php new file mode 100644 index 00000000..000adf08 --- /dev/null +++ b/src/Uplink/License/Storage/Storage_Handler.php @@ -0,0 +1,79 @@ +factory = $factory; + $this->file = $file; + } + + /** + * Store a license key in either site_options or the site's options table. + * + * @param Resource $resource + * @param string $license_key + * + * @return bool + */ + public function store( Resource $resource, string $license_key ): bool { + return $this->factory->make( $resource )->store( $resource, $license_key ); + } + + /** + * Get a license key from either site_options or the site's options table. + * + * @param Resource $resource + * + * @return string|null + */ + public function get( Resource $resource ): ?string { + $license_key = $this->factory->make( $resource )->get( $resource ); + + // Fallback to the original file based storage key. + if ( ! $license_key ) { + $license_key = $this->file->get( $resource ); + } + + return $license_key; + } + + /** + * Delete a license key from either site_options or the site's options table. + * + * @param Resource $resource + * + * @return bool + */ + public function delete( Resource $resource ): bool { + return $this->factory->make( $resource )->delete( $resource ); + } + +} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/File.php b/src/Uplink/License/Strategies/Pipeline/Processors/File.php index 3c1ee798..6f045fb9 100644 --- a/src/Uplink/License/Strategies/Pipeline/Processors/File.php +++ b/src/Uplink/License/Strategies/Pipeline/Processors/File.php @@ -3,20 +3,20 @@ namespace StellarWP\Uplink\License\Strategies\Pipeline\Processors; use Closure; -use StellarWP\Uplink\License\Storage\License_File_Storage; +use StellarWP\Uplink\License\Storage\File_Storage; use StellarWP\Uplink\License\Strategies\Pipeline\License_Traveler; final class File { /** - * @var License_File_Storage + * @var File_Storage */ private $storage; /** - * @param License_File_Storage $storage + * @param File_Storage $storage */ - public function __construct( License_File_Storage $storage ) { + public function __construct( File_Storage $storage ) { $this->storage = $storage; } diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Network.php b/src/Uplink/License/Strategies/Pipeline/Processors/Network.php index f50e8e24..524ebc51 100644 --- a/src/Uplink/License/Strategies/Pipeline/Processors/Network.php +++ b/src/Uplink/License/Strategies/Pipeline/Processors/Network.php @@ -3,20 +3,20 @@ namespace StellarWP\Uplink\License\Strategies\Pipeline\Processors; use Closure; -use StellarWP\Uplink\License\Storage\License_Network_Storage; +use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Strategies\Pipeline\License_Traveler; final class Network { /** - * @var License_Network_Storage + * @var Network_Storage */ private $storage; /** - * @param License_Network_Storage $storage + * @param Network_Storage $storage */ - public function __construct( License_Network_Storage $storage ) { + public function __construct( Network_Storage $storage ) { $this->storage = $storage; } diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Single.php b/src/Uplink/License/Strategies/Pipeline/Processors/Single.php index 706b986e..21cfcd1e 100644 --- a/src/Uplink/License/Strategies/Pipeline/Processors/Single.php +++ b/src/Uplink/License/Strategies/Pipeline/Processors/Single.php @@ -3,20 +3,20 @@ namespace StellarWP\Uplink\License\Strategies\Pipeline\Processors; use Closure; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\License\Strategies\Pipeline\License_Traveler; final class Single { /** - * @var License_Single_Site_Storage + * @var Local_Storage */ private $storage; /** - * @param License_Single_Site_Storage $storage + * @param Local_Storage $storage */ - public function __construct( License_Single_Site_Storage $storage ) { + public function __construct( Local_Storage $storage ) { $this->storage = $storage; } diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index b3289fda..3f951dbb 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -113,6 +113,14 @@ abstract class Resource { */ protected $home_url; + /** + * Whether the current site and configuration is using network + * licensing. + * + * @var bool + */ + protected $uses_network_licensing; + /** * Constructor. * @@ -133,6 +141,17 @@ public function __construct( $slug, $name, $version, $path, $class, string $lice $this->license_class = $license_class; $this->version = $version; $this->container = Config::get_container(); + // TODO: finish implementing this once refactor is complete. + $this->uses_network_licensing = false; + } + + /** + * @TODO finish implementing this once refactor is complete. + * + * @return bool + */ + public function uses_network_licensing(): bool { + return $this->uses_network_licensing; } /** diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index f277ea65..5c75e337 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -15,9 +15,9 @@ use StellarWP\Uplink\Components\Controller; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Manager\License_Manager; -use StellarWP\Uplink\License\Storage\License_File_Storage; -use StellarWP\Uplink\License\Storage\License_Network_Storage; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\File_Storage; +use StellarWP\Uplink\License\Storage\Network_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Resources\Plugin; use StellarWP\Uplink\Resources\Resource; @@ -244,10 +244,10 @@ function get_license_key( string $slug ): ?string { * * @throws \RuntimeException * - * @return License_Network_Storage + * @return Network_Storage */ -function get_license_network_storage(): License_Network_Storage { - return get_container()->get( License_Network_Storage::class ); +function get_license_network_storage(): Network_Storage { + return get_container()->get( Network_Storage::class ); } /** @@ -257,10 +257,10 @@ function get_license_network_storage(): License_Network_Storage { * * @throws \RuntimeException * - * @return License_Single_Site_Storage + * @return Local_Storage */ -function get_license_single_site_storage(): License_Single_Site_Storage { - return get_container()->get( License_Single_Site_Storage::class ); +function get_license_single_site_storage(): Local_Storage { + return get_container()->get( Local_Storage::class ); } /** @@ -318,7 +318,7 @@ function get_default_license_key( string $slug ): ?string { return null; } - return get_container()->get( License_File_Storage::class )->get( $resource ); + return get_container()->get( File_Storage::class )->get( $resource ); } /** diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php index 3c54fcbf..f49f7e43 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php @@ -6,8 +6,8 @@ use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Manager\License_Manager; -use StellarWP\Uplink\License\Storage\License_Network_Storage; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\Network_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Tests\Sample_Plugin; @@ -42,14 +42,14 @@ final class LicenseKeyMultisiteGlobalFetcherTest extends UplinkTestCase { /** * Directly access single site license storage. * - * @var License_Single_Site_Storage + * @var Local_Storage */ private $single_storage; /** * Directly access network license storage. * - * @var License_Network_Storage + * @var Network_Storage */ private $network_storage; @@ -74,8 +74,8 @@ protected function setUp(): void { $this->container->get( License_Manager::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); - $this->network_storage = $this->container->get( License_Network_Storage::class ); + $this->single_storage = $this->container->get( Local_Storage::class ); + $this->network_storage = $this->container->get( Network_Storage::class ); } /** diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php index b24e09b6..97c859a2 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php @@ -7,8 +7,8 @@ use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Manager\License_Manager; -use StellarWP\Uplink\License\Storage\License_Network_Storage; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\Network_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Tests\Sample_Plugin; @@ -45,14 +45,14 @@ final class LicenseKeyMultisiteIsolatedFetcherTest extends UplinkTestCase { /** * Directly access single site license storage. * - * @var License_Single_Site_Storage + * @var Local_Storage */ private $single_storage; /** * Directly access network license storage. * - * @var License_Network_Storage + * @var Network_Storage */ private $network_storage; @@ -77,8 +77,8 @@ protected function setUp(): void { $this->container->get( License_Manager::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); - $this->network_storage = $this->container->get( License_Network_Storage::class ); + $this->single_storage = $this->container->get( Local_Storage::class ); + $this->network_storage = $this->container->get( Network_Storage::class ); } /** diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php index 4989c47a..9f54b847 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php @@ -7,7 +7,7 @@ use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Manager\License_Manager; -use StellarWP\Uplink\License\Storage\License_Single_Site_Storage; +use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; use StellarWP\Uplink\Resources\Resource; use StellarWP\Uplink\Tests\Sample_Plugin; @@ -39,7 +39,7 @@ final class LicenseKeySingleSiteFetcherTest extends UplinkTestCase { /** * Directly access single site license storage. * - * @var License_Single_Site_Storage + * @var Local_Storage */ private $single_storage; @@ -58,7 +58,7 @@ protected function setUp(): void { $this->container->get( License_Manager::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( License_Single_Site_Storage::class ); + $this->single_storage = $this->container->get( Local_Storage::class ); } /** From f743b0e0f7451e84710257c99dace1f4867bc9e6 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 13:55:48 -0700 Subject: [PATCH 36/72] Rename to License_Handler, improve method names and comments --- src/Uplink/Admin/Ajax.php | 10 +++++----- src/Uplink/Auth/Admin/Connect_Controller.php | 8 ++++---- src/Uplink/Auth/Token/Token_Factory.php | 10 +++++----- .../License/License_Key_Strategy_Factory.php | 10 +++++----- .../{License_Manager.php => License_Handler.php} | 15 +++++++-------- src/Uplink/License/Provider.php | 6 +++--- src/Uplink/Resources/License.php | 6 +++--- src/Uplink/functions.php | 4 ++-- .../LicenseKeyMultisiteGlobalFetcherTest.php | 4 ++-- .../LicenseKeyMultisiteIsolatedFetcherTest.php | 4 ++-- .../LicenseKeySingleSiteFetcherTest.php | 4 ++-- 11 files changed, 40 insertions(+), 41 deletions(-) rename src/Uplink/License/Manager/{License_Manager.php => License_Handler.php} (83%) diff --git a/src/Uplink/Admin/Ajax.php b/src/Uplink/Admin/Ajax.php index 4807e493..a1d5d4d6 100644 --- a/src/Uplink/Admin/Ajax.php +++ b/src/Uplink/Admin/Ajax.php @@ -2,7 +2,7 @@ namespace StellarWP\Uplink\Admin; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Utils; @@ -19,7 +19,7 @@ class Ajax { protected $field; /** - * @var License_Manager + * @var License_Handler */ protected $license_manager; @@ -28,12 +28,12 @@ class Ajax { * * @param Collection $resources The plugin/services collection. * @param License_Field $field The license field. - * @param License_Manager $license_manager The license manager. + * @param License_Handler $license_manager The license manager. */ public function __construct( Collection $resources, License_Field $field, - License_Manager $license_manager + License_Handler $license_manager ) { $this->resources = $resources; $this->field = $field; @@ -70,7 +70,7 @@ public function validate_license(): void { ] ); } - $network_validate = $this->license_manager->allows_multisite_license( $plugin ); + $network_validate = $this->license_manager->current_site_allows_network_licensing( $plugin ); $results = $plugin->validate_license( $submission['key'], $network_validate ); $message = $network_validate ? $results->get_network_message()->get() : $results->get_message()->get(); diff --git a/src/Uplink/Auth/Admin/Connect_Controller.php b/src/Uplink/Auth/Admin/Connect_Controller.php index 8b959d95..5094aa83 100644 --- a/src/Uplink/Auth/Admin/Connect_Controller.php +++ b/src/Uplink/Auth/Admin/Connect_Controller.php @@ -6,7 +6,7 @@ use StellarWP\Uplink\Auth\Nonce; use StellarWP\Uplink\Auth\Token\Connector; use StellarWP\Uplink\Auth\Token\Exceptions\InvalidTokenException; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Notice\Notice; use StellarWP\Uplink\Notice\Notice_Handler; use StellarWP\Uplink\Resources\Collection; @@ -38,7 +38,7 @@ final class Connect_Controller { private $collection; /** - * @var License_Manager + * @var License_Handler */ private $license_manager; @@ -51,7 +51,7 @@ public function __construct( Connector $connector, Notice_Handler $notice, Collection $collection, - License_Manager $license_manager, + License_Handler $license_manager, Authorizer $authorizer ) { $this->connector = $connector; @@ -136,7 +136,7 @@ public function maybe_store_token_data(): void { // Store or override an existing license. if ( $license ) { - $network = $this->license_manager->allows_multisite_license( $plugin ); + $network = $this->license_manager->current_site_allows_network_licensing( $plugin ); $response = $plugin->validate_license( $license, $network ); if ( ! $response->is_valid() ) { diff --git a/src/Uplink/Auth/Token/Token_Factory.php b/src/Uplink/Auth/Token/Token_Factory.php index 030e6da0..c4cdf818 100644 --- a/src/Uplink/Auth/Token/Token_Factory.php +++ b/src/Uplink/Auth/Token/Token_Factory.php @@ -5,13 +5,13 @@ use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; use StellarWP\Uplink\Auth\Token\Managers\Network_Token_Manager; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Resources\Resource; final class Token_Factory { /** - * @var License_Manager + * @var License_Handler */ private $license_manager; @@ -21,10 +21,10 @@ final class Token_Factory { private $container; /** - * @param License_Manager $license_manager + * @param License_Handler $license_manager * @param ContainerInterface $container */ - public function __construct( License_Manager $license_manager, ContainerInterface $container ) { + public function __construct( License_Handler $license_manager, ContainerInterface $container ) { $this->license_manager = $license_manager; $this->container = $container; } @@ -37,7 +37,7 @@ public function __construct( License_Manager $license_manager, ContainerInterfac * @return Token_Manager */ public function make( Resource $resource ): Token_Manager { - $network_license = $this->license_manager->allows_multisite_license( $resource ); + $network_license = $this->license_manager->current_site_allows_network_licensing( $resource ); return $this->container->get( $network_license ? Network_Token_Manager::class : Managers\Token_Manager::class ); } diff --git a/src/Uplink/License/License_Key_Strategy_Factory.php b/src/Uplink/License/License_Key_Strategy_Factory.php index 1d47fbe6..03c3f1ae 100644 --- a/src/Uplink/License/License_Key_Strategy_Factory.php +++ b/src/Uplink/License/License_Key_Strategy_Factory.php @@ -7,7 +7,7 @@ use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\Contracts\License_Key_Fetching_Strategy; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Strategies\Global_License_Key_Strategy; use StellarWP\Uplink\License\Strategies\Network_Only_License_Key_Strategy; use StellarWP\Uplink\License\Strategies\Single_Site_License_Key_Strategy; @@ -21,17 +21,17 @@ final class License_Key_Strategy_Factory { private $container; /** - * @var License_Manager + * @var License_Handler */ private $license_manager; /** * @param ContainerInterface $container - * @param License_Manager $license_manager + * @param License_Handler $license_manager */ public function __construct( ContainerInterface $container, - License_Manager $license_manager + License_Handler $license_manager ) { $this->container = $container; $this->license_manager = $license_manager; @@ -53,7 +53,7 @@ public function make( Resource $resource ): License_Key_Fetching_Strategy { return $this->container->get( Global_License_Key_Strategy::class ); case License_Strategy::ISOLATED: - $network = $this->license_manager->allows_multisite_license( $resource ); + $network = $this->license_manager->current_site_allows_network_licensing( $resource ); $class = $network ? Network_Only_License_Key_Strategy::class : Single_Site_License_Key_Strategy::class; return $this->container->get( $class ); diff --git a/src/Uplink/License/Manager/License_Manager.php b/src/Uplink/License/Manager/License_Handler.php similarity index 83% rename from src/Uplink/License/Manager/License_Manager.php rename to src/Uplink/License/Manager/License_Handler.php index c3c6d856..0b43ea4f 100644 --- a/src/Uplink/License/Manager/License_Manager.php +++ b/src/Uplink/License/Manager/License_Handler.php @@ -6,7 +6,7 @@ use StellarWP\Uplink\Pipeline\Pipeline; use StellarWP\Uplink\Resources\Resource; -final class License_Manager { +final class License_Handler { /** * The multisite processing pipeline. @@ -37,20 +37,19 @@ public function __construct( Pipeline $pipeline ) { } /** - * Check if the current multisite and Uplink configuration allows a multisite - * license for the current subsite. + * Check if the current site and configuration allows network licensing. * * Out of the box, sub-sites act independently of the network. * - * @see Config::allow_site_level_licenses_for_subfolder_multisite() - * @see Config::allow_site_level_licenses_for_subdomain_multisite() - * @see Config::allow_site_level_licenses_for_mapped_domain_multisite() - * * @param Resource $resource The current resource to check against. * * @return bool + *@see Config::allow_site_level_licenses_for_mapped_domain_multisite() + * + * @see Config::allow_site_level_licenses_for_subfolder_multisite() + * @see Config::allow_site_level_licenses_for_subdomain_multisite() */ - public function allows_multisite_license( Resource $resource ): bool { + public function current_site_allows_network_licensing( Resource $resource ): bool { $key = $resource->get_slug(); if ( $this->cache_enabled ) { diff --git a/src/Uplink/License/Provider.php b/src/Uplink/License/Provider.php index f361b527..58295178 100644 --- a/src/Uplink/License/Provider.php +++ b/src/Uplink/License/Provider.php @@ -5,7 +5,7 @@ use RuntimeException; use StellarWP\Uplink\Contracts\Abstract_Provider; use StellarWP\Uplink\License\Contracts\License_Key_Fetching_Strategy; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Domain_Mapping; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Main_Site; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Subdomain; @@ -44,9 +44,9 @@ private function register_license_manager(): void { ] ); $this->container->singleton( - License_Manager::class, + License_Handler::class, static function () use ( $pipeline ) { - return new License_Manager( $pipeline ); + return new License_Handler( $pipeline ); } ); } diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index c2a341c8..d2373929 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -4,7 +4,7 @@ use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Config; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Site\Data; use StellarWP\Uplink\Utils; @@ -264,7 +264,7 @@ public function get_key_origin_code(): string { * @return string|null */ protected function get_key_status(): ?string { - $network = $this->container->get( License_Manager::class )->allows_multisite_license( $this->resource ); + $network = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this->resource ); $func = 'get_option'; if ( $network ) { @@ -398,7 +398,7 @@ public function set_key( string $key, string $type = 'local' ): bool { */ public function set_key_status( $valid ): void { $status = Utils\Checks::is_truthy( $valid ) ? 'valid' : 'invalid'; - $network = $this->container->get( License_Manager::class )->allows_multisite_license( $this->resource ); + $network = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this->resource ); $timeout = $this->check_period * HOUR_IN_SECONDS; $func = 'update_option'; diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 5c75e337..270af53d 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -14,7 +14,7 @@ use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\Components\Controller; use StellarWP\Uplink\License\License_Key_Fetcher; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\File_Storage; use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Storage\Local_Storage; @@ -194,7 +194,7 @@ function allows_multisite_license( $slug_or_resource ): bool { return false; } - return get_container()->get( License_Manager::class )->allows_multisite_license( $resource ); + return get_container()->get( License_Handler::class )->current_site_allows_network_licensing( $resource ); } /** diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php index f49f7e43..9db3d654 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php @@ -5,7 +5,7 @@ use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; @@ -71,7 +71,7 @@ protected function setUp(): void { // Mock our sample plugin is network activated, otherwise license key check fails. $this->mock_activate_plugin( 'uplink/index.php', true ); - $this->container->get( License_Manager::class )->disable_cache(); + $this->container->get( License_Handler::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); $this->single_storage = $this->container->get( Local_Storage::class ); diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php index 97c859a2..2b0c4122 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php @@ -6,7 +6,7 @@ use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; @@ -74,7 +74,7 @@ protected function setUp(): void { // Mock our sample plugin is network activated, otherwise license key check fails. $this->mock_activate_plugin( 'uplink/index.php', true ); - $this->container->get( License_Manager::class )->disable_cache(); + $this->container->get( License_Handler::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); $this->single_storage = $this->container->get( Local_Storage::class ); diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php index 9f54b847..c44d8c42 100644 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php +++ b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php @@ -6,7 +6,7 @@ use StellarWP\Uplink\Config; use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\License\License_Key_Fetcher; -use StellarWP\Uplink\License\Manager\License_Manager; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\Local_Storage; use StellarWP\Uplink\Register; use StellarWP\Uplink\Resources\Resource; @@ -55,7 +55,7 @@ protected function setUp(): void { Sample_Plugin::class ); - $this->container->get( License_Manager::class )->disable_cache(); + $this->container->get( License_Handler::class )->disable_cache(); $this->fetcher = $this->container->get( License_Key_Fetcher::class ); $this->single_storage = $this->container->get( Local_Storage::class ); From 5ba739695237d6d4000abb0a2418bd764232cf48 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:33:49 -0700 Subject: [PATCH 37/72] First pass at replacing the underlying storage for License/Resource --- src/Uplink/API/Validation_Response.php | 2 +- src/Uplink/Auth/Admin/Connect_Controller.php | 2 +- .../License/Storage/Storage_Handler.php | 30 +++- src/Uplink/Resources/License.php | 158 ++++-------------- src/Uplink/Resources/Resource.php | 33 ++-- src/Uplink/functions.php | 6 +- tests/muwpunit/Replacement_Key_Test.php | 31 ++-- .../Auth/Admin/ConnectControllerTest.php | 14 +- 8 files changed, 99 insertions(+), 177 deletions(-) diff --git a/src/Uplink/API/Validation_Response.php b/src/Uplink/API/Validation_Response.php index 4fb60cc4..fb102a00 100644 --- a/src/Uplink/API/Validation_Response.php +++ b/src/Uplink/API/Validation_Response.php @@ -406,7 +406,7 @@ public function set_is_valid( bool $is_valid ): void { * @return void */ private function parse(): void { - $this->current_key = $this->resource->get_license_key( $this->validation_type ); + $this->current_key = $this->resource->get_license_key(); $this->expiration = $this->response->expiration ?? __( 'unknown date', '%TEXTDOMAIN%' ); if ( ! empty( $this->response->api_inline_invalid_message ) ) { diff --git a/src/Uplink/Auth/Admin/Connect_Controller.php b/src/Uplink/Auth/Admin/Connect_Controller.php index 5094aa83..5ff188ad 100644 --- a/src/Uplink/Auth/Admin/Connect_Controller.php +++ b/src/Uplink/Auth/Admin/Connect_Controller.php @@ -148,7 +148,7 @@ public function maybe_store_token_data(): void { return; } - if ( ! $plugin->set_license_key( $license, $network ? 'network' : 'local' ) ) { + if ( ! $plugin->set_license_key( $license ) ) { $this->notice->add( new Notice( Notice::ERROR, __( 'Error storing license key.', '%TEXTDOMAIN%' ), true diff --git a/src/Uplink/License/Storage/Storage_Handler.php b/src/Uplink/License/Storage/Storage_Handler.php index 000adf08..c2f85153 100644 --- a/src/Uplink/License/Storage/Storage_Handler.php +++ b/src/Uplink/License/Storage/Storage_Handler.php @@ -23,6 +23,13 @@ final class Storage_Handler implements Storage { */ private $file; + /** + * Whether the key was the original/default file based key. + * + * @var bool + */ + private $is_original_key = false; + /** * @param Storage_Factory $factory * @param File_Storage $file @@ -35,6 +42,15 @@ public function __construct( $this->file = $file; } + /** + * Whether the key was the original file based key. + * + * @return bool + */ + public function is_original(): bool { + return $this->is_original_key; + } + /** * Store a license key in either site_options or the site's options table. * @@ -59,12 +75,24 @@ public function get( Resource $resource ): ?string { // Fallback to the original file based storage key. if ( ! $license_key ) { - $license_key = $this->file->get( $resource ); + $this->is_original_key = true; + $license_key = $this->get_from_file( $resource ); } return $license_key; } + /** + * Get a license key from the packaged class that came with the plugin (if provided). + * + * @param Resource $resource + * + * @return string|null + */ + public function get_from_file( Resource $resource ): ?string { + return $this->file->get( $resource ); + } + /** * Delete a license key from either site_options or the site's options table. * diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index d2373929..006a05f1 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -5,10 +5,12 @@ use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Config; use StellarWP\Uplink\License\Manager\License_Handler; +use StellarWP\Uplink\License\Storage\Storage_Handler; use StellarWP\Uplink\Site\Data; use StellarWP\Uplink\Utils; class License { + /** * How often to check for updates (in hours). * @@ -60,15 +62,6 @@ class License { */ protected $key_origin_code; - /** - * Option prefix for the key. - * - * @since 1.0.0 - * - * @var string - */ - public static $key_option_prefix = 'stellarwp_uplink_license_key_'; - /** * Option prefix for the key status. * @@ -87,34 +80,38 @@ class License { */ protected $resource; + /** + * The storage handler. + * + * @var Storage_Handler + */ + protected $storage; + /** * Constructor. * * @since 1.0.0 * - * @param Resource $resource The resource instance. - * @param ContainerInterface|null $container Container instance. + * @param Resource $resource The resource instance. + * @param ContainerInterface|null $container Container instance. + * + * @throws \RuntimeException */ public function __construct( Resource $resource, $container = null ) { $this->resource = $resource; $this->container = $container ?: Config::get_container(); + $this->storage = $this->container->get( Storage_Handler::class ); } /** - * Deletes the key in site options. + * Deletes the license key from the appropriate storage location. * * @since 1.0.0 * - * @param string $type Type of key (network, local). - * * @return bool */ - public function delete_key( string $type = 'local' ): bool { - if ( 'network' === $type && is_multisite() ) { - return delete_network_option( 0, $this->get_key_option_name() ); - } - - return delete_option( $this->get_key_option_name() ); + public function delete_key(): bool { + return $this->storage->delete( $this->resource ); } /** @@ -122,31 +119,13 @@ public function delete_key( string $type = 'local' ): bool { * * @since 1.0.0 * - * @param string $type The type of key to get (any, network, local, default). - * * @return string */ - public function get_key( $type = 'any' ) { - if ( empty( $this->key ) && ( 'any' === $type || 'network' === $type ) ) { - $this->key = $this->get_key_from_network_option(); + public function get_key(): string { + if ( empty( $this->key ) ) { + $this->key = $this->storage->get( $this->resource ); - if ( ! empty( $this->key ) ) { - $this->key_origin = 'network_option'; - } - } - - if ( empty( $this->key ) && ( 'any' === $type || 'local' === $type ) ) { - $this->key = $this->get_key_from_option(); - - if ( ! empty( $this->key ) ) { - $this->key_origin = 'site_option'; - } - } - - if ( empty( $this->key ) && ( 'any' === $type || 'default' === $type ) ) { - $this->key = $this->get_key_from_license_file(); - - if ( ! empty( $this->key ) ) { + if ( $this->storage->is_original() ) { $this->key_origin = 'file'; } } @@ -160,74 +139,18 @@ public function get_key( $type = 'any' ) { */ $key = apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix(). '/license_get_key', $this->key ); - return $key ?: ''; + return (string) $key; } /** - * Get the license key from a class that holds the license key. - * - * @since 1.0.0 - * - * @return string|null - */ - protected function get_key_from_license_file() { - $license_class = $this->resource->get_license_class(); - $key = null; - - if ( empty( $license_class ) ) { - return null; - } - - if ( defined( $license_class . '::KEY' ) ) { - $key = $license_class::KEY; - } elseif ( defined( $license_class . '::DATA' ) ) { - $key = $license_class::DATA; - } - - return $key; - } - - /** - * Get the license key from a network option. - * - * @since 1.0.0 - * - * @return string|null - */ - protected function get_key_from_network_option() { - if ( ! is_multisite() ) { - return null; - } - - if ( ! $this->resource->is_network_activated() ) { - return null; - } - - /** @var string|null */ - return get_network_option( 0, $this->get_key_option_name(), null ); - } - - /** - * Get the license key from an option. - * - * @since 1.0.0 - * - * @return string|null - */ - protected function get_key_from_option() { - /** @var string|null */ - return get_option( $this->get_key_option_name(), null ); - } - - /** - * Get the option name for the license key. + * Get the license key from a class that holds the license key (aka the original key). * * @since 1.0.0 * * @return string */ - public function get_key_option_name(): string { - return static::$key_option_prefix . $this->resource->get_slug(); + public function get_default_key(): ?string { + return (string) $this->storage->get_from_file( $this->resource ); } /** @@ -243,7 +166,7 @@ public function get_key_origin_code(): string { } $key = $this->get_key(); - $default_key = $this->get_key( 'default' ); + $default_key = $this->get_default_key(); if ( $key === $default_key ) { $this->key_origin_code = 'o'; @@ -273,7 +196,7 @@ protected function get_key_status(): ?string { /** @var string|null */ $status = $func( $this->get_key_status_option_name(), 'invalid' ); - $key = $this->get_key( $network ? 'network' : 'local' ); + $key = $this->get_key(); if ( null === $status && $key ) { $this->resource->validate_license( $key, $network ); @@ -300,6 +223,8 @@ public function get_key_status_option_name(): string { /** * Whether the plugin is network activated and licensed or not. * + * @TODO remove this. + * * @since 1.0.0 * * @return bool @@ -328,7 +253,7 @@ public function is_network_licensed() { * * @return bool */ - public function is_valid() { + public function is_valid(): bool { return 'valid' === $this->get_key_status(); } @@ -350,7 +275,7 @@ public function is_expired(): bool { * * @return bool */ - public function is_validation_expired() { + public function is_validation_expired(): bool { $option_expiration = get_option( $this->get_key_status_option_name() . '_timeout', null ); return is_null( $option_expiration ) || ( time() > $option_expiration ); } @@ -361,30 +286,15 @@ public function is_validation_expired() { * @since 1.0.0 * * @param string $key License key. - * @param string $type Type of key (network, local). * * @return bool */ - public function set_key( string $key, string $type = 'local' ): bool { + public function set_key( string $key ): bool { $key = Utils\Sanitize::key( $key ); $this->key = $key; - if ( 'network' === $type && is_multisite() && $this->resource->is_network_activated() ) { - // WordPress would otherwise return false if the keys already match. - if ( $this->get_key_from_network_option() === $key ) { - return true; - } - - return update_network_option( 0, $this->get_key_option_name(), $key ); - } - - // WordPress would otherwise return false if the keys already match. - if ( $this->get_key_from_option() === $key ) { - return true; - } - - return update_option( $this->get_key_option_name(), $key ); + return $this->storage->store( $this->resource, $key ); } /** @@ -418,6 +328,6 @@ public function set_key_status( $valid ): void { * @return string */ public function __toString(): string { - return $this->get_key() ?: ''; + return $this->get_key(); } } diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index 3f951dbb..2b2d0ffd 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -159,12 +159,10 @@ public function uses_network_licensing(): bool { * * @since 1.0.0 * - * @param string $type The type of key to get (any, network, local, default). - * * @return bool */ - public function delete_license_key( $type = 'local' ): bool { - return $this->get_license_object()->delete_key( $type ); + public function delete_license_key(): bool { + return $this->get_license_object()->delete_key(); } /** @@ -185,7 +183,7 @@ public function get_class() { * * @return array */ - public function get_download_args() { + public function get_download_args(): array { $args = []; /** @var Data */ @@ -205,8 +203,8 @@ public function get_download_args() { $args['wp_version'] = $stats['versions']['wp']; // the following is for install key inclusion (will apply later with PUE addons.) - $args['key'] = Utils\Sanitize::key( $this->get_license_object()->get_key() ?: '' ); - $args['dk'] = Utils\Sanitize::key( $this->get_license_object()->get_key( 'default' ) ?: '' ); + $args['key'] = Utils\Sanitize::key( $this->get_license_object()->get_key() ); + $args['dk'] = Utils\Sanitize::key( $this->get_license_object()->get_default_key() ); $args['o'] = sanitize_text_field( $this->get_license_object()->get_key_origin_code() ); return $args; @@ -246,12 +244,10 @@ public function get_license_class() { * * @since 1.0.0 * - * @param string $type The type of key to get (any, network, local, default). - * * @return string */ - public function get_license_key( $type = 'any' ): string { - return $this->get_license_object()->get_key( $type ); + public function get_license_key(): string { + return $this->get_license_object()->get_key(); } /** @@ -327,11 +323,11 @@ public function get_type() { * * @return array */ - public function get_validation_args() { + public function get_validation_args(): array { $args = []; - $args['key'] = Utils\Sanitize::key( $this->get_license_object()->get_key() ?: '' ); - $args['default_key'] = Utils\Sanitize::key( $this->get_license_object()->get_key( 'default' ) ?: '' ); + $args['key'] = Utils\Sanitize::key( $this->get_license_object()->get_key() ); + $args['default_key'] = Utils\Sanitize::key( $this->get_license_object()->get_default_key() ); $args['license_origin'] = sanitize_text_field( $this->get_license_object()->get_key_origin_code() ); $args['plugin'] = sanitize_text_field( $this->get_slug() ); $args['version'] = sanitize_text_field( $this->get_installed_version() ?: '' ); @@ -473,12 +469,11 @@ public static function register_resource( $resource_class, $slug, $name, $versio * @since 1.0.0 * * @param string $key License key. - * @param string $type The type of key to get (any, network, local, default). * * @return bool */ - public function set_license_key( $key, $type = 'local' ): bool { - return $this->get_license_object()->set_key( $key, $type ); + public function set_license_key( string $key ): bool { + return $this->get_license_object()->set_key( $key ); } /** @@ -522,7 +517,7 @@ public function validate_license( ?string $key = null, bool $do_network_validate $validation_type = $do_network_validate ? 'network' : 'local'; if ( empty( $key ) ) { - $key = $this->get_license_key( $validation_type ); + $key = $this->get_license_key(); } if ( empty( $key ) ) { @@ -531,7 +526,7 @@ public function validate_license( ?string $key = null, bool $do_network_validate return $results; } - $results = $api->validate_license( $this, $key, $validation_type ); + $results = $api->validate_license( $this, $key ); $results_key = $results->get_key(); $result_type = $results->get_result(); $has_replacement_key = $results->has_replacement_key(); diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 270af53d..b33fe2a4 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -360,7 +360,7 @@ function set_license_key( string $slug, string $license ): bool { } $network = allows_multisite_license( $resource ); - $result = $resource->set_license_key( $license, $network ? 'network' : 'local' ); + $result = $resource->set_license_key( $license ); // Force update the key status. $resource->validate_license( $license, $network ); @@ -385,9 +385,7 @@ function delete_license_key( string $slug ): bool { return false; } - $network = allows_multisite_license( $resource ); - - return $network ? get_license_network_storage()->delete( $resource ) : get_license_single_site_storage()->delete( $resource ); + return $resource->delete_license_key(); } /** diff --git a/tests/muwpunit/Replacement_Key_Test.php b/tests/muwpunit/Replacement_Key_Test.php index e9d1dc6e..1e0b7f3d 100644 --- a/tests/muwpunit/Replacement_Key_Test.php +++ b/tests/muwpunit/Replacement_Key_Test.php @@ -57,9 +57,8 @@ public function set_plugin_active_for_network(): void { * @test */ public function should_not_update_license_key_if_replacement_key_not_provided(): void { - // Ensure there is no key set. - $this->resource->delete_license_key(); $validated_key = md5( microtime() ); + $this->assertEmpty( $this->resource->get_license_key() ); $body = $this->service_mock->get_validate_key_success_body(); $mock_response = $this->service_mock->make_response( 200, $body, 'application/json' ); $this->service_mock->will_reply_to_request( 'POST', '/plugins/v2/license/validate', $mock_response ); @@ -76,16 +75,16 @@ public function should_not_update_license_key_if_replacement_key_not_provided(): * @test */ public function should_not_update_license_key_if_replacement_key_is_empty(): void { - // Ensure there is no key set. - $this->resource->delete_license_key(); $validated_key = md5( microtime() ); + $this->assertEmpty( $this->resource->get_license_key() ); + $body = $this->service_mock->get_validate_key_success_body(); // Add an empty replacement key to the response body. $body['results'][0]['replacement_key'] = ''; $mock_response = $this->service_mock->make_response( 200, $body, 'application/json' ); $this->service_mock->will_reply_to_request( 'POST', '/plugins/v2/license/validate', $mock_response ); - $result = $this->resource->validate_license( $validated_key ); + $this->resource->validate_license( $validated_key ); $this->assertEquals( $validated_key, $this->resource->get_license_key() ); } @@ -97,8 +96,7 @@ public function should_not_update_license_key_if_replacement_key_is_empty(): voi */ public function should_update_license_key_if_replacement_key_provided_and_key_not_previously_set(): void { $validated_key = md5( microtime() ); - // Ensure there is no key set. - $this->resource->delete_license_key(); + $this->assertEmpty( $this->resource->get_license_key() ); // Set the response mock to provide a replacement key. $replacement_key = '2222222222222222222222222222222222222222'; $body = $this->service_mock->get_validate_key_success_body(); @@ -107,7 +105,7 @@ public function should_update_license_key_if_replacement_key_provided_and_key_no $mock_response = $this->service_mock->make_response( 200, $body, 'application/json' ); $this->service_mock->will_reply_to_request( 'POST', '/plugins/v2/license/validate', $mock_response ); - $result = $this->resource->validate_license( $validated_key ); + $this->resource->validate_license( $validated_key ); $this->assertEquals( $replacement_key, $this->resource->get_license_key() ); } @@ -141,9 +139,7 @@ public function should_update_license_key_if_replacement_key_provided_and_key_pr */ public function should_set_network_key_to_validated_key_when_not_previously_set_and_replacement_not_provided(): void { $validated_key = md5( microtime() ); - // Ensure there is no license key locally or network wide. - $this->resource->delete_license_key(); - $this->resource->delete_license_key( 'network' ); + $this->assertEmpty( $this->resource->get_license_key() ); $body = $this->service_mock->get_validate_key_success_body(); $mock_response = $this->service_mock->make_response( 200, $body, 'application/json' ); $this->service_mock->will_reply_to_request( 'POST', '/plugins/v2/license/validate', $mock_response ); @@ -158,9 +154,7 @@ public function should_set_network_key_to_validated_key_when_not_previously_set_ */ public function should_set_network_key_to_validated_key_when_not_previously_set_and_replacement_key_empty(): void { $validated_key = md5( microtime() ); - // Ensure there is no license key locally or network wide. - $this->resource->delete_license_key(); - $this->resource->delete_license_key( 'network' ); + $this->assertEmpty( $this->resource->get_license_key() ); $body = $this->service_mock->get_validate_key_success_body(); // Add a replacement key to the response body. $body['results'][0]['replacement_key'] = ''; @@ -177,9 +171,7 @@ public function should_set_network_key_to_validated_key_when_not_previously_set_ */ public function should_set_network_key_to_provided_replacement_key_when_not_previously_set(): void { $validated_key = md5( microtime() ); - // Ensure there is no license key locally or network wide. - $this->resource->delete_license_key(); - $this->resource->delete_license_key( 'network' ); + $this->assertEmpty( $this->resource->get_license_key() ); $body = $this->service_mock->get_validate_key_success_body(); // Add a replacement key to the response body. $replacement_key = '2222222222222222222222222222222222222222'; @@ -200,9 +192,8 @@ public function should_set_network_key_to_provided_replacement_key_when_not_prev */ public function should_set_previously_set_network_key_to_replacement_key_if_provided() { $validated_key = md5( microtime() ); - // Ensure there is no license key locally or network wide. - $this->resource->delete_license_key(); - $this->resource->delete_license_key( 'network' ); + $this->assertEmpty( $this->resource->get_license_key() ); + $body = $this->service_mock->get_validate_key_success_body(); // Add a replacement key to the response body. $replacement_key = '2222222222222222222222222222222222222222'; diff --git a/tests/wpunit/Auth/Admin/ConnectControllerTest.php b/tests/wpunit/Auth/Admin/ConnectControllerTest.php index 6250dedf..424240e8 100644 --- a/tests/wpunit/Auth/Admin/ConnectControllerTest.php +++ b/tests/wpunit/Auth/Admin/ConnectControllerTest.php @@ -139,7 +139,7 @@ public function test_it_sets_additional_license_key(): void { do_action( 'admin_init' ); $this->assertSame( $token, $token_manager->get() ); - $this->assertSame( $plugin->get_license_key( is_multisite() ? 'network' : 'local' ), $license ); + $this->assertSame( $plugin->get_license_key(), $license ); } public function test_it_does_not_store_with_an_invalid_nonce(): void { @@ -261,7 +261,7 @@ public function test_it_stores_token_but_not_license_without_a_license(): void { do_action( 'admin_init' ); $this->assertSame( $token, $token_manager->get() ); - $this->assertEmpty( $plugin->get_license_key( is_multisite() ? 'network' : 'local' ) ); + $this->assertEmpty( $plugin->get_license_key() ); } public function test_it_stores_token_but_not_license_without_a_valid_license(): void { @@ -308,7 +308,7 @@ public function test_it_stores_token_but_not_license_without_a_valid_license(): do_action( 'admin_init' ); $this->assertSame( $token, $token_manager->get() ); - $this->assertEmpty( $plugin->get_license_key( is_multisite() ? 'network' : 'local' ) ); + $this->assertEmpty( $plugin->get_license_key() ); } /** @@ -341,7 +341,7 @@ public function test_it_sets_token_and_additional_license_key_on_multisite_netwo // Mock our sample plugin is network activated, otherwise license key check fails. $this->mock_activate_plugin( 'uplink/index.php', true ); - $this->assertEmpty( $plugin->get_license_key( 'network' ) ); + $this->assertEmpty( $plugin->get_license_key() ); $token_manager = $this->token_manager_factory->make( $plugin ); @@ -368,7 +368,7 @@ public function test_it_sets_token_and_additional_license_key_on_multisite_netwo do_action( 'admin_init' ); $this->assertSame( $token, $token_manager->get() ); - $this->assertSame( $plugin->get_license_key( 'network' ), $license ); + $this->assertSame( $plugin->get_license_key(), $license ); } /** @@ -404,7 +404,7 @@ public function test_it_stores_token_data_on_subfolder_subsite(): void { // Mock our sample plugin is network activated, otherwise license key check fails. $this->mock_activate_plugin( 'uplink/index.php', true ); - $this->assertEmpty( $plugin->get_license_key( 'network' ) ); + $this->assertEmpty( $plugin->get_license_key() ); $token_manager = $this->token_manager_factory->make( $plugin ); @@ -431,7 +431,7 @@ public function test_it_stores_token_data_on_subfolder_subsite(): void { do_action( 'admin_init' ); $this->assertSame( $token, $token_manager->get() ); - $this->assertSame( $plugin->get_license_key( 'network' ), $license ); + $this->assertSame( $plugin->get_license_key(), $license ); } } From 5c5998fa7eeb32069011c9f7618585b8ef484ef1 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:35:58 -0700 Subject: [PATCH 38/72] Wire up uses_network_licensing method --- src/Uplink/Resources/Resource.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index 2b2d0ffd..e60e7211 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -7,6 +7,7 @@ use StellarWP\Uplink\API; use StellarWP\Uplink\Config; use StellarWP\Uplink\Exceptions; +use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Site\Data; use StellarWP\Uplink\Utils; @@ -134,19 +135,18 @@ abstract class Resource { * @param string|null $license_class Class that holds the embedded license key. */ public function __construct( $slug, $name, $version, $path, $class, string $license_class = null ) { - $this->name = $name; - $this->slug = $slug; - $this->path = $path; - $this->class = $class; - $this->license_class = $license_class; - $this->version = $version; - $this->container = Config::get_container(); - // TODO: finish implementing this once refactor is complete. - $this->uses_network_licensing = false; + $this->name = $name; + $this->slug = $slug; + $this->path = $path; + $this->class = $class; + $this->license_class = $license_class; + $this->version = $version; + $this->container = Config::get_container(); + $this->uses_network_licensing = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this ); } /** - * @TODO finish implementing this once refactor is complete. + * Whether the current site, in the current configuration is using network licensing. * * @return bool */ From 0fbd48df2cf00c0bb7415b3f2248ad6738957903 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:38:07 -0700 Subject: [PATCH 39/72] Replace license handler from functions --- src/Uplink/functions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index b33fe2a4..8bc6c66f 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -14,7 +14,6 @@ use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\Components\Controller; use StellarWP\Uplink\License\License_Key_Fetcher; -use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\File_Storage; use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Storage\Local_Storage; @@ -194,7 +193,7 @@ function allows_multisite_license( $slug_or_resource ): bool { return false; } - return get_container()->get( License_Handler::class )->current_site_allows_network_licensing( $resource ); + return $resource->uses_network_licensing(); } /** From 73f93341d8cff59206ef5e01c3ada023f1aa28ab Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:54:30 -0700 Subject: [PATCH 40/72] Refactor license validation no longer require context --- docs/features.md | 3 -- src/Uplink/API/Client.php | 12 +++---- src/Uplink/API/Validation_Response.php | 25 ++++--------- src/Uplink/Auth/Token/Token_Factory.php | 14 ++------ src/Uplink/Resources/Resource.php | 35 +++++++------------ src/Uplink/functions.php | 30 ++-------------- tests/wpunit/API/Validation_ResponseTest.php | 4 +-- .../Auth/Admin/ConnectControllerTest.php | 8 ++--- 8 files changed, 36 insertions(+), 95 deletions(-) diff --git a/docs/features.md b/docs/features.md index b6d0061d..7e8e35d7 100644 --- a/docs/features.md +++ b/docs/features.md @@ -187,7 +187,4 @@ the correct location. // Gets the local URL to disconnect a token (delete it locally). \StellarWP\Uplink\get_disconnect_url( 'my-plugin-slug' ); - -// Checks if the current site (e.g. the sub-site on multisite) would support multisite licensing. -\StellarWP\Uplink\allows_multisite_license( 'my-plugin-slug' ); ``` diff --git a/src/Uplink/API/Client.php b/src/Uplink/API/Client.php index 1189347f..f1dd6af9 100644 --- a/src/Uplink/API/Client.php +++ b/src/Uplink/API/Client.php @@ -18,6 +18,7 @@ * @property-read ContainerInterface $container Container instance. */ class Client { + /** * API base endpoint. * @@ -187,16 +188,15 @@ protected function request( $method, $endpoint, $args ) { * * @since 1.0.0 * - * @param Resource $resource Resource to validate. - * @param string|null $key License key. - * @param string $validation_type Validation type (local or network). - * @param bool $force Force the validation. + * @param Resource $resource Resource to validate. + * @param string|null $key License key. + * @param bool $force Force the validation. * * @throws \RuntimeException * * @return Validation_Response|mixed */ - public function validate_license( Resource $resource, ?string $key = null, string $validation_type = 'local', bool $force = false ) { + public function validate_license( Resource $resource, ?string $key = null, bool $force = false ) { /** @var Data */ $site_data = $this->container->get( Data::class ); $args = $resource->get_validation_args(); @@ -235,7 +235,7 @@ public function validate_license( Resource $resource, ?string $key = null, strin $results = null; } - $results = new Validation_Response( $key, $validation_type, $results, $resource ); + $results = new Validation_Response( $key, $results, $resource ); /** * Filter the license validation results. diff --git a/src/Uplink/API/Validation_Response.php b/src/Uplink/API/Validation_Response.php index fb102a00..48d62e32 100644 --- a/src/Uplink/API/Validation_Response.php +++ b/src/Uplink/API/Validation_Response.php @@ -98,15 +98,6 @@ class Validation_Response { */ protected $result = 'success'; - /** - * Validation type. - * - * @since 1.0.0 - * - * @var string - */ - protected $validation_type; - /** * Version from validation response. * @@ -121,16 +112,14 @@ class Validation_Response { * * @since 1.0.0 * - * @param string|null $key License key. - * @param string $validation_type Validation type (local or network). - * @param stdClass|null $response Validation response. - * @param Resource $resource Resource instance. + * @param string|null $key License key. + * @param stdClass|null $response Validation response. + * @param Resource $resource Resource instance. */ - public function __construct( ?string $key, string $validation_type, ?stdClass $response, Resource $resource ) { - $this->key = $key ?: ''; - $this->validation_type = 'network' === $validation_type ? 'network' : 'local'; - $this->response = $response; - $this->resource = $resource; + public function __construct( ?string $key, ?stdClass $response, Resource $resource ) { + $this->key = $key ?: ''; + $this->response = $response; + $this->resource = $resource; if ( isset( $this->response->results ) ) { $this->response = is_array( $this->response->results ) ? reset( $this->response->results ) : $this->response->results; diff --git a/src/Uplink/Auth/Token/Token_Factory.php b/src/Uplink/Auth/Token/Token_Factory.php index c4cdf818..3a7828ba 100644 --- a/src/Uplink/Auth/Token/Token_Factory.php +++ b/src/Uplink/Auth/Token/Token_Factory.php @@ -5,28 +5,20 @@ use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; use StellarWP\Uplink\Auth\Token\Managers\Network_Token_Manager; -use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Resources\Resource; final class Token_Factory { - /** - * @var License_Handler - */ - private $license_manager; - /** * @var ContainerInterface */ private $container; /** - * @param License_Handler $license_manager * @param ContainerInterface $container */ - public function __construct( License_Handler $license_manager, ContainerInterface $container ) { - $this->license_manager = $license_manager; - $this->container = $container; + public function __construct( ContainerInterface $container ) { + $this->container = $container; } /** @@ -37,7 +29,7 @@ public function __construct( License_Handler $license_manager, ContainerInterfac * @return Token_Manager */ public function make( Resource $resource ): Token_Manager { - $network_license = $this->license_manager->current_site_allows_network_licensing( $resource ); + $network_license = $resource->uses_network_licensing(); return $this->container->get( $network_license ? Network_Token_Manager::class : Managers\Token_Manager::class ); } diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index e60e7211..b19b87f9 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -24,6 +24,7 @@ * @property-read string $path The resource path. */ abstract class Resource { + /** * Resource class. * @@ -114,14 +115,6 @@ abstract class Resource { */ protected $home_url; - /** - * Whether the current site and configuration is using network - * licensing. - * - * @var bool - */ - protected $uses_network_licensing; - /** * Constructor. * @@ -135,14 +128,13 @@ abstract class Resource { * @param string|null $license_class Class that holds the embedded license key. */ public function __construct( $slug, $name, $version, $path, $class, string $license_class = null ) { - $this->name = $name; - $this->slug = $slug; - $this->path = $path; - $this->class = $class; - $this->license_class = $license_class; - $this->version = $version; - $this->container = Config::get_container(); - $this->uses_network_licensing = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this ); + $this->name = $name; + $this->slug = $slug; + $this->path = $path; + $this->class = $class; + $this->license_class = $license_class; + $this->version = $version; + $this->container = Config::get_container(); } /** @@ -151,7 +143,7 @@ public function __construct( $slug, $name, $version, $path, $class, string $lice * @return bool */ public function uses_network_licensing(): bool { - return $this->uses_network_licensing; + return $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this ); } /** @@ -506,22 +498,19 @@ public function should_validate(): bool { * @since 1.0.0 * * @param string|null $key License key. - * @param bool $do_network_validate Validate the key as a network key. * * @return API\Validation_Response */ - public function validate_license( ?string $key = null, bool $do_network_validate = false ) { + public function validate_license( ?string $key = null ): API\Validation_Response { /** @var API\Client */ $api = $this->container->get( API\Client::class ); - $validation_type = $do_network_validate ? 'network' : 'local'; - if ( empty( $key ) ) { $key = $this->get_license_key(); } if ( empty( $key ) ) { - $results = new API\Validation_Response( null, $validation_type, new stdClass(), $this ); + $results = new API\Validation_Response( null, new stdClass(), $this ); $results->set_is_valid( false ); return $results; } @@ -535,7 +524,7 @@ public function validate_license( ?string $key = null, bool $do_network_validate $result_type === 'new' || $has_replacement_key ) { - $this->get_license_object()->set_key( $results_key, $validation_type ); + $this->get_license_object()->set_key( $results_key ); } $this->get_license_object()->set_key_status( $results->is_valid() ); diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 8bc6c66f..6d94e473 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -174,28 +174,6 @@ function get_resource( string $slug ) { return get_container()->get( Collection::class )->offsetGet( $slug ); } -/** - * Compares the Uplink configuration to the current site this function is called on, - * e.g. a sub-site to determine if the product supports multisite licenses. - * - * Not to be confused with Config::supports_network_licenses(). - * - * @param string|Resource|Plugin|Service $slug_or_resource The product/service slug or a Resource object. - * - * @throws \RuntimeException - * - * @return bool - */ -function allows_multisite_license( $slug_or_resource ): bool { - $resource = $slug_or_resource instanceof Resource ? $slug_or_resource : get_resource( $slug_or_resource ); - - if ( ! $resource ) { - return false; - } - - return $resource->uses_network_licensing(); -} - /** * A multisite aware license validation check. * @@ -213,10 +191,7 @@ function validate_license( string $slug, string $license = '' ): ?Validation_Res return null; } - $license = $license ?: get_license_key( $slug ); - $network = allows_multisite_license( $resource ); - - return $resource->validate_license( $license, $network ); + return $resource->validate_license( $license ); } /** @@ -358,11 +333,10 @@ function set_license_key( string $slug, string $license ): bool { return false; } - $network = allows_multisite_license( $resource ); $result = $resource->set_license_key( $license ); // Force update the key status. - $resource->validate_license( $license, $network ); + $resource->validate_license( $license ); return $result; } diff --git a/tests/wpunit/API/Validation_ResponseTest.php b/tests/wpunit/API/Validation_ResponseTest.php index dc732476..f2535657 100644 --- a/tests/wpunit/API/Validation_ResponseTest.php +++ b/tests/wpunit/API/Validation_ResponseTest.php @@ -35,7 +35,7 @@ public function get_dummy_api_invalid_response(): \stdClass { public function test_it_should_provide_valid_update_details(): void { - $result = new Validation_Response( 'aaa11', 'local', $this->get_dummy_valid_response(), $this->resource ); + $result = new Validation_Response( 'aaa11', $this->get_dummy_valid_response(), $this->resource ); $update = $result->get_update_details(); $this->assertEquals( '', $update->id ); @@ -46,7 +46,7 @@ public function test_it_should_provide_valid_update_details(): void { } public function test_it_should_provide_api_error_details_with_corresponding_message() { - $result = new Validation_Response( 'aaa11', 'local', $this->get_dummy_api_invalid_response(), $this->resource ); + $result = new Validation_Response( 'aaa11', $this->get_dummy_api_invalid_response(), $this->resource ); $update = $result->get_update_details(); $this->assertEquals( '1.0.10', $update->new_version ); diff --git a/tests/wpunit/Auth/Admin/ConnectControllerTest.php b/tests/wpunit/Auth/Admin/ConnectControllerTest.php index 424240e8..7ddd5ba6 100644 --- a/tests/wpunit/Auth/Admin/ConnectControllerTest.php +++ b/tests/wpunit/Auth/Admin/ConnectControllerTest.php @@ -105,7 +105,7 @@ public function test_it_sets_additional_license_key(): void { $response->api_upgrade = 0; $response->api_expired = 0; - return new Validation_Response( '123456', is_multisite() ? 'network' : 'local', $response, $plugin ); + return new Validation_Response( '123456', $response, $plugin ); }, ] ); @@ -275,7 +275,7 @@ public function test_it_stores_token_but_not_license_without_a_valid_license(): $response->api_upgrade = 0; $response->api_expired = 1; // makes validation fail. - return new Validation_Response( '123456', is_multisite() ? 'network' : 'local', $response, $plugin ); + return new Validation_Response( '123456', $response, $plugin ); }, ] ); @@ -325,7 +325,7 @@ public function test_it_sets_token_and_additional_license_key_on_multisite_netwo $response->api_upgrade = 0; $response->api_expired = 0; - return new Validation_Response( '123456', 'network', $response, $plugin ); + return new Validation_Response( '123456', $response, $plugin ); }, ] ); @@ -385,7 +385,7 @@ public function test_it_stores_token_data_on_subfolder_subsite(): void { $response->api_upgrade = 0; $response->api_expired = 0; - return new Validation_Response( '123456', 'network', $response, $plugin ); + return new Validation_Response( '123456', $response, $plugin ); }, ] ); From 962704108ca5da69c800c2db8d0b694eac28990d Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:56:30 -0700 Subject: [PATCH 41/72] Rename provider method --- src/Uplink/License/Provider.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Uplink/License/Provider.php b/src/Uplink/License/Provider.php index 58295178..e834b59c 100644 --- a/src/Uplink/License/Provider.php +++ b/src/Uplink/License/Provider.php @@ -25,17 +25,17 @@ final class Provider extends Abstract_Provider { * @throws RuntimeException */ public function register(): void { - $this->register_license_manager(); + $this->register_license_handler(); $this->register_license_strategies(); } /** - * Register the license manager and its pipeline to detect different + * Register the license handler and its pipeline to detect different * multisite licenses. * * @return void */ - private function register_license_manager(): void { + private function register_license_handler(): void { $pipeline = ( new Pipeline( $this->container ) )->through( [ Multisite_Main_Site::class, Multisite_Subfolder::class, From f63fc4361557328253dfa9f58c2b493e13b45505 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 14:57:43 -0700 Subject: [PATCH 42/72] Remove license handler from license resource --- src/Uplink/Resources/License.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 006a05f1..982f6316 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -4,7 +4,6 @@ use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Config; -use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Storage\Storage_Handler; use StellarWP\Uplink\Site\Data; use StellarWP\Uplink\Utils; @@ -187,7 +186,7 @@ public function get_key_origin_code(): string { * @return string|null */ protected function get_key_status(): ?string { - $network = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this->resource ); + $network = $this->resource->uses_network_licensing(); $func = 'get_option'; if ( $network ) { @@ -199,7 +198,7 @@ protected function get_key_status(): ?string { $key = $this->get_key(); if ( null === $status && $key ) { - $this->resource->validate_license( $key, $network ); + $this->resource->validate_license( $key ); $status = $func( $this->get_key_status_option_name(), 'invalid' ); } @@ -308,7 +307,7 @@ public function set_key( string $key ): bool { */ public function set_key_status( $valid ): void { $status = Utils\Checks::is_truthy( $valid ) ? 'valid' : 'invalid'; - $network = $this->container->get( License_Handler::class )->current_site_allows_network_licensing( $this->resource ); + $network = $this->resource->uses_network_licensing(); $timeout = $this->check_period * HOUR_IN_SECONDS; $func = 'update_option'; From b9071125a457abddc18a7b43c07bb07e9a604da2 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 15:04:47 -0700 Subject: [PATCH 43/72] Remove license key fetcher/pipeline/strategies --- src/Uplink/License/License_Key_Fetcher.php | 69 --- .../License/License_Key_Strategy_Factory.php | 66 --- src/Uplink/License/Provider.php | 39 -- .../Global_License_Key_Strategy.php | 37 -- .../Network_Only_License_Key_Strategy.php | 35 -- .../Strategies/Pipeline/License_Traveler.php | 31 -- .../Strategies/Pipeline/Processors/File.php | 40 -- .../Pipeline/Processors/Network.php | 39 -- .../Strategies/Pipeline/Processors/Single.php | 39 -- .../Single_Site_License_Key_Strategy.php | 35 -- src/Uplink/functions.php | 9 +- .../wpunit/License/LicenseKeyFactoryTest.php | 169 ------- .../LicenseKeyMultisiteGlobalFetcherTest.php | 207 -------- ...LicenseKeyMultisiteIsolatedFetcherTest.php | 442 ------------------ .../LicenseKeySingleSiteFetcherTest.php | 157 ------- 15 files changed, 7 insertions(+), 1407 deletions(-) delete mode 100644 src/Uplink/License/License_Key_Fetcher.php delete mode 100644 src/Uplink/License/License_Key_Strategy_Factory.php delete mode 100644 src/Uplink/License/Strategies/Global_License_Key_Strategy.php delete mode 100644 src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php delete mode 100644 src/Uplink/License/Strategies/Pipeline/License_Traveler.php delete mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/File.php delete mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/Network.php delete mode 100644 src/Uplink/License/Strategies/Pipeline/Processors/Single.php delete mode 100644 src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php delete mode 100644 tests/wpunit/License/LicenseKeyFactoryTest.php delete mode 100644 tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php delete mode 100644 tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php delete mode 100644 tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php diff --git a/src/Uplink/License/License_Key_Fetcher.php b/src/Uplink/License/License_Key_Fetcher.php deleted file mode 100644 index 61b035e7..00000000 --- a/src/Uplink/License/License_Key_Fetcher.php +++ /dev/null @@ -1,69 +0,0 @@ -factory = $factory; - $this->resources = $resources; - } - - /** - * Get a license key using one of the available licensing strategies. - * - * @see Config::set_license_key_strategy() - * @see License_Key_Strategy_Factory::make() - * @see get_license_key() - * - * @param string $slug The product/service slug. - * - * @throws \RuntimeException - * - * @return string|null - */ - public function get_key( string $slug ): ?string { - $resource = $this->resources->offsetGet( $slug ); - - if ( ! $resource ) { - return null; - } - - $key = $this->factory->make( $resource )->get_key( $resource ); - - /** - * Filter the license key. - * - * @since 1.0.0 - * - * @param string|null $key The license key. - * @param Resource $resource The resource associated with the license key. - */ - return apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/license_get_key', $key, $resource ); - } - -} diff --git a/src/Uplink/License/License_Key_Strategy_Factory.php b/src/Uplink/License/License_Key_Strategy_Factory.php deleted file mode 100644 index 03c3f1ae..00000000 --- a/src/Uplink/License/License_Key_Strategy_Factory.php +++ /dev/null @@ -1,66 +0,0 @@ -container = $container; - $this->license_manager = $license_manager; - } - - /** - * Make a license key fetching strategy based on the Uplink license key strategy - * and the multisite site license state. - * - * You should use the License Key Fetcher. - * - * @see License_Key_Fetcher::get_key() - * - * @throws RuntimeException - */ - public function make( Resource $resource ): License_Key_Fetching_Strategy { - switch( Config::get_license_key_strategy() ) { - case License_Strategy::GLOBAL: - return $this->container->get( Global_License_Key_Strategy::class ); - - case License_Strategy::ISOLATED: - $network = $this->license_manager->current_site_allows_network_licensing( $resource ); - $class = $network ? Network_Only_License_Key_Strategy::class : Single_Site_License_Key_Strategy::class; - - return $this->container->get( $class ); - - default: - throw new RuntimeException( 'Invalid config license strategy provided. See Config::set_license_key_strategy()' ); - } - } - -} diff --git a/src/Uplink/License/Provider.php b/src/Uplink/License/Provider.php index e834b59c..9f1f5c5e 100644 --- a/src/Uplink/License/Provider.php +++ b/src/Uplink/License/Provider.php @@ -4,21 +4,15 @@ use RuntimeException; use StellarWP\Uplink\Contracts\Abstract_Provider; -use StellarWP\Uplink\License\Contracts\License_Key_Fetching_Strategy; use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Domain_Mapping; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Main_Site; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Subdomain; use StellarWP\Uplink\License\Manager\Pipeline\Processors\Multisite_Subfolder; -use StellarWP\Uplink\License\Strategies\Global_License_Key_Strategy; -use StellarWP\Uplink\License\Strategies\Network_Only_License_Key_Strategy; -use StellarWP\Uplink\License\Strategies\Single_Site_License_Key_Strategy; use StellarWP\Uplink\Pipeline\Pipeline; final class Provider extends Abstract_Provider { - public const LICENSE_PIPELINE = 'uplink.license.strategy.pipeline'; - /** * @inheritDoc * @@ -26,7 +20,6 @@ final class Provider extends Abstract_Provider { */ public function register(): void { $this->register_license_handler(); - $this->register_license_strategies(); } /** @@ -51,36 +44,4 @@ static function () use ( $pipeline ) { ); } - /** - * Register all available license key strategies. - * - * @throws RuntimeException - * - * @return void - */ - private function register_license_strategies(): void { - $this->container->singleton( self::LICENSE_PIPELINE, new Pipeline( $this->container ) ); - - $this->container->singleton( - Global_License_Key_Strategy::class, - static function( $c ): License_Key_Fetching_Strategy { - return new Global_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); - } - ); - - $this->container->singleton( - Network_Only_License_Key_Strategy::class, - static function( $c ): License_Key_Fetching_Strategy { - return new Network_Only_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); - } - ); - - $this->container->singleton( - Single_Site_License_Key_Strategy::class, - static function( $c ): License_Key_Fetching_Strategy { - return new Single_Site_License_Key_Strategy( $c->get( self::LICENSE_PIPELINE ) ); - } - ); - } - } diff --git a/src/Uplink/License/Strategies/Global_License_Key_Strategy.php b/src/Uplink/License/Strategies/Global_License_Key_Strategy.php deleted file mode 100644 index ec3acd3c..00000000 --- a/src/Uplink/License/Strategies/Global_License_Key_Strategy.php +++ /dev/null @@ -1,37 +0,0 @@ - check single site -> fallback to file license (if included). - */ -final class Global_License_Key_Strategy extends Strategy { - - /** - * Get a license key from everywhere. - * - * @param Resource $resource - * - * @return string|null - */ - public function get_key( Resource $resource ): ?string { - /** @var License_Traveler $result */ - $result = $this->pipeline->through( [ - Network::class, - Single::class, - File::class, - ] )->send( new License_Traveler( $resource ) )->thenReturn(); - - return $result->licence_key; - } - -} diff --git a/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php b/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php deleted file mode 100644 index 1f1a2f1f..00000000 --- a/src/Uplink/License/Strategies/Network_Only_License_Key_Strategy.php +++ /dev/null @@ -1,35 +0,0 @@ - fallback to file license (if included). - */ -final class Network_Only_License_Key_Strategy extends Strategy { - - /** - * Get a network license key. - * - * @param Resource $resource - * - * @return string|null - */ - public function get_key( Resource $resource ): ?string { - /** @var License_Traveler $result */ - $result = $this->pipeline->through( [ - Network::class, - File::class, - ] )->send( new License_Traveler( $resource ) )->thenReturn(); - - return $result->licence_key; - } - -} diff --git a/src/Uplink/License/Strategies/Pipeline/License_Traveler.php b/src/Uplink/License/Strategies/Pipeline/License_Traveler.php deleted file mode 100644 index 644e252f..00000000 --- a/src/Uplink/License/Strategies/Pipeline/License_Traveler.php +++ /dev/null @@ -1,31 +0,0 @@ -resource = $resource; - } - - public function resource(): Resource { - return $this->resource; - } - -} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/File.php b/src/Uplink/License/Strategies/Pipeline/Processors/File.php deleted file mode 100644 index 6f045fb9..00000000 --- a/src/Uplink/License/Strategies/Pipeline/Processors/File.php +++ /dev/null @@ -1,40 +0,0 @@ -storage = $storage; - } - - /** - * Attempt to get a license key from the helper class included in - * the plugin. - * - * @param License_Traveler $traveler The instance passed through the pipeline. - * @param Closure $next The next step in the pipeline. - * - * @return License_Traveler - */ - public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { - if ( ! $traveler->licence_key ) { - $traveler->licence_key = $this->storage->get( $traveler->resource() ); - } - - return $next( $traveler ); - } - -} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Network.php b/src/Uplink/License/Strategies/Pipeline/Processors/Network.php deleted file mode 100644 index 524ebc51..00000000 --- a/src/Uplink/License/Strategies/Pipeline/Processors/Network.php +++ /dev/null @@ -1,39 +0,0 @@ -storage = $storage; - } - - /** - * Attempt to get a license key from the WordPress network. - * - * @param License_Traveler $traveler The instance passed through the pipeline. - * @param Closure $next The next step in the pipeline. - * - * @return License_Traveler - */ - public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { - if ( ! $traveler->licence_key ) { - $traveler->licence_key = $this->storage->get( $traveler->resource() ); - } - - return $next( $traveler ); - } - -} diff --git a/src/Uplink/License/Strategies/Pipeline/Processors/Single.php b/src/Uplink/License/Strategies/Pipeline/Processors/Single.php deleted file mode 100644 index 21cfcd1e..00000000 --- a/src/Uplink/License/Strategies/Pipeline/Processors/Single.php +++ /dev/null @@ -1,39 +0,0 @@ -storage = $storage; - } - - /** - * Attempt to get a license key from the current site (multisite or not). - * - * @param License_Traveler $traveler The instance passed through the pipeline. - * @param Closure $next The next step in the pipeline. - * - * @return License_Traveler - */ - public function __invoke( License_Traveler $traveler, Closure $next ): License_Traveler { - if ( ! $traveler->licence_key ) { - $traveler->licence_key = $this->storage->get( $traveler->resource() ); - } - - return $next( $traveler ); - } - -} diff --git a/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php b/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php deleted file mode 100644 index 2cfd55f2..00000000 --- a/src/Uplink/License/Strategies/Single_Site_License_Key_Strategy.php +++ /dev/null @@ -1,35 +0,0 @@ - fallback to file license (if included). - */ -final class Single_Site_License_Key_Strategy extends Strategy { - - /** - * Get a license key for the current site (multisite or not). - * - * @param Resource $resource - * - * @return string|null - */ - public function get_key( Resource $resource ): ?string { - /** @var License_Traveler $result */ - $result = $this->pipeline->through( [ - Single::class, - File::class, - ] )->send( new License_Traveler( $resource ) )->thenReturn(); - - return $result->licence_key; - } - -} diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 6d94e473..4e1c8ee3 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -13,7 +13,6 @@ use StellarWP\Uplink\Auth\Token\Token_Factory; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; use StellarWP\Uplink\Components\Controller; -use StellarWP\Uplink\License\License_Key_Fetcher; use StellarWP\Uplink\License\Storage\File_Storage; use StellarWP\Uplink\License\Storage\Network_Storage; use StellarWP\Uplink\License\Storage\Local_Storage; @@ -208,7 +207,13 @@ function validate_license( string $slug, string $license = '' ): ?Validation_Res * @return string|null */ function get_license_key( string $slug ): ?string { - return get_container()->get( License_Key_Fetcher::class )->get_key( $slug ); + $resource = get_resource( $slug ); + + if ( ! $resource ) { + return null; + } + + return $resource->get_license_key(); } /** diff --git a/tests/wpunit/License/LicenseKeyFactoryTest.php b/tests/wpunit/License/LicenseKeyFactoryTest.php deleted file mode 100644 index ee68d99c..00000000 --- a/tests/wpunit/License/LicenseKeyFactoryTest.php +++ /dev/null @@ -1,169 +0,0 @@ -resource = Register::plugin( - 'sample', - 'Lib Sample', - '1.0.10', - 'uplink/index.php', - Sample_Plugin::class - ); - - $this->factory = $this->container->get( License_Key_Strategy_Factory::class ); - } - - public function test_it_gets_the_default_strategy(): void { - $this->assertInstanceOf( - Global_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - - public function test_it_throws_exception_with_invalid_license_key_strategy(): void { - $this->expectException( RuntimeException::class ); - $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); - - Config::set_license_key_strategy( 'invalid' ); - - $this->factory->make( $this->resource ); - } - - public function test_it_gets_the_single_site_license_key_strategy(): void { - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - - $this->assertInstanceOf( - Single_Site_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - - /** - * @env multisite - */ - public function test_it_gets_the_single_site_license_key_strategy_when_in_multisite_without_configuration(): void { - $this->assertTrue( is_multisite() ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->assertInstanceOf( - Single_Site_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_strategy_with_subfolders_configured(): void { - $this->assertTrue( is_multisite() ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::allow_site_level_licenses_for_subfolder_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->assertInstanceOf( - Network_Only_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_strategy_with_subdomains_configured(): void { - $this->assertTrue( is_multisite() ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::allow_site_level_licenses_for_subdomain_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->assertInstanceOf( - Network_Only_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_strategy_with_domain_mapping_configured(): void { - $this->assertTrue( is_multisite() ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->assertInstanceOf( - Network_Only_License_Key_Strategy::class, - $this->factory->make( $this->resource ) - ); - } - -} diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php deleted file mode 100644 index 9db3d654..00000000 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteGlobalFetcherTest.php +++ /dev/null @@ -1,207 +0,0 @@ -resource = Register::plugin( - $this->slug, - 'Lib Sample', - '1.0.10', - 'uplink/index.php', - Sample_Plugin::class - ); - - // Set global license key strategy. - Config::set_license_key_strategy( License_Strategy::GLOBAL ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - $this->container->get( License_Handler::class )->disable_cache(); - - $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( Local_Storage::class ); - $this->network_storage = $this->container->get( Network_Storage::class ); - } - - /** - * @env multisite - */ - public function test_it_returns_null_with_unknown_resource(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_license_key_on_main_site(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - $this->single_storage->store( $this->resource, 'local-key' ); - - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { - $this->assertTrue( is_multisite() ); - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // No local key stored. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_when_local_key_is_present(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-legacy' ); - - // Network key returned. - $this->assertSame( 'network-key-legacy', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_local_license_key_with_no_network_key(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - // No network key stored. - $this->assertEmpty( $this->network_storage->get( $this->resource ) ); - - // Local key returned. - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_file_license_key_no_local_or_network_key(): void { - $this->assertTrue( is_multisite() ); - - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - // No local key stored. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // No network key stored. - $this->assertEmpty( $this->network_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - -} diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php deleted file mode 100644 index 2b0c4122..00000000 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeyMultisiteIsolatedFetcherTest.php +++ /dev/null @@ -1,442 +0,0 @@ -resource = Register::plugin( - $this->slug, - 'Lib Sample', - '1.0.10', - 'uplink/index.php', - Sample_Plugin::class - ); - - // Set isolated license key strategy. - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - - // Mock our sample plugin is network activated, otherwise license key check fails. - $this->mock_activate_plugin( 'uplink/index.php', true ); - - $this->container->get( License_Handler::class )->disable_cache(); - - $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( Local_Storage::class ); - $this->network_storage = $this->container->get( Network_Storage::class ); - } - - /** - * @env multisite - */ - public function test_it_throws_exception_with_invalid_license_key_strategy(): void { - $this->assertTrue( is_multisite() ); - $this->expectException( RuntimeException::class ); - $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); - - Config::set_license_key_strategy( 'invalid' ); - - $this->fetcher->get_key( $this->slug ); - } - - /** - * @env multisite - */ - public function test_it_returns_null_with_unknown_resource(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_license_key_on_main_site(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - $this->single_storage->store( $this->resource, 'local-key' ); - - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { - $this->assertTrue( is_multisite() ); - $slug = 'sample-isolated-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // No local key stored. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_license_key_while_network_activated(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->network_storage->store( $this->resource, 'network-key' ); - $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); - - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_license_key_with_no_multisite_configuration(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key' ); - - // Local key returned. - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_single_site_license_key_with_all_multisite_types(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - $sites = [ - [ - 'domain' => 'wordpress.test', - 'path' => '/sub1', - 'name' => 'Test Subsite 1', - ], - [ - 'domain' => 'temp.wordpress.test', - 'path' => '/', - 'name' => 'Test Subdomain Subsite', - ], - [ - 'domain' => 'wordpress.custom', - 'path' => '/', - 'name' => 'Test Custom Domain Subsite', - ], - ]; - - $this->network_storage->store( $this->resource, 'network-key' ); - $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); - - foreach ( $sites as $site ) { - $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); - $this->assertNotInstanceOf( WP_Error::class, $id ); - $this->assertGreaterThan( 1, $id ); - - switch_to_blog( $id ); - - $this->assertEmpty( $this->single_storage->get( $this->resource ) ); - $this->single_storage->store( $this->resource, 'local-key' ); - - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - } - - /** - * @env multisite - */ - public function test_it_gets_fallback_file_license_key_with_no_multisite_configuration(): void { - $this->assertTrue( is_multisite() ); - - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - // No local key. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // Store network key, but it should never be fetched in this scenario. - $this->network_storage->store( $resource, 'network-key' ); - $this->assertSame( 'network-key', $this->network_storage->get( $resource )); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_with_subfolders_configured(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - Config::allow_site_level_licenses_for_subfolder_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-subfolder' ); - - $this->assertSame( 'network-key-subfolder', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_fallback_file_license_key_with_subfolders_configured(): void { - $this->assertTrue( is_multisite() ); - - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - Config::allow_site_level_licenses_for_subfolder_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - // Store a local key, but it should never be fetched in this scenario. - $this->single_storage->store( $resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $resource ) ); - - // No network key stored. - $this->assertEmpty( $this->network_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_with_subdomains_configured(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Only subdomains of the main site are licensed. - Config::allow_site_level_licenses_for_subdomain_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-subdomain' ); - - $this->assertSame( 'network-key-subdomain', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_with_domain_mapping_configured(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Only custom subsite domains are licensed. - Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); - - // Create a subsite. - $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-domain' ); - - $this->assertSame( 'network-key-domain', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @env multisite - */ - public function test_it_gets_network_license_key_with_all_multisite_types_enabled(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - Config::allow_site_level_licenses_for_subfolder_multisite( true ); - Config::allow_site_level_licenses_for_subdomain_multisite( true ); - Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); - - $sites = [ - [ - 'domain' => 'wordpress.test', - 'path' => '/sub1', - 'name' => 'Test Subsite 1', - ], - [ - 'domain' => 'temp.wordpress.test', - 'path' => '/', - 'name' => 'Test Subdomain Subsite', - ], - [ - 'domain' => 'wordpress.custom', - 'path' => '/', - 'name' => 'Test Custom Domain Subsite', - ], - ]; - - $this->network_storage->store( $this->resource, 'network-key' ); - - foreach ( $sites as $site ) { - $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); - $this->assertNotInstanceOf( WP_Error::class, $id ); - $this->assertGreaterThan( 1, $id ); - - switch_to_blog( $id ); - - $this->assertEmpty( $this->single_storage->get( $this->resource ) ); - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->assertSame( 'network-key', $this->fetcher->get_key( $this->slug ) ); - } - } - - /** - * We allow only subfolder network licensing, but we check the license on a subsite with a custom domain. - * - * @env multisite - */ - public function test_it_gets_local_license_key_when_from_a_multisite_type_that_is_not_enabled(): void { - $this->assertTrue( is_multisite() ); - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - // Only subfolders are network licensed. - Config::allow_site_level_licenses_for_subfolder_multisite( true ); - - // Create a subsite with a custom domain. - $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); - $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); - $this->assertGreaterThan( 1, $sub_site_id ); - - switch_to_blog( $sub_site_id ); - - $this->single_storage->store( $this->resource, 'local-key' ); - $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); - - $this->network_storage->store( $this->resource, 'network-key-domain' ); - - // Local key returned. - $this->assertSame( 'local-key', $this->fetcher->get_key( $this->slug ) ); - } - -} diff --git a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php deleted file mode 100644 index c44d8c42..00000000 --- a/tests/wpunit/License/LicenseKeyFetcher/LicenseKeySingleSiteFetcherTest.php +++ /dev/null @@ -1,157 +0,0 @@ -resource = Register::plugin( - $this->slug, - 'Lib Sample', - '1.0.10', - 'uplink/index.php', - Sample_Plugin::class - ); - - $this->container->get( License_Handler::class )->disable_cache(); - - $this->fetcher = $this->container->get( License_Key_Fetcher::class ); - $this->single_storage = $this->container->get( Local_Storage::class ); - } - - /** - * Data Providers must return something, but we are just using them to switch - * the config for each test. - * - * WARNING: Due to the way data Providers run, ensure "global" or whatever the default is - * in Config::$license_strategy is the last item, otherwise it doesn't get reset back. - * - * @see Config::$license_strategy - * - * @return array - */ - public function configDataProvider(): array { - $isolated = static function (): string { - Config::set_license_key_strategy( License_Strategy::ISOLATED ); - - return License_Strategy::ISOLATED; - }; - - $global = static function (): string { - Config::set_license_key_strategy( License_Strategy::GLOBAL ); - - return License_Strategy::GLOBAL; - }; - - return [ - [ - $isolated(), - ], - [ - $global(), - ], - ]; - } - - /** - * @dataProvider configDataProvider - */ - public function test_it_throws_exception_with_invalid_license_key_strategy( string $config ): void { - // Ensure the data provider is working just once. - $this->assertThat( $config, $this->logicalOr( - $this->equalTo( License_Strategy::ISOLATED ), - $this->equalTo( License_Strategy::GLOBAL ) - ) ); - - $this->expectException( RuntimeException::class ); - $this->expectExceptionMessage( 'Invalid config license strategy provided.' ); - - Config::set_license_key_strategy( 'invalid' ); - - $this->fetcher->get_key( $this->slug ); - } - - /** - * @dataProvider configDataProvider - */ - public function test_it_returns_null_with_unknown_resource(): void { - $this->assertNull( $this->fetcher->get_key( 'unknown-resource' ) ); - } - - /** - * @dataProvider configDataProvider - */ - public function test_it_gets_single_site_license_key(): void { - $this->assertNull( $this->fetcher->get_key( $this->slug ) ); - - $this->single_storage->store( $this->resource, 'abcdef' ); - - $this->assertSame( 'abcdef', $this->fetcher->get_key( $this->slug ) ); - } - - /** - * @dataProvider configDataProvider - */ - public function test_it_gets_single_site_fallback_file_license_key(): void { - $slug = 'sample-with-license'; - - // Register the sample plugin as a developer would in their plugin. - $resource = Register::plugin( - $slug, - 'Lib Sample With License', - '1.2.0', - 'uplink/index.php', - Sample_Plugin::class, - Sample_Plugin_Helper::class - ); - - // No local key stored. - $this->assertEmpty( $this->single_storage->get( $resource ) ); - - // File based key returned. - $this->assertSame( 'file-based-license-key', $this->fetcher->get_key( $slug ) ); - } - -} From 6eda5098a7dd8603cc370ad8becebf7f8ca8b078 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 15:45:24 -0700 Subject: [PATCH 44/72] Remove strategy config, bring back and update license key tests --- src/Uplink/Config.php | 39 -- src/Uplink/Enums/License_Strategy.php | 13 - src/Uplink/functions.php | 2 - tests/_support/Helper/UplinkTestCase.php | 13 - .../LicenseKeyMultisiteNoConfigTest.php | 188 ++++++++ .../LicenseKeyMultisiteWithConfigTest.php | 409 ++++++++++++++++++ .../LicenseKeySingleSiteFetcherTest.php | 82 ++++ 7 files changed, 679 insertions(+), 67 deletions(-) delete mode 100644 src/Uplink/Enums/License_Strategy.php create mode 100644 tests/wpunit/Resources/License/LicenseKeyMultisiteNoConfigTest.php create mode 100644 tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php create mode 100644 tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index c3625db5..9786da92 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -6,7 +6,6 @@ use RuntimeException; use StellarWP\ContainerContract\ContainerInterface; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; -use StellarWP\Uplink\Enums\License_Strategy; use StellarWP\Uplink\Utils\Sanitize; class Config { @@ -61,20 +60,6 @@ class Config { */ protected static $supports_site_level_override_for_multisite_license = false; - /** - * The License Strategy to use: - * - * global: Check network > check single site > fallback to file (if provided). - * isolated: - * - if multisite network licensing is enabled: check network > fallback to file (if provided). - * - if single site licensing: check single site > fallback to file (if provided). - * - * @see License_Strategy - * - * @var string - */ - protected static $license_strategy = License_Strategy::GLOBAL; - /** * Get the container. * @@ -334,28 +319,4 @@ public static function supports_site_level_override_for_multisite_license(): boo ); } - /** - * Set the current license strategy. - * - * @see License_Strategy - * - * @param string $strategy - * - * @return void - */ - public static function set_license_key_strategy( string $strategy ): void { - self::$license_strategy = $strategy; - } - - /** - * Get the configured license key strategy. - * - * @see License_Strategy - * - * @return string - */ - public static function get_license_key_strategy(): string { - return self::$license_strategy; - } - } diff --git a/src/Uplink/Enums/License_Strategy.php b/src/Uplink/Enums/License_Strategy.php deleted file mode 100644 index d2b5a42b..00000000 --- a/src/Uplink/Enums/License_Strategy.php +++ /dev/null @@ -1,13 +0,0 @@ -network_subfolder_license = Config::supports_site_level_licenses_for_subfolder_multisite(); $this->network_subdomain_license = Config::supports_site_level_licenses_for_subdomain_multisite(); $this->network_domain_mapping_license = Config::supports_site_level_licenses_for_mapped_domain_multisite(); - - // Capture default license key strategy. - $this->strategy = Config::get_license_key_strategy(); } protected function tearDown(): void { @@ -74,9 +64,6 @@ protected function tearDown(): void { Config::allow_site_level_licenses_for_subdomain_multisite( $this->network_subdomain_license ); Config::allow_site_level_licenses_for_mapped_domain_multisite( $this->network_domain_mapping_license ); - // Reset license key strategy to the default. - Config::set_license_key_strategy( $this->strategy ); - parent::tearDown(); } diff --git a/tests/wpunit/Resources/License/LicenseKeyMultisiteNoConfigTest.php b/tests/wpunit/Resources/License/LicenseKeyMultisiteNoConfigTest.php new file mode 100644 index 00000000..0a6bd10c --- /dev/null +++ b/tests/wpunit/Resources/License/LicenseKeyMultisiteNoConfigTest.php @@ -0,0 +1,188 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + $this->container->get( License_Handler::class )->disable_cache(); + + $this->single_storage = $this->container->get( Local_Storage::class ); + $this->network_storage = $this->container->get( Network_Storage::class ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_local_license_key_with_existing_network_key(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + // Local key returned. + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_local_license_key_with_no_network_key(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $this->resource ) ); + + // Local key returned. + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_file_license_key_no_local_or_network_key(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + +} diff --git a/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php b/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php new file mode 100644 index 00000000..41ce4036 --- /dev/null +++ b/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php @@ -0,0 +1,409 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + $this->container->get( License_Handler::class )->disable_cache(); + + $this->single_storage = $this->container->get( Local_Storage::class ); + $this->network_storage = $this->container->get( Network_Storage::class ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_fallback_file_license_key_on_main_site(): void { + $this->assertTrue( is_multisite() ); + $slug = 'sample-isolated-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_while_network_activated(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_with_no_multisite_configuration(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key' ); + + // Local key returned. + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_single_site_license_key_with_all_multisite_types(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $sites = [ + [ + 'domain' => 'wordpress.test', + 'path' => '/sub1', + 'name' => 'Test Subsite 1', + ], + [ + 'domain' => 'temp.wordpress.test', + 'path' => '/', + 'name' => 'Test Subdomain Subsite', + ], + [ + 'domain' => 'wordpress.custom', + 'path' => '/', + 'name' => 'Test Custom Domain Subsite', + ], + ]; + + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + foreach ( $sites as $site ) { + $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); + $this->assertNotInstanceOf( WP_Error::class, $id ); + $this->assertGreaterThan( 1, $id ); + + switch_to_blog( $id ); + + $this->assertEmpty( $this->single_storage->get( $this->resource ) ); + $this->single_storage->store( $this->resource, 'local-key' ); + + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + } + + /** + * @env multisite + */ + public function test_it_gets_fallback_file_license_key_with_no_multisite_configuration(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // No local key. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // Store network key, but it should never be fetched in this scenario. + $this->network_storage->store( $resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_subfolders_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-subfolder' ); + + $this->assertSame( 'network-key-subfolder', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_fallback_file_license_key_with_subfolders_configured(): void { + $this->assertTrue( is_multisite() ); + + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + // Store a local key, but it should never be fetched in this scenario. + $this->single_storage->store( $resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $resource ) ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_subdomains_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Only subdomains of the main site are licensed. + Config::allow_site_level_licenses_for_subdomain_multisite( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'temp.wordpress.test', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-subdomain' ); + + $this->assertSame( 'network-key-subdomain', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_domain_mapping_configured(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Only custom subsite domains are licensed. + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-domain' ); + + $this->assertSame( 'network-key-domain', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_all_multisite_types_enabled(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); + + $sites = [ + [ + 'domain' => 'wordpress.test', + 'path' => '/sub1', + 'name' => 'Test Subsite 1', + ], + [ + 'domain' => 'temp.wordpress.test', + 'path' => '/', + 'name' => 'Test Subdomain Subsite', + ], + [ + 'domain' => 'wordpress.custom', + 'path' => '/', + 'name' => 'Test Custom Domain Subsite', + ], + ]; + + $this->network_storage->store( $this->resource, 'network-key' ); + + foreach ( $sites as $site ) { + $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); + $this->assertNotInstanceOf( WP_Error::class, $id ); + $this->assertGreaterThan( 1, $id ); + + switch_to_blog( $id ); + + $this->assertEmpty( $this->single_storage->get( $this->resource ) ); + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->assertSame( 'network-key', $this->resource->get_license_key() ); + } + } + + /** + * We allow only subfolder network licensing, but we check the license on a subsite with a custom domain. + * + * @env multisite + */ + public function test_it_gets_local_license_key_when_from_a_multisite_type_that_is_not_enabled(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + // Only subfolders are network licensed. + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + + // Create a subsite with a custom domain. + $sub_site_id = wpmu_create_blog( 'wordpress.custom', '/', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + + switch_to_blog( $sub_site_id ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->network_storage->store( $this->resource, 'network-key-domain' ); + + // Local key returned. + $this->assertSame( 'local-key', $this->resource->get_license_key() ); + } + +} diff --git a/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php new file mode 100644 index 00000000..ba469415 --- /dev/null +++ b/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php @@ -0,0 +1,82 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + $this->container->get( License_Handler::class )->disable_cache(); + + $this->single_storage = $this->container->get( Local_Storage::class ); + } + + public function test_it_gets_single_site_license_key(): void { + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->single_storage->store( $this->resource, 'abcdef' ); + + $this->assertSame( 'abcdef', $this->resource->get_license_key() ); + } + + public function test_it_gets_single_site_fallback_file_license_key(): void { + $slug = 'sample-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No local key stored. + $this->assertEmpty( $this->single_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + +} From 9e4825eead1557537e31248d25ba987bbc044789 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 15:47:23 -0700 Subject: [PATCH 45/72] Update comment --- .../Resources/License/LicenseKeyMultisiteWithConfigTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php b/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php index 41ce4036..36e4a297 100644 --- a/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php +++ b/tests/wpunit/Resources/License/LicenseKeyMultisiteWithConfigTest.php @@ -14,8 +14,8 @@ use WP_Error; /** - * The "isolated" licensing strategy takes into account Uplink configuring for each - * multisite type as well as the current site being checked. + * Test different multisite licensing configurations and where the license key is stored + * and retrieved. * * Without any configuration, every subsite is treated as their own site, requiring * their own license key. From 5ed44d4f6f7755c432368b75343d5e1e472292a6 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 15:47:50 -0700 Subject: [PATCH 46/72] Update comment --- .../Resources/License/LicenseKeySingleSiteFetcherTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php b/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php index ba469415..bb0bc220 100644 --- a/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php +++ b/tests/wpunit/Resources/License/LicenseKeySingleSiteFetcherTest.php @@ -11,7 +11,7 @@ use StellarWP\Uplink\Tests\UplinkTestCase; /** - * Test both "isolated" and "global" strategies function in single site mode. + * Test license key fetching in single site mode. */ final class LicenseKeySingleSiteFetcherTest extends UplinkTestCase { From 31621ef5382ad38ac44d888a6d6c2846018dda4e Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:06:39 -0700 Subject: [PATCH 47/72] Add network admin logic for when we have a proper form + tests --- .../Processors/Multisite_Network_Admin.php | 27 +++ src/Uplink/License/Provider.php | 2 + .../LicenseKeyMultisiteNetworkAdminTest.php | 182 ++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 src/Uplink/License/Manager/Pipeline/Processors/Multisite_Network_Admin.php create mode 100644 tests/wpunit/Resources/License/LicenseKeyMultisiteNetworkAdminTest.php diff --git a/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Network_Admin.php b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Network_Admin.php new file mode 100644 index 00000000..22ec2afb --- /dev/null +++ b/src/Uplink/License/Manager/Pipeline/Processors/Multisite_Network_Admin.php @@ -0,0 +1,27 @@ +container ) )->through( [ + Multisite_Network_Admin::class, Multisite_Main_Site::class, Multisite_Subfolder::class, Multisite_Subdomain::class, diff --git a/tests/wpunit/Resources/License/LicenseKeyMultisiteNetworkAdminTest.php b/tests/wpunit/Resources/License/LicenseKeyMultisiteNetworkAdminTest.php new file mode 100644 index 00000000..a178aa3b --- /dev/null +++ b/tests/wpunit/Resources/License/LicenseKeyMultisiteNetworkAdminTest.php @@ -0,0 +1,182 @@ +resource = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + // Allow all multisite modes. + Config::allow_site_level_licenses_for_subfolder_multisite( true ); + Config::allow_site_level_licenses_for_mapped_domain_multisite( true ); + Config::allow_site_level_licenses_for_subdomain_multisite( true ); + + $this->container->get( License_Handler::class )->disable_cache(); + + $this->single_storage = $this->container->get( Local_Storage::class ); + $this->network_storage = $this->container->get( Network_Storage::class ); + + // Mock we're in the network dashboard, so is_network_admin() returns true. + $screen = WP_Screen::get( 'dashboard-network' ); + $GLOBALS['current_screen'] = $screen; + + $this->assertTrue( $screen->in_admin( 'network' ) ); + } + + protected function tearDown(): void { + $GLOBALS['current_screen'] = null; + + parent::tearDown(); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->network_storage->store( $this->resource, 'network-key' ); + + $this->assertSame( 'network-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_fallback_file_license_key(): void { + $this->assertTrue( is_multisite() ); + $slug = 'sample-isolated-with-license'; + + // Register the sample plugin as a developer would in their plugin. + $resource = Register::plugin( + $slug, + 'Lib Sample With License', + '1.2.0', + 'uplink/index.php', + Sample_Plugin::class, + Sample_Plugin_Helper::class + ); + + // No network key stored. + $this->assertEmpty( $this->network_storage->get( $resource ) ); + + // File based key returned. + $this->assertSame( 'file-based-license-key', $resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_with_existing_local_key(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $this->single_storage->store( $this->resource, 'local-key' ); + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'local-key', $this->single_storage->get( $this->resource ) ); + + $this->assertSame( 'network-key', $this->resource->get_license_key() ); + } + + /** + * @env multisite + */ + public function test_it_gets_network_license_key_when_all_multisite_types(): void { + $this->assertTrue( is_multisite() ); + $this->assertEmpty( $this->resource->get_license_key() ); + + $sites = [ + [ + 'domain' => 'wordpress.test', + 'path' => '/sub1', + 'name' => 'Test Subsite 1', + ], + [ + 'domain' => 'temp.wordpress.test', + 'path' => '/', + 'name' => 'Test Subdomain Subsite', + ], + [ + 'domain' => 'wordpress.custom', + 'path' => '/', + 'name' => 'Test Custom Domain Subsite', + ], + ]; + + $this->network_storage->store( $this->resource, 'network-key' ); + $this->assertSame( 'network-key', $this->network_storage->get( $this->resource ) ); + + $main_blog_id = get_current_blog_id(); + + foreach ( $sites as $site ) { + $id = wpmu_create_blog( $site['domain'], $site['path'], $site['name'], 1 ); + $this->assertNotInstanceOf( WP_Error::class, $id ); + $this->assertGreaterThan( 1, $id ); + + switch_to_blog( $id ); + + $this->assertEmpty( $this->single_storage->get( $this->resource ) ); + $this->single_storage->store( $this->resource, 'local-key' ); + + switch_to_blog( $main_blog_id ); + + $this->assertSame( 'network-key', $this->resource->get_license_key() ); + } + } + +} From fa21000d7e27fd737ed3cffde97ca2307cb84414 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:28:53 -0700 Subject: [PATCH 48/72] Remove test that ever ran, will add something later. --- tests/wpunit/Admin/AjaxText.php | 48 --------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 tests/wpunit/Admin/AjaxText.php diff --git a/tests/wpunit/Admin/AjaxText.php b/tests/wpunit/Admin/AjaxText.php deleted file mode 100644 index 14e4ecf2..00000000 --- a/tests/wpunit/Admin/AjaxText.php +++ /dev/null @@ -1,48 +0,0 @@ - 0, - 'message' => __( 'Invalid request: nonce field is expired. Please try again.', '%TEXTDOMAIN%' ) - ]; - - $this->assertSame( - json_encode( $invalid_response ), - $handler->validate_license(), - 'Should return invalid request message if nonce or key is missing is empty' - ); - $_POST['_wpnonce'] = wp_create_nonce( License_Field::get_group_name() ); - $_POST['key'] = 'sample'; - $_POST['plugin'] = 'sample/index.php'; - - $this->assertSame( json_encode( [ - 'status' => 0, - ] ), $handler->validate_license(), 'Should return 0 status since endpoint is unreachable' ); - } - -} From c44fa9c3b53ffe3f7d0f5123cb1d7e3e7f56c217 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:29:35 -0700 Subject: [PATCH 49/72] Fix Ajax logic --- src/Uplink/Admin/Ajax.php | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/Uplink/Admin/Ajax.php b/src/Uplink/Admin/Ajax.php index a1d5d4d6..842c4c21 100644 --- a/src/Uplink/Admin/Ajax.php +++ b/src/Uplink/Admin/Ajax.php @@ -2,7 +2,6 @@ namespace StellarWP\Uplink\Admin; -use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Resources\Collection; use StellarWP\Uplink\Utils; @@ -18,26 +17,18 @@ class Ajax { */ protected $field; - /** - * @var License_Handler - */ - protected $license_manager; - /** * Constructor. * - * @param Collection $resources The plugin/services collection. - * @param License_Field $field The license field. - * @param License_Handler $license_manager The license manager. + * @param Collection $resources The plugin/services collection. + * @param License_Field $field The license field. */ public function __construct( Collection $resources, - License_Field $field, - License_Handler $license_manager + License_Field $field ) { - $this->resources = $resources; - $this->field = $field; - $this->license_manager = $license_manager; + $this->resources = $resources; + $this->field = $field; } /** @@ -70,9 +61,8 @@ public function validate_license(): void { ] ); } - $network_validate = $this->license_manager->current_site_allows_network_licensing( $plugin ); - $results = $plugin->validate_license( $submission['key'], $network_validate ); - $message = $network_validate ? $results->get_network_message()->get() : $results->get_message()->get(); + $results = $plugin->validate_license( $submission['key'] ); + $message = $plugin->uses_network_licensing() ? $results->get_network_message()->get() : $results->get_message()->get(); wp_send_json( [ 'status' => absint( $results->is_valid() ), From 604eee9da81461e128b9ca2b01dcb4bdeb3a4628 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:31:27 -0700 Subject: [PATCH 50/72] Remove license handler dep from connect controller --- src/Uplink/Auth/Admin/Connect_Controller.php | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/Uplink/Auth/Admin/Connect_Controller.php b/src/Uplink/Auth/Admin/Connect_Controller.php index 5ff188ad..dc8fe166 100644 --- a/src/Uplink/Auth/Admin/Connect_Controller.php +++ b/src/Uplink/Auth/Admin/Connect_Controller.php @@ -6,7 +6,6 @@ use StellarWP\Uplink\Auth\Nonce; use StellarWP\Uplink\Auth\Token\Connector; use StellarWP\Uplink\Auth\Token\Exceptions\InvalidTokenException; -use StellarWP\Uplink\License\Manager\License_Handler; use StellarWP\Uplink\Notice\Notice; use StellarWP\Uplink\Notice\Notice_Handler; use StellarWP\Uplink\Resources\Collection; @@ -37,11 +36,6 @@ final class Connect_Controller { */ private $collection; - /** - * @var License_Handler - */ - private $license_manager; - /** * @var Authorizer */ @@ -51,14 +45,12 @@ public function __construct( Connector $connector, Notice_Handler $notice, Collection $collection, - License_Handler $license_manager, Authorizer $authorizer ) { - $this->connector = $connector; - $this->notice = $notice; - $this->collection = $collection; - $this->license_manager = $license_manager; - $this->authorizer = $authorizer; + $this->connector = $connector; + $this->notice = $notice; + $this->collection = $collection; + $this->authorizer = $authorizer; } /** @@ -136,8 +128,7 @@ public function maybe_store_token_data(): void { // Store or override an existing license. if ( $license ) { - $network = $this->license_manager->current_site_allows_network_licensing( $plugin ); - $response = $plugin->validate_license( $license, $network ); + $response = $plugin->validate_license( $license ); if ( ! $response->is_valid() ) { $this->notice->add( new Notice( Notice::ERROR, From 0d71c5007c5f3c670d8e6e1a843f9fc55c32d26d Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:34:25 -0700 Subject: [PATCH 51/72] Add another todo, comment out code for phpstan --- src/Uplink/Resources/License.php | 30 +++++++++++++++--------------- src/Uplink/Resources/Resource.php | 2 ++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 982f6316..fbfacc26 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -222,27 +222,27 @@ public function get_key_status_option_name(): string { /** * Whether the plugin is network activated and licensed or not. * - * @TODO remove this. + * @TODO remove this once override logic is complete. * * @since 1.0.0 * * @return bool */ public function is_network_licensed() { - $is_network_licensed = false; - - if ( ! is_network_admin() && $this->resource->is_network_activated() ) { - $network_key = $this->get_key( 'network' ); - $local_key = $this->get_key( 'local' ); - - // Check whether the network is licensed and NOT overridden by local license - // TODO: Need to account for this in the new system - if ( $network_key && ( empty( $local_key ) || $local_key === $network_key ) ) { - $is_network_licensed = true; - } - } - - return $is_network_licensed; +// $is_network_licensed = false; +// +// if ( ! is_network_admin() && $this->resource->is_network_activated() ) { +// $network_key = $this->get_key( 'network' ); +// $local_key = $this->get_key( 'local' ); +// +// // Check whether the network is licensed and NOT overridden by local license +// // TODO: Need to account for this in the new system +// if ( $network_key && ( empty( $local_key ) || $local_key === $network_key ) ) { +// $is_network_licensed = true; +// } +// } +// +// return $is_network_licensed; } /** diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index b19b87f9..d4ab0aa4 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -382,6 +382,8 @@ public function is_network_activated() { /** * Whether the plugin is network activated and licensed or not. * + * @TODO remove this once override logic is complete. + * * @since 1.0.0 * * @return bool From a10a41e30b75fdfe56972ec257f99ffa0fe1b9b5 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:39:05 -0700 Subject: [PATCH 52/72] Remove network licensed proxy from Resource, fully comment out in license --- src/Uplink/Resources/License.php | 4 ++-- src/Uplink/Resources/Resource.php | 13 ------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index fbfacc26..825948c9 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -228,7 +228,7 @@ public function get_key_status_option_name(): string { * * @return bool */ - public function is_network_licensed() { +// public function is_network_licensed() { // $is_network_licensed = false; // // if ( ! is_network_admin() && $this->resource->is_network_activated() ) { @@ -243,7 +243,7 @@ public function is_network_licensed() { // } // // return $is_network_licensed; - } +// } /** * Whether the plugin is validly licensed or not. diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index d4ab0aa4..04213e57 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -379,19 +379,6 @@ public function is_network_activated() { return is_plugin_active_for_network( $this->get_path() ); } - /** - * Whether the plugin is network activated and licensed or not. - * - * @TODO remove this once override logic is complete. - * - * @since 1.0.0 - * - * @return bool - */ - public function is_network_licensed(): bool { - return $this->get_license_object()->is_network_licensed(); - } - /** * Register a resource and add it to the collection. * From da9f9406d2f398f140787ae582d5798c7079fe58 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:43:00 -0700 Subject: [PATCH 53/72] Remove unneeded license key strategy contracts --- .../License_Key_Fetching_Strategy.php | 18 ------------- src/Uplink/License/Contracts/Strategy.php | 27 ------------------- 2 files changed, 45 deletions(-) delete mode 100644 src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php delete mode 100644 src/Uplink/License/Contracts/Strategy.php diff --git a/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php b/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php deleted file mode 100644 index a67c45b5..00000000 --- a/src/Uplink/License/Contracts/License_Key_Fetching_Strategy.php +++ /dev/null @@ -1,18 +0,0 @@ -pipeline = $pipeline; - } - -} From 03fbfa3e3fa1b5b22e62797f49b9a6e470ca0c9a Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:47:33 -0700 Subject: [PATCH 54/72] Add some more TODOs --- src/Uplink/Resources/License.php | 4 ++++ src/Uplink/Resources/Resource.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 825948c9..4b496c91 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -105,6 +105,8 @@ public function __construct( Resource $resource, $container = null ) { /** * Deletes the license key from the appropriate storage location. * + * @TODO we should fire an action here to validate the key. + * * @since 1.0.0 * * @return bool @@ -282,6 +284,8 @@ public function is_validation_expired(): bool { /** * Sets the key in site options. * + * @TODO we should fire an action here to validate the key. + * * @since 1.0.0 * * @param string $key License key. diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index 04213e57..52ea1dc8 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -484,6 +484,8 @@ public function should_validate(): bool { /** * Validates the resource's license key. * + * @TODO add an action here so this can fire when the key is deleted or modified. + * * @since 1.0.0 * * @param string|null $key License key. From c6ffae06453885bd40128c0d7e8fc796deb8fb86 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 20 Dec 2023 16:50:28 -0700 Subject: [PATCH 55/72] Clean up function names, add notes --- src/Uplink/functions.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index 761d49e0..fe5ab119 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -190,7 +190,7 @@ function validate_license( string $slug, string $license = '' ): ?Validation_Res return null; } - return $resource->validate_license( $license ); + return $resource->validate_license( $license ); } /** @@ -236,13 +236,15 @@ function get_license_network_storage(): Network_Storage { * * @return Local_Storage */ -function get_license_single_site_storage(): Local_Storage { +function get_license_local_storage(): Local_Storage { return get_container()->get( Local_Storage::class ); } /** * Get the raw license key from the network, ignoring any Uplink/multisite configuration. * + * @note You should avoid this function unless you're doing something REALLY custom. + * * @param string $slug The plugin/service slug. * * @throws \RuntimeException @@ -263,20 +265,22 @@ function get_raw_network_license_key( string $slug ): ?string { * Get the raw license key from the current single site, ignoring any Uplink/multisite * configuration. * + * @note You should avoid this function unless you're doing something REALLY custom. + * * @param string $slug The plugin/service slug. * * @throws \RuntimeException * * @return string|null */ -function get_raw_single_site_license_key( string $slug ): ?string { +function get_raw_local_license_key( string $slug ): ?string { $resource = get_resource( $slug ); if ( ! $resource ) { return null; } - return get_license_single_site_storage()->get( $resource ); + return get_license_local_storage()->get( $resource ); } /** @@ -336,9 +340,10 @@ function set_license_key( string $slug, string $license ): bool { return false; } - $result = $resource->set_license_key( $license ); + $result = $resource->set_license_key( $license ); // Force update the key status. + // TODO: we'll automate this via set_license_key $resource->validate_license( $license ); return $result; From 22369e7da81a7a447c6c064ca91477de9be92801 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 09:32:00 -0700 Subject: [PATCH 56/72] Move related methods together --- src/Uplink/Resources/License.php | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 4b496c91..ce80fcac 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -180,33 +180,6 @@ public function get_key_origin_code(): string { return $this->key_origin_code; } - /** - * Get the license key status from an option. - * - * @since 1.0.0 - * - * @return string|null - */ - protected function get_key_status(): ?string { - $network = $this->resource->uses_network_licensing(); - $func = 'get_option'; - - if ( $network ) { - $func = 'get_site_option'; - } - - /** @var string|null */ - $status = $func( $this->get_key_status_option_name(), 'invalid' ); - $key = $this->get_key(); - - if ( null === $status && $key ) { - $this->resource->validate_license( $key ); - $status = $func( $this->get_key_status_option_name(), 'invalid' ); - } - - return $status; - } - /** * Get the option name for the license key status. * @@ -300,6 +273,33 @@ public function set_key( string $key ): bool { return $this->storage->store( $this->resource, $key ); } + /** + * Get the license key status from an option. + * + * @since 1.0.0 + * + * @return string|null + */ + protected function get_key_status(): ?string { + $network = $this->resource->uses_network_licensing(); + $func = 'get_option'; + + if ( $network ) { + $func = 'get_site_option'; + } + + /** @var string|null */ + $status = $func( $this->get_key_status_option_name(), 'invalid' ); + $key = $this->get_key(); + + if ( null === $status && $key ) { + $this->resource->validate_license( $key ); + $status = $func( $this->get_key_status_option_name(), 'invalid' ); + } + + return $status; + } + /** * Sets the key status based on the key validation check results. * From da10a67da6b298ea7eb2cc415ee558e7c0cd6084 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:11:21 -0700 Subject: [PATCH 57/72] cast key to string --- src/Uplink/API/Validation_Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/API/Validation_Response.php b/src/Uplink/API/Validation_Response.php index 48d62e32..92a48d8d 100644 --- a/src/Uplink/API/Validation_Response.php +++ b/src/Uplink/API/Validation_Response.php @@ -117,7 +117,7 @@ class Validation_Response { * @param Resource $resource Resource instance. */ public function __construct( ?string $key, ?stdClass $response, Resource $resource ) { - $this->key = $key ?: ''; + $this->key = (string) $key; $this->response = $response; $this->resource = $resource; From b6940ebaa6663bb409c20c0f70ca2df781e8cc44 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:13:15 -0700 Subject: [PATCH 58/72] Fix get_key_status() logic that never ran --- src/Uplink/Resources/License.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index ce80fcac..1373b0f8 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -288,13 +288,19 @@ protected function get_key_status(): ?string { $func = 'get_site_option'; } - /** @var string|null */ - $status = $func( $this->get_key_status_option_name(), 'invalid' ); + /** @var string|null $status */ + $status = $func( $this->get_key_status_option_name(), null ); $key = $this->get_key(); + // If no status has been set, run the update again. if ( null === $status && $key ) { $this->resource->validate_license( $key ); - $status = $func( $this->get_key_status_option_name(), 'invalid' ); + $status = $func( $this->get_key_status_option_name(), null ); + + // If it still failed, default to invalid. + if ( null === $status ) { + $status = 'invalid'; + } } return $status; From a47aac51d9553957857e0a443affa0bb7b5ebdb2 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:24:12 -0700 Subject: [PATCH 59/72] Use local method to set key --- src/Uplink/Resources/Resource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index 52ea1dc8..b8284e2e 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -515,7 +515,7 @@ public function validate_license( ?string $key = null ): API\Validation_Response $result_type === 'new' || $has_replacement_key ) { - $this->get_license_object()->set_key( $results_key ); + $this->set_license_key( $results_key ); } $this->get_license_object()->set_key_status( $results->is_valid() ); From fc91f49bf86477e452567454acedae9f5cae660e Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:24:34 -0700 Subject: [PATCH 60/72] Update docblock, although I think the comment is wrong and it's just a bool --- src/Uplink/Resources/License.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 1373b0f8..5fd5d0f1 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -311,7 +311,7 @@ protected function get_key_status(): ?string { * * @since TBD * - * @param int $valid 0 for invalid, 1 or 2 for valid. + * @param int|bool|string $valid 0 for invalid, 1 or 2 for valid. * * @return void */ From 9d8015619cbea7ea60c33101731a7420924555b8 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:42:30 -0700 Subject: [PATCH 61/72] Move api container fetching below empty check --- src/Uplink/Resources/Resource.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Uplink/Resources/Resource.php b/src/Uplink/Resources/Resource.php index b8284e2e..bc050573 100644 --- a/src/Uplink/Resources/Resource.php +++ b/src/Uplink/Resources/Resource.php @@ -493,9 +493,6 @@ public function should_validate(): bool { * @return API\Validation_Response */ public function validate_license( ?string $key = null ): API\Validation_Response { - /** @var API\Client */ - $api = $this->container->get( API\Client::class ); - if ( empty( $key ) ) { $key = $this->get_license_key(); } @@ -503,9 +500,13 @@ public function validate_license( ?string $key = null ): API\Validation_Response if ( empty( $key ) ) { $results = new API\Validation_Response( null, new stdClass(), $this ); $results->set_is_valid( false ); + return $results; } + /** @var API\Client $api */ + $api = $this->container->get( API\Client::class ); + $results = $api->validate_license( $this, $key ); $results_key = $results->get_key(); $result_type = $results->get_result(); From c882c781ca8fe915053bae6f8325896f71e94f8b Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 21 Dec 2023 11:48:25 -0700 Subject: [PATCH 62/72] Group key methods together --- src/Uplink/Resources/License.php | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Uplink/Resources/License.php b/src/Uplink/Resources/License.php index 5fd5d0f1..8cac2279 100644 --- a/src/Uplink/Resources/License.php +++ b/src/Uplink/Resources/License.php @@ -102,6 +102,25 @@ public function __construct( Resource $resource, $container = null ) { $this->storage = $this->container->get( Storage_Handler::class ); } + /** + * Sets the key in site options. + * + * @TODO we should fire an action here to validate the key. + * + * @since 1.0.0 + * + * @param string $key License key. + * + * @return bool + */ + public function set_key( string $key ): bool { + $key = Utils\Sanitize::key( $key ); + + $this->key = $key; + + return $this->storage->store( $this->resource, $key ); + } + /** * Deletes the license key from the appropriate storage location. * @@ -254,25 +273,6 @@ public function is_validation_expired(): bool { return is_null( $option_expiration ) || ( time() > $option_expiration ); } - /** - * Sets the key in site options. - * - * @TODO we should fire an action here to validate the key. - * - * @since 1.0.0 - * - * @param string $key License key. - * - * @return bool - */ - public function set_key( string $key ): bool { - $key = Utils\Sanitize::key( $key ); - - $this->key = $key; - - return $this->storage->store( $this->resource, $key ); - } - /** * Get the license key status from an option. * From 1f01bd86e035e49f22ad963541ebff9c4011b578 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 14:04:39 -0700 Subject: [PATCH 63/72] Fix HTTP mocks not working after base url was renamed. --- tests/_support/Helper/Licensing/Service_Mock.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/_support/Helper/Licensing/Service_Mock.php b/tests/_support/Helper/Licensing/Service_Mock.php index 4a9a1280..de626985 100644 --- a/tests/_support/Helper/Licensing/Service_Mock.php +++ b/tests/_support/Helper/Licensing/Service_Mock.php @@ -5,6 +5,7 @@ use StellarWP\Uplink\Tests\Http_API\Http_API_Mock; class Service_Mock extends Http_API_Mock { + /** * Returns the body of a success response to the key validation request, in array format. * @@ -50,11 +51,11 @@ public function get_validate_key_success_body(): array { ]; } - /** * {@inheritdoc } */ protected function get_url(): string { - return 'https://pue.theeventscalendar.com/api/'; + return 'https://licensing.stellarwp.com/api/'; } + } From a519978c359efef0d86d2394b03cca4656b1af3b Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:44:58 -0700 Subject: [PATCH 64/72] Reset config after each test --- tests/_support/Helper/UplinkTestCase.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/_support/Helper/UplinkTestCase.php b/tests/_support/Helper/UplinkTestCase.php index fcd4a603..61911f0a 100644 --- a/tests/_support/Helper/UplinkTestCase.php +++ b/tests/_support/Helper/UplinkTestCase.php @@ -32,4 +32,10 @@ protected function setUp(): void { $this->container = Config::get_container(); } + protected function tearDown(): void { + Config::reset(); + + parent::tearDown(); + } + } From a223aa60b805d9e76eed356daecaae5b174299a9 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:45:28 -0700 Subject: [PATCH 65/72] Add token auth caching config + docs --- README.md | 6 ++++++ src/Uplink/Config.php | 40 ++++++++++++++++++++++++++++++++++--- tests/wpunit/ConfigTest.php | 8 ++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cb689a32..2bcba4f2 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ add_action( 'plugins_loaded', function() { */ Config::set_token_auth_prefix( 'my_origin' ); + // Optionally, change the default auth token caching. + Config::set_auth_cache_expiration( WEEK_IN_SECONDS ); + + // Or, disable it completely. + Config::set_auth_cache_expiration( -1 ); + Uplink::init(); }, 0 ); ``` diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index dcaaa2ec..a06563b6 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -1,4 +1,4 @@ -singleton( self::TOKEN_OPTION_NAME, null ); @@ -174,4 +187,25 @@ public static function set_token_auth_prefix( string $prefix ): void { self::get_container()->singleton( self::TOKEN_OPTION_NAME, $key ); } + /** + * Set the token authorization expiration. + * + * @param int $seconds The time seconds the cache will exist for. + * -1 = disabled, 0 = no expiration. + * + * @return void + */ + public static function set_auth_cache_expiration( int $seconds ): void { + static::$auth_cache_expiration = $seconds; + } + + /** + * Get the token authorization expiration. + * + * @return int + */ + public static function get_auth_cache_expiration(): int { + return static::$auth_cache_expiration; + } + } diff --git a/tests/wpunit/ConfigTest.php b/tests/wpunit/ConfigTest.php index 99ddcc02..6c61204b 100644 --- a/tests/wpunit/ConfigTest.php +++ b/tests/wpunit/ConfigTest.php @@ -54,4 +54,12 @@ public function test_it_throws_exception_with_long_prefix(): void { Config::set_token_auth_prefix( 'fluffy_unicorn_rainbow_sunshine_happy_smile_peace_joy_love_puppy_harmony_giggles_dreams_celebrate_fantastic_wonderful_whimsical_serendipity_butterfly_magic_sparkle_sweetness_trust_' ); } + public function test_it_gets_and_sets_auth_token_cache_expiration(): void { + $this->assertSame( 21600, Config::get_auth_cache_expiration() ); + + Config::set_auth_cache_expiration( DAY_IN_SECONDS ); + + $this->assertSame( DAY_IN_SECONDS, Config::get_auth_cache_expiration() ); + } + } From c4c52b55e3e66a54c167c5d3da27268a0b2780b2 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:46:16 -0700 Subject: [PATCH 66/72] Add token authorizer contract, decorator and tests --- .../V3/Auth/Contracts/Token_Authorizer.php | 21 +++++ src/Uplink/API/V3/Auth/Token_Authorizer.php | 2 +- .../Auth/Token_Authorizer_Cache_Decorator.php | 86 +++++++++++++++++++ src/Uplink/API/V3/Provider.php | 32 +++++++ tests/wpunit/API/V3/AuthorizerCacheTest.php | 65 ++++++++++++++ tests/wpunit/API/V3/AuthorizerTest.php | 18 ++++ 6 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 src/Uplink/API/V3/Auth/Contracts/Token_Authorizer.php create mode 100644 src/Uplink/API/V3/Auth/Token_Authorizer_Cache_Decorator.php create mode 100644 tests/wpunit/API/V3/AuthorizerCacheTest.php diff --git a/src/Uplink/API/V3/Auth/Contracts/Token_Authorizer.php b/src/Uplink/API/V3/Auth/Contracts/Token_Authorizer.php new file mode 100644 index 00000000..7de31571 --- /dev/null +++ b/src/Uplink/API/V3/Auth/Contracts/Token_Authorizer.php @@ -0,0 +1,21 @@ +authorizer = $authorizer; + $this->expiration = $expiration; + } + + /** + * Check if a license is authorized and cache successful responses. + * + * @see Config::set_auth_cache_expiration() + * @see is_authorized() + * @see Token_Authorizer + * + * @param string $license The license key. + * @param string $token The stored token. + * @param string $domain The user's domain. + * + * @return bool + */ + public function is_authorized( string $license, string $token, string $domain ): bool { + $transient = $this->build_transient( [ $license, $token, $domain ] ); + $is_authorized = get_transient( $transient ); + + if ( $is_authorized === true ) { + return true; + } + + $is_authorized = $this->authorizer->is_authorized( $license, $token, $domain ); + + // Only cache successful responses. + if ( $is_authorized ) { + set_transient( $transient, true, $this->expiration ); + } + + return $is_authorized; + } + + /** + * Build a transient key. + * + * @param array ...$args + * + * @return string + */ + public function build_transient( array ...$args ): string { + return self::TRANSIENT_PREFIX . hash( 'sha256', json_encode( $args ) ); + } + +} diff --git a/src/Uplink/API/V3/Provider.php b/src/Uplink/API/V3/Provider.php index ad2bb834..2d4795e0 100644 --- a/src/Uplink/API/V3/Provider.php +++ b/src/Uplink/API/V3/Provider.php @@ -4,6 +4,8 @@ use StellarWP\Uplink\API\V3\Auth\Auth_Url_Cache_Decorator; use StellarWP\Uplink\API\V3\Auth\Contracts\Auth_Url; +use StellarWP\Uplink\API\V3\Auth\Contracts\Token_Authorizer; +use StellarWP\Uplink\API\V3\Auth\Token_Authorizer_Cache_Decorator; use StellarWP\Uplink\API\V3\Contracts\Client_V3; use StellarWP\Uplink\Config; use StellarWP\Uplink\Contracts\Abstract_Provider; @@ -54,6 +56,36 @@ public function register() { return new Client( $api_root, $base_url, $request_args, new WP_Http() ); } ); + + $this->register_token_authorizer(); + } + + /** + * Based on the developer's configuration, determine if we will enable Token Authorization caching. + * + * @return void + */ + private function register_token_authorizer(): void { + $expiration = Config::get_auth_cache_expiration(); + + if ( $expiration >= 0 ) { + $this->container->bind( + Token_Authorizer::class, + static function ( $c ) use ( $expiration ): Token_Authorizer { + return new Token_Authorizer_Cache_Decorator( + $c->get( Auth\Token_Authorizer::class ), + $expiration + ); + } + ); + + return; + } + + $this->container->bind( + Token_Authorizer::class, + Auth\Token_Authorizer::class + ); } } diff --git a/tests/wpunit/API/V3/AuthorizerCacheTest.php b/tests/wpunit/API/V3/AuthorizerCacheTest.php new file mode 100644 index 00000000..71a0726a --- /dev/null +++ b/tests/wpunit/API/V3/AuthorizerCacheTest.php @@ -0,0 +1,65 @@ +assertInstanceOf( + Token_Authorizer_Cache_Decorator::class, + $this->container->get( Token_Authorizer::class ) + ); + } + + public function test_it_caches_a_valid_token_response(): void { + $authorizer_mock = $this->makeEmpty( \StellarWP\Uplink\API\V3\Auth\Token_Authorizer::class, [ + 'is_authorized' => static function (): bool { + return true; + }, + ] ); + + $this->container->bind( \StellarWP\Uplink\API\V3\Auth\Token_Authorizer::class, $authorizer_mock ); + + $decorator = $this->container->get( Token_Authorizer::class ); + $transient = $decorator->build_transient( [ '1234', 'dc2c98d9-9ff8-4409-bfd2-a3cce5b5c840', 'test.com' ] ); + + // No cache should exist. + $this->assertFalse( get_transient( $transient ) ); + + $authorized = $decorator->is_authorized( '1234', 'dc2c98d9-9ff8-4409-bfd2-a3cce5b5c840', 'test.com' ); + + $this->assertTrue( $authorized ); + + // Cache should now be present. + $this->assertTrue( get_transient( $transient ) ); + $this->assertTrue( $decorator->is_authorized( '1234', 'dc2c98d9-9ff8-4409-bfd2-a3cce5b5c840', 'test.com' ) ); + } + + public function test_it_does_not_cache_an_invalid_token_response(): void { + $authorizer_mock = $this->makeEmpty( \StellarWP\Uplink\API\V3\Auth\Token_Authorizer::class, [ + 'is_authorized' => static function (): bool { + return false; + }, + ] ); + + $this->container->bind( \StellarWP\Uplink\API\V3\Auth\Token_Authorizer::class, $authorizer_mock ); + + $decorator = $this->container->get( Token_Authorizer::class ); + $transient = $decorator->build_transient( [ '1234', 'dc2c98d9-9ff8-4409-bfd2-a3cce5b5c840', 'test.com' ] ); + + // No cache should exist. + $this->assertFalse( get_transient( $transient ) ); + + $authorized = $decorator->is_authorized( '1234', 'dc2c98d9-9ff8-4409-bfd2-a3cce5b5c840', 'test.com' ); + + $this->assertFalse( $authorized ); + + // Cache should still be empty, unfortunately the default is "false" for transients, so this isn't the best test. + $this->assertFalse( get_transient( $transient ) ); + } + +} diff --git a/tests/wpunit/API/V3/AuthorizerTest.php b/tests/wpunit/API/V3/AuthorizerTest.php index a0053fd4..49a0490d 100644 --- a/tests/wpunit/API/V3/AuthorizerTest.php +++ b/tests/wpunit/API/V3/AuthorizerTest.php @@ -4,10 +4,28 @@ use StellarWP\Uplink\API\V3\Auth\Token_Authorizer; use StellarWP\Uplink\API\V3\Contracts\Client_V3; +use StellarWP\Uplink\Config; use StellarWP\Uplink\Tests\UplinkTestCase; +use StellarWP\Uplink\Uplink; final class AuthorizerTest extends UplinkTestCase { + protected function setUp(): void { + parent::setUp(); + + // Disable auth caching. + Config::set_auth_cache_expiration( -1 ); + + Uplink::init(); + } + + public function test_it_binds_the_correct_instance_when_auth_cache_is_disabled(): void { + $this->assertInstanceOf( + Token_Authorizer::class, + $this->container->get( \StellarWP\Uplink\API\V3\Auth\Contracts\Token_Authorizer::class ) + ); + } + public function test_it_authorizes_a_valid_token(): void { $clientMock = $this->makeEmpty( Client_V3::class, [ 'get' => static function () { From 8bb2d1cfd851078c9c66c6a979703c19338a567c Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:46:28 -0700 Subject: [PATCH 67/72] Update function to fetch interface --- src/Uplink/functions.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Uplink/functions.php b/src/Uplink/functions.php index c6d98018..e2544006 100644 --- a/src/Uplink/functions.php +++ b/src/Uplink/functions.php @@ -2,7 +2,7 @@ namespace StellarWP\Uplink; -use StellarWP\Uplink\API\V3\Auth\Token_Authorizer; +use StellarWP\Uplink\API\V3\Auth\Contracts\Token_Authorizer; use StellarWP\Uplink\Auth\Auth_Url_Builder; use StellarWP\Uplink\Auth\Token\Contracts\Token_Manager; use StellarWP\Uplink\Components\Admin\Authorize_Button_Controller; @@ -48,7 +48,9 @@ function get_authorization_token(): ?string { } /** - * Manually check if a license is authorized. + * Check if a license is authorized. + * + * @note This response may be cached. * * @param string $license The license key. * @param string $token The stored token. From 9fbcf0293fc7422ede321af863955e651fe00972 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:49:00 -0700 Subject: [PATCH 68/72] Fix bad return type --- src/Uplink/Pipeline/Pipeline.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uplink/Pipeline/Pipeline.php b/src/Uplink/Pipeline/Pipeline.php index beed20ee..31608ea2 100644 --- a/src/Uplink/Pipeline/Pipeline.php +++ b/src/Uplink/Pipeline/Pipeline.php @@ -223,7 +223,7 @@ protected function pipes(): array { * * @return ContainerInterface */ - protected function getContainer(): ?ContainerInterface { + protected function getContainer(): ContainerInterface { if ( ! $this->container ) { throw new RuntimeException( 'A container instance has not been passed to the Pipeline.' ); } From bff5b58d749b1c4da4192e5f61c06c0c2edab16d Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Wed, 3 Jan 2024 15:58:01 -0700 Subject: [PATCH 69/72] Use auth default constant in test --- tests/wpunit/ConfigTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wpunit/ConfigTest.php b/tests/wpunit/ConfigTest.php index 6c61204b..f0ea865b 100644 --- a/tests/wpunit/ConfigTest.php +++ b/tests/wpunit/ConfigTest.php @@ -55,7 +55,7 @@ public function test_it_throws_exception_with_long_prefix(): void { } public function test_it_gets_and_sets_auth_token_cache_expiration(): void { - $this->assertSame( 21600, Config::get_auth_cache_expiration() ); + $this->assertSame( Config::DEFAULT_AUTH_CACHE, Config::get_auth_cache_expiration() ); Config::set_auth_cache_expiration( DAY_IN_SECONDS ); From 366318f8b960328c49566c6b2b1500d6ca154425 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 4 Jan 2024 09:53:32 -0700 Subject: [PATCH 70/72] Use late static bindings --- src/Uplink/Config.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index d1db6702..b729548e 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -245,7 +245,7 @@ public static function get_auth_cache_expiration(): int { * @return void */ public static function allow_site_level_licenses_for_subfolder_multisite( bool $allowed ): void { - self::$supports_site_level_licenses_for_subfolder_multisite = $allowed; + static::$supports_site_level_licenses_for_subfolder_multisite = $allowed; } /** @@ -256,7 +256,7 @@ public static function allow_site_level_licenses_for_subfolder_multisite( bool $ * @return void */ public static function allow_site_level_licenses_for_subdomain_multisite( bool $allowed ): void { - self::$supports_site_level_licenses_for_subdomain_multisite = $allowed; + static::$supports_site_level_licenses_for_subdomain_multisite = $allowed; } /** @@ -267,7 +267,7 @@ public static function allow_site_level_licenses_for_subdomain_multisite( bool $ * @return void */ public static function allow_site_level_licenses_for_mapped_domain_multisite( bool $allowed ): void { - self::$supports_site_level_licenses_for_mapped_domain_multisite = $allowed; + static::$supports_site_level_licenses_for_mapped_domain_multisite = $allowed; } /** @@ -280,7 +280,7 @@ public static function allow_site_level_licenses_for_mapped_domain_multisite( bo public static function supports_site_level_licenses_for_subfolder_multisite(): bool { return (bool) apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_subfolder_multisite', - self::$supports_site_level_licenses_for_subfolder_multisite + static::$supports_site_level_licenses_for_subfolder_multisite ); } @@ -294,7 +294,7 @@ public static function supports_site_level_licenses_for_subfolder_multisite(): b public static function supports_site_level_licenses_for_subdomain_multisite(): bool { return (bool) apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_subdomain_multisite', - self::$supports_site_level_licenses_for_subdomain_multisite + static::$supports_site_level_licenses_for_subdomain_multisite ); } @@ -308,7 +308,7 @@ public static function supports_site_level_licenses_for_subdomain_multisite(): b public static function supports_site_level_licenses_for_mapped_domain_multisite(): bool { return (bool) apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_licenses_for_mapped_domain_multisite', - self::$supports_site_level_licenses_for_mapped_domain_multisite + static::$supports_site_level_licenses_for_mapped_domain_multisite ); } @@ -321,9 +321,9 @@ public static function supports_site_level_licenses_for_mapped_domain_multisite( */ public static function supports_network_licenses(): bool { $config = [ - self::supports_site_level_licenses_for_subfolder_multisite(), - self::supports_site_level_licenses_for_subdomain_multisite(), - self::supports_site_level_licenses_for_mapped_domain_multisite(), + static::supports_site_level_licenses_for_subfolder_multisite(), + static::supports_site_level_licenses_for_subdomain_multisite(), + static::supports_site_level_licenses_for_mapped_domain_multisite(), ]; return in_array( true, $config, true ); @@ -338,7 +338,7 @@ public static function supports_network_licenses(): bool { * @return void */ public static function allow_site_level_override_for_multisite_license( bool $allowed ): void { - self::$supports_site_level_override_for_multisite_license = $allowed; + static::$supports_site_level_override_for_multisite_license = $allowed; } /** @@ -349,7 +349,7 @@ public static function allow_site_level_override_for_multisite_license( bool $al public static function supports_site_level_override_for_multisite_license(): bool { return (bool) apply_filters( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/supports_site_level_override_for_multisite_license', - self::$supports_site_level_override_for_multisite_license + static::$supports_site_level_override_for_multisite_license ); } From 3132afaab04688773fec17c2ee2dc88a14adf6dc Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 4 Jan 2024 10:01:45 -0700 Subject: [PATCH 71/72] Add a default state for multisite config options, and properly reset them --- src/Uplink/Config.php | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Uplink/Config.php b/src/Uplink/Config.php index b729548e..6aa9fcb2 100644 --- a/src/Uplink/Config.php +++ b/src/Uplink/Config.php @@ -17,6 +17,13 @@ class Config { */ public const DEFAULT_AUTH_CACHE = 21600; + /** + * The default state for all multisite licensing options. + * + * @var bool + */ + public const DEFAULT_MULTISITE_STATE = false; + /** * Container object. * @@ -48,21 +55,21 @@ class Config { * * @var bool */ - protected static $supports_site_level_licenses_for_subfolder_multisite = false; + protected static $supports_site_level_licenses_for_subfolder_multisite = self::DEFAULT_MULTISITE_STATE; /** * Whether your plugin allows multisite subdomain licenses. * * @var bool */ - protected static $supports_site_level_licenses_for_subdomain_multisite = false; + protected static $supports_site_level_licenses_for_subdomain_multisite = self::DEFAULT_MULTISITE_STATE; /** * Whether your plugin allows multisite domain mapping licenses. * * @var bool */ - protected static $supports_site_level_licenses_for_mapped_domain_multisite = false; + protected static $supports_site_level_licenses_for_mapped_domain_multisite = self::DEFAULT_MULTISITE_STATE; /** * If true, enables a checkbox in the License Field so that you can use a local license key @@ -70,7 +77,7 @@ class Config { * * @var bool */ - protected static $supports_site_level_override_for_multisite_license = false; + protected static $supports_site_level_override_for_multisite_license = self::DEFAULT_MULTISITE_STATE; /** * Get the container. @@ -144,8 +151,12 @@ public static function has_container(): bool { * @return void */ public static function reset(): void { - static::$hook_prefix = ''; - static::$auth_cache_expiration = self::DEFAULT_AUTH_CACHE; + static::$hook_prefix = ''; + static::$auth_cache_expiration = self::DEFAULT_AUTH_CACHE; + static::$supports_site_level_licenses_for_subfolder_multisite = self::DEFAULT_MULTISITE_STATE; + static::$supports_site_level_licenses_for_subdomain_multisite = self::DEFAULT_MULTISITE_STATE; + static::$supports_site_level_licenses_for_mapped_domain_multisite = self::DEFAULT_MULTISITE_STATE; + static::$supports_site_level_override_for_multisite_license = self::DEFAULT_MULTISITE_STATE; if ( self::has_container() ) { self::$container->singleton( self::TOKEN_OPTION_NAME, null ); From dc3e890e699fe882f309a5bc790f97260410db61 Mon Sep 17 00:00:00 2001 From: Justin Frydman Date: Thu, 4 Jan 2024 10:02:08 -0700 Subject: [PATCH 72/72] Update base testcase to fix merge issue and use config::reset() --- tests/_support/Helper/UplinkTestCase.php | 54 ++++++------------------ 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/tests/_support/Helper/UplinkTestCase.php b/tests/_support/Helper/UplinkTestCase.php index 13269d12..65e63d9d 100644 --- a/tests/_support/Helper/UplinkTestCase.php +++ b/tests/_support/Helper/UplinkTestCase.php @@ -1,4 +1,4 @@ -container = Config::get_container(); - - $this->network_subfolder_license = Config::supports_site_level_licenses_for_subfolder_multisite(); - $this->network_subdomain_license = Config::supports_site_level_licenses_for_subdomain_multisite(); - $this->network_domain_mapping_license = Config::supports_site_level_licenses_for_mapped_domain_multisite(); } protected function tearDown(): void { - // Reset back to default config, in case any tests changed them. - Config::allow_site_level_licenses_for_subfolder_multisite( $this->network_subfolder_license ); - Config::allow_site_level_licenses_for_subdomain_multisite( $this->network_subdomain_license ); - Config::allow_site_level_licenses_for_mapped_domain_multisite( $this->network_domain_mapping_license ); + Config::reset(); parent::tearDown(); } /** - * @param string $path The path to the plugin file, e.g. my-plugin/my-plugin.php - * @param bool $network_wide Whether this should happen network wide. + * Fake that WordPress has a plugin activated by manually inserting the records. + * + * @param string $path The path to the plugin file, e.g. my-plugin/my-plugin.php + * @param bool $network_wide Whether this should happen network wide. * * @return void */ @@ -83,18 +57,14 @@ protected function mock_activate_plugin( string $path, bool $network_wide = fals $current[ $path ] = time(); update_site_option( 'active_sitewide_plugins', $current ); - } else { - update_option( - 'active_plugins', - array_merge(get_option('active_plugins', []), [$path]) - ); - } - } - protected function tearDown(): void { - Config::reset(); + return; + } - parent::tearDown(); + update_option( + 'active_plugins', + array_merge( get_option( 'active_plugins', [] ), [ $path ] ) + ); } }