Add client metadata to session creation and enforce TOS/PP

This commit is contained in:
netkas 2024-12-12 14:55:44 -05:00
parent d2119df824
commit 756297671f
10 changed files with 414 additions and 206 deletions

View file

@ -72,6 +72,10 @@ class Configuration
// Registration configuration
$config->setDefault('registration.enabled', true);
$config->setDefault('registration.privacy_policy_document', null);
$config->setDefault('registration.accept_privacy_policy', true);
$config->setDefault('registration.terms_of_service_document', null);
$config->setDefault('registration.accept_terms_of_service', null);
$config->setDefault('registration.password_required', true);
$config->setDefault('registration.otp_required', false);
$config->setDefault('registration.display_name_required', false);

View file

@ -9,6 +9,10 @@ namespace Socialbox\Classes\Configuration;
class RegistrationConfiguration
{
private bool $registrationEnabled;
private ?string $privacyPolicyDocument;
private bool $acceptPrivacyPolicy;
private ?string $termsOfServiceDocument;
private bool $acceptTermsOfService;
private bool $passwordRequired;
private bool $otpRequired;
private bool $displayNameRequired;
@ -31,6 +35,10 @@ class RegistrationConfiguration
public function __construct(array $data)
{
$this->registrationEnabled = (bool)$data['enabled'];
$this->privacyPolicyDocument = $data['privacy_policy_document'] ?? null;
$this->acceptPrivacyPolicy = $data['accept_privacy_policy'] ?? true;
$this->termsOfServiceDocument = $data['terms_of_service_document'] ?? null;
$this->acceptTermsOfService = $data['accept_terms_of_service'] ?? true;
$this->passwordRequired = (bool)$data['password_required'];
$this->otpRequired = (bool)$data['otp_required'];
$this->displayNameRequired = (bool)$data['display_name_required'];
@ -50,6 +58,47 @@ class RegistrationConfiguration
return $this->registrationEnabled;
}
/**
* Retrieves the privacy policy document.
*
* @return ?string Returns the privacy policy document or null if not set.
*/
public function getPrivacyPolicyDocument(): ?string
{
return $this->privacyPolicyDocument;
}
/**
* Checks if accepting the privacy policy is required.
*
* @return bool Returns true if the privacy policy must be accepted, false otherwise.
*/
public function isAcceptPrivacyPolicyRequired(): bool
{
return $this->acceptPrivacyPolicy;
}
/**
* Retrieves the terms of service document.
*
* @return ?string Returns the terms of service document or null if not set.
*/
public function getTermsOfServiceDocument(): ?string
{
return $this->termsOfServiceDocument;
}
/**
* Checks if accepting the terms of service is required.
*
* @return bool Returns true if the terms of service must be accepted, false otherwise.
*/
public function isAcceptTermsOfServiceRequired(): bool
{
return $this->acceptTermsOfService;
}
/**
* Determines if a password is required.
*

View file

@ -3,6 +3,7 @@
namespace Socialbox\Classes\StandardMethods;
use Socialbox\Abstracts\Method;
use Socialbox\Enums\StandardError;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\RpcRequest;
@ -15,6 +16,11 @@
*/
public static function execute(ClientRequest $request, RpcRequest $rpcRequest): ?SerializableInterface
{
// TODO: Implement execute() method.
if($request->getSessionUuid() === null)
{
return $rpcRequest->produceError(StandardError::SESSION_REQUIRED);
}
return $rpcRequest->produceResponse($request->getSession()->toStandardSessionState());
}
}

View file

@ -4,12 +4,18 @@
enum SessionFlags : string
{
// Session states
case REGISTRATION_REQUIRED = 'REGISTRATION_REQUIRED'; // Peer has to register
case AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED'; // Peer has to authenticate
// Verification, require fields
case SET_PASSWORD = 'SET_PASSWORD'; // Peer has to set a password
case SET_OTP = 'SET_OTP'; // Peer has to set an OTP
case SET_DISPLAY_NAME = 'SET_DISPLAY_NAME'; // Peer has to set a display name
// Verification, verification requirements
case VER_PRIVACY_POLICY = 'VER_PRIVACY_POLICY'; // Peer has to accept the privacy policy
case VER_TERMS_OF_SERVICE = 'VER_TERMS_OF_SERVICE'; // Peer has to accept the terms of service
case VER_EMAIL = 'VER_EMAIL'; // Peer has to verify their email
case VER_SMS = 'VER_SMS'; // Peer has to verify their phone number
case VER_PHONE_CALL = 'VER_PHONE_CALL'; // Peer has to verify their phone number via a phone call

View file

@ -1,23 +1,18 @@
<?php
namespace Socialbox\Enums;
namespace Socialbox\Enums;
use Socialbox\Classes\StandardMethods\CreateSession;
use Socialbox\Classes\StandardMethods\Identify;
use Socialbox\Classes\StandardMethods\VerificationAnswerImageCaptcha;
use Socialbox\Classes\StandardMethods\VerificationGetImageCaptcha;
use Socialbox\Classes\StandardMethods\GetMe;
use Socialbox\Classes\StandardMethods\Ping;
use Socialbox\Classes\StandardMethods\Register;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\ClientRequestOld;
use Socialbox\Objects\RpcRequest;
use Socialbox\Classes\StandardMethods\GetSessionState;
use Socialbox\Classes\StandardMethods\Ping;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Objects\ClientRequest;
use Socialbox\Objects\RpcRequest;
enum StandardMethods : string
{
enum StandardMethods : string
{
case PING = 'ping';
case GET_SESSION_STATE = 'getSessionState';
/**
* @param ClientRequest $request
@ -30,6 +25,7 @@ enum StandardMethods : string
return match ($this)
{
self::PING => Ping::execute($request, $rpcRequest),
self::GET_SESSION_STATE => GetSessionState::execute($request, $rpcRequest),
};
}
}
}

View file

@ -27,13 +27,12 @@
* Creates a new session with the given public key.
*
* @param string $publicKey The public key to associate with the new session.
*
* @return string The UUID of the newly created session.
* @param RegisteredPeerRecord $peer
*
* @throws InvalidArgumentException If the public key is empty or invalid.
* @throws DatabaseOperationException If there is an error while creating the session in the database.
*/
public static function createSession(string $publicKey, RegisteredPeerRecord $peer): string
public static function createSession(string $publicKey, RegisteredPeerRecord $peer, string $clientName, string $clientVersion): string
{
if($publicKey === '')
{
@ -50,6 +49,8 @@
if($peer->isEnabled())
{
$flags[] = SessionFlags::AUTHENTICATION_REQUIRED;
if(RegisteredPeerManager::getPasswordAuthentication($peer))
{
$flags[] = SessionFlags::VER_PASSWORD;
@ -62,6 +63,8 @@
}
else
{
$flags[] = SessionFlags::REGISTRATION_REQUIRED;
if(Configuration::getRegistrationConfiguration()->isDisplayNameRequired())
{
$flags[] = SessionFlags::SET_DISPLAY_NAME;
@ -96,6 +99,16 @@
{
$flags[] = SessionFlags::SET_OTP;
}
if(Configuration::getRegistrationConfiguration()->isAcceptPrivacyPolicyRequired())
{
$flags[] = SessionFlags::VER_PRIVACY_POLICY;
}
if(Configuration::getRegistrationConfiguration()->isAcceptTermsOfServiceRequired())
{
$flags[] = SessionFlags::VER_TERMS_OF_SERVICE;
}
}
if(count($flags) > 0)
@ -111,11 +124,13 @@
try
{
$statement = Database::getConnection()->prepare("INSERT INTO sessions (uuid, peer_uuid, public_key, flags) VALUES (?, ?, ?, ?)");
$statement = Database::getConnection()->prepare("INSERT INTO sessions (uuid, peer_uuid, client_name, client_version, public_key, flags) VALUES (?, ?, ?, ?, ?, ?)");
$statement->bindParam(1, $uuid);
$statement->bindParam(2, $peerUuid);
$statement->bindParam(3, $publicKey);
$statement->bindParam(4, $implodedFlags);
$statement->bindParam(3, $clientName);
$statement->bindParam(4, $clientVersion);
$statement->bindParam(5, $publicKey);
$statement->bindParam(6, $implodedFlags);
$statement->execute();
}
catch(PDOException $e)

View file

@ -6,11 +6,14 @@
use Socialbox\Enums\Flags\SessionFlags;
use Socialbox\Enums\SessionState;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Managers\RegisteredPeerManager;
class SessionRecord implements SerializableInterface
{
private string $uuid;
private ?string $peerUuid;
private string $clientName;
private string $clientVersion;
private bool $authenticated;
private string $publicKey;
private SessionState $state;
@ -36,6 +39,8 @@
{
$this->uuid = $data['uuid'];
$this->peerUuid = $data['peer_uuid'] ?? null;
$this->clientName = $data['client_name'];
$this->clientVersion = $data['client_version'];
$this->authenticated = $data['authenticated'] ?? false;
$this->publicKey = $data['public_key'];
$this->created = $data['created'];
@ -149,6 +154,38 @@
return $this->lastRequest;
}
/**
* Retrieves the client name.
*
* @return string Returns the client name.
*/
public function getClientName(): string
{
return $this->clientName;
}
/**
* Retrieves the client version.
*
* @return string Returns the client version.
*/
public function getClientVersion(): string
{
return $this->clientVersion;
}
public function toStandardSessionState(): \Socialbox\Objects\Standard\SessionState
{
return new \Socialbox\Objects\Standard\SessionState([
'uuid' => $this->uuid,
'identified_as' => RegisteredPeerManager::getPeer($this->peerUuid)->getAddress(),
'authenticated' => $this->authenticated,
'flags' => $this->flags,
'created' => $this->created
]);
}
/**
* Creates a new instance of the class using the provided array data.
*

View file

@ -1,17 +1,17 @@
<?php
namespace Socialbox\Objects;
namespace Socialbox\Objects;
use InvalidArgumentException;
use ncc\ThirdParty\nikic\PhpParser\Node\Expr\BinaryOp\BooleanOr;
use Socialbox\Classes\Logger;
use Socialbox\Enums\StandardError;
use Socialbox\Exceptions\RpcException;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
use InvalidArgumentException;
use ncc\ThirdParty\nikic\PhpParser\Node\Expr\BinaryOp\BooleanOr;
use Socialbox\Classes\Logger;
use Socialbox\Enums\StandardError;
use Socialbox\Exceptions\RpcException;
use Socialbox\Exceptions\StandardException;
use Socialbox\Interfaces\SerializableInterface;
class RpcRequest implements SerializableInterface
{
class RpcRequest implements SerializableInterface
{
private ?string $id;
private string $method;
private ?array $parameters;
@ -190,4 +190,4 @@ class RpcRequest implements SerializableInterface
{
return new RpcRequest($data['method'], $data['id'] ?? null, $data['parameters'] ?? null);
}
}
}

View file

@ -2,7 +2,103 @@
namespace Socialbox\Objects\Standard;
class SessionState
{
use DateTime;
use Socialbox\Enums\Flags\SessionFlags;
use Socialbox\Interfaces\SerializableInterface;
class SessionState implements SerializableInterface
{
private string $uuid;
private string $identifiedAs;
private bool $authenticated;
/**
* @var SessionFlags[]|null
*/
private ?array $flags;
private DateTime $created;
/**
* Constructor for initializing the object with the provided data.
*
* @param array $data An associative array containing the values for initializing the object.
* - 'uuid': string, Unique identifier.
* - 'identified_as': mixed, The identity information.
* - 'authenticated': bool, Whether the object is authenticated.
* - 'flags': string|null, Optional flags in
* @throws \DateMalformedStringException
*/
public function __construct(array $data)
{
$this->uuid = $data['uuid'];
$this->identifiedAs = $data['identified_as'];
$this->authenticated = $data['authenticated'];
if(is_string($data['flags']))
{
$this->flags = SessionFlags::fromString($data['flags']);
}
elseif(is_array($data['flags']))
{
$this->flags = $data['flags'];
}
else
{
$this->flags = null;
}
if(is_int($data['created']))
{
$this->created = new DateTime();
$this->created->setTimestamp($data['created']);
}
elseif($data['created'] instanceof DateTime)
{
$this->created = $data['created'];
}
else
{
$this->created = new DateTime($data['created']);
}
}
public function getUuid(): string
{
return $this->uuid;
}
public function getIdentifiedAs(): string
{
return $this->identifiedAs;
}
public function isAuthenticated(): bool
{
return $this->authenticated;
}
public function getFlags(): ?array
{
return $this->flags;
}
public function getCreated(): DateTime
{
return $this->created;
}
public static function fromArray(array $data): SessionState
{
return new self($data);
}
public function toArray(): array
{
return [
'uuid' => $this->uuid,
'identified_as' => $this->identifiedAs,
'authenticated' => $this->authenticated,
'flags' => $this->flags,
'created' => $this->created->getTimestamp()
];
}
}

View file

@ -149,8 +149,7 @@
}
// Create the session UUID
// TODO: Save client name and version to the database
$sessionUuid = SessionManager::createSession($clientRequest->getHeader(StandardHeaders::PUBLIC_KEY), $registeredPeer);
$sessionUuid = SessionManager::createSession($clientRequest->getHeader(StandardHeaders::PUBLIC_KEY), $registeredPeer, $clientRequest->getClientName(), $clientRequest->getClientVersion());
http_response_code(201); // Created
print($sessionUuid); // Return the session UUID
}