diff --git a/README.md b/README.md index 23fe506..cbb1798 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ use RealtimeRegister\IsProxy; $isProxy = new IsProxy('my-secret-api-key'); foreach ($isProxy->checkMany('example', ['nl', 'com', 'net', 'org']) as $result) { - echo $result->getDomain() . $result->isAvailable() ? ' ✅' : ' ❌'; + echo $result->getDomain() . ($result->isAvailable() ? ' ✅' : ' ❌') . PHP_EOL; } // example.nl ✅ // example.com ❌ diff --git a/src/IsProxy.php b/src/IsProxy.php index e4f01e3..5863ea7 100644 --- a/src/IsProxy.php +++ b/src/IsProxy.php @@ -10,9 +10,9 @@ final class IsProxy { private IsProxyConnection $connection; - public function __construct(string $apiKey, string $host = 'is.yoursrs.com', int $port = 2001) + public function __construct(string $apiKey, string $host = 'is.yoursrs.com', int $port = 2001, bool $tls = true) { - $this->setConnection(new IsProxyConnection($apiKey, $host, $port)); + $this->setConnection(new IsProxyConnection($apiKey, $host, $port, $tls)); } public function setConnection(IsProxyConnection $connection): void diff --git a/src/Support/IsProxyConnection.php b/src/Support/IsProxyConnection.php index 68c5139..8e0a4fa 100644 --- a/src/Support/IsProxyConnection.php +++ b/src/Support/IsProxyConnection.php @@ -14,11 +14,14 @@ class IsProxyConnection /** @var resource */ protected $socket; - public function __construct(string $apiKey, string $host = 'is.yoursrs.com', int $port = 2001) + protected bool $tls; + + public function __construct(string $apiKey, string $host = 'is.yoursrs.com', int $port = 2001, bool $tls = true) { $this->apiKey = $apiKey; $this->host = $host; $this->port = $port; + $this->tls = $tls; } public function __destruct() @@ -34,11 +37,23 @@ public function connect(): bool } $this->socket = $socket; + + // Try to set up tls, if enabled; + if ($this->tls) { + if ($this->upgradeToTls() === false) { + return false; + } + } + return $this->login(); } public function disconnect(): void { + if (! $this->isConnected()) { + return; + } + $this->write('CLOSE'); @fclose($this->socket); @@ -84,4 +99,28 @@ protected function login(): bool return (bool) preg_match('#^100\sLogin\sok#', $response); } + + protected function upgradeToTls(): bool + { + if (! $this->write('STARTTLS')) { + return false; + } + + $response = $this->read(); + if (! preg_match('#^100\sOK#', $response)) { + return true; + } + + $methods = STREAM_CRYPTO_METHOD_TLS_CLIENT; + + if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { + $methods |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + } + + if (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) { + $methods |= STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT; + } + + return stream_socket_enable_crypto($this->socket, true, $methods) === true; + } } diff --git a/tests/Clients/Domains/DomainsApiTransferTest.php b/tests/Clients/Domains/DomainsApiTransferTest.php index 8e99d5b..f30b592 100644 --- a/tests/Clients/Domains/DomainsApiTransferTest.php +++ b/tests/Clients/Domains/DomainsApiTransferTest.php @@ -31,7 +31,6 @@ public function test_transfer_quote(): void authcode: '123123123', autoRenew: true, ns: [], - transferContacts: ['REGISTRANT'], designatedAgent: 'OLD', zone: Zone::fromArray(include __DIR__ . '/../../Domain/data/dns/zones/zone_valid.php'), contacts: DomainContactCollection::fromArray([include __DIR__ . '/../../Domain/data/domains/domain_contact_valid.php']), @@ -64,7 +63,7 @@ public function test_transfer(): void '123123123', true, [], - ['ADMIN'], + null, 'OLD', Zone::fromArray(include __DIR__ . '/../../Domain/data/dns/zones/zone_valid.php'), DomainContactCollection::fromArray([include __DIR__ . '/../../Domain/data/domains/domain_contact_valid.php']), diff --git a/tests/Helpers/MockedIsProxyConnection.php b/tests/Helpers/MockedIsProxyConnection.php index b0b9692..2470833 100644 --- a/tests/Helpers/MockedIsProxyConnection.php +++ b/tests/Helpers/MockedIsProxyConnection.php @@ -19,9 +19,9 @@ class MockedIsProxyConnection extends IsProxyConnection /** @var bool */ private $connected = false; - public function __construct(string $apiKey, TestCase $testCase) + public function __construct(string $apiKey, TestCase $testCase, bool $tls = true) { - parent::__construct($apiKey); + parent::__construct($apiKey, tls: $tls); $this->testCase = $testCase; } @@ -55,6 +55,13 @@ public function expectWrite(string $message): MockedIsProxyConnection public function connect(): bool { $this->connected = true; + + if ($this->tls) { + if ($this->upgradeToTls() === false) { + return false; + } + } + return $this->login(); } @@ -81,4 +88,19 @@ public function isConnected(): bool { return $this->connected; } + + protected function upgradeToTls(): bool + { + if (! $this->write('STARTTLS')) { + return false; + } + + $response = $this->read(); + + if ($response !== '100 OK') { + return false; + } + + return true; + } } diff --git a/tests/IsProxyConnectionTest.php b/tests/IsProxyConnectionTest.php index aeac1e9..abb3cbb 100644 --- a/tests/IsProxyConnectionTest.php +++ b/tests/IsProxyConnectionTest.php @@ -13,6 +13,8 @@ class IsProxyConnectionTest extends TestCase public function test_check(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('100 Login ok') ->expectWrite('IS example.com') @@ -33,6 +35,8 @@ public function test_check(): void public function test_connection_error(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('400 Login failed'); @@ -46,6 +50,8 @@ public function test_connection_error(): void public function test_check_wrong_answer(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('100 Login ok') ->expectWrite('IS example.com') @@ -63,6 +69,8 @@ public function test_check_wrong_answer(): void public function test_check_many(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('100 Login ok') ->expectWrite('IS example.com') @@ -110,6 +118,8 @@ public function test_check_many(): void public function test_check_many_connection_fail(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('400 Login failed'); @@ -123,6 +133,8 @@ public function test_check_many_connection_fail(): void public function test_check_premium(): void { $connection = (new MockedIsProxyConnection('secret', $this)) + ->expectWrite('STARTTLS') + ->expectRead('100 OK') ->expectWrite('LOGIN secret') ->expectRead('100 Login ok') ->expectWrite('ENABLE premium') @@ -182,4 +194,24 @@ public function test_check_premium(): void $this->assertEmpty($availableDomain->getExtras()); $this->assertTrue($invalidDomain->isInvalid()); } + + public function test_check_without_ssl_support(): void + { + $connection = (new MockedIsProxyConnection('secret', $this, false)) + ->expectWrite('LOGIN secret') + ->expectRead('100 Login ok') + ->expectWrite('IS example.com') + ->expectRead('example.com available') + ->expectWrite('CLOSE'); + + $isProxy = new IsProxy(apiKey:'secret', tls: false); + $isProxy->setConnection($connection); + + $result = $isProxy->check('example', 'com'); + + $this->assertInstanceOf(IsProxyDomain::class, $result); + $this->assertSame(IsProxyDomain::STATUS_AVAILABLE, $result->getStatus()); + $this->assertSame('example.com', $result->getDomain()); + $this->assertTrue($result->isAvailable()); + } }