From 214fc0d0f98324eec138da3966710493cddf0eb3 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Tue, 25 Jun 2019 18:02:56 +0200 Subject: [PATCH 01/11] Bugfix --- src/danog/MadelineProto/Loop/Connection/ReadLoop.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php index f124b1eb..1f773f08 100644 --- a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php @@ -18,6 +18,8 @@ namespace danog\MadelineProto\Loop\Connection; +use Amp\ByteStream\PendingReadError; +use Amp\ByteStream\StreamException; use Amp\Loop; use Amp\Websocket\ClosedException; use danog\MadelineProto\Logger; @@ -25,7 +27,6 @@ use danog\MadelineProto\Loop\Impl\SignalLoop; use danog\MadelineProto\MTProtoTools\Crypt; use danog\MadelineProto\NothingInTheSocketException; use danog\MadelineProto\Tools; -use Amp\ByteStream\StreamException; /** * Socket read loop. @@ -57,7 +58,7 @@ class ReadLoop extends SignalLoop while (true) { try { $error = yield $this->waitSignal($this->readMessage()); - } catch (NothingInTheSocketException|StreamException $e) { + } catch (NothingInTheSocketException | StreamException | PendingReadError $e) { if (isset($connection->old)) { return; } @@ -65,10 +66,6 @@ class ReadLoop extends SignalLoop $API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR); yield $connection->reconnect(); continue; - } catch (ClosedException $e) { - $API->logger->logger($e->getMessage(), Logger::FATAL_ERROR); - - throw $e; } if (is_int($error)) { From eafa19eb4ed6605f98086f37a3451aaa1097fa5a Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Tue, 25 Jun 2019 18:11:42 +0200 Subject: [PATCH 02/11] Small workaround --- .../MTProtoTools/ResponseHandler.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php index 0c0eeaf1..8b687363 100644 --- a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php @@ -312,7 +312,15 @@ trait ResponseHandler if (isset($request['promise'])) { $promise = $request['promise']; unset($request['promise']); - $promise->fail($data); + try { + $promise->fail($data); + } catch (\Error $e) { + if (strpos($e->getMessage(), "Promise has already been resolved") !== 0) { + throw $e; + } + $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); + } + } else { $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-')); $this->logger->logger("Rejecting: $data"); @@ -576,7 +584,14 @@ trait ResponseHandler if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise'])) { // This should not happen but happens, should debug $promise = $this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise']; unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise']); - $promise->resolve($response); + try { + $promise->resolve($response); + } catch (\Error $e) { + if (strpos($e->getMessage(), "Promise has already been resolved") !== 0) { + throw $e; + } + $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); + } } } )()); From 5af3fe77c6a80b4b8baa66968d92fc9a5b2c7b20 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Thu, 27 Jun 2019 11:27:13 +0200 Subject: [PATCH 03/11] Bugfix --- src/danog/MadelineProto/Stream/Common/BufferedRawStream.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php b/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php index 129380e9..56defd56 100644 --- a/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php +++ b/src/danog/MadelineProto/Stream/Common/BufferedRawStream.php @@ -24,6 +24,7 @@ use danog\MadelineProto\Exception; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\ConnectionContext; use function Amp\Socket\connect; +use Amp\ByteStream\ClosedException; /** * Buffered raw stream. From 49903b215e25ab117cc3910494876b78d013e99b Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 28 Jun 2019 19:37:23 +0200 Subject: [PATCH 04/11] Obfuscated bugfix --- .../Stream/MTProtoTransport/ObfuscatedStream.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php index 2aa2759d..8043158e 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.php @@ -186,12 +186,15 @@ class ObfuscatedStream implements BufferedProxyStreamInterface */ public function setExtra($extra) { - if (isset($extra['secret']) && strlen($extra['secret']) > 17) { - $extra['secret'] = hex2bin($extra['secret']); - } - if (isset($extra['secret']) && strlen($extra['secret']) == 17) { - $extra['secret'] = substr($extra['secret'], 0, 16); + if (isset($extra['secret'])) { + if (strlen($extra['secret']) > 17) { + $extra['secret'] = hex2bin($extra['secret']); + } + if (strlen($extra['secret']) == 17) { + $extra['secret'] = substr($extra['secret'], 1, 16); + } } + $this->extra = $extra; } From 6b5775da795869ee43d8d048efd15a3f4b8d47dc Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 29 Jun 2019 15:21:29 +0200 Subject: [PATCH 05/11] Default to obfuscated transport with websocket --- docs | 2 +- src/danog/MadelineProto/DataCenter.php | 12 ++---------- .../MadelineProto/Stream/Transport/WsStream.php | 1 + 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/docs b/docs index cbd913fb..7414ae3e 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit cbd913fba2249a0055bb732452a67f911119c40a +Subproject commit 7414ae3e537b26a15b75d2a00ef6f93e702d2cd8 diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index c6dc9369..902a0639 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -444,18 +444,10 @@ class DataCenter } break; case 'wss': - if ($this->settings[$dc_config_number]['obfuscated']) { - $default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; - } else { - $default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], end($default)]; - } + $default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; break; case 'ws': - if ($this->settings[$dc_config_number]['obfuscated']) { - $default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; - } else { - $default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], end($default)]; - } + $default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; break; } } diff --git a/src/danog/MadelineProto/Stream/Transport/WsStream.php b/src/danog/MadelineProto/Stream/Transport/WsStream.php index 6d70f5c1..6e01385e 100644 --- a/src/danog/MadelineProto/Stream/Transport/WsStream.php +++ b/src/danog/MadelineProto/Stream/Transport/WsStream.php @@ -84,6 +84,7 @@ class WsStream implements RawStreamInterface break; } } + if (!$this->stream) { throw new ConnectionException('Failed to read response from server'); } From 37a9133a6ff9ab596080f4b06e95f6a0637c379a Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sun, 30 Jun 2019 15:12:43 +0200 Subject: [PATCH 06/11] Improved 2FA --- README.md | 1 + docs | 2 +- .../MTProtoTools/AuthKeyHandler.php | 2 + .../MTProtoTools/PasswordCalculator.php | 109 ++++++++- src/danog/MadelineProto/Magic.php | 6 + src/danog/MadelineProto/RPCErrorException.php | 211 ++++++------------ src/danog/MadelineProto/Wrappers/Login.php | 2 +- tests/testing.php | 12 +- 8 files changed, 194 insertions(+), 151 deletions(-) diff --git a/README.md b/README.md index 021bec54..594ae56f 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ Tip: if you receive an error (or nothing), [send us](https://t.me/pwrtelegramgro * [Full chat info with full list of participants](https://docs.madelineproto.xyz/docs/CHAT_INFO.html#get_pwr_chat-now-fully-async) * [Full chat info](https://docs.madelineproto.xyz/docs/CHAT_INFO.html#get_full_info-now-fully-async) * [Reduced chat info (very fast)](https://docs.madelineproto.xyz/docs/CHAT_INFO.html#get_info-now-fully-async) + * [Just the chat ID (extremely fast)](https://docs.madelineproto.xyz/docs/CHAT_INFO.html#get_id-now-fully-async) * [Getting all chats (dialogs)](https://docs.madelineproto.xyz/docs/DIALOGS.html) * [Dialog list](https://docs.madelineproto.xyz/docs/DIALOGS.html#get_dialogs-now-fully-async) * [Full dialog info](https://docs.madelineproto.xyz/docs/DIALOGS.html#get_full_dialogs-now-fully-async) diff --git a/docs b/docs index 7414ae3e..ddb2e4f7 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 7414ae3e537b26a15b75d2a00ef6f93e702d2cd8 +Subproject commit ddb2e4f76938b69ceac6e4615901c642accae1ef diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index 76959f2d..3584687e 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -390,6 +390,8 @@ trait AuthKeyHandler $req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi'; } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); + } catch (\Throwable $e) { + $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) { diff --git a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php index 43f75255..a1ed6da7 100644 --- a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php +++ b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php @@ -25,24 +25,77 @@ use danog\MadelineProto\Tools; use phpseclib\Math\BigInteger; /** - * Manages password calculation. + * Manages SRP password calculation + * + * @author Daniil Gentili + * @link https://docs.madelineproto.xyz MadelineProto documentation */ class PasswordCalculator { use AuthKeyHandler; use Tools; + + /** + * The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object) + * + * @var array + */ private $new_algo; + /** + * A secure random string that can be used to compute the password + * + * @var string + */ private $secure_random = ''; + /** + * The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object) + * + * @var array + */ private $current_algo; + + /** + * SRP b parameter + * + * @var BigInteger + */ private $srp_B; + /** + * SRP b parameter for hashing + * + * @var BigInteger + */ private $srp_BForHash; + /** + * SRP ID + * + * @var [type] + */ private $srp_id; + /** + * Logger + * + * @var \danog\MadelineProto\Logger + */ public $logger; - // This is needed do not remove this - public function __construct($logger) { $this->logger = $logger; } + /** + * Initialize logger + * + * @param \danog\MadelineProto\Logger $logger + */ + public function __construct($logger) + { + $this->logger = $logger; + } + /** + * Popupate 2FA configuration + * + * @param array $object 2FA configuration object obtained using account.getPassword + * @return void + */ public function addInfo(array $object) { if ($object['_'] !== 'account.password') { @@ -101,16 +154,39 @@ class PasswordCalculator $this->secure_random = $object['secure_random']; } + /** + * Create a random string (eventually prefixed by the specified string) + * + * @param string $prefix Prefix + * @return string Salt + */ public function createSalt(string $prefix = ''): string { return $prefix.$this->random(32); } + /** + * Hash specified data using the salt with SHA256 + * + * The result will be the SHA256 hash of the salt concatenated with the data concatenated with the salt + * + * @param string $data Data to hash + * @param string $salt Salt + * @return string Hash + */ public function hashSha256(string $data, string $salt): string { return hash('sha256', $salt.$data.$salt, true); } + /** + * Hashes the specified password + * + * @param string $password Password + * @param string $client_salt Client salt + * @param string $server_salt Server salt + * @return string Resulting hash + */ public function hashPassword(string $password, string $client_salt, string $server_salt): string { $buf = $this->hashSha256($password, $client_salt); @@ -120,9 +196,15 @@ class PasswordCalculator return $this->hashSha256($hash, $server_salt); } + /** + * Get the InputCheckPassword object for checking the validity of a password using account.checkPassword + * + * @param string $password The password + * @return array InputCheckPassword object + */ public function getCheckPassword(string $password): array { - if ($password === '') { + if ($password === '' || !$this->current_algo) { return ['_' => 'inputCheckPasswordEmpty']; } $client_salt = $this->current_algo['salt1']; @@ -166,9 +248,20 @@ class PasswordCalculator return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1]; } + /** + * Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password + * + * The input params array can contain password, new_password, email and hint params. + * + * @param array $params Input params + * @return array account.updatePasswordSettings parameters + */ public function getPassword(array $params): array { - $return = ['password' => $this->getCheckPassword(isset($params['password']) ? $params['password'] : ''), 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']]; + $oldPassword = $this->getCheckPassword($params['password'] ?? ''); + + $return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']]; + $new_settings = &$return['new_settings']; if (isset($params['new_password']) && $params['new_password'] !== '') { @@ -183,11 +276,11 @@ class PasswordCalculator $vForHash = str_pad($v->toBytes(), 256, chr(0), \STR_PAD_LEFT); $new_settings['new_algo'] = [ - '_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', + '_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', 'salt1' => $client_salt, 'salt2' => $server_salt, - 'g' => (int) $g->toString(), - 'p' => $pForHash, + 'g' => (int) $g->toString(), + 'p' => $pForHash, ]; $new_settings['new_password_hash'] = $vForHash; $new_settings['hint'] = $params['hint']; diff --git a/src/danog/MadelineProto/Magic.php b/src/danog/MadelineProto/Magic.php index ebc0efd9..873bfa73 100644 --- a/src/danog/MadelineProto/Magic.php +++ b/src/danog/MadelineProto/Magic.php @@ -175,6 +175,12 @@ class Magic //$this->logger->logger('Could not enable PHP logging'); } } + + $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?allv3'), true); + if (isset($res['ok']) && $res['ok']) { + RPCErrorException::$errorMethodMap = $res['result']; + RPCErrorException::$descriptions += $res['human_result']; + } self::$inited = true; } } diff --git a/src/danog/MadelineProto/RPCErrorException.php b/src/danog/MadelineProto/RPCErrorException.php index 50e257df..1c66ac30 100644 --- a/src/danog/MadelineProto/RPCErrorException.php +++ b/src/danog/MadelineProto/RPCErrorException.php @@ -25,21 +25,86 @@ class RPCErrorException extends \Exception private $fetched = false; public static $rollbar = true; - public function getMess() + public static $descriptions = [ + 'RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', + 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', + 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", + 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", + 'USER_IS_BOT' => "Bots can't send messages to other bots", + 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', + 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', + 'USERNAME_INVALID' => 'The provided username is not valid', + 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', + 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', + 'FIRSTNAME_INVALID' => 'The first name is invalid', + 'LASTNAME_INVALID' => 'The last name is invalid', + 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', + 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', + 'PHONE_CODE_EMPTY' => 'phone_code is missing', + 'PHONE_CODE_EXPIRED' => 'The confirmation code has expired', + 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', + 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', + 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', + 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', + 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', + 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', + 'FILE_PART_INVALID' => 'The file part number is invalid', + 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', + 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', + 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', + 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', + 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', + 'MSG_WAIT_FAILED' => 'A waiting call returned an error', + 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', + 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', + 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', + 'INVITE_HASH_EXPIRED' => 'The invite link has expired', + 'USER_DEACTIVATED' => 'The user was deactivated', + 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', + 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', + 'PEER_ID_INVALID' => 'The provided peer id is invalid', + 'CHAT_ID_INVALID' => 'The provided chat id is invalid', + 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", + 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', + -429 => 'Too many requests', + 'PEER_FLOOD' => "You are spamreported, you can't do this", + ]; + public static $errorMethodMap = []; + + private $caller = ''; + public static function localizeMessage($method, $code, $error) { - if ($this->fetched === false) { - $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$additional[0].'&code='.$code.'&error='.$this->rpc), true); + if (!$method || !$code || !$error) { + return $error; + } + + $error = preg_replace('/\d+$/', "X", $error); + + $description = self::$descriptions[$error] ?? ''; + + + if (!isset(self::$errorMethodMap[$code][$method][$error]) + || !isset(self::$descriptions[$error]) + || $code === 500 + ) { + $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$this->caller.'&code='.$this->code.'&error='.$this->rpc), true); if (isset($res['ok']) && $res['ok']) { - $this->message = $res['result']; + $description = $res['result']; + + self::$descriptions[$error] = $description; + self::$errorMethodMap[$code][$method][$error] = $error; } } - return $this->message; + if (!$description) { + return $error; + } + return $description; } public function __toString() { - $result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], $this->getMess()." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL; + $result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL; if (php_sapi_name() !== 'cli') { $result = str_replace(PHP_EOL, '
'.PHP_EOL, $result); } @@ -50,147 +115,19 @@ class RPCErrorException extends \Exception public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null) { $this->rpc = $message; - switch ($message) { - case 'RPC_MCGET_FAIL': - case 'RPC_CALL_FAIL': - $message = 'Telegram is having internal issues, please try again later.'; - break; - case 'USER_PRIVACY_RESTRICTED': - $message = "The user's privacy settings do not allow you to do this"; - break; - case 'CHANNEL_PRIVATE': - $message = "You haven't joined this channel/supergroup"; - break; - case 'FLOOD_WAIT_666': - $message = 'Spooky af m8'; - break; - case 'USER_IS_BOT': - $message = "Bots can't send messages to other bots"; - break; - case 'BOT_METHOD_INVALID': - $message = 'This method cannot be run by a bot'; - break; - case 'PHONE_CODE_EXPIRED': - $message = 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)'; - break; - case 'USERNAME_INVALID': - $message = 'The provided username is not valid'; - break; - case 'ACCESS_TOKEN_INVALID': - $message = 'The provided token is not valid'; - break; - case 'ACTIVE_USER_REQUIRED': - $message = 'The method is only available to already activated users'; - break; - case 'FIRSTNAME_INVALID': - $message = 'The first name is invalid'; - break; - case 'LASTNAME_INVALID': - $message = 'The last name is invalid'; - break; - case 'PHONE_NUMBER_INVALID': - $message = 'The phone number is invalid'; - break; - case 'PHONE_CODE_HASH_EMPTY': - $message = 'phone_code_hash is missing'; - break; - case 'PHONE_CODE_EMPTY': - $message = 'phone_code is missing'; - break; - case 'PHONE_CODE_EXPIRED': - $message = 'The confirmation code has expired'; - break; - case 'API_ID_INVALID': - $message = 'The api_id/api_hash combination is invalid'; - break; - case 'PHONE_NUMBER_OCCUPIED': - $message = 'The phone number is already in use'; - break; - case 'PHONE_NUMBER_UNOCCUPIED': - $message = 'The phone number is not yet being used'; - break; - case 'USERS_TOO_FEW': - $message = 'Not enough users (to create a chat, for example)'; - break; - case 'USERS_TOO_MUCH': - $message = 'The maximum number of users has been exceeded (to create a chat, for example)'; - break; - case 'TYPE_CONSTRUCTOR_INVALID': - $message = 'The type constructor is invalid'; - break; - case 'FILE_PART_INVALID': - $message = 'The file part number is invalid'; - break; - case 'FILE_PARTS_INVALID': - $message = 'The number of file parts is invalid'; - break; - case 'MD5_CHECKSUM_INVALID': - $message = 'The MD5 checksums do not match'; - break; - case 'PHOTO_INVALID_DIMENSIONS': - $message = 'The photo dimensions are invalid'; - break; - case 'FIELD_NAME_INVALID': - $message = 'The field with the name FIELD_NAME is invalid'; - break; - case 'FIELD_NAME_EMPTY': - $message = 'The field with the name FIELD_NAME is missing'; - break; - case 'MSG_WAIT_FAILED': - $message = 'A waiting call returned an error'; - break; - case 'USERNAME_NOT_OCCUPIED': - $message = 'The provided username is not occupied'; - break; - case 'PHONE_NUMBER_BANNED': - $message = 'The provided phone number is banned from telegram'; - break; - case 'AUTH_KEY_UNREGISTERED': - $message = 'The authorization key has expired'; - break; - case 'INVITE_HASH_EXPIRED': - $message = 'The invite link has expired'; - break; - case 'USER_DEACTIVATED': - $message = 'The user was deactivated'; - break; - case 'USER_ALREADY_PARTICIPANT': - $message = 'The user is already in the group'; - break; - case 'MESSAGE_ID_INVALID': - $message = 'The provided message id is invalid'; - break; - case 'PEER_ID_INVALID': - $message = 'The provided peer id is invalid'; - break; - case 'CHAT_ID_INVALID': - $message = 'The provided chat id is invalid'; - break; - case 'MESSAGE_DELETE_FORBIDDEN': - $message = "You can't delete one of the messages you tried to delete, most likely because it is a service message."; - break; - case 'CHAT_ADMIN_REQUIRED': - $message = 'You must be an admin in this chat to do this'; - break; - case -429: - case 'PEER_FLOOD': - $message = 'Too many requests'; - break; - } parent::__construct($message, $code, $previous); $this->prettify_tl($caller); + $this->caller = $caller; + $additional = []; foreach ($this->getTrace() as $level) { if (isset($level['function']) && $level['function'] === 'method_call') { $this->line = $level['line']; $this->file = $level['file']; $additional = $level['args']; - break; + } } - if ($this->rpc !== $message) { - $this->fetched = true; - } if (!self::$rollbar || !class_exists('\\Rollbar\\Rollbar')) { return; } diff --git a/src/danog/MadelineProto/Wrappers/Login.php b/src/danog/MadelineProto/Wrappers/Login.php index 45140170..0960dd67 100644 --- a/src/danog/MadelineProto/Wrappers/Login.php +++ b/src/danog/MadelineProto/Wrappers/Login.php @@ -205,7 +205,7 @@ trait Login /** * Update the 2FA password * - * The params can contain password, new_password, email and hint params. + * The params array can contain password, new_password, email and hint params. * * @param array $params The params * @return void diff --git a/tests/testing.php b/tests/testing.php index 7469075c..f26365ca 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -1,5 +1,7 @@ #!/usr/bin/env php accept_tos(); } } + //var_dump(count($MadelineProto->get_pwr_chat('@madelineproto')['participants'])); /* @@ -78,7 +82,7 @@ $message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sem /* * Try making a phone call */ -if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) { +if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to make a call? (y/n): '), 'y') !== false) { $controller = $MadelineProto->request_call(getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw'); while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) { $MadelineProto->get_updates(); @@ -92,8 +96,8 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to /* * Try receiving a phone call */ -if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) { - $howmany = $MadelineProto->readline('How many calls would you like me to handle? '); +if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) { + $howmany = readline('How many calls would you like me to handle? '); $offset = 0; while ($howmany > 0) { $updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout @@ -114,7 +118,7 @@ if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to /* * Secret chat usage */ -if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) { +if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) { /** * Request a secret chat. */ From c451471f783596ddecf9d52c2df6da256001acd0 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Mon, 1 Jul 2019 10:04:34 +0200 Subject: [PATCH 07/11] Setting alias --- src/danog/MadelineProto/Logger.php | 4 +++- .../MTProtoTools/PasswordCalculator.php | 1 + tests/testing.php | 12 ++++-------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/danog/MadelineProto/Logger.php b/src/danog/MadelineProto/Logger.php index a1609c05..7670884a 100644 --- a/src/danog/MadelineProto/Logger.php +++ b/src/danog/MadelineProto/Logger.php @@ -101,7 +101,9 @@ class Logger Exception::$rollbar = false; RPCErrorException::$rollbar = false; } - + if (!isset($settings['logger']['logger_param']) && isset($settings['logger']['param'])) { + $settings['logger']['logger_param'] = $settings['logger']['param']; + } if (php_sapi_name() !== 'cli') { if (isset($settings['logger']['logger_param']) && basename($settings['logger']['logger_param']) === 'MadelineProto.log') { $settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log'; diff --git a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php index a1ed6da7..36c03727 100644 --- a/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php +++ b/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php @@ -213,6 +213,7 @@ class PasswordCalculator $gForHash = $this->current_algo['gForHash']; $p = $this->current_algo['p']; $pForHash = $this->current_algo['pForHash']; + $B = $this->srp_B; $BForHash = $this->srp_BForHash; $id = $this->srp_id; diff --git a/tests/testing.php b/tests/testing.php index f26365ca..7469075c 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -1,7 +1,5 @@ #!/usr/bin/env php accept_tos(); } } - //var_dump(count($MadelineProto->get_pwr_chat('@madelineproto')['participants'])); /* @@ -82,7 +78,7 @@ $message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sem /* * Try making a phone call */ -if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to make a call? (y/n): '), 'y') !== false) { +if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) { $controller = $MadelineProto->request_call(getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw'); while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) { $MadelineProto->get_updates(); @@ -96,8 +92,8 @@ if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to make a call? (y /* * Try receiving a phone call */ -if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) { - $howmany = readline('How many calls would you like me to handle? '); +if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) { + $howmany = $MadelineProto->readline('How many calls would you like me to handle? '); $offset = 0; while ($howmany > 0) { $updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout @@ -118,7 +114,7 @@ if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to handle incoming /* * Secret chat usage */ -if (!getenv('TRAVIS_COMMIT') && stripos(readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) { +if (!getenv('TRAVIS_COMMIT') && stripos($MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) { /** * Request a secret chat. */ From 53bf8176f5263808537b0fd8a9adab1525ce03dd Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Mon, 1 Jul 2019 13:14:56 +0200 Subject: [PATCH 08/11] Stuffs --- src/danog/MadelineProto/Connection.php | 8 ++++- src/danog/MadelineProto/Logger.php | 2 ++ .../Loop/Connection/ReadLoop.php | 2 +- src/danog/MadelineProto/MTProto.php | 1 - src/danog/MadelineProto/Magic.php | 2 +- src/danog/MadelineProto/RPCErrorException.php | 2 +- src/danog/MadelineProto/Serialization.php | 5 --- src/danog/MadelineProto/TL_telegram_v102.tl | 7 ++-- src/danog/MadelineProto/Tools.php | 3 +- src/danog/MadelineProto/Wrappers/Loop.php | 34 +++++++++++++++++-- tests/testing.php | 2 +- 11 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index 20ef8729..e5a29c28 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -215,7 +215,13 @@ class Connection $this->disconnect(); yield $this->API->datacenter->dcConnectAsync($this->ctx->getDc()); if ($this->API->hasAllAuth() && !$this->hasPendingCalls()) { - $this->callFork($this->API->method_call_async_read('ping', ['ping_id' => $this->random_int()], ['datacenter' => $this->datacenter])); + $this->callFork((function () { + try { + $this->API->method_call_async_read('ping', ['ping_id' => $this->random_int()], ['datacenter' => $this->datacenter]); + } catch (\Throwable $e) { + $this->API->logger("Got an error while pinging on reconnect: $e", Logger::FATAL_ERROR); + } + })()); } } diff --git a/src/danog/MadelineProto/Logger.php b/src/danog/MadelineProto/Logger.php index 7670884a..c8a8cf8f 100644 --- a/src/danog/MadelineProto/Logger.php +++ b/src/danog/MadelineProto/Logger.php @@ -181,6 +181,8 @@ class Logger { if (!is_null(self::$default)) { self::$default->logger($param, $level, basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php')); + } else { + echo $param.PHP_EOL; } } diff --git a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php index 1f773f08..fa0197f4 100644 --- a/src/danog/MadelineProto/Loop/Connection/ReadLoop.php +++ b/src/danog/MadelineProto/Loop/Connection/ReadLoop.php @@ -58,7 +58,7 @@ class ReadLoop extends SignalLoop while (true) { try { $error = yield $this->waitSignal($this->readMessage()); - } catch (NothingInTheSocketException | StreamException | PendingReadError $e) { + } catch (NothingInTheSocketException | StreamException | PendingReadError | \Error $e) { if (isset($connection->old)) { return; } diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 3ec5273d..f30dd719 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -302,7 +302,6 @@ class MTProto extends AsyncConstruct implements TLCallback public function __wakeup_async($backtrace) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); - set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']); $this->setup_logger(); if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread())) { return; diff --git a/src/danog/MadelineProto/Magic.php b/src/danog/MadelineProto/Magic.php index 873bfa73..62ebe284 100644 --- a/src/danog/MadelineProto/Magic.php +++ b/src/danog/MadelineProto/Magic.php @@ -66,7 +66,7 @@ class Magic public static function class_exists() { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); - //set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']); + set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']); if (!self::$inited) { self::$has_thread = class_exists('\\Thread') && method_exists('\\Thread', 'getCurrentThread'); self::$BIG_ENDIAN = pack('L', 1) === pack('N', 1); diff --git a/src/danog/MadelineProto/RPCErrorException.php b/src/danog/MadelineProto/RPCErrorException.php index 1c66ac30..d7f27a12 100644 --- a/src/danog/MadelineProto/RPCErrorException.php +++ b/src/danog/MadelineProto/RPCErrorException.php @@ -87,7 +87,7 @@ class RPCErrorException extends \Exception || !isset(self::$descriptions[$error]) || $code === 500 ) { - $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$this->caller.'&code='.$this->code.'&error='.$this->rpc), true); + $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error), true); if (isset($res['ok']) && $res['ok']) { $description = $res['result']; diff --git a/src/danog/MadelineProto/Serialization.php b/src/danog/MadelineProto/Serialization.php index 2346814b..54fba515 100644 --- a/src/danog/MadelineProto/Serialization.php +++ b/src/danog/MadelineProto/Serialization.php @@ -24,11 +24,6 @@ namespace danog\MadelineProto; */ class Serialization { - public static function serialize_all($exception) - { - echo $exception.PHP_EOL; - } - public static function realpaths($file) { $file = Absolute::absolute($file); diff --git a/src/danog/MadelineProto/TL_telegram_v102.tl b/src/danog/MadelineProto/TL_telegram_v102.tl index 8d69f8e5..97fb9d97 100644 --- a/src/danog/MadelineProto/TL_telegram_v102.tl +++ b/src/danog/MadelineProto/TL_telegram_v102.tl @@ -1050,17 +1050,20 @@ invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; +auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; +auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; + auth.logOut#5717da40 = Bool; + auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; + auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; -auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; diff --git a/src/danog/MadelineProto/Tools.php b/src/danog/MadelineProto/Tools.php index 74e85123..2b0870b8 100644 --- a/src/danog/MadelineProto/Tools.php +++ b/src/danog/MadelineProto/Tools.php @@ -191,6 +191,7 @@ trait Tools try { Loop::run(function () use (&$resolved, &$value, &$exception, $promise) { $promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) { + Loop::stop(); $resolved = true; $exception = $e; @@ -329,7 +330,7 @@ trait Tools return; } $b = self::call($b()); - $b->onResolve(static function ($e, $res) use ($deferred) { + $b->onResolve(function ($e, $res) use ($deferred) { if ($e) { if (isset($this)) { $this->rethrow($e, $file); diff --git a/src/danog/MadelineProto/Wrappers/Loop.php b/src/danog/MadelineProto/Wrappers/Loop.php index ce71e383..7f83c44c 100644 --- a/src/danog/MadelineProto/Wrappers/Loop.php +++ b/src/danog/MadelineProto/Wrappers/Loop.php @@ -68,6 +68,9 @@ trait Loop } catch (\danog\MadelineProto\Exception $e) { $needs_restart = true; } + if (isset($_REQUEST['MadelineSelfRestart'])) { + $this->logger->logger("Self-restarted, restart token ".$_REQUEST['MadelineSelfRestart']); + } $this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart'); $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); @@ -105,9 +108,31 @@ trait Loop if ($needs_restart) { $logger = &$this->logger; Shutdown::addCallback(static function () use (&$logger) { - $a = fsockopen((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']); - fwrite($a, $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n"); - $logger->logger('Self-restarted'); + $address = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + + $uri = $_SERVER['REQUEST_URI']; + + $params = $_GET; + $params['MadelineSelfRestart'] = $this->random_int(); + + list($url, $query) = explode($uri, '?', 2); + $query = http_build_query($params); + $uri = implode('?', [$url, $query]); + + $payload = $_SERVER['REQUEST_METHOD'].' '.$uri.' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n"; + + $logger->logger("Connecting to $address:$port"); + $a = fsockopen($address, $port); + + $logger->logger("Sending self-restart payload"); + $logger->logger($payload); + fwrite($a, $payload); + + $logger->logger("Payload sent with token {$params['MadelineSelfRestart']}, waiting for self-restart"); + + sleep(10); + fclose($a); }, 'restarter'); } @@ -164,5 +189,8 @@ trait Loop ob_end_flush(); flush(); $GLOBALS['exited'] = true; + if (function_exists('fastcgi_finish_request')) { + \fastcgi_finish_request(); + } } } diff --git a/tests/testing.php b/tests/testing.php index 7469075c..dce3c12b 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -37,7 +37,7 @@ if (file_exists('.env')) { $dotenv->load(); } if (getenv('TEST_SECRET_CHAT') == '') { - echo('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL); + echo ('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL); die(1); } echo 'Loading settings...'.PHP_EOL; From 19ed075f70ec0531feb5d73f3c02ccbf7a7361c3 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 3 Jul 2019 12:34:19 +0200 Subject: [PATCH 09/11] Fix build --- tests/makephar.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/makephar.sh b/tests/makephar.sh index c3326e32..0fc91c17 100755 --- a/tests/makephar.sh +++ b/tests/makephar.sh @@ -52,7 +52,7 @@ cd .. sudo apt-get update -q sudo apt-get install php7.3-cli php7.3-json php7.3-mbstring php7.3-curl php7.3-xml php7.3-json -y - composer global require spatie/7to5 dev-master#5c65f68 + composer global require spatie/7to5 dev-master#3c8363c [ -f $HOME/.composer/vendor/bin/php7to5 ] && php7to5=$HOME/.composer/vendor/bin/php7to5 [ -f $HOME/.config/composer/vendor/bin/php7to5 ] && php7to5=$HOME/.config/composer/vendor/bin/php7to5 From d5c58af01353c88918546f719547f8eeeab0f289 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 3 Jul 2019 13:11:26 +0200 Subject: [PATCH 10/11] Fix php 5 build --- tests/makephar.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/makephar.sh b/tests/makephar.sh index 0fc91c17..3ee7a360 100755 --- a/tests/makephar.sh +++ b/tests/makephar.sh @@ -52,7 +52,7 @@ cd .. sudo apt-get update -q sudo apt-get install php7.3-cli php7.3-json php7.3-mbstring php7.3-curl php7.3-xml php7.3-json -y - composer global require spatie/7to5 dev-master#3c8363c + composer global require spatie/7to5 dev-master#d4be6d0 [ -f $HOME/.composer/vendor/bin/php7to5 ] && php7to5=$HOME/.composer/vendor/bin/php7to5 [ -f $HOME/.config/composer/vendor/bin/php7to5 ] && php7to5=$HOME/.config/composer/vendor/bin/php7to5 From 3dc3d6e5c821936aaa66c6f3c542ec1c93e93331 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 6 Jul 2019 17:45:03 +0200 Subject: [PATCH 11/11] Some bugfixes --- bot.php | 1 - .../MadelineProto/MTProtoTools/Files.php | 71 ++++++++++--------- src/danog/MadelineProto/Tools.php | 35 ++++++--- 3 files changed, 63 insertions(+), 44 deletions(-) diff --git a/bot.php b/bot.php index 33cbc70b..d7c5f869 100755 --- a/bot.php +++ b/bot.php @@ -39,7 +39,6 @@ class EventHandler extends \danog\MadelineProto\EventHandler if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') { return; } - $res = json_encode($update, JSON_PRETTY_PRINT); try { diff --git a/src/danog/MadelineProto/MTProtoTools/Files.php b/src/danog/MadelineProto/MTProtoTools/Files.php index 325a6d41..8bf3dad7 100644 --- a/src/danog/MadelineProto/MTProtoTools/Files.php +++ b/src/danog/MadelineProto/MTProtoTools/Files.php @@ -23,6 +23,7 @@ use danog\MadelineProto\Async\AsyncParameters; use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; use danog\MadelineProto\RPCErrorException; +use danog\MadelineProto\Tools; use function Amp\Promise\all; /** @@ -331,7 +332,7 @@ trait Files $res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg'); } if (!isset($res['name'])) { - $res['name'] = $message_media['file']['access_hash']; + $res['name'] = Tools::unpack_signed_long_string($message_media['file']['access_hash']); } return $res; @@ -401,7 +402,7 @@ trait Files $res['thumb_size'] = $message_media['type']; if ($message_media['location']['_'] === 'fileLocationUnavailable') { - $res['name'] = $message_media['volume_id'].'_'.$message_media['local_id']; + $res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id']; $res['mime'] = $this->get_mime_from_buffer($res['data']); $res['ext'] = $this->get_extension_from_mime($res['mime']); } else { @@ -423,7 +424,7 @@ trait Files case 'fileLocationUnavailable': throw new \danog\MadelineProto\Exception('File location unavailable'); case 'fileLocation': - $res['name'] = $message_media['volume_id'].'_'.$message_media['local_id']; + $res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id']; $res['InputFileLocation'] = [ '_' => 'inputFileLocation', 'volume_id' => $message_media['volume_id'], @@ -440,7 +441,7 @@ trait Files return $res; case 'fileLocationToBeDeprecated': - $res['name'] = $message_media['volume_id'].'_'.$message_media['local_id']; + $res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id']; $res['ext'] = '.jpg'; $res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg'); $res['InputFileLocation'] = [ @@ -495,7 +496,7 @@ trait Files $res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], $this->get_extension_from_mime($message_media['document']['mime_type'])); } if (!isset($res['name'])) { - $res['name'] = $message_media['document']['access_hash']; + $res['name'] = Tools::unpack_signed_long_string($message_media['document']['access_hash']); } if (isset($message_media['document']['size'])) { $res['size'] = $message_media['document']['size']; @@ -537,7 +538,7 @@ trait Files $size = fstat($stream)['size']; $this->logger->logger('Waiting for lock of file to download...'); do { - $res = flock($stream, LOCK_EX|LOCK_NB); + $res = flock($stream, LOCK_EX | LOCK_NB); if (!$res) { yield $this->sleep(0.1); } @@ -606,35 +607,35 @@ trait Files } try { - $res = $cdn ? - yield $this->method_call_async_read( - 'upload.getCdnFile', - [ - 'file_token' => $message_media['file_token'], - 'offset' => $offset, - 'limit' => $part_size - ], - [ - 'heavy' => true, - 'file' => true, - 'FloodWaitLimit' => 0, - 'datacenter' => $datacenter - ] - ) : - yield $this->method_call_async_read( - 'upload.getFile', - [ - 'location' => $message_media['InputFileLocation'], - 'offset' => $offset, - 'limit' => $part_size - ], - [ - 'heavy' => true, - 'file' => true, - 'FloodWaitLimit' => 0, - 'datacenter' => &$datacenter - ] - ); + $res = $cdn ? + yield $this->method_call_async_read( + 'upload.getCdnFile', + [ + 'file_token' => $message_media['file_token'], + 'offset' => $offset, + 'limit' => $part_size, + ], + [ + 'heavy' => true, + 'file' => true, + 'FloodWaitLimit' => 0, + 'datacenter' => $datacenter, + ] + ) : + yield $this->method_call_async_read( + 'upload.getFile', + [ + 'location' => $message_media['InputFileLocation'], + 'offset' => $offset, + 'limit' => $part_size, + ], + [ + 'heavy' => true, + 'file' => true, + 'FloodWaitLimit' => 0, + 'datacenter' => &$datacenter, + ] + ); } catch (\danog\MadelineProto\RPCErrorException $e) { if (strpos($e->rpc, 'FLOOD_WAIT_') === 0) { if (isset($message_media['MessageMedia']) && !$this->authorization['user']['bot'] && $this->settings['download']['report_broken_media']) { diff --git a/src/danog/MadelineProto/Tools.php b/src/danog/MadelineProto/Tools.php index 2b0870b8..ce609db3 100644 --- a/src/danog/MadelineProto/Tools.php +++ b/src/danog/MadelineProto/Tools.php @@ -23,15 +23,16 @@ use Amp\Failure; use Amp\Loop; use Amp\Promise; use Amp\Success; +use function Amp\ByteStream\getOutputBufferStream; +use function Amp\ByteStream\getStdin; +use function Amp\ByteStream\getStdout; use function Amp\Promise\all; use function Amp\Promise\any; use function Amp\Promise\first; use function Amp\Promise\some; use function Amp\Promise\timeout; use function Amp\Promise\wait; -use function Amp\ByteStream\getStdin; -use function Amp\ByteStream\getStdout; -use function Amp\ByteStream\getOutputBufferStream; +use phpseclib\Math\BigInteger; /** * Some tools. @@ -119,6 +120,16 @@ trait Tools return unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1]; } + public static function unpack_signed_long_string($value) + { + if (strlen($value) !== 8) { + throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); + } + + $big = new BigInteger($value, -256); + return (string) $big; + } + public static function pack_signed_int($value) { if ($value > 2147483647) { @@ -306,12 +317,21 @@ trait Tools if ($file) { $file = " started @ $file"; } - if ($logger) $logger->logger("Got the following exception within a forked strand$file, trying to rethrow"); + if ($logger) { + $logger->logger("Got the following exception within a forked strand$file, trying to rethrow"); + } + if ($e->getMessage() === "Cannot get return value of a generator that hasn't returned") { $logger->logger("Well you know, this might actually not be the actual exception, scroll up in the logs to see the actual exception"); - if (!$zis || !$zis->destructing) Promise\rethrow(new Failure($e)); + if (!$zis || !$zis->destructing) { + Promise\rethrow(new Failure($e)); + } + } else { - if ($logger) $logger->logger($e); + if ($logger) { + $logger->logger($e); + } + Promise\rethrow(new Failure($e)); } } @@ -370,8 +390,7 @@ trait Tools return array_shift($lines); } - public static function echo($string) - { + public static function echo ($string) { return getOutputBufferStream()->write($string); } public static function is_array_or_alike($var)