diff --git a/src/Socialbox/Classes/StandardMethods/AddressBook/AddressBookGetContact.php b/src/Socialbox/Classes/StandardMethods/AddressBook/AddressBookGetContact.php index 756fc37..a51e971 100644 --- a/src/Socialbox/Classes/StandardMethods/AddressBook/AddressBookGetContact.php +++ b/src/Socialbox/Classes/StandardMethods/AddressBook/AddressBookGetContact.php @@ -43,13 +43,11 @@ return $rpcRequest->produceError(StandardError::NOT_FOUND, 'Contact does not exist'); } - $contact = ContactManager::getContact($request->getPeer(), $address); + $rpcRequest->produceResponse(ContactManager::getStandardContact($request->getPeer(), $address)); } catch(DatabaseOperationException $e) { throw new StandardRpcException('Failed to get contact', StandardError::INTERNAL_SERVER_ERROR, $e); } - - return $rpcRequest->produceResponse($contact->toStandard()); } } \ No newline at end of file diff --git a/src/Socialbox/Managers/ContactManager.php b/src/Socialbox/Managers/ContactManager.php index 4bd00e1..906fc74 100644 --- a/src/Socialbox/Managers/ContactManager.php +++ b/src/Socialbox/Managers/ContactManager.php @@ -8,10 +8,13 @@ use Socialbox\Classes\Database; use Socialbox\Enums\Types\ContactRelationshipType; use Socialbox\Exceptions\DatabaseOperationException; + use Socialbox\Exceptions\Standard\StandardRpcException; use Socialbox\Objects\Database\ContactDatabaseRecord; use Socialbox\Objects\Database\ContactKnownKeyRecord; use Socialbox\Objects\PeerAddress; + use Socialbox\Objects\Standard\ContactRecord; use Socialbox\Objects\Standard\SigningKey; + use Socialbox\Socialbox; class ContactManager { @@ -173,7 +176,7 @@ } /** - * Updates the relationship type of a contact associated with a specific peer. + * Updates the relationship type of contact associated with a specific peer. * * @param string $peerUuid The unique identifier for the peer whose contact relationship is to be updated. * @param string|PeerAddress $contactAddress The address of the contact to update. Can be provided as a string or an instance of PeerAddress. @@ -476,4 +479,38 @@ throw new DatabaseOperationException('Failed to get the number of signing keys for a contact from the database', $e); } } + + /** + * Returns a standard contact record for a given peer UUID and contact address. + * + * @param string $peerUuid The unique identifier of the peer. + * @param string|PeerAddress $contactAddress The contact's address, either as a string or a PeerAddress instance. + * @return ContactRecord|null The standard contact record if found, or null if no matching contact exists. + * @throws DatabaseOperationException If the database query fails. + */ + public static function getStandardContact(string $peerUuid, string|PeerAddress $contactAddress): ?ContactRecord + { + $contact = self::getContact($peerUuid, $contactAddress); + if($contact === null) + { + return null; + } + + try + { + $peer = Socialbox::resolvePeer($contactAddress); + } + catch (StandardRpcException $e) + { + $peer = null; + } + + return new ContactRecord([ + 'address' => $contact->getContactPeerAddress(), + 'peer' => $peer, + 'relationship' => $contact->getRelationship(), + 'known_keys' => self::contactGetSigningKeys($contact), + 'added_timestamp' => $contact->getCreated()->getTimestamp() + ]); + } } \ No newline at end of file diff --git a/src/Socialbox/Objects/Database/ContactKnownKeyRecord.php b/src/Socialbox/Objects/Database/ContactKnownKeyRecord.php index 1dd8de4..ca2d075 100644 --- a/src/Socialbox/Objects/Database/ContactKnownKeyRecord.php +++ b/src/Socialbox/Objects/Database/ContactKnownKeyRecord.php @@ -5,6 +5,7 @@ use DateTime; use InvalidArgumentException; use Socialbox\Interfaces\SerializableInterface; + use Socialbox\Objects\Standard\KnownSigningKey; class ContactKnownKeyRecord implements SerializableInterface { @@ -16,6 +17,12 @@ private DateTime $created; private DateTime $trustedOn; + /** + * Constructs a new instance with the provided parameters. + * + * @param array $data The array of data to use for the object. + * @throws \DateMalformedStringException If the date string is malformed. + */ public function __construct(array $data) { $this->contactUuid = $data['contact_uuid']; @@ -96,36 +103,71 @@ } } + /** + * Gets the contact UUID. + * + * @return string The contact UUID. + */ public function getContactUuid(): string { return $this->contactUuid; } + /** + * Gets the signature UUID. + * + * @return string The signature UUID. + */ public function getSignatureUuid(): string { return $this->signatureUuid; } + /** + * Gets the signature name. + * + * @return string The signature name. + */ public function getSignatureName(): string { return $this->signatureName; } + /** + * Gets the signature key. + * + * @return string The signature key. + */ public function getSignatureKey(): string { return $this->signatureKey; } + /** + * Gets the expiration date. + * + * @return DateTime|null The expiration date. + */ public function getExpires(): ?DateTime { return $this->expires; } + /** + * Gets the creation date. + * + * @return DateTime The creation date. + */ public function getCreated(): DateTime { return $this->created; } + /** + * Gets the trusted on date. + * + * @return DateTime The trusted on date. + */ public function getTrustedOn(): DateTime { return $this->trustedOn; @@ -139,6 +181,21 @@ return new self($data); } + /** + * @inheritDoc + */ + public function toStandard(): KnownSigningKey + { + return new KnownSigningKey([ + 'uuid' => $this->signatureUuid, + 'name' => $this->signatureName, + 'public_key' => $this->signatureKey, + 'expires' => $this->expires?->getTimestamp(), + 'created' => $this->created->getTimestamp(), + 'trusted_on' => $this->trustedOn->getTimestamp() + ]); + } + /** * @inheritDoc */ diff --git a/src/Socialbox/Objects/Standard/ContactRecord.php b/src/Socialbox/Objects/Standard/ContactRecord.php index 919efb0..841ef9f 100644 --- a/src/Socialbox/Objects/Standard/ContactRecord.php +++ b/src/Socialbox/Objects/Standard/ContactRecord.php @@ -2,6 +2,7 @@ namespace Socialbox\Objects\Standard; + use InvalidArgumentException; use Socialbox\Enums\Types\ContactRelationshipType; use Socialbox\Interfaces\SerializableInterface; use Socialbox\Objects\PeerAddress; @@ -9,7 +10,12 @@ class ContactRecord implements SerializableInterface { private PeerAddress $address; + private ?Peer $peer; private ContactRelationshipType $relationship; + /** + * @var KnownSigningKey[] + */ + private array $knownKeys; private int $addedTimestamp; /** @@ -20,7 +26,53 @@ public function __construct(array $data) { $this->address = PeerAddress::fromAddress($data['address']); - $this->relationship = ContactRelationshipType::tryFrom($data['relationship']) ?? ContactRelationshipType::MUTUAL; + if(is_array($data['peer'])) + { + $this->peer = Peer::fromArray($data['peer']); + } + elseif($data['peer'] instanceof Peer) + { + $this->peer = $data['peer']; + } + elseif(is_null($data['peer'])) + { + $this->peer = null; + } + else + { + throw new InvalidArgumentException('Invalid peer data'); + } + + if($data['relationship'] instanceof ContactRelationshipType) + { + $this->relationship = $data['relationship']; + } + elseif(is_string($data['relationship'])) + { + $this->relationship = ContactRelationshipType::tryFrom($data['relationship']) ?? ContactRelationshipType::MUTUAL; + } + else + { + throw new InvalidArgumentException('Invalid relationship data'); + } + + $this->knownKeys = []; + + foreach($data['known_keys'] as $key) + { + if(is_array($key)) + { + $this->knownKeys[] = KnownSigningKey::fromArray($key); + } + elseif($key instanceof KnownSigningKey) + { + $this->knownKeys[] = $key; + } + else + { + throw new InvalidArgumentException('Invalid known key data'); + } + } $this->addedTimestamp = $data['added_timestamp']; } @@ -34,6 +86,16 @@ return $this->address; } + /** + * Retrieves the peer of the contact. + * + * @return Peer|null Returns the peer of the contact. If the peer is not known, null is returned. + */ + public function getPeer(): ?Peer + { + return $this->peer; + } + /** * Retrieves the relationship of the contact. * @@ -44,6 +106,16 @@ return $this->relationship; } + /** + * Retrieves the known keys of the contact. + * + * @return KnownSigningKey[] Returns the known keys of the contact. + */ + public function getKnownKeys(): array + { + return $this->knownKeys; + } + /** * Retrieves the timestamp when the contact was added. * @@ -57,7 +129,7 @@ /** * @inheritDoc */ - public static function fromArray(array $data): object + public static function fromArray(array $data): ContactRecord { return new self($data); } @@ -69,7 +141,9 @@ { return [ 'address' => $this->address->getAddress(), + 'peer' => $this->peer?->toArray(), 'relationship' => $this->relationship->value, + 'known_keys' => array_map(function($key) {return $key->toArray();}, $this->knownKeys), 'added_timestamp' => $this->addedTimestamp ]; } diff --git a/src/Socialbox/Objects/Standard/KnownSigningKey.php b/src/Socialbox/Objects/Standard/KnownSigningKey.php new file mode 100644 index 0000000..b85b6be --- /dev/null +++ b/src/Socialbox/Objects/Standard/KnownSigningKey.php @@ -0,0 +1,161 @@ +uuid = $data['uuid']; + $this->name = $data['name']; + $this->publicKey = $data['public_key']; + + if(is_int($data['expires'])) + { + $this->expires = $data['expires']; + } + elseif($data['expires'] instanceof DateTime) + { + $this->expires = $data['expires']->getTimestamp(); + } + else + { + throw new InvalidArgumentException('Invalid expires value'); + } + + if(is_int($data['created'])) + { + $this->created = $data['created']; + } + elseif($data['created'] instanceof DateTime) + { + $this->created = $data['created']->getTimestamp(); + } + else + { + throw new InvalidArgumentException('Invalid created value'); + } + + if(is_int($data['trusted_on'])) + { + $this->trustedOn = $data['trusted_on']; + } + elseif($data['trusted_on'] instanceof DateTime) + { + $this->trustedOn = $data['trusted_on']->getTimestamp(); + } + else + { + throw new InvalidArgumentException('Invalid trusted_on value'); + } + } + + /** + * Retrieves the UUID associated with this instance. + * + * @return string The UUID as a string. + */ + public function getUuid(): string + { + return $this->uuid; + } + + /** + * Retrieves the name associated with this instance. + * + * @return string|null The name as a string, or null if not set. + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * + * Retrieves the public key. + * + * @return string The public key. + */ + public function getPublicKey(): string + { + return $this->publicKey; + } + + /** + * Retrieves the expiration time. + * + * @return int The expiration time as an integer. + */ + public function getExpires(): int + { + return $this->expires; + } + + /** + * + * @return int The timestamp representing the creation time. + */ + public function getCreated(): int + { + return $this->created; + } + + /** + * Retrieves the timestamp representing the time the key was trusted. + * + * @return int The timestamp representing the time the key was trusted. + */ + public function getTrustedOn(): int + { + return $this->trustedOn; + } + + /** + * @inheritDoc + */ + public static function fromArray(array $data): KnownSigningKey + { + return new self($data); + } + + /** + * @inheritDoc + */ + public function toArray(): array + { + return [ + 'uuid' => $this->uuid, + 'name' => $this->name, + 'public_key' => $this->publicKey, + 'expires' => $this->expires, + 'created' => $this->created, + 'trusted_on' => $this->trustedOn + ]; + } + } \ No newline at end of file