Compare commits

...

6 commits

Author SHA1 Message Date
f36a7f8563
Increase UDP buffer size and adjust recvfrom limit in UDP server
Some checks are pending
CI / release (push) Waiting to run
CI / debug (push) Waiting to run
CI / release_executable (push) Waiting to run
CI / debug_executable (push) Waiting to run
CI / check-phpunit (push) Waiting to run
CI / check-phpdoc (push) Waiting to run
CI / generate-phpdoc (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / release-documentation (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
2025-03-27 13:12:58 -04:00
bb8698bff9
Syntax correction (oops) 2025-03-27 12:54:17 -04:00
eaccaacf96
Normalize domain input to lowercase in getExternalSession method and add authentication check 2025-03-27 12:52:46 -04:00
fb31c3cc6a
Normalize server input to lowercase in RpcClient constructor 2025-03-27 12:52:39 -04:00
dff25f31ba
Normalize domain input to lowercase in session management methods 2025-03-27 12:52:31 -04:00
df519ad89b
Added tests for password deletion and OTP settings in AddressBookTest and SettingsTest 2025-03-27 12:52:16 -04:00
6 changed files with 68 additions and 6 deletions

View file

@ -303,12 +303,13 @@ class MultiProtocolServer:
def _start_udp_server(self): def _start_udp_server(self):
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_socket: with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_socket:
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1024 * 1024)
udp_socket.bind((self.host, self.port)) udp_socket.bind((self.host, self.port))
self.logger.debug(f"UDP server running on {self.host}:{self.port}") self.logger.debug(f"UDP server running on {self.host}:{self.port}")
while not self.stop_event.is_set(): while not self.stop_event.is_set():
try: try:
data, address = udp_socket.recvfrom(4096) data, address = udp_socket.recvfrom(65535)
self._handle_udp_client(data, address) self._handle_udp_client(data, address)
except Exception as e: except Exception as e:
self.logger.error(f"UDP server error: {e}") self.logger.error(f"UDP server error: {e}")

View file

@ -59,6 +59,10 @@
public function __construct(string|PeerAddress $identifiedAs, ?string $server=null, ?ExportedSession $exportedSession=null) public function __construct(string|PeerAddress $identifiedAs, ?string $server=null, ?ExportedSession $exportedSession=null)
{ {
$this->logger = new \LogLib2\Logger('net.nosial.socialbox'); $this->logger = new \LogLib2\Logger('net.nosial.socialbox');
if($server !== null)
{
$server = strtolower($server);
}
// If an exported session is provided, no need to re-connect. // If an exported session is provided, no need to re-connect.
// Just use the session details provided. // Just use the session details provided.

View file

@ -20,6 +20,8 @@
*/ */
public static function sessionExists(string $domain): bool public static function sessionExists(string $domain): bool
{ {
$domain = strtolower($domain);
try try
{ {
$stmt = Database::getConnection()->prepare("SELECT COUNT(*) FROM external_sessions WHERE domain=:domain LIMIT 1"); $stmt = Database::getConnection()->prepare("SELECT COUNT(*) FROM external_sessions WHERE domain=:domain LIMIT 1");
@ -47,7 +49,7 @@
try try
{ {
$stmt = Database::getConnection()->prepare("INSERT INTO external_sessions (domain, rpc_endpoint, session_uuid, transport_encryption_algorithm, server_keypair_expires, server_public_signing_key, server_public_encryption_key, host_public_encryption_key, host_private_encryption_key, private_shared_secret, host_transport_encryption_key, server_transport_encryption_key) VALUES (:domain, :rpc_endpoint, :session_uuid, :transport_encryption_algorithm, :server_keypair_expires, :server_public_signing_key, :server_public_encryption_key, :host_public_encryption_key, :host_private_encryption_key, :private_shared_secret, :host_transport_encryption_key, :server_transport_encryption_key)"); $stmt = Database::getConnection()->prepare("INSERT INTO external_sessions (domain, rpc_endpoint, session_uuid, transport_encryption_algorithm, server_keypair_expires, server_public_signing_key, server_public_encryption_key, host_public_encryption_key, host_private_encryption_key, private_shared_secret, host_transport_encryption_key, server_transport_encryption_key) VALUES (:domain, :rpc_endpoint, :session_uuid, :transport_encryption_algorithm, :server_keypair_expires, :server_public_signing_key, :server_public_encryption_key, :host_public_encryption_key, :host_private_encryption_key, :private_shared_secret, :host_transport_encryption_key, :server_transport_encryption_key)");
$domain = $exportedSession->getRemoteServer(); $domain = strtolower($exportedSession->getRemoteServer());
$stmt->bindParam(':domain', $domain); $stmt->bindParam(':domain', $domain);
$rpcEndpoint = $exportedSession->getRpcEndpoint(); $rpcEndpoint = $exportedSession->getRpcEndpoint();
$stmt->bindParam(':rpc_endpoint', $rpcEndpoint); $stmt->bindParam(':rpc_endpoint', $rpcEndpoint);
@ -89,6 +91,8 @@
*/ */
public static function getSession(string $domain): ?ExportedSession public static function getSession(string $domain): ?ExportedSession
{ {
$domain = strtolower($domain);
try try
{ {
$stmt = Database::getConnection()->prepare("SELECT * FROM external_sessions WHERE domain=:domain LIMIT 1"); $stmt = Database::getConnection()->prepare("SELECT * FROM external_sessions WHERE domain=:domain LIMIT 1");
@ -134,6 +138,8 @@
*/ */
public static function removeSession(string $domain): void public static function removeSession(string $domain): void
{ {
$domain = strtolower($domain);
try try
{ {
$stmt = Database::getConnection()->prepare("DELETE FROM external_sessions WHERE domain=:domain"); $stmt = Database::getConnection()->prepare("DELETE FROM external_sessions WHERE domain=:domain");
@ -156,6 +162,8 @@
*/ */
public static function updateLastAccessed(string $domain): void public static function updateLastAccessed(string $domain): void
{ {
try try
{ {
$stmt = Database::getConnection()->prepare("UPDATE external_sessions SET last_accessed=CURRENT_TIMESTAMP WHERE domain=:domain"); $stmt = Database::getConnection()->prepare("UPDATE external_sessions SET last_accessed=CURRENT_TIMESTAMP WHERE domain=:domain");

View file

@ -734,6 +734,8 @@
*/ */
public static function getExternalSession(string $domain): SocialClient public static function getExternalSession(string $domain): SocialClient
{ {
$domain = strtolower($domain);
if(ExternalSessionManager::sessionExists($domain)) if(ExternalSessionManager::sessionExists($domain))
{ {
return new SocialClient(self::getServerAddress(), $domain, ExternalSessionManager::getSession($domain)); return new SocialClient(self::getServerAddress(), $domain, ExternalSessionManager::getSession($domain));
@ -749,6 +751,11 @@
throw new ResolutionException(sprintf('Failed to connect to remote server %s: %s', $domain, $e->getMessage()), $e->getCode(), $e); throw new ResolutionException(sprintf('Failed to connect to remote server %s: %s', $domain, $e->getMessage()), $e->getCode(), $e);
} }
if(!$client->getSessionState()->isAuthenticated())
{
throw new ResolutionException(sprintf('Failed to authenticate with remote server %s', $domain));
}
ExternalSessionManager::addSession($client->exportSession()); ExternalSessionManager::addSession($client->exportSession());
return $client; return $client;
} }

View file

@ -688,12 +688,14 @@
public function testCaseInsensitiveContactAddress(): void public function testCaseInsensitiveContactAddress(): void
{ {
$johnClient = Helper::generateRandomClient(TEAPOT_DOMAIN, prefix: 'johnCaseTest'); $johnClient = Helper::generateRandomClient(TEAPOT_DOMAIN, prefix: 'johnCaseTest');
$johnClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'John Doe'); $this->assertTrue($johnClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'John Doe'));
$johnClient->settingsSetPassword('SecretTestingPassword123'); $this->assertTrue($johnClient->settingsSetPassword('SecretTestingPassword123'));
$this->assertTrue($johnClient->getSessionState()->isAuthenticated());
$aliceClient = Helper::generateRandomClient(COFFEE_DOMAIN, prefix: 'aliceCaseTest'); $aliceClient = Helper::generateRandomClient(COFFEE_DOMAIN, prefix: 'aliceCaseTest');
$aliceClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'Alice Smith'); $this->assertTrue($aliceClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'Alice Smith'));
$aliceClient->settingsSetPassword('SecretTestingPassword123'); $this->assertTrue($aliceClient->settingsSetPassword('SecretTestingPassword123'));
$this->assertTrue($aliceClient->getSessionState()->isAuthenticated());
$aliceAddress = $aliceClient->getIdentifiedAs(); $aliceAddress = $aliceClient->getIdentifiedAs();
$mixedCaseAddress = ucfirst(strtolower($aliceAddress->getUsername())).'@'.strtoupper($aliceAddress->getDomain()); $mixedCaseAddress = ucfirst(strtolower($aliceAddress->getUsername())).'@'.strtoupper($aliceAddress->getDomain());

View file

@ -4,6 +4,7 @@
use Helper; use Helper;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Socialbox\Enums\Flags\SessionFlags;
use Socialbox\Enums\PrivacyState; use Socialbox\Enums\PrivacyState;
use Socialbox\Enums\Types\InformationFieldName; use Socialbox\Enums\Types\InformationFieldName;
use Socialbox\Exceptions\CryptographyException; use Socialbox\Exceptions\CryptographyException;
@ -512,4 +513,43 @@
$this->assertTrue($aliceResolved->informationFieldExists(InformationFieldName::DISPLAY_NAME)); $this->assertTrue($aliceResolved->informationFieldExists(InformationFieldName::DISPLAY_NAME));
$this->assertEquals('Alice Smith', $aliceResolved->getInformationField(InformationFieldName::DISPLAY_NAME)->getValue()); $this->assertEquals('Alice Smith', $aliceResolved->getInformationField(InformationFieldName::DISPLAY_NAME)->getValue());
} }
/**
* @throws RpcException
* @throws ResolutionException
* @throws CryptographyException
* @throws DatabaseOperationException
*/
public function testDeleteRequiredPassword(): void
{
$testClient = Helper::generateRandomClient(COFFEE_DOMAIN, prefix: 'deleteRequiredPassword');
$this->assertTrue($testClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'John Doe'));
$this->assertTrue($testClient->settingsSetPassword('SecretTestingPassword123'));
$this->assertTrue($testClient->getSessionState()->isAuthenticated());
$this->expectException(RpcException::class);
$testClient->settingsDeletePassword();
}
/**
* @throws RpcException
* @throws DatabaseOperationException
* @throws ResolutionException
* @throws CryptographyException
*/
public function testSettingsSetOtp(): void
{
$testClient = Helper::generateRandomClient(COFFEE_DOMAIN, prefix: 'testSetOtp');
$testAddress = $testClient->getIdentifiedAs();
$this->assertTrue($testClient->settingsAddInformationField(InformationFieldName::DISPLAY_NAME, 'John Doe'));
$this->assertTrue($testClient->settingsSetPassword('SecretTestingPassword123'));
$this->assertTrue($testClient->getSessionState()->isAuthenticated());
$secret = $testClient->settingsSetOtp('SecretTestingPassword123');
$this->assertNotEmpty($secret);
$testClient = new SocialClient($testAddress);
$this->assertFalse($testClient->getSessionState()->isAuthenticated());
$this->assertTrue($testClient->getSessionState()->containsFlag(SessionFlags::VER_OTP));
}
} }