From 14effd7ef81484ff7e8f3c1cb6f4931b5e9d14c5 Mon Sep 17 00:00:00 2001 From: netkas Date: Tue, 3 Jun 2025 20:46:49 -0400 Subject: [PATCH] Add PushEntity class and enhance EntitiesManager with UUID handling and existence checks --- src/FederationServer/Classes/Enums/Method.php | 1 + .../Classes/Managers/EntitiesManager.php | 82 ++++++++++++++++++- .../Methods/Entities/PushEntity.php | 66 +++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/FederationServer/Methods/Entities/PushEntity.php diff --git a/src/FederationServer/Classes/Enums/Method.php b/src/FederationServer/Classes/Enums/Method.php index c6afba8..32e57ba 100644 --- a/src/FederationServer/Classes/Enums/Method.php +++ b/src/FederationServer/Classes/Enums/Method.php @@ -10,6 +10,7 @@ use FederationServer\Methods\Audit\ViewAuditEntry; use FederationServer\Methods\Entities\GetEntity; use FederationServer\Methods\Entities\ListEntities; + use FederationServer\Methods\Entities\PushEntity; use FederationServer\Methods\Entities\QueryEntity; use FederationServer\Methods\Operators\CreateOperator; use FederationServer\Methods\Operators\DeleteOperator; diff --git a/src/FederationServer/Classes/Managers/EntitiesManager.php b/src/FederationServer/Classes/Managers/EntitiesManager.php index 65c73e9..2c54b0a 100644 --- a/src/FederationServer/Classes/Managers/EntitiesManager.php +++ b/src/FederationServer/Classes/Managers/EntitiesManager.php @@ -8,6 +8,7 @@ use InvalidArgumentException; use PDO; use PDOException; + use Symfony\Component\Uid\Uuid; class EntitiesManager { @@ -19,7 +20,7 @@ * @throws InvalidArgumentException If the ID exceeds 255 characters or if the domain is invalid. * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. */ - public static function registerEntity(string $id, ?string $domain=null): void + public static function registerEntity(string $id, ?string $domain=null): string { if(strlen($id) > 255) { @@ -34,9 +35,12 @@ throw new InvalidArgumentException("Domain cannot exceed 255 characters."); } + $uuid = Uuid::v4()->toRfc4122(); + try { - $stmt = DatabaseConnection::getConnection()->prepare("INSERT INTO entities (id, domain) VALUES (:id, :domain)"); + $stmt = DatabaseConnection::getConnection()->prepare("INSERT INTO entities (uuid, id, domain) VALUES (:uuid, :id, :domain)"); + $stmt->bindParam(':uuid', $uuid); $stmt->bindParam(':id', $id); $stmt->bindParam(':domain', $domain); $stmt->execute(); @@ -45,6 +49,8 @@ { throw new DatabaseOperationException("Failed to register entity: " . $e->getMessage(), $e->getCode(), $e); } + + return $uuid; } /** @@ -131,6 +137,78 @@ } } + /** + * Checks if an entity exists by its ID and domain. + * + * @param string $id The ID of the entity. + * @param string|null $domain The domain of the entity, can be null. + * @return bool True if the entity exists, false otherwise. + * @throws InvalidArgumentException If the ID is not provided or is invalid. + * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. + */ + public static function entityExists(string $id, ?string $domain): bool + { + if(strlen($id) < 1) + { + throw new InvalidArgumentException("Entity ID must be provided."); + } + + if(!is_null($domain) && !filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) + { + throw new InvalidArgumentException("Invalid domain format."); + } + + try + { + if(is_null($domain)) + { + $stmt = DatabaseConnection::getConnection()->prepare("SELECT COUNT(*) FROM entities WHERE id = :id"); + $stmt->bindParam(':id', $id); + } + else + { + $stmt = DatabaseConnection::getConnection()->prepare("SELECT COUNT(*) FROM entities WHERE id = :id AND domain = :domain"); + $stmt->bindParam(':id', $id); + $stmt->bindParam(':domain', $domain); + } + + $stmt->execute(); + return (bool)$stmt->fetchColumn(); + } + catch (PDOException $e) + { + throw new DatabaseOperationException("Failed to check entity existence: " . $e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Checks if an entity exists by its UUID. + * + * @param string $uuid The UUID of the entity. + * @return bool True if the entity exists, false otherwise. + * @throws InvalidArgumentException If the UUID is not provided or is invalid. + * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. + */ + public static function entityExistsByUuid(string $uuid): bool + { + if(strlen($uuid) < 1) + { + throw new InvalidArgumentException("Entity UUID must be provided."); + } + + try + { + $stmt = DatabaseConnection::getConnection()->prepare("SELECT COUNT(*) FROM entities WHERE uuid = :uuid"); + $stmt->bindParam(':uuid', $uuid); + $stmt->execute(); + return (bool)$stmt->fetchColumn(); + } + catch (PDOException $e) + { + throw new DatabaseOperationException("Failed to check entity existence by UUID: " . $e->getMessage(), $e->getCode(), $e); + } + } + /** * Deletes an entity by its UUID. * diff --git a/src/FederationServer/Methods/Entities/PushEntity.php b/src/FederationServer/Methods/Entities/PushEntity.php new file mode 100644 index 0000000..9e196cd --- /dev/null +++ b/src/FederationServer/Methods/Entities/PushEntity.php @@ -0,0 +1,66 @@ +isClient() && !$authenticatedOperator->canManageOperators()) + { + throw new RequestException('Unauthorized: Insufficient permissions to push entities', 403); + } + + $id = FederationServer::getParameter('id'); + $domain = FederationServer::getParameter('domain') ?? null; + + if(!$id) + { + throw new RequestException('Bad Request: Entity ID is required', 400); + } + + if(strlen($id) > 255) + { + throw new RequestException('Bad Request: Entity ID exceeds maximum length of 255 characters', 400); + } + + if(!is_null($domain) && !filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) + { + throw new RequestException('Bad Request: Invalid domain format', 400); + } + + if(!is_null($domain) && strlen($domain) > 255) + { + throw new RequestException('Bad Request: Domain exceeds maximum length of 255 characters', 400); + } + + try + { + if(!EntitiesManager::entityExists($id, $domain)) + { + $entityUuid = EntitiesManager::registerEntity($id, $domain); + } + else + { + $entityUuid = EntitiesManager::getEntity($id, $domain)->getUuid(); + } + } + catch (DatabaseOperationException $e) + { + throw new RequestException('Internal Server Error: Unable to register entity', 500, $e); + } + + self::successResponse($entityUuid); + } + } +