Implemented MTProto v2 in secret chats
This commit is contained in:
parent
2ab82c3a70
commit
8c4ad60f84
42
magna.php
42
magna.php
@ -76,12 +76,20 @@ $message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sem
|
|||||||
if (!isset($MadelineProto->programmed_call)) {
|
if (!isset($MadelineProto->programmed_call)) {
|
||||||
$MadelineProto->programmed_call = [];
|
$MadelineProto->programmed_call = [];
|
||||||
}
|
}
|
||||||
|
$MadelineProto->session = 'session.madeline';
|
||||||
|
$inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic
|
||||||
|
$inputEncryptedFileGif = $MadelineProto->upload_encrypted('tests/pony.mp4');
|
||||||
|
$inputEncryptedFileSticker = $MadelineProto->upload_encrypted('tests/lel.webp');
|
||||||
|
$inputEncryptedFileDocument = $MadelineProto->upload_encrypted('tests/60', 'magic'); // This gets an inputFile object with file name magic
|
||||||
|
$inputEncryptedFileVideo = $MadelineProto->upload_encrypted('tests/swing.mp4');
|
||||||
|
$inputEncryptedFileAudio = $MadelineProto->upload_encrypted('tests/mosconi.mp3');
|
||||||
|
|
||||||
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL; echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $MadelineProto).' bytes'.PHP_EOL;
|
|
||||||
/*
|
/*
|
||||||
$m = new \danog\MadelineProto\API($settings);
|
$m = new \danog\MadelineProto\API($settings);
|
||||||
$m->import_authorization($MadelineProto->export_authorization());
|
$m->import_authorization($MadelineProto->export_authorization());
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$MadelineProto->serialize();
|
||||||
$times = [];
|
$times = [];
|
||||||
$calls = [];
|
$calls = [];
|
||||||
$users = [];
|
$users = [];
|
||||||
@ -133,6 +141,37 @@ $users = [];
|
|||||||
\danog\MadelineProto\Logger::log([$update]);
|
\danog\MadelineProto\Logger::log([$update]);
|
||||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||||
switch ($update['update']['_']) {
|
switch ($update['update']['_']) {
|
||||||
|
case 'updateNewEncryptedMessage':
|
||||||
|
$secret = $update['update']['message']['chat_id'];
|
||||||
|
$secret_media = [];
|
||||||
|
|
||||||
|
// Photo uploaded as document, secret chat
|
||||||
|
$secret_media['document_photo'] = ['peer' => $secret, 'file' => $inputEncryptedFilePhoto, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/faust.jpg'), 'caption' => 'This file was uploaded using MadelineProto', 'key' => $inputEncryptedFilePhoto['key'], 'iv' => $inputEncryptedFilePhoto['iv'], 'file_name' => 'faust.jpg', 'size' => filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914]]]]];
|
||||||
|
|
||||||
|
// Photo, secret chat
|
||||||
|
$secret_media['photo'] = ['peer' => $secret, 'file' => $inputEncryptedFilePhoto, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaPhoto', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'caption' => 'This file was uploaded using MadelineProto', 'key' => $inputEncryptedFilePhoto['key'], 'iv' => $inputEncryptedFilePhoto['iv'], 'size' => filesize('tests/faust.jpg'), 'w' => 1280, 'h' => 914]]];
|
||||||
|
|
||||||
|
// GIF, secret chat
|
||||||
|
$secret_media['gif'] = ['peer' => $secret, 'file' => $inputEncryptedFileGif, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'key' => $inputEncryptedFileGif['key'], 'iv' => $inputEncryptedFileGif['iv'], 'file_name' => 'pony.mp4', 'size' => filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]];
|
||||||
|
|
||||||
|
// Sticker, secret chat
|
||||||
|
$secret_media['sticker'] = ['peer' => $secret, 'file' => $inputEncryptedFileSticker, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/lel.webp'), 'caption' => 'test', 'key' => $inputEncryptedFileSticker['key'], 'iv' => $inputEncryptedFileSticker['iv'], 'file_name' => 'lel.webp', 'size' => filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]];
|
||||||
|
|
||||||
|
// Document, secrey chat
|
||||||
|
$secret_media['document'] = ['peer' => $secret, 'file' => $inputEncryptedFileDocument, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'key' => $inputEncryptedFileDocument['key'], 'iv' => $inputEncryptedFileDocument['iv'], 'file_name' => 'magic.magic', 'size' => filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]];
|
||||||
|
|
||||||
|
// Video, secret chat
|
||||||
|
$secret_media['video'] = ['peer' => $secret, 'file' => $inputEncryptedFileVideo, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'key' => $inputEncryptedFileVideo['key'], 'iv' => $inputEncryptedFileVideo['iv'], 'file_name' => 'swing.mp4', 'size' => filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo', 'duration' => 5, 'w' => 1280, 'h' => 720]]]]];
|
||||||
|
|
||||||
|
// audio, secret chat
|
||||||
|
$secret_media['audio'] = ['peer' => $secret, 'file' => $inputEncryptedFileAudio, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'key' => $inputEncryptedFileAudio['key'], 'iv' => $inputEncryptedFileAudio['iv'], 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'duration' => 1, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
||||||
|
|
||||||
|
$secret_media['voice'] = ['peer' => $secret, 'file' => $inputEncryptedFileAudio, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'key' => $inputEncryptedFileAudio['key'], 'iv' => $inputEncryptedFileAudio['iv'], 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'duration' => 1, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
|
||||||
|
|
||||||
|
foreach ($secret_media as $type => $smessage) {
|
||||||
|
$type = $MadelineProto->messages->sendEncryptedFile($smessage);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'updateNewMessage':
|
case 'updateNewMessage':
|
||||||
include 'songs.php';
|
include 'songs.php';
|
||||||
if ($update['update']['message']['out'] || $update['update']['message']['to_id']['_'] !== 'peerUser' || !isset($update['update']['message']['from_id'])) {
|
if ($update['update']['message']['out'] || $update['update']['message']['to_id']['_'] !== 'peerUser' || !isset($update['update']['message']['from_id'])) {
|
||||||
@ -232,5 +271,4 @@ Propic art by @magnaluna on deviantart.", 'parse_mode' => 'Markdown']);
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $MadelineProto).' bytes'.PHP_EOL;
|
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ while (true) {
|
|||||||
/*case 'updateNewChannelMessage':
|
/*case 'updateNewChannelMessage':
|
||||||
if ($update['update']['message']['out'] || $update['update']['message']['message'] === '') continue;
|
if ($update['update']['message']['out'] || $update['update']['message']['message'] === '') continue;
|
||||||
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $update['update']['message']['message']]);
|
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $update['update']['message']['message']]);
|
||||||
break;*/
|
break;
|
||||||
case 'updateNewMessage':
|
case 'updateNewMessage':
|
||||||
if ($update['update']['message']['out'] || $update['update']['message']['message'] === '') {
|
if ($update['update']['message']['out'] || $update['update']['message']['message'] === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;*/
|
||||||
case 'updateNewEncryptedMessage':
|
case 'updateNewEncryptedMessage':
|
||||||
//var_dump($MadelineProto->download_to_dir($update['update']['message'], '.'));
|
//var_dump($MadelineProto->download_to_dir($update['update']['message'], '.'));
|
||||||
if (isset($sent[$update['update']['message']['chat_id']])) {
|
if (isset($sent[$update['update']['message']['chat_id']])) {
|
||||||
|
@ -21,6 +21,7 @@ class API extends APIFactory
|
|||||||
public function ___construct($params = [])
|
public function ___construct($params = [])
|
||||||
{
|
{
|
||||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||||
|
set_exception_handler(['\danog\MadelineProto\Serialization', 'serialize_all']);
|
||||||
if (is_string($params)) {
|
if (is_string($params)) {
|
||||||
if (file_exists($params)) {
|
if (file_exists($params)) {
|
||||||
$this->session = $params;
|
$this->session = $params;
|
||||||
@ -68,6 +69,7 @@ class API extends APIFactory
|
|||||||
$this->API = $unserialized->API;
|
$this->API = $unserialized->API;
|
||||||
$this->APIFactory();
|
$this->APIFactory();
|
||||||
}
|
}
|
||||||
|
Serialization::$instances[spl_object_hash($unserialized)] = $unserialized;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -82,11 +84,16 @@ class API extends APIFactory
|
|||||||
//\danog\MadelineProto\Logger::log(['Getting future salts...'], Logger::ULTRA_VERBOSE);
|
//\danog\MadelineProto\Logger::log(['Getting future salts...'], Logger::ULTRA_VERBOSE);
|
||||||
//$this->future_salts = $this->get_future_salts(['num' => 3]);
|
//$this->future_salts = $this->get_future_salts(['num' => 3]);
|
||||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['madelineproto_ready']], Logger::NOTICE);
|
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['madelineproto_ready']], Logger::NOTICE);
|
||||||
|
|
||||||
|
Serialization::$instances[spl_object_hash($this)] = $this;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
//if (method_exists($this->API, 'wakeup')) $this->API = $this->API->wakeup();
|
//if (method_exists($this->API, 'wakeup')) $this->API = $this->API->wakeup();
|
||||||
|
Serialization::$instances[spl_object_hash($this)] = $this;
|
||||||
|
|
||||||
$this->APIFactory();
|
$this->APIFactory();
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class MTProto
|
|||||||
/*
|
/*
|
||||||
const V = 71;
|
const V = 71;
|
||||||
*/
|
*/
|
||||||
const V = 80;
|
const V = 82;
|
||||||
|
|
||||||
const NOT_LOGGED_IN = 0;
|
const NOT_LOGGED_IN = 0;
|
||||||
const WAITING_CODE = 1;
|
const WAITING_CODE = 1;
|
||||||
@ -219,9 +219,6 @@ class MTProto
|
|||||||
$this->rsa_keys[$key->fp] = $key;
|
$this->rsa_keys[$key->fp] = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Istantiate TL class
|
|
||||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['TL_translation']], Logger::ULTRA_VERBOSE);
|
|
||||||
$this->construct_TL($this->settings['tl_schema']['src']);
|
|
||||||
/*
|
/*
|
||||||
* ***********************************************************************
|
* ***********************************************************************
|
||||||
* Define some needed numbers for BigInteger
|
* Define some needed numbers for BigInteger
|
||||||
@ -237,9 +234,15 @@ class MTProto
|
|||||||
$this->twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328');
|
$this->twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328');
|
||||||
$this->twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656');
|
$this->twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656');
|
||||||
|
|
||||||
|
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['TL_translation']], Logger::ULTRA_VERBOSE);
|
||||||
|
$this->construct_TL($this->settings['tl_schema']['src']);
|
||||||
|
|
||||||
|
// Istantiate TL class
|
||||||
$this->connect_to_all_dcs();
|
$this->connect_to_all_dcs();
|
||||||
$this->datacenter->curdc = 2;
|
$this->datacenter->curdc = 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) {
|
if (!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) {
|
||||||
try {
|
try {
|
||||||
$nearest_dc = $this->method_call('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]);
|
$nearest_dc = $this->method_call('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -269,6 +272,8 @@ class MTProto
|
|||||||
public function __wakeup()
|
public function __wakeup()
|
||||||
{
|
{
|
||||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||||
|
set_exception_handler(['\danog\MadelineProto\Serialization', 'serialize_all']);
|
||||||
|
|
||||||
$this->setup_logger();
|
$this->setup_logger();
|
||||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||||
return;
|
return;
|
||||||
@ -319,7 +324,9 @@ class MTProto
|
|||||||
foreach ($this->channels_state as $key => $state) {
|
foreach ($this->channels_state as $key => $state) {
|
||||||
$this->channels_state[$key]['sync_loading'] = false;
|
$this->channels_state[$key]['sync_loading'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$force = false;
|
$force = false;
|
||||||
|
|
||||||
$this->reset_session();
|
$this->reset_session();
|
||||||
if (!isset($this->v) || $this->v !== self::V) {
|
if (!isset($this->v) || $this->v !== self::V) {
|
||||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['serialization_ofd']], Logger::WARNING);
|
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['serialization_ofd']], Logger::WARNING);
|
||||||
@ -334,6 +341,13 @@ class MTProto
|
|||||||
foreach ($this->full_chats as $id => $full) {
|
foreach ($this->full_chats as $id => $full) {
|
||||||
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
|
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
|
||||||
}
|
}
|
||||||
|
foreach ($this->secret_chats as $key => &$chat) {
|
||||||
|
if ($chat['layer'] >= 73) {
|
||||||
|
$chat['mtproto'] = 2;
|
||||||
|
} else {
|
||||||
|
$chat['mtproto'] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach ($settings['connection_settings'] as $key => &$connection) {
|
foreach ($settings['connection_settings'] as $key => &$connection) {
|
||||||
if (!is_array($connection)) {
|
if (!is_array($connection)) {
|
||||||
continue;
|
continue;
|
||||||
@ -353,6 +367,11 @@ class MTProto
|
|||||||
$this->dh_config = ['version' => 0];
|
$this->dh_config = ['version' => 0];
|
||||||
$this->__construct($settings);
|
$this->__construct($settings);
|
||||||
$force = true;
|
$force = true;
|
||||||
|
foreach ($this->secret_chats as $chat => $data) {
|
||||||
|
try {
|
||||||
|
if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== NULL) $this->notify_layer($chat);
|
||||||
|
} catch (\danog\MadelineProto\RPCErrorException $e) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!$this->settings['updates']['handle_old_updates']) {
|
if (!$this->settings['updates']['handle_old_updates']) {
|
||||||
$this->channels_state = [];
|
$this->channels_state = [];
|
||||||
|
@ -14,9 +14,9 @@ namespace danog\MadelineProto\MTProtoTools;
|
|||||||
|
|
||||||
trait Crypt
|
trait Crypt
|
||||||
{
|
{
|
||||||
public function aes_calculate($msg_key, $auth_key, $direction = 'to server')
|
public function aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||||
{
|
{
|
||||||
$x = ($direction === 'to server') ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha256_a = hash('sha256', $msg_key.substr($auth_key, $x, 36), true);
|
$sha256_a = hash('sha256', $msg_key.substr($auth_key, $x, 36), true);
|
||||||
$sha256_b = hash('sha256', substr($auth_key, 40 + $x, 36).$msg_key, true);
|
$sha256_b = hash('sha256', substr($auth_key, 40 + $x, 36).$msg_key, true);
|
||||||
$aes_key = substr($sha256_a, 0, 8).substr($sha256_b, 8, 16).substr($sha256_a, 24, 8);
|
$aes_key = substr($sha256_a, 0, 8).substr($sha256_b, 8, 16).substr($sha256_a, 24, 8);
|
||||||
@ -25,9 +25,9 @@ trait Crypt
|
|||||||
return [$aes_key, $aes_iv];
|
return [$aes_key, $aes_iv];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function old_aes_calculate($msg_key, $auth_key, $direction = 'to server')
|
public function old_aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||||
{
|
{
|
||||||
$x = ($direction === 'to server') ? 0 : 8;
|
$x = $to_server ? 0 : 8;
|
||||||
$sha1_a = sha1($msg_key.substr($auth_key, $x, 32), true);
|
$sha1_a = sha1($msg_key.substr($auth_key, $x, 32), true);
|
||||||
$sha1_b = sha1(substr($auth_key, 32 + $x, 16).$msg_key.substr($auth_key, 48 + $x, 16), true);
|
$sha1_b = sha1(substr($auth_key, 32 + $x, 16).$msg_key.substr($auth_key, 48 + $x, 16), true);
|
||||||
$sha1_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true);
|
$sha1_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true);
|
||||||
|
@ -74,7 +74,7 @@ trait MessageHandler
|
|||||||
} elseif ($auth_key_id === $this->datacenter->sockets[$datacenter]->temp_auth_key['id']) {
|
} elseif ($auth_key_id === $this->datacenter->sockets[$datacenter]->temp_auth_key['id']) {
|
||||||
$message_key = substr($payload, 8, 16);
|
$message_key = substr($payload, 8, 16);
|
||||||
$encrypted_data = substr($payload, 24);
|
$encrypted_data = substr($payload, 24);
|
||||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], 'from server');
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], false);
|
||||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
/*
|
/*
|
||||||
$server_salt = substr($decrypted_data, 0, 8);
|
$server_salt = substr($decrypted_data, 0, 8);
|
||||||
|
@ -41,7 +41,7 @@ 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]];
|
$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];
|
||||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||||
$this->check_G($g_b, $dh_config['p']);
|
$this->check_G($g_b, $dh_config['p']);
|
||||||
$this->method_call('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
$this->method_call('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
@ -96,7 +96,7 @@ 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]];
|
$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->notify_layer($params['id']);
|
$this->notify_layer($params['id']);
|
||||||
$this->handle_pending_updates();
|
$this->handle_pending_updates();
|
||||||
\danog\MadelineProto\Logger::log(['Secret chat '.$params['id'].' completed successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
\danog\MadelineProto\Logger::log(['Secret chat '.$params['id'].' completed successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
@ -168,7 +168,8 @@ trait AuthKeyHandler
|
|||||||
|
|
||||||
public function commit_rekey($chat, $params)
|
public function commit_rekey($chat, $params)
|
||||||
{
|
{
|
||||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 1) {
|
if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) {
|
||||||
|
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
\danog\MadelineProto\Logger::log(['Committing rekeying of secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
|
\danog\MadelineProto\Logger::log(['Committing rekeying of secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||||
|
@ -37,10 +37,21 @@ trait MessageHandler
|
|||||||
$message = $this->serialize_object(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
$message = $this->serialize_object(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']);
|
||||||
$message = $this->pack_unsigned_int(strlen($message)).$message;
|
$message = $this->pack_unsigned_int(strlen($message)).$message;
|
||||||
|
|
||||||
$message_key = substr(sha1($message, true), -16);
|
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
||||||
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], 'to server');
|
$padding = $this->posmod(-strlen($message), 16);
|
||||||
|
if ($padding < 12) {
|
||||||
|
$padding += 16;
|
||||||
|
}
|
||||||
|
$message .= $this->random($padding);
|
||||||
|
|
||||||
$message .= $this->random($this->posmod(-strlen($message), 16));
|
$message_key = substr(hash('sha256', substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16);
|
||||||
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
|
||||||
|
} else {
|
||||||
|
$message_key = substr(sha1($message, true), -16);
|
||||||
|
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
|
||||||
|
|
||||||
|
$message .= $this->random($this->posmod(-strlen($message), 16));
|
||||||
|
}
|
||||||
|
|
||||||
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv);
|
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv);
|
||||||
|
|
||||||
@ -57,7 +68,6 @@ trait MessageHandler
|
|||||||
$auth_key_id = substr($message['message']['bytes'], 0, 8);
|
$auth_key_id = substr($message['message']['bytes'], 0, 8);
|
||||||
$old = false;
|
$old = false;
|
||||||
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) {
|
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) {
|
||||||
//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 (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']) {
|
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) {
|
||||||
$this->discard_secret_chat($message['message']['chat_id']);
|
$this->discard_secret_chat($message['message']['chat_id']);
|
||||||
@ -71,26 +81,35 @@ trait MessageHandler
|
|||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$message_key = substr($message['message']['bytes'], 8, 16);
|
$message_key = substr($message['message']['bytes'], 8, 16);
|
||||||
$encrypted_data = substr($message['message']['bytes'], 24);
|
$encrypted_data = substr($message['message']['bytes'], 24);
|
||||||
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$message['message']['chat_id']][$old ? 'old_key' : 'key']['auth_key'], 'to server');
|
|
||||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
||||||
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
\danog\MadelineProto\Logger::log(['Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
if ($message_data_length > strlen($decrypted_data)) {
|
try {
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
$message_data = $this->try_mtproto_v2_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v2 decryption failed with message '.$e->getMessage().', trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
$message_data = $this->try_mtproto_v1_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
\danog\MadelineProto\Logger::log(['Trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
try {
|
||||||
|
$message_data = $this->try_mtproto_v1_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v1 decryption failed with message '.$e->getMessage().', trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
$message_data = $this->try_mtproto_v2_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
|
||||||
|
\danog\MadelineProto\Logger::log(['MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||||
|
|
||||||
|
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((strlen($decrypted_data) - 4) - $message_data_length > 15) {
|
|
||||||
throw new \danog\MadelineProto\SecurityException('difference between message_data_length and the length of the remaining decrypted buffer is too big');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($decrypted_data) % 16 != 0) {
|
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
|
||||||
}
|
|
||||||
$message_data = substr($decrypted_data, 4, $message_data_length);
|
|
||||||
if ($message_key != substr(sha1(substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) {
|
|
||||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
|
||||||
}
|
|
||||||
$deserialized = $this->deserialize($message_data, ['type' => '']);
|
$deserialized = $this->deserialize($message_data, ['type' => '']);
|
||||||
$this->secret_chats[$message['message']['chat_id']]['ttr']--;
|
$this->secret_chats[$message['message']['chat_id']]['ttr']--;
|
||||||
if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) {
|
if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) {
|
||||||
@ -98,12 +117,58 @@ trait MessageHandler
|
|||||||
}
|
}
|
||||||
unset($message['message']['bytes']);
|
unset($message['message']['bytes']);
|
||||||
$message['message']['decrypted_message'] = $deserialized;
|
$message['message']['decrypted_message'] = $deserialized;
|
||||||
if ($test = true) {
|
|
||||||
//var_dump($message);
|
|
||||||
}
|
|
||||||
$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'];
|
||||||
|
|
||||||
//var_dump($message);
|
|
||||||
$this->handle_decrypted_update($message);
|
$this->handle_decrypted_update($message);
|
||||||
}
|
}
|
||||||
|
public function try_mtproto_v1_decrypt($message_key, $chat_id, $old, $encrypted_data) {
|
||||||
|
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
|
||||||
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
|
|
||||||
|
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
||||||
|
$message_data = substr($decrypted_data, 4, $message_data_length);
|
||||||
|
if ($message_data_length > strlen($decrypted_data)) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($message_key != substr(sha1(substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
||||||
|
}
|
||||||
|
if ((strlen($decrypted_data) - 4) - $message_data_length > 15) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException('difference between message_data_length and the length of the remaining decrypted buffer is too big');
|
||||||
|
}
|
||||||
|
if (strlen($decrypted_data) % 16 != 0) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $message_data;
|
||||||
|
}
|
||||||
|
public function try_mtproto_v2_decrypt($message_key, $chat_id, $old, $encrypted_data) {
|
||||||
|
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
|
||||||
|
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||||
|
|
||||||
|
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
||||||
|
$message_data = substr($decrypted_data, 4, $message_data_length);
|
||||||
|
if ($message_data_length > strlen($decrypted_data)) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($message_key != substr(hash('sha256', substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strlen($decrypted_data) - 4) - $message_data_length < 12) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException('padding is too small');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strlen($decrypted_data) - 4) - $message_data_length > 1024) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException('padding is too big');
|
||||||
|
}
|
||||||
|
if (strlen($decrypted_data) % 16 != 0) {
|
||||||
|
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $message_data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ trait ResponseHandler
|
|||||||
if ($update['message']['decrypted_message']['action']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
if ($update['message']['decrypted_message']['action']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) {
|
||||||
$this->notify_layer($update['message']['chat_id']);
|
$this->notify_layer($update['message']['chat_id']);
|
||||||
}
|
}
|
||||||
|
if ($update['message']['decrypted_message']['action']['layer'] >= 73) $this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -53,12 +54,20 @@ trait ResponseHandler
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 'decryptedMessageActionNoop':
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
case 'decryptedMessageActionResend':
|
case 'decryptedMessageActionResend':
|
||||||
|
$update['message']['decrypted_message']['action']['start_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
||||||
|
$update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
|
||||||
|
$update['message']['decrypted_message']['action']['start_seq_no'] /= 2;
|
||||||
|
$update['message']['decrypted_message']['action']['end_seq_no'] /= 2;
|
||||||
|
\danog\MadelineProto\Logger::log(['Resending messages for secret chat '.$update['message']['chat_id']], \danog\MadelineProto\Logger::WARNING);
|
||||||
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
|
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
|
||||||
$seq--;
|
|
||||||
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
|
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
|
||||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
|
//throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
|
||||||
// $this->send_encrypted_message($update['message']['chat_id'], $update['message']['decrypted_message']);
|
$this->method_call('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ namespace danog\MadelineProto;
|
|||||||
*/
|
*/
|
||||||
class Serialization
|
class Serialization
|
||||||
{
|
{
|
||||||
|
static public $instances = [];
|
||||||
|
static public function serialize_all($exception) {
|
||||||
|
echo $exception.PHP_EOL;
|
||||||
|
foreach (self::$instances as $instance) { if (isset($instance->session)) $instance->serialize(); }
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Serialize API class.
|
* Serialize API class.
|
||||||
*
|
*
|
||||||
@ -26,7 +31,7 @@ class Serialization
|
|||||||
*
|
*
|
||||||
* @return number
|
* @return number
|
||||||
*/
|
*/
|
||||||
public static function serialize($filename, $instance, $force = false)
|
static public function serialize($filename, $instance, $force = false)
|
||||||
{
|
{
|
||||||
if (isset($instance->API->setdem) && $instance->API->setdem) {
|
if (isset($instance->API->setdem) && $instance->API->setdem) {
|
||||||
$instance->API->setdem = false;
|
$instance->API->setdem = false;
|
||||||
@ -56,7 +61,7 @@ class Serialization
|
|||||||
*
|
*
|
||||||
* @return API
|
* @return API
|
||||||
*/
|
*/
|
||||||
public static function deserialize($filename, $no_updates = false)
|
static public function deserialize($filename, $no_updates = false)
|
||||||
{
|
{
|
||||||
if (file_exists($filename)) {
|
if (file_exists($filename)) {
|
||||||
if (!file_exists($lock = $filename.'.lock')) {
|
if (!file_exists($lock = $filename.'.lock')) {
|
||||||
@ -102,6 +107,7 @@ class Serialization
|
|||||||
if ($unserialized instanceof \danog\MadelineProto\API) {
|
if ($unserialized instanceof \danog\MadelineProto\API) {
|
||||||
$unserialized->session = $filename;
|
$unserialized->session = $filename;
|
||||||
}
|
}
|
||||||
|
self::$instances[spl_object_hash($unserialized)] = $unserialized;
|
||||||
|
|
||||||
return $unserialized;
|
return $unserialized;
|
||||||
}
|
}
|
||||||
|
@ -183,11 +183,6 @@ trait TL
|
|||||||
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->encrypted_layer != $orig && isset($this->secret_chats)) {
|
|
||||||
foreach ($this->secret_chats as $chat => $data) {
|
|
||||||
$this->notify_layer($chat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (isset($files['td']) && isset($files['telegram'])) {
|
if (isset($files['td']) && isset($files['telegram'])) {
|
||||||
foreach ($this->td_constructors->by_id as $id => $data) {
|
foreach ($this->td_constructors->by_id as $id => $data) {
|
||||||
|
@ -71,3 +71,6 @@ documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = Docume
|
|||||||
|
|
||||||
===66===
|
===66===
|
||||||
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
|
||||||
|
|
||||||
|
===73===
|
||||||
|
decryptedMessage#91cc4674 flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector<MessageEntity> via_bot_name:flags.11?string reply_to_random_id:flags.3?long grouped_id:flags.17?long = DecryptedMessage;
|
||||||
|
Loading…
Reference in New Issue
Block a user