diff --git a/secret_bot.php b/secret_bot.php index 06193d6b..e0dad596 100755 --- a/secret_bot.php +++ b/secret_bot.php @@ -22,7 +22,6 @@ try { } catch (\danog\MadelineProto\Exception $e) { var_dump($e->getMessage()); } -var_dump(file_exists('.env')); if (file_exists('.env')) { echo 'Loading .env...'.PHP_EOL; $dotenv = new Dotenv\Dotenv(getcwd()); @@ -74,17 +73,19 @@ echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('s.madeline', $Madel $offset = 0; while (true) { - $updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout - //\danog\MadelineProto\Logger::log([$updates]); - foreach ($updates as $update) { - $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id - switch ($update['update']['_']) { - case 'updateNewEncryptedMessage': - $i = 0; - while (true) { - $MadelineProto->messages->sendEncrypted(['peer' => $update['update']['message']['chat_id'], 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => $i++]]); - } + try { + $updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout + //\danog\MadelineProto\Logger::log([$updates]); + foreach ($updates as $update) { + $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id + switch ($update['update']['_']) { + case 'updateNewEncryptedMessage': + $i = 0; + while (true) { + $MadelineProto->messages->sendEncrypted(['peer' => $update['update']['message']['chat_id'], 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => $i++]]); + } + } } - } + } catch (\danog\MadelineProto\SecurityException $e) { ; } echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('bot.madeline', $MadelineProto).' bytes'.PHP_EOL; } diff --git a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php index b5faa5fa..983bcd52 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php @@ -251,7 +251,7 @@ trait UpdateHandler $this->set_update_state($difference['state']); //var_dump($difference['new_encrypted_messages']); foreach ($difference['new_encrypted_messages'] as $encrypted) { - $this->handle_encrypted_update(['_' => 'updateNewEncryptedMessage', 'message' => $encrypted]); + $this->handle_encrypted_update(['_' => 'updateNewEncryptedMessage', 'message' => $encrypted], true); } $this->handle_multiple_update($difference['other_updates']); $this->handle_update_messages($difference['new_messages']); diff --git a/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php b/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php index b1147000..6f6a78a9 100644 --- a/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php +++ b/src/danog/MadelineProto/SecretChats/AuthKeyHandler.php @@ -24,6 +24,12 @@ trait AuthKeyHandler public function accept_secret_chat($params) { + if ($this->secret_chat_status($params['id']) !== 0) { + //var_dump($this->secret_chat_status($params['id'])); + \danog\MadelineProto\Logger::log(["I've already accepted secret chat ".$params['id']]); + + return false; + } $this->should_serialize = true; $dh_config = $this->get_dh_config(); \danog\MadelineProto\Logger::log(['Generating b...'], \danog\MadelineProto\Logger::VERBOSE); @@ -85,9 +91,8 @@ trait AuthKeyHandler unset($this->temp_requested_secret_chats[$params['id']]); $key['fingerprint'] = substr(sha1($key['auth_key'], true), -8); //var_dump($key); - if ($key['fingerprint'] !== $params['key_fingerprint']) { - $this->method_call('messages.discardEncryption', ['chat_id' => $params['id']], ['datacenter' => $this->datacenter->curdc]); + $this->discard_secret_chat($params['id']); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } $key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16); @@ -232,4 +237,22 @@ trait AuthKeyHandler { return $this->secret_chats[$chat]; } + + public function discard_secret_chat($chat) { + if (isset($this->secret_chats[$chat])) { + unset($this->secret_chats[$chat]); + } + if (isset($this->temp_requested_secret_chats[$chat])) { + unset($this->temp_requested_secret_chats[$chat]); + } + if (isset($this->temp_rekeyed_secret_chats[$chat])) { + unset($this->temp_rekeyed_secret_chats[$chat]); + } + try { + $this->method_call('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]); + } catch (\danog\MadelineProto\RPCErrorException $e) { + if ($e->rpc !== "ENCRYPTION_ALREADY_DECLINED") throw $e; + } + + } } diff --git a/src/danog/MadelineProto/SecretChats/MessageHandler.php b/src/danog/MadelineProto/SecretChats/MessageHandler.php index bb34e4f3..f3c7b708 100644 --- a/src/danog/MadelineProto/SecretChats/MessageHandler.php +++ b/src/danog/MadelineProto/SecretChats/MessageHandler.php @@ -29,8 +29,9 @@ trait MessageHandler if (($this->secret_chats[$chat_id]['ttr'] <= 0 || time() - $this->secret_chats[$chat_id]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$chat_id]['rekeying'][0] === 0) { $this->rekey($chat_id); } - if ($this->secret_chats[$chat_id]['layer'] !== 8) { + if ($this->secret_chats[$chat_id]['layer'] > 8) { $message = ['_' => 'decryptedMessageLayer', 'layer' => $this->secret_chats[$chat_id]['layer'], 'in_seq_no' => $this->generate_secret_in_seq_no($chat_id), 'out_seq_no' => $this->generate_secret_out_seq_no($chat_id), 'message' => $message]; + $this->secret_chats[$chat_id]['out_seq_no']++; } $this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message; $message = $this->serialize_object(['type' => $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $this->secret_chats[$chat_id]['layer']); @@ -40,14 +41,13 @@ trait MessageHandler list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], 'to server'); $message .= $this->random($this->posmod(-strlen($message), 16)); - $this->secret_chats[$chat_id]['out_seq_no']++; $message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv); return $message; } - public function handle_encrypted_update($message) + public function handle_encrypted_update($message, $test = false) { if (!isset($this->secret_chats[$message['message']['chat_id']])) { \danog\MadelineProto\Logger::log('I do not have the secret chat '.$message['message']['chat_id'].' in the database, skipping message...'); @@ -60,10 +60,12 @@ trait MessageHandler //var_dump($auth_key_id, $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']); if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) { if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) { + $this->discard_secret_chat($message['message']['chat_id']); throw new \danog\MadelineProto\SecurityException('Key fingerprint mismatch'); } $old = true; } else { + $this->discard_secret_chat($message['message']['chat_id']); throw new \danog\MadelineProto\SecurityException('Key fingerprint mismatch'); } } @@ -94,7 +96,11 @@ trait MessageHandler } unset($message['message']['bytes']); $message['message']['decrypted_message'] = $deserialized; - $this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']++] = $message['message']; + if ($test) { + var_dump($message); + } + $this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message']; + //var_dump($message); $this->handle_decrypted_update($message); } diff --git a/src/danog/MadelineProto/SecretChats/ResponseHandler.php b/src/danog/MadelineProto/SecretChats/ResponseHandler.php index f87c4825..a85e46c7 100644 --- a/src/danog/MadelineProto/SecretChats/ResponseHandler.php +++ b/src/danog/MadelineProto/SecretChats/ResponseHandler.php @@ -72,6 +72,13 @@ trait ResponseHandler break; case 'decryptedMessageLayer': if ($this->check_secret_out_seq_no($update['message']['chat_id'], $update['message']['decrypted_message']['out_seq_no']) && $this->check_secret_in_seq_no($update['message']['chat_id'], $update['message']['decrypted_message']['in_seq_no'])) { + $this->secret_chats[$update['message']['chat_id']]['in_seq_no']++; + if ($update['message']['decrypted_message']['layer'] >= 17) { + $this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['layer']; + if ($update['message']['decrypted_message']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) { + $this->notify_layer($update['message']['chat_id']); + } + } $update['message']['decrypted_message'] = $update['message']['decrypted_message']['message']; $this->handle_decrypted_update($update); } diff --git a/src/danog/MadelineProto/SecretChats/SeqNoHandler.php b/src/danog/MadelineProto/SecretChats/SeqNoHandler.php index 9af1dd7d..b43e4a4a 100644 --- a/src/danog/MadelineProto/SecretChats/SeqNoHandler.php +++ b/src/danog/MadelineProto/SecretChats/SeqNoHandler.php @@ -24,14 +24,14 @@ trait SeqNoHandler foreach ($this->secret_chats[$chat_id]['incoming'] as $message) { if (isset($message['decrypted_message']['in_seq_no'])) { if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) { - unset($this->secret_chats[$chat_id]); + $this->discard_secret_chat($chat_id); throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing'); } $last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2; } } if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) { - unset($this->secret_chats[$chat_id]); + $this->discard_secret_chat($chat_id); throw new \danog\MadelineProto\SecurityException('in_seq_no is too big'); } @@ -43,14 +43,17 @@ trait SeqNoHandler $seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2; $C = 0; foreach ($this->secret_chats[$chat_id]['incoming'] as $message) { - if (isset($message['decrypted_message']['out_seq_no']) && $C !== $this->secret_chats[$chat_id]['in_seq_no'] - 1) { + var_dump($message); + if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) { if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) { + $this->discard_secret_chat($chat_id); throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.(($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2)); } else { $C++; } } } + var_dump($C, $seqno); if ($seqno < $C) { // <= C \danog\MadelineProto\Logger::log(['WARNING: dropping repeated message with seqno '.$seqno]); $this->secret_chats[$chat_id]['in_seq_no']--; @@ -58,7 +61,7 @@ trait SeqNoHandler return false; } if ($seqno > $C) { // > C+1 - unset($this->secret_chats[$chat_id]); + $this->discard_secret_chat($chat_id); throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!'); return false; }