1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 07:38:58 +01:00

Fixed bugs, improved exception erro rhandling, blah, blah, blah (#RTFC)

This commit is contained in:
Daniil Gentili 2016-11-24 12:16:06 +00:00
parent 87e625ea9c
commit c168890384
18 changed files with 131 additions and 183 deletions

1
.gitignore vendored
View File

@ -64,3 +64,4 @@ vendor
*save* *save*
*bak *bak
number.php number.php
token.php

View File

@ -12,16 +12,16 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto; namespace danog\MadelineProto;
class API extends Tools class API extends APIFactory
{ {
public $API; public $API;
public $settings; public $settings;
public $namespace = '';
public function __construct($params = []) public function __construct($params = [])
{ {
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']); set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
$this->API = new MTProto($params); $this->API = new MTProto($params);
\danog\MadelineProto\Logger::log('Running APIFactory...'); \danog\MadelineProto\Logger::log('Running APIFactory...');
foreach ($this->API->tl->methods->method_namespace as $namespace => $method) { foreach ($this->API->tl->methods->method_namespace as $namespace => $method) {
$this->{$method} = new APIFactory($method, $this->API); $this->{$method} = new APIFactory($method, $this->API);
@ -35,15 +35,11 @@ class API extends Tools
\danog\MadelineProto\Logger::log('MadelineProto is ready!'); \danog\MadelineProto\Logger::log('MadelineProto is ready!');
restore_error_handler();
} }
public function __destruct() public function __destruct()
{ {
restore_error_handler(); restore_error_handler();
} }
public function __call($name, $arguments)
{
return $this->API->method_call($name, $arguments[0]);
}
} }

View File

@ -25,6 +25,8 @@ class APIFactory
public function __call($name, $arguments) public function __call($name, $arguments)
{ {
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
return $this->API->method_call($this->namespace.$name, $arguments[0]); return $this->API->method_call($this->namespace.$name, $arguments[0]);
restore_error_handler();
} }
} }

View File

@ -20,6 +20,9 @@ class Connection extends Tools
public $sock = null; public $sock = null;
public $protocol = null; public $protocol = null;
public $ip = null;
public $port = null;
public $timeout = null;
public $time_delta = 0; public $time_delta = 0;
public $temp_auth_key; public $temp_auth_key;
@ -27,7 +30,7 @@ class Connection extends Tools
public $session_id; public $session_id;
public $seq_no = 0; public $seq_no = 0;
public function __construct($ip, $port, $protocol = 'tcp_full') public function __construct($ip, $port, $protocol, $timeout)
{ {
// Can use: // Can use:
/* /*
@ -39,12 +42,13 @@ class Connection extends Tools
- udp - udp
*/ */
$this->protocol = $protocol; $this->protocol = $protocol;
$this->timeout = $timeout;
$this->ip = $ip; $this->ip = $ip;
$this->port = $port; $this->port = $port;
switch ($this->protocol) { switch ($this->protocol) {
case 'tcp_abridged': case 'tcp_abridged':
$this->sock = fsockopen('tcp://'.$ip.':'.$port); $this->sock = fsockopen('tcp://'.$ip.':'.$port);
stream_set_timeout($this->sock, 5); stream_set_timeout($this->sock, $timeout);
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) { if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
throw new Exception("Connection: couldn't connect to socket."); throw new Exception("Connection: couldn't connect to socket.");
} }
@ -52,7 +56,7 @@ class Connection extends Tools
break; break;
case 'tcp_intermediate': case 'tcp_intermediate':
$this->sock = fsockopen('tcp://'.$ip.':'.$port); $this->sock = fsockopen('tcp://'.$ip.':'.$port);
stream_set_timeout($this->sock, 5); stream_set_timeout($this->sock, $timeout);
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) { if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
throw new Exception("Connection: couldn't connect to socket."); throw new Exception("Connection: couldn't connect to socket.");
} }
@ -60,7 +64,7 @@ class Connection extends Tools
break; break;
case 'tcp_full': case 'tcp_full':
$this->sock = fsockopen('tcp://'.$ip.':'.$port); $this->sock = fsockopen('tcp://'.$ip.':'.$port);
stream_set_timeout($this->sock, 5); stream_set_timeout($this->sock, $timeout);
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) { if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
throw new Exception("Connection: couldn't connect to socket."); throw new Exception("Connection: couldn't connect to socket.");
} }
@ -98,7 +102,7 @@ class Connection extends Tools
public function close_and_reopen() public function close_and_reopen()
{ {
$this->__destruct(); $this->__destruct();
$this->__construct($this->ip, $this->port, $this->protocol); $this->__construct($this->ip, $this->port, $this->protocol, $this->timeout);
} }
/** /**

View File

@ -19,6 +19,7 @@ class DataCenter extends Tools
{ {
public $referenced_variables = ['time_delta', 'temp_auth_key', 'auth_key', 'session_id', 'seq_no']; public $referenced_variables = ['time_delta', 'temp_auth_key', 'auth_key', 'session_id', 'seq_no'];
public $sockets; public $sockets;
public $curdc = 0;
public function __construct($dclist, $settings) public function __construct($dclist, $settings)
{ {
@ -36,6 +37,7 @@ class DataCenter extends Tools
'protocol' => 'tcp_full', 'protocol' => 'tcp_full',
'port' => '443', 'port' => '443',
'test_mode' => true, 'test_mode' => true,
'timeout' => 10,
]; ];
} }
} }
@ -55,10 +57,9 @@ class DataCenter extends Tools
public function dc_connect($dc_number, $settings = []) public function dc_connect($dc_number, $settings = [])
{ {
if (isset($this->sockets[$dc_number])) { if (isset($this->sockets[$dc_number])) {
return false;
$this->set_curdc($dc_number); $this->set_curdc($dc_number);
return false;
} }
$this->set_curdc($dc_number);
\danog\MadelineProto\Logger::log('Connecting to DC '.$dc_number.'...'); \danog\MadelineProto\Logger::log('Connecting to DC '.$dc_number.'...');
@ -71,8 +72,8 @@ class DataCenter extends Tools
$path = $settings['test_mode'] ? 'apiw_test1' : 'apiw1'; $path = $settings['test_mode'] ? 'apiw_test1' : 'apiw1';
$address = 'https://'.$subdomain.'.web.telegram.org/'.$path; $address = 'https://'.$subdomain.'.web.telegram.org/'.$path;
} }
$this->sockets[$dc_number] = new Connection($address, $settings['port'], $settings['protocol']); $this->sockets[$dc_number] = new Connection($address, $settings['port'], $settings['protocol'], $settings['timeout']);
$this->set_curdc($dc_number);
return true; return true;
} }
@ -84,11 +85,11 @@ class DataCenter extends Tools
} }
} }
public function unset_curdc($dc_number) public function unset_curdc()
{ {
unset($this->curdc); $this->curdc = 0;
foreach ($this->referenced_variables as $key) { foreach ($this->referenced_variables as $key) {
unset($this->sockets[$dc_number]->{$key}); unset($this->{$key});
} }
} }

View File

@ -22,7 +22,7 @@ class DebugTools
public static function hex_dump(...$what) public static function hex_dump(...$what)
{ {
foreach ($what as $w) { foreach ($what as $w) {
var_dump(bin2hex($w)); \danog\MadelienProto\Logger::log(bin2hex($w));
} }
} }

View File

@ -14,16 +14,6 @@ namespace danog\MadelineProto;
class Exception extends \Exception class Exception extends \Exception
{ {
public function __construct($message, $code = 0, Exception $previous = null)
{
// some code
if (isset($GLOBALS['doingphptests']) && $GLOBALS['doingphptests']) {
var_dump($message);
}
// make sure everything is assigned properly
parent::__construct($message, $code, $previous);
}
/** /**
* ExceptionErrorHandler. * ExceptionErrorHandler.
* *
@ -35,6 +25,9 @@ class Exception extends \Exception
if (error_reporting() === 0) { if (error_reporting() === 0) {
return true; // return true to continue through the others error handlers return true; // return true to continue through the others error handlers
} }
throw new self($errstr.' on line '.$errline.' of file '.$errfile, $errno); $e = new self($errstr, $errno);
$e->file = $errfile;
$e->line = $errline;
throw $e;
} }
} }

View File

@ -24,7 +24,7 @@ class MTProto extends MTProtoTools
// Set default settings // Set default settings
$default_settings = [ $default_settings = [
'authorization' => [ 'authorization' => [
'default_temp_auth_key_expires_in' => 86400, 'default_temp_auth_key_expires_in' => 31557600,
'rsa_key' => '-----BEGIN RSA PUBLIC KEY----- 'rsa_key' => '-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
@ -60,8 +60,9 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
'protocol' => 'tcp_full', 'protocol' => 'tcp_full',
'test_mode' => false, 'test_mode' => false,
'port' => '443', 'port' => '443',
'timeout' => 10
], ],
'default_dc' => 4, 'default_dc' => 2,
], ],
'app_info' => [ 'app_info' => [
'api_id' => 25628, 'api_id' => 25628,
@ -139,10 +140,15 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
public function switch_dc($new_dc, $allow_nearest_dc_switch = false) public function switch_dc($new_dc, $allow_nearest_dc_switch = false)
{ {
\danog\MadelineProto\Logger::log('Switching to DC '.$new_dc.'...'); \danog\MadelineProto\Logger::log('Switching to DC '.$new_dc.'...');
/* if ($this->datacenter->curdc !== 0) {
try {
$exported_authorization = $this->method_call('auth.exportAuthorization', ['dc_id' => $new_dc]);
} catch (\danog\MadelineProto\RPCErrorException $e) { ; }
}*/
if ($this->datacenter->dc_connect($new_dc)) { if ($this->datacenter->dc_connect($new_dc)) {
$this->init_authorization(); $this->init_authorization();
$this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in']);
$this->write_client_info($allow_nearest_dc_switch); $this->write_client_info($allow_nearest_dc_switch);
// if (isset($exported_authorization)) $this->method_call('auth.importAuthorization', $exported_authorization);
} }
} }
@ -159,6 +165,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
} }
\danog\MadelineProto\Logger::log('Generating temporary authorization key...'); \danog\MadelineProto\Logger::log('Generating temporary authorization key...');
$this->datacenter->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in']); $this->datacenter->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in']);
$this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in']);
} }
} }

View File

@ -21,7 +21,7 @@ class AckHandler extends \danog\MadelineProto\PrimeModule
{ {
// The server acknowledges that it received my message // The server acknowledges that it received my message
if (!isset($this->outgoing_messages[$message_id])) { if (!isset($this->outgoing_messages[$message_id])) {
throw new Exception("Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?'); throw new \danog\MadelineProto\Exception("Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?');
} }
$this->outgoing_messages[$message_id]['ack'] = true; $this->outgoing_messages[$message_id]['ack'] = true;
} }
@ -33,7 +33,7 @@ class AckHandler extends \danog\MadelineProto\PrimeModule
} }
// I let the server know that I received its message // I let the server know that I received its message
if (!isset($this->incoming_messages[$message_id])) { if (!isset($this->incoming_messages[$message_id])) {
throw new Exception("Couldn't find message id ".$message_id.' in the array of incoming message ids. Maybe try to increase its size?'); throw new \danog\MadelineProto\Exception("Couldn't find message id ".$message_id.' in the array of incoming message ids. Maybe try to increase its size?');
} }
$this->object_call('msgs_ack', ['msg_ids' => [$message_id]]); $this->object_call('msgs_ack', ['msg_ids' => [$message_id]]);
$this->incoming_messages[$message_id]['ack'] = true; $this->incoming_messages[$message_id]['ack'] = true;

View File

@ -55,7 +55,7 @@ class AuthKeyHandler extends AckHandler
* Check if the client's nonce and the server's nonce are the same * Check if the client's nonce and the server's nonce are the same
*/ */
if ($ResPQ['nonce'] !== $nonce) { if ($ResPQ['nonce'] !== $nonce) {
throw new Exception('wrong nonce'); throw new \danog\MadelineProto\Exception('wrong nonce');
} }
/* /*
@ -72,7 +72,7 @@ class AuthKeyHandler extends AckHandler
} }
if (!isset($public_key_fingerprint)) { if (!isset($public_key_fingerprint)) {
throw new Exception("Couldn't find our key in the server_public_key_fingerprints vector."); throw new \danog\MadelineProto\Exception("Couldn't find our key in the server_public_key_fingerprints vector.");
} }
$pq_bytes = $ResPQ['pq']; $pq_bytes = $ResPQ['pq'];
@ -92,7 +92,7 @@ class AuthKeyHandler extends AckHandler
} }
if (!($pq->equals($p->multiply($q)) && $p->compare($q) < 0)) { if (!($pq->equals($p->multiply($q)) && $p->compare($q) < 0)) {
throw new Exception("couldn't compute p and q."); throw new \danog\MadelineProto\Exception("couldn't compute p and q.");
} }
\danog\MadelineProto\Logger::log('Factorization '.$pq.' = '.$p.' * '.$q); \danog\MadelineProto\Logger::log('Factorization '.$pq.' = '.$p.' * '.$q);
@ -105,38 +105,25 @@ class AuthKeyHandler extends AckHandler
$q_bytes = \danog\PHP\Struct::pack('>I', (string) $q); $q_bytes = \danog\PHP\Struct::pack('>I', (string) $q);
$new_nonce = \phpseclib\Crypt\Random::string(32); $new_nonce = \phpseclib\Crypt\Random::string(32);
if ($expires_in < 0) {
$data = $this->tl->serialize_obj('p_q_inner_data', $data_unserialized = [
[ 'pq' => $pq_bytes,
'pq' => $pq_bytes, 'p' => $p_bytes,
'p' => $p_bytes, 'q' => $q_bytes,
'q' => $q_bytes, 'nonce' => $nonce,
'nonce' => $nonce, 'server_nonce' => $server_nonce,
'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce,
'new_nonce' => $new_nonce, 'expires_in' => $expires_in
] ];
); $p_q_inner_data = $this->tl->serialize_obj('p_q_inner_data'.(($expires_in < 0) ? '' : '_temp'), $data_unserialized);
} else {
$data = $this->tl->serialize_obj('p_q_inner_data_temp',
[
'pq' => $pq_bytes,
'p' => $p_bytes,
'q' => $q_bytes,
'nonce' => $nonce,
'server_nonce' => $server_nonce,
'new_nonce' => $new_nonce,
'expires_in' => $expires_in,
]
);
}
/* /*
* *********************************************************************** * ***********************************************************************
* Encrypt serialized object * Encrypt serialized object
*/ */
$sha_digest = sha1($data, true); $sha_digest = sha1($p_q_inner_data, true);
$random_bytes = \phpseclib\Crypt\Random::string(255 - strlen($data) - strlen($sha_digest)); $random_bytes = \phpseclib\Crypt\Random::string(255 - strlen($p_q_inner_data) - strlen($sha_digest));
$to_encrypt = $sha_digest.$data.$random_bytes; $to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes;
$encrypted_data = $this->key->encrypt($to_encrypt); $encrypted_data = $this->key->encrypt($to_encrypt);
\danog\MadelineProto\Logger::log('Starting Diffie Hellman key exchange'); \danog\MadelineProto\Logger::log('Starting Diffie Hellman key exchange');
@ -176,7 +163,7 @@ class AuthKeyHandler extends AckHandler
* Check if the client's nonce and the server's nonce are the same * Check if the client's nonce and the server's nonce are the same
*/ */
if ($nonce != $server_dh_params['nonce']) { if ($nonce != $server_dh_params['nonce']) {
throw new Exception('wrong nonce.'); throw new \danog\MadelineProto\Exception('wrong nonce.');
} }
/* /*
@ -184,7 +171,7 @@ class AuthKeyHandler extends AckHandler
* Check if server_nonce and new server_nonce are the same * Check if server_nonce and new server_nonce are the same
*/ */
if ($server_nonce != $server_dh_params['server_nonce']) { if ($server_nonce != $server_dh_params['server_nonce']) {
throw new Exception('wrong server nonce.'); throw new \danog\MadelineProto\Exception('wrong server nonce.');
} }
/* /*
@ -193,7 +180,7 @@ class AuthKeyHandler extends AckHandler
* new nonce hash return in server_DH_params_fail * new nonce hash return in server_DH_params_fail
*/ */
if (isset($server_dh_params['new_nonce_hash']) && substr(sha1($new_nonce), -32) != $server_dh_params['new_nonce_hash']) { if (isset($server_dh_params['new_nonce_hash']) && substr(sha1($new_nonce), -32) != $server_dh_params['new_nonce_hash']) {
throw new Exception('wrong new nonce hash.'); throw new \danog\MadelineProto\Exception('wrong new nonce hash.');
} }
/* /*
@ -233,15 +220,15 @@ class AuthKeyHandler extends AckHandler
*/ */
$server_DH_inner_data_length = $this->tl->get_length($this->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) { if (sha1(substr($answer, 0, $server_DH_inner_data_length), true) != $answer_hash) {
throw new Exception('answer_hash mismatch.'); throw new \danog\MadelineProto\Exception('answer_hash mismatch.');
} }
if ($nonce != $server_DH_inner_data['nonce']) { if ($nonce != $server_DH_inner_data['nonce']) {
throw new Exception('wrong nonce'); throw new \danog\MadelineProto\Exception('wrong nonce');
} }
if ($server_nonce != $server_DH_inner_data['server_nonce']) { if ($server_nonce != $server_DH_inner_data['server_nonce']) {
throw new Exception('wrong server nonce'); throw new \danog\MadelineProto\Exception('wrong server nonce');
} }
$g = new \phpseclib\Math\BigInteger($server_DH_inner_data['g']); $g = new \phpseclib\Math\BigInteger($server_DH_inner_data['g']);
@ -275,7 +262,7 @@ class AuthKeyHandler extends AckHandler
*/ */
\danog\MadelineProto\Logger::log('Executing dh_prime checks (1/3)...'); \danog\MadelineProto\Logger::log('Executing dh_prime checks (1/3)...');
if (!$dh_prime->isPrime()) { if (!$dh_prime->isPrime()) {
throw new Exception("dh_prime isn't a safe 2048-bit prime (dh_prime isn't a prime)."); throw new \danog\MadelineProto\Exception("dh_prime isn't a safe 2048-bit prime (dh_prime isn't a prime).");
} }
@ -289,7 +276,7 @@ class AuthKeyHandler extends AckHandler
/* /*
\danog\MadelineProto\Logger::log('Executing dh_prime checks (2/3)...'); \danog\MadelineProto\Logger::log('Executing dh_prime checks (2/3)...');
if (!$dh_prime->subtract($one)->divide($two)[0]->isPrime()) { if (!$dh_prime->subtract($one)->divide($two)[0]->isPrime()) {
throw new Exception("dh_prime isn't a safe 2048-bit prime ((dh_prime - 1) / 2 isn't a prime)."); throw new \danog\MadelineProto\Exception("dh_prime isn't a safe 2048-bit prime ((dh_prime - 1) / 2 isn't a prime).");
} }
*/ */
@ -302,7 +289,7 @@ class AuthKeyHandler extends AckHandler
if ($dh_prime->compare($twoe2047) <= 0 // 2^2047 < dh_prime or dh_prime > 2^2047 or ! dh_prime <= 2^2047 if ($dh_prime->compare($twoe2047) <= 0 // 2^2047 < dh_prime or dh_prime > 2^2047 or ! dh_prime <= 2^2047
|| $dh_prime->compare($twoe2048) >= 0 // dh_prime < 2^2048 or ! dh_prime >= 2^2048 || $dh_prime->compare($twoe2048) >= 0 // dh_prime < 2^2048 or ! dh_prime >= 2^2048
) { ) {
throw new Exception("g isn't a safe 2048-bit prime (2^2047 < dh_prime < 2^2048 is false)."); throw new \danog\MadelineProto\Exception("g isn't a safe 2048-bit prime (2^2047 < dh_prime < 2^2048 is false).");
} }
/* /*
@ -315,7 +302,7 @@ class AuthKeyHandler extends AckHandler
if ($g->compare($one) <= 0 // 1 < g or g > 1 or ! g <= 1 if ($g->compare($one) <= 0 // 1 < g or g > 1 or ! g <= 1
|| $g->compare($dh_prime->subtract($one)) >= 0 // g < dh_prime - 1 or ! g >= dh_prime - 1 || $g->compare($dh_prime->subtract($one)) >= 0 // g < dh_prime - 1 or ! g >= dh_prime - 1
) { ) {
throw new Exception('g is invalid (1 < g < dh_prime - 1 is false).'); throw new \danog\MadelineProto\Exception('g is invalid (1 < g < dh_prime - 1 is false).');
} }
/* /*
@ -327,7 +314,7 @@ class AuthKeyHandler extends AckHandler
if ($g_a->compare($one) <= 0 // 1 < g_a or g_a > 1 or ! g_a <= 1 if ($g_a->compare($one) <= 0 // 1 < g_a or g_a > 1 or ! g_a <= 1
|| $g_a->compare($dh_prime->subtract($one)) >= 0 // g_a < dh_prime - 1 or ! g_a >= dh_prime - 1 || $g_a->compare($dh_prime->subtract($one)) >= 0 // g_a < dh_prime - 1 or ! g_a >= dh_prime - 1
) { ) {
throw new Exception('g_a is invalid (1 < g_a < dh_prime - 1 is false).'); throw new \danog\MadelineProto\Exception('g_a is invalid (1 < g_a < dh_prime - 1 is false).');
} }
foreach ($this->range(0, $this->settings['max_tries']['authorization']) as $retry_id) { foreach ($this->range(0, $this->settings['max_tries']['authorization']) as $retry_id) {
@ -343,7 +330,7 @@ class AuthKeyHandler extends AckHandler
if ($g_b->compare($one) <= 0 // 1 < g_b or g_b > 1 or ! g_b <= 1 if ($g_b->compare($one) <= 0 // 1 < g_b or g_b > 1 or ! g_b <= 1
|| $g_b->compare($dh_prime->subtract($one)) >= 0 // g_b < dh_prime - 1 or ! g_b >= dh_prime - 1 || $g_b->compare($dh_prime->subtract($one)) >= 0 // g_b < dh_prime - 1 or ! g_b >= dh_prime - 1
) { ) {
throw new Exception('g_b is invalid (1 < g_b < dh_prime - 1 is false).'); throw new \danog\MadelineProto\Exception('g_b is invalid (1 < g_b < dh_prime - 1 is false).');
} }
\danog\MadelineProto\Logger::log('Preparing client_DH_inner_data...'); \danog\MadelineProto\Logger::log('Preparing client_DH_inner_data...');
@ -425,7 +412,7 @@ class AuthKeyHandler extends AckHandler
* Check if the client's nonce and the server's nonce are the same * Check if the client's nonce and the server's nonce are the same
*/ */
if ($Set_client_DH_params_answer['nonce'] != $nonce) { if ($Set_client_DH_params_answer['nonce'] != $nonce) {
throw new Exception('wrong nonce.'); throw new \danog\MadelineProto\Exception('wrong nonce.');
} }
/* /*
@ -433,7 +420,7 @@ class AuthKeyHandler extends AckHandler
* Check if server_nonce and new server_nonce are the same * Check if server_nonce and new server_nonce are the same
*/ */
if ($Set_client_DH_params_answer['server_nonce'] != $server_nonce) { if ($Set_client_DH_params_answer['server_nonce'] != $server_nonce) {
throw new Exception('wrong server nonce'); throw new \danog\MadelineProto\Exception('wrong server nonce');
} }
/* /*
@ -443,7 +430,7 @@ class AuthKeyHandler extends AckHandler
switch ($Set_client_DH_params_answer['_']) { switch ($Set_client_DH_params_answer['_']) {
case 'dh_gen_ok': case 'dh_gen_ok':
if ($Set_client_DH_params_answer['new_nonce_hash1'] != $new_nonce_hash1) { if ($Set_client_DH_params_answer['new_nonce_hash1'] != $new_nonce_hash1) {
throw new Exception('wrong new_nonce_hash1'); throw new \danog\MadelineProto\Exception('wrong new_nonce_hash1');
} }
\danog\MadelineProto\Logger::log('Diffie Hellman key exchange processed successfully!'); \danog\MadelineProto\Logger::log('Diffie Hellman key exchange processed successfully!');
@ -452,8 +439,9 @@ class AuthKeyHandler extends AckHandler
$res_authorization['auth_key'] = $auth_key_str; $res_authorization['auth_key'] = $auth_key_str;
$res_authorization['id'] = substr($auth_key_sha, -8); $res_authorization['id'] = substr($auth_key_sha, -8);
if ($expires_in < 0) { //check if permanent authorization if ($expires_in >= 0) { //check if permanent authorization
$res_authorization['expires_in'] = $expires_in; $res_authorization['expires_in'] = $expires_in;
$res_authorization['p_q_inner_data_temp'] = $p_q_inner_data;
} }
\danog\MadelineProto\Logger::log('Auth key generated'); \danog\MadelineProto\Logger::log('Auth key generated');
@ -461,7 +449,7 @@ class AuthKeyHandler extends AckHandler
return $res_authorization; return $res_authorization;
case 'dh_gen_retry': case 'dh_gen_retry':
if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) { if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) {
throw new Exception('wrong new_nonce_hash_2'); throw new \danog\MadelineProto\Exception('wrong new_nonce_hash_2');
} }
//repeat foreach //repeat foreach
@ -469,13 +457,13 @@ class AuthKeyHandler extends AckHandler
break; break;
case 'dh_gen_fail': case 'dh_gen_fail':
if ($Set_client_DH_params_answer['new_nonce_hash3'] != $new_nonce_hash3) { if ($Set_client_DH_params_answer['new_nonce_hash3'] != $new_nonce_hash3) {
throw new Exception('wrong new_nonce_hash_3'); throw new \danog\MadelineProto\Exception('wrong new_nonce_hash_3');
} }
\danog\MadelineProto\Logger::log('Auth Failed'); \danog\MadelineProto\Logger::log('Auth Failed');
break 2; break 2;
default: default:
throw new Exception('Response Error'); throw new \danog\MadelineProto\Exception('Response Error');
break; break;
} }
} }
@ -484,7 +472,7 @@ class AuthKeyHandler extends AckHandler
} }
} }
throw new Exception('Auth Failed'); throw new \danog\MadelineProto\Exception('Auth Failed');
} }
public function bind_temp_auth_key($expires_in) public function bind_temp_auth_key($expires_in)
@ -519,6 +507,6 @@ class AuthKeyHandler extends AckHandler
return true; return true;
} }
throw new Exception('An error occurred while binding temporary and permanent authorization keys.'); throw new \danog\MadelineProto\Exception('An error occurred while binding temporary and permanent authorization keys.');
} }
} }

View File

@ -33,7 +33,7 @@ class CallHandler extends AuthKeyHandler
} }
} }
if ($response == null) { if ($response == null) {
throw new Exception("Couldn't get response"); throw new \danog\MadelineProto\Exception("Couldn't get response");
} }
switch ($response['_']) { switch ($response['_']) {
case 'rpc_error': case 'rpc_error':
@ -47,7 +47,7 @@ class CallHandler extends AuthKeyHandler
break; break;
default: default:
throw new Exception('Got rpc error '.$response['error_code'].': '.$response['error_message']); throw new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code']);
break; break;
} }
break; break;
@ -60,7 +60,7 @@ class CallHandler extends AuthKeyHandler
public function method_call($method, $args, $message_id = null) public function method_call($method, $args, $message_id = null)
{ {
if (!is_array($args)) { if (!is_array($args)) {
throw new Exception("Arguments aren't an array."); throw new \danog\MadelineProto\Exception("Arguments aren't an array.");
} }
foreach (range(1, $this->settings['max_tries']['query']) as $i) { foreach (range(1, $this->settings['max_tries']['query']) as $i) {
try { try {
@ -68,24 +68,32 @@ class CallHandler extends AuthKeyHandler
$int_message_id = $this->send_message($this->tl->serialize_method($method, $args), $this->tl->content_related($method), $message_id); $int_message_id = $this->send_message($this->tl->serialize_method($method, $args), $this->tl->content_related($method), $message_id);
$this->outgoing_messages[$int_message_id]['content'] = ['method' => $method, 'args' => $args]; $this->outgoing_messages[$int_message_id]['content'] = ['method' => $method, 'args' => $args];
$server_answer = $this->wait_for_response($int_message_id, $method); $server_answer = $this->wait_for_response($int_message_id, $method);
} catch (Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Recreating connection and retrying to call method...'); \danog\MadelineProto\Logger::log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Recreating connection and retrying to call method...');
$this->datacenter->close_and_reopen(); $this->datacenter->close_and_reopen();
continue; continue;
} catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->getCode() == -404) {
\danog\MadelineProto\Logger::log('Temporary authorization key expired. Regenerating and recalling method...');
$this->datacenter->temp_auth_key = null;
$this->init_authorization();
continue;
}
throw $e;
} }
if ($server_answer == null) { if ($server_answer == null) {
throw new Exception('An error occurred while calling method '.$method.'.'); throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.'.');
} }
return $server_answer; return $server_answer;
} }
throw new Exception('An error occurred while calling method '.$method.'.'); throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.'.');
} }
public function object_call($object, $args) public function object_call($object, $args)
{ {
if (!is_array($args)) { if (!is_array($args)) {
throw new Exception("Arguments aren't an array."); throw new \danog\MadelineProto\Exception("Arguments aren't an array.");
} }
foreach (range(1, $this->settings['max_tries']['query']) as $i) { foreach (range(1, $this->settings['max_tries']['query']) as $i) {
@ -101,11 +109,11 @@ class CallHandler extends AuthKeyHandler
return; return;
// if ($server_answer == null) { // if ($server_answer == null) {
// throw new Exception('An error occurred while calling object '.$object.'.'); // throw new \danog\MadelineProto\Exception('An error occurred while calling object '.$object.'.');
// } // }
// $deserialized = $this->tl->deserialize($this->fopen_and_write('php://memory', 'rw+b', $server_answer)); // $deserialized = $this->tl->deserialize($this->fopen_and_write('php://memory', 'rw+b', $server_answer));
// return $deserialized; // return $deserialized;
} }
throw new Exception('An error occurred while calling object '.$object.'.'); throw new \danog\MadelineProto\Exception('An error occurred while calling object '.$object.'.');
} }
} }

View File

@ -50,17 +50,17 @@ class Crypt extends CallHandler
public function _ige($message, $key, $iv, $operation = 'decrypt') public function _ige($message, $key, $iv, $operation = 'decrypt')
{ {
if (strlen($key) != 32) { if (strlen($key) != 32) {
throw new Exception('key must be 32 bytes long (was '.strlen($key).' bytes)'); throw new \danog\MadelineProto\Exception('key must be 32 bytes long (was '.strlen($key).' bytes)');
} }
if (strlen($iv) != 32) { if (strlen($iv) != 32) {
throw new Exception('iv must be 32 bytes long (was '.strlen($iv).' bytes)'); throw new \danog\MadelineProto\Exception('iv must be 32 bytes long (was '.strlen($iv).' bytes)');
} }
$cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB); $cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB);
$cipher->setKey($key); $cipher->setKey($key);
$cipher->paddable = false; $cipher->paddable = false;
$blocksize = $cipher->block_size; $blocksize = $cipher->block_size;
if ((strlen($message) % $blocksize) != 0) { if ((strlen($message) % $blocksize) != 0) {
throw new Exception('message must be a multiple of 16 bytes (try adding '.(16 - (strlen($message) % 16)).' bytes of padding)'); throw new \danog\MadelineProto\Exception('message must be a multiple of 16 bytes (try adding '.(16 - (strlen($message) % 16)).' bytes of padding)');
} }
$ivp = substr($iv, 0, $blocksize); $ivp = substr($iv, 0, $blocksize);
$ivp2 = substr($iv, $blocksize); $ivp2 = substr($iv, $blocksize);
@ -80,7 +80,7 @@ class Crypt extends CallHandler
$ivp = $outdata; $ivp = $outdata;
$ivp2 = $indata; $ivp2 = $indata;
} else { } else {
throw new Exception('Crypt: operation must be either \'decrypt\' or \'encrypt\''); throw new \danog\MadelineProto\Exception('Crypt: operation must be either \'decrypt\' or \'encrypt\'');
} }
$ciphered .= $outdata; $ciphered .= $outdata;
} }

View File

@ -1,40 +0,0 @@
<?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 MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
namespace danog\MadelineProto\MTProtoTools;
class Exception extends \Exception
{
public function __construct($message, $code = 0, Exception $previous = null)
{
// some code
if (isset($GLOBALS['doingphptests']) && $GLOBALS['doingphptests']) {
var_dump($message);
}
// make sure everything is assigned properly
parent::__construct($message, $code, $previous);
}
/**
* ExceptionErrorHandler.
*
* Error handler
*/
public static function ExceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
{
// If error is suppressed with @, don't throw an exception
if (error_reporting() === 0) {
return true; // return true to continue through the others error handlers
}
throw new self($errstr.' on line '.$errline.' of file '.$errfile, $errno);
}
}

View File

@ -27,7 +27,7 @@ class MessageHandler extends Crypt
$int_message_id = $this->generate_message_id(); $int_message_id = $this->generate_message_id();
} }
if (!is_int($int_message_id)) { if (!is_int($int_message_id)) {
throw new Exception("Specified message id isn't an integer"); throw new \danog\MadelineProto\Exception("Specified message id isn't an integer");
} }
$message_id = \danog\PHP\Struct::pack('<Q', $int_message_id); $message_id = \danog\PHP\Struct::pack('<Q', $int_message_id);
@ -54,7 +54,7 @@ class MessageHandler extends Crypt
{ {
$payload = $this->datacenter->read_message(); $payload = $this->datacenter->read_message();
if (fstat($payload)['size'] == 4) { if (fstat($payload)['size'] == 4) {
throw new Exception('Server response error: '.abs(\danog\PHP\Struct::unpack('<i', fread($payload, 4))[0])); throw new \danog\MadelineProto\RPCErrorException('Generic', \danog\PHP\Struct::unpack('<i', fread($payload, 4))[0]);
} }
$auth_key_id = fread($payload, 8); $auth_key_id = fread($payload, 8);
if ($auth_key_id == $this->string2bin('\x00\x00\x00\x00\x00\x00\x00\x00')) { if ($auth_key_id == $this->string2bin('\x00\x00\x00\x00\x00\x00\x00\x00')) {
@ -69,12 +69,12 @@ class MessageHandler extends Crypt
$server_salt = \danog\PHP\Struct::unpack('<q', substr($decrypted_data, 0, 8))[0]; $server_salt = \danog\PHP\Struct::unpack('<q', substr($decrypted_data, 0, 8))[0];
if ($server_salt != $this->datacenter->temp_auth_key['server_salt']) { if ($server_salt != $this->datacenter->temp_auth_key['server_salt']) {
throw new Exception('Server salt mismatch (my server salt '.$this->datacenter->temp_auth_key['server_salt'].' is not equal to server server salt '.$server_salt.').'); throw new \danog\MadelineProto\Exception('Server salt mismatch (my server salt '.$this->datacenter->temp_auth_key['server_salt'].' is not equal to server server salt '.$server_salt.').');
} }
$session_id = substr($decrypted_data, 8, 8); $session_id = substr($decrypted_data, 8, 8);
if ($session_id != $this->datacenter->session_id) { if ($session_id != $this->datacenter->session_id) {
throw new Exception('Session id mismatch.'); throw new \danog\MadelineProto\Exception('Session id mismatch.');
} }
$message_id = \danog\PHP\Struct::unpack('<Q', substr($decrypted_data, 16, 8))[0]; $message_id = \danog\PHP\Struct::unpack('<Q', substr($decrypted_data, 16, 8))[0];
@ -86,28 +86,28 @@ class MessageHandler extends Crypt
$message_data_length = \danog\PHP\Struct::unpack('<I', substr($decrypted_data, 28, 4)) [0]; $message_data_length = \danog\PHP\Struct::unpack('<I', substr($decrypted_data, 28, 4)) [0];
if ($message_data_length > strlen($decrypted_data)) { if ($message_data_length > strlen($decrypted_data)) {
throw new Exception('message_data_length is too big'); throw new \danog\MadelineProto\Exception('message_data_length is too big');
} }
if ((strlen($decrypted_data) - 32) - $message_data_length > 15) { if ((strlen($decrypted_data) - 32) - $message_data_length > 15) {
throw new Exception('difference between message_data_length and the length of the remaining decrypted buffer is too big'); throw new \danog\MadelineProto\Exception('difference between message_data_length and the length of the remaining decrypted buffer is too big');
} }
if ($message_data_length < 0) { if ($message_data_length < 0) {
throw new Exception('message_data_length not positive'); throw new \danog\MadelineProto\Exception('message_data_length not positive');
} }
if ($message_data_length % 4 != 0) { if ($message_data_length % 4 != 0) {
throw new Exception('message_data_length not divisible by 4'); throw new \danog\MadelineProto\Exception('message_data_length not divisible by 4');
} }
$message_data = substr($decrypted_data, 32, $message_data_length); $message_data = substr($decrypted_data, 32, $message_data_length);
if ($message_key != substr(sha1(substr($decrypted_data, 0, 32 + $message_data_length), true), -16)) { if ($message_key != substr(sha1(substr($decrypted_data, 0, 32 + $message_data_length), true), -16)) {
throw new Exception('msg_key mismatch'); throw new \danog\MadelineProto\Exception('msg_key mismatch');
} }
$this->incoming_messages[$message_id]['seq_no'] = $seq_no; $this->incoming_messages[$message_id]['seq_no'] = $seq_no;
} else { } else {
throw new Exception('Got unknown auth_key id'); throw new \danog\MadelineProto\Exception('Got unknown auth_key id');
} }
$deserialized = $this->tl->deserialize($this->fopen_and_write('php://memory', 'rw+b', $message_data)); $deserialized = $this->tl->deserialize($this->fopen_and_write('php://memory', 'rw+b', $message_data));
$this->incoming_messages[$message_id]['content'] = $deserialized; $this->incoming_messages[$message_id]['content'] = $deserialized;

View File

@ -20,19 +20,19 @@ class MsgIdHandler extends MessageHandler
public function check_message_id($new_message_id, $outgoing, $container = false) public function check_message_id($new_message_id, $outgoing, $container = false)
{ {
if (((int) ((time() + $this->datacenter->time_delta - 300) * pow(2, 30)) * 4) > $new_message_id) { if (((int) ((time() + $this->datacenter->time_delta - 300) * pow(2, 30)) * 4) > $new_message_id) {
throw new Exception('Given message id ('.$new_message_id.') is too old.'); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too old.');
} }
if (((int) ((time() + $this->datacenter->time_delta + 30) * pow(2, 30)) * 4) < $new_message_id) { if (((int) ((time() + $this->datacenter->time_delta + 30) * pow(2, 30)) * 4) < $new_message_id) {
throw new Exception('Given message id ('.$new_message_id.') is too new.'); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new.');
} }
if ($outgoing) { if ($outgoing) {
if ($new_message_id % 4 != 0) { if ($new_message_id % 4 != 0) {
throw new Exception('Given message id ('.$new_message_id.') is not divisible by 4.'); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4.');
} }
$keys = array_keys($this->outgoing_messages); $keys = array_keys($this->outgoing_messages);
asort($keys); asort($keys);
if ($new_message_id <= end($keys)) { if ($new_message_id <= end($keys)) {
throw new Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.end($keys).').', 1); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.end($keys).').', 1);
} }
$this->outgoing_messages[$new_message_id] = []; $this->outgoing_messages[$new_message_id] = [];
if (count($this->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) { if (count($this->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) {
@ -40,19 +40,19 @@ class MsgIdHandler extends MessageHandler
} }
} else { } else {
if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) { if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) {
throw new Exception('message id mod 4 != 1 or 3'); throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
} }
$keys = array_keys($this->incoming_messages); $keys = array_keys($this->incoming_messages);
if ($container) { if ($container) {
asort($keys); asort($keys);
if ($new_message_id >= end($keys)) { if ($new_message_id >= end($keys)) {
throw new Exception('Given message id ('.$new_message_id.') is bigger than or equal than the current limit ('.end($keys).').'); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is bigger than or equal than the current limit ('.end($keys).').');
} }
} else { } else {
asort($keys); asort($keys);
foreach ($keys as $message_id) { foreach ($keys as $message_id) {
if ($new_message_id <= $message_id) { if ($new_message_id <= $message_id) {
throw new Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.$message_id.').'); throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.$message_id.').');
} }
} }
} }

View File

@ -54,7 +54,7 @@ class ResponseHandler extends MsgIdHandler
48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)', 48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)',
64 => 'invalid container.', 64 => 'invalid container.',
]; ];
throw new Exception('Received bad_msg_notification for '.$response['bad_msg_id'].': '.$error_codes[$response['error_code']]); throw new \danog\MadelineProto\Exception('Received bad_msg_notification for '.$response['bad_msg_id'].': '.$error_codes[$response['error_code']]);
break; break;
case 'bad_server_salt': case 'bad_server_salt':
$this->datacenter->temp_auth_key['server_salt'] = $response['new_server_salt']; $this->datacenter->temp_auth_key['server_salt'] = $response['new_server_salt'];

View File

@ -14,27 +14,4 @@ namespace danog\MadelineProto\TL;
class Exception extends \Exception class Exception extends \Exception
{ {
public function __construct($message, $code = 0, Exception $previous = null)
{
// some code
if (isset($GLOBALS['doingphptests']) && $GLOBALS['doingphptests']) {
var_dump($message);
}
// make sure everything is assigned properly
parent::__construct($message, $code, $previous);
}
/**
* ExceptionErrorHandler.
*
* Error handler
*/
public function ExceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null)
{
// If error is suppressed with @, don't throw an exception
if (error_reporting() === 0) {
return true; // return true to continue through the others error handlers
}
throw new self($errstr.' on line '.$errline.' of file '.$errfile, $errno);
}
} }

View File

@ -14,8 +14,7 @@ If not, see <http://www.gnu.org/licenses/>.
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
$MadelineProto = new \danog\MadelineProto\API(); $MadelineProto = new \danog\MadelineProto\API();
var_dump(strlen(var_export($MadelineProto, true))); /*if (file_exists('number.php')) {
if (file_exists('number.php')) {
include_once 'number.php'; include_once 'number.php';
$sentCode = $MadelineProto->auth->sendCode( $sentCode = $MadelineProto->auth->sendCode(
[ [
@ -40,4 +39,16 @@ if (file_exists('number.php')) {
] ]
); );
var_dump($authorization); var_dump($authorization);
}*/
if (file_exists('token.php')) {
include_once 'token.php';
$botauthorization = $MadelineProto->auth->importBotAuthorization(
[
'bot_auth_token' => $token,
'api_id' => $MadelineProto->API->settings['app_info']['api_id'],
'api_hash' => $MadelineProto->API->settings['app_info']['api_hash'],
]
);
var_dump($botauthorization);
} }
echo 'Size of MadelineProto instance is '.strlen(var_export($MadelineProto, true)).' bytes'.PHP_EOL;