diff --git a/src/FederationServer/Classes/Configuration/ServerConfiguration.php b/src/FederationServer/Classes/Configuration/ServerConfiguration.php index e8ed77e..8fd3485 100644 --- a/src/FederationServer/Classes/Configuration/ServerConfiguration.php +++ b/src/FederationServer/Classes/Configuration/ServerConfiguration.php @@ -4,6 +4,7 @@ class ServerConfiguration { + private string $baseUrl; private string $name; private ?string $apiKey; private int $maxUploadSize; @@ -16,12 +17,23 @@ */ public function __construct(array $config) { + $this->baseUrl = $config['server.base_url'] ?? 'http://127.0.0.1:6161'; $this->name = $config['server.name'] ?? 'Federation Server'; $this->apiKey = $config['server.api_key'] ?? null; $this->maxUploadSize = $config['max_upload_size'] ?? 52428800; // 50MB default $this->storagePath = $config['server.storage_path'] ?? '/var/www/uploads'; } + /** + * Get the base URL of the server. + * + * @return string The base URL of the server. + */ + public function getBaseUrl(): string + { + return $this->baseUrl; + } + /** * Get the name of the server. * diff --git a/src/FederationServer/Classes/Managers/EvidenceManager.php b/src/FederationServer/Classes/Managers/EvidenceManager.php index a080d57..1b74c40 100644 --- a/src/FederationServer/Classes/Managers/EvidenceManager.php +++ b/src/FederationServer/Classes/Managers/EvidenceManager.php @@ -19,10 +19,11 @@ * @param string|null $blacklist Optional blacklist value, can be null. * @param string|null $textContent Optional text content, can be null. * @param string|null $note Optional note, can be null. + * @param bool $confidential Whether the evidence is confidential (default is false). * @throws InvalidArgumentException If the entity or operator is not provided or is empty. * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. */ - public static function addEvidence(string $entity, string $operator, ?string $blacklist=null, ?string $textContent=null, ?string $note=null): void + public static function addEvidence(string $entity, string $operator, ?string $blacklist=null, ?string $textContent=null, ?string $note=null, bool $confidential=false): void { if(strlen($entity) < 1 || strlen($operator) < 1) { @@ -31,9 +32,10 @@ try { - $stmt = DatabaseConnection::getConnection()->prepare("INSERT INTO evidence (entity, operator, blacklist, text_content, note) VALUES (:entity, :operator, :blacklist, :text_content, :note)"); + $stmt = DatabaseConnection::getConnection()->prepare("INSERT INTO evidence (entity, operator, confidential, blacklist, text_content, note) VALUES (:entity, :operator, :confidential, :blacklist, :text_content, :note)"); $stmt->bindParam(':entity', $entity); $stmt->bindParam(':operator', $operator); + $stmt->bindParam(':confidential', $confidential); $stmt->bindParam(':blacklist', $blacklist); $stmt->bindParam(':text_content', $textContent); $stmt->bindParam(':note', $note); @@ -109,10 +111,11 @@ * Retrieves all evidence records associated with a specific operator. * * @param string $entity The UUID of the entity. + * @param bool $includeConfidential Whether to include confidential evidence records (default is false). * @return EvidenceRecord[] An array of EvidenceRecord objects. * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. */ - public static function getEvidenceByEntity(string $entity): array + public static function getEvidenceByEntity(string $entity, bool $includeConfidential=false): array { if(strlen($entity) < 1) { @@ -121,7 +124,13 @@ try { - $stmt = DatabaseConnection::getConnection()->prepare("SELECT * FROM evidence WHERE entity = :entity"); + $query = "SELECT * FROM evidence WHERE entity = :entity"; + if(!$includeConfidential) + { + $query .= " AND confidential = 0"; + } + + $stmt = DatabaseConnection::getConnection()->prepare($query); $stmt->bindParam(':entity', $entity); $stmt->execute(); @@ -144,11 +153,12 @@ * Retrieves all evidence records associated with a specific operator. * * @param string $operator The UUID of the operator. + * @param bool $includeConfidential Whether to include confidential evidence records (default is false). * @return EvidenceRecord[] An array of EvidenceRecord objects. * @throws InvalidArgumentException If the operator is not provided or is empty. * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. */ - public static function getEvidenceByOperator(string $operator): array + public static function getEvidenceByOperator(string $operator, bool $includeConfidential=false): array { if(strlen($operator) < 1) { @@ -157,7 +167,13 @@ try { - $stmt = DatabaseConnection::getConnection()->prepare("SELECT * FROM evidence WHERE operator = :operator"); + $query = "SELECT * FROM evidence WHERE operator = :operator"; + if(!$includeConfidential) + { + $query .= " AND confidential = 0"; + } + + $stmt = DatabaseConnection::getConnection()->prepare($query); $stmt->bindParam(':operator', $operator); $stmt->execute(); @@ -175,4 +191,53 @@ throw new DatabaseOperationException("Failed to retrieve evidence by operator: " . $e->getMessage(), $e->getCode(), $e); } } + + public static function evidenceExists(string $uuid): bool + { + if(strlen($uuid) < 1) + { + throw new InvalidArgumentException('UUID must be provided.'); + } + + try + { + $stmt = DatabaseConnection::getConnection()->prepare("SELECT COUNT(*) FROM evidence WHERE uuid = :uuid"); + $stmt->bindParam(':uuid', $uuid); + $stmt->execute(); + + return $stmt->fetchColumn() > 0; + } + catch (PDOException $e) + { + throw new DatabaseOperationException("Failed to check evidence existence: " . $e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Updates the confidentiality status of an evidence record. + * + * @param string $uuid The UUID of the evidence record to update. + * @param bool $confidential The new confidentiality status (true for confidential, false for non-confidential). + * @throws InvalidArgumentException If the UUID is not provided or is empty. + * @throws DatabaseOperationException If there is an error preparing or executing the SQL statement. + */ + public static function updateConfidentiality(string $uuid, bool $confidential): void + { + if(strlen($uuid) < 1) + { + throw new InvalidArgumentException('UUID must be provided.'); + } + + try + { + $stmt = DatabaseConnection::getConnection()->prepare("UPDATE evidence SET confidential = :confidential WHERE uuid = :uuid"); + $stmt->bindParam(':uuid', $uuid); + $stmt->bindParam(':confidential', $confidential, PDO::PARAM_BOOL); + $stmt->execute(); + } + catch (PDOException $e) + { + throw new DatabaseOperationException("Failed to update confidentiality: " . $e->getMessage(), $e->getCode(), $e); + } + } } \ No newline at end of file diff --git a/src/FederationServer/Classes/Managers/OperatorManager.php b/src/FederationServer/Classes/Managers/OperatorManager.php index 73e71ea..ca2a513 100644 --- a/src/FederationServer/Classes/Managers/OperatorManager.php +++ b/src/FederationServer/Classes/Managers/OperatorManager.php @@ -17,7 +17,7 @@ * Create a new operator with a unique API key. * * @param string $name The name of the operator. - * @return string The generated API key for the operator. + * @return string The generated UUID for the operator. * @throws InvalidArgumentException If the name is empty or exceeds 255 characters. * @throws DatabaseOperationException If there is an error during the database operation. */ diff --git a/src/FederationServer/FederationServer.php b/src/FederationServer/FederationServer.php index ed7797d..779304c 100644 --- a/src/FederationServer/FederationServer.php +++ b/src/FederationServer/FederationServer.php @@ -2,7 +2,168 @@ namespace FederationServer; - class FederationServer - { + use FederationServer\Classes\Configuration; + use FederationServer\Classes\Enums\AuditLogType; + use FederationServer\Classes\Enums\Method; + use FederationServer\Classes\FileUploadHandler; + use FederationServer\Classes\Logger; + use FederationServer\Classes\Managers\AuditLogManager; + use FederationServer\Classes\Managers\FileAttachmentManager; + use FederationServer\Classes\Managers\OperatorManager; + use FederationServer\Classes\RequestHandler; + use FederationServer\Exceptions\DatabaseOperationException; + use FederationServer\Exceptions\RequestException; + use FederationServer\Methods\CreateOperator; + use FederationServer\Methods\DownloadAttachment; + use FederationServer\Methods\UploadAttachment; + use FederationServer\Objects\OperatorRecord; + use Throwable; - } \ No newline at end of file + class FederationServer extends RequestHandler + { + private static ?string $decodedContent = null; + + /** + * Handle incoming requests to the Federation Server. + * + * @return void + */ + public static function handleRequest(): void + { + try + { + // Always call parent::handleRequest() to ensure the base request handling is done. + parent::handleRequest(); + + // Execute the request method + Method::matchHandle(self::getRequestMethod(), self::getPath())->handleRequest(); + + switch (true) + { + case self::getRequestMethod() === 'POST' && self::getPath() === '/': + self::errorResponse('Method Not Allowed', 405); + break; + + case preg_match('#^/attachment/([a-fA-F0-9\-]{36,})$#', self::getPath()): + DownloadAttachment::handleRequest(); + break; + + case self::getRequestMethod() === 'POST' && self::getPath() === '/createOperator': + CreateOperator::handleRequest(); + break; + + case (self::getRequestMethod() === 'POST' | self::getRequestMethod() === 'PUT') && self::getPath() === '/upload': + UploadAttachment::handleRequest(); + break; + + default: + self::errorResponse('Method Not Found', 405); + break; + } + } + catch (RequestException $e) + { + self::throwableResponse($e); + } + } + + /** + * Handle the root POST request. + * + * This method is a placeholder for handling POST requests to the root path. + * It can be extended to implement specific functionality as needed. + * + * @return void + */ + private static function handlePost(): void + { + // Placeholder for handling POST requests to the root path. + // This can be extended to implement specific functionality as needed. + self::successResponse(['message' => 'Root POST request handled successfully.']); + } + + + /** + * Get a parameter from the request, checking POST, GET, and decoded JSON content. + * + * This method retrieves a parameter by name from the POST data, GET parameters, + * or decoded JSON content if available. It trims the value and returns it. + * + * @param string $name The name of the parameter to retrieve. + * @return mixed The value of the parameter or null if not found. + */ + public static function getParameter(string $name): mixed + { + // Check if the parameter exists in the POST data. + if (isset($_POST[$name]) && is_string($_POST[$name])) + { + return trim($_POST[$name]); + } + + // If not found in POST, check the GET parameters. + if (isset($_GET[$name]) && is_string($_GET[$name])) + { + return trim($_GET[$name]); + } + + if(self::$decodedContent !== null && is_array(self::$decodedContent)) + { + // If the parameter is found in the decoded JSON content, return it. + if (isset(self::$decodedContent[$name])) + { + return self::$decodedContent[$name]; + } + } + + // If the parameter is not found in any of the sources, return null. + return null; + } + + /** + * @inheritDoc + */ + public static function getDecodedContent(): ?array + { + return parent::getDecodedContent(); + } + + /** + * @inheritDoc + */ + public static function getInputContent(): ?string + { + return parent::getInputContent(); + } + + /** + * @inheritDoc + */ + public static function getRequestMethod(): ?string + { + return parent::getRequestMethod(); + } + + /** + * @inheritDoc + */ + public static function getPath(): ?string + { + return parent::getPath(); + } + + /** + * @inheritDoc + */ + public static function getUri(): ?string + { + return parent::getUri(); + } + + /** + * @inheritDoc + */ + public static function getAuthenticatedOperator(): OperatorRecord + { + return parent::getAuthenticatedOperator(); + } + } diff --git a/src/FederationServer/Objects/EvidenceRecord.php b/src/FederationServer/Objects/EvidenceRecord.php index ef57162..260f409 100644 --- a/src/FederationServer/Objects/EvidenceRecord.php +++ b/src/FederationServer/Objects/EvidenceRecord.php @@ -11,6 +11,7 @@ private ?string $blacklist; private string $entity; private string $operator; + private bool $confidential; private ?string $textContent; private ?string $note; private int $created; @@ -26,6 +27,7 @@ $this->blacklist = $data['blacklist'] ?? null; $this->entity = $data['entity'] ?? ''; $this->operator = $data['operator'] ?? ''; + $this->confidential = (bool)$data['confidential'] ?? false; $this->textContent = $data['text_content'] ?? null; $this->note = $data['note'] ?? null; $this->created = isset($data['created']) ? (int)$data['created'] : time(); @@ -71,6 +73,16 @@ return $this->operator; } + /** + * Check if the evidence is confidential. + * + * @return bool + */ + public function isConfidential(): bool + { + return $this->confidential; + } + /** * Get the text content value. * @@ -112,6 +124,7 @@ 'blacklist' => $this->blacklist, 'entity' => $this->entity, 'operator' => $this->operator, + 'confidential' => $this->confidential, 'text_content' => $this->textContent, 'note' => $this->note, 'created' => $this->created, diff --git a/src/FederationServer/Objects/FileAttachmentRecord.php b/src/FederationServer/Objects/FileAttachmentRecord.php index 862523a..913f5e4 100644 --- a/src/FederationServer/Objects/FileAttachmentRecord.php +++ b/src/FederationServer/Objects/FileAttachmentRecord.php @@ -11,6 +11,7 @@ private string $evidence; private string $fileName; private int $fileSize; + private string $fileMime; private int $created; /** @@ -21,6 +22,7 @@ * - 'evidence': string, UUID of the associated evidence record. * - 'file_name': string, Name of the file. * - 'file_size': int, Size of the file in bytes. + * - 'file_mime': string, The MIME of the file * - 'created': int, Timestamp of when the record was created. */ public function __construct(array $data) @@ -29,6 +31,7 @@ $this->evidence = $data['evidence'] ?? ''; $this->fileName = $data['file_name'] ?? ''; $this->fileSize = isset($data['file_size']) ? (int)$data['file_size'] : 0; + $this->fileMime = $data['file_mime'] ?? ''; $this->created = isset($data['created']) ? (int)$data['created'] : time(); } @@ -72,6 +75,16 @@ return $this->fileSize; } + /** + * Get the MIME type of the file. + * + * @return string + */ + public function getFileMime(): string + { + return $this->fileMime; + } + /** * Get the timestamp of when the record was created. * @@ -93,6 +106,7 @@ 'evidence' => $this->evidence, 'file_name' => $this->fileName, 'file_size' => $this->fileSize, + 'file_mime' => $this->fileMime, 'created' => $this->created, ]; }