Apply fixes from StyleCI

This commit is contained in:
Daniil Gentili 2017-03-11 18:55:56 +00:00 committed by StyleCI Bot
parent dfd8bf93da
commit f53927d3a7
20 changed files with 396 additions and 167 deletions

View File

@ -101,9 +101,11 @@ while (true) {
} else {
array_walk($rows, function (&$value, $key) {
$value = explode('|', $value);
array_walk($value, function (&$value, $key) { $value = ['text' => trim($value)]; });
array_walk($value, function (&$value, $key) {
$value = ['text' => trim($value)];
});
$toset['results'] = [['_' => 'inputBotInlineResult', 'id' => rand(0, pow(2,31)-1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]];
});
$toset['results'] = [['_' => 'inputBotInlineResult', 'id' => rand(0, pow(2, 31) - 1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]];
$MadelineProto->messages->setInlineBotResults($toset);
}
}

View File

@ -38,7 +38,7 @@ $docs = [
'readme' => false,
],
[
'tl_schema' => ['telegram' => __DIR__.'/src/danog/MadelineProto/TL_telegram_v62.tl', 'secret' => __DIR__.'/src/danog/MadelineProto/TL_secret.tl','td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'],
'tl_schema' => ['telegram' => __DIR__.'/src/danog/MadelineProto/TL_telegram_v62.tl', 'secret' => __DIR__.'/src/danog/MadelineProto/TL_secret.tl', 'td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'],
'title' => 'MadelineProto API documentation (layer 62)',
'description' => 'MadelineProto API documentation (layer 62)',
'output_dir' => __DIR__.'/docs/API_docs',

View File

@ -97,6 +97,7 @@ trait BotAPI
foreach ($data as $key => $element) {
$newd[$key] = $this->MTProto_to_botAPI($element, $sent_arguments);
}
return $newd;
}
switch ($data['_']) {
@ -450,5 +451,4 @@ trait BotAPI
return $arguments;
}
}

View File

@ -59,6 +59,7 @@ trait BotAPIFiles
$new .= $cur;
}
}
return $new;
}
@ -146,7 +147,6 @@ trait BotAPIFiles
return $res;
case 9:
$constructor = ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]];
list($type, $constructor['dc_id'], $constructor['id'], $constructor['access_hash'], $verify) = \danog\PHP\Struct::unpack('<iiqqb', $file_id);

View File

@ -38,7 +38,7 @@ trait TD
'via_bot_user_id' => ['via_bot_id'],
'views' => ['views'],
'content' => ['choose_message_content'],
'reply_markup' => ['reply_markup']
'reply_markup' => ['reply_markup'],
],
'messages.sendMessage' => [
@ -47,17 +47,25 @@ trait TD
'disable_notification' => ['silent'],
'from_background' => ['background'],
'input_message_content' => ['choose_message_content'],
'reply_markup' => ['reply_markup']
]
'reply_markup' => ['reply_markup'],
],
];
private $reverse = [
'sendMessage'=> 'messages.sendMessage',
];
private $ignore = ['updateMessageID'];
public function tdcli_to_td(&$params, $key=null) {
if (!is_array($params)) return $params;
if (!isset($params['ID'])) { array_walk($params, [$this, 'tdcli_to_td']); return $params; }
public function tdcli_to_td(&$params, $key = null)
{
if (!is_array($params)) {
return $params;
}
if (!isset($params['ID'])) {
array_walk($params, [$this, 'tdcli_to_td']);
return $params;
}
foreach ($params as $key => $value) {
$value = $this->tdcli_to_td($value);
if (preg_match('/_$/', $key)) {
@ -67,9 +75,12 @@ trait TD
}
$params['_'] = lcfirst($params['ID']);
unset($params['ID']);
return $params;
}
public function td_to_mtproto($params) {
public function td_to_mtproto($params)
{
$newparams = ['_' => $this->reverse[$params['_']]];
foreach ($this->td_params_conversion[$newparams['_']] as $td => $mtproto) {
@ -79,28 +90,45 @@ trait TD
switch ($params[$td]['_']) {
case 'inputMessageText':
$params[$td]['_'] = 'messages.sendMessage';
if (isset($params['disable_web_page_preview'])) $newparams['no_webpage'] = $params[$td]['disable_web_page_preview'];
$newparams = array_merge($params[$td],$newparams);
if (isset($params['disable_web_page_preview'])) {
$newparams['no_webpage'] = $params[$td]['disable_web_page_preview'];
}
$newparams = array_merge($params[$td], $newparams);
break;
default: throw new Exception("Can't convert non text messages yet!");
}
break;
default:
$newparams[$mtproto[0]] = isset($params[$td]) ? $params[$td] : null;
if (is_array($newparams[$mtproto[0]])) $newparams[$mtproto[0]] = $this->mtproto_to_td($newparams[$mtproto[0]]);
if (is_array($newparams[$mtproto[0]])) {
$newparams[$mtproto[0]] = $this->mtproto_to_td($newparams[$mtproto[0]]);
}
}
}
}
return $newparams;
}
public function mtproto_to_tdcli($params) {
public function mtproto_to_tdcli($params)
{
return $this->td_to_tdcli($this->mtproto_to_td($params));
}
public function mtproto_to_td(&$params) {
if (!is_array($params)) return $params;
if (!isset($params['_'])) { array_walk($params, [$this, 'mtproto_to_td']); return $params; }
public function mtproto_to_td(&$params)
{
if (!is_array($params)) {
return $params;
}
if (!isset($params['_'])) {
array_walk($params, [$this, 'mtproto_to_td']);
return $params;
}
$newparams = ['_' => $params['_']];
if (in_array($params['_'], $this->ignore)) return $params;
if (in_array($params['_'], $this->ignore)) {
return $params;
}
foreach ($this->td_params_conversion[$params['_']] as $td => $mtproto) {
if (is_string($mtproto)) {
$newparams[$td] = $mtproto;
@ -121,11 +149,19 @@ trait TD
case 'choose_forward_info':
if (isset($params['fwd_from'])) {
$newparams[$td] = ['_' => 'messageForwardedFromUser'];
if (isset($params['fwd_from']['channel_id'])) $newparams[$td] = ['_'=> 'messageForwardedPost', 'chat_id' => '-100'.$params['fwd_from']['channel_id']];
if (isset($params['fwd_from']['channel_id'])) {
$newparams[$td] = ['_'=> 'messageForwardedPost', 'chat_id' => '-100'.$params['fwd_from']['channel_id']];
}
$newparams[$td]['date'] = $params['fwd_from']['date'];
if (isset($params['fwd_from']['channel_post'])) $newparams[$td]['channel_post'] = $params['fwd_from']['channel_post'];
if (isset($params['fwd_from']['from_id'])) $newparams[$td]['sender_user_id'] = $params['fwd_from']['from_id'];
} else $newparams[$td] = null;
if (isset($params['fwd_from']['channel_post'])) {
$newparams[$td]['channel_post'] = $params['fwd_from']['channel_post'];
}
if (isset($params['fwd_from']['from_id'])) {
$newparams[$td]['sender_user_id'] = $params['fwd_from']['from_id'];
}
} else {
$newparams[$td] = null;
}
break;
case 'choose_ttl':
$newparams[$td] = isset($params['ttl']) ? $params['ttl'] : 0;
@ -136,9 +172,15 @@ trait TD
case 'choose_message_content':
if ($params['message'] !== '') {
$newparams[$td] = ['_' => 'messageText', 'text' => $params['message']];
if (isset($params['media']['_']) && $params['media']['_'] === 'messageMediaWebPage') $newparams[$td]['web_page'] = $this->mtproto_to_td($params['media']['webpage']);
if (isset($params['entities'])) $newparams[$td]['entities'] = $params['entities'];
} else throw new Exception("Can't convert non text messages yet!");
if (isset($params['media']['_']) && $params['media']['_'] === 'messageMediaWebPage') {
$newparams[$td]['web_page'] = $this->mtproto_to_td($params['media']['webpage']);
}
if (isset($params['entities'])) {
$newparams[$td]['entities'] = $params['entities'];
}
} else {
throw new Exception("Can't convert non text messages yet!");
}
break;
default:
if (isset($mtproto[1])) {
@ -146,24 +188,33 @@ trait TD
} else {
$newparams[$td] = isset($params[$mtproto[0]]) ? $params[$mtproto[0]] : null;
}
if (is_array($newparams[$td])) $newparams[$td] = $this->mtproto_to_td($newparams[$td]);
if (is_array($newparams[$td])) {
$newparams[$td] = $this->mtproto_to_td($newparams[$td]);
}
}
}
}
return $newparams;
}
public function td_to_tdcli($params) {
if (!is_array($params)) return $params;
public function td_to_tdcli($params)
{
if (!is_array($params)) {
return $params;
}
$newparams = [];
foreach ($params as $key => $value) {
if ($key === '_') {
$newparams['ID'] = ucfirst($value);
} else {
if (!is_numeric($key) && !preg_match('/_^/', $key)) $key = $key.'_';
if (!is_numeric($key) && !preg_match('/_^/', $key)) {
$key = $key.'_';
}
$newparams[$key] = $this->td_to_tdcli($value);
}
}
return $newparams;
}
}

View File

@ -20,8 +20,12 @@ class DocsBuilder
{
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
$this->construct_TL($settings['tl_schema']);
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) $this->constructors = $this->td_constructors;
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) $this->methods = $this->td_methods;
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) {
$this->constructors = $this->td_constructors;
}
if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) {
$this->methods = $this->td_methods;
}
$this->settings = $settings;
if (!file_exists($this->settings['output_dir'])) {
mkdir($this->settings['output_dir']);
@ -155,7 +159,7 @@ description: '.$this->settings['description'].'
$params .= "'".$param['name']."' => ";
$params .= (isset($param['subtype']) ? '['.$ptype.']' : $ptype).', ';
$lua_params .= $param['name']."=";
$lua_params .= $param['name'].'=';
$lua_params .= (isset($param['subtype']) ? '{'.$ptype.'}' : $ptype).', ';
if ($param['name'] === 'entities') {
$hasentities = true;
@ -389,7 +393,7 @@ description: List of methods
$params .= "'".$param['name']."' => ";
$params .= (isset($param['subtype']) ? '['.$param['subtype'].']' : $param['type']).', ';
$lua_params .= $param['name']."=";
$lua_params .= $param['name'].'=';
$lua_params .= (isset($param['subtype']) ? '{'.$param['subtype'].'}' : $param['type']).', ';
}
$params = "['_' => '".$rconstructor."', ".$params.']';
@ -531,11 +535,11 @@ $".$type." = 'channel#38575794'; // tg-cli style id (channels)
$header .= 'The following syntax can also be used:
```
$'.$type." = -147286699; // Numeric chat id returned by request_secret_chat, can be positive or negative
$'.$type.' = -147286699; // Numeric chat id returned by request_secret_chat, can be positive or negative
```
";
';
}
$constructors = '### Possible values (constructors):

View File

@ -18,8 +18,11 @@ class Lua
private $Lua;
private $script;
public function __construct($script, $MadelineProto) {
if (!file_exists($script)) throw new Exception('Provided script does not exist');
public function __construct($script, $MadelineProto)
{
if (!file_exists($script)) {
throw new Exception('Provided script does not exist');
}
$this->MadelineProto = $MadelineProto;
$settings = $this->MadelineProto->get_settings();
$settings['updates']['handle_updates'] = true;
@ -27,8 +30,14 @@ class Lua
$this->script = $script;
$this->__wakeup();
}
public function __sleep() { return ['MadelineProto', 'script']; }
public function __wakeup() {
public function __sleep()
{
return ['MadelineProto', 'script'];
}
public function __wakeup()
{
$this->Lua = new \Lua($this->script);
$this->madelineproto_lua = 1;
$this->Lua->registerCallback('tdcli_function', [$this, 'tdcli_function']);
@ -45,37 +54,73 @@ class Lua
$this->{$namespace} = $methods[$namespace];
}
}
public function tdcli_function ($params, $cb = null, $cb_extra = null) {
public function tdcli_function($params, $cb = null, $cb_extra = null)
{
$params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcli_to_td($params));
if ($params === 0) return 0;
if ($params === 0) {
return 0;
}
$result = $this->MadelineProto->API->method_call($params['_'], $params);
if (is_callable($cb)) $cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
if (is_callable($cb)) {
$cb($this->MadelineProto->mtproto_to_td($result), $cb_extra);
}
return $result;
}
public function madeline_function ($params, $cb = null, $cb_extra = null) {
public function madeline_function($params, $cb = null, $cb_extra = null)
{
$result = $this->MadelineProto->API->method_call($params['_'], $params);
if (is_callable($cb)) $cb($result, $cb_extra);
if (is_callable($cb)) {
$cb($result, $cb_extra);
}
return $result;
}
public function tdcli_update_callback($update) {
public function tdcli_update_callback($update)
{
$this->Lua->tdcli_update_callback($this->MadelineProto->mtproto_to_tdcli($update));
}
private function convert_array($array) {
if (!is_array($value)) return $array;
if ($this->is_seqential($value)) return array_flip(array_map(function($el){ return $el + 1; }, array_flip($array)));
private function convert_array($array)
{
if (!is_array($value)) {
return $array;
}
if ($this->is_seqential($value)) {
return array_flip(array_map(function ($el) {
return $el + 1;
}, array_flip($array)));
}
}
private function is_sequential(array $arr)
{
if ([] === $arr) {
return false;
}
private function is_sequential(array $arr) {
if (array() === $arr) return false;
return isset($arr[0]) && array_keys($arr) === range(0, count($arr) - 1);
}
public function __get($name) {
if ($name === 'API') return $this->MadelineProto->API;
public function __get($name)
{
if ($name === 'API') {
return $this->MadelineProto->API;
}
return $this->Lua->{$name};
}
public function __call($name, $params) { return $this->Lua->{$name}(...$params); }
public function __set($name, $value) { return $this->Lua->{$name} = $value; }
public function __call($name, $params)
{
return $this->Lua->{$name}(...$params);
}
public function __set($name, $value)
{
return $this->Lua->{$name} = $value;
}
}

View File

@ -71,7 +71,6 @@ class MTProto
$this->twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328');
$this->twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656');
$this->switch_dc(2, true);
$this->get_config();
}
@ -387,7 +386,9 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
{
return 2;
}
public function get_self() {
public function get_self()
{
return $this->datacenter->authorization['user'];
}
}

View File

@ -414,7 +414,9 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\SecurityException('Auth Failed');
}
public function check_G($g_a, $p) {
public function check_G($g_a, $p)
{
/*
* ***********************************************************************
@ -437,7 +439,9 @@ trait AuthKeyHandler
return true;
}
public function check_p_g($p, $g) {
public function check_p_g($p, $g)
{
/*
* ***********************************************************************
* Check validity of dh_prime
@ -486,24 +490,32 @@ trait AuthKeyHandler
) {
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
}
return true;
}
public function get_dh_config() {
public function get_dh_config()
{
$this->getting_state = true;
$dh_config = $this->method_call('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0]);
$this->getting_state = false;
if ($dh_config['_'] === 'messages.dhConfigNotModified') {
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Logger::VERBOSE, ['DH configuration not modified']);
return $this->dh_config;
}
$dh_config['p'] = new \phpseclib\Math\BigInteger($dh_config['p'], 256);
$dh_config['g'] = new \phpseclib\Math\BigInteger($dh_config['g']);
$this->check_p_g($dh_config['p'], $dh_config['g']);
return $this->dh_config = $dh_config;
}
private $temp_requested_secret_chats = [];
private $secret_chats = [];
public function accept_secret_chat($params) {
public function accept_secret_chat($params)
{
$dh_config = $this->get_dh_config();
\danog\MadelineProto\Logger::log(['Generating b...'], \danog\MadelineProto\Logger::VERBOSE);
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
@ -518,9 +530,10 @@ trait AuthKeyHandler
$this->check_G($g_b, $dh_config['p']);
$this->notify_layer($params['id']);
$this->handle_pending_updates();
}
public function request_secret_chat($user) {
public function request_secret_chat($user)
{
$user = $this->get_info($user)['InputUser'];
\danog\MadelineProto\Logger::log(['Creating secret chat with '.$user['user_id'].'...'], \danog\MadelineProto\Logger::VERBOSE);
$dh_config = $this->get_dh_config();
@ -533,11 +546,15 @@ trait AuthKeyHandler
$this->temp_requested_secret_chats[$res['id']] = $a;
$this->handle_pending_updates();
$this->get_updates_difference();
return $res['id'];
}
public function complete_secret_chat($params) {
public function complete_secret_chat($params)
{
if ($this->secret_chat_status($params['id']) !== 1) {
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat '.$params['id']]);
return false;
}
$dh_config = $this->get_dh_config();
@ -556,12 +573,19 @@ trait AuthKeyHandler
$this->notify_layer($params['id']);
$this->handle_pending_updates();
}
public function notify_layer($chat) {
public function notify_layer($chat)
{
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]]);
}
private $temp_rekeyed_secret_chats = [];
public function rekey($chat) {
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) return;
public function rekey($chat)
{
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
return;
}
\danog\MadelineProto\Logger::log(['Rekeying secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
$dh_config = $this->get_dh_config();
\danog\MadelineProto\Logger::log(['Generating a...'], \danog\MadelineProto\Logger::VERBOSE);
@ -575,9 +599,12 @@ trait AuthKeyHandler
$this->secret_chats[$chat]['rekeying'] = [1, $e];
$this->handle_pending_updates();
$this->get_updates_difference();
return $e;
}
public function accept_rekey($chat, $params) {
public function accept_rekey($chat, $params)
{
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
$my = $this->temp_rekeyed_secret_chats[$this->secret_chats[$chat]['rekeying'][1]];
if ($my['exchange_id'] > $params['exchange_id']) {
@ -586,6 +613,7 @@ trait AuthKeyHandler
if ($my['exchange_id'] === $params['exchange_id']) {
$this->secret_chats[$chat]['rekeying'] = [0];
$this->rekey($chat);
return;
}
}
@ -606,10 +634,13 @@ trait AuthKeyHandler
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]]);
$this->handle_pending_updates();
$this->get_updates_difference();
}
public function commit_rekey($chat, $params) {
if ($this->secret_chats[$chat]['rekeying'][0] !== 1) return;
public function commit_rekey($chat, $params)
{
if ($this->secret_chats[$chat]['rekeying'][0] !== 1) {
return;
}
\danog\MadelineProto\Logger::log(['Committing rekeying of secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
$dh_config = $this->get_dh_config();
$params['g_b'] = new \phpseclib\Math\BigInteger($params['g_b'], 256);
@ -631,10 +662,13 @@ trait AuthKeyHandler
$this->handle_pending_updates();
$this->get_updates_difference();
}
public function complete_rekey($chat, $params) {
if ($this->secret_chats[$chat]['rekeying'][0] !== 2) return;
public function complete_rekey($chat, $params)
{
if ($this->secret_chats[$chat]['rekeying'][0] !== 2) {
return;
}
if ($this->temp_rekeyed_secret_chats['fingerprint'] !== $params['key_fingerprint']) {
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]]);
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
@ -647,14 +681,24 @@ trait AuthKeyHandler
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]]);
}
public function secret_chat_status($chat) {
if (isset($this->secret_chats[$chat])) return 2;
if (isset($this->temp_requested_secret_chats[$chat])) return 1;
public function secret_chat_status($chat)
{
if (isset($this->secret_chats[$chat])) {
return 2;
}
if (isset($this->temp_requested_secret_chats[$chat])) {
return 1;
}
return 0;
}
public function get_secret_chat($chat) {
public function get_secret_chat($chat)
{
return $this->secret_chats[$chat];
}
public function bind_temp_auth_key($expires_in)
{
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {

View File

@ -158,7 +158,9 @@ trait CallHandler
throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.' ('.$last_error.').');
}
public function object_call($object, $args = [], $aargs = ['message_id' => null, 'heavy' => false]) {
public function object_call($object, $args = [], $aargs = ['message_id' => null, 'heavy' => false])
{
if (!is_array($args)) {
throw new \danog\MadelineProto\Exception("Arguments aren't an array.");
}

View File

@ -13,7 +13,7 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto\MTProtoTools;
/**
* Manages upload and download of files
* Manages upload and download of files.
*/
trait Files
{
@ -46,7 +46,7 @@ trait Files
$key = $this->random(32);
$iv = $this->random(32);
$digest = hash('md5', $key.$iv, true);
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4)^substr($digest, 4, 4))[0];
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4) ^ substr($digest, 4, 4))[0];
$ige = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_IGE);
$ige->setIV($iv);
$ige->setKey($key);
@ -70,12 +70,15 @@ trait Files
$constructor['key'] = $key;
$constructor['key'] = $iv;
}
return $constructor;
}
public function upload_encrypted($file, $file_name = '', $cb = null)
{
return $this->upload($file, $file_name, $cb, true);
}
public function get_download_info($message_media)
{
if (is_string($message_media)) {
@ -99,7 +102,9 @@ trait Files
}
$res['name'] = $pathinfo['filename'];
}
if (isset($message_media['decrypted_message']['media']['mime_type'])) $res['mime'] = $message_media['decrypted_message']['media']['mime_type'];
if (isset($message_media['decrypted_message']['media']['mime_type'])) {
$res['mime'] = $message_media['decrypted_message']['media']['mime_type'];
}
if (isset($message_media['decrypted_message']['media']['attributes'])) {
foreach ($message_media['decrypted_message']['media']['attributes'] as $attribute) {
switch ($attribute['_']) {
@ -128,6 +133,7 @@ trait Files
if (!isset($res['name'])) {
$res['name'] = $message_media['file']['access_hash'];
}
return $res;
case 'messageMediaPhoto':
$photo = end($message_media['photo']['sizes']);
@ -245,8 +251,10 @@ trait Files
}
if (isset($info['key'])) {
$digest = hash('md5', $info['key'].$info['iv'], true);
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4)^substr($digest, 4, 4))[0];
if ($fingerprint !== $info['key_fingerprint']) throw new \danog\MadelineProto\Exception('Fingerprint mismatch!');
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4) ^ substr($digest, 4, 4))[0];
if ($fingerprint !== $info['key_fingerprint']) {
throw new \danog\MadelineProto\Exception('Fingerprint mismatch!');
}
$ige = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_IGE);
$ige->setIV($info['iv']);
$ige->setKey($info['key']);

View File

@ -129,15 +129,18 @@ trait MessageHandler
$this->datacenter->new_incoming[$message_id] = $message_id;
$this->handle_messages();
}
public function encrypt_secret_message($chat_id, $message) {
public function encrypt_secret_message($chat_id, $message)
{
if (!isset($this->secret_chats[$chat_id])) {
\danog\MadelineProto\Logger::log('I do not have the secret chat '.$chat_id.' in the database, skipping message...');
return false;
}
$message = $this->serialize_object(['type' => $message['_']], $message, $this->secret_chats[$chat_id]['layer']);
$this->secret_chats[$chat_id]['outgoing'][] = $message;
$this->secret_chats[$chat_id]['ttr']--;
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) {
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) {
$this->rekey($chat_id);
}
@ -146,15 +149,21 @@ trait MessageHandler
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], 'to server');
$padding = $this->random($this->posmod(-strlen($message), 16));
$message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message.$padding, $aes_key, $aes_iv);
return $message;
}
public function handle_encrypted_update($message) {
public function handle_encrypted_update($message)
{
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...');
return false;
}
$auth_key_id = \danog\PHP\Struct::unpack('<q', substr($message['message']['bytes'], 0, 8))[0];
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) throw new \danog\MadelineProto\SecurityException('Key fingerprint mismatch');
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) {
throw new \danog\MadelineProto\SecurityException('Key fingerprint mismatch');
}
$message_key = substr($message['message']['bytes'], 8, 16);
$encrypted_data = substr($message['message']['bytes'], 24);
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$message['message']['chat_id']]['key']['auth_key'], 'to server');
@ -180,7 +189,7 @@ trait MessageHandler
throw new \danog\MadelineProto\SecurityException('random_bytes is too short');
}
$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) {
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) {
$this->rekey($message['message']['chat_id']);
}
unset($message['message']['bytes']);

View File

@ -332,31 +332,42 @@ trait ResponseHandler
break;
}
}
public function handle_decrypted_update($update) {
if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) throw new \danog\MadelineProto\ResponseException('random_bytes is too short!');
public function handle_decrypted_update($update)
{
if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) {
throw new \danog\MadelineProto\ResponseException('random_bytes is too short!');
}
$this->secret_chats[$update['message']['chat_id']]['incoming'][] = $update['message'];
switch ($update['message']['decrypted_message']['_']) {
case 'decryptedMessageService':
switch ($update['message']['decrypted_message']['action']) {
case 'decryptedMessageActionRequestKey':
$this->accept_rekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
return;
case 'decryptedMessageActionAcceptKey':
$this->commit_rekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
return;
case 'decryptedMessageActionCommitKey':
$this->complete_rekey($update['message']['chat_id'], $update['message']['decrypted_message']['action']);
return;
case 'decryptedMessageActionNotifyLayer':
$this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer'];
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']);
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']);
}
return;
case 'decryptedMessageActionSetMessageTTL':
$this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds'];
return;
case 'decryptedMessageActionResend':
@ -366,6 +377,7 @@ trait ResponseHandler
// $this->send_encrypted_message($update['message']['chat_id'], $update['message']['decrypted_message']);
}
}
return;
default:
// $this->save_update(['_' => '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']]);

View File

@ -25,10 +25,14 @@ trait SeqNoHandler
return ($value * 2) + $in;
}
public function get_in_seq_no($chat) {
public function get_in_seq_no($chat)
{
return count($this->secret_chats[$chat]['incoming']);
}
public function get_out_seq_no($chat) {
public function get_out_seq_no($chat)
{
return count($this->secret_chats[$chat]['outgoing']);
}
}

View File

@ -198,6 +198,7 @@ trait UpdateHandler
$this->should_serialize = true;
$this->updates_state['qts'] = 0;
}
return $this->updates_state;
}
@ -500,7 +501,7 @@ trait UpdateHandler
return false;
}
if ($update['qts'] > $cur_state['qts']+1) {
if ($update['qts'] > $cur_state['qts'] + 1) {
\danog\MadelineProto\Logger::log(['Qts hole. update qts: '.$update['qts'].' > current qts '.$cur_state['qts'].'+1, chat id: '.$update['message']['chat_id']], \danog\MadelineProto\Logger::ERROR);
$this->get_updates_difference();
@ -511,6 +512,7 @@ trait UpdateHandler
$cur_state['qts'] = $update['qts'];
$this->should_serialize = true;
$this->handle_encrypted_update($update);
return;
}
/*
@ -521,16 +523,25 @@ trait UpdateHandler
if ($update['_'] === 'updateEncryption') {
switch ($update['chat']['_']) {
case 'encryptedChatRequested':
if ($this->settings['secret_chats']['accept_chats'] === false || (is_array($this->settings['secret_chats']['accept_chats']) && !in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats']))) return;
if ($this->settings['secret_chats']['accept_chats'] === false || (is_array($this->settings['secret_chats']['accept_chats']) && !in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats']))) {
return;
}
\danog\MadelineProto\Logger::log(['Accepting secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
return $this->accept_secret_chat($update['chat']);
case 'encryptedChatDiscarded':
\danog\MadelineProto\Logger::log(['Revoking secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
if (isset($this->secret_chats[$update['chat']['id']])) unset($this->secret_chats[$update['chat']['id']]);
if (isset($this->temp_requested_secret_chats[$update['chat']['id']])) unset($this->temp_requested_secret_chats[$update['chat']['id']]);
if (isset($this->secret_chats[$update['chat']['id']])) {
unset($this->secret_chats[$update['chat']['id']]);
}
if (isset($this->temp_requested_secret_chats[$update['chat']['id']])) {
unset($this->temp_requested_secret_chats[$update['chat']['id']]);
}
return;
case 'encryptedChat':
\danog\MadelineProto\Logger::log(['Completing creation of secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
return $this->complete_secret_chat($update['chat']);
}
\danog\MadelineProto\Logger::log([$update], \danog\MadelineProto\Logger::NOTICE);

View File

@ -63,6 +63,7 @@ class Serialization
if ($unserialized === false) {
throw new Exception('An error occurred on deserialization');
}
return $unserialized;
}
}

View File

@ -15,6 +15,7 @@ namespace danog\MadelineProto\TL;
trait TL
{
public $encrypted_layer = -1;
public function construct_tl($files)
{
\danog\MadelineProto\Logger::log(['Loading TL schemes...'], \danog\MadelineProto\Logger::VERBOSE);
@ -40,7 +41,9 @@ trait TL
if (preg_match('|^//@|', $line)) {
$list = explode(' @', str_replace('//', ' ', $line));
foreach ($list as $elem) {
if ($elem === '') continue;
if ($elem === '') {
continue;
}
$elem = explode(' ', $elem, 2);
if ($elem[0] === 'class') {
$elem = explode(' ', $elem[1], 2);
@ -51,11 +54,15 @@ trait TL
if (!is_null($class)) {
$this->td_descriptions['types'][$class] = $elem[1];
$class = null;
} else $e = $elem[1];
} else {
$e = $elem[1];
}
continue;
}
if ($elem[0] === 'param_description') $elem[0] = 'description';
$dparams[$elem[0]]= $elem[1];
if ($elem[0] === 'param_description') {
$elem[0] = 'description';
}
$dparams[$elem[0]] = $elem[1];
}
continue;
}
@ -78,9 +85,13 @@ trait TL
if (preg_match('/^vector#/', $line)) {
continue;
}
if (preg_match('/ \?= /', $line)) continue;
if (preg_match('/ \?= /', $line)) {
continue;
}
$name = preg_replace(['/#.*/', '/\s.*/'], '', $line);
if (in_array($name, ['bytes', 'int128', 'int256', 'int512'])) continue;
if (in_array($name, ['bytes', 'int128', 'int256', 'int512'])) {
continue;
}
$clean = preg_replace([
'/:bytes /',
'/;/',
@ -93,7 +104,7 @@ trait TL
'/ $/',
'/\?bytes /',
'/{/',
'/}/'
'/}/',
], [
':string ',
'',
@ -106,10 +117,10 @@ trait TL
'',
'?string ',
'',
''], $line);
'', ], $line);
$id = hash('crc32b', $clean);
if (preg_match('/^[^\s]+#/', $line)) {
$nid = str_pad(preg_replace(['/^[^#]+#/', '/\s.+/'], '', $line), 8, "0", \STR_PAD_LEFT);
$nid = str_pad(preg_replace(['/^[^#]+#/', '/\s.+/'], '', $line), 8, '0', \STR_PAD_LEFT);
if ($id !== $nid) {
\danog\MadelineProto\Logger::log(['CRC32 mismatch ('.$id.', '.$nid.') for '.$line], \danog\MadelineProto\Logger::ERROR);
}
@ -123,7 +134,9 @@ trait TL
$TL_dict[$type][$key]['id'] = \danog\PHP\Struct::unpack('<i', \danog\PHP\Struct::pack('<I', hexdec($id)))[0];
$TL_dict[$type][$key]['params'] = [];
$TL_dict[$type][$key]['type'] = preg_replace(['/.+\s/', '/;/'], '', $line);
if ($layer !== null) $TL_dict[$type][$key]['layer'] = $layer;
if ($layer !== null) {
$TL_dict[$type][$key]['layer'] = $layer;
}
foreach (explode(' ', preg_replace(['/^[^\s]+\s/', '/=\s[^\s]+/', '/\s$/'], '', $line)) as $param) {
if ($param === '') {
continue;
@ -143,17 +156,23 @@ trait TL
$orig = $this->encrypted_layer;
\danog\MadelineProto\Logger::log(['Translating objects...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
foreach ($TL_dict['constructors'] as $elem) {
if ($scheme_type === 'secret') $this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
if ($scheme_type === 'secret') {
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
}
$this->{($scheme_type === 'td' ? 'td_' : '').'constructors'}->add($elem, $scheme_type);
}
\danog\MadelineProto\Logger::log(['Translating methods...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
foreach ($TL_dict['methods'] as $elem) {
$this->{($scheme_type === 'td' ? 'td_' : '').'methods'}->add($elem);
if ($scheme_type === 'secret') $this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
if ($scheme_type === 'secret') {
$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); }
foreach ($this->secret_chats as $chat => $data) {
$this->notify_layer($chat);
}
}
}
if (isset($files['td']) && isset($files['telegram'])) {
@ -185,7 +204,6 @@ trait TL
return array_unique(array_values($this->methods->method_namespace));
}
public function serialize_bool($bool)
{
return \danog\PHP\Struct::pack('<i', $this->constructors->find_by_predicate('bool'.($bool ? 'True' : 'False'))['id']);
@ -224,13 +242,19 @@ trait TL
return \danog\PHP\Struct::pack('<q', $object);
case 'int128':
if (strlen($object) !== 16) throw new Exception('Given value is not 16 bytes long');
if (strlen($object) !== 16) {
throw new Exception('Given value is not 16 bytes long');
}
return (string) $object;
case 'int256':
if (strlen($object) !== 32) throw new Exception('Given value is not 32 bytes long');
if (strlen($object) !== 32) {
throw new Exception('Given value is not 32 bytes long');
}
return (string) $object;
case 'int512':
if (strlen($object) !== 64) throw new Exception('Given value is not 64 bytes long');
if (strlen($object) !== 64) {
throw new Exception('Given value is not 64 bytes long');
}
return (string) $object;
case 'double':
return \danog\PHP\Struct::pack('<d', $object);
@ -297,10 +321,13 @@ trait TL
}
$concat = '';
if ($constructorData['predicate'] === 'messageEntityMentionName') $constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName');
if ($constructorData['predicate'] === 'messageEntityMentionName') {
$constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName');
}
if (!$bare) {
$concat .= \danog\PHP\Struct::pack('<i', $constructorData['id']);
}
return $concat.$this->serialize_params($constructorData, $object);
}
@ -310,10 +337,10 @@ trait TL
if ($tl === false) {
throw new Exception('Could not find method: '.$method);
}
return \danog\PHP\Struct::pack('<i', $tl['id']).$this->serialize_params($tl, $arguments);
}
public function serialize_params($tl, $arguments)
{
$serialized = '';
@ -348,7 +375,7 @@ trait TL
continue;
}
if ($current_argument['name'] === 'random_bytes') {
$serialized .= $this->random(15+random_int(0, 10));
$serialized .= $this->random(15 + random_int(0, 10));
continue;
}
if ($current_argument['name'] === 'data' && isset($arguments['message'])) {

View File

@ -27,7 +27,9 @@ class TLConstructor extends TLParams
$this->predicate[$this->key] = (string) ((($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message') ? 'MT' : '').$json_dict['predicate']);
$this->type[$this->key] = (($scheme_type === 'mtproto' && $json_dict['type'] === 'Message') ? 'MT' : '').$json_dict['type'];
$this->params[$this->key] = $json_dict['params'];
if ($scheme_type === 'secret') $this->layer[$this->key] = $json_dict['layer'];
if ($scheme_type === 'secret') {
$this->layer[$this->key] = $json_dict['layer'];
}
$this->parse_params($this->key, $scheme_type === 'mtproto');
$this->key++;
}
@ -50,10 +52,16 @@ class TLConstructor extends TLParams
$key = 0;
$keys = array_keys($this->predicate, $predicate);
foreach ($keys as $k) {
if ($this->layer[$k] === $layer) $key = $k;
if ($this->layer[$k] === $layer) {
$key = $k;
}
}
if ($key === 0) {
$key = array_search($predicate, $this->predicate);
}
} else {
$key = array_search($predicate, $this->predicate);
}
if ($key === 0) $key = array_search($predicate, $this->predicate);
} else $key = array_search($predicate, $this->predicate);
return ($key === false) ? false : [
'id' => $this->id[$key],

View File

@ -47,9 +47,11 @@ class TLMethod extends TLParams
'params' => $this->params[$key],
];
}
public function find_by_id($id)
{
$key = array_search($id, $this->id);
return ($key === false) ? false : [
'id' => $this->id[$key],
'method' => $this->method[$key],

View File

@ -32,7 +32,6 @@ echo 'Loading settings...'.PHP_EOL;
$settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: [];
if ($MadelineProto === false) {
echo 'Loading MadelineProto...'.PHP_EOL;
$MadelineProto = new \danog\MadelineProto\API($settings);
if (getenv('TRAVIS_COMMIT') == '') {
@ -88,7 +87,6 @@ $media['document_photo'] = ['_' => 'inputMediaUploadedDocument', 'file' => $inpu
//$inputFile = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic
//$secret_media['document_photo'] = ['peer' => $secret, 'file' => $inputFile, 'message' => ['ttl' => PHP_INT_MAX, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'mime_type' => mime_content_type('tests/faust.jpg'), 'caption' => 'This file was uploaded using MadelineProto', 'attributes' => [['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914]]]]];
// Photo
$media['photo'] = ['_' => 'inputMediaUploadedPhoto', 'file' => $inputFile, 'mime_type' => mime_content_type('tests/faust.jpg'), 'caption' => 'This photo was uploaded using MadelineProto'];