v0.1.0
This commit is contained in:
commit
bc1cb5e00a
32 changed files with 4254 additions and 0 deletions
111
includes/class-robotstxt-manager-encryption.php
Normal file
111
includes/class-robotstxt-manager-encryption.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
/**
|
||||
* AES-256-CBC encryption helper for the account-level API key.
|
||||
*
|
||||
* @package Robotstxt_Manager
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Robotstxt_Manager_Encryption
|
||||
*
|
||||
* Same symmetric AES-256-CBC pattern Plugins Core uses for its Forgejo
|
||||
* token. Encrypted values are base64-encoded strings with the IV prepended
|
||||
* to the ciphertext, safe for wp_options storage.
|
||||
*/
|
||||
class Robotstxt_Manager_Encryption {
|
||||
|
||||
/**
|
||||
* OpenSSL cipher method.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const CIPHER = 'aes-256-cbc';
|
||||
|
||||
/**
|
||||
* Context string used to derive a plugin-specific key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const CONTEXT = 'robotstxt_manager_encryption_v1';
|
||||
|
||||
/**
|
||||
* Encrypts a plaintext string and returns a base64-encoded payload.
|
||||
*
|
||||
* @param string $plaintext The value to encrypt.
|
||||
*
|
||||
* @return string Base64-encoded ciphertext, or empty string on failure.
|
||||
*/
|
||||
public static function encrypt( string $plaintext ): string {
|
||||
if ( '' === $plaintext ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$key = self::derive_key();
|
||||
$iv_length = openssl_cipher_iv_length( self::CIPHER );
|
||||
|
||||
if ( false === $iv_length ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$iv = openssl_random_pseudo_bytes( $iv_length );
|
||||
$ciphertext = openssl_encrypt( $plaintext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv );
|
||||
|
||||
if ( false === $ciphertext ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return base64_encode( $iv . $ciphertext ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a base64-encoded payload previously produced by encrypt().
|
||||
*
|
||||
* @param string $encoded The base64-encoded ciphertext.
|
||||
*
|
||||
* @return string The original plaintext, or empty string on failure.
|
||||
*/
|
||||
public static function decrypt( string $encoded ): string {
|
||||
if ( '' === $encoded ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$decoded = base64_decode( $encoded, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
|
||||
if ( false === $decoded ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$iv_length = openssl_cipher_iv_length( self::CIPHER );
|
||||
|
||||
if ( false === $iv_length || strlen( $decoded ) <= $iv_length ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$key = self::derive_key();
|
||||
$iv = substr( $decoded, 0, $iv_length );
|
||||
$ciphertext = substr( $decoded, $iv_length );
|
||||
$plaintext = openssl_decrypt( $ciphertext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv );
|
||||
|
||||
return false !== $plaintext ? $plaintext : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives a 32-byte encryption key from WordPress secret constants.
|
||||
*
|
||||
* @return string 32-byte raw key.
|
||||
*/
|
||||
private static function derive_key(): string {
|
||||
$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : 'auth_key_not_defined';
|
||||
$auth_salt = defined( 'AUTH_SALT' ) ? AUTH_SALT : 'auth_salt_not_defined';
|
||||
|
||||
return substr(
|
||||
hash_hmac( 'sha256', self::CONTEXT, $auth_key . $auth_salt, true ),
|
||||
0,
|
||||
32
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue