33namespace Clue \React \Socks ;
44
55use React \Socket \ServerInterface ;
6- use React \Promise ;
7- use React \Promise \Deferred ;
86use React \Promise \PromiseInterface ;
97use React \Socket \ConnectorInterface ;
108use React \Socket \Connector ;
@@ -39,14 +37,40 @@ final class Server
3937
4038 private $ connector ;
4139
42- private $ auth = null ;
40+ /**
41+ * @var null|callable
42+ */
43+ private $ auth ;
4344
44- public function __construct (LoopInterface $ loop , ConnectorInterface $ connector = null )
45+ /**
46+ * @param LoopInterface $loop
47+ * @param null|ConnectorInterface $connector
48+ * @param null|array|callable $auth
49+ */
50+ public function __construct (LoopInterface $ loop , ConnectorInterface $ connector = null , $ auth = null )
4551 {
4652 if ($ connector === null ) {
4753 $ connector = new Connector ($ loop );
4854 }
4955
56+ if (\is_array ($ auth )) {
57+ // wrap authentication array in authentication callback
58+ $ this ->auth = function ($ username , $ password ) use ($ auth ) {
59+ return \React \Promise \resolve (
60+ isset ($ auth [$ username ]) && (string )$ auth [$ username ] === $ password
61+ );
62+ };
63+ } elseif (\is_callable ($ auth )) {
64+ // wrap authentication callback in order to cast its return value to a promise
65+ $ this ->auth = function ($ username , $ password , $ remote ) use ($ auth ) {
66+ return \React \Promise \resolve (
67+ \call_user_func ($ auth , $ username , $ password , $ remote )
68+ );
69+ };
70+ } elseif ($ auth !== null ) {
71+ throw new \InvalidArgumentException ('Invalid authenticator given ' );
72+ }
73+
5074 $ this ->loop = $ loop ;
5175 $ this ->connector = $ connector ;
5276 }
@@ -63,36 +87,6 @@ public function listen(ServerInterface $socket)
6387 });
6488 }
6589
66- public function setAuth ($ auth )
67- {
68- if (!is_callable ($ auth )) {
69- throw new InvalidArgumentException ('Given authenticator is not a valid callable ' );
70- }
71-
72- // wrap authentication callback in order to cast its return value to a promise
73- $ this ->auth = function ($ username , $ password , $ remote ) use ($ auth ) {
74- $ ret = call_user_func ($ auth , $ username , $ password , $ remote );
75- if ($ ret instanceof PromiseInterface) {
76- return $ ret ;
77- }
78- $ deferred = new Deferred ();
79- $ ret ? $ deferred ->resolve () : $ deferred ->reject ();
80- return $ deferred ->promise ();
81- };
82- }
83-
84- public function setAuthArray (array $ login )
85- {
86- $ this ->setAuth (function ($ username , $ password ) use ($ login ) {
87- return (isset ($ login [$ username ]) && (string )$ login [$ username ] === $ password );
88- });
89- }
90-
91- public function unsetAuth ()
92- {
93- $ this ->auth = null ;
94- }
95-
9690 /** @internal */
9791 public function onConnection (ConnectionInterface $ connection )
9892 {
@@ -215,7 +209,7 @@ public function handleSocks4(ConnectionInterface $stream, StreamReader $reader)
215209 }
216210
217211 /** @internal */
218- public function handleSocks5 (ConnectionInterface $ stream , $ auth= null , StreamReader $ reader )
212+ public function handleSocks5 (ConnectionInterface $ stream , $ auth , StreamReader $ reader )
219213 {
220214 $ remote = $ stream ->getRemoteAddress ();
221215 if ($ remote !== null ) {
@@ -255,13 +249,19 @@ public function handleSocks5(ConnectionInterface $stream, $auth=null, StreamRead
255249 $ remote = str_replace (':// ' , ':// ' . rawurlencode ($ username ) . ': ' . rawurlencode ($ password ) . '@ ' , $ remote );
256250 }
257251
258- return $ auth ($ username , $ password , $ remote )->then (function () use ($ stream ) {
259- // accept
260- $ stream ->write (pack ('C2 ' , 0x01 , 0x00 ));
261- }, function () use ($ stream ) {
262- // reject => send any code but 0x00
252+ return $ auth ($ username , $ password , $ remote )->then (function ($ authenticated ) use ($ stream ) {
253+ if ($ authenticated ) {
254+ // accept auth
255+ $ stream ->write (pack ('C2 ' , 0x01 , 0x00 ));
256+ } else {
257+ // reject auth => send any code but 0x00
258+ $ stream ->end (pack ('C2 ' , 0x01 , 0xFF ));
259+ throw new UnexpectedValueException ('Authentication denied ' );
260+ }
261+ }, function ($ e ) use ($ stream ) {
262+ // reject failed authentication => send any code but 0x00
263263 $ stream ->end (pack ('C2 ' , 0x01 , 0xFF ));
264- throw new UnexpectedValueException ('Unable to authenticate ' );
264+ throw new UnexpectedValueException ('Authentication error ' , 0 , $ e );
265265 });
266266 });
267267 });
@@ -336,7 +336,7 @@ public function connectTarget(ConnectionInterface $stream, array $target)
336336 // validate URI so a string hostname can not pass excessive URI parts
337337 $ parts = parse_url ('tcp:// ' . $ uri );
338338 if (!$ parts || !isset ($ parts ['scheme ' ], $ parts ['host ' ], $ parts ['port ' ]) || count ($ parts ) !== 3 ) {
339- return Promise \reject (new InvalidArgumentException ('Invalid target URI given ' ));
339+ return \ React \ Promise \reject (new InvalidArgumentException ('Invalid target URI given ' ));
340340 }
341341
342342 if (isset ($ target [2 ])) {
0 commit comments