From d1bbc86d21458ada3368c165ea5a5292c9752042 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Mon, 2 Sep 2019 15:30:29 +0200 Subject: [PATCH] Bugfixes --- src/danog/MadelineProto/Connection.php | 30 ++++++++++++++ src/danog/MadelineProto/DataCenter.php | 6 +-- .../MadelineProto/DataCenterConnection.php | 39 +++++++++++++++---- .../Loop/Generic/PeriodicLoop.php | 9 +++-- .../MTProtoSession/AckHandler.php | 4 +- .../MTProtoSession/CallHandler.php | 2 +- .../MTProtoSession/ResponseHandler.php | 27 ++++++------- .../MTProtoTools/AuthKeyHandler.php | 22 +++++------ .../MTProtoTools/CallHandler.php | 2 + src/danog/MadelineProto/TL/TL.php | 5 +-- src/danog/MadelineProto/Wrappers/Login.php | 2 +- 11 files changed, 104 insertions(+), 44 deletions(-) diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index e6b0a8b8..504aff55 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -266,6 +266,36 @@ class Connection extends Session return $this->ctx; } + /** + * Check if is an HTTP connection. + * + * @return boolean + */ + public function isHttp(): bool + { + return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]); + } + + /** + * Check if is a media connection + * + * @return boolean + */ + public function isMedia(): bool + { + return $this->ctx->isMedia(); + } + + /** + * Check if is a CDN connection + * + * @return boolean + */ + public function isCDN(): bool + { + return $this->ctx->isCDN(); + } + /** * Connects to a telegram DC using the specified protocol, proxy and connection parameters. * diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index fbab6972..8251cd10 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -41,9 +41,9 @@ use Amp\Socket\ClientTlsContext; use Amp\Socket\ConnectException; use Amp\Socket\Socket; use Amp\TimeoutException; -use danog\MadelineProto\AuthKey\AuthKey; -use danog\MadelineProto\AuthKey\PermAuthKey; -use danog\MadelineProto\AuthKey\TempAuthKey; +use danog\MadelineProto\MTProto\AuthKey; +use danog\MadelineProto\MTProto\PermAuthKey; +use danog\MadelineProto\MTProto\TempAuthKey; use danog\MadelineProto\Stream\Common\BufferedRawStream; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream; diff --git a/src/danog/MadelineProto/DataCenterConnection.php b/src/danog/MadelineProto/DataCenterConnection.php index d52dd338..ba5e1af0 100644 --- a/src/danog/MadelineProto/DataCenterConnection.php +++ b/src/danog/MadelineProto/DataCenterConnection.php @@ -18,9 +18,10 @@ namespace danog\MadelineProto; -use danog\MadelineProto\AuthKey\AuthKey; -use danog\MadelineProto\AuthKey\PermAuthKey; -use danog\MadelineProto\AuthKey\TempAuthKey; +use danog\MadelineProto\Loop\Generic\PeriodicLoop; +use danog\MadelineProto\MTProto\AuthKey; +use danog\MadelineProto\MTProto\PermAuthKey; +use danog\MadelineProto\MTProto\TempAuthKey; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpStream; @@ -229,7 +230,11 @@ class DataCenterConnection implements JsonSerializable */ public function authorized(bool $authorized) { - $this->getTempAuthKey()->authorized($authorized); + if ($authorized) { + $this->getTempAuthKey()->authorized($authorized); + } else if ($this->hasTempAuthKey()) { + $this->getTempAuthKey()->authorized($authorized); + } } /** @@ -297,7 +302,7 @@ class DataCenterConnection implements JsonSerializable if ($count > 1) { if (!$this->robinLoop) { - $this->robinLoop = new PeriodicLoop($this, [$this, 'even'], "Robin loop DC {$this->datacenter}", 10); + $this->robinLoop = new PeriodicLoop($this->API, [$this, 'even'], "Robin loop DC {$this->datacenter}", 10); } $this->robinLoop->start(); } @@ -363,7 +368,7 @@ class DataCenterConnection implements JsonSerializable */ public function getConnection(): Connection { - if (\count($this->availableConnections) === 1) { + if (\count($this->availableConnections) <= 1) { return $this->connections[0]; } \max($this->availableConnections); @@ -440,11 +445,31 @@ class DataCenterConnection implements JsonSerializable * * @return boolean */ - public function isHttp() + public function isHttp(): bool { return \in_array($this->ctx->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]); } + /** + * Check if is a media connection + * + * @return boolean + */ + public function isMedia(): bool + { + return $this->ctx->isMedia(); + } + + /** + * Check if is a CDN connection + * + * @return boolean + */ + public function isCDN(): bool + { + return $this->ctx->isCDN(); + } + /** * Get DC-specific settings * diff --git a/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php b/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php index 192e3686..df4a4e03 100644 --- a/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php +++ b/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php @@ -19,6 +19,7 @@ namespace danog\MadelineProto\Loop\Generic; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; +use danog\MadelineProto\MTProto; /** * Periodic loop. @@ -30,14 +31,16 @@ class PeriodicLoop extends ResumableSignalLoop private $callback; private $name; private $timeout; - + /** * Constructor. * - * * @param \danog\MadelineProto\MTProto $API Instance of MTProto class + * @param callable $callback Callback to call + * @param string $name Loop name + * @param int $timeout Loop timeout */ - public function __construct($API, $callback, $name, $timeout) + public function __construct(MTProto $API, $callback, string $name, $timeout) { $this->API = $API; $this->callback = $callback; diff --git a/src/danog/MadelineProto/MTProtoSession/AckHandler.php b/src/danog/MadelineProto/MTProtoSession/AckHandler.php index def2bb32..cbd36349 100644 --- a/src/danog/MadelineProto/MTProtoSession/AckHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/AckHandler.php @@ -99,7 +99,7 @@ trait AckHandler && $this->shared->hasTempAuthKey() === !$this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req' ) { - if ($pfs && !$this->shared->getTempAuthKey()->bound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { + if ($pfs && !$this->shared->getTempAuthKey()->isBound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } @@ -128,7 +128,7 @@ trait AckHandler && $this->shared->hasTempAuthKey() === !$this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req' ) { - if ($pfs && !$this->shared->getTempAuthKey()->bound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { + if ($pfs && !$this->shared->getTempAuthKey()->isBound() && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } diff --git a/src/danog/MadelineProto/MTProtoSession/CallHandler.php b/src/danog/MadelineProto/MTProtoSession/CallHandler.php index cf67f243..72123a09 100644 --- a/src/danog/MadelineProto/MTProtoSession/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/CallHandler.php @@ -149,7 +149,7 @@ trait CallHandler if (isset($args['multiple'])) { $aargs['multiple'] = true; } - if (isset($args['message']) && \is_string($args['message']) && \mb_strlen($args['message'], 'UTF-8') > $this->API->config['message_length_max'] && \mb_strlen((yield $this->parse_mode_async($args))['message'], 'UTF-8') > $this->API->config['message_length_max']) { + if (isset($args['message']) && \is_string($args['message']) && \mb_strlen($args['message'], 'UTF-8') > (yield $this->API->get_config_async())['message_length_max'] && \mb_strlen((yield $this->parse_mode_async($args))['message'], 'UTF-8') > (yield $this->API->get_config_async())['message_length_max']) { $args = yield $this->split_to_chunks_async($args); $promises = []; $aargs['queue'] = $method; diff --git a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php index 8d714b24..a818f1c0 100644 --- a/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoSession/ResponseHandler.php @@ -20,6 +20,7 @@ namespace danog\MadelineProto\MTProtoSession; use Amp\Loop; +use danog\MadelineProto\MTProto; /** * Manages responses. @@ -118,8 +119,8 @@ trait ResponseHandler $this->ack_incoming_message_id($current_msg_id); // Acknowledge that I received the server's response - if ($this->authorized === self::LOGGED_IN && !$this->initing_authorization && $this->API->datacenter->getDataCenterConnection($this->API->datacenter->curdc)->hasTempAuthKey() && isset($this->updaters[false])) { - $this->updaters[false]->resumeDefer(); + if ($this->API->authorized === MTProto::LOGGED_IN && !$this->API->isInitingAuthorization() && $this->API->datacenter->getDataCenterConnection($this->API->datacenter->curdc)->hasTempAuthKey() && isset($this->API->updaters[false])) { + $this->API->updaters[false]->resumeDefer(); } unset($this->incoming_messages[$current_msg_id]['content']); @@ -190,7 +191,7 @@ trait ResponseHandler *$this->got_response_for_outgoing_message_id($msg_id); *} */ - foreach (self::MSGS_INFO_FLAGS as $flag => $description) { + foreach (MTProto::MSGS_INFO_FLAGS as $flag => $description) { if (($info & $flag) !== 0) { $status .= $description; } @@ -263,7 +264,7 @@ trait ResponseHandler case 'Updates': unset($this->new_incoming[$current_msg_id]); - if (\strpos($this->datacenter, 'cdn') === false) { + if (!$this->isCdn()) { $this->callForkDefer($this->API->handle_updates_async($this->incoming_messages[$current_msg_id]['content'])); } @@ -408,9 +409,9 @@ trait ResponseHandler $this->logger->logger($response['error_message'], \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->API->datacenter->getDataCenterConnections() as $socket) { - $socket->authKey(null, true); - $socket->authKey(null, false); $socket->authorized(false); + $socket->setTempAuthKey(null); + $socket->setPermAuthKey(null); $socket->resetSession(); } @@ -435,7 +436,7 @@ trait ResponseHandler return; case 'AUTH_KEY_UNREGISTERED': case 'AUTH_KEY_INVALID': - if ($this->authorized !== self::LOGGED_IN) { + if ($this->API->authorized !== MTProto::LOGGED_IN) { $this->got_response_for_outgoing_message_id($request_id); $this->callFork((function () use (&$request, &$response) { @@ -452,14 +453,14 @@ trait ResponseHandler $this->logger->logger('Auth key not registered, resetting temporary and permanent auth keys...', \danog\MadelineProto\Logger::ERROR); - if ($this->API->authorized_dc === $this->datacenter && $this->authorized === self::LOGGED_IN) { + if ($this->API->authorized_dc === $this->datacenter && $this->API->authorized === MTProto::LOGGED_IN) { $this->got_response_for_outgoing_message_id($request_id); $this->logger->logger('Permanent auth key was main authorized key, logging out...', \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->API->datacenter->getDataCenterConnections() as $socket) { - $socket->authKey(null, true); - $socket->authKey(null, false); $socket->authorized(false); + $socket->setTempAuthKey(null); + $socket->setPermAuthKey(null); } $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); @@ -531,7 +532,7 @@ trait ResponseHandler break; case 'bad_server_salt': case 'bad_msg_notification': - $this->logger->logger('Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); + $this->logger->logger('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); switch ($response['error_code']) { case 48: $this->getTempAuthKey()->setServerSalt($response['new_server_salt']); @@ -552,7 +553,7 @@ trait ResponseHandler return; } $this->got_response_for_outgoing_message_id($request_id); - $this->handle_reject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], isset($request['_']) ? $request['_'] : '')); + $this->handle_reject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], isset($request['_']) ? $request['_'] : '')); return; } @@ -568,7 +569,7 @@ trait ResponseHandler return; } $botAPI = isset($request['botAPI']) && $request['botAPI']; - if (isset($response['_']) && \strpos($this->datacenter, 'cdn') === false && $this->API->constructors->find_by_predicate($response['_'])['type'] === 'Updates') { + if (isset($response['_']) && !$this->isCdn() && $this->API->constructors->find_by_predicate($response['_'])['type'] === 'Updates') { $response['request'] = $request; $this->callForkDefer($this->API->handle_updates_async($response)); } diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index 64f7e2c1..655af128 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -20,9 +20,9 @@ namespace danog\MadelineProto\MTProtoTools; use Amp\Artax\Request; -use danog\MadelineProto\AuthKey\AuthKey; -use danog\MadelineProto\AuthKey\PermAuthKey; -use danog\MadelineProto\AuthKey\TempAuthKey; +use danog\MadelineProto\MTProto\AuthKey; +use danog\MadelineProto\MTProto\PermAuthKey; +use danog\MadelineProto\MTProto\TempAuthKey; use danog\MadelineProto\DataCenterConnection; use phpseclib\Math\BigInteger; @@ -64,9 +64,9 @@ trait AuthKeyHandler */ public function create_auth_key_async(int $expires_in, string $datacenter): \Generator { - $cdn = \strpos($datacenter, 'cdn'); - $req_pq = $cdn ? 'req_pq' : 'req_pq_multi'; $connection = $this->datacenter->getAuthConnection($datacenter); + $cdn = $connection->isCDN(); + $req_pq = $cdn ? 'req_pq' : 'req_pq_multi'; for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { try { @@ -430,7 +430,7 @@ trait AuthKeyHandler $this->logger->logger('An exception occurred while generating the authorization key: '.$e.PHP_EOL.' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); } } - if (\strpos($datacenter, 'cdn') === false) { + if (!$cdn) { throw new \danog\MadelineProto\SecurityException('Auth Failed'); } } @@ -653,7 +653,7 @@ trait AuthKeyHandler $dcs = []; $postpone = []; foreach ($this->datacenter->getDataCenterConnections() as $id => $socket) { - if (\strpos($id, 'media') !== false) { + if ($socket->isMedia()) { $oid = \intval($id); if (isset($dcs[$oid])) { $postpone[$id] = $socket; @@ -711,13 +711,13 @@ trait AuthKeyHandler $connection->session_in_seq_no = 0; $connection->session_out_seq_no = 0; } - $cdn = \strpos($id, 'cdn'); - $media = \strpos($id, 'media'); + $cdn = $socket->isCDN(); + $media = $socket->isMedia(); if (!$socket->hasTempAuthKey() || !$socket->hasPermAuthKey()) { if (!$socket->hasPermAuthKey() && !$cdn && !$media) { $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); $socket->setPermAuthKey(yield $this->create_auth_key_async(-1, $id)); - $socket->authorized(false); + //$socket->authorized(false); } if ($media) { $socket->link(\intval($id)); @@ -778,7 +778,7 @@ trait AuthKeyHandler if ($this->authorized_dc !== -1 && $authorized_dc_id !== $this->authorized_dc) { continue; } - if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && \strpos($authorized_dc_id, 'cdn') === false) { + if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) { try { $this->logger->logger('Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id); $exported_authorization = yield $this->method_call_async_read('auth.exportAuthorization', ['dc_id' => \preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]); diff --git a/src/danog/MadelineProto/MTProtoTools/CallHandler.php b/src/danog/MadelineProto/MTProtoTools/CallHandler.php index aa99fe25..8c55035f 100644 --- a/src/danog/MadelineProto/MTProtoTools/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/CallHandler.php @@ -19,6 +19,8 @@ namespace danog\MadelineProto\MTProtoTools; +use Amp\Promise; + /** * Manages method and object calls. */ diff --git a/src/danog/MadelineProto/TL/TL.php b/src/danog/MadelineProto/TL/TL.php index 4429d62a..48a5524d 100644 --- a/src/danog/MadelineProto/TL/TL.php +++ b/src/danog/MadelineProto/TL/TL.php @@ -785,7 +785,6 @@ trait TL if (!isset($type['subtype'])) { $type['subtype'] = ''; } - return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'connection' => $type['connection'], 'subtype' => $type['subtype']]); } if ($constructorData['type'] === 'Vector t') { @@ -849,8 +848,8 @@ trait TL $arg['subtype'] = str_replace(['Vector<', '>'], '', $type['connection']->outgoing_messages[$x['req_msg_id']]['type']); } } - if (isset($type['datacenter'])) { - $arg['datacenter'] = $type['datacenter']; + if (isset($type['connection'])) { + $arg['connection'] = $type['connection']; } $x[$arg['name']] = $this->deserialize($stream, $arg); if ($arg['name'] === 'random_bytes') { diff --git a/src/danog/MadelineProto/Wrappers/Login.php b/src/danog/MadelineProto/Wrappers/Login.php index 8bcf1e64..a97a9f01 100644 --- a/src/danog/MadelineProto/Wrappers/Login.php +++ b/src/danog/MadelineProto/Wrappers/Login.php @@ -19,7 +19,7 @@ namespace danog\MadelineProto\Wrappers; -use danog\MadelineProto\AuthKey\PermAuthKey; +use danog\MadelineProto\MTProto\PermAuthKey; use danog\MadelineProto\MTProtoTools\PasswordCalculator; /**