Add methods for deleting and updating peer information

This commit is contained in:
netkas 2025-01-04 15:32:42 -05:00
parent cb1cc5ee15
commit b04de2f2a7
5 changed files with 343 additions and 25 deletions

View file

@ -0,0 +1,39 @@
<?php
namespace Socialbox\Classes\StandardMethods;
use Exception;
use Socialbox\Abstracts\Method;
use Socialbox\Classes\Configuration;
use Socialbox\Enums\StandardError;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Managers\RegisteredPeerManager;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\RpcRequest;
class SettingsDeleteDisplayName extends Method
{
/**
* @inheritDoc
*/
public static function execute(ClientRequest $request, RpcRequest $rpcRequest): ?SerializableInterface
{
if(Configuration::getRegistrationConfiguration()->isDisplayNameRequired())
{
return $rpcRequest->produceError(StandardError::FORBIDDEN, 'A display name is required for this server');
}
try
{
// Set the password
RegisteredPeerManager::deleteDisplayName($request->getPeer());
}
catch(Exception $e)
{
throw new StandardException('Failed to set password due to an internal exception', StandardError::INTERNAL_SERVER_ERROR, $e);
}
return $rpcRequest->produceResponse(true);
}
}

View file

@ -34,4 +34,14 @@ class Validator
return preg_match(self::USERNAME_PATTERN, $username) === 1; return preg_match(self::USERNAME_PATTERN, $username) === 1;
} }
/**
* Validates whether a given phone number conforms to the required format.
*
* @param string $phoneNumber The phone number to validate. Must start with a "+" followed by 1 to 15 digits.
* @return bool Returns true if the phone number is valid according to the format, otherwise false.
*/
public static function validatePhoneNumber(string $phoneNumber): bool
{
return preg_match("/^\+[0-9]{1,15}$/", $phoneNumber) === 1;
}
} }

View file

@ -11,6 +11,7 @@
use Socialbox\Classes\StandardMethods\GetTermsOfService; use Socialbox\Classes\StandardMethods\GetTermsOfService;
use Socialbox\Classes\StandardMethods\Ping; use Socialbox\Classes\StandardMethods\Ping;
use Socialbox\Classes\StandardMethods\SettingsAddSigningKey; use Socialbox\Classes\StandardMethods\SettingsAddSigningKey;
use Socialbox\Classes\StandardMethods\SettingsDeleteDisplayName;
use Socialbox\Classes\StandardMethods\SettingsGetSigningKeys; use Socialbox\Classes\StandardMethods\SettingsGetSigningKeys;
use Socialbox\Classes\StandardMethods\SettingsSetDisplayName; use Socialbox\Classes\StandardMethods\SettingsSetDisplayName;
use Socialbox\Classes\StandardMethods\SettingsSetPassword; use Socialbox\Classes\StandardMethods\SettingsSetPassword;
@ -55,6 +56,7 @@
case SETTINGS_SET_PASSWORD = 'settingsSetPassword'; case SETTINGS_SET_PASSWORD = 'settingsSetPassword';
case SETTINGS_SET_OTP = 'settingsSetOtp'; case SETTINGS_SET_OTP = 'settingsSetOtp';
case SETTINGS_SET_DISPLAY_NAME = 'settingsSetDisplayName'; case SETTINGS_SET_DISPLAY_NAME = 'settingsSetDisplayName';
case SETTINGS_DELETE_DISPLAY_NAME = 'settingsDeleteDisplayName';
case SETTINGS_SET_DISPLAY_PICTURE = 'settingsSetDisplayPicture'; case SETTINGS_SET_DISPLAY_PICTURE = 'settingsSetDisplayPicture';
case SETTINGS_SET_EMAIL = 'settingsSetEmail'; case SETTINGS_SET_EMAIL = 'settingsSetEmail';
case SETTINGS_SET_PHONE = 'settingsSetPhone'; case SETTINGS_SET_PHONE = 'settingsSetPhone';
@ -90,6 +92,7 @@
self::SETTINGS_SET_PASSWORD => SettingsSetPassword::execute($request, $rpcRequest), self::SETTINGS_SET_PASSWORD => SettingsSetPassword::execute($request, $rpcRequest),
self::SETTINGS_SET_DISPLAY_NAME => SettingsSetDisplayName::execute($request, $rpcRequest), self::SETTINGS_SET_DISPLAY_NAME => SettingsSetDisplayName::execute($request, $rpcRequest),
self::SETTINGS_DELETE_DISPLAY_NAME => SettingsDeleteDisplayName::execute($request, $rpcRequest),
self::SETTINGS_ADD_SIGNING_KEY => SettingsAddSigningKey::execute($request, $rpcRequest), self::SETTINGS_ADD_SIGNING_KEY => SettingsAddSigningKey::execute($request, $rpcRequest),
self::SETTINGS_GET_SIGNING_KEYS => SettingsGetSigningKeys::execute($request, $rpcRequest), self::SETTINGS_GET_SIGNING_KEYS => SettingsGetSigningKeys::execute($request, $rpcRequest),

View file

@ -2,7 +2,6 @@
namespace Socialbox\Managers; namespace Socialbox\Managers;
use DateMalformedStringException;
use Exception; use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use PDO; use PDO;
@ -10,10 +9,10 @@
use Socialbox\Classes\Configuration; use Socialbox\Classes\Configuration;
use Socialbox\Classes\Database; use Socialbox\Classes\Database;
use Socialbox\Classes\Logger; use Socialbox\Classes\Logger;
use Socialbox\Classes\Validator;
use Socialbox\Enums\Flags\PeerFlags; use Socialbox\Enums\Flags\PeerFlags;
use Socialbox\Exceptions\DatabaseOperationException; use Socialbox\Exceptions\DatabaseOperationException;
use Socialbox\Objects\Database\RegisteredPeerRecord; use Socialbox\Objects\Database\RegisteredPeerRecord;
use Socialbox\Objects\Database\SecurePasswordRecord;
use Socialbox\Objects\PeerAddress; use Socialbox\Objects\PeerAddress;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
@ -177,7 +176,7 @@
return new RegisteredPeerRecord($result); return new RegisteredPeerRecord($result);
} }
catch(PDOException | DateMalformedStringException $e) catch(Exception $e)
{ {
throw new DatabaseOperationException('Failed to get the peer from the database', $e); throw new DatabaseOperationException('Failed to get the peer from the database', $e);
} }
@ -365,6 +364,41 @@
} }
} }
/**
* Deletes the display name of a registered peer identified by a unique identifier or RegisteredPeerRecord object.
*
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
* @return void
* @throws InvalidArgumentException If the peer is external and its display name cannot be deleted.
* @throws DatabaseOperationException If there is an error during the database operation.
*/
public static function deleteDisplayName(string|RegisteredPeerRecord $peer): void
{
if(is_string($peer))
{
$peer = self::getPeer($peer);
}
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot delete the display name of an external peer');
}
Logger::getLogger()->verbose(sprintf("Deleting display name of peer %s", $peer->getUuid()));
try
{
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET display_name=NULL WHERE uuid=?');
$uuid = $peer->getUuid();
$statement->bindParam(1, $uuid);
$statement->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to delete the display name of the peer in the database', $e);
}
}
/** /**
* Updates the display picture of a registered peer in the database. * Updates the display picture of a registered peer in the database.
* *
@ -420,37 +454,211 @@
} }
/** /**
* Retrieves the password authentication record associated with the given unique peer identifier or a RegisteredPeerRecord object. * Deletes the display picture of a registered peer based on the given unique identifier or RegisteredPeerRecord object.
* *
* @param string|RegisteredPeerRecord $peerUuid The unique identifier of the peer, or an instance of RegisteredPeerRecord. * @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
* @return SecurePasswordRecord|null Returns a SecurePasswordRecord object if a password authentication record exists, otherwise null. * @return void
* @throws InvalidArgumentException If the peer is external and its display picture cannot be deleted.
* @throws DatabaseOperationException If there is an error during the database operation. * @throws DatabaseOperationException If there is an error during the database operation.
*/ */
public static function getPasswordAuthentication(string|RegisteredPeerRecord $peerUuid): ?SecurePasswordRecord public static function deleteDisplayPicture(string|RegisteredPeerRecord $peer): void
{ {
if($peerUuid instanceof RegisteredPeerRecord) if(is_string($peer))
{ {
$peerUuid = $peerUuid->getUuid(); $peer = self::getPeer($peer);
} }
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot delete the display picture of an external peer');
}
Logger::getLogger()->verbose(sprintf("Deleting display picture of peer %s", $peer->getUuid()));
try try
{ {
$statement = Database::getConnection()->prepare('SELECT * FROM `authentication_passwords` WHERE peer_uuid=?'); $statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET display_picture=NULL WHERE uuid=?');
$statement->bindParam(1, $peerUuid); $uuid = $peer->getUuid();
$statement->bindParam(1, $uuid);
$statement->execute(); $statement->execute();
}
$result = $statement->fetch(PDO::FETCH_ASSOC); catch(PDOException $e)
if($result === false)
{ {
return null; throw new DatabaseOperationException('Failed to delete the display picture of the peer in the database', $e);
}
} }
return new SecurePasswordRecord($result); /**
} * Updates the email address of a registered peer.
catch(PDOException | DateMalformedStringException $e) *
* @param string|RegisteredPeerRecord $peer The unique identifier of the peer, or an instance of RegisteredPeerRecord.
* @param string $emailAddress The new email address to be assigned to the peer.
* @return void
* @throws InvalidArgumentException If the email address is empty, exceeds 256 characters, is not a valid email format, or if the peer is external.
* @throws DatabaseOperationException If there is an error during the database operation.
*/
public static function updateEmailAddress(string|RegisteredPeerRecord $peer, string $emailAddress): void
{ {
throw new DatabaseOperationException('Failed to get the secure password record from the database', $e); if(empty($emailAddress))
{
throw new InvalidArgumentException('The email address cannot be empty');
}
if(strlen($emailAddress) > 256)
{
throw new InvalidArgumentException('The email address cannot exceed 256 characters');
}
if(filter_var($emailAddress, FILTER_VALIDATE_EMAIL) === false)
{
throw new InvalidArgumentException('The email address is not valid');
}
if(is_string($peer))
{
$peer = self::getPeer($peer);
}
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot update the email address of an external peer');
}
Logger::getLogger()->verbose(sprintf("Updating email address of peer %s to %s", $peer->getUuid(), $emailAddress));
try
{
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET email_address=? WHERE uuid=?');
$statement->bindParam(1, $emailAddress);
$uuid = $peer->getUuid();
$statement->bindParam(2, $uuid);
$statement->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to update the email address of the peer in the database', $e);
}
}
/**
* Deletes the email address of a registered peer identified by either a unique identifier or a RegisteredPeerRecord object.
*
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
* @return void
* @throws InvalidArgumentException If the peer is external and its email address cannot be deleted.
* @throws DatabaseOperationException If there is an error during the database operation.
*/
public static function deleteEmailAddress(string|RegisteredPeerRecord $peer): void
{
if(is_string($peer))
{
$peer = self::getPeer($peer);
}
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot delete the email address of an external peer');
}
Logger::getLogger()->verbose(sprintf("Deleting email address of peer %s", $peer->getUuid()));
try
{
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET email_address=NULL WHERE uuid=?');
$uuid = $peer->getUuid();
$statement->bindParam(1, $uuid);
$statement->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to delete the email address of the peer in the database', $e);
}
}
/**
* Updates the phone number of the specified registered peer.
*
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
* @param string $phoneNumber The new phone number to be set for the peer.
* @return void
* @throws InvalidArgumentException If the phone number is empty, exceeds 16 characters, is invalid, or if the peer is external.
* @throws DatabaseOperationException If there is an error during the database operation.
*/
public static function updatePhoneNumber(string|RegisteredPeerRecord $peer, string $phoneNumber): void
{
if(empty($phoneNumber))
{
throw new InvalidArgumentException('The phone number cannot be empty');
}
if(strlen($phoneNumber) > 16)
{
throw new InvalidArgumentException('The phone number cannot exceed 16 characters');
}
if(!Validator::validatePhoneNumber($phoneNumber))
{
throw new InvalidArgumentException('The phone number is not valid');
}
if(is_string($peer))
{
$peer = self::getPeer($peer);
}
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot update the phone number of an external peer');
}
Logger::getLogger()->verbose(sprintf("Updating phone number of peer %s to %s", $peer->getUuid(), $phoneNumber));
try
{
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET phone_number=? WHERE uuid=?');
$statement->bindParam(1, $phoneNumber);
$uuid = $peer->getUuid();
$statement->bindParam(2, $uuid);
$statement->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to update the phone number of the peer in the database', $e);
}
}
/**
* Deletes the phone number of a registered peer based on the given unique identifier or RegisteredPeerRecord object.
*
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
* @return void This method does not return a value.
* @throws InvalidArgumentException If the peer is external and its phone number cannot be deleted.
* @throws DatabaseOperationException If there is an error during the database operation.
*/
public static function deletePhoneNumber(string|RegisteredPeerRecord $peer): void
{
if(is_string($peer))
{
$peer = self::getPeer($peer);
}
if($peer->isExternal())
{
throw new InvalidArgumentException('Cannot delete the phone number of an external peer');
}
Logger::getLogger()->verbose(sprintf("Deleting phone number of peer %s", $peer->getUuid()));
try
{
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET phone_number=NULL WHERE uuid=?');
$uuid = $peer->getUuid();
$statement->bindParam(1, $uuid);
$statement->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to delete the phone number of the peer in the database', $e);
} }
} }
} }

View file

@ -16,6 +16,9 @@
private string $server; private string $server;
private ?string $displayName; private ?string $displayName;
private ?string $displayPicture; private ?string $displayPicture;
private ?string $emailAddress;
private ?string $phoneNumber;
private ?DateTime $birthday;
/** /**
* @var PeerFlags[] * @var PeerFlags[]
*/ */
@ -27,7 +30,6 @@
* Constructor for initializing class properties from provided data. * Constructor for initializing class properties from provided data.
* *
* @param array $data Array containing initialization data. * @param array $data Array containing initialization data.
* @throws \DateMalformedStringException
*/ */
public function __construct(array $data) public function __construct(array $data)
{ {
@ -36,6 +38,25 @@
$this->server = $data['server']; $this->server = $data['server'];
$this->displayName = $data['display_name'] ?? null; $this->displayName = $data['display_name'] ?? null;
$this->displayPicture = $data['display_picture'] ?? null; $this->displayPicture = $data['display_picture'] ?? null;
$this->emailAddress = $data['email_address'] ?? null;
$this->phoneNumber = $data['phone_number'] ?? null;
if(is_int($data['birthday']))
{
$this->birthday = (new DateTime())->setTimestamp($data['birthday']);
}
elseif(is_string($data['birthday']))
{
$this->birthday = new DateTime($data['birthday']);
}
elseif($data['birthday'] instanceof DateTime)
{
$this->birthday = $data['birthday'];
}
else
{
$this->birthday = null;
}
if($data['flags']) if($data['flags'])
{ {
@ -48,13 +69,17 @@
$this->enabled = $data['enabled']; $this->enabled = $data['enabled'];
if (is_string($data['created'])) if(is_int($data['created']))
{
$this->created = (new DateTime())->setTimestamp($data['created']);
}
elseif(is_string($data['created']))
{ {
$this->created = new DateTime($data['created']); $this->created = new DateTime($data['created']);
} }
else else
{ {
$this->created = $data['created']; throw new \InvalidArgumentException("The created field must be a valid timestamp or date string.");
} }
} }
@ -118,6 +143,36 @@
return $this->displayPicture; return $this->displayPicture;
} }
/**
* Retrieves the email address.
*
* @return string|null The email address if set, or null otherwise.
*/
public function getEmailAddress(): ?string
{
return $this->emailAddress;
}
/**
* Retrieves the phone number.
*
* @return string|null The phone number if set, or null otherwise.
*/
public function getPhoneNumber(): ?string
{
return $this->phoneNumber;
}
/**
* Retrieves the birthday.
*
* @return DateTime|null The birthday if set, or null otherwise.
*/
public function getBirthday(): ?DateTime
{
return $this->birthday;
}
/** /**
* Retrieves the flags. * Retrieves the flags.
* *
@ -221,6 +276,9 @@
'server' => $this->server, 'server' => $this->server,
'display_name' => $this->displayName, 'display_name' => $this->displayName,
'display_picture' => $this->displayPicture, 'display_picture' => $this->displayPicture,
'email_address' => $this->emailAddress,
'phone_number' => $this->phoneNumber,
'birthday' => $this->birthday?->getTimestamp(),
'flags' => PeerFlags::toString($this->flags), 'flags' => PeerFlags::toString($this->flags),
'enabled' => $this->enabled, 'enabled' => $this->enabled,
'created' => $this->created 'created' => $this->created