Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Token Manager / Auth / Token Connecting/Disconnecting #77

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;

}
10 changes: 7 additions & 3 deletions src/Uplink/API/V3/Auth/Token_Authorizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ public function __construct( Client_V3 $client ) {
* @see is_authorized()
*
* @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()
defunctl marked this conversation as resolved.
Show resolved Hide resolved
*/
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
124 changes: 124 additions & 0 deletions src/Uplink/Auth/Action_Manager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?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 Resource $resource The resource.
*
* @example stellarwp/uplink/my_hook_prefix/admin_action_my_plugin_slug
*
* @throws \RuntimeException
*
* @return string
*/
public function get_hook_name( Resource $resource ): string {
return sprintf( 'stellarwp/uplink/%s/%s_%s',
Config::get_hook_prefix(),
self::ACTION,
$resource->get_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 );

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;
}

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

/**
* Fires when an 'uplink_slug' request variable is sent.
*
* The dynamic portion of the hook name, `$action`, refers to
* the action derived from the `GET` or `POST` request.
*/
do_action( sprintf( 'stellarwp/uplink/%s/%s_%s',
Config::get_hook_prefix(),
self::ACTION,
$action
) );
defunctl marked this conversation as resolved.
Show resolved Hide resolved
}

}
Loading
Loading