Refactor and enhance peer resolution logic
This commit is contained in:
parent
aba9adf916
commit
3311862263
1 changed files with 176 additions and 95 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
if(is_string($identifiedAs))
|
||||
{
|
||||
$identifiedAs = PeerAddress::fromAddress($identifiedAs);
|
||||
}
|
||||
|
||||
// Resolve the peer from the local database if it exists
|
||||
try
|
||||
{
|
||||
$registeredPeer = RegisteredPeerManager::getPeerByAddress($peerAddress);
|
||||
$existingPeer = 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);
|
||||
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
|
||||
}
|
||||
|
||||
// Return not found if the peer was found but is disabled
|
||||
if($registeredPeer !== null && !$registeredPeer->isEnabled())
|
||||
if($existingPeer === null)
|
||||
{
|
||||
throw new StandardException('The requested peer is disabled', StandardError::PEER_NOT_FOUND);
|
||||
}
|
||||
// if the peer doesn't exist, resolve it externally and synchronize it
|
||||
|
||||
// If the peer was not found but the peer resides in an external server, resolve it
|
||||
try
|
||||
{
|
||||
if($registeredPeer === null && $peerAddress->getDomain() !== Configuration::getInstanceConfiguration()->getDomain())
|
||||
{
|
||||
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);
|
||||
}
|
||||
// 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())
|
||||
{
|
||||
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()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue