<?php
/**
 * Encryption trait.
 *
 * @package WP_Sites_Monitor
 * @author  Verdant Studio
 * @since   1.2.0
 */

namespace WPSitesMonitor\Traits;

/**
 * Exit when accessed directly.
 */
if ( ! defined( 'ABSPATH' )) {
	exit;
}

/**
 * Encryption trait.
 *
 * @since 1.2.0
 */
trait EncryptionTrait
{
	/**
	 * Key to use for encryption.
	 *
	 * @since 0.0.1
	 *
	 * @var string
	 */
	private $key;

	/**
	 * Salt to use for encryption.
	 *
	 * @since 0.0.1
	 *
	 * @var string
	 */
	private $salt;

	/**
	 * Constructor.
	 *
	 * @since 0.0.1
	 */
	public function initialize_encryption()
	{
		$this->key  = $this->get_default_key();
		$this->salt = $this->get_default_salt();
	}

	/**
	 * Gets the default encryption key to use.
	 *
	 * @since 0.0.1
	 */
	private function get_default_key(): string
	{

		if (defined( 'LOGGED_IN_KEY' ) && '' !== LOGGED_IN_KEY) {
			return LOGGED_IN_KEY;
		}

		// If this is reached, you're either not on a live site or have a serious security issue.
		return 'there-is-no-default-key-set';
	}

	/**
	 * Gets the default encryption salt to use.
	 *
	 * @since 0.0.1
	 */
	private function get_default_salt(): string
	{

		if (defined( 'LOGGED_IN_SALT' ) && '' !== LOGGED_IN_SALT) {
			return LOGGED_IN_SALT;
		}

		// If this is reached, you're either not on a live site or have a serious security issue.
		return 'there-is-no-default-salt-set';
	}

	/**
	 * Encrypts a value.
	 *
	 * If a user-based key is set, that key is used. Otherwise, the default key is used.
	 *
	 * @since 0.0.1
	 *
	 * @return string|bool Encrypted value, or false on failure.
	 */
	public function encrypt( string $value )
	{
		if ( ! extension_loaded( 'openssl' )) {
			return $value;
		}

		$method = 'aes-256-ctr';
		$ivlen  = openssl_cipher_iv_length( $method );
		$iv     = openssl_random_pseudo_bytes( $ivlen );

		$raw_value = openssl_encrypt( $value . $this->salt, $method, $this->key, 0, $iv );
		if ( ! $raw_value) {
			return false;
		}

		return base64_encode( $iv . $raw_value ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
	}

	/**
	 * Decrypts a value.
	 *
	 * If a user-based key is set, that key is used. Otherwise, the default key is used.
	 *
	 * @since 0.0.1
	 *
	 * @return string|bool Decrypted value, or false on failure.
	 */
	public function decrypt( string $raw_value )
	{
		if ( ! extension_loaded( 'openssl' )) {
			return $raw_value;
		}

		$raw_value = base64_decode( $raw_value, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode

		$method = 'aes-256-ctr';
		$ivlen  = openssl_cipher_iv_length( $method );
		$iv     = substr( $raw_value, 0, $ivlen );

		$raw_value = substr( $raw_value, $ivlen );

		$value = openssl_decrypt( $raw_value, $method, $this->key, 0, $iv );
		if ( ! $value || substr( $value, - strlen( $this->salt ) ) !== $this->salt) {
			return false;
		}

		return substr( $value, 0, - strlen( $this->salt ) );
	}
}
