diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f82794..a80a065 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: strategy: matrix: php: + - 8.4 - 8.3 - 8.2 - 8.1 diff --git a/composer.json b/composer.json index 3f824db..ed9e822 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,15 @@ ], "require": { "php": ">=5.3", - "react/promise": "^3 || ^2.1 || ^1.2", - "react/socket": "^1.12" + "react/promise": "^3.2 || ^2.1 || ^1.2", + "react/socket": "^1.16" }, "require-dev": { "clue/connection-manager-extra": "^1.3", "phpunit/phpunit": "^9.6 || ^8.5 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", + "react/async": "^4.3 || ^3 || ^2", "react/event-loop": "^1.2", - "react/http": "^1.6" + "react/http": "^1.11" }, "autoload": { "psr-4": { diff --git a/src/Client.php b/src/Client.php index fb689c8..5d4e415 100644 --- a/src/Client.php +++ b/src/Client.php @@ -34,8 +34,12 @@ final class Client implements ConnectorInterface public function __construct( #[\SensitiveParameter] $socksUri, - ConnectorInterface $connector = null + $connector = null ) { + if ($connector !== null && !$connector instanceof ConnectorInterface) { // manual type check to support legacy PHP < 7.1 + throw new InvalidArgumentException('Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + } + // support `sockss://` scheme for SOCKS over TLS // support `socks+unix://` scheme for Unix domain socket (UDS) paths if (preg_match('/^(socks(?:5|4)?)(s|\+unix):\/\/(.*?@)?(.+?)$/', $socksUri, $match)) { diff --git a/src/Server.php b/src/Server.php index 2d89139..3309635 100644 --- a/src/Server.php +++ b/src/Server.php @@ -58,11 +58,18 @@ final class Server * @param null|array|callable $auth */ public function __construct( - LoopInterface $loop = null, - ConnectorInterface $connector = null, + $loop = null, + $connector = null, #[\SensitiveParameter] $auth = null ) { + if ($loop !== null && !$loop instanceof LoopInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #1 ($loop) expected null|React\EventLoop\LoopInterface'); + } + if ($connector !== null && !$connector instanceof ConnectorInterface) { // manual type check to support legacy PHP < 7.1 + throw new \InvalidArgumentException('Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + } + if (\is_array($auth)) { // wrap authentication array in authentication callback $this->auth = function ( diff --git a/tests/ClientTest.php b/tests/ClientTest.php index b11c1ba..4b81714 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -121,6 +121,12 @@ public function testInvalidProtocolVersion() $this->client = new Client('socks3://127.0.0.1:9050', $this->connector); } + public function testCtorThrowsForInvalidConnector() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + new Client('127.0.0.1:1080', 'connector'); + } + public function testCreateWillConnectToProxy() { $promise = new Promise(function () { }); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 6f71410..274d558 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -68,6 +68,18 @@ public function testConstructorWithStaticAuthArray() )); } + public function testConstructorThrowsForInvalidLoop() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #1 ($loop) expected null|React\EventLoop\LoopInterface'); + new Server('loop'); + } + + public function testConstructorThrowsForInvalidConnector() + { + $this->setExpectedException('InvalidArgumentException', 'Argument #2 ($connector) expected null|React\Socket\ConnectorInterface'); + new Server(null, 'connector'); + } + public function testConstructorWithInvalidAuthenticatorThrows() { $this->setExpectedException("InvalidArgumentException");