Fixed handling of bad_server_salt notifications, improved switching of DCs when user is authorized, session ids and sequence numbers will now be resetted on deserialization

This commit is contained in:
Daniil Gentili 2016-11-26 10:50:20 +00:00
parent dae2375bf3
commit 496d6790bc
4 changed files with 36 additions and 14 deletions

View File

@ -8,6 +8,8 @@ PHP implementation of MTProto, based on [telepy](https://github.com/griganton/te
This project can run on PHP 7, PHP 5.6 and HHVM.
Also note that MadelineProto will perform better if a big math extension like gmp o bcmath is installed.
This project is in beta state.

View File

@ -178,6 +178,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
{
$this->setup_logger();
$this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']);
$this->reset_session();
}
public function setup_logger()
@ -187,24 +188,40 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
\danog\MadelineProto\Logger::constructor($this->settings['logger']['logger'], $this->settings['logger']['logger_param']);
}
}
public function reset_session() {
foreach ($this->datacenter->sockets as $id => &$socket) {
\danog\MadelineProto\Logger::log('Resetting session id and seq_no in DC '.$id.'...');
$socket->session_id = \phpseclib\Crypt\Random::string(8);
$socket->seq_no = 0;
}
}
// Switches to a new datacenter and if necessary creates authorization keys, binds them and writes client info
public function switch_dc($new_dc, $allow_nearest_dc_switch = false)
{
\danog\MadelineProto\Logger::log('Switching to DC '.$new_dc.'...');
if ($this->datacenter->curdc !== 0 && $this->datacenter->authorized) {
$exported_authorization = $this->method_call('auth.exportAuthorization', ['dc_id' => $new_dc]);
}
if ($this->datacenter->dc_connect($new_dc)) {
$old_dc = $this->datacenter->curdc;
if (!isset($this->datacenter->sockets[$new_dc])) {
$this->datacenter->dc_connect($new_dc);
$this->init_authorization();
$this->config = $this->write_client_info('help.getConfig');
$this->parse_config();
if (isset($exported_authorization)) {
$this->datacenter->authorization = $this->method_call('auth.importAuthorization', $exported_authorization);
$this->datacenter->authorized = true;
}
$this->get_nearest_dc($allow_nearest_dc_switch);
}
if (
(isset($this->datacenter->sockets[$old_dc]->authorized) && $this->datacenter->sockets[$old_dc]->authorized) &&
!(isset($this->datacenter->sockets[$new_dc]->authorized) && $this->datacenter->sockets[$new_dc]->authorized && $this->datacenter->sockets[$new_dc]->authorization['user']['id'] === $this->datacenter->sockets[$old_dc]->authorization['user']['id'])
) {
$this->datacenter->curdc = $old_dc;
$exported_authorization = $this->method_call('auth.exportAuthorization', ['dc_id' => $new_dc]);
$this->datacenter->curdc = $new_dc;
if (isset($this->datacenter->sockets[$new_dc]->authorized) && $this->datacenter->sockets[$new_dc]->authorized && $this->datacenter->sockets[$new_dc]->authorization['user']['id'] !== $this->datacenter->sockets[$old_dc]->authorization['user']['id']) {
$this->method_call('auth.logOut');
}
$this->datacenter->authorization = $this->method_call('auth.importAuthorization', $exported_authorization);
$this->datacenter->authorized = true;
}
}
// Creates authorization keys

View File

@ -69,7 +69,7 @@ class MessageHandler extends Crypt
$server_salt = \danog\PHP\Struct::unpack('<q', substr($decrypted_data, 0, 8))[0];
if ($server_salt != $this->datacenter->temp_auth_key['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.').');
\danog\MadelineProto\Logger::log('WARNING: 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);

View File

@ -43,6 +43,7 @@ class ResponseHandler extends MsgIdHandler
$this->datacenter->incoming_messages[$last_received]['content'] = $response;
break;
case 'bad_server_salt':
case 'bad_msg_notification':
$error_codes = [
16 => 'msg_id too low (most likely, client time is wrong; it would be worthwhile to synchronize it using msg_id notifications and re-send the original message with the “correct” msg_id or wrap it in a container with a new msg_id if the original message had waited too long on the client to be transmitted)',
@ -57,13 +58,15 @@ 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)',
64 => 'invalid container.',
];
switch ($response['error_code']) {
case 48:
$this->datacenter->temp_auth_key['server_salt'] = $response['new_server_salt'];
$this->ack_outgoing_message_id($response['bad_msg_id']); // Acknowledge that the server received my request
throw new \danog\MadelineProto\Exception('New server salt stored, re-executing query');
break;
}
throw new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification for '.$response['bad_msg_id'].': '.$error_codes[$response['error_code']]);
break;
case 'bad_server_salt':
$this->datacenter->temp_auth_key['server_salt'] = $response['new_server_salt'];
$this->ack_outgoing_message_id($response['bad_msg_id']); // Acknowledge that the server received my request
$this->datacenter->outgoing_messages[$response['bad_msg_id']]['response'] = $last_received;
$this->datacenter->incoming_messages[$last_received]['content'] = $response;
break;
case 'pong':