Skip to content

Commit

Permalink
Merge pull request #77 from stellarwp/feat/use-resource-for-token-man…
Browse files Browse the repository at this point in the history
…ager

Refactor Token Manager / Auth / Token Connecting/Disconnecting
  • Loading branch information
defunctl authored Jul 18, 2024
2 parents 625aa10 + 83947ba commit c774714
Show file tree
Hide file tree
Showing 37 changed files with 1,242 additions and 831 deletions.
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,12 @@ src/Uplink/Helper.php
The file should match the following - keeping the `KEY` constant set to a blank string, or, if you want a default license key, set it to that.:

```php
<?php
<?php declare( strict_types=1 );

namespace Whatever\Namespace\Uplink;

class Helper {
const KEY = '';
final class Helper {
public const KEY = '';
}
```

Expand Down Expand Up @@ -256,15 +257,15 @@ You can also pass in a custom license domain, which can be fetched on the Uplink
This connects to the licensing server to check in real time if the license is authorized. Use sparingly.

```php
$container = \StellarWP\Uplink\Config::get_container();
$token_manager = $container->get( \StellarWP\Uplink\Auth\Token\Contracts\Token_Manager::class );
$token = $token_manager->get();
$token = \StellarWP\Uplink\get_authorization_token( 'my-plugin-slug' );
$license_key = \StellarWP\Uplink\get_license_key( 'my-plugin-slug' );
$domain = \StellarWP\Uplink\get_license_domain();

if ( ! $token ) {
return;
if ( ! $token || ! $license_key || ! $domain ) {
return; // or, log/show errors.
}

$is_authorized = \StellarWP\Uplink\is_authorized( 'customer_license_key', $token, 'customer_domain' );
$is_authorized = \StellarWP\Uplink\is_authorized( $license_key, 'my-plugin-slug', $token, $domain );

echo $is_authorized ? esc_html__( 'authorized' ) : esc_html__( 'not authorized' );
```
Expand All @@ -274,13 +275,7 @@ echo $is_authorized ? esc_html__( 'authorized' ) : esc_html__( 'not authorized'
If for some reason you need to fetch your `auth_url` manually, you can do so by:

```php
$container = \StellarWP\Uplink\Config::get_container();
$auth_url_manager = $container->get( \StellarWP\Uplink\API\V3\Auth\Contracts\Auth_Url::class );

// Pass your product or service slug.
$auth_url = $auth_url_manager->get( 'kadence-blocks-pro' );

echo $auth_url;
echo esc_url( \StellarWP\Uplink\get_auth_url( 'my-plugin-slug' ) );
```

> 💡 Auth URL connections are cached for one day using transients.
Expand Down
3 changes: 2 additions & 1 deletion src/Uplink/API/V3/Auth/Contracts/Token_Authorizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ interface Token_Authorizer {
* @see \StellarWP\Uplink\API\V3\Auth\Token_Authorizer
*
* @param string $license The license key.
* @param string $slug The plugin/service slug.
* @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;
public function is_authorized( string $license, string $slug, string $token, string $domain ): bool;

}
11 changes: 8 additions & 3 deletions src/Uplink/API/V3/Auth/Token_Authorizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,21 @@ public function __construct( Client_V3 $client ) {
* Manually check if a license is authorized.
*
* @see is_authorized()
* @see Token_Authorizer_Cache_Decorator
*
* @param string $license The license key.
* @param string $token The stored token.
* @param string $domain The user's domain.
* @param string $slug The plugin/service slug.
* @param string $token The stored token.
* @param string $domain The user's domain.
*
* @return bool
*
* @see is_authorized()
*/
public function is_authorized( string $license, string $token, string $domain ): bool {
public function is_authorized( string $license, string $slug, string $token, string $domain ): bool {
$response = $this->client->get( 'tokens/auth', [
'license' => $license,
'slug' => $slug,
'token' => $token,
'domain' => $domain,
] );
Expand Down
22 changes: 17 additions & 5 deletions src/Uplink/API/V3/Auth/Token_Authorizer_Cache_Decorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,21 @@ public function __construct(
* @see Token_Authorizer
*
* @param string $license The license key.
* @param string $slug The plugin/service slug.
* @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 {
public function is_authorized( string $license, string $slug, 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 );
$is_authorized = $this->authorizer->is_authorized( $license, $slug, $token, $domain );

// Only cache successful responses.
if ( $is_authorized ) {
Expand All @@ -75,12 +76,23 @@ public function is_authorized( string $license, string $token, string $domain ):
/**
* Build a transient key.
*
* @param array<int, string> ...$args
* @param array<int, string> $args
*
* @return string
*/
public function build_transient( array ...$args ): string {
return self::TRANSIENT_PREFIX . hash( 'sha256', json_encode( $args ) );
public function build_transient( array $args ): string {
return self::TRANSIENT_PREFIX . $this->build_transient_no_prefix( $args );
}

/**
* Build a transient key without the prefix.
*
* @param array $args
*
* @return string
*/
public function build_transient_no_prefix( array $args ): string {
return hash( 'sha256', json_encode( $args ) );
}

}
4 changes: 4 additions & 0 deletions src/Uplink/Admin/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ public function ajax_validate_license(): void {
* @return void
*/
public function admin_init(): void {
if ( wp_doing_ajax() ) {
return;
}

$this->container->get( License_Field::class )->register_settings();
}

Expand Down
122 changes: 122 additions & 0 deletions src/Uplink/Auth/Action_Manager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php declare( strict_types=1 );

namespace StellarWP\Uplink\Auth;

use StellarWP\Uplink\Auth\Admin\Connect_Controller;
use StellarWP\Uplink\Auth\Admin\Disconnect_Controller;
use StellarWP\Uplink\Config;
use StellarWP\Uplink\Resources\Collection;
use StellarWP\Uplink\Resources\Resource;

/**
* Manages Token Authorization WordPress actions to connect/disconnect
* tokens.
*/
final class Action_Manager {

public const ACTION = 'admin_action';

/**
* @var Disconnect_Controller
*/
private $disconnect_controller;

/**
* @var Connect_Controller
*/
private $connect_controller;

/**
* @var Collection
*/
private $resources;

/**
* @param Disconnect_Controller $disconnect_controller
* @param Connect_Controller $connect_controller
* @param Collection $resources
*/
public function __construct(
Disconnect_Controller $disconnect_controller,
Connect_Controller $connect_controller,
Collection $resources
) {
$this->disconnect_controller = $disconnect_controller;
$this->connect_controller = $connect_controller;
$this->resources = $resources;
}

/**
* Get the resource's unique hook name.
*
* @param string $slug The plugin/service slug.
*
* @example stellarwp/uplink/my_hook_prefix/admin_action_my_plugin_slug
*
* @throws \RuntimeException
*
* @return string
*/
public function get_hook_name( string $slug ): string {
return sprintf( 'stellarwp/uplink/%s/%s_%s',
Config::get_hook_prefix(),
self::ACTION,
$slug
);
}

/**
* Register a unique action for each resource in order to fire off connect/disconnect logic
* uniquely so as one plugin would not interfere with another.
*
* @action admin_init
*
* @throws \RuntimeException
*
* @return void
*/
public function add_actions(): void {
foreach ( $this->resources as $resource ) {
$hook_name = $this->get_hook_name( $resource->get_slug() );

add_action(
$hook_name,
[ $this->disconnect_controller, 'maybe_disconnect' ]
);

add_action(
$hook_name,
[ $this->connect_controller, 'maybe_store_token_data' ]
);
}
}

/**
* When an `uplink_slug` query parameter is available, fire off the appropriate
* resource action.
*
* @action current_screen
*
* @throws \RuntimeException
*
* @return void
*/
public function do_action(): void {
if ( empty( $_REQUEST[ Disconnect_Controller::SLUG ] ) ) {
return;
}

$slug = $_REQUEST[ Disconnect_Controller::SLUG ];

/**
* Fires when an 'uplink_slug' request variable is sent.
*
* The dynamic portion of the hook name, `$slug`, refers to
* the action derived from the `GET` or `POST` request.
*
* @example stellarwp/uplink/my_hook_prefix/admin_action_my_plugin_slug
*/
do_action( $this->get_hook_name( $slug ) );
}

}
Loading

0 comments on commit c774714

Please sign in to comment.