🏠 Root
/
home
/
a
/
r
/
t
/
artorgp
/
www
/
wp-content
/
plugins
/
wordpress-seo
/
src
/
myyoast-client
/
infrastructure
/
token
/
Editing: token-storage.php
<?php // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure. namespace Yoast\WP\SEO\MyYoast_Client\Infrastructure\Token; use Exception; use Yoast\WP\SEO\MyYoast_Client\Application\Exceptions\Token_Storage_Exception; use Yoast\WP\SEO\MyYoast_Client\Application\Ports\Token_Storage_Interface; use Yoast\WP\SEO\MyYoast_Client\Domain\Token_Set; use Yoast\WP\SEO\MyYoast_Client\Infrastructure\Crypto\Encryption; use Yoast\WP\SEO\MyYoast_Client\Infrastructure\Crypto\Encryption_Exception; use Yoast\WP\SEO\MyYoast_Client\Infrastructure\OIDC\Issuer_Config; use YoastSEO_Vendor\Psr\Log\LoggerAwareInterface; use YoastSEO_Vendor\Psr\Log\LoggerAwareTrait; use YoastSEO_Vendor\Psr\Log\NullLogger; /** * Stores and retrieves encrypted site-level tokens as a WordPress option. * * Used for client_credentials tokens (site-level, no user context). * The option key is scoped by issuer so that switching issuers * isolates all stored data. */ class Token_Storage implements Token_Storage_Interface, LoggerAwareInterface { use LoggerAwareTrait; private const OPTION_KEY_PREFIX = 'wpseo_myyoast_site_tokens_'; private const ENCRYPTION_CONTEXT = 'yoast-myyoast-site-tokens'; /** * The encryption service. * * @var Encryption */ private $encryption; /** * The issuer configuration. * * @var Issuer_Config */ private $issuer_config; /** * Token_Storage constructor. * * @param Encryption $encryption The encryption service. * @param Issuer_Config $issuer_config The issuer configuration. */ public function __construct( Encryption $encryption, Issuer_Config $issuer_config ) { $this->encryption = $encryption; $this->issuer_config = $issuer_config; $this->logger = new NullLogger(); } /** * Stores a token set (encrypted). * * @param Token_Set $token_set The token set to store. * * @return void * * @throws Token_Storage_Exception If encryption fails. */ public function store( Token_Set $token_set ): void { try { // phpcs:ignore Yoast.Yoast.JsonEncodeAlternative.Found -- Encoding for encrypted storage, not user-facing output. $json = \wp_json_encode( $token_set->to_array() ); if ( $json === false ) { throw new Token_Storage_Exception( 'Failed to JSON-encode token set for storage.' ); } $encrypted = $this->encryption->encrypt( $json, self::ENCRYPTION_CONTEXT ); } catch ( Encryption_Exception $e ) { // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Internal exception message. throw new Token_Storage_Exception( 'Failed to encrypt token set for storage: ' . $e->getMessage(), 0, $e ); } \update_option( $this->get_option_key(), $encrypted, false ); } /** * Retrieves the stored token set. * * @return Token_Set|null The token set, or null if not stored or decryption fails. */ public function get(): ?Token_Set { $stored = \get_option( $this->get_option_key(), '' ); if ( ! \is_string( $stored ) || $stored === '' ) { return null; } try { $decrypted = $this->encryption->decrypt( $stored, self::ENCRYPTION_CONTEXT ); $data = \json_decode( $decrypted, true, 512, \JSON_THROW_ON_ERROR ); if ( ! \is_array( $data ) || empty( $data['access_token'] ) ) { return null; } return Token_Set::from_array( $data ); } catch ( Exception $e ) { $this->logger->error( 'Failed to decrypt stored site token: {error}', [ 'error' => $e->getMessage() ] ); return null; } } /** * Deletes the stored token set. * * @return void */ public function delete(): void { \delete_option( $this->get_option_key() ); } /** * Returns the issuer-scoped option key. * * @return string The option key. */ private function get_option_key(): string { return self::OPTION_KEY_PREFIX . $this->issuer_config->get_issuer_key(); } }
Save
Cancel