Add confidentiality handling to evidence management
Some checks are pending
CI / release (push) Waiting to run
CI / debug (push) Waiting to run
CI / check-phpunit (push) Waiting to run
CI / check-phpdoc (push) Waiting to run
CI / generate-phpdoc (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / release-documentation (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions

This commit is contained in:
netkas 2025-06-02 18:29:58 -04:00
parent c3748c5f51
commit 319aa80159
Signed by: netkas
GPG key ID: 4D8629441B76E4CC
6 changed files with 275 additions and 10 deletions

View file

@ -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.
*

View file

@ -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);
}
}
}

View file

@ -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.
*/

View file

@ -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;
}
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();
}
}

View file

@ -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,

View file

@ -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,
];
}