From f331931365c690842d75f086ace88b577a163161 Mon Sep 17 00:00:00 2001 From: danogentili Date: Sun, 9 Oct 2016 17:42:39 +0200 Subject: [PATCH] Refactored AuthorizationHandler and written DataCenter class --- README.md | 1 + src/danog/MadelineProto/API.php | 2 +- src/danog/MadelineProto/DataCenter.php | 71 +++++++++++++++ src/danog/MadelineProto/MTProto.php | 33 +++++-- .../MTProtoTools/AuthKeyHandler.php | 88 ++++++++++--------- .../MTProtoTools/CallHandler.php | 10 +-- .../MTProtoTools/MessageHandler.php | 6 +- 7 files changed, 152 insertions(+), 59 deletions(-) create mode 100644 src/danog/MadelineProto/DataCenter.php diff --git a/README.md b/README.md index 7a6dc9023..0e57efd95 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ src/danog/MadelineProto/ TLMethod - Represents a TL method API - Wrapper class that istantiates the MTProto class, sets the error handler, and provides a wrapper for calling mtproto methods directly as class submethods Connection - Handles tcp/udp/http connections and wrapping payloads generated by MTProtoTools/MessageHandler into the right message according to the protocol + DataCenter - Handles mtproto datacenters DebugTools - Various debugging tools Exception - Handles exceptions in the main namespace MTProto - Extends MTProtoTools, handles initial connection, generation of authorization keys, istantiation of classes diff --git a/src/danog/MadelineProto/API.php b/src/danog/MadelineProto/API.php index 9219b7122..d128164ae 100644 --- a/src/danog/MadelineProto/API.php +++ b/src/danog/MadelineProto/API.php @@ -12,7 +12,7 @@ If not, see . namespace danog\MadelineProto; -class API +class API extends Tools { public $session; diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php new file mode 100644 index 000000000..a589fbcee --- /dev/null +++ b/src/danog/MadelineProto/DataCenter.php @@ -0,0 +1,71 @@ +. +*/ + +namespace danog\MadelineProto; + +/** + * Manages all of the mtproto stuff. + */ +class DataCenter extends Tools +{ + public function __construct($dclist, $settings) { + $this->dclist = $dclist; + $this->settings = $settings; + if (isset($this->settings["all"])) { + foreach ($this->range(1, 6) as $n) { + $this->settings[$n] = $this->settings["all"]; + } + unset($this->settings["all"]); + } + foreach ($this->range(1, 6) as $n) { + if (!isset($this->settings[$n])) { + $this->settings[$n] = [ + 'protocol' => 'tcp_full', + 'port' => '443', + 'test_mode' => true + ]; + } + } + $this->connect(2); + } + public function connnect($dc_number, $settings = []) { + if ($settings == []) { + $settings = $this->settings[$dc_number]; + } + $address = $settings["test_mode"] ? $this->dclist["test"][$dc_number] : $this->dclist["main"][$dc_number]; + if ($settings["protocol"] == "https") { + $subdomain = $this->dclist["ssl_subdomains"][$dc_number] . ($settings["upload"] ? '-1' : ''); + $path = $settings["test_mode"] ? 'apiw_test1' : 'apiw1'; + $address = 'https://' . $subdomain . '.web.telegram.org/' . $path; + } + $this->sockets[$dc_number] = new Connection($address, $settings["port"], $settings["protocol"]); + $this->curdc = $dc_number; + } + public function send_message($message, $dc_number = -1) { + if ($dc_number == -1) { + $dc_number = $this->curdc; + } + return $this->sockets[$dc_number]->send_message($message); + } + public function read_message($dc_number = -1) { + if ($dc_number == -1) { + $dc_number = $this->curdc; + } + return $this->sockets[$dc_number]->read_message(); + } + + public function __destroy() { + foreach ($this->sockets as $n => $socket) { + unset($this->sockets[$n]); + } + } +} \ No newline at end of file diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index db39481c4..9703e1200 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -38,12 +38,30 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB -----END RSA PUBLIC KEY-----', ], 'connection' => [ - 'dc_list' => [ - 2 => [ - 'ip_address' => '149.154.167.50', - 'port' => '443', - 'protocol' => 'tcp_full', - ], + 'ssl_subdomains' => [ + 1 => 'pluto', + 2 => 'venus', + 3 => 'aurora', + 4 => 'vesta', + 5 => 'flora' + ], + 'test' => [ + 1 => '149.154.175.10', + 2 => '149.154.167.40', + 3 => '149.154.175.117' + ], + 'main' => [ + 1 => '149.154.175.50', + 2 => '149.154.167.51', + 3 => '149.154.175.100', + 4 => '149.154.167.91', + 5 => '149.154.171.5' + ] + ], + 'connection_settings' => [ + 'all' => [ + 'protocol' => 'tcp_full', + 'test_mode' => true ], ], 'app_info' => [ @@ -85,7 +103,8 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $this->settings = $settings; // Connect to servers - $this->sock = new Connection($this->settings['connection']['ip_address'], $this->settings['connection']['port'], $this->settings['connection']['protocol']); + $this->connection = new DataCenter($this->settings['connection'], $this->settings['connection_settings']); + var_dump($this->connection); // Load rsa key $this->key = new RSA($settings['authorization']['rsa_key']); diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index b9848513a..ad803db73 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -22,7 +22,7 @@ class AuthKeyHandler extends AckHandler { public function create_auth_key($expires_in = -1) { - foreach (\danog\MadelineProto\Tools::range(0, $this->settings['max_tries']['authorization']) as $retry_id_total) { + foreach ($this->range(0, $this->settings['max_tries']['authorization']) as $retry_id_total) { $this->log->log('Handshake: Requesting pq'); /** @@ -51,7 +51,7 @@ class AuthKeyHandler extends AckHandler /* * *********************************************************************** - * Compare the equal of nonce client and nonce server + * Check if the client's nonce and the server's nonce are the same */ if ($ResPQ['nonce'] !== $nonce) { throw new Exception('Handshake: wrong nonce'); @@ -94,7 +94,7 @@ class AuthKeyHandler extends AckHandler throw new Exception("Handshake: couldn't compute p and q."); } - $this->log->log(sprintf('Factorization %s = %s * %s', $pq, $p, $q)); + $this->log->log('Handshake: Factorization '.$pq.' = '.$p.' * '.$q); /* * *********************************************************************** @@ -138,7 +138,7 @@ class AuthKeyHandler extends AckHandler $to_encrypt = $sha_digest.$data.$random_bytes; $encrypted_data = $this->key->encrypt($to_encrypt); - $this->log->log('Starting Diffie Hellman key exchange'); + $this->log->log('Handshake: Starting Diffie Hellman key exchange'); /* * *********************************************************************** * Starting Diffie Hellman key exchange, Server authentication @@ -172,7 +172,7 @@ class AuthKeyHandler extends AckHandler /* * *********************************************************************** - * Compare the equal of nonce client and nonce server + * Check if the client's nonce and the server's nonce are the same */ if ($nonce != $server_dh_params['nonce']) { throw new Exception('Handshake: wrong nonce.'); @@ -180,7 +180,7 @@ class AuthKeyHandler extends AckHandler /* * *********************************************************************** - * Compare the equal of server_nonce and new server_nonce + * Check if server_nonce and new server_nonce are the same */ if ($server_nonce != $server_dh_params['server_nonce']) { throw new Exception('Handshake: wrong server nonce.'); @@ -224,13 +224,13 @@ class AuthKeyHandler extends AckHandler * int $server_time * ] */ - $server_DH_inner_data = $this->tl->deserialize(\danog\MadelineProto\Tools::fopen_and_write('php://memory', 'rw+b', $answer)); + $server_DH_inner_data = $this->tl->deserialize($this->fopen_and_write('php://memory', 'rw+b', $answer)); /* * *********************************************************************** * Do some checks */ - $server_DH_inner_data_length = $this->tl->get_length(\danog\MadelineProto\Tools::fopen_and_write('php://memory', 'rw+b', $answer)); + $server_DH_inner_data_length = $this->tl->get_length($this->fopen_and_write('php://memory', 'rw+b', $answer)); if (sha1(substr($answer, 0, $server_DH_inner_data_length), true) != $answer_hash) { throw new Exception('Handshake: answer_hash mismatch.'); } @@ -252,9 +252,9 @@ class AuthKeyHandler extends AckHandler * Time delta */ $server_time = $server_DH_inner_data['server_time']; - $this->timedelta = ($server_time - time()); + $this->timedelta = $server_time - time(); - $this->log->log(sprintf('Server-client time delta = %.1f s', $this->timedelta)); + $this->log->log(sprintf('Handshake: Server-client time delta = %.1f s', $this->timedelta)); /* @@ -310,7 +310,7 @@ class AuthKeyHandler extends AckHandler throw new Exception('Handshake: g_a is invalid (1 < g_a < dh_prime - 1 is false).'); } - foreach (\danog\MadelineProto\Tools::range(0, $this->settings['max_tries']['authorization']) as $retry_id) { + foreach ($this->range(0, $this->settings['max_tries']['authorization']) as $retry_id) { $b = new \phpseclib\Math\BigInteger(\phpseclib\Crypt\Random::string(256), 256); $g_b = $g->powMod($b, $dh_prime); @@ -352,7 +352,7 @@ class AuthKeyHandler extends AckHandler * encrypt client_DH_inner_data */ $data_with_sha = sha1($data, true).$data; - $data_with_sha_padded = $data_with_sha.\phpseclib\Crypt\Random::string(\danog\MadelineProto\Tools::posmod(-strlen($data_with_sha), 16)); + $data_with_sha_padded = $data_with_sha.\phpseclib\Crypt\Random::string($this->posmod(-strlen($data_with_sha), 16)); $encrypted_data = $this->ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); /* @@ -395,7 +395,7 @@ class AuthKeyHandler extends AckHandler /* * *********************************************************************** - * Compare the equal of nonce client and nonce server + * Check if the client's nonce and the server's nonce are the same */ if ($Set_client_DH_params_answer['nonce'] != $nonce) { throw new Exception('Handshake: wrong nonce.'); @@ -403,7 +403,7 @@ class AuthKeyHandler extends AckHandler /* * *********************************************************************** - * Compare the equal of server_nonce and new server_nonce + * Check if server_nonce and new server_nonce are the same */ if ($Set_client_DH_params_answer['server_nonce'] != $server_nonce) { throw new Exception('Handshake: wrong server nonce'); @@ -413,41 +413,43 @@ class AuthKeyHandler extends AckHandler * *********************************************************************** * Check Set_client_DH_params_answer type */ - if ($Set_client_DH_params_answer['_'] == 'dh_gen_ok') { - if ($Set_client_DH_params_answer['new_nonce_hash1'] != $new_nonce_hash1) { - throw new Exception('Handshake: wrong new_nonce_hash1'); - } + switch ($Set_client_DH_params_answer['_']) { + case 'dh_gen_ok': + if ($Set_client_DH_params_answer['new_nonce_hash1'] != $new_nonce_hash1) { + throw new Exception('Handshake: wrong new_nonce_hash1'); + } - $this->log->log('Diffie Hellman key exchange processed successfully'); + $this->log->log('Diffie Hellman key exchange processed successfully'); - $res_authorization['server_salt'] = $this->struct->unpack('struct->unpack('log->log('Auth key generated'); - $this->timedelta = 0; + $this->log->log('Auth key generated'); + $this->timedelta = 0; + return $res_authorization; + case 'dh_gen_retry': + if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) { + throw new Exception('Handshake: wrong new_nonce_hash_2'); + } - return $res_authorization; - } elseif ($Set_client_DH_params_answer['_'] == 'dh_gen_retry') { - if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) { - throw new Exception('Handshake: wrong new_nonce_hash_2'); - } + //repeat foreach + $this->log->log('Handshake: Retrying Auth'); + break; + case 'dh_gen_fail': + if ($Set_client_DH_params_answer['new_nonce_hash3'] != $new_nonce_hash3) { + throw new Exception('Handshake: wrong new_nonce_hash_3'); + } - //repeat foreach - $this->log->log('Retrying Auth'); - } elseif ($Set_client_DH_params_answer['_'] == 'dh_gen_fail') { - if ($Set_client_DH_params_answer['new_nonce_hash3'] != $new_nonce_hash3) { - throw new Exception('Handshake: wrong new_nonce_hash_3'); - } - - $this->log->log('Auth Failed'); - break; - } else { - throw new Exception('Response Error'); + $this->log->log('Handshake: Auth Failed'); + break 2; + default: + throw new Exception('Response Error'); + break; } } } diff --git a/src/danog/MadelineProto/MTProtoTools/CallHandler.php b/src/danog/MadelineProto/MTProtoTools/CallHandler.php index 9708a3882..43e04ea5e 100644 --- a/src/danog/MadelineProto/MTProtoTools/CallHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/CallHandler.php @@ -52,8 +52,8 @@ class CallHandler extends AuthKeyHandler $server_answer = $this->wait_for_response($int_message_id); } catch (Exception $e) { $this->log->log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().$e->getTraceAsString().'. Recreating connection and retrying to call method...'); - unset($this->sock); - $this->sock = new \danog\MadelineProto\Connection($this->settings['connection']['ip_address'], $this->settings['connection']['port'], $this->settings['connection']['protocol']); + unset($this->connection); + $this->connection = new DataCenter($this->settings['connection'], $this->settings['connection_settings']); continue; } if ($server_answer == null) { @@ -73,9 +73,9 @@ class CallHandler extends AuthKeyHandler $this->outgoing_messages[$int_message_id]['content'] = ['object' => $object, 'args' => $args]; // $server_answer = $this->wait_for_response($int_message_id); } catch (Exception $e) { - $this->log->log('An error occurred while calling object '.$object.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().'. Recreating connection and retrying to call object...'); - unset($this->sock); - $this->sock = new \danog\MadelineProto\Connection($this->settings['connection']['ip_address'], $this->settings['connection']['port'], $this->settings['connection']['protocol']); + $this->log->log('An error occurred while calling object '.$object.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().'. Recreating connection and retrying to call object...'); + unset($this->connection); + $this->connection = new DataCenter($this->settings['connection'], $this->settings['connection_settings']); continue; } diff --git a/src/danog/MadelineProto/MTProtoTools/MessageHandler.php b/src/danog/MadelineProto/MTProtoTools/MessageHandler.php index f8c5d4346..47990dcce 100644 --- a/src/danog/MadelineProto/MTProtoTools/MessageHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/MessageHandler.php @@ -38,17 +38,17 @@ class MessageHandler extends Crypt $message = $this->settings['authorization']['temp_auth_key']['id'].$message_key.$this->ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); $this->outgoing_messages[$int_message_id]['seq_no'] = $seq_no; } - $this->sock->send_message($message); + $this->connection->send_message($message); return $int_message_id; } /** - * Reading socket and receiving message from server. Check the CRC32. + * Reading connectionet and receiving message from server. Check the CRC32. */ public function recv_message() { - $payload = $this->sock->read_message(); + $payload = $this->connection->read_message(); if (fstat($payload)['size'] == 4) { throw new Exception('Server response error: '.abs($this->struct->unpack('