Implement secret chat feeder loop
This commit is contained in:
parent
f03705e4aa
commit
73384f0bb4
113
src/danog/MadelineProto/Loop/Update/SecretFeedLoop.php
Normal file
113
src/danog/MadelineProto/Loop/Update/SecretFeedLoop.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update feeder loop.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
|
*
|
||||||
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace danog\MadelineProto\Loop\Update;
|
||||||
|
|
||||||
|
use danog\Loop\ResumableSignalLoop;
|
||||||
|
use danog\MadelineProto\Loop\InternalLoop;
|
||||||
|
use danog\MadelineProto\MTProto;
|
||||||
|
use danog\MadelineProto\SecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secret feed loop.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
*/
|
||||||
|
class SecretFeedLoop extends ResumableSignalLoop
|
||||||
|
{
|
||||||
|
use InternalLoop {
|
||||||
|
__construct as private init;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Incoming secret updates array.
|
||||||
|
*/
|
||||||
|
private array $incomingUpdates = [];
|
||||||
|
/**
|
||||||
|
* Secret chat ID.
|
||||||
|
*/
|
||||||
|
private int $secretId;
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param MTProto $API API instance
|
||||||
|
* @param integer $secretId Secret chat ID
|
||||||
|
*/
|
||||||
|
public function __construct(MTProto $API, int $secretId)
|
||||||
|
{
|
||||||
|
$this->init($API);
|
||||||
|
$this->secretId = $secretId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Main loop.
|
||||||
|
*
|
||||||
|
* @return \Generator
|
||||||
|
*/
|
||||||
|
public function loop(): \Generator
|
||||||
|
{
|
||||||
|
$API = $this->API;
|
||||||
|
while (!$API->hasAllAuth()) {
|
||||||
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
while (!$API->hasAllAuth()) {
|
||||||
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (yield $this->waitSignal($this->pause())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$API->logger->logger("Resumed {$this}");
|
||||||
|
while ($this->incomingUpdates) {
|
||||||
|
$updates = $this->incomingUpdates;
|
||||||
|
$this->incomingUpdates = [];
|
||||||
|
foreach ($updates as $update) {
|
||||||
|
try {
|
||||||
|
if (!yield from $API->handleEncryptedUpdate($update)) {
|
||||||
|
$API->logger->logger("Secret chat deleted, exiting $this...");
|
||||||
|
unset($API->secretFeeders[$this->secretId]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (SecurityException $e) {
|
||||||
|
$API->logger->logger("Secret chat deleted, exiting $this...");
|
||||||
|
unset($API->secretFeeders[$this->secretId]);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$updates = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Feed incoming update to loop.
|
||||||
|
*
|
||||||
|
* @param array $update
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function feed(array $update): void
|
||||||
|
{
|
||||||
|
$this->incomingUpdates []= $update;
|
||||||
|
}
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return "secret chat feed loop {$this->secretId}";
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ use danog\MadelineProto\Db\MemoryArray;
|
|||||||
use danog\MadelineProto\Ipc\Server;
|
use danog\MadelineProto\Ipc\Server;
|
||||||
use danog\MadelineProto\Loop\Generic\PeriodicLoopInternal;
|
use danog\MadelineProto\Loop\Generic\PeriodicLoopInternal;
|
||||||
use danog\MadelineProto\Loop\Update\FeedLoop;
|
use danog\MadelineProto\Loop\Update\FeedLoop;
|
||||||
|
use danog\MadelineProto\Loop\Update\SecretFeedLoop;
|
||||||
use danog\MadelineProto\Loop\Update\SeqLoop;
|
use danog\MadelineProto\Loop\Update\SeqLoop;
|
||||||
use danog\MadelineProto\Loop\Update\UpdateLoop;
|
use danog\MadelineProto\Loop\Update\UpdateLoop;
|
||||||
use danog\MadelineProto\MTProtoTools\CombinedUpdatesState;
|
use danog\MadelineProto\MTProtoTools\CombinedUpdatesState;
|
||||||
@ -394,6 +395,12 @@ class MTProto extends AsyncConstruct implements TLCallback
|
|||||||
* @var array<\danog\MadelineProto\Loop\Update\FeedLoop>
|
* @var array<\danog\MadelineProto\Loop\Update\FeedLoop>
|
||||||
*/
|
*/
|
||||||
public $feeders = [];
|
public $feeders = [];
|
||||||
|
/**
|
||||||
|
* Secret chat feeder loops.
|
||||||
|
*
|
||||||
|
* @var array<\danog\MadelineProto\Loop\Update\SecretFeedLoop>
|
||||||
|
*/
|
||||||
|
public $secretFeeders = [];
|
||||||
/**
|
/**
|
||||||
* Updater loops.
|
* Updater loops.
|
||||||
*
|
*
|
||||||
@ -1563,6 +1570,14 @@ class MTProto extends AsyncConstruct implements TLCallback
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->logger("Starting update system");
|
$this->logger("Starting update system");
|
||||||
|
foreach ($this->secret_chats as $id => $chat) {
|
||||||
|
if (!isset($this->secretFeeders[$id])) {
|
||||||
|
$this->secretFeeders[$id] = new SecretFeedLoop($this, $id);
|
||||||
|
}
|
||||||
|
if ($this->secretFeeders[$id]->start() && isset($this->secretFeeders[$id])) {
|
||||||
|
$this->secretFeeders[$id]->resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!isset($this->seqUpdater)) {
|
if (!isset($this->seqUpdater)) {
|
||||||
$this->seqUpdater = new SeqLoop($this);
|
$this->seqUpdater = new SeqLoop($this);
|
||||||
}
|
}
|
||||||
|
@ -382,7 +382,7 @@ trait ResponseHandler
|
|||||||
$seconds = \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
$seconds = \preg_replace('/[^0-9]+/', '', $response['error_message']);
|
||||||
$limit = $request->getFloodWaitLimit() ?? $this->API->settings->getRPC()->getFloodTimeout();
|
$limit = $request->getFloodWaitLimit() ?? $this->API->settings->getRPC()->getFloodTimeout();
|
||||||
if (\is_numeric($seconds) && $seconds < $limit) {
|
if (\is_numeric($seconds) && $seconds < $limit) {
|
||||||
$this->logger->logger("Flood, waiting '.$seconds.' seconds before repeating async call of $request...", Logger::NOTICE);
|
$this->logger->logger("Flood, waiting $seconds seconds before repeating async call of $request...", Logger::NOTICE);
|
||||||
$request->setSent(($request->getSent() ?? \time()) + $seconds);
|
$request->setSent(($request->getSent() ?? \time()) + $seconds);
|
||||||
Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request->getMsgId()]);
|
Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request->getMsgId()]);
|
||||||
return null;
|
return null;
|
||||||
|
@ -365,7 +365,12 @@ trait UpdateHandler
|
|||||||
$this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE);
|
$this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
yield from $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], $this->settings->getDefaultDcParams());
|
yield from $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], $this->settings->getDefaultDcParams());
|
||||||
}
|
}
|
||||||
yield from $this->handleEncryptedUpdate($update);
|
if (!isset($this->secret_chats[$update['message']['chat_id']])) {
|
||||||
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $update['message']['chat_id']));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->secretFeeders[$update['message']['chat_id']]->feed($update);
|
||||||
|
$this->secretFeeders[$update['message']['chat_id']]->resume();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\SecretChats;
|
namespace danog\MadelineProto\SecretChats;
|
||||||
|
|
||||||
|
use danog\MadelineProto\Loop\Update\SecretFeedLoop;
|
||||||
use danog\MadelineProto\Loop\Update\UpdateLoop;
|
use danog\MadelineProto\Loop\Update\UpdateLoop;
|
||||||
use danog\MadelineProto\MTProto;
|
use danog\MadelineProto\MTProto;
|
||||||
use danog\MadelineProto\MTProtoTools\Crypt;
|
use danog\MadelineProto\MTProtoTools\Crypt;
|
||||||
@ -67,7 +68,34 @@ trait AuthKeyHandler
|
|||||||
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
|
||||||
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
||||||
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'from server', 'mtproto' => 1];
|
$this->secret_chats[$params['id']] = [
|
||||||
|
'key' => $key,
|
||||||
|
'admin' => false,
|
||||||
|
'user_id' => $params['admin_id'],
|
||||||
|
'InputEncryptedChat' => [
|
||||||
|
'_' => 'inputEncryptedChat',
|
||||||
|
'chat_id' => $params['id'],
|
||||||
|
'access_hash' => $params['access_hash']
|
||||||
|
],
|
||||||
|
'in_seq_no_x' => 1,
|
||||||
|
'out_seq_no_x' => 0,
|
||||||
|
'in_seq_no' => 0,
|
||||||
|
'out_seq_no' => 0,
|
||||||
|
'layer' => 8,
|
||||||
|
'ttl' => 0,
|
||||||
|
'ttr' => 100,
|
||||||
|
'updated' => \time(),
|
||||||
|
'incoming' => [],
|
||||||
|
'outgoing' => [],
|
||||||
|
'created' => \time(),
|
||||||
|
'rekeying' => [0],
|
||||||
|
'key_x' => 'from server',
|
||||||
|
'mtproto' => 1
|
||||||
|
];
|
||||||
|
$this->secretFeeders[$params['id']] = new SecretFeedLoop($this, $params['id']);
|
||||||
|
if ($this->secretFeeders[$params['id']]->start()) {
|
||||||
|
$this->secretFeeders[$params['id']]->resume();
|
||||||
|
}
|
||||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||||
Crypt::checkG($g_b, $dh_config['p']);
|
Crypt::checkG($g_b, $dh_config['p']);
|
||||||
yield from $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']]);
|
yield from $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']]);
|
||||||
@ -129,6 +157,10 @@ trait AuthKeyHandler
|
|||||||
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
$key['visualization_orig'] = \substr(\sha1($key['auth_key'], true), 16);
|
||||||
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
|
||||||
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
|
||||||
|
$this->secretFeeders[$params['id']] = new SecretFeedLoop($this, $params['id']);
|
||||||
|
if ($this->secretFeeders[$params['id']]->start()) {
|
||||||
|
$this->secretFeeders[$params['id']]->resume();
|
||||||
|
}
|
||||||
yield from $this->notifyLayer($params['id']);
|
yield from $this->notifyLayer($params['id']);
|
||||||
$this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
$this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ trait MessageHandler
|
|||||||
$this->secret_chats[$chat_id]['out_seq_no']++;
|
$this->secret_chats[$chat_id]['out_seq_no']++;
|
||||||
}
|
}
|
||||||
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
||||||
$message = (yield from $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']));
|
$constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer';
|
||||||
|
$message = yield from $this->TL->serializeObject(['type' => $constructor], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
||||||
$message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)).$message;
|
$message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)).$message;
|
||||||
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
||||||
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16);
|
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16);
|
||||||
@ -70,7 +71,15 @@ trait MessageHandler
|
|||||||
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.Crypt::igeEncrypt($message, $aes_key, $aes_iv);
|
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.Crypt::igeEncrypt($message, $aes_key, $aes_iv);
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
private function handleEncryptedUpdate(array $message): \Generator
|
/**
|
||||||
|
* Handle encrypted update.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @param array $message
|
||||||
|
* @return \Generator
|
||||||
|
*/
|
||||||
|
public function handleEncryptedUpdate(array $message): \Generator
|
||||||
{
|
{
|
||||||
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
||||||
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
||||||
@ -127,6 +136,7 @@ trait MessageHandler
|
|||||||
$message['message']['decrypted_message'] = $deserialized;
|
$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'];
|
$this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message'];
|
||||||
yield from $this->handleDecryptedUpdate($message);
|
yield from $this->handleDecryptedUpdate($message);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return false|string
|
* @return false|string
|
||||||
|
@ -24,73 +24,73 @@ namespace danog\MadelineProto\SecretChats;
|
|||||||
*/
|
*/
|
||||||
trait ResponseHandler
|
trait ResponseHandler
|
||||||
{
|
{
|
||||||
private function handleDecryptedUpdate($update): \Generator
|
private function handleDecryptedUpdate(array $update): \Generator
|
||||||
{
|
{
|
||||||
// already checked in TL.php
|
$chatId = $update['message']['chat_id'];
|
||||||
switch ($update['message']['decrypted_message']['_']) {
|
$decryptedMessage = $update['message']['decrypted_message'];
|
||||||
case 'decryptedMessageService':
|
if ($decryptedMessage['_'] === 'decryptedMessage') {
|
||||||
switch ($update['message']['decrypted_message']['action']['_']) {
|
yield from $this->saveUpdate($update);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($decryptedMessage['_'] === 'decryptedMessageService') {
|
||||||
|
$action = $decryptedMessage['action'];
|
||||||
|
switch ($action['_']) {
|
||||||
case 'decryptedMessageActionRequestKey':
|
case 'decryptedMessageActionRequestKey':
|
||||||
yield from $this->acceptRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield from $this->acceptRekey($chatId, $action);
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionAcceptKey':
|
case 'decryptedMessageActionAcceptKey':
|
||||||
yield from $this->commitRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield from $this->commitRekey($chatId, $action);
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionCommitKey':
|
case 'decryptedMessageActionCommitKey':
|
||||||
yield from $this->completeRekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
|
yield from $this->completeRekey($chatId, $action);
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionNotifyLayer':
|
case 'decryptedMessageActionNotifyLayer':
|
||||||
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
|
$this->secret_chats[$chatId]['layer'] = $action['layer'];
|
||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 17 && \time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
if ($action['layer'] >= 17 && \time() - $this->secret_chats[$chatId]['created'] > 15) {
|
||||||
yield from $this->notifyLayer($update['message']['chat_id']);
|
yield from $this->notifyLayer($chatId);
|
||||||
}
|
}
|
||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
if ($action['layer'] >= 73) {
|
||||||
$this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2;
|
$this->secret_chats[$chatId]['mtproto'] = 2;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionSetMessageTTL':
|
case 'decryptedMessageActionSetMessageTTL':
|
||||||
$this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds'];
|
$this->secret_chats[$chatId]['ttl'] = $action['ttl_seconds'];
|
||||||
yield from $this->saveUpdate($update);
|
yield from $this->saveUpdate($update);
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionNoop':
|
case 'decryptedMessageActionNoop':
|
||||||
return;
|
return;
|
||||||
case 'decryptedMessageActionResend':
|
case 'decryptedMessageActionResend':
|
||||||
$update['message']['decrypted_message']['action']['start_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
$action['start_seq_no'] -= $this->secret_chats[$chatId]['out_seq_no_x'];
|
||||||
$update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
$action['end_seq_no'] -= $this->secret_chats[$chatId]['out_seq_no_x'];
|
||||||
$update['message']['decrypted_message']['action']['start_seq_no'] /= 2;
|
$action['start_seq_no'] /= 2;
|
||||||
$update['message']['decrypted_message']['action']['end_seq_no'] /= 2;
|
$action['end_seq_no'] /= 2;
|
||||||
$this->logger->logger('Resending messages for secret chat '.$update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING);
|
$this->logger->logger('Resending messages for secret chat '.$chatId, \danog\MadelineProto\Logger::WARNING);
|
||||||
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
|
foreach ($this->secret_chats[$chatId]['outgoing'] as $seq => $message) {
|
||||||
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
|
if ($seq >= $action['start_seq_no'] && $seq <= $action['end_seq_no']) {
|
||||||
//throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
|
yield from $this->methodCallAsyncRead('messages.sendEncrypted', ['peer' => $chatId, 'message' => $message]);
|
||||||
yield from $this->methodCallAsyncRead('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
// yield $this->saveUpdate(['_' => 'updateNewDecryptedMessage', 'peer' => $this->secret_chats[$update['message']['chat_id']]['InputEncryptedChat'], 'in_seq_no' => $this->get_in_seq_no($update['message']['chat_id']), 'out_seq_no' => $this->get_out_seq_no($update['message']['chat_id']), 'message' => $update['message']['decrypted_message']]);
|
|
||||||
yield from $this->saveUpdate($update);
|
yield from $this->saveUpdate($update);
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
case 'decryptedMessage':
|
}
|
||||||
yield from $this->saveUpdate($update);
|
if ($decryptedMessage['_'] === 'decryptedMessageLayer') {
|
||||||
break;
|
if ((yield from $this->checkSecretOutSeqNo($chatId, $decryptedMessage['out_seq_no']))
|
||||||
case 'decryptedMessageLayer':
|
&& (yield from $this->checkSecretInSeqNo($chatId, $decryptedMessage['in_seq_no']))) {
|
||||||
if ((yield from $this->checkSecretOutSeqNo($update['message']['chat_id'], $update['message']['decrypted_message']['out_seq_no'])) && (yield from $this->checkSecretInSeqNo($update['message']['chat_id'], $update['message']['decrypted_message']['in_seq_no']))) {
|
$this->secret_chats[$chatId]['in_seq_no']++;
|
||||||
$this->secret_chats[$update['message']['chat_id']]['in_seq_no']++;
|
if ($decryptedMessage['layer'] >= 17) {
|
||||||
if ($update['message']['decrypted_message']['layer'] >= 17) {
|
$this->secret_chats[$chatId]['layer'] = $decryptedMessage['layer'];
|
||||||
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['layer'];
|
if ($decryptedMessage['layer'] >= 17 && \time() - $this->secret_chats[$chatId]['created'] > 15) {
|
||||||
if ($update['message']['decrypted_message']['layer'] >= 17 && \time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
yield from $this->notifyLayer($chatId);
|
||||||
yield from $this->notifyLayer($update['message']['chat_id']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$update['message']['decrypted_message'] = $update['message']['decrypted_message']['message'];
|
$update['message']['decrypted_message'] = $decryptedMessage['message'];
|
||||||
yield from $this->handleDecryptedUpdate($update);
|
yield from $this->handleDecryptedUpdate($update);
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
default:
|
|
||||||
throw new \danog\MadelineProto\ResponseException('Unrecognized decrypted message received: '.\var_export($update, true));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
throw new \danog\MadelineProto\ResponseException('Unrecognized decrypted message received: '.\var_export($update, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\SecretChats;
|
namespace danog\MadelineProto\SecretChats;
|
||||||
|
|
||||||
|
use danog\MadelineProto\Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages sequence numbers.
|
* Manages sequence numbers.
|
||||||
*/
|
*/
|
||||||
@ -31,6 +33,7 @@ trait SeqNoHandler
|
|||||||
foreach ($this->secret_chats[$chat_id]['incoming'] as $message) {
|
foreach ($this->secret_chats[$chat_id]['incoming'] as $message) {
|
||||||
if (isset($message['decrypted_message']['in_seq_no'])) {
|
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) {
|
if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) {
|
||||||
|
$this->logger->logger("Discarding secret chat $chat_id, in_seq_no is not increasing", Logger::LEVEL_FATAL);
|
||||||
yield from $this->discardSecretChat($chat_id);
|
yield from $this->discardSecretChat($chat_id);
|
||||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing');
|
throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing');
|
||||||
}
|
}
|
||||||
@ -38,6 +41,7 @@ trait SeqNoHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) {
|
if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) {
|
||||||
|
$this->logger->logger("Discarding secret chat $chat_id, in_seq_no is too big", Logger::LEVEL_FATAL);
|
||||||
yield from $this->discardSecretChat($chat_id);
|
yield from $this->discardSecretChat($chat_id);
|
||||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is too big');
|
throw new \danog\MadelineProto\SecurityException('in_seq_no is too big');
|
||||||
}
|
}
|
||||||
@ -49,9 +53,11 @@ trait SeqNoHandler
|
|||||||
$C = 0;
|
$C = 0;
|
||||||
foreach ($this->secret_chats[$chat_id]['incoming'] as $message) {
|
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']) {
|
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) {
|
$temp = ($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2;
|
||||||
|
if ($temp !== $C) {
|
||||||
|
$this->logger->logger("Discarding secret chat $chat_id, out_seq_no hole: should be $C, is $temp", Logger::LEVEL_FATAL);
|
||||||
yield from $this->discardSecretChat($chat_id);
|
yield from $this->discardSecretChat($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);
|
throw new \danog\MadelineProto\SecurityException("out_seq_no hole: should be $C, is $temp");
|
||||||
}
|
}
|
||||||
$C++;
|
$C++;
|
||||||
}
|
}
|
||||||
@ -64,6 +70,7 @@ trait SeqNoHandler
|
|||||||
}
|
}
|
||||||
if ($seqno > $C) {
|
if ($seqno > $C) {
|
||||||
// > C+1
|
// > C+1
|
||||||
|
$this->logger->logger("Discarding secret chat $chat_id, out_seq_no gap detected: ($seqno > $C)", Logger::LEVEL_FATAL);
|
||||||
yield from $this->discardSecretChat($chat_id);
|
yield from $this->discardSecretChat($chat_id);
|
||||||
throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!');
|
throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!');
|
||||||
}
|
}
|
||||||
|
@ -537,7 +537,6 @@ class TL
|
|||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$auto = false;
|
|
||||||
if ($type['type'] === 'InputMessage' && !\is_array($object)) {
|
if ($type['type'] === 'InputMessage' && !\is_array($object)) {
|
||||||
$object = ['_' => 'inputMessageID', 'id' => $object];
|
$object = ['_' => 'inputMessageID', 'id' => $object];
|
||||||
} elseif (isset($this->callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!\is_array($object) || isset($object['_']) && $this->constructors->findByPredicate($object['_'])['type'] !== $type['type'])) {
|
} elseif (isset($this->callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!\is_array($object) || isset($object['_']) && $this->constructors->findByPredicate($object['_'])['type'] !== $type['type'])) {
|
||||||
@ -569,7 +568,6 @@ class TL
|
|||||||
$type['type'] = \substr($type['type'], 1);
|
$type['type'] = \substr($type['type'], 1);
|
||||||
}
|
}
|
||||||
if ($predicate === $type['type']) {
|
if ($predicate === $type['type']) {
|
||||||
//} && !$auto) {
|
|
||||||
$bare = true;
|
$bare = true;
|
||||||
}
|
}
|
||||||
if ($predicate === 'messageEntityMentionName') {
|
if ($predicate === 'messageEntityMentionName') {
|
||||||
@ -652,7 +650,7 @@ class TL
|
|||||||
} elseif (isset($arguments['id'])) {
|
} elseif (isset($arguments['id'])) {
|
||||||
$method = 'photos.updateProfilePhoto';
|
$method = 'photos.updateProfilePhoto';
|
||||||
}
|
}
|
||||||
} else if ($method === 'messages.uploadMedia') {
|
} elseif ($method === 'messages.uploadMedia') {
|
||||||
if (!isset($arguments['peer']) && !$this->API->getSelf()['bot']) {
|
if (!isset($arguments['peer']) && !$this->API->getSelf()['bot']) {
|
||||||
$arguments['peer'] = 'me';
|
$arguments['peer'] = 'me';
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user