From 1d452bc71bcdb530b50155c05b692a96e4d4df02 Mon Sep 17 00:00:00 2001 From: netkas Date: Tue, 10 Dec 2024 13:30:08 -0500 Subject: [PATCH] Add session flags management and encryption key support --- .../Classes/CliCommands/InitializeCommand.php | 11 +- src/Socialbox/Classes/Configuration.php | 1 + .../Configuration/InstanceConfiguration.php | 145 ++++++++++-------- src/Socialbox/Classes/Cryptography.php | 21 +++ src/Socialbox/Enums/StandardError.php | 4 +- src/Socialbox/Enums/StandardMethods.php | 3 + src/Socialbox/Managers/SessionManager.php | 95 ++++++++++++ .../Objects/Database/SessionRecord.php | 5 - 8 files changed, 209 insertions(+), 76 deletions(-) diff --git a/src/Socialbox/Classes/CliCommands/InitializeCommand.php b/src/Socialbox/Classes/CliCommands/InitializeCommand.php index c45e09d..8498fea 100644 --- a/src/Socialbox/Classes/CliCommands/InitializeCommand.php +++ b/src/Socialbox/Classes/CliCommands/InitializeCommand.php @@ -3,7 +3,6 @@ namespace Socialbox\Classes\CliCommands; use Exception; -use LogLib\Log; use PDOException; use Socialbox\Abstracts\CacheLayer; use Socialbox\Classes\Configuration; @@ -97,22 +96,28 @@ class InitializeCommand implements CliCommandInterface } } - if(!Configuration::getInstanceConfiguration()->getPublicKey() || !Configuration::getInstanceConfiguration()->getPrivateKey()) + if( + !Configuration::getInstanceConfiguration()->getPublicKey() || + !Configuration::getInstanceConfiguration()->getPrivateKey() || + !Configuration::getInstanceConfiguration()->getEncryptionKey() + ) { try { Logger::getLogger()->info('Generating new key pair...'); $keyPair = Cryptography::generateKeyPair(); + $encryptionKey = Cryptography::randomBytes(230, 314); } catch (CryptographyException $e) { - Logger::getLogger()->error('Failed to generate keypair', $e); + Logger::getLogger()->error('Failed to generate cryptography values', $e); return 1; } Logger::getLogger()->info('Updating configuration...'); Configuration::getConfigurationLib()->set('instance.private_key', $keyPair->getPrivateKey()); Configuration::getConfigurationLib()->set('instance.public_key', $keyPair->getPublicKey()); + Configuration::getConfigurationLib()->set('instance.encryption_key', $encryptionKey); Configuration::getConfigurationLib()->save(); Logger::getLogger()->info(sprintf('Set the DNS TXT record for the domain %s to the following value:', Configuration::getInstanceConfiguration()->getDomain())); diff --git a/src/Socialbox/Classes/Configuration.php b/src/Socialbox/Classes/Configuration.php index d667097..c26c9fc 100644 --- a/src/Socialbox/Classes/Configuration.php +++ b/src/Socialbox/Classes/Configuration.php @@ -36,6 +36,7 @@ class Configuration $config->setDefault('instance.rpc_endpoint', null); $config->setDefault('instance.private_key', null); $config->setDefault('instance.public_key', null); + $config->setDefault('instance.encryption_key', null); // Security Configuration $config->setDefault('security.display_internal_exceptions', false); diff --git a/src/Socialbox/Classes/Configuration/InstanceConfiguration.php b/src/Socialbox/Classes/Configuration/InstanceConfiguration.php index 26ea951..4ebafc6 100644 --- a/src/Socialbox/Classes/Configuration/InstanceConfiguration.php +++ b/src/Socialbox/Classes/Configuration/InstanceConfiguration.php @@ -1,76 +1,87 @@ enabled = (bool)$data['enabled']; - $this->domain = $data['domain']; - $this->rpcEndpoint = $data['rpc_endpoint']; - $this->privateKey = $data['private_key']; - $this->publicKey = $data['public_key']; - } + private bool $enabled; + private ?string $domain; + private ?string $rpcEndpoint; + private ?string $privateKey; + private ?string $publicKey; + private ?string $encryptionKey; - /** - * Checks if the current object is enabled. - * - * @return bool True if the object is enabled, false otherwise. - */ - public function isEnabled(): bool - { - return $this->enabled; - } + /** + * Constructor that initializes object properties with the provided data. + * + * @param array $data An associative array with keys 'enabled', 'domain', 'private_key', and 'public_key'. + * @return void + */ + public function __construct(array $data) + { + $this->enabled = (bool)$data['enabled']; + $this->domain = $data['domain']; + $this->rpcEndpoint = $data['rpc_endpoint']; + $this->privateKey = $data['private_key']; + $this->publicKey = $data['public_key']; + $this->encryptionKey = $data['encryption_key']; + } - /** - * Retrieves the domain. - * - * @return string|null The domain. - */ - public function getDomain(): ?string - { - return $this->domain; - } + /** + * Checks if the current object is enabled. + * + * @return bool True if the object is enabled, false otherwise. + */ + public function isEnabled(): bool + { + return $this->enabled; + } - /** - * @return string|null - */ - public function getRpcEndpoint(): ?string - { - return $this->rpcEndpoint; - } + /** + * Retrieves the domain. + * + * @return string|null The domain. + */ + public function getDomain(): ?string + { + return $this->domain; + } - /** - * Retrieves the private key. - * - * @return string|null The private key. - */ - public function getPrivateKey(): ?string - { - return $this->privateKey; - } + /** + * @return string|null + */ + public function getRpcEndpoint(): ?string + { + return $this->rpcEndpoint; + } - /** - * Retrieves the public key. - * - * @return string|null The public key. - */ - public function getPublicKey(): ?string - { - return $this->publicKey; - } -} \ No newline at end of file + /** + * Retrieves the private key. + * + * @return string|null The private key. + */ + public function getPrivateKey(): ?string + { + return $this->privateKey; + } + + /** + * Retrieves the public key. + * + * @return string|null The public key. + */ + public function getPublicKey(): ?string + { + return $this->publicKey; + } + + /** + * Retrieves the encryption key. + * + * @return string|null The encryption key. + */ + public function getEncryptionKey(): ?string + { + return $this->encryptionKey; + } + } \ No newline at end of file diff --git a/src/Socialbox/Classes/Cryptography.php b/src/Socialbox/Classes/Cryptography.php index f69605d..7872d60 100644 --- a/src/Socialbox/Classes/Cryptography.php +++ b/src/Socialbox/Classes/Cryptography.php @@ -3,6 +3,7 @@ namespace Socialbox\Classes; use InvalidArgumentException; +use Random\RandomException; use Socialbox\Exceptions\CryptographyException; use Socialbox\Objects\KeyPair; @@ -266,4 +267,24 @@ class Cryptography return true; } + + /** + * Generates a random sequence of bytes with a length determined between the specified minimum and maximum. + * + * @param int $minLength The minimum length of the generated byte sequence. + * @param int $maxLength The maximum length of the generated byte sequence. + * @return string A hexadecimal string representing the random byte sequence. + * @throws CryptographyException If the random byte generation fails. + */ + public static function randomBytes(int $minLength, int $maxLength): string + { + try + { + return bin2hex(random_bytes(random_int($minLength, $maxLength))); + } + catch(RandomException $e) + { + throw new CryptographyException('Failed to generate random bytes: ' . $e->getMessage()); + } + } } \ No newline at end of file diff --git a/src/Socialbox/Enums/StandardError.php b/src/Socialbox/Enums/StandardError.php index 9ab424f..ad0c31c 100644 --- a/src/Socialbox/Enums/StandardError.php +++ b/src/Socialbox/Enums/StandardError.php @@ -31,6 +31,7 @@ enum StandardError : int case PEER_NOT_FOUND = -4000; case INVALID_USERNAME = -4001; case USERNAME_ALREADY_EXISTS = -4002; + case NOT_REGISTERED = -4003; /** * Returns the default generic message for the error @@ -62,7 +63,8 @@ enum StandardError : int self::PEER_NOT_FOUND => 'The requested peer was not found', self::INVALID_USERNAME => 'The given username is invalid, it must be Alphanumeric with a minimum of 3 character but no greater than 255 characters', - self::USERNAME_ALREADY_EXISTS => 'The given username already exists on the network' + self::USERNAME_ALREADY_EXISTS => 'The given username already exists on the network', + self::NOT_REGISTERED => 'The given username is not registered on the server', }; } diff --git a/src/Socialbox/Enums/StandardMethods.php b/src/Socialbox/Enums/StandardMethods.php index 6eb44cc..b454ec2 100644 --- a/src/Socialbox/Enums/StandardMethods.php +++ b/src/Socialbox/Enums/StandardMethods.php @@ -3,6 +3,7 @@ namespace Socialbox\Enums; use Socialbox\Classes\StandardMethods\CreateSession; +use Socialbox\Classes\StandardMethods\Identify; use Socialbox\Classes\StandardMethods\VerificationAnswerImageCaptcha; use Socialbox\Classes\StandardMethods\VerificationGetImageCaptcha; use Socialbox\Classes\StandardMethods\GetMe; @@ -18,6 +19,7 @@ enum StandardMethods : string case PING = 'ping'; case CREATE_SESSION = 'createSession'; case REGISTER = 'register'; + case IDENTIFY = 'identify'; case GET_ME = 'getMe'; case VERIFICATION_GET_IMAGE_CAPTCHA = 'verificationGetImageCaptcha'; case VERIFICATION_ANSWER_IMAGE_CAPTCHA = 'verificationAnswerImageCaptcha'; @@ -35,6 +37,7 @@ enum StandardMethods : string self::PING => Ping::execute($request, $rpcRequest), self::CREATE_SESSION => CreateSession::execute($request, $rpcRequest), self::REGISTER => Register::execute($request, $rpcRequest), + self::IDENTIFY => Identify::execute($request, $rpcRequest), self::GET_ME => GetMe::execute($request, $rpcRequest), self::VERIFICATION_GET_IMAGE_CAPTCHA => VerificationGetImageCaptcha::execute($request, $rpcRequest), self::VERIFICATION_ANSWER_IMAGE_CAPTCHA => VerificationAnswerImageCaptcha::execute($request, $rpcRequest), diff --git a/src/Socialbox/Managers/SessionManager.php b/src/Socialbox/Managers/SessionManager.php index 160eefc..f7565da 100644 --- a/src/Socialbox/Managers/SessionManager.php +++ b/src/Socialbox/Managers/SessionManager.php @@ -10,6 +10,7 @@ use Socialbox\Classes\Cryptography; use Socialbox\Classes\Database; use Socialbox\Classes\Logger; + use Socialbox\Classes\Utilities; use Socialbox\Enums\SessionState; use Socialbox\Enums\StandardError; use Socialbox\Exceptions\DatabaseOperationException; @@ -224,4 +225,98 @@ throw new DatabaseOperationException('Failed to update session state', $e); } } + + /** + * Retrieves the flags associated with a specific session. + * + * @param string $uuid The UUID of the session to retrieve flags for. + * @return array An array of flags associated with the specified session. + * @throws StandardException If the specified session does not exist. + * @throws DatabaseOperationException If there + */ + private static function getFlags(string $uuid): array + { + Logger::getLogger()->verbose(sprintf("Retrieving flags for session %s", $uuid)); + + try + { + $statement = Database::getConnection()->prepare("SELECT flags FROM sessions WHERE uuid=?"); + $statement->bindParam(1, $uuid); + $statement->execute(); + $data = $statement->fetch(PDO::FETCH_ASSOC); + + if ($data === false) + { + throw new StandardException(sprintf("The requested session '%s' does not exist", $uuid), StandardError::SESSION_NOT_FOUND); + } + + return Utilities::unserializeList($data['flags']); + } + catch (PDOException $e) + { + throw new DatabaseOperationException(sprintf('Failed to retrieve flags for session %s', $uuid), $e); + } + } + + /** + * Adds the specified flags to the session identified by the given UUID. + * + * @param string $uuid The unique identifier of the session to which the flags will be added. + * @param array $flags The flags to add to the session. + * @return void + * @throws DatabaseOperationException|StandardException If there is an error while updating the session in the database. + */ + public static function addFlags(string $uuid, array $flags): void + { + Logger::getLogger()->verbose(sprintf("Adding flags to session %s", $uuid)); + + // First get the existing flags + $existingFlags = self::getFlags($uuid); + + // Merge the new flags with the existing ones + $flags = array_unique(array_merge($existingFlags, $flags)); + + try + { + $statement = Database::getConnection()->prepare("UPDATE sessions SET flags=? WHERE uuid=?"); + $statement->bindValue(1, Utilities::serializeList($flags)); + $statement->bindParam(2, $uuid); + $statement->execute(); + } + catch (PDOException $e) + { + throw new DatabaseOperationException('Failed to add flags to session', $e); + } + } + + /** + * Removes specified flags from the session associated with the given UUID. + * + * @param string $uuid The UUID of the session from which the flags will be removed. + * @param array $flags An array of flags to be removed from the session. + * @return void + * @throws DatabaseOperationException|StandardException If there is an error while updating the session in the database. + */ + public static function removeFlags(string $uuid, array $flags): void + { + Logger::getLogger()->verbose(sprintf("Removing flags from session %s", $uuid)); + + // First get the existing flags + $existingFlags = self::getFlags($uuid); + + // Remove the specified flags + $flags = array_diff($existingFlags, $flags); + + try + { + $statement = Database::getConnection()->prepare("UPDATE sessions SET flags=? WHERE uuid=?"); + $statement->bindValue(1, Utilities::serializeList($flags)); + $statement->bindParam(2, $uuid); + $statement->execute(); + } + catch (PDOException $e) + { + throw new DatabaseOperationException('Failed to remove flags from session', $e); + } + } } \ No newline at end of file diff --git a/src/Socialbox/Objects/Database/SessionRecord.php b/src/Socialbox/Objects/Database/SessionRecord.php index 70d7a8e..ddce0cc 100644 --- a/src/Socialbox/Objects/Database/SessionRecord.php +++ b/src/Socialbox/Objects/Database/SessionRecord.php @@ -85,11 +85,6 @@ return false; } - if(in_array(SessionFlags::AUTHENTICATED, $this->flags)) - { - return true; - } - return $this->authenticated; }