🏠 Root
/
home
/
artorgp
/
www
/
wp-content
/
plugins
/
wordpress-seo
/
src
/
myyoast-client
/
infrastructure
/
token
/
Editing: user-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\Helpers\User_Helper; use Yoast\WP\SEO\MyYoast_Client\Application\Exceptions\Token_Storage_Exception; use Yoast\WP\SEO\MyYoast_Client\Application\Ports\User_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 user-level tokens in wp_usermeta. * * Used for authorization code flow tokens (user-specific). */ class User_Token_Storage implements User_Token_Storage_Interface, LoggerAwareInterface { use LoggerAwareTrait; private const META_KEY_PREFIX = '_wpseo_myyoast_user_tokens_'; private const ENCRYPTION_CONTEXT = 'yoast-myyoast-user-tokens'; /** * The user helper. * * @var User_Helper */ private $user_helper; /** * The encryption service. * * @var Encryption */ private $encryption; /** * The issuer configuration. * * @var Issuer_Config */ private $issuer_config; /** * User_Token_Storage constructor. * * @param User_Helper $user_helper The user helper. * @param Encryption $encryption The encryption service. * @param Issuer_Config $issuer_config The issuer configuration. */ public function __construct( User_Helper $user_helper, Encryption $encryption, Issuer_Config $issuer_config ) { $this->user_helper = $user_helper; $this->encryption = $encryption; $this->issuer_config = $issuer_config; $this->logger = new NullLogger(); } /** * Returns the issuer-scoped user meta key. * * @return string The meta key. */ private function get_meta_key(): string { return self::META_KEY_PREFIX . $this->issuer_config->get_issuer_key(); } /** * Stores a token set for a user (encrypted). * * @param int $user_id The user ID. * @param Token_Set $token_set The token set to store. * * @return void * * @throws Token_Storage_Exception If encryption fails. */ public function store( int $user_id, 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 ); } $this->user_helper->update_meta( $user_id, $this->get_meta_key(), $encrypted ); } /** * Retrieves the stored token set for a user. * * @param int $user_id The user ID. * * @return Token_Set|null The token set, or null if not stored or decryption fails. */ public function get( int $user_id ): ?Token_Set { $stored = $this->user_helper->get_meta( $user_id, $this->get_meta_key(), true ); 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 user token for user {user_id}: {error}', [ 'user_id' => $user_id, 'error' => $e->getMessage(), ], ); return null; } } /** * Deletes the stored token set for a user. * * @param int $user_id The user ID. * * @return void */ public function delete( int $user_id ): void { $this->user_helper->delete_meta( $user_id, $this->get_meta_key() ); } /** * Deletes all stored user token sets across all issuers. * This is used for cleanup on uninstall, as we cannot know which users had tokens stored. * Uses a LIKE match on the meta key prefix to ensure tokens from all issuers are removed. * * @return void */ public function delete_all(): void { global $wpdb; if ( isset( $wpdb ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Bulk cleanup on uninstall. $wpdb->query( $wpdb->prepare( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Bulk cleanup on uninstall. "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s", $wpdb->esc_like( self::META_KEY_PREFIX ) . '%', ), ); } } }
Save
Cancel