Refactored AuthorizationHandler and written DataCenter class

This commit is contained in:
danogentili 2016-10-09 17:42:39 +02:00
parent 246579d645
commit f331931365
7 changed files with 152 additions and 59 deletions

View File

@ -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

View File

@ -12,7 +12,7 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto;
class API
class API extends Tools
{
public $session;

View File

@ -0,0 +1,71 @@
<?php
/*
Copyright 2016 Daniil Gentili
(https://daniil.it)
This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with the MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
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]);
}
}
}

View File

@ -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']);

View File

@ -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('<q', substr($new_nonce, 0, 8 - 0) ^ substr($server_nonce, 0, 8 - 0))[0];
$res_authorization['auth_key'] = $auth_key_str;
$res_authorization['id'] = substr($auth_key_sha, -8);
$res_authorization['server_salt'] = $this->struct->unpack('<q', substr($new_nonce, 0, 8 - 0) ^ substr($server_nonce, 0, 8 - 0))[0];
$res_authorization['auth_key'] = $auth_key_str;
$res_authorization['id'] = substr($auth_key_sha, -8);
if ($expires_in < 0) { //check if permanent authorization
$res_authorization['expires_in'] = $expires_in;
}
if ($expires_in < 0) { //check if permanent authorization
$res_authorization['expires_in'] = $expires_in;
}
$this->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;
}
}
}

View File

@ -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) {
@ -74,8 +74,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 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']);
unset($this->connection);
$this->connection = new DataCenter($this->settings['connection'], $this->settings['connection_settings']);
continue;
}

View File

@ -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('<i', fread($payload, 4))[0]));
}