Phase 5: Content and SEO - Yoast SEO, Schema.org markup, Open Graph, favicon support, XML sitemap
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Application;
|
||||
|
||||
use Yoast\WP\SEO\AI_Authorization\Domain\Code_Verifier;
|
||||
|
||||
/**
|
||||
* Interface Code_Verifier_Handler_Interface
|
||||
*
|
||||
* This interface defines the methods for handling code verifier.
|
||||
*/
|
||||
interface Code_Verifier_Handler_Interface {
|
||||
|
||||
/**
|
||||
* Generate a code verifier for a user.
|
||||
*
|
||||
* @param string $user_email The user email.
|
||||
*
|
||||
* @return Code_Verifier The generated code verifier.
|
||||
*/
|
||||
public function generate( string $user_email ): Code_Verifier;
|
||||
|
||||
/**
|
||||
* Validate the code verifier for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return string The code verifier.
|
||||
*
|
||||
* @throws RuntimeException If the code verifier is expired or invalid.
|
||||
*/
|
||||
public function validate( int $user_id ): string;
|
||||
}
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Application;
|
||||
|
||||
use RuntimeException;
|
||||
use Yoast\WP\SEO\AI_Authorization\Domain\Code_Verifier;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Code_Verifier_User_Meta_Repository;
|
||||
use Yoast\WP\SEO\Helpers\Date_Helper;
|
||||
/**
|
||||
* Class Code_Verifier_Service
|
||||
* Handles the generation and validation of code verifiers for users.
|
||||
*/
|
||||
class Code_Verifier_Handler implements Code_Verifier_Handler_Interface {
|
||||
private const VALIDITY_IN_SECONDS = 300; // 5 minutes
|
||||
|
||||
/**
|
||||
* The date helper.
|
||||
*
|
||||
* @var Date_Helper
|
||||
*/
|
||||
private $date_helper;
|
||||
|
||||
/**
|
||||
* The code verifier repository.
|
||||
*
|
||||
* @var Code_Verifier_User_Meta_Repository
|
||||
*/
|
||||
private $code_verifier_repository;
|
||||
|
||||
/**
|
||||
* Code_Verifier_Service constructor.
|
||||
*
|
||||
* @param Date_Helper $date_helper The date helper.
|
||||
* @param Code_Verifier_User_Meta_Repository $code_verifier_repository The code verifier repository.
|
||||
*/
|
||||
public function __construct( Date_Helper $date_helper, Code_Verifier_User_Meta_Repository $code_verifier_repository ) {
|
||||
$this->date_helper = $date_helper;
|
||||
$this->code_verifier_repository = $code_verifier_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a code verifier for a user.
|
||||
*
|
||||
* @param string $user_email The user email.
|
||||
*
|
||||
* @return Code_Verifier The generated code verifier.
|
||||
*/
|
||||
public function generate( string $user_email ): Code_Verifier {
|
||||
$random_string = \substr( \str_shuffle( '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ), 1, 10 );
|
||||
$code = \hash( 'sha256', $user_email . $random_string );
|
||||
$created_at = $this->date_helper->current_time();
|
||||
|
||||
return new Code_Verifier( $code, $created_at );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the code verifier for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return string The code verifier.
|
||||
*
|
||||
* @throws RuntimeException If the code verifier is expired or invalid.
|
||||
*/
|
||||
public function validate( int $user_id ): string {
|
||||
$code_verifier = $this->code_verifier_repository->get_code_verifier( $user_id );
|
||||
|
||||
if ( $code_verifier === null || $code_verifier->is_expired( self::VALIDITY_IN_SECONDS ) ) {
|
||||
$this->code_verifier_repository->delete_code_verifier( $user_id );
|
||||
throw new RuntimeException( 'Code verifier has expired or is invalid.' );
|
||||
}
|
||||
|
||||
return $code_verifier->get_code();
|
||||
}
|
||||
}
|
||||
Executable
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Application;
|
||||
|
||||
use RuntimeException;
|
||||
use WP_User;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Bad_Request_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Forbidden_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Internal_Server_Error_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Not_Found_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Payment_Required_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Request_Timeout_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Service_Unavailable_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Too_Many_Requests_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Unauthorized_Exception;
|
||||
|
||||
/**
|
||||
* Interface Token_Manager_Interface
|
||||
*/
|
||||
interface Token_Manager_Interface {
|
||||
|
||||
/**
|
||||
* Invalidates the access token.
|
||||
*
|
||||
* @param string $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the access token.
|
||||
*/
|
||||
public function token_invalidate( string $user_id ): void;
|
||||
|
||||
/**
|
||||
* Requests a new set of JWT tokens.
|
||||
*
|
||||
* Requests a new JWT access and refresh token for a user from the Yoast AI Service and stores it in the database
|
||||
* under usermeta. The storing of the token happens in a HTTP callback that is triggered by this request.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
*/
|
||||
public function token_request( WP_User $user ): void;
|
||||
|
||||
/**
|
||||
* Refreshes the JWT access token.
|
||||
*
|
||||
* Refreshes a stored JWT access token for a user with the Yoast AI Service and stores it in the database under
|
||||
* usermeta. The storing of the token happens in a HTTP callback that is triggered by this request.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the refresh token.
|
||||
*/
|
||||
public function token_refresh( WP_User $user ): void;
|
||||
|
||||
/**
|
||||
* Checks whether the token has expired.
|
||||
*
|
||||
* @param string $jwt The JWT.
|
||||
*
|
||||
* @return bool Whether the token has expired.
|
||||
*/
|
||||
public function has_token_expired( string $jwt ): bool;
|
||||
|
||||
/**
|
||||
* Retrieves the access token.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return string The access token.
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the access or refresh token.
|
||||
*/
|
||||
public function get_or_request_access_token( WP_User $user ): string;
|
||||
}
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Application;
|
||||
|
||||
use RuntimeException;
|
||||
use WP_User;
|
||||
use WPSEO_Utils;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Access_Token_User_Meta_Repository_Interface;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Code_Verifier_User_Meta_Repository;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Refresh_Token_User_Meta_Repository_Interface;
|
||||
use Yoast\WP\SEO\AI_Consent\Application\Consent_Handler;
|
||||
use Yoast\WP\SEO\AI_Generator\Infrastructure\WordPress_URLs;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Application\Request_Handler;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Bad_Request_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Forbidden_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Internal_Server_Error_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Not_Found_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Payment_Required_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Request_Timeout_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Service_Unavailable_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Too_Many_Requests_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Unauthorized_Exception;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Request;
|
||||
use Yoast\WP\SEO\Helpers\User_Helper;
|
||||
|
||||
/**
|
||||
* Class Token_Manager
|
||||
* Handles the management of JWT tokens used in the authorization process.
|
||||
*
|
||||
* @makePublic
|
||||
*/
|
||||
class Token_Manager implements Token_Manager_Interface {
|
||||
|
||||
/**
|
||||
* The access token repository.
|
||||
*
|
||||
* @var Access_Token_User_Meta_Repository_Interface
|
||||
*/
|
||||
private $access_token_repository;
|
||||
|
||||
/**
|
||||
* The code verifier service.
|
||||
*
|
||||
* @var Code_Verifier_Handler
|
||||
*/
|
||||
private $code_verifier;
|
||||
|
||||
/**
|
||||
* The consent handler.
|
||||
*
|
||||
* @var Consent_Handler
|
||||
*/
|
||||
private $consent_handler;
|
||||
|
||||
/**
|
||||
* The refresh token repository.
|
||||
*
|
||||
* @var Refresh_Token_User_Meta_Repository_Interface
|
||||
*/
|
||||
private $refresh_token_repository;
|
||||
|
||||
/**
|
||||
* The user helper.
|
||||
*
|
||||
* @var User_Helper
|
||||
*/
|
||||
private $user_helper;
|
||||
|
||||
/**
|
||||
* The code verifier repository.
|
||||
*
|
||||
* @var Code_Verifier_User_Meta_Repository
|
||||
*/
|
||||
private $code_verifier_repository;
|
||||
|
||||
/**
|
||||
* The URLs service.
|
||||
*
|
||||
* @var WordPress_URLs
|
||||
*/
|
||||
private $urls;
|
||||
|
||||
/**
|
||||
* The request handler.
|
||||
*
|
||||
* @var Request_Handler
|
||||
*/
|
||||
private $request_handler;
|
||||
|
||||
/**
|
||||
* Token_Manager constructor.
|
||||
*
|
||||
* @param Access_Token_User_Meta_Repository_Interface $access_token_repository The access token repository.
|
||||
* @param Code_Verifier_Handler $code_verifier The code verifier service.
|
||||
* @param Consent_Handler $consent_handler The consent handler.
|
||||
* @param Refresh_Token_User_Meta_Repository_Interface $refresh_token_repository The refresh token repository.
|
||||
* @param User_Helper $user_helper The user helper.
|
||||
* @param Request_Handler $request_handler The request handler.
|
||||
* @param Code_Verifier_User_Meta_Repository $code_verifier_repository The code verifier repository.
|
||||
* @param WordPress_URLs $urls The URLs service.
|
||||
*/
|
||||
public function __construct(
|
||||
Access_Token_User_Meta_Repository_Interface $access_token_repository,
|
||||
Code_Verifier_Handler $code_verifier,
|
||||
Consent_Handler $consent_handler,
|
||||
Refresh_Token_User_Meta_Repository_Interface $refresh_token_repository,
|
||||
User_Helper $user_helper,
|
||||
Request_Handler $request_handler,
|
||||
Code_Verifier_User_Meta_Repository $code_verifier_repository,
|
||||
WordPress_URLs $urls
|
||||
) {
|
||||
$this->access_token_repository = $access_token_repository;
|
||||
$this->code_verifier = $code_verifier;
|
||||
$this->consent_handler = $consent_handler;
|
||||
$this->refresh_token_repository = $refresh_token_repository;
|
||||
$this->user_helper = $user_helper;
|
||||
$this->request_handler = $request_handler;
|
||||
$this->code_verifier_repository = $code_verifier_repository;
|
||||
$this->urls = $urls;
|
||||
}
|
||||
|
||||
// phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- PHPCS doesn't take into account exceptions thrown in called methods.
|
||||
|
||||
/**
|
||||
* Invalidates the access token.
|
||||
*
|
||||
* @param string $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the access token.
|
||||
*/
|
||||
public function token_invalidate( string $user_id ): void {
|
||||
try {
|
||||
$access_jwt = $this->access_token_repository->get_token( $user_id );
|
||||
} catch ( RuntimeException $e ) {
|
||||
$access_jwt = '';
|
||||
}
|
||||
|
||||
$request_body = [
|
||||
'user_id' => (string) $user_id,
|
||||
];
|
||||
$request_headers = [
|
||||
'Authorization' => "Bearer $access_jwt",
|
||||
];
|
||||
|
||||
try {
|
||||
$this->request_handler->handle(
|
||||
new Request(
|
||||
'/token/invalidate',
|
||||
$request_body,
|
||||
$request_headers
|
||||
)
|
||||
);
|
||||
} catch ( Unauthorized_Exception | Forbidden_Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch -- Reason: Ignored on purpose.
|
||||
// If the credentials in our request were already invalid, our job is done and we continue to remove the tokens client-side.
|
||||
}
|
||||
|
||||
// Delete the stored JWT tokens.
|
||||
$this->user_helper->delete_meta( $user_id, '_yoast_wpseo_ai_generator_access_jwt' );
|
||||
$this->user_helper->delete_meta( $user_id, '_yoast_wpseo_ai_generator_refresh_jwt' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a new set of JWT tokens.
|
||||
*
|
||||
* Requests a new JWT access and refresh token for a user from the Yoast AI Service and stores it in the database
|
||||
* under usermeta. The storing of the token happens in a HTTP callback that is triggered by this request.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
*/
|
||||
public function token_request( WP_User $user ): void {
|
||||
// Ensure the user has given consent.
|
||||
if ( $this->user_helper->get_meta( $user->ID, '_yoast_wpseo_ai_consent', true ) !== '1' ) {
|
||||
// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- false positive.
|
||||
$this->consent_handler->revoke_consent( $user->ID );
|
||||
throw new Forbidden_Exception( 'CONSENT_REVOKED', 403 );
|
||||
|
||||
// phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
// Generate a code verifier and store it in the database.
|
||||
$code_verifier = $this->code_verifier->generate( $user->user_email );
|
||||
$this->code_verifier_repository->store_code_verifier( $user->ID, $code_verifier->get_code(), $code_verifier->get_created_at() );
|
||||
|
||||
$request_body = [
|
||||
'service' => 'openai',
|
||||
'code_challenge' => \hash( 'sha256', $code_verifier->get_code() ),
|
||||
'license_site_url' => WPSEO_Utils::get_home_url(),
|
||||
'user_id' => (string) $user->ID,
|
||||
'callback_url' => $this->urls->get_callback_url(),
|
||||
'refresh_callback_url' => $this->urls->get_refresh_callback_url(),
|
||||
];
|
||||
|
||||
$this->request_handler->handle( new Request( '/token/request', $request_body ) );
|
||||
|
||||
// The callback saves the metadata. Because that is in another session, we need to delete the current cache here. Or we may get the old token.
|
||||
\wp_cache_delete( $user->ID, 'user_meta' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the JWT access token.
|
||||
*
|
||||
* Refreshes a stored JWT access token for a user with the Yoast AI Service and stores it in the database under
|
||||
* usermeta. The storing of the token happens in a HTTP callback that is triggered by this request.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the refresh token.
|
||||
*/
|
||||
public function token_refresh( WP_User $user ): void {
|
||||
$refresh_jwt = $this->refresh_token_repository->get_token( $user->ID );
|
||||
|
||||
// Generate a code verifier and store it in the database.
|
||||
$code_verifier = $this->code_verifier->generate( $user->ID, $user->user_email );
|
||||
$this->code_verifier_repository->store_code_verifier( $user->ID, $code_verifier->get_code(), $code_verifier->get_created_at() );
|
||||
|
||||
$request_body = [
|
||||
'code_challenge' => \hash( 'sha256', $code_verifier->get_code() ),
|
||||
];
|
||||
$request_headers = [
|
||||
'Authorization' => "Bearer $refresh_jwt",
|
||||
];
|
||||
|
||||
$this->request_handler->handle( new Request( '/token/refresh', $request_body, $request_headers ) );
|
||||
|
||||
// The callback saves the metadata. Because that is in another session, we need to delete the current cache here. Or we may get the old token.
|
||||
\wp_cache_delete( $user->ID, 'user_meta' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the token has expired.
|
||||
*
|
||||
* @param string $jwt The JWT.
|
||||
*
|
||||
* @return bool Whether the token has expired.
|
||||
*/
|
||||
public function has_token_expired( string $jwt ): bool {
|
||||
$parts = \explode( '.', $jwt );
|
||||
if ( \count( $parts ) !== 3 ) {
|
||||
// Headers, payload and signature parts are not detected.
|
||||
return true;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Reason: Decoding the payload of the JWT.
|
||||
$payload = \base64_decode( $parts[1] );
|
||||
$json = \json_decode( $payload );
|
||||
if ( $json === null || ! isset( $json->exp ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure exp is a valid numeric value.
|
||||
if ( ! \is_numeric( $json->exp ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $json->exp < \time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the access token.
|
||||
*
|
||||
* @param WP_User $user The WP user.
|
||||
*
|
||||
* @return string The access token.
|
||||
*
|
||||
* @throws Bad_Request_Exception Bad_Request_Exception.
|
||||
* @throws Forbidden_Exception Forbidden_Exception.
|
||||
* @throws Internal_Server_Error_Exception Internal_Server_Error_Exception.
|
||||
* @throws Not_Found_Exception Not_Found_Exception.
|
||||
* @throws Payment_Required_Exception Payment_Required_Exception.
|
||||
* @throws Request_Timeout_Exception Request_Timeout_Exception.
|
||||
* @throws Service_Unavailable_Exception Service_Unavailable_Exception.
|
||||
* @throws Too_Many_Requests_Exception Too_Many_Requests_Exception.
|
||||
* @throws Unauthorized_Exception Unauthorized_Exception.
|
||||
* @throws RuntimeException Unable to retrieve the access or refresh token.
|
||||
*/
|
||||
public function get_or_request_access_token( WP_User $user ): string {
|
||||
$access_jwt = $this->user_helper->get_meta( $user->ID, '_yoast_wpseo_ai_generator_access_jwt', true );
|
||||
if ( ! \is_string( $access_jwt ) || $access_jwt === '' ) {
|
||||
$this->token_request( $user );
|
||||
$access_jwt = $this->access_token_repository->get_token( $user->ID );
|
||||
}
|
||||
elseif ( $this->has_token_expired( $access_jwt ) ) {
|
||||
try {
|
||||
$this->token_refresh( $user );
|
||||
} catch ( Unauthorized_Exception $exception ) {
|
||||
$this->token_request( $user );
|
||||
} catch ( Forbidden_Exception $exception ) {
|
||||
// Follow the API in the consent being revoked (Use case: user sent an e-mail to revoke?).
|
||||
// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- false positive.
|
||||
$this->consent_handler->revoke_consent( $user->ID );
|
||||
throw new Forbidden_Exception( 'CONSENT_REVOKED', 403 );
|
||||
// phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
$access_jwt = $this->access_token_repository->get_token( $user->ID );
|
||||
}
|
||||
|
||||
return $access_jwt;
|
||||
}
|
||||
|
||||
// phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Domain;
|
||||
|
||||
/**
|
||||
* Class Code_Verifier representing a challenge code and its creation time.
|
||||
* This is used during the authorization process to verify the user requesting a token.
|
||||
*/
|
||||
class Code_Verifier {
|
||||
|
||||
/**
|
||||
* The code.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $code;
|
||||
|
||||
/**
|
||||
* The time the code was created.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $created_at;
|
||||
|
||||
/**
|
||||
* Code_Verifier constructor.
|
||||
*
|
||||
* @param string $code The code.
|
||||
* @param int $created_at The time the code was created.
|
||||
*/
|
||||
public function __construct( string $code, int $created_at ) {
|
||||
$this->code = $code;
|
||||
$this->created_at = $created_at;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code.
|
||||
*
|
||||
* @return string The code.
|
||||
*/
|
||||
public function get_code(): string {
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the creation time of the code.
|
||||
*
|
||||
* @return int The creation time of the code.
|
||||
*/
|
||||
public function get_created_at(): int {
|
||||
return $this->created_at;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the code is expired.
|
||||
*
|
||||
* @param int $validity_in_seconds The validity of the code in seconds.
|
||||
*
|
||||
* @return bool True if the code is expired, false otherwise.
|
||||
*/
|
||||
public function is_expired( int $validity_in_seconds ): bool {
|
||||
return $this->created_at < ( \time() - $validity_in_seconds );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Domain;
|
||||
|
||||
/**
|
||||
* Class Token
|
||||
* Represents a token used for authentication with the AI Generator API.
|
||||
*/
|
||||
class Token {
|
||||
|
||||
/**
|
||||
* The token value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* The expiration time.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $expiration;
|
||||
|
||||
/**
|
||||
* Token constructor.
|
||||
*
|
||||
* @param string $value The token value.
|
||||
* @param int $expiration The expiration time.
|
||||
*/
|
||||
public function __construct( string $value, int $expiration ) {
|
||||
$this->value = $value;
|
||||
$this->expiration = $expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token value.
|
||||
*
|
||||
* @return string The token value.
|
||||
*/
|
||||
public function get_value(): string {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the token is expired.
|
||||
*
|
||||
* @return bool True if the token is expired, false otherwise.
|
||||
*/
|
||||
public function is_expired(): bool {
|
||||
return $this->expiration < \time();
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
/**
|
||||
* Interface Access_Token_User_Meta_Repository_Interface
|
||||
*
|
||||
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
*/
|
||||
interface Access_Token_User_Meta_Repository_Interface extends Token_User_Meta_Repository_Interface {
|
||||
public const META_KEY = '_yoast_wpseo_ai_generator_access_jwt';
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
use RuntimeException;
|
||||
use Yoast\WP\SEO\Helpers\User_Helper;
|
||||
|
||||
/**
|
||||
* Class Access_Token_Repository
|
||||
* Handles the storage and retrieval of access tokens for users.
|
||||
*/
|
||||
class Access_Token_User_Meta_Repository implements Access_Token_User_Meta_Repository_Interface {
|
||||
|
||||
/**
|
||||
* The user helper.
|
||||
*
|
||||
* @var User_Helper
|
||||
*/
|
||||
private $user_helper;
|
||||
|
||||
/**
|
||||
* Access_Token_Repository constructor.
|
||||
*
|
||||
* @param User_Helper $user_helper The user helper.
|
||||
*/
|
||||
public function __construct( User_Helper $user_helper ) {
|
||||
$this->user_helper = $user_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return string The token data.
|
||||
*
|
||||
* @throws RuntimeException If the token is not found or invalid.
|
||||
*/
|
||||
public function get_token( int $user_id ): string {
|
||||
$access_jwt = $this->user_helper->get_meta( $user_id, self::META_KEY, true );
|
||||
if ( ! \is_string( $access_jwt ) || $access_jwt === '' ) {
|
||||
throw new RuntimeException( 'Unable to retrieve the access token.' );
|
||||
}
|
||||
|
||||
return $access_jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $value The token value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store_token( int $user_id, string $value ): void {
|
||||
$this->user_helper->update_meta(
|
||||
$user_id,
|
||||
self::META_KEY,
|
||||
$value
|
||||
); }
|
||||
|
||||
/**
|
||||
* Delete the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_token( int $user_id ): void {
|
||||
$this->user_helper->delete_meta( $user_id, self::META_KEY );
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
use RuntimeException;
|
||||
use Yoast\WP\SEO\AI_Authorization\Domain\Code_Verifier;
|
||||
|
||||
// phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
/**
|
||||
* Interface for the Code Verifier User Meta Repository.
|
||||
*
|
||||
* This interface defines methods for managing code verifiers associated with users.
|
||||
*/
|
||||
interface Code_Verifier_User_Meta_Repository_Interface {
|
||||
|
||||
/**
|
||||
* Get the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @throws RuntimeException If the code verifier is not found or has expired.
|
||||
* @return Code_Verifier The verification code or null if not found.
|
||||
*/
|
||||
public function get_code_verifier( int $user_id ): ?Code_Verifier;
|
||||
|
||||
/**
|
||||
* Store the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $code The code verifier.
|
||||
* @param int $created_at The time the code was created.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store_code_verifier( int $user_id, string $code, int $created_at ): void;
|
||||
|
||||
/**
|
||||
* Delete the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_code_verifier( int $user_id ): void;
|
||||
}
|
||||
//phpcs:enable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
use RuntimeException;
|
||||
use Yoast\WP\SEO\AI_Authorization\Domain\Code_Verifier;
|
||||
use Yoast\WP\SEO\Helpers\Date_Helper;
|
||||
use Yoast\WP\SEO\Helpers\User_Helper;
|
||||
/**
|
||||
* Class Code_Verifier_Repository
|
||||
*/
|
||||
class Code_Verifier_User_Meta_Repository implements Code_Verifier_User_Meta_Repository_Interface {
|
||||
|
||||
private const CODE_VERIFIER_VALIDITY = 300; // 5 minutes
|
||||
|
||||
/**
|
||||
* The date helper.
|
||||
*
|
||||
* @var Date_Helper
|
||||
*/
|
||||
private $date_helper;
|
||||
|
||||
/**
|
||||
* The user helper.
|
||||
*
|
||||
* @var User_Helper
|
||||
*/
|
||||
private $user_helper;
|
||||
|
||||
/**
|
||||
* Code_Verifier_Repository constructor.
|
||||
*
|
||||
* @param Date_Helper $date_helper The date helper.
|
||||
* @param User_Helper $user_helper The user helper.
|
||||
*/
|
||||
public function __construct( Date_Helper $date_helper, User_Helper $user_helper ) {
|
||||
$this->date_helper = $date_helper;
|
||||
$this->user_helper = $user_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $code The code verifier.
|
||||
* @param int $created_at The time the code was created.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store_code_verifier( int $user_id, string $code, int $created_at ): void {
|
||||
$this->user_helper->update_meta(
|
||||
$user_id,
|
||||
'yoast_wpseo_ai_generator_code_verifier_for_blog_' . \get_current_blog_id(),
|
||||
[
|
||||
'code' => $code,
|
||||
'created_at' => $created_at,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @throws RuntimeException If the code verifier is not found or has expired.
|
||||
* @return Code_Verifier The verification code or null if not found.
|
||||
*/
|
||||
public function get_code_verifier( int $user_id ): ?Code_Verifier {
|
||||
$data = $this->user_helper->get_meta( $user_id, 'yoast_wpseo_ai_generator_code_verifier_for_blog_' . \get_current_blog_id(), true );
|
||||
|
||||
if ( ! \is_array( $data ) || ! isset( $data['code'] ) || $data['code'] === '' ) {
|
||||
throw new RuntimeException( 'Unable to retrieve the verification code.' );
|
||||
}
|
||||
|
||||
if ( ! isset( $data['created_at'] ) || $data['created_at'] < ( $this->date_helper->current_time() - self::CODE_VERIFIER_VALIDITY ) ) {
|
||||
$this->delete_code_verifier( $user_id );
|
||||
throw new RuntimeException( 'Code verifier has expired.' );
|
||||
}
|
||||
|
||||
return new Code_Verifier( $data['code'], $data['created_at'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the verification code for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_code_verifier( int $user_id ): void {
|
||||
$this->user_helper->delete_meta( $user_id, 'yoast_wpseo_ai_generator_code_verifier_for_blog_' . \get_current_blog_id() );
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
/**
|
||||
* Interface Refresh_Token_User_Meta_Repository_Interface
|
||||
*
|
||||
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
*/
|
||||
interface Refresh_Token_User_Meta_Repository_Interface extends Token_User_Meta_Repository_Interface {
|
||||
public const META_KEY = '_yoast_wpseo_ai_generator_refresh_jwt';
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
use RuntimeException;
|
||||
use Yoast\WP\SEO\Helpers\User_Helper;
|
||||
|
||||
/**
|
||||
* Class Refresh_Token_Repository
|
||||
* Handles the storage and retrieval of refresh tokens for users.
|
||||
*/
|
||||
class Refresh_Token_User_Meta_Repository implements Refresh_Token_User_Meta_Repository_Interface {
|
||||
|
||||
/**
|
||||
* The user helper.
|
||||
*
|
||||
* @var User_Helper
|
||||
*/
|
||||
private $user_helper;
|
||||
|
||||
/**
|
||||
* Refresh_Token_Repository constructor.
|
||||
*
|
||||
* @param User_Helper $user_helper The user helper.
|
||||
*/
|
||||
public function __construct( User_Helper $user_helper ) {
|
||||
$this->user_helper = $user_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return string The token data.
|
||||
*
|
||||
* @throws RuntimeException If the token is not found or invalid.
|
||||
*/
|
||||
public function get_token( int $user_id ): string {
|
||||
$refresh_jwt = $this->user_helper->get_meta( $user_id, self::META_KEY, true );
|
||||
if ( ! \is_string( $refresh_jwt ) || $refresh_jwt === '' ) {
|
||||
throw new RuntimeException( 'Unable to retrieve the refresh token.' );
|
||||
}
|
||||
|
||||
return $refresh_jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $value The token value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store_token( int $user_id, string $value ): void {
|
||||
$this->user_helper->update_meta(
|
||||
$user_id,
|
||||
self::META_KEY,
|
||||
$value
|
||||
); }
|
||||
|
||||
/**
|
||||
* Delete the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_token( int $user_id ): void {
|
||||
$this->user_helper->delete_meta( $user_id, self::META_KEY );
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\AI_Authorization\Infrastructure;
|
||||
|
||||
/**
|
||||
* Interface Token_Repository_Interface
|
||||
*/
|
||||
interface Token_User_Meta_Repository_Interface {
|
||||
|
||||
/**
|
||||
* Get the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return string The token data.
|
||||
*/
|
||||
public function get_token( int $user_id ): string;
|
||||
|
||||
/**
|
||||
* Store the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
* @param string $value The token value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function store_token( int $user_id, string $value ): void;
|
||||
|
||||
/**
|
||||
* Delete the token for a user.
|
||||
*
|
||||
* @param int $user_id The user ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete_token( int $user_id ): void;
|
||||
}
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
|
||||
namespace Yoast\WP\SEO\AI_Authorization\User_Interface;
|
||||
|
||||
use RuntimeException;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Access_Token_User_Meta_Repository_Interface;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Code_Verifier_User_Meta_Repository_Interface;
|
||||
use Yoast\WP\SEO\AI_Authorization\Infrastructure\Refresh_Token_User_Meta_Repository_Interface;
|
||||
use Yoast\WP\SEO\AI_HTTP_Request\Domain\Exceptions\Unauthorized_Exception;
|
||||
use Yoast\WP\SEO\Conditionals\AI_Conditional;
|
||||
use Yoast\WP\SEO\Main;
|
||||
use Yoast\WP\SEO\Routes\Route_Interface;
|
||||
|
||||
/**
|
||||
* The base class for the callback routes.
|
||||
*/
|
||||
abstract class Abstract_Callback_Route implements Route_Interface {
|
||||
|
||||
/**
|
||||
* The namespace for this route.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const ROUTE_NAMESPACE = Main::API_V1_NAMESPACE;
|
||||
|
||||
/**
|
||||
* The access token repository instance.
|
||||
*
|
||||
* @var Access_Token_User_Meta_Repository_Interface
|
||||
*/
|
||||
protected $access_token_repository;
|
||||
|
||||
/**
|
||||
* The refresh token repository instance.
|
||||
*
|
||||
* @var Refresh_Token_User_Meta_Repository_Interface
|
||||
*/
|
||||
protected $refresh_token_repository;
|
||||
|
||||
/**
|
||||
* The code verifier instance.
|
||||
*
|
||||
* @var Code_Verifier_User_Meta_Repository_Interface
|
||||
*/
|
||||
protected $code_verifier_repository;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array<string> The conditionals.
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ AI_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback_Route constructor.
|
||||
*
|
||||
* @param Access_Token_User_Meta_Repository_Interface $access_token_repository The access token repository instance.
|
||||
* @param Refresh_Token_User_Meta_Repository_Interface $refresh_token_repository The refresh token repository instance.
|
||||
* @param Code_Verifier_User_Meta_Repository_Interface $code_verifier_repository The code verifier instance.
|
||||
*/
|
||||
public function __construct( Access_Token_User_Meta_Repository_Interface $access_token_repository, Refresh_Token_User_Meta_Repository_Interface $refresh_token_repository, Code_Verifier_User_Meta_Repository_Interface $code_verifier_repository ) {
|
||||
$this->access_token_repository = $access_token_repository;
|
||||
$this->refresh_token_repository = $refresh_token_repository;
|
||||
$this->code_verifier_repository = $code_verifier_repository;
|
||||
}
|
||||
|
||||
// phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- PHPCS doesn't take into account exceptions thrown in called methods.
|
||||
|
||||
/**
|
||||
* Runs the callback to store connection credentials and the tokens locally.
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response The response of the callback action.
|
||||
*
|
||||
* @throws Unauthorized_Exception If the code challenge is not valid.
|
||||
* @throws RuntimeException If the verification code is not found.
|
||||
*/
|
||||
public function callback( WP_REST_Request $request ): WP_REST_Response {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
try {
|
||||
$code_verifier = $this->code_verifier_repository->get_code_verifier( $user_id );
|
||||
|
||||
if ( $request->get_param( 'code_challenge' ) !== \hash( 'sha256', $code_verifier->get_code() ) ) {
|
||||
throw new Unauthorized_Exception( 'Unauthorized' );
|
||||
}
|
||||
|
||||
$this->access_token_repository->store_token( $user_id, $request->get_param( 'access_jwt' ) );
|
||||
$this->refresh_token_repository->store_token( $user_id, $request->get_param( 'refresh_jwt' ) );
|
||||
$this->code_verifier_repository->delete_code_verifier( $user_id );
|
||||
} catch ( Unauthorized_Exception | RuntimeException $e ) {
|
||||
return new WP_REST_Response( 'Unauthorized.', 401 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response(
|
||||
[
|
||||
'message' => 'Tokens successfully stored.',
|
||||
'code_verifier' => $code_verifier->get_code(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- PHPCS doesn't take into account exceptions thrown in called methods.
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
|
||||
namespace Yoast\WP\SEO\AI_Authorization\User_Interface;
|
||||
|
||||
/**
|
||||
* Registers the callback route used in the authorization process.
|
||||
*
|
||||
* @makePublic
|
||||
*
|
||||
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
*/
|
||||
class Callback_Route extends Abstract_Callback_Route {
|
||||
/**
|
||||
* The prefix for this route.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const ROUTE_PREFIX = '/ai_generator/callback';
|
||||
|
||||
/**
|
||||
* Registers routes with WordPress.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_routes() {
|
||||
\register_rest_route(
|
||||
parent::ROUTE_NAMESPACE,
|
||||
self::ROUTE_PREFIX,
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'args' => [
|
||||
'access_jwt' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The access JWT.',
|
||||
],
|
||||
'refresh_jwt' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The JWT to be used when the access JWT needs to be refreshed.',
|
||||
],
|
||||
'code_challenge' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The SHA266 of the verification code used to check the authenticity of a callback call.',
|
||||
],
|
||||
'user_id' => [
|
||||
'required' => true,
|
||||
'type' => 'integer',
|
||||
'description' => 'The id of the user associated to the code verifier.',
|
||||
],
|
||||
],
|
||||
'callback' => [ $this, 'callback' ],
|
||||
'permission_callback' => '__return_true',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
|
||||
namespace Yoast\WP\SEO\AI_Authorization\User_Interface;
|
||||
|
||||
/**
|
||||
* Registers the callback route used in the authorization process.
|
||||
*
|
||||
* @makePublic
|
||||
*
|
||||
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
|
||||
*/
|
||||
class Refresh_Callback_Route extends Abstract_Callback_Route {
|
||||
/**
|
||||
* The prefix for this route.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const ROUTE_PREFIX = '/ai_generator/refresh_callback';
|
||||
|
||||
/**
|
||||
* Registers routes with WordPress.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_routes() {
|
||||
\register_rest_route(
|
||||
parent::ROUTE_NAMESPACE,
|
||||
self::ROUTE_PREFIX,
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'args' => [
|
||||
'access_jwt' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The access JWT.',
|
||||
],
|
||||
'refresh_jwt' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The JWT to be used when the access JWT needs to be refreshed.',
|
||||
],
|
||||
'code_challenge' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'The SHA266 of the verification code used to check the authenticity of a callback call.',
|
||||
],
|
||||
'user_id' => [
|
||||
'required' => true,
|
||||
'type' => 'integer',
|
||||
'description' => 'The id of the user associated to the code verifier.',
|
||||
],
|
||||
],
|
||||
'callback' => [ $this, 'callback' ],
|
||||
'permission_callback' => '__return_true',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user