diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml
deleted file mode 100644
index ea6eea8..0000000
--- a/.idea/php-test-framework.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/php.xml b/.idea/php.xml
index 1a158d8..6e91387 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -69,7 +69,7 @@
-
+
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
index 5b5c311..12d6855 100644
--- a/.idea/sqldialects.xml
+++ b/.idea/sqldialects.xml
@@ -4,6 +4,9 @@
+
+
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 2136802..c76565e 100644
--- a/composer.json
+++ b/composer.json
@@ -11,6 +11,8 @@
],
"require": {
"ext-pdo": "*",
- "ext-openssl": "*"
+ "ext-openssl": "*",
+ "ext-redis": "*",
+ "ext-memcached": "*"
}
}
\ No newline at end of file
diff --git a/src/Socialbox/Abstracts/CacheLayer.php b/src/Socialbox/Abstracts/CacheLayer.php
index 72d0f07..e825def 100644
--- a/src/Socialbox/Abstracts/CacheLayer.php
+++ b/src/Socialbox/Abstracts/CacheLayer.php
@@ -2,8 +2,15 @@
namespace Socialbox\Abstracts;
+use RuntimeException;
+use Socialbox\Classes\CacheLayer\MemcachedCacheLayer;
+use Socialbox\Classes\CacheLayer\RedisCacheLayer;
+use Socialbox\Classes\Configuration;
+
abstract class CacheLayer
{
+ private static ?CacheLayer $instance = null;
+
/**
* Stores a value in the cache with an associated key and an optional time-to-live (TTL).
*
@@ -38,10 +45,46 @@ abstract class CacheLayer
*/
public abstract function exists(string $key): bool;
+ /**
+ * Counts the number of items that start with the given prefix.
+ *
+ * @param string $prefix The prefix to search for.
+ * @return int The count of items starting with the provided prefix.
+ */
+ public abstract function getPrefixCount(string $prefix): int;
+
/**
* Clears all values from the cache.
*
* @return bool Returns true if the cache was successfully cleared, false otherwise.
*/
public abstract function clear(): bool;
+
+ /**
+ * Retrieves the singleton instance of the cache layer.
+ *
+ * @return CacheLayer The singleton instance of the cache layer.
+ */
+ public static function getInstance(): CacheLayer
+ {
+ if (self::$instance === null)
+ {
+ $engine = Configuration::getConfiguration()['cache']['engine'];
+
+ if ($engine === 'redis')
+ {
+ self::$instance = new RedisCacheLayer();
+ }
+ else if ($engine === 'memcached')
+ {
+ self::$instance = new MemcachedCacheLayer();
+ }
+ else
+ {
+ throw new RuntimeException('Invalid cache engine specified in the configuration, must be either "redis" or "memcached".');
+ }
+ }
+
+ return self::$instance;
+ }
}
\ No newline at end of file
diff --git a/src/Socialbox/Classes/CacheLayer/MemcachedCacheLayer.php b/src/Socialbox/Classes/CacheLayer/MemcachedCacheLayer.php
index a67502a..8095ae1 100644
--- a/src/Socialbox/Classes/CacheLayer/MemcachedCacheLayer.php
+++ b/src/Socialbox/Classes/CacheLayer/MemcachedCacheLayer.php
@@ -5,6 +5,7 @@ namespace Socialbox\Classes\CacheLayer;
use Memcached;
use RuntimeException;
use Socialbox\Abstracts\CacheLayer;
+use Socialbox\Classes\Configuration;
class MemcachedCacheLayer extends CacheLayer
{
@@ -12,11 +13,8 @@ class MemcachedCacheLayer extends CacheLayer
/**
* Memcached cache layer constructor.
- *
- * @param string $host The Memcached server host.
- * @param int $port The Memcached server port.
*/
- public function __construct(string $host, int $port)
+ public function __construct()
{
if (!extension_loaded('memcached'))
{
@@ -24,9 +22,10 @@ class MemcachedCacheLayer extends CacheLayer
}
$this->memcached = new Memcached();
- if (!$this->memcached->addServer($host, $port))
+ $this->memcached->addServer(Configuration::getConfiguration()['cache']['host'], (int)Configuration::getConfiguration()['cache']['port']);
+ if(Configuration::getConfiguration()['cache']['username'] !== null || Configuration::getConfiguration()['cache']['password'] !== null)
{
- throw new RuntimeException('Failed to connect to the Memcached server.');
+ $this->memcached->setSaslAuthData(Configuration::getConfiguration()['cache']['username'], Configuration::getConfiguration()['cache']['password']);
}
}
@@ -80,6 +79,25 @@ class MemcachedCacheLayer extends CacheLayer
return $this->memcached->getResultCode() === Memcached::RES_SUCCESS;
}
+ /**
+ * @inheritDoc
+ */
+ public function getPrefixCount(string $prefix): int
+ {
+ $stats = $this->memcached->getStats();
+ $count = 0;
+
+ foreach ($stats as $server => $data)
+ {
+ if (str_starts_with($server, $prefix))
+ {
+ $count += $data['curr_items'];
+ }
+ }
+
+ return $count;
+ }
+
/**
* @inheritDoc
*/
diff --git a/src/Socialbox/Classes/CacheLayer/RedisCacheLayer.php b/src/Socialbox/Classes/CacheLayer/RedisCacheLayer.php
index 1fcb787..1715e51 100644
--- a/src/Socialbox/Classes/CacheLayer/RedisCacheLayer.php
+++ b/src/Socialbox/Classes/CacheLayer/RedisCacheLayer.php
@@ -6,6 +6,7 @@ use Redis;
use RedisException;
use RuntimeException;
use Socialbox\Abstracts\CacheLayer;
+use Socialbox\Classes\Configuration;
class RedisCacheLayer extends CacheLayer
{
@@ -13,12 +14,8 @@ class RedisCacheLayer extends CacheLayer
/**
* Redis cache layer constructor.
- *
- * @param string $host The Redis server host.
- * @param int $port The Redis server port.
- * @param string|null $password Optional. The Redis server password.
*/
- public function __construct(string $host, int $port, ?string $password=null)
+ public function __construct()
{
if (!extension_loaded('redis'))
{
@@ -29,10 +26,15 @@ class RedisCacheLayer extends CacheLayer
try
{
- $this->redis->connect($host, $port);
- if ($password !== null)
+ $this->redis->connect(Configuration::getConfiguration()['cache']['host'], (int)Configuration::getConfiguration()['cache']['port']);
+ if (Configuration::getConfiguration()['cache']['password'] !== null)
{
- $this->redis->auth($password);
+ $this->redis->auth(Configuration::getConfiguration()['cache']['password']);
+ }
+
+ if (Configuration::getConfiguration()['cache']['database'] !== 0)
+ {
+ $this->redis->select((int)Configuration::getConfiguration()['cache']['database']);
}
}
catch (RedisException $e)
@@ -101,6 +103,21 @@ class RedisCacheLayer extends CacheLayer
}
}
+ /**
+ * @inheritDoc
+ */
+ public function getPrefixCount(string $prefix): int
+ {
+ try
+ {
+ return count($this->redis->keys($prefix . '*'));
+ }
+ catch (RedisException $e)
+ {
+ throw new RuntimeException('Failed to get the count of keys with the specified prefix in the Redis cache.', 0, $e);
+ }
+ }
+
/**
* @inheritDoc
*/
diff --git a/src/Socialbox/Classes/CliCommands/InitializeCommand.php b/src/Socialbox/Classes/CliCommands/InitializeCommand.php
index 8a71ad7..9cf5b64 100644
--- a/src/Socialbox/Classes/CliCommands/InitializeCommand.php
+++ b/src/Socialbox/Classes/CliCommands/InitializeCommand.php
@@ -2,13 +2,18 @@
namespace Socialbox\Classes\CliCommands;
+use Exception;
use LogLib\Log;
use PDOException;
+use Socialbox\Abstracts\CacheLayer;
use Socialbox\Classes\Configuration;
+use Socialbox\Classes\Cryptography;
use Socialbox\Classes\Database;
use Socialbox\Classes\Resources;
use Socialbox\Enums\DatabaseObjects;
+use Socialbox\Exceptions\DatabaseOperationException;
use Socialbox\Interfaces\CliCommandInterface;
+use Socialbox\Managers\VariableManager;
class InitializeCommand implements CliCommandInterface
{
@@ -23,7 +28,14 @@ class InitializeCommand implements CliCommandInterface
return 1;
}
- print("Initializing Socialbox...\n");
+ Log::info('net.nosial.socialbox', 'Initializing Socialbox...');
+
+ if(Configuration::getConfiguration()['cache']['enabled'])
+ {
+ Log::verbose('net.nosial.socialbox', 'Clearing cache layer...');
+ CacheLayer::getInstance()->clear();
+ }
+
foreach(DatabaseObjects::casesOrdered() as $object)
{
Log::verbose('net.nosial.socialbox', "Initializing database object {$object->value}");
@@ -46,13 +58,34 @@ class InitializeCommand implements CliCommandInterface
return 1;
}
}
- catch(\Exception $e)
+ catch(Exception $e)
{
Log::error('net.nosial.socialbox', "Failed to initialize database object {$object->value}: {$e->getMessage()}", $e);
return 1;
}
}
+ try
+ {
+
+ if(!VariableManager::variableExists('PUBLIC_KEY') || !VariableManager::variableExists('PRIVATE_KEY'))
+ {
+ Log::info('net.nosial.socialbox', 'Generating new key pair...');
+
+ $keyPair = Cryptography::generateKeyPair();
+ VariableManager::setVariable('PUBLIC_KEY', $keyPair->getPublicKey());
+ VariableManager::setVariable('PRIVATE_KEY', $keyPair->getPrivateKey());
+
+ Log::info('net.nosial.socialbox', 'Set the DNS TXT record for the public key to the following value:');
+ Log::info('net.nosial.socialbox', "socialbox-key={$keyPair->getPublicKey()}");
+ }
+ }
+ catch(DatabaseOperationException $e)
+ {
+ Log::error('net.nosial.socialbox', "Failed to generate key pair: {$e->getMessage()}", $e);
+ return 1;
+ }
+
Log::info('net.nosial.socialbox', 'Socialbox has been initialized successfully');
return 0;
}
diff --git a/src/Socialbox/Classes/Configuration.php b/src/Socialbox/Classes/Configuration.php
index 5bc47a0..648e439 100644
--- a/src/Socialbox/Classes/Configuration.php
+++ b/src/Socialbox/Classes/Configuration.php
@@ -22,6 +22,18 @@ class Configuration
$config->setDefault('database.username', 'root');
$config->setDefault('database.password', 'root');
$config->setDefault('database.name', 'test');
+
+ $config->setDefault('cache.enabled', false);
+ $config->setDefault('cache.engine', 'redis');
+ $config->setDefault('cache.host', '127.0.0.1');
+ $config->setDefault('cache.port', 6379);
+ $config->setDefault('cache.username', null);
+ $config->setDefault('cache.password', null);
+ $config->setDefault('cache.database', 0);
+ $config->setDefault('cache.variables.enabled', true);
+ $config->setDefault('cache.variables.ttl', 3600);
+ $config->setDefault('cache.variables.max', 1000);
+
$config->save();
self::$configuration = $config->getConfiguration();
diff --git a/src/Socialbox/Classes/Resources/database/variables.sql b/src/Socialbox/Classes/Resources/database/variables.sql
new file mode 100644
index 0000000..29b865d
--- /dev/null
+++ b/src/Socialbox/Classes/Resources/database/variables.sql
@@ -0,0 +1,11 @@
+create table variables
+(
+ name varchar(255) not null comment 'The name of the variable'
+ primary key comment 'The unique index for the variable name',
+ value text null comment 'The value of the variable',
+ `read_only` tinyint(1) default 0 not null comment 'Boolean indicator if the variable is read only',
+ created timestamp default current_timestamp() not null comment 'The Timestamp for when this record was created',
+ updated timestamp null comment 'The Timestamp for when this record was last updated',
+ constraint variables_name_uindex
+ unique (name) comment 'The unique index for the variable name'
+);
\ No newline at end of file
diff --git a/src/Socialbox/Classes/RpcClient.php b/src/Socialbox/Classes/RpcClient.php
new file mode 100644
index 0000000..31dbcc0
--- /dev/null
+++ b/src/Socialbox/Classes/RpcClient.php
@@ -0,0 +1,88 @@
+domain = $domain;
+ $this->endpoint = $resolved->getEndpoint();
+ $this->serverPublicKey = $resolved->getPublicKey();
+ $this->clientPrivateKey = null;
+ }
+
+ public function getDomain(): string
+ {
+ return $this->domain;
+ }
+
+ public function getEndpoint(): string
+ {
+ return $this->endpoint;
+ }
+
+ public function getServerPublicKey(): string
+ {
+ return $this->serverPublicKey;
+ }
+
+ public function sendRequest(array $data)
+ {
+ $ch = curl_init($this->endpoint);
+
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, Utilities::jsonEncode($data));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ Utilities::generateHeader(StandardHeaders::CLIENT_NAME, self::CLIENT_NAME),
+ Utilities::generateHeader(StandardHeaders::CLIENT_VERSION, self::CLIENT_VERSION),
+ Utilities::generateHeader(StandardHeaders::CONTENT_TYPE, self::CONTENT_TYPE)
+ ]);
+ curl_setopt($ch, CURLOPT_HEADER, true);
+
+ $response = curl_exec($ch);
+
+ if (curl_errno($ch))
+ {
+ $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+ // Separate headers and body
+ $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $response_body = substr($response, $header_size);
+
+ curl_close($ch);
+
+ // Throw exception with response body as message and status code as code
+ throw new RpcRequestException($response_body, $statusCode);
+ }
+
+ $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+ // Separate headers and body
+ $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $response_headers = substr($response, 0, $header_size);
+ $response_body = substr($response, $header_size);
+
+ curl_close($ch);
+ }
+ }
\ No newline at end of file
diff --git a/src/Socialbox/Classes/RpcHandler.php b/src/Socialbox/Classes/RpcHandler.php
index 810c3d7..df24724 100644
--- a/src/Socialbox/Classes/RpcHandler.php
+++ b/src/Socialbox/Classes/RpcHandler.php
@@ -8,6 +8,7 @@ use Socialbox\Enums\StandardHeaders;
use Socialbox\Exceptions\CryptographyException;
use Socialbox\Exceptions\DatabaseOperationException;
use Socialbox\Exceptions\RpcException;
+use Socialbox\Exceptions\StandardException;
use Socialbox\Managers\SessionManager;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\RpcRequest;
@@ -85,11 +86,6 @@ class RpcHandler
try
{
- if(!SessionManager::sessionExists($clientRequest->getSessionUuid()))
- {
- throw new RpcException('Session UUID not found', 404);
- }
-
$session = SessionManager::getSession($clientRequest->getSessionUuid());
// Verify the signature of the request
@@ -98,6 +94,10 @@ class RpcHandler
throw new RpcException('Request signature check failed', 400);
}
}
+ catch(StandardException $e)
+ {
+ throw new RpcException($e->getMessage(), 400);
+ }
catch(CryptographyException $e)
{
throw new RpcException('Request signature check failed (Cryptography Error)', 400, $e);
diff --git a/src/Socialbox/Classes/ServerResolver.php b/src/Socialbox/Classes/ServerResolver.php
new file mode 100644
index 0000000..58bf1ff
--- /dev/null
+++ b/src/Socialbox/Classes/ServerResolver.php
@@ -0,0 +1,52 @@
+getTraceAsString()
);
}
+
+ public static function generateHeader(StandardHeaders $header, string $value): string
+ {
+ return $header->value . ': ' . $value;
+ }
}
\ No newline at end of file
diff --git a/src/Socialbox/Enums/DatabaseObjects.php b/src/Socialbox/Enums/DatabaseObjects.php
index 5ca0b51..d0037e3 100644
--- a/src/Socialbox/Enums/DatabaseObjects.php
+++ b/src/Socialbox/Enums/DatabaseObjects.php
@@ -7,6 +7,7 @@ enum DatabaseObjects : string
case PASSWORD_AUTHENTICATION = 'password_authentication.sql';
case REGISTERED_PEERS = 'registered_peers.sql';
case SESSIONS = 'sessions.sql';
+ case VARIABLES = 'variables.sql';
/**
* Returns the priority of the database object
@@ -17,6 +18,7 @@ enum DatabaseObjects : string
{
return match ($this)
{
+ self::VARIABLES => 0,
self::REGISTERED_PEERS => 1,
self::PASSWORD_AUTHENTICATION, self::SESSIONS => 2,
};
diff --git a/src/Socialbox/Enums/StandardHeaders.php b/src/Socialbox/Enums/StandardHeaders.php
index 37841fe..9d707de 100644
--- a/src/Socialbox/Enums/StandardHeaders.php
+++ b/src/Socialbox/Enums/StandardHeaders.php
@@ -13,6 +13,7 @@ enum StandardHeaders : string
case SESSION_UUID = 'Session-UUID';
case FROM_PEER = 'From-Peer';
case SIGNATURE = 'Signature';
+ case PUBLIC_KEY = 'Public-Key';
/**
* Determines if the current instance is required based on its type.
diff --git a/src/Socialbox/Exceptions/ResolutionException.php b/src/Socialbox/Exceptions/ResolutionException.php
new file mode 100644
index 0000000..d17a840
--- /dev/null
+++ b/src/Socialbox/Exceptions/ResolutionException.php
@@ -0,0 +1,13 @@
+prepare("INSERT INTO variables (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=?");
+ $statement->bindParam(1, $name);
+ $statement->bindParam(2, $value);
+ $statement->bindParam(3, $value);
+ $statement->execute();
+ }
+ catch(PDOException $e)
+ {
+ throw new DatabaseOperationException(sprintf('Failed to set variable %s in the database', $name), $e);
+ }
+ finally
+ {
+ if(Configuration::getConfiguration()['cache']['enabled'] && Configuration::getConfiguration()['cache']['variables']['enabled'])
+ {
+ if(Configuration::getConfiguration()['cache']['variables']['max'] > 0)
+ {
+ if(CacheLayer::getInstance()->getPrefixCount('VARIABLES_') >= Configuration::getConfiguration()['cache']['variables']['max'])
+ {
+ // Return early if the cache is full
+ return;
+ }
+ }
+
+ CacheLayer::getInstance()->set(sprintf("VARIABLES_%s", $name), $value, (int)Configuration::getConfiguration()['cache']['variables']['ttl']);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the value of a variable from the database based on its name.
+ *
+ * @param string $name The name of the variable to retrieve.
+ * @return string The value of the variable.
+ * @throws DatabaseOperationException If the database operation fails.
+ */
+ public static function getVariable(string $name): string
+ {
+ if(Configuration::getConfiguration()['cache']['enabled'] && Configuration::getConfiguration()['cache']['variables']['enabled'])
+ {
+ $cachedValue = CacheLayer::getInstance()->get(sprintf("VARIABLES_%s", $name));
+ if($cachedValue !== false)
+ {
+ return $cachedValue;
+ }
+ }
+
+ try
+ {
+ $statement = Database::getConnection()->prepare("SELECT value FROM variables WHERE name=?");
+ $statement->bindParam(1, $name);
+ $statement->execute();
+
+ if($statement->rowCount() === 0)
+ {
+ throw new DatabaseOperationException(sprintf('Variable with name %s does not exist', $name));
+ }
+
+ $result = $statement->fetch(PDO::FETCH_ASSOC);
+ return $result['value'];
+ }
+ catch(PDOException $e)
+ {
+ throw new DatabaseOperationException(sprintf('Failed to get variable %s from the database', $name), $e);
+ }
+ }
+
+ /**
+ * Checks if a variable with the specified name exists in the database.
+ *
+ * @param string $name The name of the variable to check for existence.
+ * @return bool Returns true if the variable exists, false otherwise.
+ * @throws DatabaseOperationException If the database operation fails.
+ */
+ public static function variableExists(string $name): bool
+ {
+ if(Configuration::getConfiguration()['cache']['enabled'] && Configuration::getConfiguration()['cache']['variables']['enabled'])
+ {
+ $cachedValue = CacheLayer::getInstance()->get(sprintf("VARIABLES_%s", $name));
+ if($cachedValue !== false)
+ {
+ return true;
+ }
+ }
+
+ try
+ {
+ $statement = Database::getConnection()->prepare("SELECT COUNT(*) FROM variables WHERE name=?");
+ $statement->bindParam(1, $name);
+ $statement->execute();
+ $result = $statement->fetchColumn();
+ return $result > 0;
+ }
+ catch(PDOException $e)
+ {
+ throw new DatabaseOperationException(sprintf('Failed to check if the variable %s exists', $name), $e);
+ }
+ }
+
+ /**
+ * Deletes a variable from the database using the provided name.
+ *
+ * @param string $name The name of the variable to be deleted.
+ * @return void
+ * @throws DatabaseOperationException If the database operation fails.
+ */
+ public static function deleteVariable(string $name): void
+ {
+ try
+ {
+ $statement = Database::getConnection()->prepare("DELETE FROM variables WHERE name=?");
+ $statement->bindParam(1, $name);
+ $statement->execute();
+ }
+ catch(PDOException $e)
+ {
+ throw new DatabaseOperationException(sprintf('Failed to delete variable %s from the database', $name), $e);
+ }
+ finally
+ {
+ if(Configuration::getConfiguration()['cache']['enabled'] && Configuration::getConfiguration()['cache']['variables']['enabled'])
+ {
+ CacheLayer::getInstance()->delete(sprintf("VARIABLES_%s", $name));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Socialbox/Objects/ClientRequest.php b/src/Socialbox/Objects/ClientRequest.php
index 6e6bf7c..ecb942a 100644
--- a/src/Socialbox/Objects/ClientRequest.php
+++ b/src/Socialbox/Objects/ClientRequest.php
@@ -2,7 +2,14 @@
namespace Socialbox\Objects;
+use RuntimeException;
+use Socialbox\Classes\Cryptography;
+use Socialbox\Enums\StandardError;
use Socialbox\Enums\StandardHeaders;
+use Socialbox\Exceptions\CryptographyException;
+use Socialbox\Exceptions\DatabaseOperationException;
+use Socialbox\Exceptions\StandardException;
+use Socialbox\Managers\SessionManager;
class ClientRequest
{
@@ -95,15 +102,41 @@ class ClientRequest
return $this->headers[StandardHeaders::SIGNATURE->value];
}
+ /**
+ * @return bool
+ * @throws DatabaseOperationException
+ */
public function verifySignature(): bool
{
$signature = $this->getSignature();
+ $sessionUuid = $this->getSessionUuid();
- if($signature == null)
+ if($signature == null || $sessionUuid == null)
{
return false;
}
+ try
+ {
+ $session = SessionManager::getSession($sessionUuid);
+ }
+ catch(StandardException $e)
+ {
+ if($e->getStandardError() == StandardError::SESSION_NOT_FOUND)
+ {
+ return false;
+ }
+ throw new RuntimeException($e);
+ }
+
+ try
+ {
+ return Cryptography::verifyContent($this->getHash(), $signature, $session->getPublicKey());
+ }
+ catch(CryptographyException $e)
+ {
+ return false;
+ }
}
}
\ No newline at end of file
diff --git a/src/Socialbox/Objects/ResolvedServer.php b/src/Socialbox/Objects/ResolvedServer.php
new file mode 100644
index 0000000..4ecd4e5
--- /dev/null
+++ b/src/Socialbox/Objects/ResolvedServer.php
@@ -0,0 +1,25 @@
+endpoint = $endpoint;
+ $this->publicKey = $publicKey;
+ }
+
+ public function getEndpoint(): string
+ {
+ return $this->endpoint;
+ }
+
+ public function getPublicKey(): string
+ {
+ return $this->publicKey;
+ }
+}
\ No newline at end of file
diff --git a/src/Socialbox/Objects/RpcResponse.php b/src/Socialbox/Objects/RpcResponse.php
index 01ac789..a109eab 100644
--- a/src/Socialbox/Objects/RpcResponse.php
+++ b/src/Socialbox/Objects/RpcResponse.php
@@ -55,13 +55,6 @@ class RpcResponse implements SerializableInterface
return $data->toArray();
}
- // If the data is an array, recursively apply this method to each element
- if (is_array($data))
- {
- return array_map([$this, 'convertToArray'], $data);
- }
-
- // Otherwise, return the data as-is (e.g., for scalar values)
return $data;
}
diff --git a/tests/Socialbox/Classes/CryptographyTest.php b/tests/Socialbox/Classes/CryptographyTest.php
index a90815b..483ba13 100644
--- a/tests/Socialbox/Classes/CryptographyTest.php
+++ b/tests/Socialbox/Classes/CryptographyTest.php
@@ -20,6 +20,8 @@ class CryptographyTest extends TestCase
$this->assertObjectHasProperty('privateKey', $keyPair);
$this->assertIsString($keyPair->getPublicKey());
$this->assertIsString($keyPair->getPrivateKey());
+
+ print_r($keyPair);
}
/**
diff --git a/tests/Socialbox/Classes/ServerResolverTest.php b/tests/Socialbox/Classes/ServerResolverTest.php
new file mode 100644
index 0000000..ef7e8a1
--- /dev/null
+++ b/tests/Socialbox/Classes/ServerResolverTest.php
@@ -0,0 +1,21 @@
+getEndpoint());
+ self::assertNotEmpty($resolvedServer->getPublicKey());
+ }
+}
\ No newline at end of file
diff --git a/tests/Socialbox/Managers/SessionManagerTest.php b/tests/Socialbox/Managers/SessionManagerTest.php
index 6b0f954..1da708c 100644
--- a/tests/Socialbox/Managers/SessionManagerTest.php
+++ b/tests/Socialbox/Managers/SessionManagerTest.php
@@ -6,7 +6,6 @@ use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Socialbox\Classes\Cryptography;
use Socialbox\Classes\Utilities;
-use Socialbox\Exceptions\DatabaseOperationException;
use Socialbox\Objects\SessionRecord;
class SessionManagerTest extends TestCase
@@ -27,14 +26,6 @@ class SessionManagerTest extends TestCase
$this->assertTrue(SessionManager::sessionExists($uuid));
}
- public function testGetSessionWithInvalidUuid(): void
- {
- $uuid = 'invalid_uuid';
-
- $this->expectException(DatabaseOperationException::class);
- SessionManager::getSession($uuid);
- }
-
public function testGetSessionWithValidUuid(): void
{
$keyPair = Cryptography::generateKeyPair();
diff --git a/tests/Socialbox/Managers/VariableManagerTest.php b/tests/Socialbox/Managers/VariableManagerTest.php
new file mode 100644
index 0000000..d1060f3
--- /dev/null
+++ b/tests/Socialbox/Managers/VariableManagerTest.php
@@ -0,0 +1,34 @@
+clear();
+
+ VariableManager::deleteVariable('test_name');
+ VariableManager::setVariable('test_name', 'test_value');
+ $this->assertTrue(VariableManager::variableExists('test_name'));
+ $this->assertEquals('test_value', VariableManager::getVariable('test_name'));
+ VariableManager::deleteVariable('test_name');
+
+ VariableManager::deleteVariable('test_name2');
+ VariableManager::setVariable('test_name2', 'test_value2');
+ $this->assertTrue(VariableManager::variableExists('test_name2'));
+ $this->assertEquals('test_value2', VariableManager::getVariable('test_name2'));
+ VariableManager::deleteVariable('test_name2');
+ }
+
+}
\ No newline at end of file