storage = $storage; } abstract public function is_supported(): bool; abstract public function encrypt( string $value ): string; abstract public function decrypt( string $value ): string; } abstract class WP_Encrypted_Secret_Storage { abstract public function is_supported(): bool; abstract public function set( string $secret_key ): bool; abstract public function get(): ?string; } class WP_Encrypted_Secret_Storage_File extends WP_Encrypted_Secret_Storage { protected string $file; public function __construct( string $file_path ) { $this->file = $file_path; } public function is_supported(): bool { return is_writable( dirname( $this->file ) ); } public function set( string $secret_key ): bool { $secret = [ 'key' => base64_encode( $secret_key ), 'created' => time(), ]; $secret_stored = sprintf( 'is_supported() ) { return (bool) file_put_contents( $this->file, $secret_stored ); } return false; } public function get(): ?string { if ( is_readable( $this->file ) ) { $secret = include $this->file; if ( is_array( $secret ) && ! empty( $secret['key'] ) ) { return base64_decode( $secret['key'] ) ?? null; } } return null; } } class WP_Encrypted_Method_Sodium_Secretbox extends WP_Encrypted_Secret_Method { public function is_supported(): bool { return function_exists( 'sodium_crypto_secretbox_keygen' ) && function_exists( 'sodium_crypto_secretbox' ); } public function is_configured(): bool { return ! empty( $this->storage->get() ); } public function configure(): bool { if ( $this->is_supported() ) { return $this->storage->set( sodium_crypto_secretbox_keygen() ); } return false; } public function encrypt( string $value ): string { $secret_key = $this->storage->get(); if ( ! empty( $secret_key ) ) { $nonce = sodium_crypto_generichash( $value, '', SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); $encrypted = sodium_crypto_secretbox( $value, $nonce, $secret_key ); return base64_encode( $nonce . $encrypted ); } return $value; } public function decrypt( string $value ): string { $encrypted = base64_decode( $value ); $secret_key = $this->storage->get(); if ( $encrypted && ! empty( $secret_key ) ) { $nonce = substr( $encrypted, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); $encrypted = substr( $encrypted, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); if ( ! empty( $secret_key ) && ! empty( $nonce ) && ! empty( $encrypted ) ) { return sodium_crypto_secretbox_open( $encrypted, $nonce, $secret_key ); } } return $value; } } $storage = new WP_Encrypted_Secret_Storage_File( __DIR__ . '/secret.php' ); $method = new WP_Encrypted_Method_Sodium_Secretbox( $storage ); if ( $method->is_supported() && $storage->is_supported() ) { if ( ! $method->is_configured() ) { $method->configure(); } $encrypted = $method->encrypt( 'Hello, World!' ); var_dump( $encrypted, $method->decrypt( $encrypted ) ); //add_filter( 'option_' . $option_name, [ $option, 'decrypt' ] ); //add_filter( 'pre_update_option_' . $option_name, [ $option, 'encrypt' ] ); }