Made message signing in Cryptography use SHA512 as the message content for... #1

Closed
netkas wants to merge 421 commits from master into dev
Showing only changes of commit 3311862263 - Show all commits

View file

@ -11,11 +11,14 @@
use Socialbox\Classes\ServerResolver; use Socialbox\Classes\ServerResolver;
use Socialbox\Classes\Utilities; use Socialbox\Classes\Utilities;
use Socialbox\Classes\Validator; use Socialbox\Classes\Validator;
use Socialbox\Enums\Flags\PeerFlags;
use Socialbox\Enums\PrivacyState;
use Socialbox\Enums\ReservedUsernames; use Socialbox\Enums\ReservedUsernames;
use Socialbox\Enums\SessionState; use Socialbox\Enums\SessionState;
use Socialbox\Enums\StandardError; use Socialbox\Enums\StandardError;
use Socialbox\Enums\StandardHeaders; use Socialbox\Enums\StandardHeaders;
use Socialbox\Enums\StandardMethods; use Socialbox\Enums\StandardMethods;
use Socialbox\Enums\Types\ContactRelationshipType;
use Socialbox\Enums\Types\RequestType; use Socialbox\Enums\Types\RequestType;
use Socialbox\Exceptions\CryptographyException; use Socialbox\Exceptions\CryptographyException;
use Socialbox\Exceptions\DatabaseOperationException; use Socialbox\Exceptions\DatabaseOperationException;
@ -23,11 +26,12 @@
use Socialbox\Exceptions\ResolutionException; use Socialbox\Exceptions\ResolutionException;
use Socialbox\Exceptions\RpcException; use Socialbox\Exceptions\RpcException;
use Socialbox\Exceptions\StandardException; use Socialbox\Exceptions\StandardException;
use Socialbox\Managers\ContactManager;
use Socialbox\Managers\ExternalSessionManager; use Socialbox\Managers\ExternalSessionManager;
use Socialbox\Managers\PeerInformationManager;
use Socialbox\Managers\RegisteredPeerManager; use Socialbox\Managers\RegisteredPeerManager;
use Socialbox\Managers\SessionManager; use Socialbox\Managers\SessionManager;
use Socialbox\Objects\ClientRequest; use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\Database\PeerRecord;
use Socialbox\Objects\PeerAddress; use Socialbox\Objects\PeerAddress;
use Socialbox\Objects\Standard\Peer; use Socialbox\Objects\Standard\Peer;
use Socialbox\Objects\Standard\ServerInformation; 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 // 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. // 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 the host is not registered, register it
if($registeredPeer === null) if($registeredPeer === null)
{ {
$peerUuid = RegisteredPeerManager::createPeer(PeerAddress::fromAddress($clientRequest->getHeader(StandardHeaders::IDENTIFY_AS))); $peerUuid = RegisteredPeerManager::createPeer(PeerAddress::fromAddress($clientRequest->getHeader(StandardHeaders::IDENTIFY_AS)));
RegisteredPeerManager::updateDisplayName($peerUuid, $serverInformation->getServerName());
RegisteredPeerManager::enablePeer($peerUuid); RegisteredPeerManager::enablePeer($peerUuid);
} }
// Otherwise, update the display name if it has changed
else 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 // Otherwise the peer isn't registered, so we need to register it
@ -273,15 +277,22 @@
} }
// Generate server's encryption keys for this session // 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 // 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 // The server responds back with the session UUID & The server's public encryption key as the header
http_response_code(201); // Created http_response_code(201); // Created
header('Content-Type: text/plain'); 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 print($sessionUuid); // Return the session UUID
} }
catch(InvalidArgumentException $e) catch(InvalidArgumentException $e)
@ -514,7 +525,7 @@
// Synchronize the peer // Synchronize the peer
try try
{ {
self::synchronizeExternalPeer($clientRequest->getIdentifyAs()); self::resolvePeer($clientRequest->getIdentifyAs());
} }
catch (DatabaseOperationException $e) 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. * 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 * @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 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)) if(is_string($peerAddress))
{ {
$peerAddress = PeerAddress::fromAddress($peerAddress); $peerAddress = PeerAddress::fromAddress($peerAddress);
} }
try if(is_string($identifiedAs))
{ {
$registeredPeer = RegisteredPeerManager::getPeerByAddress($peerAddress); $identifiedAs = PeerAddress::fromAddress($identifiedAs);
}
catch (DatabaseOperationException $e)
{
throw new StandardException('There was an unexpected error while trying to resolve the peer internally', StandardError::INTERNAL_SERVER_ERROR, $e);
} }
// Return not found if the peer was found but is disabled // Resolve the peer from the local database if it exists
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
try try
{ {
if($registeredPeer === null && $peerAddress->getDomain() !== Configuration::getInstanceConfiguration()->getDomain()) $existingPeer = RegisteredPeerManager::getPeerByAddress($peerAddress);
{
try
{
$registeredPeer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($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 if($existingPeer === null)
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 the peer doesn't exist, resolve it externally and synchronize it
try try
{ {
$registeredPeer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress); $peer = self::getExternalSession($peerAddress->getDomain())->resolvePeer($peerAddress, $identifiedAs);
}
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;
} }
catch(Exception $e) catch(Exception $e)
{ {
throw new StandardException('Failed to resolve the peer: ' . $e->getMessage(), StandardError::RESOLUTION_FAILED, $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); 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()
]);
} }
/** /**