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

Closed
netkas wants to merge 421 commits from master into dev
10 changed files with 1066 additions and 0 deletions
Showing only changes of commit 0e08bef3bc - Show all commits

3
.idea/sqldialects.xml generated
View file

@ -4,8 +4,10 @@
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/authentication_otp.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/authentication_passwords.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/captcha_images.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/channel_com.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/contact_known_keys.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/contacts.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/encrypted_channels.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/external_sessions.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/peer_information.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/peers.sql" dialect="MariaDB" />
@ -14,6 +16,7 @@
<file url="file://$PROJECT_DIR$/src/Socialbox/Classes/Resources/database/variables.sql" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/CaptchaManager.php" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/ContactManager.php" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/EncryptionChannelManager.php" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/ExternalSessionManager.php" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/OneTimePasswordManager.php" dialect="MariaDB" />
<file url="file://$PROJECT_DIR$/src/Socialbox/Managers/PasswordManager.php" dialect="MariaDB" />

View file

@ -0,0 +1,32 @@
create table channel_com
(
uuid varchar(36) default uuid() not null comment 'The UUID of the message',
channel_uuid varchar(36) not null comment 'The UUID of the encryption channel used',
recipient enum ('SENDER', 'RECEIVER') not null comment 'The recipient of the message',
message text not null comment 'The encrypted message content',
signature varchar(64) not null comment 'The signature of the decrypted message',
received tinyint(1) default 0 not null comment 'True if the message was received by the recipient',
timestamp timestamp default current_timestamp() not null comment 'The timestamp of the mssage being sent',
primary key (uuid, channel_uuid) comment 'The Unique Pair Index for the channel UUID and message UUID',
constraint channel_com_uuid_channel_uuid_uindex
unique (uuid, channel_uuid) comment 'The Unique Pair Index for the channel UUID and message UUID',
constraint channel_com_uuid_channel_uuid_uindex_2
unique (uuid, channel_uuid) comment 'The Unique Index Pair for the channel UUID and message UUID',
constraint channel_com_encryption_channels_uuid_fk
foreign key (channel_uuid) references encryption_channels (uuid)
on update cascade on delete cascade
)
comment 'Table for housing communication messages over encryption channels';
create index channel_com_received_index
on channel_com (received)
comment 'The index for the received column';
create index channel_com_recipient_index
on channel_com (recipient)
comment 'The index for the recipient column';
create index channel_com_timestamp_index
on channel_com (timestamp)
comment 'The index for the Timestamp column';

View file

@ -0,0 +1,36 @@
create table encryption_channels
(
uuid varchar(36) not null comment 'The Unique Universal Identifier for the encryption channel'
primary key comment 'The Unique Index of the encryption channel UUID',
calling_peer varchar(320) not null comment 'The address of the calling peer',
calling_signature_uuid varchar(64) not null comment 'The UUID of the signing key that the calling peer is going to use to sign their messages',
calling_signature_public_key varchar(32) not null,
calling_encryption_public_key varchar(32) not null comment 'The public encryption key of the caller',
receiving_peer varchar(320) not null comment 'The address of the receiving peer',
receiving_signature_uuid varchar(256) null comment 'The UUID of the signature that the receiver peer will use to sign messages with',
receiving_signature_public_key varchar(32) null comment 'The public key of the receiver''s signing key',
receiving_encryption_public_key varchar(32) null comment 'The encryption key of the receiver',
transport_encryption_algorithm enum ('xchacha20', 'chacha20', 'aes256gcm') default 'xchacha20' not null comment 'The transport encryption algorithm used as selected by the caller',
transport_encryption_key varchar(256) null comment 'The transport encryption key encrypted using the caller''s public encryption key',
state enum ('AWAITING_RECEIVER', 'ERROR', 'DECLINED', 'AWAITING_DHE', 'OPENED', 'CLOSED') default 'AWAITING_RECEIVER' not null comment 'The current state of the encryption channel',
created timestamp default current_timestamp() not null comment 'The Timestamp for when this record was created',
constraint encryption_channels_uuid_uindex
unique (uuid) comment 'The Unique Index of the encryption channel UUID'
);
create index encryption_channels_calling_peer_index
on encryption_channels (calling_peer)
comment 'The index of the calling peer address';
create index encryption_channels_created_index
on encryption_channels (created)
comment 'The Index for when the record was created';
create index encryption_channels_receiving_peer_index
on encryption_channels (receiving_peer)
comment 'The index of the receiving peer address';
create index encryption_channels_state_index
on encryption_channels (state)
comment 'The index for the state column';

View file

@ -18,6 +18,9 @@
case SIGNING_KEYS = 'signing_keys.sql';
case EXTERNAL_SESSIONS = 'external_sessions.sql';
case ENCRYPTED_CHANNELS = 'encrypted_channels.sql';
case CHANNEL_COM = 'channel_com.sql';
case CONTACT_KNOWN_KEYS = 'contact_known_keys.sql';
/**
@ -43,6 +46,8 @@
self::SIGNING_KEYS,
self::EXTERNAL_SESSIONS => 2,
self::ENCRYPTED_CHANNELS,
self::CHANNEL_COM,
self::CONTACT_KNOWN_KEYS => 3,
};
}

View file

@ -18,6 +18,7 @@
case CONFLICT = -107;
case EXPIRED = -108;
case CRYPTOGRAPHIC_ERROR = -109;
case UUID_CONFLICT = -110;
// RPC Errors
case RPC_METHOD_NOT_FOUND = -1000;

View file

@ -0,0 +1,12 @@
<?php
namespace Socialbox\Enums\Status;
enum EncryptionChannelState : string
{
case AWAITING_RECEIVER = 'AWAITING_RECEIVER';
case ERROR = 'ERROR';
case DECLINED = 'DECLINED';
case OPENED = 'OPENED';
case CLOSED = 'CLOSED';
}

View file

@ -0,0 +1,9 @@
<?php
namespace Socialbox\Enums\Types;
enum CommunicationRecipientType : string
{
case SENDER = 'SENDER';
case RECEIVER = 'RECEIVER';
}

View file

@ -0,0 +1,568 @@
<?php
namespace Socialbox\Managers;
use InvalidArgumentException;
use ncc\ThirdParty\Symfony\Uid\UuidV4;
use PDO;
use PDOException;
use Socialbox\Classes\Cryptography;
use Socialbox\Classes\Database;
use Socialbox\Enums\Status\EncryptionChannelState;
use Socialbox\Enums\Types\CommunicationRecipientType;
use Socialbox\Exceptions\DatabaseOperationException;
use Socialbox\Objects\Database\ChannelMessageRecord;
use Socialbox\Objects\Database\EncryptionChannelRecord;
use Socialbox\Objects\PeerAddress;
class EncryptionChannelManager
{
/**
* Creates a new encryption channel between two peers.
*
* @param PeerAddress|string $callingPeer The peer that is creating the channel.
* @param PeerAddress|string $receivingPeer The peer that is receiving the channel.
* @param string $signatureUuid The UUID of the signature used to create the channel.
* @param string $signingPublicKey The public key used for signing.
* @param string $encryptionPublicKey The public key used for encryption.
* @param string $transportEncryptionAlgorithm The algorithm used for transport encryption.
* @return string The UUID of the created channel.
* @throws DatabaseOperationException If an error occurs while creating the channel.
*/
public static function createChannel(PeerAddress|string $callingPeer, PeerAddress|string $receivingPeer,
string $signatureUuid, string $signingPublicKey, string $encryptionPublicKey, string $transportEncryptionAlgorithm,
?string $uuid=null
): string
{
if(is_string($callingPeer))
{
$callingPeer = PeerAddress::fromAddress($callingPeer);
}
if(is_string($receivingPeer))
{
$receivingPeer = PeerAddress::fromAddress($receivingPeer);
}
if(!Cryptography::validatePublicSigningKey($signingPublicKey))
{
throw new InvalidArgumentException('Invalid signing public key provided');
}
if(!Cryptography::validatePublicEncryptionKey($encryptionPublicKey))
{
throw new InvalidArgumentException('Invalid encryption public key provided');
}
$transportEncryptionAlgorithm = strtolower($transportEncryptionAlgorithm);
if(!Cryptography::isSupportedAlgorithm($transportEncryptionAlgorithm))
{
throw new InvalidArgumentException('Unsupported transport encryption algorithm');
}
if($uuid === null)
{
$uuid = UuidV4::v4()->toRfc4122();
}
try
{
$stmt = Database::getConnection()->prepare('INSERT INTO encryption_channels (uuid, calling_peer, calling_signature_uuid, calling_signature_public_key, calling_encryption_public_key, receiving_peer, transport_encryption_algorithm) VALUES (:uuid, :calling_peer, :calling_signature_uuid, :calling_signature_public_key, :calling_encryption_public_key, :receiving_peer, :transport_encryption_algorithm)');
$stmt->bindParam(':uuid', $uuid);
$callingPeerAddress = $callingPeer->getAddress();
$stmt->bindParam(':calling_peer', $callingPeerAddress);
$stmt->bindParam(':calling_signature_uuid', $signatureUuid);
$stmt->bindParam(':calling_signature_public_key', $signingPublicKey);
$stmt->bindParam(':calling_encryption_public_key', $encryptionPublicKey);
$receivingPeerAddress = $receivingPeer->getAddress();
$stmt->bindParam(':receiving_peer', $receivingPeerAddress);
$stmt->bindParam(':transport_encryption_algorithm', $transportEncryptionAlgorithm);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to create the encryption channel', $e);
}
return $uuid;
}
/**
* Retrieves the incoming encryption channels for the specified peer.
*
* @param string|PeerAddress $peerAddress The peer to retrieve the channels for.
* @param int $limit The maximum number of channels to retrieve.
* @param int $page The page of channels to retrieve.
* @return EncryptionChannelRecord[] The incoming channels for the peer.
* @throws DatabaseOperationException If an error occurs while retrieving the channels.
* @throws \DateMalformedStringException If the created date is not a valid date string.
*/
public static function getChannels(string|PeerAddress $peerAddress, int $limit=100, int $page=0): array
{
if($peerAddress instanceof PeerAddress)
{
$peerAddress = $peerAddress->getAddress();
}
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM encryption_channels WHERE calling_peer=:address OR receiving_peer=:address LIMIT :limit OFFSET :offset');
$stmt->bindParam(':address', $peerAddress);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$offset = $page * $limit;
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$results = $stmt->fetchAll();
$channels = [];
foreach($results as $result)
{
$channels[] = new EncryptionChannelRecord($result);
}
return $channels;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channels', $e);
}
}
/**
* Retrieves the incoming encryption channels for the specified peer.
*
* @param string|PeerAddress $peerAddress The peer to retrieve the channels for.
* @param int $limit The maximum number of channels to retrieve.
* @param int $page The page of channels to retrieve.
* @return EncryptionChannelRecord[] The incoming channels for the peer.
* @throws DatabaseOperationException If an error occurs while retrieving the channels.
* @throws \DateMalformedStringException If the created date is not a valid date string.
*/
public static function getRequests(string|PeerAddress $peerAddress, int $limit=100, int $page=0): array
{
if($peerAddress instanceof PeerAddress)
{
$peerAddress = $peerAddress->getAddress();
}
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM encryption_channels WHERE receiving_peer=:address AND state=:state LIMIT :limit OFFSET :offset');
$stmt->bindParam(':address', $peerAddress);
$state = EncryptionChannelState::AWAITING_RECEIVER->value;
$stmt->bindParam(':state', $state);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$offset = $page * $limit;
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$results = $stmt->fetchAll();
$channels = [];
foreach($results as $result)
{
$channels[] = new EncryptionChannelRecord($result);
}
return $channels;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channels', $e);
}
}
/**
* Retrieves the incoming encryption channels for the specified peer.
*
* @param string|PeerAddress $peerAddress The peer to retrieve the channels for.
* @param int $limit The maximum number of channels to retrieve.
* @param int $page The page of channels to retrieve.
* @return EncryptionChannelRecord[] The incoming channels for the peer.
* @throws DatabaseOperationException If an error occurs while retrieving the channels.
* @throws \DateMalformedStringException If the created date is not a valid date string.
*/
public static function getIncomingChannels(string|PeerAddress $peerAddress, int $limit=100, int $page=0): array
{
if($peerAddress instanceof PeerAddress)
{
$peerUuid = $peerAddress->getAddress();
}
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM encryption_channels WHERE receiving_peer=:address LIMIT :limit OFFSET :offset');
$stmt->bindParam(':address', $peerUuid);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$offset = $page * $limit;
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$results = $stmt->fetchAll();
$channels = [];
foreach($results as $result)
{
$channels[] = new EncryptionChannelRecord($result);
}
return $channels;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channels', $e);
}
}
/**
* Retrieves the outgoing channels for the specified peer.
*
* @param string|PeerAddress $peerAddress The peer to retrieve the channels for.
* @param int $limit The maximum number of channels to retrieve.
* @param int $page The page of channels to retrieve.
* @return EncryptionChannelRecord[] The outgoing channels for the specified peer.
* @throws DatabaseOperationException If an error occurs while retrieving the channels.
* @throws \DateMalformedStringException If the created date is not a valid date string.
*/
public static function getOutgoingChannels(string|PeerAddress $peerAddress, int $limit=100, int $page=0): array
{
if($peerAddress instanceof PeerAddress)
{
$peerAddress = $peerAddress->getAddress();
}
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM encryption_channels WHERE calling_peer=:address LIMIT :limit OFFSET :offset');
$stmt->bindParam(':address', $peerAddress);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$offset = $page * $limit;
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$results = $stmt->fetchAll();
$channels = [];
foreach($results as $result)
{
$channels[] = new EncryptionChannelRecord($result);
}
return $channels;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channels', $e);
}
}
/**
* Declines the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to decline.
* @throws DatabaseOperationException If an error occurs while declining the channel.
*/
public static function declineChannel(string $channelUuid): void
{
try
{
$stmt = Database::getConnection()->prepare('UPDATE encryption_channels SET state=:state WHERE uuid=:uuid');
$state = EncryptionChannelState::DECLINED->value;
$stmt->bindParam(':state', $state);
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to decline the encryption channel', $e);
}
}
/**
* Accepts the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to accept.
* @param string $signatureUuid The UUID of the signature used to create the channel.
* @param string $signaturePublicKey The public key used for signing.
* @param string $encryptionPublicKey The public key used for encryption.
* @param string $transportEncryptionAlgorithm The algorithm used for transport encryption.
* @param string $encryptedTransportEncryptionKey The encrypted transport encryption key.
* @throws DatabaseOperationException If an error occurs while accepting the channel.
*/
public static function acceptChannel(string $channelUuid, string $signatureUuid, string $signaturePublicKey, string $encryptionPublicKey, string $transportEncryptionAlgorithm, string $encryptedTransportEncryptionKey): void
{
try
{
$stmt = Database::getConnection()->prepare('UPDATE encryption_channels SET state=:state, receiving_signature_uuid=:receiving_signature_uuid, receiving_signature_public_key=:receiving_signature_public_key, receiving_encryption_public_key=:receiving_encryption_public_key, transport_encryption_algorithm=:transport_encryption_algorithm, transport_encryption_key=:transport_encryption_key WHERE uuid=:uuid');
$state = EncryptionChannelState::OPENED->value;
$stmt->bindParam(':state', $state);
$stmt->bindParam(':receiving_signature_uuid', $signatureUuid);
$stmt->bindParam(':receiving_signature_public_key', $signaturePublicKey);
$stmt->bindParam(':receiving_encryption_public_key', $encryptionPublicKey);
$stmt->bindParam(':transport_encryption_algorithm', $transportEncryptionAlgorithm);
$stmt->bindParam(':transport_encryption_key', $encryptedTransportEncryptionKey);
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to accept the encryption channel', $e);
}
}
/**
* Retrieves the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to retrieve.
* @return EncryptionChannelRecord|null The record of the encryption channel. Null if the channel does not exist.
* @throws DatabaseOperationException If an error occurs while retrieving the channel.
* @throws \DateMalformedStringException If the created date is not a valid date string.
*/
public static function getChannel(string $channelUuid): ?EncryptionChannelRecord
{
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM encryption_channels WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
$result = $stmt->fetch();
if($result === false)
{
return null;
}
return new EncryptionChannelRecord($result);
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channel', $e);
}
}
/**
* Deletes the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to delete.
* @return void
*@throws DatabaseOperationException If an error occurs while deleting the channel.
*/
public static function deleteChannel(string $channelUuid): void
{
try
{
$stmt = Database::getConnection()->prepare('DELETE FROM encryption_channels WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to delete the encryption channel', $e);
}
}
/**
* Updates the state of the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to update.
* @return EncryptionChannelState The current state of the channel.
* @throws DatabaseOperationException If an error occurs while updating the channel state.
*/
public static function getChannelState(string $channelUuid): EncryptionChannelState
{
try
{
$stmt = Database::getConnection()->prepare('SELECT state FROM encryption_channels WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
return EncryptionChannelState::from($stmt->fetchColumn());
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the encryption channel state', $e);
}
}
/**
* Updates the state of the encryption channel with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to update.
* @param EncryptionChannelState $state The new state of the channel.
* @return void The current state of the channel.
* @throws DatabaseOperationException If an error occurs while updating the channel state.
*/
public static function updateChannelState(string $channelUuid, EncryptionChannelState $state): void
{
try
{
$stmt = Database::getConnection()->prepare('UPDATE encryption_channels SET state=:state WHERE uuid=:uuid');
$state = $state->value;
$stmt->bindParam(':state', $state);
$stmt->bindParam(':uuid', $channelUuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to update the encryption channel state', $e);
}
}
/**
* Checks if a channel with the provided UUID exists.
*
* @param string $uuid The UUID of the channel to check.
* @return bool True if the channel exists, False otherwise.
* @throws DatabaseOperationException If an error occurs while checking the channel.
*/
public static function channelExists(string $uuid): bool
{
try
{
$stmt = Database::getConnection()->prepare('SELECT COUNT(*) FROM encryption_channels WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $uuid);
$stmt->execute();
return $stmt->fetchColumn() > 0;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('There was an error while trying to check if the channel UUID exists', $e);
}
}
/**
* Sends data to the specified channel.
*
* @param string $channelUuid The UUID of the channel to send the data to.
* @param string $message The message to send.
* @param string $signature The signature of the message.
* @param CommunicationRecipientType $recipient The recipient type.
* @return string The UUID of the sent message.
* @throws DatabaseOperationException If an error occurs while sending the message.
*/
public static function sendData(string $channelUuid, string $message, string $signature, CommunicationRecipientType $recipient): string
{
$uuid = UuidV4::v4()->toRfc4122();
try
{
$stmt = Database::getConnection()->prepare('INSERT INTO channel_com (uuid, channel_uuid, recipient, message, signature) VALUES (:uuid, :channel_uuid, :recipient, :message, :signature)');
$stmt->bindParam(':uuid', $uuid);
$stmt->bindParam(':channel_uuid', $channelUuid);
$recipient = $recipient->value;
$stmt->bindParam(':recipient', $recipient);
$stmt->bindParam(':message', $message);
$stmt->bindParam(':signature', $signature);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to send the message', $e);
}
return $uuid;
}
/**
* Retrieves the messages for the specified channel and recipient.
*
* @param string $channelUuid The UUID of the channel to retrieve the messages for.
* @param CommunicationRecipientType $recipient The recipient type to retrieve the messages for.
* @return ChannelMessageRecord[] The messages for the specified channel and recipient.
* @throws DatabaseOperationException If an error occurs while retrieving the messages.
*/
public static function receiveData(string $channelUuid, CommunicationRecipientType $recipient): array
{
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM channel_com WHERE channel_uuid=:channel_uuid AND recipient=:recipient AND received=0 ORDER BY timestamp');
$stmt->bindParam(':channel_uuid', $channelUuid);
$recipient = $recipient->value;
$stmt->bindParam(':recipient', $recipient);
$stmt->execute();
$results = $stmt->fetchAll();
$messages = [];
foreach($results as $result)
{
$messages[] = new ChannelMessageRecord($result);
}
return $messages;
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the messages', $e);
}
}
/**
* Retrieves the message with the specified UUID.
*
* @param string $channelUuid The UUID of the channel to retrieve the message for.
* @param string $messageUuid The UUID of the message to retrieve.
* @return ChannelMessageRecord|null The message with the specified UUID. Null if the message does not exist.
* @throws DatabaseOperationException If an error occurs while retrieving the message.
*/
public static function getData(string $channelUuid, string $messageUuid): ?ChannelMessageRecord
{
try
{
$stmt = Database::getConnection()->prepare('SELECT * FROM channel_com WHERE channel_uuid=:channel_uuid AND uuid=:uuid');
$stmt->bindParam(':channel_uuid', $channelUuid);
$stmt->bindParam(':uuid', $messageUuid);
$stmt->execute();
$result = $stmt->fetch();
if($result === false)
{
return null;
}
return new ChannelMessageRecord($result);
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to retrieve the message', $e);
}
}
/**
* Marks the message with the specified UUID as received.
*
* @param string $uuid The UUID of the message to mark as received.
* @throws DatabaseOperationException If an error occurs while marking the message as received.
*/
public static function markDataAsReceived(string $uuid): void
{
try
{
$stmt = Database::getConnection()->prepare('UPDATE channel_com SET received=1 WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $uuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to mark the message as received', $e);
}
}
/**
* Deletes the message with the specified UUID.
*
* @param string $uuid The UUID of the message to delete.
* @throws DatabaseOperationException If an error occurs while deleting the message.
*/
public static function deleteData(string $uuid): void
{
try
{
$stmt = Database::getConnection()->prepare('DELETE FROM channel_com WHERE uuid=:uuid');
$stmt->bindParam(':uuid', $uuid);
$stmt->execute();
}
catch(PDOException $e)
{
throw new DatabaseOperationException('Failed to delete the message', $e);
}
}
}

View file

@ -0,0 +1,141 @@
<?php
namespace Socialbox\Objects\Database;
use Socialbox\Enums\Types\CommunicationRecipientType;
use Socialbox\Interfaces\SerializableInterface;
class ChannelMessageRecord implements SerializableInterface
{
private string $uuid;
private string $channelUuid;
private CommunicationRecipientType $recipient;
private string $message;
private string $signature;
private bool $received;
private \DateTime $timestamp;
/**
* Constructs a new instance of this class and initializes its properties with the provided data.
*
* @param array $data An associative array containing initialization data. Expected keys:
* - 'uuid' (string): The unique identifier.
* - 'channel_uuid' (string): The channel UUID.
* - 'recipient' (string): The recipient type, which will be cast to a CommunicationRecipientType instance.
* - 'message' (string): The message.
* - 'signature' (string): The signature.
* - 'received' (bool): Whether the message has been received.
* - 'timestamp' (int|string|\DateTime): The timestamp of the message.
* @return void
*/
public function __construct(array $data)
{
$this->uuid = $data['uuid'];
$this->channelUuid = $data['channel_uuid'];
$this->recipient = CommunicationRecipientType::from($data['recipient']);
$this->message = $data['message'];
$this->signature = $data['signature'];
$this->received = (bool)$data['received'];
if($data['timestamp'] instanceof \DateTime)
{
$this->timestamp = $data['timestamp'];
}
elseif(is_int($data['timestamp']))
{
$this->timestamp = (new \DateTime())->setTimestamp($data['timestamp']);
}
elseif(is_string($data['timestamp']))
{
$this->timestamp = new \DateTime($data['timestamp']);
}
else
{
throw new \InvalidArgumentException('Invalid timestamp type, got ' . gettype($data['timestamp']));
}
}
/**
* Returns the unique identifier for the message.
*
* @return string
*/
public function getUuid(): string
{
return $this->uuid;
}
/**
* Returns the UUID of the channel that the message belongs to.
*
* @return string
*/
public function getChannelUuid(): string
{
return $this->channelUuid;
}
/**
* Returns the recipient type of the message.
*
* @return CommunicationRecipientType
*/
public function getRecipient(): CommunicationRecipientType
{
return $this->recipient;
}
/**
* Returns the message content.
*
* @return string
*/
public function getMessage(): string
{
return $this->message;
}
/**
* Returns the signature of the message.
*
* @return string
*/
public function getSignature(): string
{
return $this->signature;
}
public function isReceived(): bool
{
return $this->received;
}
public function getTimestamp(): \DateTime
{
return $this->timestamp;
}
/**
* @inheritDoc
*/
public static function fromArray(array $data): ChannelMessageRecord
{
return new self($data);
}
/**
* @inheritDoc
*/
public function toArray(): array
{
return [
'uuid' => $this->uuid,
'channel_uuid' => $this->channelUuid,
'recipient' => $this->recipient->value,
'message' => $this->message,
'signature' => $this->signature,
'received' => $this->received,
'timestamp' => $this->timestamp->format('Y-m-d H:i:s')
];
}
}

View file

@ -0,0 +1,259 @@
<?php
namespace Socialbox\Objects\Database;
use DateTime;
use InvalidArgumentException;
use Socialbox\Enums\Status\EncryptionChannelState;
use Socialbox\Interfaces\SerializableInterface;
use Socialbox\Objects\PeerAddress;
class EncryptionChannelRecord implements SerializableInterface
{
private string $uuid;
private PeerAddress $callingPeer;
private string $callingSignatureUuid;
private string $callingEncryptionPublicKey;
private PeerAddress $receivingPeer;
private ?string $receivingSignatureUuid;
private ?string $receivingSignaturePublicKey;
private ?string $receivingEncryptionPublicKey;
private string $transportEncryptionAlgorithm;
private ?string $transportEncryptionKey;
private EncryptionChannelState $state;
private DateTime $created;
/**
* Public Constructor for the encryption channel record
*
* @param array $data
* @throws \DateMalformedStringException
*/
public function __construct(array $data)
{
$this->uuid = $data['uuid'];
if(!isset($data['calling_peer']))
{
throw new InvalidArgumentException('Missing property calling_peer');
}
else
{
if(is_string($data['calling_peer']))
{
$this->callingPeer = PeerAddress::fromAddress($data['calling_peer']);
}
elseif($data['calling_peer'] instanceof PeerAddress)
{
$this->callingPeer = $data['calling_peer'];
}
else
{
throw new InvalidArgumentException('Unexpected calling_peer type, got ' . gettype($data['calling_peer']));
}
}
$this->callingSignatureUuid = $data['calling_signature_uuid'];
$this->callingEncryptionPublicKey = $data['calling_encryption_public_key'];
if(!isset($data['receiving_peer']))
{
throw new InvalidArgumentException('Missing property receiving_peer');
}
else
{
if(is_string($data['receiving_peer']))
{
$this->receivingPeer = PeerAddress::fromAddress($data['receiving_peer']);
}
elseif($data['receiving_peer'] instanceof PeerAddress)
{
$this->receivingPeer = $data['receiving_peer'];
}
else
{
throw new InvalidArgumentException('Unexpected receiving_peer type, got ' . gettype($data['receiving_peer']));
}
}
$this->receivingSignatureUuid = $data['receiving_signature_uuid'] ?? null;
$this->receivingSignaturePublicKey = $data['receiving_signature_public_key'] ?? null;
$this->receivingEncryptionPublicKey = $data['receiving_encryption_public_key'] ?? null;
$this->transportEncryptionAlgorithm = $data['transport_encryption_algorithm'];
$this->transportEncryptionKey = $data['transport_encryption_key'] ?? null;
$this->state = EncryptionChannelState::tryFrom($data['state']) ?? EncryptionChannelState::ERROR;
if(!isset($data['created']))
{
throw new InvalidArgumentException('Missing property created');
}
else
{
if(is_string($data['created']))
{
$this->created = new DateTime($data['created']);
}
elseif(is_int($data['created']))
{
$this->created = (new DateTime())->setTimestamp($data['created']);
}
elseif($data['created'] instanceof DateTime)
{
$this->created = $data['created'];
}
else
{
throw new InvalidArgumentException('Unexpected created type, got ' . gettype($data['created']));
}
}
}
/**
* Returns the Unique Universal Identifier for the encryption record
*
* @return string
*/
public function getUuid(): string
{
return $this->uuid;
}
/**
* Returns the address of the calling peer
*
* @return PeerAddress
*/
public function getCallingPeer(): PeerAddress
{
return $this->callingPeer;
}
/**
* Returns the UUID of the signing keypair that the caller is using
*
* @return string
*/
public function getCallingSignatureUuid(): string
{
return $this->callingSignatureUuid;
}
/**
* Returns the public key of the encryption keypair that the caller is using
*
* @return string
*/
public function getCallingEncryptionPublicKey(): string
{
return $this->callingEncryptionPublicKey;
}
/**
* Returns the address of the receiving peer
*
* @return PeerAddress
*/
public function getReceivingPeer(): PeerAddress
{
return $this->receivingPeer;
}
/**
* Returns the UUID of the signing keypair that the receiver is using
*
* @return string|null
*/
public function getReceivingSignatureUuid(): ?string
{
return $this->receivingSignatureUuid;
}
/**
* Returns the public key of the signing keypair that the receiver is using
*
* @return string|null
*/
public function getReceivingSignaturePublicKey(): ?string
{
return $this->receivingSignaturePublicKey;
}
/**
* Returns the public key of the encryption keypair that the receiver is using
*
* @return string|null
*/
public function getReceivingEncryptionPublicKey(): ?string
{
return $this->receivingEncryptionPublicKey;
}
/**
* Returns the algorithm used for transport encryption
*
* @return string
*/
public function getTransportEncryptionAlgorithm(): string
{
return $this->transportEncryptionAlgorithm;
}
/**
* Returns the key used for transport encryption
*
* @return string|null
*/
public function getTransportEncryptionKey(): ?string
{
return $this->transportEncryptionKey;
}
/**
* Returns the current state of the encryption channel
*
* @return EncryptionChannelState
*/
public function getState(): EncryptionChannelState
{
return $this->state;
}
/**
* Returns the creation date of the encryption channel
*
* @return DateTime
*/
public function getCreated(): DateTime
{
return $this->created;
}
/**
* @inheritDoc
*/
public static function fromArray(array $data): EncryptionChannelRecord
{
return new self($data);
}
/**
* @inheritDoc
*/
public function toArray(): array
{
return [
'uuid' => $this->uuid,
'calling_peer' => $this->callingPeer->getAddress(),
'calling_signature_uuid' => $this->callingSignatureUuid,
'calling_encryption_public_key' => $this->callingEncryptionPublicKey,
'receiving_peer' => $this->receivingPeer->getAddress(),
'receiving_signature_uuid' => $this->receivingSignatureUuid,
'receiving_signature_public_key' => $this->receivingSignaturePublicKey,
'receiving_encryption_public_key' => $this->receivingEncryptionPublicKey,
'transport_encryption_algorithm' => $this->transportEncryptionAlgorithm,
'transport_encryption_key' => $this->transportEncryptionKey,
'state' => $this->state->value,
'created' => $this->created->format('Y-m-d H:i:s')
];
}
}