Refactor and enhance peer resolution logic

This commit is contained in:
netkas 2025-01-25 17:26:13 -05:00
parent aba9adf916
commit 3311862263

View file

@ -11,11 +11,14 @@
use Socialbox\Classes\ServerResolver;
use Socialbox\Classes\Utilities;
use Socialbox\Classes\Validator;
use Socialbox\Enums\Flags\PeerFlags;
use Socialbox\Enums\PrivacyState;
use Socialbox\Enums\ReservedUsernames;
use Socialbox\Enums\SessionState;
use Socialbox\Enums\StandardError;
use Socialbox\Enums\StandardHeaders;
use Socialbox\Enums\StandardMethods;
use Socialbox\Enums\Types\ContactRelationshipType;
use Socialbox\Enums\Types\RequestType;
use Socialbox\Exceptions\CryptographyException;
use Socialbox\Exceptions\DatabaseOperationException;
@ -23,11 +26,12 @@
use Socialbox\Exceptions\ResolutionException;
use Socialbox\Exceptions\RpcException;
use Socialbox\Exceptions\StandardException;
use Socialbox\Managers\ContactManager;
use Socialbox\Managers\ExternalSessionManager;
use Socialbox\Managers\PeerInformationManager;
use Socialbox\Managers\RegisteredPeerManager;
use Socialbox\Managers\SessionManager;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\Database\PeerRecord;
use Socialbox\Objects\PeerAddress;
use Socialbox\Objects\Standard\Peer;
use Socialbox\Objects\Standard\ServerInformation;
@ -239,21 +243,21 @@
}
// If-clause for handling the host peer, host peers are always enabled unless the fist clause is true
// in which case the host was blocked by this server.
elseif($clientRequest->getIdentifyAs() === ReservedUsernames::HOST->value)
elseif($clientRequest->getIdentifyAs()->getUsername() === ReservedUsernames::HOST->value)
{
$serverInformation = self::getExternalServerInformation($clientRequest->getIdentifyAs()->getDomain());
// If the host is not registered, register it
if($registeredPeer === null)
{
$peerUuid = RegisteredPeerManager::createPeer(PeerAddress::fromAddress($clientRequest->getHeader(StandardHeaders::IDENTIFY_AS)));
RegisteredPeerManager::updateDisplayName($peerUuid, $serverInformation->getServerName());
RegisteredPeerManager::enablePeer($peerUuid);
}
// Otherwise, update the display name if it has changed
else
{
RegisteredPeerManager::updateDisplayName($registeredPeer->getUuid(), $serverInformation->getServerName());
// If the host is registered, but disabled, enable it
if(!$registeredPeer->isEnabled())
{
RegisteredPeerManager::enablePeer($registeredPeer->getUuid());
}
}
}
// Otherwise the peer isn't registered, so we need to register it
@ -273,15 +277,22 @@
}
// Generate server's encryption keys for this session
$serverEncryptionKey = Cryptography::generateEncryptionKeyPair();
$serverEncryptionKeyPair = Cryptography::generateEncryptionKeyPair();
// Create the session passing on the registered peer, client name, version, and public keys
$sessionUuid = SessionManager::createSession($registeredPeer, $clientRequest->getClientName(), $clientRequest->getClientVersion(), $clientPublicSigningKey, $clientPublicEncryptionKey, $serverEncryptionKey);
$sessionUuid = SessionManager::createSession(
peer: $registeredPeer,
clientName: $clientRequest->getClientName(),
clientVersion: $clientRequest->getClientVersion(),
clientPublicSigningKey: $clientPublicSigningKey,
clientPublicEncryptionKey: $clientPublicEncryptionKey,
serverEncryptionKeyPair: $serverEncryptionKeyPair
);
// The server responds back with the session UUID & The server's public encryption key as the header
http_response_code(201); // Created
header('Content-Type: text/plain');
header(StandardHeaders::ENCRYPTION_PUBLIC_KEY->value . ': ' . $serverEncryptionKey->getPublicKey());
header(StandardHeaders::ENCRYPTION_PUBLIC_KEY->value . ': ' . $serverEncryptionKeyPair->getPublicKey());
print($sessionUuid); // Return the session UUID
}
catch(InvalidArgumentException $e)
@ -514,7 +525,7 @@
// Synchronize the peer
try
{
self::synchronizeExternalPeer($clientRequest->getIdentifyAs());
self::resolvePeer($clientRequest->getIdentifyAs());
}
catch (DatabaseOperationException $e)
{
@ -730,33 +741,6 @@
}
}
/**
* Synchronizes an external peer by resolving and integrating its information into the system.
*
* @param PeerAddress|Peer|string $externalPeer The external peer to synchronize, provided as a PeerAddress instance or a string.
* @return void
* @throws CryptographyException If there is an error in the cryptography
* @throws DatabaseOperationException If there is an error while processing the peer against the database
* @throws ResolutionException If the synchronization process fails due to unresolved peer information or other errors.
* @throws RpcException If there is an RPC exception while connecting to the remote server
*/
public static function synchronizeExternalPeer(PeerAddress|Peer|string $externalPeer): void
{
if($externalPeer instanceof Peer)
{
RegisteredPeerManager::synchronizeExternalPeer($externalPeer);
return;
}
if($externalPeer instanceof PeerAddress)
{
$externalPeer = $externalPeer->getAddress();
}
$client = self::getExternalSession($externalPeer->getDomain());
RegisteredPeerManager::synchronizeExternalPeer($client->resolvePeer($externalPeer));
}
/**
* Resolves an external peer based on the given peer address or string identifier.
*
@ -766,88 +750,185 @@
* @throws StandardException Thrown if there was an error with the resolution process
*/
public static function resolvePeer(PeerAddress|string $peerAddress, null|PeerAddress|string $identifiedAs=null): Peer
{
if($peerAddress->getDomain() !== Configuration::getInstanceConfiguration()->getDomain())
{
return self::resolveExternalPeer($peerAddress, $identifiedAs);
}
return self::resolveLocalPeer($peerAddress);
}
/**
* Resolves a peer based on the given peer address or string identifier.
*
* @param PeerAddress|string $peerAddress The peer address or string identifier to be resolved.
* @param PeerAddress|string|null $identifiedAs Optional. The peer address or string identifier by which the caller is identified
* @return Peer The resolved peer after synchronization.
* @throws StandardException Thrown if there was an error with the resolution process
*/
private static function resolveExternalPeer(PeerAddress|string $peerAddress, null|PeerAddress|string $identifiedAs=null): Peer
{
if(is_string($peerAddress))
{
$peerAddress = PeerAddress::fromAddress($peerAddress);
}
try
if(is_string($identifiedAs))
{
$registeredPeer = RegisteredPeerManager::getPeerByAddress($peerAddress);
}
catch (DatabaseOperationException $e)
{
throw new StandardException('There was an unexpected error while trying to resolve the peer internally', StandardError::INTERNAL_SERVER_ERROR, $e);
$identifiedAs = PeerAddress::fromAddress($identifiedAs);
}
// Return not found if the peer was found but is disabled
if($registeredPeer !== null && !$registeredPeer->isEnabled())
{
throw new StandardException('The requested peer is disabled', StandardError::PEER_NOT_FOUND);
}
// If the peer was not found but the peer resides in an external server, resolve it
// Resolve the peer from the local database if it exists
try
{
if($registeredPeer === null && $peerAddress->getDomain() !== Configuration::getInstanceConfiguration()->getDomain())
{
try
{
$registeredPeer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress);
$existingPeer = RegisteredPeerManager::getPeerByAddress($peerAddress);
}
catch (DatabaseOperationException $e)
catch(DatabaseOperationException $e)
{
throw new StandardException('There was an unexpected error while trying to resolve the peer externally: ' . $e->getMessage(), StandardError::RESOLUTION_FAILED, $e);
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
// Synchronize the peer for future use
self::synchronizeExternalPeer($registeredPeer);
}
// If the peer was found and the peer does reside in an external server, re-resolve it if necessary
elseif($registeredPeer !== null && $peerAddress->getDomain() !== Configuration::getInstanceConfiguration()->getDomain())
{
if($registeredPeer->getUpdated()->getTimestamp() < time() - Configuration::getPoliciesConfiguration()->getPeerSyncInterval())
if($existingPeer === null)
{
// if the peer doesn't exist, resolve it externally and synchronize it
try
{
$registeredPeer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress);
}
catch (DatabaseOperationException $e)
{
throw new StandardException('There was an unexpected error while trying to resolve the peer externally: ' . $e->getMessage(), StandardError::RESOLUTION_FAILED, $e);
}
// Synchronize the peer for future use
self::synchronizeExternalPeer($registeredPeer);
}
}
}
catch(StandardException $e)
{
throw $e;
$peer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress, $identifiedAs);
}
catch(Exception $e)
{
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::RESOLUTION_FAILED, $e);
}
if($registeredPeer === null)
try
{
RegisteredPeerManager::synchronizeExternalPeer($peer);
}
catch(DatabaseOperationException $e)
{
throw new StandardException('Failed to synchronize the external peer: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
return $peer;
}
// If the peer exists, but it's outdated, synchronize it
if($existingPeer->getUpdated()->getTimestamp() < time() - Configuration::getPoliciesConfiguration()->getPeerSyncInterval())
{
try
{
$peer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress, $identifiedAs);
}
catch(Exception $e)
{
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::RESOLUTION_FAILED, $e);
}
try
{
RegisteredPeerManager::synchronizeExternalPeer($peer);
}
catch(DatabaseOperationException $e)
{
throw new StandardException('Failed to synchronize the external peer: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
return $peer;
}
// If the peer exists and is up to date, return it
return $existingPeer->toStandardPeer();
}
/**
* Resolves a peer locally based on the given peer address or string identifier.
*
* @param PeerAddress|string $peerAddress The peer address or string identifier to be resolved.
* @param PeerAddress|string|null $identifiedAs Optional. The peer address or string identifier by which the caller is identified
* @return Peer The resolved peer after synchronization.
* @throws StandardException Thrown if there was an error with the resolution process
*/
private static function resolveLocalPeer(PeerAddress|string $peerAddress, null|PeerAddress|string $identifiedAs=null): Peer
{
if(is_string($peerAddress))
{
$peerAddress = PeerAddress::fromAddress($peerAddress);
}
if(is_string($identifiedAs))
{
$identifiedAs = PeerAddress::fromAddress($identifiedAs);
}
// Resolve the peer
try
{
$peer = RegisteredPeerManager::getPeerByAddress($peerAddress);
if($peer === null)
{
throw new StandardException('The requested peer was not found', StandardError::PEER_NOT_FOUND);
}
if($registeredPeer instanceof PeerRecord)
}
catch(DatabaseOperationException $e)
{
$registeredPeer = $registeredPeer->toStandardPeer();
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
return $registeredPeer;
try
{
// Get the initial peer information fields, public always
$peerInformationFields = PeerInformationManager::getFilteredFields($peer, [PrivacyState::PUBLIC]);
}
catch (DatabaseOperationException $e)
{
throw new StandardException('Failed to resolve peer information: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
private static function localResolvePeer(PeerAddress|string $peerAddress, null|PeerAddress|string $identifiedAs=null)
// If there's an identifier, we can resolve more information fields if the target peer has added the caller
// as a contact or if the caller is a trusted contact
if($identifiedAs !== null)
{
try
{
$peerContact = ContactManager::getContact($peer->getUuid(), $identifiedAs);
}
catch (DatabaseOperationException $e)
{
throw new StandardException('Failed to resolve peer because there was an error while trying to retrieve contact information for the peer', StandardError::INTERNAL_SERVER_ERROR, $e);
}
// If it is a contact, what sort of contact? retrieve depending on the contact type
if($peerContact !== null)
{
try
{
if($peerContact->getRelationship() === ContactRelationshipType::MUTUAL)
{
// Retrieve the mutual information fields
array_merge($peerInformationFields, PeerInformationManager::getFilteredFields($peer, [PrivacyState::CONTACTS]));
}
elseif($peerContact->getRelationship() === ContactRelationshipType::TRUSTED)
{
// Retrieve the mutual and trusted information fields
array_merge($peerInformationFields, PeerInformationManager::getFilteredFields($peer, [PrivacyState::CONTACTS, PrivacyState::TRUSTED]));
}
}
catch (DatabaseOperationException $e)
{
throw new StandardException('Failed to resolve peer information: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
}
}
}
return new Peer([
'address' => $peer->getAddress(),
'information_fields' => $peerInformationFields,
'flags' => PeerFlags::toString($peer->getFlags()),
'registered' => $peer->getCreated()->getTimestamp()
]);
}
/**