Apply fixes from StyleCI
This commit is contained in:
parent
5519782618
commit
d3cff5e0af
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class API extends APIFactory
|
||||
@ -17,6 +18,7 @@ class API extends APIFactory
|
||||
use \danog\Serializable;
|
||||
public $session;
|
||||
public $serialized = 0;
|
||||
|
||||
public function __magic_construct($params = [])
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
@ -32,6 +34,7 @@ class API extends APIFactory
|
||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'r');
|
||||
\danog\MadelineProto\Logger::log(['Waiting for shared lock of serialization lockfile...']);
|
||||
flock($realpaths['lockfile'], LOCK_SH);
|
||||
|
||||
try {
|
||||
$unserialized = file_get_contents($realpaths['file']);
|
||||
} finally {
|
||||
@ -40,10 +43,11 @@ class API extends APIFactory
|
||||
}
|
||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $unserialized);
|
||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||
class_exists('\\danog\\MadelineProto\\' . $class);
|
||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
||||
}
|
||||
class_exists('\\Volatile');
|
||||
\danog\MadelineProto\Logger::class_exists();
|
||||
|
||||
try {
|
||||
$unserialized = unserialize($tounserialize);
|
||||
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
||||
@ -69,6 +73,7 @@ class API extends APIFactory
|
||||
$this->APIFactory();
|
||||
}
|
||||
Serialization::$instances[spl_object_hash($unserialized)] = $unserialized;
|
||||
|
||||
return;
|
||||
}
|
||||
$this->API = new MTProto($params);
|
||||
@ -76,18 +81,20 @@ class API extends APIFactory
|
||||
$this->APIFactory();
|
||||
\danog\MadelineProto\Logger::log(['Ping...'], Logger::ULTRA_VERBOSE);
|
||||
$pong = $this->ping(['ping_id' => 3]);
|
||||
\danog\MadelineProto\Logger::log(['Pong: ' . $pong['ping_id']], Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Pong: '.$pong['ping_id']], Logger::ULTRA_VERBOSE);
|
||||
//\danog\MadelineProto\Logger::log(['Getting future salts...'], Logger::ULTRA_VERBOSE);
|
||||
//$this->future_salts = $this->get_future_salts(['num' => 3]);
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['madelineproto_ready']], Logger::NOTICE);
|
||||
Serialization::$instances[spl_object_hash($this)] = $this;
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
//if (method_exists($this->API, 'wakeup')) $this->API = $this->API->wakeup();
|
||||
Serialization::$instances[spl_object_hash($this)] = $this;
|
||||
$this->APIFactory();
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
@ -98,45 +105,56 @@ class API extends APIFactory
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['API'];
|
||||
}
|
||||
|
||||
public function &__get($name)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
$this->API->setdem = true;
|
||||
|
||||
return $this->API->settings;
|
||||
}
|
||||
|
||||
return $this->API->storage[$name];
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
return $this->API->__construct($value);
|
||||
}
|
||||
|
||||
return $this->API->storage[$name] = $value;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
public function APIFactory()
|
||||
{
|
||||
foreach ($this->API->get_method_namespaces() as $namespace) {
|
||||
$this->{$namespace} = new APIFactory($namespace, $this->API);
|
||||
}
|
||||
}
|
||||
|
||||
public function serialize($params = '')
|
||||
{
|
||||
if ($params === '') {
|
||||
$params = $this->session;
|
||||
}
|
||||
Logger::log([\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']]);
|
||||
|
||||
return Serialization::serialize($params, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class APIFactory
|
||||
@ -108,11 +109,13 @@ class APIFactory
|
||||
public $namespace = '';
|
||||
public $API;
|
||||
public $lua = false;
|
||||
|
||||
public function __construct($namespace, $API)
|
||||
{
|
||||
$this->namespace = $namespace . '.';
|
||||
$this->namespace = $namespace.'.';
|
||||
$this->API = $API;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if ($this->API->setdem) {
|
||||
@ -127,11 +130,13 @@ class APIFactory
|
||||
$this->serialize($this->session);
|
||||
}
|
||||
if ($this->lua === false) {
|
||||
return method_exists($this->API, $this->namespace . $name) ? $this->API->{$this->namespace . $name}(...$arguments) : $this->API->method_call($this->namespace . $name, isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [], $aargs);
|
||||
return method_exists($this->API, $this->namespace.$name) ? $this->API->{$this->namespace.$name}(...$arguments) : $this->API->method_call($this->namespace.$name, isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [], $aargs);
|
||||
}
|
||||
|
||||
try {
|
||||
$deserialized = method_exists($this->API, $this->namespace . $name) ? $this->API->{$this->namespace . $name}(...$arguments) : $this->API->method_call($this->namespace . $name, isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [], $aargs);
|
||||
$deserialized = method_exists($this->API, $this->namespace.$name) ? $this->API->{$this->namespace.$name}(...$arguments) : $this->API->method_call($this->namespace.$name, isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [], $aargs);
|
||||
Lua::convert_objects($deserialized);
|
||||
|
||||
return $deserialized;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
@ -149,4 +154,4 @@ class APIFactory
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,29 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
|
||||
class AnnotationsBuilder
|
||||
{
|
||||
use \danog\MadelineProto\TL\TL;
|
||||
use Tools;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->construct_TL($settings['tl_schema']);
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function mk_annotations()
|
||||
{
|
||||
\danog\MadelineProto\Logger::log(['Generating annotations...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->setProperties();
|
||||
$this->createInternalClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open file of class APIFactory
|
||||
* Insert properties
|
||||
@ -43,22 +48,23 @@ class AnnotationsBuilder
|
||||
if ($raw_docblock = $property->getDocComment()) {
|
||||
$docblock = $fixture->create($raw_docblock);
|
||||
if ($docblock->hasTag('internal')) {
|
||||
$content = str_replace("\n " . $raw_docblock . "\n public \$" . $property->getName() . ';', '', $content);
|
||||
$content = str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($this->get_method_namespaces() as $namespace) {
|
||||
$content = preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}' . " /**\n" . " * @internal this is a internal property generated by build_docs.php, don't change manually\n" . " *\n" . " * @var {$namespace}\n" . " */\n" . " public \${$namespace};\n", $content);
|
||||
$content = preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content);
|
||||
}
|
||||
file_put_contents($filename, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create file InternalDoc with all interfaces.
|
||||
*/
|
||||
private function createInternalClasses()
|
||||
{
|
||||
\danog\MadelineProto\Logger::log(['Creating internal classes...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
$handle = fopen(dirname(__FILE__) . '/InternalDoc.php', 'w');
|
||||
$handle = fopen(dirname(__FILE__).'/InternalDoc.php', 'w');
|
||||
foreach ($this->methods->by_id as $id => $data) {
|
||||
if (!strpos($data['method'], '.')) {
|
||||
continue;
|
||||
@ -120,4 +126,4 @@ class AnnotationsBuilder
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class Bug74586Exception extends \Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
/**
|
||||
@ -172,6 +173,7 @@ class Connection
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
@ -194,15 +196,18 @@ class Connection
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function close_and_reopen()
|
||||
{
|
||||
$this->__destruct();
|
||||
$this->must_open = true;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['proxy', 'extra', 'protocol', 'ip', 'port', 'timeout', 'parsed', 'time_delta', 'temp_auth_key', 'auth_key', 'session_id', 'session_out_seq_no', 'session_in_seq_no', 'ipv6', 'incoming_messages', 'outgoing_messages', 'new_incoming', 'new_outgoing', 'max_incoming_id', 'max_outgoing_id', 'obfuscated', 'authorized', 'object_queue', 'ack_queue'];
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$keys = array_keys((array) get_object_vars($this));
|
||||
@ -212,6 +217,7 @@ class Connection
|
||||
$this->time_delta = 0;
|
||||
//$this->__construct($this->proxy, $this->extra, $this->ip, $this->port, $this->protocol, $this->timeout, $this->ipv6);
|
||||
}
|
||||
|
||||
public function write($what, $length = null)
|
||||
{
|
||||
if ($this->must_open) {
|
||||
@ -237,6 +243,7 @@ class Connection
|
||||
while (($wrote += $this->sock->write(substr($what, $wrote))) !== $length) {
|
||||
}
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
break;
|
||||
case 'udp':
|
||||
@ -247,6 +254,7 @@ class Connection
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
if ($this->must_open) {
|
||||
@ -264,8 +272,10 @@ class Connection
|
||||
}
|
||||
if (strlen($packet) !== $length) {
|
||||
$this->close_and_reopen();
|
||||
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['wrong_length_read'], $length, strlen($packet)));
|
||||
}
|
||||
|
||||
return @$this->obfuscated['decryption']->encrypt($packet);
|
||||
case 'tcp_abridged':
|
||||
case 'tcp_intermediate':
|
||||
@ -282,8 +292,10 @@ class Connection
|
||||
}
|
||||
if (strlen($packet) !== $length) {
|
||||
$this->close_and_reopen();
|
||||
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['wrong_length_read'], $length, strlen($packet)));
|
||||
}
|
||||
|
||||
return $packet;
|
||||
case 'udp':
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_not_implemented']);
|
||||
@ -292,6 +304,7 @@ class Connection
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function read_message()
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
@ -299,7 +312,7 @@ class Connection
|
||||
$packet_length_data = $this->read(4);
|
||||
$packet_length = unpack('V', $packet_length_data)[1];
|
||||
$packet = $this->read($packet_length - 4);
|
||||
if (strrev(hash('crc32b', $packet_length_data . substr($packet, 0, -4), true)) !== substr($packet, -4)) {
|
||||
if (strrev(hash('crc32b', $packet_length_data.substr($packet, 0, -4), true)) !== substr($packet, -4)) {
|
||||
throw new Exception('CRC32 was not correct!');
|
||||
}
|
||||
$this->in_seq_no++;
|
||||
@ -307,13 +320,15 @@ class Connection
|
||||
if ($in_seq_no != $this->in_seq_no) {
|
||||
throw new Exception('Incoming seq_no mismatch');
|
||||
}
|
||||
|
||||
return substr($packet, 4, $packet_length - 12);
|
||||
case 'tcp_intermediate':
|
||||
return $this->read(unpack('V', $this->read(4))[1]);
|
||||
case 'obfuscated2':
|
||||
case 'tcp_abridged':
|
||||
$packet_length = ord($this->read(1));
|
||||
return $this->read($packet_length < 127 ? $packet_length << 2 : unpack('V', $this->read(3) . "\0")[1] << 2);
|
||||
|
||||
return $this->read($packet_length < 127 ? $packet_length << 2 : unpack('V', $this->read(3)."\0")[1] << 2);
|
||||
case 'http':
|
||||
case 'https':
|
||||
case 'https_proxied':
|
||||
@ -328,37 +343,39 @@ class Connection
|
||||
if ($close) {
|
||||
$this->close_and_reopen();
|
||||
}
|
||||
|
||||
return $response['body'];
|
||||
case 'udp':
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_not_implemented']);
|
||||
}
|
||||
}
|
||||
|
||||
public function send_message($message)
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_full':
|
||||
$this->out_seq_no++;
|
||||
$step1 = pack('VV', strlen($message) + 12, $this->out_seq_no) . $message;
|
||||
$step2 = $step1 . strrev(hash('crc32b', $step1, true));
|
||||
$step1 = pack('VV', strlen($message) + 12, $this->out_seq_no).$message;
|
||||
$step2 = $step1.strrev(hash('crc32b', $step1, true));
|
||||
$this->write($step2);
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$this->write(pack('V', strlen($message)) . $message);
|
||||
$this->write(pack('V', strlen($message)).$message);
|
||||
break;
|
||||
case 'obfuscated2':
|
||||
case 'tcp_abridged':
|
||||
$len = strlen($message) / 4;
|
||||
if ($len < 127) {
|
||||
$message = chr($len) . $message;
|
||||
$message = chr($len).$message;
|
||||
} else {
|
||||
$message = chr(127) . substr(pack('V', $len), 0, 3) . $message;
|
||||
$message = chr(127).substr(pack('V', $len), 0, 3).$message;
|
||||
}
|
||||
$this->write($message);
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
case 'https_proxied':
|
||||
$this->write('POST ' . $this->parsed['path'] . " HTTP/1.1\r\nHost: " . $this->parsed['host'] . "\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: " . strlen($message) . "\r\n\r\n" . $message);
|
||||
$this->write('POST '.$this->parsed['path']." HTTP/1.1\r\nHost: ".$this->parsed['host']."\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".strlen($message)."\r\n\r\n".$message);
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_not_implemented']);
|
||||
@ -370,35 +387,32 @@ class Connection
|
||||
public function read_http_line()
|
||||
{
|
||||
$line = '';
|
||||
while (($curchar = $this->read(1)) !== "\n")
|
||||
{
|
||||
$line.= $curchar;
|
||||
while (($curchar = $this->read(1)) !== "\n") {
|
||||
$line .= $curchar;
|
||||
}
|
||||
|
||||
return rtrim($line);
|
||||
}
|
||||
|
||||
function read_http_payload()
|
||||
public function read_http_payload()
|
||||
{
|
||||
$header = explode(' ', $this->read_http_line() , 3);
|
||||
$header = explode(' ', $this->read_http_line(), 3);
|
||||
$protocol = $header[0];
|
||||
$code = (int)$header[1];
|
||||
$code = (int) $header[1];
|
||||
$description = $header[2];
|
||||
$headers = [];
|
||||
while (strlen($current_header = $this->read_http_line())) {
|
||||
$current_header = explode(':', $current_header, 2);
|
||||
$headers[strtolower($current_header[0]) ] = trim($current_header[1]);
|
||||
$headers[strtolower($current_header[0])] = trim($current_header[1]);
|
||||
}
|
||||
|
||||
$read = '';
|
||||
if (isset($headers['content-length']))
|
||||
{
|
||||
$read = $this->read((int)$headers['content-length']);
|
||||
if (isset($headers['content-length'])) {
|
||||
$read = $this->read((int) $headers['content-length']);
|
||||
} elseif (isset($headers['transfer-encoding']) && $headers['transfer-encoding'] === 'chunked') {
|
||||
do
|
||||
{
|
||||
do {
|
||||
$length = hexdec($this->read_http_line($res));
|
||||
$read.= $this->read($length);
|
||||
$read .= $this->read($length);
|
||||
$this->read_http_line($res);
|
||||
} while ($length);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
/**
|
||||
@ -23,10 +24,12 @@ class DataCenter
|
||||
public $curdc = 0;
|
||||
private $dclist = [];
|
||||
private $settings = [];
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['sockets', 'curdc', 'dclist', 'settings'];
|
||||
}
|
||||
|
||||
public function __magic_construct($dclist, $settings)
|
||||
{
|
||||
$this->dclist = $dclist;
|
||||
@ -41,6 +44,7 @@ class DataCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function dc_disconnect($dc_number)
|
||||
{
|
||||
if ($this->curdc === $dc_number) {
|
||||
@ -51,6 +55,7 @@ class DataCenter
|
||||
unset($this->sockets[$dc_number]);
|
||||
}
|
||||
}
|
||||
|
||||
public function dc_connect($dc_number)
|
||||
{
|
||||
if (isset($this->sockets[$dc_number]) && !isset($this->sockets[$dc_number]->old)) {
|
||||
@ -63,6 +68,7 @@ class DataCenter
|
||||
$ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4';
|
||||
if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) {
|
||||
unset($this->sockets[$dc_number]);
|
||||
|
||||
return false;
|
||||
}
|
||||
$address = $this->dclist[$test][$ipv6][$dc_number]['ip_address'];
|
||||
@ -79,18 +85,19 @@ class DataCenter
|
||||
if (strpos($this->settings[$dc_config_number]['protocol'], 'https') === 0) {
|
||||
$subdomain = $this->dclist['ssl_subdomains'][$dc_number];
|
||||
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1';
|
||||
$address = 'https://' . $subdomain . '.web.telegram.org/' . $path;
|
||||
$address = 'https://'.$subdomain.'.web.telegram.org/'.$path;
|
||||
$port = 443;
|
||||
}
|
||||
if ($this->settings[$dc_config_number]['protocol'] === 'http') {
|
||||
if ($ipv6) {
|
||||
$address = '[' . $address . ']';
|
||||
$address = '['.$address.']';
|
||||
}
|
||||
$address = $this->settings[$dc_config_number]['protocol'] . '://' . $address . '/api';
|
||||
$address = $this->settings[$dc_config_number]['protocol'].'://'.$address.'/api';
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['dc_con_test_start'], $dc_number, $test, $ipv6, $this->settings[$dc_config_number]['protocol'])], \danog\MadelineProto\Logger::VERBOSE);
|
||||
foreach (array_unique([$port, 443, 80, 88]) as $port) {
|
||||
\danog\MadelineProto\Logger::log(['Trying connection on port ' . $port . '...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Trying connection on port '.$port.'...'], \danog\MadelineProto\Logger::WARNING);
|
||||
|
||||
try {
|
||||
if (isset($this->sockets[$dc_number]->old)) {
|
||||
$this->sockets[$dc_number]->__construct($this->settings[$dc_config_number]['proxy'], $this->settings[$dc_config_number]['proxy_extra'], $address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout'], $this->settings[$dc_config_number]['ipv6']);
|
||||
@ -99,6 +106,7 @@ class DataCenter
|
||||
$this->sockets[$dc_number] = new Connection($this->settings[$dc_config_number]['proxy'], $this->settings[$dc_config_number]['proxy_extra'], $address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout'], $this->settings[$dc_config_number]['ipv6']);
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['OK!'], \danog\MadelineProto\Logger::WARNING);
|
||||
|
||||
return true;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||
@ -107,26 +115,29 @@ class DataCenter
|
||||
switch ($x) {
|
||||
case 0:
|
||||
$this->settings[$dc_config_number]['ipv6'] = !$this->settings[$dc_config_number]['ipv6'];
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection with ' . ($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4') . '...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
|
||||
continue;
|
||||
case 1:
|
||||
$this->settings[$dc_config_number]['proxy'] = '\\Socket';
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with ' . ($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4') . '...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
|
||||
continue;
|
||||
case 2:
|
||||
$this->settings[$dc_config_number]['ipv6'] = !$this->settings[$dc_config_number]['ipv6'];
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with ' . ($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4') . '...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
|
||||
continue;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} while (++$x);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_dcs($all = true)
|
||||
{
|
||||
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
||||
$ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4';
|
||||
|
||||
return $all ? array_keys((array) $this->dclist[$test][$ipv6]) : array_keys((array) $this->sockets);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class DocsBuilder
|
||||
@ -19,6 +20,7 @@ class DocsBuilder
|
||||
use \danog\MadelineProto\DocsBuilder\Constructors;
|
||||
use Tools;
|
||||
public $td = false;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
@ -35,24 +37,28 @@ class DocsBuilder
|
||||
chdir($this->settings['output_dir']);
|
||||
$this->index = $settings['readme'] ? 'README.md' : 'index.md';
|
||||
}
|
||||
|
||||
public $types = [];
|
||||
public $any = '*';
|
||||
|
||||
public function end($what)
|
||||
{
|
||||
return end($what);
|
||||
}
|
||||
|
||||
public function escape($hwat)
|
||||
{
|
||||
return str_replace('_', '\\_', $hwat);
|
||||
}
|
||||
|
||||
public function mk_docs()
|
||||
{
|
||||
\danog\MadelineProto\Logger::log(['Generating documentation index...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
file_put_contents($this->index, '---
|
||||
title: ' . $this->settings['title'] . '
|
||||
description: ' . $this->settings['description'] . '
|
||||
title: '.$this->settings['title'].'
|
||||
description: '.$this->settings['description'].'
|
||||
---
|
||||
# ' . $this->settings['description'] . '
|
||||
# '.$this->settings['description'].'
|
||||
|
||||
[Methods](methods/)
|
||||
|
||||
@ -81,14 +87,14 @@ description: ' . $this->settings['description'] . '
|
||||
//$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
|
||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $otype);
|
||||
$type = preg_replace('/.*_of_/', '', $type);
|
||||
$index .= '[' . str_replace('_', '\\_', $type) . '](' . $type . '.md)<a name="' . $type . '"></a>
|
||||
$index .= '['.str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a>
|
||||
|
||||
';
|
||||
$constructors = '';
|
||||
foreach ($keys['constructors'] as $data) {
|
||||
$predicate = str_replace('.', '_', $data['predicate']) . (isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : '');
|
||||
$predicate = str_replace('.', '_', $data['predicate']).(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '');
|
||||
$md_predicate = str_replace('_', '\\_', $predicate);
|
||||
$constructors .= '[' . $md_predicate . '](../constructors/' . $predicate . '.md)
|
||||
$constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md)
|
||||
|
||||
';
|
||||
}
|
||||
@ -96,38 +102,38 @@ description: ' . $this->settings['description'] . '
|
||||
foreach ($keys['methods'] as $data) {
|
||||
$name = str_replace('.', '_', $data['method']);
|
||||
$md_name = str_replace('_', '->', $name);
|
||||
$methods .= '[$MadelineProto->' . $md_name . '](../methods/' . $name . '.md)
|
||||
$methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md)
|
||||
|
||||
';
|
||||
}
|
||||
$description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of typr ' . $type;
|
||||
$description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of typr '.$type;
|
||||
$header = '---
|
||||
title: ' . $type . '
|
||||
description: constructors and methods of type ' . $type . '
|
||||
title: '.$type.'
|
||||
description: constructors and methods of type '.$type.'
|
||||
---
|
||||
## Type: ' . str_replace('_', '\\_', $type) . '
|
||||
## Type: '.str_replace('_', '\\_', $type).'
|
||||
[Back to types index](index.md)
|
||||
|
||||
|
||||
|
||||
';
|
||||
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] . PHP_EOL . PHP_EOL : '';
|
||||
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : '';
|
||||
if (!isset($this->settings['td'])) {
|
||||
if (in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer'])) {
|
||||
$header .= 'The following syntaxes can also be used:
|
||||
|
||||
```
|
||||
$' . $type . " = '@username'; // Username\n\n\$" . $type . ' = 44700; // bot API id (users)
|
||||
$' . $type . ' = -492772765; // bot API id (chats)
|
||||
$' . $type . ' = -10038575794; // bot API id (channels)
|
||||
$'.$type." = '@username'; // Username\n\n\$".$type.' = 44700; // bot API id (users)
|
||||
$'.$type.' = -492772765; // bot API id (chats)
|
||||
$'.$type.' = -10038575794; // bot API id (channels)
|
||||
|
||||
$' . $type . " = 'user#44700'; // tg-cli style id (users)\n\$" . $type . " = 'chat#492772765'; // tg-cli style id (chats)\n\$" . $type . " = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
||||
$'.$type." = 'user#44700'; // tg-cli style id (users)\n\$".$type." = 'chat#492772765'; // tg-cli style id (chats)\n\$".$type." = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
|
||||
}
|
||||
if (in_array($type, ['InputEncryptedChat'])) {
|
||||
$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
|
||||
```
|
||||
|
||||
|
||||
@ -139,7 +145,7 @@ $' . $type . ' = -147286699; // Numeric chat id returned by request_secret_chat,
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $' . $type . '->click();
|
||||
$result = $'.$type.'->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
@ -159,12 +165,12 @@ $result = $' . $type . '->click();
|
||||
}
|
||||
$constructors = '### Possible values (constructors):
|
||||
|
||||
' . $constructors . '
|
||||
'.$constructors.'
|
||||
|
||||
';
|
||||
$methods = '### Methods that return an object of this type (methods):
|
||||
|
||||
' . $methods . '
|
||||
'.$methods.'
|
||||
|
||||
';
|
||||
if (!isset($this->settings['td'])) {
|
||||
@ -351,14 +357,14 @@ After modifying it, you must always parse the new configuration with a call to `
|
||||
';
|
||||
}
|
||||
}
|
||||
if (file_exists('types/' . $type . '.md')) {
|
||||
if (file_exists('types/'.$type.'.md')) {
|
||||
\danog\MadelineProto\Logger::log([$type]);
|
||||
}
|
||||
file_put_contents('types/' . $type . '.md', $header . $constructors . $methods);
|
||||
file_put_contents('types/'.$type.'.md', $header.$constructors.$methods);
|
||||
$last_namespace = $new_namespace;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Generating types index...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
file_put_contents('types/' . $this->index, '---
|
||||
file_put_contents('types/'.$this->index, '---
|
||||
title: Types
|
||||
description: List of types
|
||||
---
|
||||
@ -366,7 +372,7 @@ description: List of types
|
||||
[Back to API documentation index](..)
|
||||
|
||||
|
||||
' . $index);
|
||||
'.$index);
|
||||
\danog\MadelineProto\Logger::log(['Generating additional types...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
file_put_contents('types/string.md', '---
|
||||
title: string
|
||||
@ -514,4 +520,4 @@ Any json-encodable data.
|
||||
');
|
||||
\danog\MadelineProto\Logger::log(['Done!'], \danog\MadelineProto\Logger::NOTICE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,14 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\DocsBuilder;
|
||||
|
||||
trait Constructors
|
||||
{
|
||||
public function mk_constructors()
|
||||
{
|
||||
foreach (glob('constructors/' . $this->any) as $unlink) {
|
||||
foreach (glob('constructors/'.$this->any) as $unlink) {
|
||||
unlink($unlink);
|
||||
}
|
||||
if (file_exists('constructors')) {
|
||||
@ -36,7 +37,7 @@ trait Constructors
|
||||
if (preg_match('/%/', $type)) {
|
||||
$type = $this->constructors->find_by_type(str_replace('%', '', $type))['predicate'];
|
||||
}*/
|
||||
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : '';
|
||||
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '';
|
||||
$type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']);
|
||||
$php_type = preg_replace('/.*_of_/', '', $type);
|
||||
$constructor = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['predicate']);
|
||||
@ -65,12 +66,12 @@ trait Constructors
|
||||
if (substr($param[$type_or_subtype], -1) === '>') {
|
||||
$param[$type_or_subtype] = substr($param[$type_or_subtype], 0, -1);
|
||||
}
|
||||
$params .= "'" . $param['name'] . "' => ";
|
||||
$param[$type_or_subtype] = '[' . $this->escape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)';
|
||||
$params .= (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', ';
|
||||
$params .= "'".$param['name']."' => ";
|
||||
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
||||
$params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
||||
}
|
||||
$md_constructor = str_replace('_', '\\_', $constructor . $layer);
|
||||
$this->docs_constructors[$constructor] = '[$' . $md_constructor . '](../constructors/' . $php_constructor . $layer . '.md) = \\[' . $params . '\\];<a name="' . $constructor . $layer . '"></a>
|
||||
$md_constructor = str_replace('_', '\\_', $constructor.$layer);
|
||||
$this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a>
|
||||
|
||||
';
|
||||
$table = empty($data['params']) ? '' : '### Attributes:
|
||||
@ -117,31 +118,31 @@ trait Constructors
|
||||
case 'false':
|
||||
$ptype = 'Bool';
|
||||
}
|
||||
$table .= '|' . str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . str_replace('_', '\\_', $ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']) . 'Empty') ? 'Optional' : 'Yes') . '|';
|
||||
$table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty') ? 'Optional' : 'Yes').'|';
|
||||
if (isset($this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']])) {
|
||||
$table .= $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']] . '|';
|
||||
$table .= $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']].'|';
|
||||
}
|
||||
$table .= PHP_EOL;
|
||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype;
|
||||
$ppptype = in_array($ptype, ['string', 'bytes']) ? '"' . $ptype . '"' : $ptype;
|
||||
$params .= ", '" . $param['name'] . "' => ";
|
||||
$params .= isset($param['subtype']) ? '[' . $pptype . ']' : $pptype;
|
||||
$lua_params .= ', ' . $param['name'] . '=';
|
||||
$lua_params .= isset($param['subtype']) ? '{' . $pptype . '}' : $pptype;
|
||||
$pwr_params .= ', "' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype);
|
||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
||||
$ppptype = in_array($ptype, ['string', 'bytes']) ? '"'.$ptype.'"' : $ptype;
|
||||
$params .= ", '".$param['name']."' => ";
|
||||
$params .= isset($param['subtype']) ? '['.$pptype.']' : $pptype;
|
||||
$lua_params .= ', '.$param['name'].'=';
|
||||
$lua_params .= isset($param['subtype']) ? '{'.$pptype.'}' : $pptype;
|
||||
$pwr_params .= ', "'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype);
|
||||
if ($param['name'] === 'reply_markup') {
|
||||
$hasreplymarkup = true;
|
||||
}
|
||||
}
|
||||
$params = "['_' => '" . $data['predicate'] . "'" . $params . ']';
|
||||
$lua_params = "{_='" . $data['predicate'] . "'" . $lua_params . '}';
|
||||
$pwr_params = '{"_": "' . $data['predicate'] . '"' . $pwr_params . '}';
|
||||
$description = isset($this->td_descriptions['constructors'][$data['predicate']]) ? $this->td_descriptions['constructors'][$data['predicate']]['description'] : $constructor . ' attributes, type and example';
|
||||
$params = "['_' => '".$data['predicate']."'".$params.']';
|
||||
$lua_params = "{_='".$data['predicate']."'".$lua_params.'}';
|
||||
$pwr_params = '{"_": "'.$data['predicate'].'"'.$pwr_params.'}';
|
||||
$description = isset($this->td_descriptions['constructors'][$data['predicate']]) ? $this->td_descriptions['constructors'][$data['predicate']]['description'] : $constructor.' attributes, type and example';
|
||||
$header = '---
|
||||
title: ' . $data['predicate'] . '
|
||||
description: ' . $description . '
|
||||
title: '.$data['predicate'].'
|
||||
description: '.$description.'
|
||||
---
|
||||
## Constructor: ' . str_replace('_', '\\_', $data['predicate'] . $layer) . '
|
||||
## Constructor: '.str_replace('_', '\\_', $data['predicate'].$layer).'
|
||||
[Back to constructors index](index.md)
|
||||
|
||||
|
||||
@ -152,9 +153,9 @@ description: ' . $description . '
|
||||
|
||||
';
|
||||
if (isset($this->td_descriptions['constructors'][$data['predicate']])) {
|
||||
$header .= $this->td_descriptions['constructors'][$data['predicate']]['description'] . PHP_EOL . PHP_EOL;
|
||||
$header .= $this->td_descriptions['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL;
|
||||
}
|
||||
$type = '### Type: [' . str_replace('_', '\\_', $php_type) . '](../types/' . $php_type . '.md)
|
||||
$type = '### Type: ['.str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md)
|
||||
|
||||
|
||||
';
|
||||
@ -163,13 +164,13 @@ description: ' . $description . '
|
||||
$example = '### Example:
|
||||
|
||||
```
|
||||
$' . $constructor . $layer . ' = ' . $params . ';
|
||||
$'.$constructor.$layer.' = '.$params.';
|
||||
```
|
||||
|
||||
[PWRTelegram](https://pwrtelegram.xyz) json-encoded version:
|
||||
|
||||
```
|
||||
' . $pwr_params . '
|
||||
'.$pwr_params.'
|
||||
```
|
||||
|
||||
|
||||
@ -177,7 +178,7 @@ Or, if you\'re into Lua:
|
||||
|
||||
|
||||
```
|
||||
' . $constructor . $layer . '=' . $lua_params . '
|
||||
'.$constructor.$layer.'='.$lua_params.'
|
||||
|
||||
```
|
||||
|
||||
@ -227,7 +228,7 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
||||
';
|
||||
}
|
||||
}
|
||||
file_put_contents('constructors/' . $constructor . $layer . '.md', $header . $table . $type . $example);
|
||||
file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example);
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Generating constructors index...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
ksort($this->docs_constructors);
|
||||
@ -236,16 +237,16 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
||||
$new_namespace = preg_replace('/_.*/', '', $constructor);
|
||||
$br = $new_namespace != $last_namespace ? '***
|
||||
<br><br>' : '';
|
||||
$value = $br . $value;
|
||||
$value = $br.$value;
|
||||
$last_namespace = $new_namespace;
|
||||
}
|
||||
file_put_contents('constructors/' . $this->index, '---
|
||||
file_put_contents('constructors/'.$this->index, '---
|
||||
title: Constructors
|
||||
description: List of constructors
|
||||
---
|
||||
# Constructors
|
||||
[Back to API documentation index](..)
|
||||
|
||||
' . implode('', $this->docs_constructors));
|
||||
'.implode('', $this->docs_constructors));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\DocsBuilder;
|
||||
|
||||
trait Methods
|
||||
@ -19,7 +20,7 @@ trait Methods
|
||||
$bots = json_decode(file_get_contents('https://rpc.pwrtelegram.xyz/?bot'), true)['result'];
|
||||
$errors = json_decode(file_get_contents('https://rpc.pwrtelegram.xyz/?all'), true);
|
||||
$errors['result'] = array_merge_recursive(...$errors['result']);
|
||||
foreach (glob('methods/' . $this->any) as $unlink) {
|
||||
foreach (glob('methods/'.$this->any) as $unlink) {
|
||||
unlink($unlink);
|
||||
}
|
||||
if (file_exists('methods')) {
|
||||
@ -54,11 +55,11 @@ trait Methods
|
||||
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
|
||||
$type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||
$param[$type_or_subtype] = str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]);
|
||||
$param[$type_or_subtype] = '[' . $this->escape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)';
|
||||
$params .= "'" . $param['name'] . "' => " . (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', ';
|
||||
$param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
|
||||
$params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
|
||||
}
|
||||
$md_method = '[' . $php_method . '](' . $method . '.md)';
|
||||
$this->docs_methods[$method] = '$MadelineProto->' . $md_method . '(\\[' . $params . '\\]) === [$' . str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md)<a name="' . $method . '"></a>
|
||||
$md_method = '['.$php_method.']('.$method.'.md)';
|
||||
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
|
||||
|
||||
';
|
||||
$params = '';
|
||||
@ -98,19 +99,19 @@ trait Methods
|
||||
$ptype = 'Bool';
|
||||
}
|
||||
$type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
|
||||
$table .= '|' . str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . str_replace('_', '\\_', $ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']) . 'Empty') ? 'Optional' : 'Yes') . '|';
|
||||
$table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty') ? 'Optional' : 'Yes').'|';
|
||||
if (isset($this->td_descriptions['methods'][$data['method']])) {
|
||||
$table .= $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] . '|';
|
||||
$table .= $this->td_descriptions['methods'][$data['method']]['params'][$param['name']].'|';
|
||||
}
|
||||
$table .= PHP_EOL;
|
||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype;
|
||||
$ppptype = in_array($ptype, ['string', 'bytes']) ? '"' . $ptype . '"' : $ptype;
|
||||
$params .= "'" . $param['name'] . "' => ";
|
||||
$params .= (isset($param['subtype']) ? '[' . $pptype . ']' : $pptype) . ', ';
|
||||
$json_params .= '"' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype) . ', ';
|
||||
$pwr_params .= $param['name'] . ' - Json encoded ' . (isset($param['subtype']) ? ' array of ' . $ptype : $ptype) . "\n\n";
|
||||
$lua_params .= $param['name'] . '=';
|
||||
$lua_params .= (isset($param['subtype']) ? '{' . $pptype . '}' : $pptype) . ', ';
|
||||
$pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
|
||||
$ppptype = in_array($ptype, ['string', 'bytes']) ? '"'.$ptype.'"' : $ptype;
|
||||
$params .= "'".$param['name']."' => ";
|
||||
$params .= (isset($param['subtype']) ? '['.$pptype.']' : $pptype).', ';
|
||||
$json_params .= '"'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype).', ';
|
||||
$pwr_params .= $param['name'].' - Json encoded '.(isset($param['subtype']) ? ' array of '.$ptype : $ptype)."\n\n";
|
||||
$lua_params .= $param['name'].'=';
|
||||
$lua_params .= (isset($param['subtype']) ? '{'.$pptype.'}' : $pptype).', ';
|
||||
if ($param['name'] === 'reply_markup') {
|
||||
$hasreplymarkup = true;
|
||||
}
|
||||
@ -127,19 +128,19 @@ trait Methods
|
||||
$pwr_params = "parse_mode - string\n";
|
||||
}
|
||||
}
|
||||
$description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'] . ' parameters, return type and example';
|
||||
$description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'].' parameters, return type and example';
|
||||
$header = '---
|
||||
title: ' . $data['method'] . '
|
||||
description: ' . $description . '
|
||||
title: '.$data['method'].'
|
||||
description: '.$description.'
|
||||
---
|
||||
## Method: ' . str_replace('_', '\\_', $data['method']) . '
|
||||
## Method: '.str_replace('_', '\\_', $data['method']).'
|
||||
[Back to methods index](index.md)
|
||||
|
||||
|
||||
';
|
||||
if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) {
|
||||
$header .= '**' . \danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']] . "**\n\n\n\n\n";
|
||||
file_put_contents('methods/' . $method . '.md', $header);
|
||||
$header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n";
|
||||
file_put_contents('methods/'.$method.'.md', $header);
|
||||
continue;
|
||||
}
|
||||
if ($this->td) {
|
||||
@ -148,17 +149,17 @@ description: ' . $description . '
|
||||
|
||||
';
|
||||
}
|
||||
$header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] . PHP_EOL . PHP_EOL : '';
|
||||
$header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'].PHP_EOL.PHP_EOL : '';
|
||||
$table .= '
|
||||
|
||||
';
|
||||
$return = '### Return type: [' . str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md)
|
||||
$return = '### Return type: ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)
|
||||
|
||||
';
|
||||
$bot = !in_array($data['method'], $bots);
|
||||
$example = '';
|
||||
if (!isset($this->settings['td'])) {
|
||||
$example .= '### Can bots use this method: **' . ($bot ? 'YES' : 'NO') . "**\n\n\n";
|
||||
$example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n";
|
||||
if (isset($errors['result'][$data['method']])) {
|
||||
$example .= '### Errors this method can return:
|
||||
|
||||
@ -166,7 +167,7 @@ description: ' . $description . '
|
||||
|----------|---------------|
|
||||
';
|
||||
foreach ($errors['result'][$data['method']] as $error) {
|
||||
$example .= '|' . $error . '|' . $errors['human_result'][$error][0] . '|' . "\n";
|
||||
$example .= '|'.$error.'|'.$errors['human_result'][$error][0].'|'."\n";
|
||||
}
|
||||
$example .= "\n\n";
|
||||
}
|
||||
@ -176,44 +177,44 @@ description: ' . $description . '
|
||||
```
|
||||
$MadelineProto = new \\danog\\MadelineProto\\API();
|
||||
$MadelineProto->session = \'mySession.madeline\';
|
||||
' . ($bot ? 'if (isset($token)) { // Login as a bot
|
||||
'.($bot ? 'if (isset($token)) { // Login as a bot
|
||||
$MadelineProto->bot_login($token);
|
||||
}
|
||||
' : '') . 'if (isset($number)) { // Login as a user
|
||||
' : '').'if (isset($number)) { // Login as a user
|
||||
$MadelineProto->phone_login($number);
|
||||
$code = readline(\'Enter the code you received: \'); // Or do this in two separate steps in an HTTP API
|
||||
$MadelineProto->complete_phone_login($code);
|
||||
}
|
||||
|
||||
$' . $type . ' = $MadelineProto->' . $php_method . '([' . $params . ']);
|
||||
$'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']);
|
||||
```
|
||||
|
||||
Or, if you\'re using the [PWRTelegram HTTP API](https://pwrtelegram.xyz):
|
||||
|
||||
' . ($bot ? '### As a bot:
|
||||
'.($bot ? '### As a bot:
|
||||
|
||||
POST/GET to `https://api.pwrtelegram.xyz/botTOKEN/madeline`
|
||||
|
||||
Parameters:
|
||||
|
||||
* method - ' . $data['method'] . '
|
||||
* params - `{' . $json_params . '}`
|
||||
* method - '.$data['method'].'
|
||||
* params - `{'.$json_params.'}`
|
||||
|
||||
' : '') . '
|
||||
' : '').'
|
||||
|
||||
### As a user:
|
||||
|
||||
POST/GET to `https://api.pwrtelegram.xyz/userTOKEN/' . $data['method'] . '`
|
||||
POST/GET to `https://api.pwrtelegram.xyz/userTOKEN/'.$data['method'].'`
|
||||
|
||||
Parameters:
|
||||
|
||||
' . $pwr_params . '
|
||||
'.$pwr_params.'
|
||||
|
||||
|
||||
Or, if you\'re into Lua:
|
||||
|
||||
```
|
||||
' . $type . ' = ' . $data['method'] . '({' . $lua_params . '})
|
||||
'.$type.' = '.$data['method'].'({'.$lua_params.'})
|
||||
```
|
||||
|
||||
');
|
||||
@ -230,7 +231,7 @@ You can provide bot API reply_markup objects here.
|
||||
$example .= '
|
||||
## Return value
|
||||
|
||||
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of [' . str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) will be returned instead.
|
||||
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead.
|
||||
|
||||
|
||||
';
|
||||
@ -270,7 +271,7 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
||||
';
|
||||
}
|
||||
}
|
||||
file_put_contents('methods/' . $method . '.md', $header . $table . $return . $example);
|
||||
file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example);
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Generating methods index...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
ksort($this->docs_methods);
|
||||
@ -279,10 +280,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
|
||||
$new_namespace = preg_replace('/_.*/', '', $method);
|
||||
$br = $new_namespace != $last_namespace ? '***
|
||||
<br><br>' : '';
|
||||
$value = $br . $value;
|
||||
$value = $br.$value;
|
||||
$last_namespace = $new_namespace;
|
||||
}
|
||||
file_put_contents('methods/' . $this->index, '---
|
||||
file_put_contents('methods/'.$this->index, '---
|
||||
title: Methods
|
||||
description: List of methods
|
||||
---
|
||||
@ -312,6 +313,6 @@ $MadelineProto->[get_full_info](https://docs.madelineproto.xyz/get_full_info.htm
|
||||
$MadelineProto->[get_self](https://docs.madelineproto.xyz/get_self.html)();
|
||||
|
||||
|
||||
' . implode('', $this->docs_methods));
|
||||
'.implode('', $this->docs_methods));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,16 +10,19 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
use TL\PrettyException;
|
||||
public static $rollbar = true;
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception' . ($this->message !== '' ? ': ' : '') . $this->message . ' in ' . $this->file . ':' . $this->line . PHP_EOL . 'Revision: ' . @file_get_contents(__DIR__ . '/../../../.git/refs/heads/master') . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . $this->getTLTrace();
|
||||
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.'Revision: '.@file_get_contents(__DIR__.'/../../../.git/refs/heads/master').PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.$this->getTLTrace();
|
||||
}
|
||||
|
||||
public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null)
|
||||
{
|
||||
$this->prettify_tl();
|
||||
@ -34,7 +37,7 @@ class Exception extends \Exception
|
||||
$this->line = $line;
|
||||
}
|
||||
parent::__construct($message, $code, $previous);
|
||||
\danog\MadelineProto\Logger::log([$message . ' in ' . basename($this->file) . ':' . $this->line], \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
\danog\MadelineProto\Logger::log([$message.' in '.basename($this->file).':'.$this->line], \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
if (in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
||||
return;
|
||||
}
|
||||
@ -45,6 +48,7 @@ class Exception extends \Exception
|
||||
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, debug_backtrace(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ExceptionErrorHandler.
|
||||
*
|
||||
@ -57,6 +61,7 @@ class Exception extends \Exception
|
||||
return true;
|
||||
// return true to continue through the others error handlers
|
||||
}
|
||||
|
||||
throw new self($errstr, $errno, null, $errfile, $errline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -13,6 +13,7 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
/*
|
||||
* Logger class
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class Logger
|
||||
@ -37,6 +38,7 @@ class Logger
|
||||
const WARNING = 2;
|
||||
const ERROR = 1;
|
||||
const FATAL_ERROR = 0;
|
||||
|
||||
public static function class_exists()
|
||||
{
|
||||
self::$has_thread = class_exists('\\Thread') && method_exists('\\Thread', 'getCurrentThread');
|
||||
@ -50,6 +52,7 @@ class Logger
|
||||
if (!defined('\\danog\\MadelineProto\\VoIP::PHP_LIBTGVOIP_VERSION') || \danog\MadelineProto\VoIP::PHP_LIBTGVOIP_VERSION !== '1.1.2') {
|
||||
throw new \danog\MadelineProto\Exception(hex2bin(\danog\MadelineProto\Lang::$current_lang['v_tgerror']), 0, null, 'MadelineProto', 1);
|
||||
}
|
||||
|
||||
try {
|
||||
\Threaded::extend('\\danog\\MadelineProto\\VoIP');
|
||||
} catch (\RuntimeException $e) {
|
||||
@ -61,11 +64,13 @@ class Logger
|
||||
self::$colors[self::WARNING] = implode(';', [self::foreground['white'], self::set['dim'], self::background['red']]);
|
||||
self::$colors[self::ERROR] = implode(';', [self::foreground['white'], self::set['bold'], self::background['red']]);
|
||||
self::$colors[self::FATAL_ERROR] = implode(';', [self::foreground['red'], self::set['bold'], self::background['light_gray']]);
|
||||
|
||||
try {
|
||||
self::$isatty = defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor function
|
||||
* Accepts various logger modes:
|
||||
@ -83,10 +88,11 @@ class Logger
|
||||
}
|
||||
self::$mode = $mode;
|
||||
self::$optional = $optional;
|
||||
self::$prefix = $prefix === '' ? '' : ', ' . $prefix;
|
||||
self::$prefix = $prefix === '' ? '' : ', '.$prefix;
|
||||
self::$level = $level;
|
||||
self::class_exists();
|
||||
}
|
||||
|
||||
public static function log($params, $level = self::NOTICE)
|
||||
{
|
||||
if (self::$mode === 4) {
|
||||
@ -103,20 +109,20 @@ class Logger
|
||||
if (!is_string($param)) {
|
||||
$param = json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
$param = str_pad(basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0]['file'], '.php') . $prefix . ': ', 16 + strlen($prefix)) . "\t" . $param;
|
||||
$param = str_pad(basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0]['file'], '.php').$prefix.': ', 16 + strlen($prefix))."\t".$param;
|
||||
switch (self::$mode) {
|
||||
case 1:
|
||||
error_log($param);
|
||||
break;
|
||||
case 2:
|
||||
error_log($param . PHP_EOL, 3, self::$optional);
|
||||
error_log($param.PHP_EOL, 3, self::$optional);
|
||||
break;
|
||||
case 3:
|
||||
echo self::$isatty ? "\33[" . self::$colors[$level] . 'm' . $param . "\33[0m" . PHP_EOL : $param . PHP_EOL;
|
||||
echo self::$isatty ? "\33[".self::$colors[$level].'m'.$param."\33[0m".PHP_EOL : $param.PHP_EOL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class Lua
|
||||
@ -18,6 +19,7 @@ class Lua
|
||||
public $MadelineProto;
|
||||
protected $Lua;
|
||||
protected $script;
|
||||
|
||||
public function __magic_construct($script, $MadelineProto)
|
||||
{
|
||||
if (!file_exists($script)) {
|
||||
@ -28,10 +30,12 @@ class Lua
|
||||
$this->script = $script;
|
||||
$this->__wakeup();
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['MadelineProto', 'script'];
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->Lua = new \Lua($this->script);
|
||||
@ -65,6 +69,7 @@ class Lua
|
||||
$this->MadelineProto->{$namespace}->lua = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function tdcli_function($params, $cb = null, $cb_extra = null)
|
||||
{
|
||||
$params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcli_to_td($params));
|
||||
@ -75,8 +80,10 @@ class Lua
|
||||
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)
|
||||
{
|
||||
$result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]);
|
||||
@ -84,12 +91,15 @@ class Lua
|
||||
$cb($result, $cb_extra);
|
||||
}
|
||||
self::convert_objects($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
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)) {
|
||||
@ -101,23 +111,29 @@ class Lua
|
||||
}, array_flip($array)));
|
||||
}
|
||||
}
|
||||
|
||||
private function is_sequential(array $arr)
|
||||
{
|
||||
if ([] === $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;
|
||||
}
|
||||
|
||||
return $this->Lua->{$name};
|
||||
}
|
||||
|
||||
public function __call($name, $params)
|
||||
{
|
||||
self::convert_objects($params);
|
||||
|
||||
try {
|
||||
return $this->Lua->{$name}(...$params);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -136,10 +152,12 @@ class Lua
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
return $this->Lua->{$name} = $value;
|
||||
}
|
||||
|
||||
public static function convert_objects(&$data)
|
||||
{
|
||||
array_walk_recursive($data, function (&$value, $key) {
|
||||
@ -161,4 +179,4 @@ class Lua
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -21,16 +22,19 @@ trait AckHandler
|
||||
{
|
||||
// The server acknowledges that it received my message
|
||||
if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id])) {
|
||||
\danog\MadelineProto\Logger::log(["WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(["WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?'], \danog\MadelineProto\Logger::WARNING);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['ack'] = true;
|
||||
}
|
||||
|
||||
public function ack_incoming_message_id($message_id, $datacenter)
|
||||
{
|
||||
// I let the server know that I received its message
|
||||
if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$message_id])) {
|
||||
\danog\MadelineProto\Logger::log(["WARNING: Couldn't find message id " . $message_id . ' in the array of incomgoing messages. Maybe try to increase its size?'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(["WARNING: Couldn't find message id ".$message_id.' in the array of incomgoing messages. Maybe try to increase its size?'], \danog\MadelineProto\Logger::WARNING);
|
||||
//throw new \danog\MadelineProto\Exception("Couldn't find message id ".$message_id.' in the array of incoming message ids. Maybe try to increase its size?');
|
||||
}
|
||||
if ($this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === null || $this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") {
|
||||
@ -42,4 +46,4 @@ trait AckHandler
|
||||
return true;
|
||||
//$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -77,9 +78,9 @@ trait AuthKeyHandler
|
||||
list($p, $q) = [$q, $p];
|
||||
}
|
||||
if (!$pq->equals($p->multiply($q))) {
|
||||
throw new \danog\MadelineProto\SecurityException("couldn't compute p and q. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: " . $p->multiply($q));
|
||||
throw new \danog\MadelineProto\SecurityException("couldn't compute p and q. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: ".$p->multiply($q));
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Factorization ' . $pq . ' = ' . $p . ' * ' . $q], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Factorization '.$pq.' = '.$p.' * '.$q], \danog\MadelineProto\Logger::VERBOSE);
|
||||
/*
|
||||
* ***********************************************************************
|
||||
* Serialize object for req_DH_params
|
||||
@ -88,14 +89,14 @@ trait AuthKeyHandler
|
||||
$q_bytes = $q->toBytes();
|
||||
$new_nonce = $this->random(32);
|
||||
$data_unserialized = ['pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in];
|
||||
$p_q_inner_data = $this->serialize_object(['type' => 'p_q_inner_data' . ($expires_in < 0 ? '' : '_temp')], $data_unserialized, 'p_q_inner_data');
|
||||
$p_q_inner_data = $this->serialize_object(['type' => 'p_q_inner_data'.($expires_in < 0 ? '' : '_temp')], $data_unserialized, 'p_q_inner_data');
|
||||
/*
|
||||
* ***********************************************************************
|
||||
* Encrypt serialized object
|
||||
*/
|
||||
$sha_digest = sha1($p_q_inner_data, true);
|
||||
$random_bytes = $this->random(255 - strlen($p_q_inner_data) - strlen($sha_digest));
|
||||
$to_encrypt = $sha_digest . $p_q_inner_data . $random_bytes;
|
||||
$to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes;
|
||||
$encrypted_data = $key->encrypt($to_encrypt);
|
||||
\danog\MadelineProto\Logger::log(['Starting Diffie Hellman key exchange'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
/*
|
||||
@ -146,8 +147,8 @@ trait AuthKeyHandler
|
||||
* Get key, iv and decrypt answer
|
||||
*/
|
||||
$encrypted_answer = $server_dh_params['encrypted_answer'];
|
||||
$tmp_aes_key = sha1($new_nonce . $server_nonce, true) . substr(sha1($server_nonce . $new_nonce, true), 0, 12);
|
||||
$tmp_aes_iv = substr(sha1($server_nonce . $new_nonce, true), 12, 8) . sha1($new_nonce . $new_nonce, true) . substr($new_nonce, 0, 4);
|
||||
$tmp_aes_key = sha1($new_nonce.$server_nonce, true).substr(sha1($server_nonce.$new_nonce, true), 0, 12);
|
||||
$tmp_aes_iv = substr(sha1($server_nonce.$new_nonce, true), 12, 8).sha1($new_nonce.$new_nonce, true).substr($new_nonce, 0, 4);
|
||||
$answer_with_hash = $this->ige_decrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv);
|
||||
/*
|
||||
* ***********************************************************************
|
||||
@ -227,8 +228,8 @@ trait AuthKeyHandler
|
||||
* ***********************************************************************
|
||||
* encrypt client_DH_inner_data
|
||||
*/
|
||||
$data_with_sha = sha1($data, true) . $data;
|
||||
$data_with_sha_padded = $data_with_sha . $this->random($this->posmod(-strlen($data_with_sha), 16));
|
||||
$data_with_sha = sha1($data, true).$data;
|
||||
$data_with_sha_padded = $data_with_sha.$this->random($this->posmod(-strlen($data_with_sha), 16));
|
||||
$encrypted_data = $this->ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
|
||||
\danog\MadelineProto\Logger::log(['Executing set_client_DH_params...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
/*
|
||||
@ -258,9 +259,9 @@ trait AuthKeyHandler
|
||||
$auth_key_str = $auth_key->toBytes();
|
||||
$auth_key_sha = sha1($auth_key_str, true);
|
||||
$auth_key_aux_hash = substr($auth_key_sha, 0, 8);
|
||||
$new_nonce_hash1 = substr(sha1($new_nonce . chr(1) . $auth_key_aux_hash, true), -16);
|
||||
$new_nonce_hash2 = substr(sha1($new_nonce . chr(2) . $auth_key_aux_hash, true), -16);
|
||||
$new_nonce_hash3 = substr(sha1($new_nonce . chr(3) . $auth_key_aux_hash, true), -16);
|
||||
$new_nonce_hash1 = substr(sha1($new_nonce.chr(1).$auth_key_aux_hash, true), -16);
|
||||
$new_nonce_hash2 = substr(sha1($new_nonce.chr(2).$auth_key_aux_hash, true), -16);
|
||||
$new_nonce_hash3 = substr(sha1($new_nonce.chr(3).$auth_key_aux_hash, true), -16);
|
||||
/*
|
||||
* ***********************************************************************
|
||||
* Check if the client's nonce and the server's nonce are the same
|
||||
@ -290,6 +291,7 @@ trait AuthKeyHandler
|
||||
$res_authorization['id'] = substr($auth_key_sha, -8);
|
||||
$res_authorization['connection_inited'] = false;
|
||||
\danog\MadelineProto\Logger::log(['Auth key generated'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $res_authorization;
|
||||
case 'dh_gen_retry':
|
||||
if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) {
|
||||
@ -310,15 +312,15 @@ trait AuthKeyHandler
|
||||
}
|
||||
}
|
||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi';
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
if ($e->rpc === 'RPC_CALL_FAIL') {
|
||||
throw $e;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
} finally {
|
||||
$this->datacenter->sockets[$datacenter]->new_outgoing = [];
|
||||
$this->datacenter->sockets[$datacenter]->new_incoming = [];
|
||||
@ -328,6 +330,7 @@ trait AuthKeyHandler
|
||||
throw new \danog\MadelineProto\SecurityException('Auth Failed');
|
||||
}
|
||||
}
|
||||
|
||||
public function check_G($g_a, $p)
|
||||
{
|
||||
/*
|
||||
@ -343,8 +346,10 @@ trait AuthKeyHandler
|
||||
if ($g_a->compare($this->twoe1984) < 0 || $g_a->compare($p->subtract($this->twoe1984)) >= 0) {
|
||||
throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < gA < dh_prime - 2^1984 is false).');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function check_p_g($p, $g)
|
||||
{
|
||||
/*
|
||||
@ -387,11 +392,14 @@ trait AuthKeyHandler
|
||||
if ($g->compare($this->one) <= 0 || $g->compare($p->subtract($this->one)) >= 0) {
|
||||
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_dh_config()
|
||||
{
|
||||
$this->updates_state['sync_loading'] = true;
|
||||
|
||||
try {
|
||||
$dh_config = $this->method_call('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]);
|
||||
} finally {
|
||||
@ -399,13 +407,16 @@ trait AuthKeyHandler
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public function bind_temp_auth_key($expires_in, $datacenter)
|
||||
{
|
||||
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
|
||||
@ -419,36 +430,40 @@ trait AuthKeyHandler
|
||||
$message_data = $this->serialize_object(['type' => 'bind_auth_key_inner'], ['nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bind_temp_auth_key_inner');
|
||||
$message_id = $this->generate_message_id($datacenter);
|
||||
$seq_no = 0;
|
||||
$encrypted_data = $this->random(16) . $message_id . pack('VV', $seq_no, strlen($message_data)) . $message_data;
|
||||
$encrypted_data = $this->random(16).$message_id.pack('VV', $seq_no, strlen($message_data)).$message_data;
|
||||
$message_key = substr(sha1($encrypted_data, true), -16);
|
||||
$padding = $this->random($this->posmod(-strlen($encrypted_data), 16));
|
||||
//$message_key = substr(hash('sha256', substr($this->datacenter->sockets[$datacenter]->auth_key['auth_key'], 88, 32).$encrypted_data.$padding, true), 8, 16);
|
||||
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->auth_key['auth_key']);
|
||||
$encrypted_message = $this->datacenter->sockets[$datacenter]->auth_key['id'] . $message_key . $this->ige_encrypt($encrypted_data . $padding, $aes_key, $aes_iv);
|
||||
$encrypted_message = $this->datacenter->sockets[$datacenter]->auth_key['id'].$message_key.$this->ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
||||
$res = $this->method_call('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['message_id' => $message_id, 'datacenter' => $datacenter]);
|
||||
if ($res === true) {
|
||||
\danog\MadelineProto\Logger::log(['Successfully binded temporary and permanent authorization keys, DC ' . $datacenter], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Successfully binded temporary and permanent authorization keys, DC '.$datacenter], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return true;
|
||||
}
|
||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
\danog\MadelineProto\Logger::log(['An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...'], \danog\MadelineProto\Logger::WARNING);
|
||||
} finally {
|
||||
$this->datacenter->sockets[$datacenter]->new_outgoing = [];
|
||||
$this->datacenter->sockets[$datacenter]->new_incoming = [];
|
||||
}
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.');
|
||||
}
|
||||
|
||||
// Creates authorization keys
|
||||
public function init_authorization()
|
||||
{
|
||||
$this->initing_authorization = true;
|
||||
$this->updates_state['sync_loading'] = true;
|
||||
$this->postpone_updates = true;
|
||||
|
||||
try {
|
||||
foreach ($this->datacenter->sockets as $id => $socket) {
|
||||
$cdn = strpos($id, 'cdn');
|
||||
@ -500,6 +515,7 @@ trait AuthKeyHandler
|
||||
$this->updates_state['sync_loading'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function sync_authorization($id)
|
||||
{
|
||||
if (!isset($this->datacenter->sockets[$id])) {
|
||||
@ -513,15 +529,15 @@ trait AuthKeyHandler
|
||||
}
|
||||
if ($authorized_socket->temp_auth_key !== null && $authorized_socket->auth_key !== null && $authorized_socket->authorized === true && $this->authorized === self::LOGGED_IN && $socket->authorized === false && strpos($authorized_dc_id, 'cdn') === false) {
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log(['Trying to copy authorization from dc ' . $authorized_dc_id . ' to dc ' . $id]);
|
||||
\danog\MadelineProto\Logger::log(['Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id]);
|
||||
$exported_authorization = $this->method_call('auth.exportAuthorization', ['dc_id' => preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]);
|
||||
$authorization = $this->method_call('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]);
|
||||
$socket->authorized = true;
|
||||
break;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
\danog\MadelineProto\Logger::log(['Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage()], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage()], \danog\MadelineProto\Logger::ERROR);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
\danog\MadelineProto\Logger::log(['Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage()], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage()], \danog\MadelineProto\Logger::ERROR);
|
||||
if ($e->rpc === 'DC_ID_INVALID') {
|
||||
break;
|
||||
}
|
||||
@ -531,4 +547,4 @@ trait AuthKeyHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -82,15 +83,16 @@ trait CallHandler
|
||||
}
|
||||
if ($this->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($serialized)) > $this->settings['requests']['gzip_encode_if_gt'] && ($g = strlen($gzipped = gzencode($serialized))) < $l) {
|
||||
$serialized = $this->serialize_object(['type' => 'gzip_packed'], ['packed_data' => $gzipped], 'gzipped data');
|
||||
\danog\MadelineProto\Logger::log(['Using GZIP compression for ' . $method . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Using GZIP compression for '.$method.', saved '.($l - $g).' bytes of data, reduced call size by '.$g * 100 / $l.'%'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
}
|
||||
$last_recv = $this->last_recv;
|
||||
for ($count = 1; $count <= $this->settings['max_tries']['query']; $count++) {
|
||||
if ($canunset = !$this->updates_state['sync_loading']) {
|
||||
$this->updates_state['sync_loading'] = true;
|
||||
}
|
||||
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log(['Calling method (try number ' . $count . ' for ' . $method . ')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Calling method (try number '.$count.' for '.$method.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if ($this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key !== null) {
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->object_queue[] = ['body' => $serialized, 'content_related' => $content_related, 'msg_id' => $message_id = isset($aargs['message_id']) ? $aargs['message_id'] : $this->generate_message_id($aargs['datacenter'])];
|
||||
if (count($this->datacenter->sockets[$aargs['datacenter']]->ack_queue)) {
|
||||
@ -131,7 +133,7 @@ trait CallHandler
|
||||
while ($server_answer === null && $res_count++ < $this->settings['max_tries']['response'] + 1) {
|
||||
// Loop until we get a response, loop for a max of $this->settings['max_tries']['response'] times
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log(['Getting response (try number ' . $res_count . ' for ' . $method . ')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Getting response (try number '.$res_count.' for '.$method.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (!isset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']) || !isset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']]['content'])) {
|
||||
// Checks if I have received the response to the called method, if not continue looping
|
||||
if ($only_updates) {
|
||||
@ -153,9 +155,11 @@ trait CallHandler
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Resetting auth key...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key = null;
|
||||
$this->init_authorization();
|
||||
|
||||
throw new \danog\MadelineProto\Exception('I had to recreate the temporary authorization key');
|
||||
}
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
||||
}
|
||||
$only_updates = $this->handle_messages($aargs['datacenter']);
|
||||
@ -164,10 +168,10 @@ trait CallHandler
|
||||
if ($e->getMessage() === 'I had to recreate the temporary authorization key') {
|
||||
continue 2;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['An error getting response of method ' . $method . ': ' . $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An error getting response of method '.$method.': '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
continue;
|
||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||
\danog\MadelineProto\Logger::log(['An error getting response of method ' . $method . ': ' . $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['An error getting response of method '.$method.': '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -193,15 +197,16 @@ trait CallHandler
|
||||
continue 3;
|
||||
case 16:
|
||||
case 17:
|
||||
\danog\MadelineProto\Logger::log(['Received bad_msg_notification: ' . self::BAD_MSG_ERROR_CODES[$server_answer['error_code']]], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$server_answer['error_code']]], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->time_delta = (int) (new \phpseclib\Math\BigInteger(strrev($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']), 256))->bitwise_rightShift(32)->subtract(new \phpseclib\Math\BigInteger(time()))->toString();
|
||||
\danog\MadelineProto\Logger::log(['Set time delta to ' . $this->datacenter->sockets[$aargs['datacenter']]->time_delta], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Set time delta to '.$this->datacenter->sockets[$aargs['datacenter']]->time_delta], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->reset_session();
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key = null;
|
||||
$this->init_authorization();
|
||||
continue 3;
|
||||
}
|
||||
throw new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: ' . self::BAD_MSG_ERROR_CODES[$server_answer['error_code']], $server_answer['error_code']);
|
||||
|
||||
throw new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$server_answer['error_code']], $server_answer['error_code']);
|
||||
break;
|
||||
case 'boolTrue':
|
||||
case 'boolFalse':
|
||||
@ -212,16 +217,16 @@ trait CallHandler
|
||||
$server_answer = $this->MTProto_to_botAPI($server_answer, $args);
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$last_error = $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine();
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling method ' . $method . ': ' . $last_error . '. Recreating connection and retrying to call method...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$last_error = $e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine();
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling method '.$method.': '.$last_error.'. Recreating connection and retrying to call method...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->close_and_reopen($aargs['datacenter']);
|
||||
if ($e->getMessage() === 'Re-executing query after server error...') {
|
||||
return $this->method_call($method, $args, $aargs);
|
||||
}
|
||||
continue;
|
||||
} catch (\RuntimeException $e) {
|
||||
$last_error = $e->getMessage() . ' in ' . basename($e->getFile(), '.php') . ' on line ' . $e->getLine();
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling method ' . $method . ': ' . $last_error . '. Recreating connection and retrying to call method...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$last_error = $e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine();
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling method '.$method.': '.$last_error.'. Recreating connection and retrying to call method...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->close_and_reopen($aargs['datacenter']);
|
||||
continue;
|
||||
} finally {
|
||||
@ -244,11 +249,13 @@ trait CallHandler
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Resetting auth key...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key = null;
|
||||
$this->init_authorization();
|
||||
|
||||
return $this->method_call($method, $args, $aargs);
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while calling method ' . $method . ' (' . $last_error . ').');
|
||||
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.' ('.$last_error.').');
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Got response for method ' . $method . ' @ try ' . $count . ' (response try ' . $res_count . ')'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Got response for method '.$method.' @ try '.$count.' (response try '.$res_count.')'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if ($this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key !== null && (!isset($this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['connection_inited']) || $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['connection_inited'] === false)) {
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['connection_inited'] = true;
|
||||
}
|
||||
@ -260,13 +267,16 @@ trait CallHandler
|
||||
$server_answer[] = $this->method_call($method, $args, $aargs);
|
||||
}
|
||||
}
|
||||
|
||||
return $server_answer;
|
||||
}
|
||||
if ($method === 'req_pq') {
|
||||
throw new \danog\MadelineProto\RPCErrorException('RPC_CALL_FAIL');
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while calling method ' . $method . ' (' . $last_error . ').');
|
||||
|
||||
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])
|
||||
{
|
||||
if (!is_array($args)) {
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
trait Crypt
|
||||
@ -17,42 +18,51 @@ trait Crypt
|
||||
public function aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||
{
|
||||
$x = $to_server ? 0 : 8;
|
||||
$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);
|
||||
$aes_key = substr($sha256_a, 0, 8) . substr($sha256_b, 8, 16) . substr($sha256_a, 24, 8);
|
||||
$aes_iv = substr($sha256_b, 0, 8) . substr($sha256_a, 8, 16) . substr($sha256_b, 24, 8);
|
||||
$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);
|
||||
$aes_key = substr($sha256_a, 0, 8).substr($sha256_b, 8, 16).substr($sha256_a, 24, 8);
|
||||
$aes_iv = substr($sha256_b, 0, 8).substr($sha256_a, 8, 16).substr($sha256_b, 24, 8);
|
||||
|
||||
return [$aes_key, $aes_iv];
|
||||
}
|
||||
|
||||
public function old_aes_calculate($msg_key, $auth_key, $to_server = true)
|
||||
{
|
||||
$x = $to_server ? 0 : 8;
|
||||
$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_c = sha1(substr($auth_key, 64 + $x, 32) . $msg_key, true);
|
||||
$sha1_d = sha1($msg_key . substr($auth_key, 96 + $x, 32), true);
|
||||
$aes_key = substr($sha1_a, 0, 8) . substr($sha1_b, 8, 12) . substr($sha1_c, 4, 12);
|
||||
$aes_iv = substr($sha1_a, 8, 12) . substr($sha1_b, 0, 8) . substr($sha1_c, 16, 4) . substr($sha1_d, 0, 8);
|
||||
$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_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true);
|
||||
$sha1_d = sha1($msg_key.substr($auth_key, 96 + $x, 32), true);
|
||||
$aes_key = substr($sha1_a, 0, 8).substr($sha1_b, 8, 12).substr($sha1_c, 4, 12);
|
||||
$aes_iv = substr($sha1_a, 8, 12).substr($sha1_b, 0, 8).substr($sha1_c, 16, 4).substr($sha1_d, 0, 8);
|
||||
|
||||
return [$aes_key, $aes_iv];
|
||||
}
|
||||
|
||||
public function ige_encrypt($message, $key, $iv)
|
||||
{
|
||||
$cipher = new \phpseclib\Crypt\AES('ige');
|
||||
$cipher->setKey($key);
|
||||
$cipher->setIV($iv);
|
||||
|
||||
return @$cipher->encrypt($message);
|
||||
}
|
||||
|
||||
public function ctr_encrypt($message, $key, $iv)
|
||||
{
|
||||
$cipher = new \phpseclib\Crypt\AES('ctr');
|
||||
$cipher->setKey($key);
|
||||
$cipher->setIV($iv);
|
||||
|
||||
return @$cipher->encrypt($message);
|
||||
}
|
||||
|
||||
public function ige_decrypt($message, $key, $iv)
|
||||
{
|
||||
$cipher = new \phpseclib\Crypt\AES('ige');
|
||||
$cipher->setKey($key);
|
||||
$cipher->setIV($iv);
|
||||
|
||||
return @$cipher->decrypt($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -32,21 +33,21 @@ trait Files
|
||||
}
|
||||
if ($cb === null) {
|
||||
$cb = function ($percent) {
|
||||
\danog\MadelineProto\Logger::log(['Upload status: ' . $percent . '%'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Upload status: '.$percent.'%'], \danog\MadelineProto\Logger::NOTICE);
|
||||
};
|
||||
}
|
||||
$part_size = 512 * 1024;
|
||||
$part_total_num = (int) ceil($file_size / $part_size);
|
||||
$part_num = 0;
|
||||
$method = $file_size > 10 * 1024 * 1024 ? 'upload.saveBigFilePart' : 'upload.saveFilePart';
|
||||
$constructor = 'input' . ($encrypted === true ? 'Encrypted' : '') . ($file_size > 10 * 1024 * 1024 ? 'FileBig' : 'File') . ($encrypted === true ? 'Uploaded' : '');
|
||||
$constructor = 'input'.($encrypted === true ? 'Encrypted' : '').($file_size > 10 * 1024 * 1024 ? 'FileBig' : 'File').($encrypted === true ? 'Uploaded' : '');
|
||||
$file_id = $this->random(8);
|
||||
$f = fopen($file, 'r');
|
||||
fseek($f, 0);
|
||||
if ($encrypted === true) {
|
||||
$key = $this->random(32);
|
||||
$iv = $this->random(32);
|
||||
$digest = hash('md5', $key . $iv, true);
|
||||
$digest = hash('md5', $key.$iv, true);
|
||||
$fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4));
|
||||
$ige = new \phpseclib\Crypt\AES('ige');
|
||||
$ige->setIV($iv);
|
||||
@ -61,7 +62,7 @@ trait Files
|
||||
}
|
||||
hash_update($ctx, $bytes);
|
||||
if (!$this->method_call($method, ['file_id' => $file_id, 'file_part' => $part_num++, 'file_total_parts' => $part_total_num, 'bytes' => $bytes], ['heavy' => true, 'datacenter' => &$datacenter])) {
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while uploading file part ' . $part_num);
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while uploading file part '.$part_num);
|
||||
}
|
||||
$cb(ftell($f) * 100 / $file_size);
|
||||
}
|
||||
@ -73,12 +74,15 @@ trait Files
|
||||
$constructor['iv'] = $iv;
|
||||
$constructor['md5_checksum'] = '';
|
||||
}
|
||||
|
||||
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)) {
|
||||
@ -101,7 +105,7 @@ trait Files
|
||||
if (isset($message_media['decrypted_message']['media']['file_name'])) {
|
||||
$pathinfo = pathinfo($message_media['decrypted_message']['media']['file_name']);
|
||||
if (isset($pathinfo['extension'])) {
|
||||
$res['ext'] = '.' . $pathinfo['extension'];
|
||||
$res['ext'] = '.'.$pathinfo['extension'];
|
||||
}
|
||||
$res['name'] = $pathinfo['filename'];
|
||||
}
|
||||
@ -116,7 +120,7 @@ trait Files
|
||||
case 'documentAttributeFilename':
|
||||
$pathinfo = pathinfo($attribute['file_name']);
|
||||
if (isset($pathinfo['extension'])) {
|
||||
$res['ext'] = '.' . $pathinfo['extension'];
|
||||
$res['ext'] = '.'.$pathinfo['extension'];
|
||||
}
|
||||
$res['name'] = $pathinfo['filename'];
|
||||
break;
|
||||
@ -129,7 +133,7 @@ trait Files
|
||||
if (isset($audio) && isset($audio['title']) && !isset($res['name'])) {
|
||||
$res['name'] = $audio['title'];
|
||||
if (isset($audio['performer'])) {
|
||||
$res['name'] .= ' - ' . $audio['performer'];
|
||||
$res['name'] .= ' - '.$audio['performer'];
|
||||
}
|
||||
}
|
||||
if (!isset($res['ext'])) {
|
||||
@ -138,6 +142,7 @@ trait Files
|
||||
if (!isset($res['name'])) {
|
||||
$res['name'] = $message_media['file']['access_hash'];
|
||||
}
|
||||
|
||||
return $res;
|
||||
case 'photo':
|
||||
case 'messageMediaPhoto':
|
||||
@ -146,7 +151,7 @@ trait Files
|
||||
} else {
|
||||
$photo = end($message_media['photo']['sizes']);
|
||||
}
|
||||
$res['name'] = $photo['location']['volume_id'] . '_' . $photo['location']['local_id'];
|
||||
$res['name'] = $photo['location']['volume_id'].'_'.$photo['location']['local_id'];
|
||||
$res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $photo['location']['volume_id'], 'local_id' => $photo['location']['local_id'], 'secret' => $photo['location']['secret'], 'dc_id' => $photo['location']['dc_id']];
|
||||
$res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], '.jpg');
|
||||
$res['mime'] = 'image/jpeg';
|
||||
@ -156,10 +161,11 @@ trait Files
|
||||
if (isset($photo['location']['bytes'])) {
|
||||
$res['size'] = strlen($photo['location']['bytes']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
case 'photoSize':
|
||||
case 'photoCachedSize':
|
||||
$res['name'] = $message_media['location']['volume_id'] . '_' . $message_media['location']['local_id'];
|
||||
$res['name'] = $message_media['location']['volume_id'].'_'.$message_media['location']['local_id'];
|
||||
$res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $message_media['location']['volume_id'], 'local_id' => $message_media['location']['local_id'], 'secret' => $message_media['location']['secret'], 'dc_id' => $message_media['location']['dc_id']];
|
||||
$res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], '.jpg');
|
||||
$res['mime'] = 'image/jpeg';
|
||||
@ -169,6 +175,7 @@ trait Files
|
||||
if (isset($photo['location']['bytes'])) {
|
||||
$res['size'] = strlen($photo['location']['bytes']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
case 'decryptedMessageMediaExternalDocument':
|
||||
case 'document':
|
||||
@ -179,7 +186,7 @@ trait Files
|
||||
case 'documentAttributeFilename':
|
||||
$pathinfo = pathinfo($attribute['file_name']);
|
||||
if (isset($pathinfo['extension'])) {
|
||||
$res['ext'] = '.' . $pathinfo['extension'];
|
||||
$res['ext'] = '.'.$pathinfo['extension'];
|
||||
}
|
||||
$res['name'] = $pathinfo['filename'];
|
||||
break;
|
||||
@ -191,7 +198,7 @@ trait Files
|
||||
if (isset($audio) && isset($audio['title']) && !isset($res['name'])) {
|
||||
$res['name'] = $audio['title'];
|
||||
if (isset($audio['performer'])) {
|
||||
$res['name'] .= ' - ' . $audio['performer'];
|
||||
$res['name'] .= ' - '.$audio['performer'];
|
||||
}
|
||||
}
|
||||
$res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $message_media['document']['id'], 'access_hash' => $message_media['document']['access_hash'], 'version' => isset($message_media['document']['version']) ? $message_media['document']['version'] : 0, 'dc_id' => $message_media['document']['dc_id']];
|
||||
@ -204,18 +211,22 @@ trait Files
|
||||
if (isset($message_media['document']['size'])) {
|
||||
$res['size'] = $message_media['document']['size'];
|
||||
}
|
||||
$res['name'] .= '_' . $message_media['document']['id'];
|
||||
$res['name'] .= '_'.$message_media['document']['id'];
|
||||
$res['mime'] = $message_media['document']['mime_type'];
|
||||
|
||||
return $res;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor provided: ' . $message_media['_']);
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor provided: '.$message_media['_']);
|
||||
}
|
||||
}
|
||||
|
||||
public function download_to_dir($message_media, $dir, $cb = null)
|
||||
{
|
||||
$message_media = $this->get_download_info($message_media);
|
||||
return $this->download_to_file($message_media, $dir . '/' . $message_media['name'] . $message_media['ext'], $cb);
|
||||
|
||||
return $this->download_to_file($message_media, $dir.'/'.$message_media['name'].$message_media['ext'], $cb);
|
||||
}
|
||||
|
||||
public function download_to_file($message_media, $file, $cb = null)
|
||||
{
|
||||
$file = preg_replace('|/+|', '/', $file);
|
||||
@ -227,6 +238,7 @@ trait Files
|
||||
$stream = fopen($file, 'r+b');
|
||||
\danog\MadelineProto\Logger::log(['Waiting for lock of file to download...']);
|
||||
flock($stream, LOCK_EX);
|
||||
|
||||
try {
|
||||
$this->download_to_stream($message_media, $stream, $cb, filesize($file), -1);
|
||||
} finally {
|
||||
@ -234,13 +246,15 @@ trait Files
|
||||
fclose($stream);
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function download_to_stream($message_media, $stream, $cb = null, $offset = 0, $end = -1)
|
||||
{
|
||||
if ($cb === null) {
|
||||
$cb = function ($percent) {
|
||||
\danog\MadelineProto\Logger::log(['Download status: ' . $percent . '%'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Download status: '.$percent.'%'], \danog\MadelineProto\Logger::NOTICE);
|
||||
};
|
||||
}
|
||||
$message_media = $this->get_download_info($message_media);
|
||||
@ -256,7 +270,7 @@ trait Files
|
||||
$percent = 0;
|
||||
$datacenter = isset($message_media['InputFileLocation']['dc_id']) ? $message_media['InputFileLocation']['dc_id'] : $this->datacenter->curdc;
|
||||
if (isset($message_media['key'])) {
|
||||
$digest = hash('md5', $message_media['key'] . $message_media['iv'], true);
|
||||
$digest = hash('md5', $message_media['key'].$message_media['iv'], true);
|
||||
$fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4));
|
||||
if ($fingerprint !== $message_media['key_fingerprint']) {
|
||||
throw new \danog\MadelineProto\Exception('Fingerprint mismatch!');
|
||||
@ -272,6 +286,7 @@ trait Files
|
||||
if ($start_at = $offset % $part_size) {
|
||||
$offset -= $start_at;
|
||||
}
|
||||
|
||||
try {
|
||||
$res = $cdn ? $this->method_call('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]) : $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => &$datacenter]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -289,7 +304,7 @@ trait Files
|
||||
$message_media['cdn_key'] = $res['encryption_key'];
|
||||
$message_media['cdn_iv'] = $res['encryption_iv'];
|
||||
$old_dc = $datacenter;
|
||||
$datacenter = $res['dc_id'] . '_cdn';
|
||||
$datacenter = $res['dc_id'].'_cdn';
|
||||
if (!isset($this->datacenter->sockets[$datacenter])) {
|
||||
$this->config['expires'] = -1;
|
||||
$this->get_config([], ['datacenter' => $this->datacenter->curdc]);
|
||||
@ -300,6 +315,7 @@ trait Files
|
||||
if ($res['_'] === 'upload.cdnFileReuploadNeeded') {
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['cdn_reupload']], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->get_config([], ['datacenter' => $this->datacenter->curdc]);
|
||||
|
||||
try {
|
||||
$this->add_cdn_hashes($message_media['file_token'], $this->method_call('upload.reuploadCdnFile', ['file_token' => $message_media['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc]));
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -325,7 +341,7 @@ trait Files
|
||||
}
|
||||
}
|
||||
if (isset($message_media['cdn_key'])) {
|
||||
$ivec = substr($message_media['cdn_iv'], 0, 12) . pack('N', $offset >> 4);
|
||||
$ivec = substr($message_media['cdn_iv'], 0, 12).pack('N', $offset >> 4);
|
||||
$res['bytes'] = $this->ctr_encrypt($res['bytes'], $message_media['cdn_key'], $ivec);
|
||||
$this->check_cdn_hash($message_media['file_token'], $offset, $res['bytes'], $old_dc);
|
||||
}
|
||||
@ -358,9 +374,12 @@ trait Files
|
||||
if ($cdn) {
|
||||
$this->clear_cdn_hashes($message_media['file_token']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private $cdn_hashes = [];
|
||||
|
||||
private function add_cdn_hashes($file, $hashes)
|
||||
{
|
||||
if (!isset($this->cdn_hashes[$file])) {
|
||||
@ -370,6 +389,7 @@ trait Files
|
||||
$this->cdn_hashes[$file][$hash['offset']] = ['limit' => $hash['limit'], 'hash' => (string) $hash['hash']];
|
||||
}
|
||||
}
|
||||
|
||||
private function check_cdn_hash($file, $offset, $data, &$datacenter)
|
||||
{
|
||||
while (strlen($data)) {
|
||||
@ -377,19 +397,22 @@ trait Files
|
||||
$this->add_cdn_hashes($file, $this->method_call('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => $datacenter]));
|
||||
}
|
||||
if (!isset($this->cdn_hashes[$file][$offset])) {
|
||||
throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset ' . $offset);
|
||||
throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset '.$offset);
|
||||
}
|
||||
if (hash('sha256', substr($data, 0, $this->cdn_hashes[$file][$offset]['limit']), true) !== $this->cdn_hashes[$file][$offset]['hash']) {
|
||||
throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset ' . $offset);
|
||||
throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset '.$offset);
|
||||
}
|
||||
$data = substr($data, $this->cdn_hashes[$file][$offset]['limit']);
|
||||
$offset += $this->cdn_hashes[$file][$offset]['limit'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function clear_cdn_hashes($file)
|
||||
{
|
||||
unset($this->cdn_hashes[$file]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -19,10 +20,11 @@ trait MessageHandler
|
||||
{
|
||||
public function send_unencrypted_message($message_data, $message_id, $datacenter)
|
||||
{
|
||||
$message_data = "\0\0\0\0\0\0\0\0" . $message_id . $this->pack_unsigned_int(strlen($message_data)) . $message_data;
|
||||
$message_data = "\0\0\0\0\0\0\0\0".$message_id.$this->pack_unsigned_int(strlen($message_data)).$message_data;
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id] = ['response' => -1];
|
||||
$this->datacenter->sockets[$datacenter]->send_message($message_data);
|
||||
}
|
||||
|
||||
public function send_messages($datacenter)
|
||||
{
|
||||
if (count($this->datacenter->sockets[$datacenter]->object_queue) > 1) {
|
||||
@ -45,15 +47,15 @@ trait MessageHandler
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
$plaintext = $this->datacenter->sockets[$datacenter]->temp_auth_key['server_salt'] . $this->datacenter->sockets[$datacenter]->session_id . $message_id . pack('VV', $seq_no, strlen($message_data)) . $message_data;
|
||||
$plaintext = $this->datacenter->sockets[$datacenter]->temp_auth_key['server_salt'].$this->datacenter->sockets[$datacenter]->session_id.$message_id.pack('VV', $seq_no, strlen($message_data)).$message_data;
|
||||
$padding = $this->posmod(-strlen($plaintext), 16);
|
||||
if ($padding < 12) {
|
||||
$padding += 16;
|
||||
}
|
||||
$padding = $this->random($padding);
|
||||
$message_key = substr(hash('sha256', substr($this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], 88, 32) . $plaintext . $padding, true), 8, 16);
|
||||
$message_key = substr(hash('sha256', substr($this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], 88, 32).$plaintext.$padding, true), 8, 16);
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key']);
|
||||
$message = $this->datacenter->sockets[$datacenter]->temp_auth_key['id'] . $message_key . $this->ige_encrypt($plaintext . $padding, $aes_key, $aes_iv);
|
||||
$message = $this->datacenter->sockets[$datacenter]->temp_auth_key['id'].$message_key.$this->ige_encrypt($plaintext.$padding, $aes_key, $aes_iv);
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id] = ['seq_no' => $seq_no, 'response' => -1];
|
||||
$this->datacenter->sockets[$datacenter]->send_message($message);
|
||||
$this->datacenter->sockets[$datacenter]->object_queue = [];
|
||||
@ -62,6 +64,7 @@ trait MessageHandler
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->ack_queue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading connection and receiving message from server.
|
||||
*/
|
||||
@ -114,7 +117,7 @@ trait MessageHandler
|
||||
throw new \danog\MadelineProto\SecurityException('message_data_length not divisible by 4');
|
||||
}
|
||||
$message_data = substr($decrypted_data, 32, $message_data_length);
|
||||
if ($message_key != substr(hash('sha256', substr($this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], 96, 32) . $decrypted_data, true), 8, 16)) {
|
||||
if ($message_key != substr(hash('sha256', substr($this->datacenter->sockets[$datacenter]->temp_auth_key['auth_key'], 96, 32).$decrypted_data, true), 8, 16)) {
|
||||
throw new \danog\MadelineProto\SecurityException('msg_key mismatch');
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
||||
@ -127,6 +130,7 @@ trait MessageHandler
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['response'] = -1;
|
||||
$this->datacenter->sockets[$datacenter]->new_incoming[$message_id] = $message_id;
|
||||
$this->last_recv = time();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -24,18 +25,18 @@ trait MsgIdHandler
|
||||
}
|
||||
$min_message_id = (new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$aargs['datacenter']]->time_delta - 300))->bitwise_leftShift(32);
|
||||
if ($min_message_id->compare($new_message_id) > 0) {
|
||||
\danog\MadelineProto\Logger::log(['Given message id (' . $new_message_id . ') is too old compared to the min value (' . $min_message_id . ').'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').'], \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
$max_message_id = (new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$aargs['datacenter']]->time_delta + 30))->bitwise_leftShift(32);
|
||||
if ($max_message_id->compare($new_message_id) < 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is too new compared to the max value (' . $max_message_id . '). Consider syncing your date.');
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.');
|
||||
}
|
||||
if ($aargs['outgoing']) {
|
||||
if (!$new_message_id->divide($this->four)[1]->equals($this->zero)) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is not divisible by 4. Consider syncing your date.');
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4. Consider syncing your date.');
|
||||
}
|
||||
if (!\danog\MadelineProto\Logger::$has_thread && $new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], false)) <= 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', 1);
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1);
|
||||
}
|
||||
if (count($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) {
|
||||
reset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages);
|
||||
@ -51,11 +52,11 @@ trait MsgIdHandler
|
||||
$key = $this->get_max_id($aargs['datacenter'], true);
|
||||
if ($aargs['container']) {
|
||||
if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) >= 0) {
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Given message id (' . $new_message_id . ') is bigger than or equal to the current limit (' . $key . '). Consider syncing your date.'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.'], \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
} else {
|
||||
if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) <= 0) {
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.'], \danog\MadelineProto\Logger::WARNING);
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.'], \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
}
|
||||
if (count($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages) > $this->settings['msg_array_limit']['incoming']) {
|
||||
@ -70,6 +71,7 @@ trait MsgIdHandler
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[strrev($new_message_id->toBytes())] = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function generate_message_id($datacenter)
|
||||
{
|
||||
$message_id = (new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta))->bitwise_leftShift(32);
|
||||
@ -77,14 +79,17 @@ trait MsgIdHandler
|
||||
$message_id = $key->add($this->four);
|
||||
}
|
||||
$this->check_message_id($message_id, ['outgoing' => true, 'datacenter' => $datacenter, 'container' => false]);
|
||||
|
||||
return strrev($message_id->toBytes());
|
||||
}
|
||||
|
||||
public function get_max_id($datacenter, $incoming)
|
||||
{
|
||||
$incoming = $incoming ? 'incoming' : 'outgoing';
|
||||
if (isset($this->datacenter->sockets[$datacenter]->{'max_' . $incoming . '_id'}) && is_object($this->datacenter->sockets[$datacenter]->{'max_' . $incoming . '_id'})) {
|
||||
return $this->datacenter->sockets[$datacenter]->{'max_' . $incoming . '_id'};
|
||||
if (isset($this->datacenter->sockets[$datacenter]->{'max_'.$incoming.'_id'}) && is_object($this->datacenter->sockets[$datacenter]->{'max_'.$incoming.'_id'})) {
|
||||
return $this->datacenter->sockets[$datacenter]->{'max_'.$incoming.'_id'};
|
||||
}
|
||||
|
||||
return $this->zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -30,6 +31,7 @@ trait PeerHandler
|
||||
case 'user':
|
||||
if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) {
|
||||
$this->chats[$user['id']] = $user;
|
||||
|
||||
try {
|
||||
$this->get_pwr_chat($user['id'], false, true);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
@ -41,11 +43,12 @@ trait PeerHandler
|
||||
case 'userEmpty':
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid user provided at key ' . $key . ': ' . var_export($user, true));
|
||||
throw new \danog\MadelineProto\Exception('Invalid user provided at key '.$key.': '.var_export($user, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function add_chats($chats)
|
||||
{
|
||||
foreach ($chats as $key => $chat) {
|
||||
@ -55,6 +58,7 @@ trait PeerHandler
|
||||
case 'chatForbidden':
|
||||
if (!isset($this->chats[-$chat['id']]) || $this->chats[-$chat['id']] !== $chat) {
|
||||
$this->chats[-$chat['id']] = $chat;
|
||||
|
||||
try {
|
||||
$this->get_pwr_chat(-$chat['id'], $this->settings['peer']['full_fetch'], true);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
@ -76,6 +80,7 @@ trait PeerHandler
|
||||
}
|
||||
if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) {
|
||||
$this->chats[$bot_api_id] = $chat;
|
||||
|
||||
try {
|
||||
if (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== $this->get_full_info($bot_api_id)['full']['participants_count']) {
|
||||
$this->get_pwr_chat($this->to_supergroup($chat['id']), $this->settings['peer']['full_fetch'], true);
|
||||
@ -88,11 +93,12 @@ trait PeerHandler
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid chat provided at key ' . $key . ': ' . var_export($chat, true));
|
||||
throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.var_export($chat, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function peer_isset($id)
|
||||
{
|
||||
try {
|
||||
@ -103,6 +109,7 @@ trait PeerHandler
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function entities_peer_isset($entities)
|
||||
{
|
||||
try {
|
||||
@ -116,8 +123,10 @@ trait PeerHandler
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fwd_peer_isset($fwd)
|
||||
{
|
||||
try {
|
||||
@ -130,8 +139,10 @@ trait PeerHandler
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_info($id, $recursive = true)
|
||||
{
|
||||
if (is_array($id)) {
|
||||
@ -169,7 +180,7 @@ trait PeerHandler
|
||||
$id = $this->to_supergroup($id['channel_id']);
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . var_export($id, true));
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($id, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -186,7 +197,7 @@ trait PeerHandler
|
||||
}
|
||||
if (is_numeric($id)) {
|
||||
if (is_string($id)) {
|
||||
$id = \danog\MadelineProto\Logger::$bigint ? (double) $id : (int) $id;
|
||||
$id = \danog\MadelineProto\Logger::$bigint ? (float) $id : (int) $id;
|
||||
}
|
||||
if (!isset($this->chats[$id]) && $id < 0 && !preg_match('/^-100/', $id)) {
|
||||
$this->method_call('messages.getFullChat', ['chat_id' => -$id], ['datacenter' => $this->datacenter->curdc]);
|
||||
@ -195,11 +206,12 @@ trait PeerHandler
|
||||
return $this->gen_all($this->chats[$id]);
|
||||
}
|
||||
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true) {
|
||||
$dbres = json_decode(@file_get_contents('https://id.pwrtelegram.xyz/db/getusername?id=' . $id, false, stream_context_create(['http' => ['timeout' => 2]])), true);
|
||||
$dbres = json_decode(@file_get_contents('https://id.pwrtelegram.xyz/db/getusername?id='.$id, false, stream_context_create(['http' => ['timeout' => 2]])), true);
|
||||
if (isset($dbres['ok']) && $dbres['ok']) {
|
||||
return $this->get_info('@' . $dbres['result']);
|
||||
return $this->get_info('@'.$dbres['result']);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
$id = strtolower(str_replace('@', '', $id));
|
||||
@ -210,10 +222,13 @@ trait PeerHandler
|
||||
}
|
||||
if ($recursive) {
|
||||
$this->resolve_username($id);
|
||||
|
||||
return $this->get_info($id, false);
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
|
||||
public function gen_all($constructor)
|
||||
{
|
||||
$res = [$this->constructors->find_by_predicate($constructor['_'])['type'] => $constructor];
|
||||
@ -256,15 +271,18 @@ trait PeerHandler
|
||||
throw new \danog\MadelineProto\Exception('Chat forbidden');
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . var_export($constructor, true));
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($constructor, true));
|
||||
break;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function full_chat_last_updated($id)
|
||||
{
|
||||
return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0;
|
||||
}
|
||||
|
||||
public function get_full_info($id)
|
||||
{
|
||||
$partial = $this->get_info($id);
|
||||
@ -288,8 +306,10 @@ trait PeerHandler
|
||||
$res['full'] = $full;
|
||||
$res['last_update'] = time();
|
||||
$this->full_chats[$partial['bot_api_id']] = $res;
|
||||
|
||||
return array_merge($partial, $res);
|
||||
}
|
||||
|
||||
public function get_pwr_chat($id, $fullfetch = true, $send = true)
|
||||
{
|
||||
$full = $fullfetch ? $this->get_full_info($id) : $this->get_info($id);
|
||||
@ -422,6 +442,7 @@ trait PeerHandler
|
||||
$filters = ['channelParticipantsRecent', 'channelParticipantsAdmins', 'channelParticipantsKicked', 'channelParticipantsBots', 'channelParticipantsBanned'];
|
||||
foreach ($filters as $filter) {
|
||||
$offset = -$limit;
|
||||
|
||||
try {
|
||||
$gres = $this->method_call('channels.getParticipants', ['channel' => $full['InputChannel'], 'filter' => ['_' => $filter, 'q' => ''], 'offset' => $offset += $limit, 'limit' => $limit, 'hash' => 0], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -487,8 +508,10 @@ trait PeerHandler
|
||||
if ($fullfetch || $send) {
|
||||
$this->store_db($res);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function store_db($res, $force = false)
|
||||
{
|
||||
$settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all'];
|
||||
@ -516,12 +539,13 @@ trait PeerHandler
|
||||
if (empty($this->qres)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = json_encode($this->qres);
|
||||
$path = '/tmp/ids' . hash('sha256', $payload);
|
||||
$path = '/tmp/ids'.hash('sha256', $payload);
|
||||
file_put_contents($path, $payload);
|
||||
$id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'];
|
||||
$result = shell_exec('curl ' . escapeshellarg('https://id.pwrtelegram.xyz/db' . $this->settings['pwr']['db_token'] . '/addnewmadeline?d=pls&from=' . $id) . ' -d ' . escapeshellarg('@' . $path) . ' -s -o ' . escapeshellarg($path . '.log') . ' >/dev/null 2>/dev/null & ');
|
||||
$result = shell_exec('curl '.escapeshellarg('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id).' -d '.escapeshellarg('@'.$path).' -s -o '.escapeshellarg($path.'.log').' >/dev/null 2>/dev/null & ');
|
||||
\danog\MadelineProto\Logger::log([$result], \danog\MadelineProto\Logger::VERBOSE);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
\danog\MadelineProto\Logger::log([$e->getMessage()], \danog\MadelineProto\Logger::VERBOSE);
|
||||
@ -529,6 +553,7 @@ trait PeerHandler
|
||||
$this->qres = [];
|
||||
$this->last_stored = time() + 10;
|
||||
}
|
||||
|
||||
public function resolve_username($username)
|
||||
{
|
||||
try {
|
||||
@ -539,10 +564,12 @@ trait PeerHandler
|
||||
if ($res['_'] === 'contacts.resolvedPeer') {
|
||||
return $res;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function to_supergroup($id)
|
||||
{
|
||||
return -($id + pow(10, (int) floor(log($id, 10) + 3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -41,12 +42,13 @@ trait ResponseHandler
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$this->object_call('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['datacenter' => $datacenter])]['response'] = $req_msg_id;
|
||||
}
|
||||
|
||||
public function handle_messages($datacenter)
|
||||
{
|
||||
$only_updates = true;
|
||||
foreach ($this->datacenter->sockets[$datacenter]->new_incoming as $current_msg_id) {
|
||||
$unset = false;
|
||||
\danog\MadelineProto\Logger::log(['Received ' . $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'] . '.'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Received '.$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].'.'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
//\danog\MadelineProto\Logger::log([$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
if (!$this->synchronized(function ($zis, $datacenter, $current_msg_id) {
|
||||
@ -54,12 +56,13 @@ trait ResponseHandler
|
||||
return false;
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['handling'] = true;
|
||||
|
||||
return true;
|
||||
}, $this, $datacenter, $current_msg_id)) {
|
||||
\danog\MadelineProto\Logger::log([base64_encode($current_msg_id) . $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'] . ' is already being handled'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log([base64_encode($current_msg_id).$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].' is already being handled'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
continue;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Handling ' . base64_encode($current_msg_id) . $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'] . '.'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Handling '.base64_encode($current_msg_id).$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].'.'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
}
|
||||
switch ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_']) {
|
||||
case 'msgs_ack':
|
||||
@ -142,7 +145,7 @@ trait ResponseHandler
|
||||
// Acknowledge that I received the server's response
|
||||
if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) {
|
||||
$this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id'], $datacenter);
|
||||
// Acknowledge that I received the server's response
|
||||
// Acknowledge that I received the server's response
|
||||
} else {
|
||||
$this->check_message_id($message['orig_message']['msg_id'], ['outgoing' => false, 'datacenter' => $datacenter, 'container' => true]);
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']];
|
||||
@ -179,7 +182,7 @@ trait ResponseHandler
|
||||
unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]);
|
||||
foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) {
|
||||
$msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256);
|
||||
$status = 'Status for message id ' . $msg_id . ': ';
|
||||
$status = 'Status for message id '.$msg_id.': ';
|
||||
if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & 4) !== 0) {
|
||||
$this->ack_outgoing_message_id($msg_id, $datacenter);
|
||||
}
|
||||
@ -253,9 +256,9 @@ trait ResponseHandler
|
||||
break;
|
||||
default:
|
||||
$only_updates = false;
|
||||
\danog\MadelineProto\Logger::log(['Trying to assign a response of type ' . $response_type . ' to its request...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Trying to assign a response of type '.$response_type.' to its request...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $key => $expecting) {
|
||||
\danog\MadelineProto\Logger::log(['Does the request of return type ' . $expecting['type'] . ' match?'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Does the request of return type '.$expecting['type'].' match?'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
if ($response_type === $expecting['type']) {
|
||||
\danog\MadelineProto\Logger::log(['Yes'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$expecting['msg_id']]['response'] = $current_msg_id;
|
||||
@ -265,7 +268,8 @@ trait ResponseHandler
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['No'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
}
|
||||
throw new \danog\MadelineProto\ResponseException('Dunno how to handle ' . PHP_EOL . var_export($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], true));
|
||||
|
||||
throw new \danog\MadelineProto\ResponseException('Dunno how to handle '.PHP_EOL.var_export($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], true));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -293,11 +297,14 @@ trait ResponseHandler
|
||||
unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]);
|
||||
}
|
||||
}
|
||||
|
||||
return $only_updates;
|
||||
}
|
||||
|
||||
public function handle_messages_threaded()
|
||||
{
|
||||
}
|
||||
|
||||
public function handle_rpc_error($server_answer, &$aargs)
|
||||
{
|
||||
if (in_array($server_answer['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_OUTDATED', 'PERSISTENT_TIMESTAMP_INVALID'])) {
|
||||
@ -306,7 +313,8 @@ trait ResponseHandler
|
||||
switch ($server_answer['error_code']) {
|
||||
case 303:
|
||||
$this->datacenter->curdc = $aargs['datacenter'] = (int) preg_replace('/[^0-9]+/', '', $server_answer['error_message']);
|
||||
throw new \danog\MadelineProto\Exception('Received request to switch to DC ' . $this->datacenter->curdc);
|
||||
|
||||
throw new \danog\MadelineProto\Exception('Received request to switch to DC '.$this->datacenter->curdc);
|
||||
case 401:
|
||||
switch ($server_answer['error_message']) {
|
||||
case 'USER_DEACTIVATED':
|
||||
@ -346,8 +354,9 @@ trait ResponseHandler
|
||||
$seconds = preg_replace('/[^0-9]+/', '', $server_answer['error_message']);
|
||||
$limit = isset($aargs['FloodWaitLimit']) ? $aargs['FloodWaitLimit'] : $this->settings['flood_timeout']['wait_if_lt'];
|
||||
if (is_numeric($seconds) && $seconds < $limit) {
|
||||
\danog\MadelineProto\Logger::log(['Flood, waiting ' . $seconds . ' seconds...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Flood, waiting '.$seconds.' seconds...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
sleep($seconds);
|
||||
|
||||
throw new \danog\MadelineProto\Exception('Re-executing query...');
|
||||
}
|
||||
case 500:
|
||||
@ -356,6 +365,7 @@ trait ResponseHandler
|
||||
throw new \danog\MadelineProto\RPCErrorException($server_answer['error_message'], $server_answer['error_code']);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_pending_updates()
|
||||
{
|
||||
if ($this->postpone_updates) {
|
||||
@ -369,6 +379,7 @@ trait ResponseHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_updates($updates)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -377,6 +388,7 @@ trait ResponseHandler
|
||||
if ($this->postpone_updates) {
|
||||
\danog\MadelineProto\Logger::log(['Postpone update handling'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->pending_updates[] = $updates;
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->handle_pending_updates();
|
||||
@ -419,7 +431,7 @@ trait ResponseHandler
|
||||
$this->get_updates_difference();
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\ResponseException('Unrecognized update received: ' . var_export($updates, true));
|
||||
throw new \danog\MadelineProto\ResponseException('Unrecognized update received: '.var_export($updates, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -23,14 +24,16 @@ trait SaltHandler
|
||||
$this->add_salt($salt['valid_since'], $salt['valid_until'], $salt['salt']);
|
||||
}
|
||||
}
|
||||
|
||||
public function add_salt($valid_since, $valid_until, $salt)
|
||||
{
|
||||
if (!isset($this->datacenter->sockets[$datacenter]->temp_auth_key['salts'][$salt])) {
|
||||
$this->datacenter->sockets[$datacenter]->temp_auth_key['salts'][$salt] = ['valid_since' => $valid_since, 'valid_until' => $valid_until];
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_future_salts($salt)
|
||||
{
|
||||
$this->method_call('messages.sendMessage', ['peer' => $salt, 'message' => base64_decode('UG93ZXJlZCBieSBATWFkZWxpbmVQcm90bw==')], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -25,12 +26,14 @@ trait SeqNoHandler
|
||||
//var_dump("OUT $datacenter: $value + $in = ".$this->datacenter->sockets[$datacenter]->session_out_seq_no);
|
||||
return $value * 2 + $in;
|
||||
}
|
||||
|
||||
public function check_in_seq_no($datacenter, $current_msg_id)
|
||||
{
|
||||
if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generate_in_seq_no($datacenter, $this->content_related($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']))) !== $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['seq_no']) {
|
||||
//\danog\MadelineProto\Logger::log(['SECURITY WARNING: Seqno mismatch (should be '.$seq_no.', is '.$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['seq_no'].', '.$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].')'], \danog\MadelineProto\Logger::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function generate_in_seq_no($datacenter, $content_related)
|
||||
{
|
||||
$in = $content_related ? 1 : 0;
|
||||
@ -39,6 +42,7 @@ trait SeqNoHandler
|
||||
//var_dump("IN $datacenter: $value + $in = ".$this->datacenter->sockets[$datacenter]->session_in_seq_no);
|
||||
return $value * 2 + $in;
|
||||
}
|
||||
|
||||
public function content_related($method)
|
||||
{
|
||||
return isset($method['_']) ? !in_array($method['_'], [
|
||||
@ -74,4 +78,4 @@ trait SeqNoHandler
|
||||
'msg_resend_ans_req',
|
||||
]) : true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoTools;
|
||||
|
||||
/**
|
||||
@ -23,6 +24,7 @@ trait UpdateHandler
|
||||
private $channels_state = [];
|
||||
public $updates = [];
|
||||
public $updates_key = 0;
|
||||
|
||||
public function pwr_update_handler($update)
|
||||
{
|
||||
/*
|
||||
@ -55,6 +57,7 @@ trait UpdateHandler
|
||||
in_array($this->settings['pwr']['update_handler'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['pwr']['update_handler']($update);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_updates_update_handler($update)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -63,6 +66,7 @@ trait UpdateHandler
|
||||
$this->updates[$this->updates_key++] = $update;
|
||||
//\danog\MadelineProto\Logger::log(['Stored ', $update);
|
||||
}
|
||||
|
||||
public function get_updates($params = [])
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -74,6 +78,7 @@ trait UpdateHandler
|
||||
}
|
||||
});
|
||||
$time = microtime(true);
|
||||
|
||||
try {
|
||||
try {
|
||||
if (($error = $this->recv_message($this->datacenter->curdc)) !== true) {
|
||||
@ -82,9 +87,11 @@ trait UpdateHandler
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Resetting auth key...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$this->datacenter->curdc]->temp_auth_key = null;
|
||||
$this->init_authorization();
|
||||
|
||||
throw new \danog\MadelineProto\Exception('I had to recreate the temporary authorization key');
|
||||
}
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
||||
}
|
||||
$only_updates = $this->handle_messages($this->datacenter->curdc);
|
||||
@ -127,21 +134,26 @@ trait UpdateHandler
|
||||
$updates[] = ['update_id' => $key, 'update' => $value];
|
||||
}
|
||||
}
|
||||
|
||||
return $updates;
|
||||
}
|
||||
|
||||
public function &load_channel_state($channel, $pts = 0)
|
||||
{
|
||||
if (!isset($this->channels_state[$channel])) {
|
||||
$this->channels_state[$channel] = ['pts' => $pts, 'sync_loading' => false];
|
||||
}
|
||||
|
||||
return $this->channels_state[$channel];
|
||||
}
|
||||
|
||||
public function set_channel_state($channel, $data)
|
||||
{
|
||||
if (isset($data['pts']) && $data['pts'] !== 0) {
|
||||
$this->load_channel_state($channel)['pts'] = $data['pts'];
|
||||
}
|
||||
}
|
||||
|
||||
public function check_msg_id($message)
|
||||
{
|
||||
try {
|
||||
@ -152,22 +164,27 @@ trait UpdateHandler
|
||||
$message_id = $message['id'];
|
||||
if (!isset($this->msg_ids[$peer_id]) || $message_id > $this->msg_ids[$peer_id]) {
|
||||
$this->msg_ids[$peer_id] = $message_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_channel_difference($channel)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
if ($this->load_channel_state($channel)['sync_loading']) {
|
||||
\danog\MadelineProto\Logger::log(['Not fetching ' . $channel . ' difference, I am already fetching it']);
|
||||
\danog\MadelineProto\Logger::log(['Not fetching '.$channel.' difference, I am already fetching it']);
|
||||
|
||||
return;
|
||||
}
|
||||
$this->load_channel_state($channel)['sync_loading'] = true;
|
||||
|
||||
try {
|
||||
$input = $this->get_info('channel#' . $channel);
|
||||
$input = $this->get_info('channel#'.$channel);
|
||||
if (!isset($input['InputChannel'])) {
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
@ -180,17 +197,20 @@ trait UpdateHandler
|
||||
$this->load_channel_state($channel)['sync_loading'] = false;
|
||||
}
|
||||
$this->load_channel_state($channel)['sync_loading'] = true;
|
||||
\danog\MadelineProto\Logger::log(['Fetching ' . $channel . ' difference...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Fetching '.$channel.' difference...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
|
||||
try {
|
||||
$difference = $this->method_call('updates.getChannelDifference', ['channel' => $input, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $this->load_channel_state($channel)['pts'], 'limit' => 30], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
if ($e->getMessage() === "You haven't joined this channel/supergroup") {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
} catch (\danog\MadelineProto\PTSException $e) {
|
||||
unset($this->channels_state[$channel]);
|
||||
$this->load_channel_state($channel)['sync_loading'] = false;
|
||||
|
||||
return $this->get_channel_difference($channel);
|
||||
} finally {
|
||||
$this->load_channel_state($channel)['sync_loading'] = false;
|
||||
@ -202,6 +222,7 @@ trait UpdateHandler
|
||||
break;
|
||||
case 'updates.channelDifference':
|
||||
$this->load_channel_state($channel)['sync_loading'] = true;
|
||||
|
||||
try {
|
||||
$this->set_channel_state($channel, $difference);
|
||||
$this->handle_update_messages($difference['new_messages'], $channel);
|
||||
@ -215,8 +236,9 @@ trait UpdateHandler
|
||||
}
|
||||
break;
|
||||
case 'updates.channelDifferenceTooLong':
|
||||
\danog\MadelineProto\Logger::log(['Got ' . $difference['_']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->load_channel_state($channel)['sync_loading'] = true;
|
||||
|
||||
try {
|
||||
$this->set_channel_state($channel, $difference);
|
||||
$this->handle_update_messages($difference['messages'], $channel);
|
||||
@ -227,10 +249,11 @@ trait UpdateHandler
|
||||
$this->get_channel_difference($channel);
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . var_export($difference, true));
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function set_update_state($data)
|
||||
{
|
||||
if (isset($data['pts']) && $data['pts'] !== 0) {
|
||||
@ -246,6 +269,7 @@ trait UpdateHandler
|
||||
$this->load_update_state()['date'] = $data['date'];
|
||||
}
|
||||
}
|
||||
|
||||
public function &load_update_state()
|
||||
{
|
||||
if (!isset($this->updates_state['qts'])) {
|
||||
@ -255,8 +279,10 @@ trait UpdateHandler
|
||||
$this->got_state = true;
|
||||
$this->set_update_state($this->get_updates_state());
|
||||
}
|
||||
|
||||
return $this->updates_state;
|
||||
}
|
||||
|
||||
public function get_updates_difference()
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -264,6 +290,7 @@ trait UpdateHandler
|
||||
}
|
||||
if ($this->updates_state['sync_loading']) {
|
||||
\danog\MadelineProto\Logger::log(['Not fetching normal difference, I am already fetching it']);
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->updates_state['sync_loading'] = true;
|
||||
@ -278,7 +305,8 @@ trait UpdateHandler
|
||||
$this->updates_state['sync_loading'] = false;
|
||||
}
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Got ' . $difference['_']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
|
||||
try {
|
||||
switch ($difference['_']) {
|
||||
case 'updates.differenceEmpty':
|
||||
@ -303,37 +331,42 @@ trait UpdateHandler
|
||||
$this->get_updates_difference();
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . var_export($difference, true));
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true));
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
$this->updates_state['sync_loading'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_updates_state()
|
||||
{
|
||||
$last = $this->updates_state['sync_loading'];
|
||||
$this->updates_state['sync_loading'] = true;
|
||||
|
||||
try {
|
||||
$data = $this->method_call('updates.getState', [], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->get_cdn_config($this->datacenter->curdc);
|
||||
} finally {
|
||||
$this->updates_state['sync_loading'] = $last;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function handle_update($update, $options = [])
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
return;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Handling an update of type ' . $update['_'] . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Handling an update of type '.$update['_'].'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$channel_id = false;
|
||||
switch ($update['_']) {
|
||||
case 'updateNewChannelMessage':
|
||||
case 'updateEditChannelMessage':
|
||||
if ($update['message']['_'] === 'messageEmpty') {
|
||||
\danog\MadelineProto\Logger::log(['Got message empty, not saving'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
|
||||
return false;
|
||||
}
|
||||
$channel_id = $update['message']['to_id']['channel_id'];
|
||||
@ -346,24 +379,26 @@ trait UpdateHandler
|
||||
\danog\MadelineProto\Logger::log(['Got channel too long update, getting difference...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
if (!isset($this->channels_state[$channel_id]) && !isset($update['pts'])) {
|
||||
\danog\MadelineProto\Logger::log(['I do not have the channel in the states and the pts is not set.'], \danog\MadelineProto\Logger::ERROR);
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($channel_id === false) {
|
||||
$cur_state =& $this->load_update_state();
|
||||
$cur_state = &$this->load_update_state();
|
||||
} else {
|
||||
$cur_state =& $this->load_channel_state($channel_id, (isset($update['pts']) ? $update['pts'] : 0) - (isset($update['pts_count']) ? $update['pts_count'] : 0));
|
||||
$cur_state = &$this->load_channel_state($channel_id, (isset($update['pts']) ? $update['pts'] : 0) - (isset($update['pts_count']) ? $update['pts_count'] : 0));
|
||||
}
|
||||
/*
|
||||
if ($cur_state['sync_loading'] && in_array($update['_'], ['updateNewMessage', 'updateEditMessage', 'updateNewChannelMessage', 'updateEditChannelMessage'])) {
|
||||
\danog\MadelineProto\Logger::log(['Sync loading, not handling update'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
|
||||
return false;
|
||||
}*/
|
||||
switch ($update['_']) {
|
||||
case 'updateChannelTooLong':
|
||||
$this->get_channel_difference($channel_id);
|
||||
|
||||
return false;
|
||||
case 'updateNewMessage':
|
||||
case 'updateEditMessage':
|
||||
@ -376,37 +411,42 @@ trait UpdateHandler
|
||||
} else {
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ($channel_id !== false && !$this->peer_isset($this->to_supergroup($channel_id))) {
|
||||
\danog\MadelineProto\Logger::log(['Skipping update, I do not have the channel id ' . $channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Skipping update, I do not have the channel id '.$channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isset($update['pts'])) {
|
||||
if ($update['pts'] < $cur_state['pts']) {
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update, channel id: ' . $channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update, channel id: '.$channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($cur_state['pts'] + (isset($update['pts_count']) ? $update['pts_count'] : 0) !== $update['pts']) {
|
||||
\danog\MadelineProto\Logger::log(['Pts hole. current pts: ' . $cur_state['pts'] . ', pts count: ' . (isset($update['pts_count']) ? $update['pts_count'] : 0) . ', pts: ' . $update['pts'] . ', channel id: ' . $channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Pts hole. current pts: '.$cur_state['pts'].', pts count: '.(isset($update['pts_count']) ? $update['pts_count'] : 0).', pts: '.$update['pts'].', channel id: '.$channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
if ($channel_id !== false && $this->peer_isset($this->to_supergroup($channel_id))) {
|
||||
$this->get_channel_difference($channel_id);
|
||||
} else {
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (isset($update['message']['id'], $update['message']['to_id'])) {
|
||||
if (!$this->check_msg_id($update['message'])) {
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update by message id, channel id: ' . $channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update by message id, channel id: '.$channel_id], \danog\MadelineProto\Logger::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Applying pts. current pts: ' . $cur_state['pts'] . ', new pts: ' . $update['pts'] . ', channel id: ' . $channel_id], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Applying pts. current pts: '.$cur_state['pts'].', new pts: '.$update['pts'].', channel id: '.$channel_id], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$cur_state['pts'] = $update['pts'];
|
||||
if ($channel_id === false && isset($options['date']) && $cur_state['date'] < $options['date']) {
|
||||
$cur_state['date'] = $options['date'];
|
||||
@ -416,8 +456,9 @@ trait UpdateHandler
|
||||
$seq = $options['seq'];
|
||||
$seq_start = isset($options['seq_start']) ? $options['seq_start'] : $options['seq'];
|
||||
if ($seq_start != $cur_state['seq'] + 1 && $seq_start > $cur_state['seq']) {
|
||||
\danog\MadelineProto\Logger::log(['Seq hole. seq_start: ' . $seq_start . ' != cur seq: ' . $cur_state['seq'] . ' + 1'], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Seq hole. seq_start: '.$seq_start.' != cur seq: '.$cur_state['seq'].' + 1'], \danog\MadelineProto\Logger::ERROR);
|
||||
$this->get_updates_difference();
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($cur_state['seq'] !== $seq) {
|
||||
@ -429,6 +470,7 @@ trait UpdateHandler
|
||||
}
|
||||
$this->save_update($update);
|
||||
}
|
||||
|
||||
public function handle_multiple_update($updates, $options = [], $channel = false)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -444,6 +486,7 @@ trait UpdateHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_update_messages($messages, $channel = false)
|
||||
{
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
@ -453,6 +496,7 @@ trait UpdateHandler
|
||||
$this->handle_update(['_' => $channel === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => $channel === false ? $this->load_update_state()['pts'] : $this->load_channel_state($channel)['pts'], 'pts_count' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
public function save_update($update)
|
||||
{
|
||||
array_walk($this->calls, function ($controller, $id) {
|
||||
@ -463,11 +507,13 @@ trait UpdateHandler
|
||||
if ($update['_'] === 'updateDcOptions') {
|
||||
\danog\MadelineProto\Logger::log(['Got new dc options'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->parse_dc_options($update['dc_options']);
|
||||
|
||||
return;
|
||||
}
|
||||
if ($update['_'] === 'updatePhoneCall') {
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
\danog\MadelineProto\Logger::log(['The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.'], \danog\MadelineProto\Logger::WARNING);
|
||||
|
||||
return;
|
||||
}
|
||||
switch ($update['phone_call']['_']) {
|
||||
@ -495,6 +541,7 @@ trait UpdateHandler
|
||||
if (!isset($this->calls[$update['phone_call']['id']])) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->calls[$update['phone_call']['id']]->discard(['_' => 'phoneCallDiscardReasonHangup'], [], $update['phone_call']['need_debug']);
|
||||
}
|
||||
}
|
||||
@ -504,17 +551,20 @@ trait UpdateHandler
|
||||
$cur_state['qts'] = $update['qts'];
|
||||
}
|
||||
if ($update['qts'] < $cur_state['qts']) {
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update. update qts: ' . $update['qts'] . ' <= current qts ' . $cur_state['qts'] . ', chat id: ' . $update['message']['chat_id']], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Duplicate update. update qts: '.$update['qts'].' <= current qts '.$cur_state['qts'].', chat id: '.$update['message']['chat_id']], \danog\MadelineProto\Logger::ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($update['qts'] > $cur_state['qts'] + 1) {
|
||||
\danog\MadelineProto\Logger::log(['Qts hole. Fetching updates manually: update qts: ' . $update['qts'] . ' > current qts ' . $cur_state['qts'] . '+1, chat id: ' . $update['message']['chat_id']], \danog\MadelineProto\Logger::ERROR);
|
||||
\danog\MadelineProto\Logger::log(['Qts hole. Fetching updates manually: update qts: '.$update['qts'].' > current qts '.$cur_state['qts'].'+1, chat id: '.$update['message']['chat_id']], \danog\MadelineProto\Logger::ERROR);
|
||||
$this->get_updates_difference();
|
||||
|
||||
return false;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Applying qts: ' . $update['qts'] . ' over current qts ' . $cur_state['qts'] . ', chat id: ' . $update['message']['chat_id']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Applying qts: '.$update['qts'].' over current qts '.$cur_state['qts'].', chat id: '.$update['message']['chat_id']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->method_call('messages.receivedQueue', ['max_qts' => $cur_state['qts'] = $update['qts']], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->handle_encrypted_update($update);
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@ -528,11 +578,11 @@ trait UpdateHandler
|
||||
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);
|
||||
\danog\MadelineProto\Logger::log(['Accepting secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->accept_secret_chat($update['chat']);
|
||||
break;
|
||||
case 'encryptedChatDiscarded':
|
||||
\danog\MadelineProto\Logger::log(['Deleting secret chat ' . $update['chat']['id'] . ' because it was revoked by the other user'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Deleting secret chat '.$update['chat']['id'].' because it was revoked by the other user'], \danog\MadelineProto\Logger::NOTICE);
|
||||
if (isset($this->secret_chats[$update['chat']['id']])) {
|
||||
unset($this->secret_chats[$update['chat']['id']]);
|
||||
}
|
||||
@ -541,7 +591,7 @@ trait UpdateHandler
|
||||
}
|
||||
break;
|
||||
case 'encryptedChat':
|
||||
\danog\MadelineProto\Logger::log(['Completing creation of secret chat ' . $update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Completing creation of secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->complete_secret_chat($update['chat']);
|
||||
break;
|
||||
}
|
||||
@ -556,19 +606,21 @@ trait UpdateHandler
|
||||
if (isset($update['message']['from_id']) && $update['message']['from_id'] === $this->authorization['user']['id']) {
|
||||
$update['message']['out'] = true;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Saving an update of type ' . $update['_'] . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Saving an update of type '.$update['_'].'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict'] && isset($this->settings['pwr']['update_handler'])) {
|
||||
$this->pwr_update_handler($update);
|
||||
} else {
|
||||
in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['updates']['callback']($update);
|
||||
}
|
||||
}
|
||||
|
||||
public function pwr_webhook($update)
|
||||
{
|
||||
$payload = json_encode($update);
|
||||
\danog\MadelineProto\Logger::log([$update, $payload, json_last_error()]);
|
||||
if ($payload === '') {
|
||||
\danog\MadelineProto\Logger::log(['EMPTY UPDATE']);
|
||||
|
||||
return false;
|
||||
}
|
||||
$ch = curl_init();
|
||||
@ -588,7 +640,7 @@ trait UpdateHandler
|
||||
}
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
\danog\MadelineProto\Logger::log(['Result of webhook query is ' . $result], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Result of webhook query is '.$result], \danog\MadelineProto\Logger::NOTICE);
|
||||
$result = json_decode($result, true);
|
||||
if (is_array($result) && isset($result['method']) && $result['method'] != '' && is_string($result['method'])) {
|
||||
try {
|
||||
@ -600,4 +652,4 @@ trait UpdateHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class NothingInTheSocketException extends \Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -10,18 +10,21 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class PTSException extends \Exception
|
||||
{
|
||||
use TL\PrettyException;
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . 'TL Trace:' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL;
|
||||
return get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||
}
|
||||
|
||||
public function __construct($message, $file = '')
|
||||
{
|
||||
parent::__construct($message);
|
||||
$this->prettify_tl($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,23 +10,38 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
interface Proxy
|
||||
{
|
||||
public function __construct($domain, $type, $protocol);
|
||||
|
||||
public function setOption($level, $name, $value);
|
||||
|
||||
public function getOption($level, $name);
|
||||
|
||||
public function setBlocking($blocking);
|
||||
|
||||
public function bind($address, $port = 0);
|
||||
|
||||
public function listen($backlog = 0);
|
||||
|
||||
public function accept();
|
||||
|
||||
public function connect($address, $port = 0);
|
||||
|
||||
public function select(array &$read, array &$write, array &$except, $tv_sec, $tv_usec = 0);
|
||||
|
||||
public function read($length, $flags = 0);
|
||||
|
||||
public function write($buffer, $length = -1);
|
||||
|
||||
public function send($data, $length, $flags);
|
||||
|
||||
public function close();
|
||||
|
||||
public function getPeerName($port = true);
|
||||
|
||||
public function getSockName($port = true);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class RPCErrorException extends \Exception
|
||||
@ -17,20 +18,24 @@ class RPCErrorException extends \Exception
|
||||
use TL\PrettyException;
|
||||
private $fetched = false;
|
||||
public static $rollbar = true;
|
||||
|
||||
public function getMess()
|
||||
{
|
||||
if ($this->fetched === false) {
|
||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method=' . $additional[0] . '&code=' . $code . '&error=' . $this->rpc), true);
|
||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$additional[0].'&code='.$code.'&error='.$this->rpc), true);
|
||||
if (isset($res['ok']) && $res['ok']) {
|
||||
$this->message = $res['result'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], $this->getMess(), $this->rpc, $this->file, $this->line . PHP_EOL . PHP_EOL) . PHP_EOL . 'Revision: ' . @file_get_contents(__DIR__ . '/../../../.git/refs/heads/master') . PHP_EOL . $this->getTLTrace() . PHP_EOL;
|
||||
return sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], $this->getMess(), $this->rpc, $this->file, $this->line.PHP_EOL.PHP_EOL).PHP_EOL.'Revision: '.@file_get_contents(__DIR__.'/../../../.git/refs/heads/master').PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||
}
|
||||
|
||||
public function __construct($message = null, $code = 0, Exception $previous = null)
|
||||
{
|
||||
$this->rpc = $message;
|
||||
@ -186,4 +191,4 @@ class RPCErrorException extends \Exception
|
||||
}
|
||||
$message === 'Telegram is having internal issues, please try again later.' ? \Rollbar\Rollbar::log(\Rollbar\Payload\Level::critical(), $message) : \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, $additional);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ See the GNU Affero General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with the MadelineProto.
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class RSA
|
||||
@ -20,6 +21,7 @@ class RSA
|
||||
public $e;
|
||||
public $n;
|
||||
public $fp;
|
||||
|
||||
public function __magic_construct($rsa_key)
|
||||
{
|
||||
//if ($this->unserialized($rsa_key)) return true;
|
||||
@ -30,16 +32,20 @@ class RSA
|
||||
$this->n = \phpseclib\Common\Functions\Objects::getVar($key, 'modulus');
|
||||
$this->e = \phpseclib\Common\Functions\Objects::getVar($key, 'exponent');
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['computing_fingerprint']], Logger::ULTRA_VERBOSE);
|
||||
$this->fp = substr(sha1($this->serialize_object(['type' => 'bytes'], $this->n->toBytes(), 'key') . $this->serialize_object(['type' => 'bytes'], $this->e->toBytes(), 'key'), true), -8);
|
||||
$this->fp = substr(sha1($this->serialize_object(['type' => 'bytes'], $this->n->toBytes(), 'key').$this->serialize_object(['type' => 'bytes'], $this->e->toBytes(), 'key'), true), -8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['e', 'n', 'fp'];
|
||||
}
|
||||
|
||||
public function encrypt($data)
|
||||
{
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['rsa_encrypting']], Logger::VERBOSE);
|
||||
|
||||
return (new \phpseclib\Math\BigInteger($data, 256))->powMod($this->e, $this->n)->toBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class ResponseException extends \Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\SecretChats;
|
||||
|
||||
/**
|
||||
@ -21,12 +22,14 @@ trait AuthKeyHandler
|
||||
{
|
||||
protected $temp_requested_secret_chats = [];
|
||||
protected $secret_chats = [];
|
||||
|
||||
public function accept_secret_chat($params)
|
||||
{
|
||||
//var_dump($params['id'],$this->secret_chat_status($params['id']));
|
||||
if ($this->secret_chat_status($params['id']) !== 0) {
|
||||
//var_dump($this->secret_chat_status($params['id']));
|
||||
\danog\MadelineProto\Logger::log(["I've already accepted secret chat " . $params['id']]);
|
||||
\danog\MadelineProto\Logger::log(["I've already accepted secret chat ".$params['id']]);
|
||||
|
||||
return false;
|
||||
}
|
||||
$dh_config = $this->get_dh_config();
|
||||
@ -45,8 +48,9 @@ trait AuthKeyHandler
|
||||
$this->method_call('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->notify_layer($params['id']);
|
||||
$this->handle_pending_updates();
|
||||
\danog\MadelineProto\Logger::log(['Secret chat ' . $params['id'] . ' accepted successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Secret chat '.$params['id'].' accepted successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
||||
}
|
||||
|
||||
public function request_secret_chat($user)
|
||||
{
|
||||
$user = $this->get_info($user);
|
||||
@ -54,7 +58,7 @@ trait AuthKeyHandler
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
$user = $user['InputUser'];
|
||||
\danog\MadelineProto\Logger::log(['Creating secret chat with ' . $user['user_id'] . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Creating secret chat with '.$user['user_id'].'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$dh_config = $this->get_dh_config();
|
||||
\danog\MadelineProto\Logger::log(['Generating a...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$a = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
||||
@ -65,14 +69,17 @@ trait AuthKeyHandler
|
||||
$this->temp_requested_secret_chats[$res['id']] = $a;
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
\danog\MadelineProto\Logger::log(['Secret chat ' . $res['id'] . ' requested successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Secret chat '.$res['id'].' requested successfully!'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $res['id'];
|
||||
}
|
||||
|
||||
public function complete_secret_chat($params)
|
||||
{
|
||||
if ($this->secret_chat_status($params['id']) !== 1) {
|
||||
//var_dump($this->secret_chat_status($params['id']));
|
||||
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat ' . $params['id']]);
|
||||
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat '.$params['id']]);
|
||||
|
||||
return false;
|
||||
}
|
||||
$dh_config = $this->get_dh_config();
|
||||
@ -84,6 +91,7 @@ trait AuthKeyHandler
|
||||
//var_dump($key);
|
||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||
$this->discard_secret_chat($params['id']);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||
}
|
||||
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
|
||||
@ -91,19 +99,22 @@ trait AuthKeyHandler
|
||||
$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->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);
|
||||
}
|
||||
|
||||
public function notify_layer($chat)
|
||||
{
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
|
||||
protected $temp_rekeyed_secret_chats = [];
|
||||
|
||||
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);
|
||||
\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);
|
||||
$a = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
||||
@ -116,8 +127,10 @@ trait AuthKeyHandler
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionRequestKey', 'g_a' => $g_a->toBytes(), 'exchange_id' => $e]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
|
||||
return $e;
|
||||
}
|
||||
|
||||
public function accept_rekey($chat, $params)
|
||||
{
|
||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
|
||||
@ -129,10 +142,11 @@ trait AuthKeyHandler
|
||||
}
|
||||
if ($my_exchange_id === $other_exchange_id) {
|
||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Accepting rekeying of secret chat ' . $chat . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Accepting rekeying of secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$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);
|
||||
@ -150,13 +164,15 @@ trait AuthKeyHandler
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
|
||||
public function commit_rekey($chat, $params)
|
||||
{
|
||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) {
|
||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||
|
||||
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);
|
||||
$dh_config = $this->get_dh_config();
|
||||
$params['g_b'] = new \phpseclib\Math\BigInteger($params['g_b'], 256);
|
||||
$this->check_G($params['g_b'], $dh_config['p']);
|
||||
@ -166,6 +182,7 @@ trait AuthKeyHandler
|
||||
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
||||
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||
}
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionCommitKey', 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
@ -178,6 +195,7 @@ trait AuthKeyHandler
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
|
||||
public function complete_rekey($chat, $params)
|
||||
{
|
||||
if ($this->secret_chats[$chat]['rekeying'][0] !== 2 || !isset($this->temp_rekeyed_secret_chats['fingerprint'])) {
|
||||
@ -185,9 +203,10 @@ trait AuthKeyHandler
|
||||
}
|
||||
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']]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Completing rekeying of secret chat ' . $chat . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Completing rekeying of secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->secret_chats[$chat]['rekeying'] = [0];
|
||||
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
|
||||
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$chat];
|
||||
@ -195,9 +214,11 @@ trait AuthKeyHandler
|
||||
$this->secret_chats[$chat]['updated'] = time();
|
||||
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
\danog\MadelineProto\Logger::log(['Secret chat ' . $chat . ' rekeyed successfully!'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Secret chat '.$chat.' rekeyed successfully!'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function secret_chat_status($chat)
|
||||
{
|
||||
if (isset($this->secret_chats[$chat])) {
|
||||
@ -206,15 +227,18 @@ trait AuthKeyHandler
|
||||
if (isset($this->temp_requested_secret_chats[$chat])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function get_secret_chat($chat)
|
||||
{
|
||||
return $this->secret_chats[$chat];
|
||||
}
|
||||
|
||||
public function discard_secret_chat($chat)
|
||||
{
|
||||
\danog\MadelineProto\Logger::log(['Discarding secret chat ' . $chat . '...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Discarding secret chat '.$chat.'...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
//var_dump(debug_backtrace(0)[0]);
|
||||
if (isset($this->secret_chats[$chat])) {
|
||||
unset($this->secret_chats[$chat]);
|
||||
@ -225,6 +249,7 @@ trait AuthKeyHandler
|
||||
if (isset($this->temp_rekeyed_secret_chats[$chat])) {
|
||||
unset($this->temp_rekeyed_secret_chats[$chat]);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->method_call('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -233,4 +258,4 @@ trait AuthKeyHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\SecretChats;
|
||||
|
||||
/**
|
||||
@ -21,6 +22,7 @@ trait MessageHandler
|
||||
{
|
||||
if (!isset($this->secret_chats[$chat_id])) {
|
||||
\danog\MadelineProto\Logger::log(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->secret_chats[$chat_id]['ttr']--;
|
||||
@ -33,27 +35,30 @@ trait MessageHandler
|
||||
}
|
||||
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
||||
$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;
|
||||
if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
|
||||
$padding = $this->posmod(-strlen($message), 16);
|
||||
if ($padding < 12) {
|
||||
$padding += 16;
|
||||
}
|
||||
$message .= $this->random($padding);
|
||||
$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);
|
||||
$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);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function handle_encrypted_update($message, $test = false)
|
||||
{
|
||||
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
|
||||
\danog\MadelineProto\Logger::log(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
|
||||
|
||||
return false;
|
||||
}
|
||||
$auth_key_id = substr($message['message']['bytes'], 0, 8);
|
||||
@ -62,36 +67,40 @@ trait MessageHandler
|
||||
if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) {
|
||||
if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) {
|
||||
$this->discard_secret_chat($message['message']['chat_id']);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||
}
|
||||
$old = true;
|
||||
} else {
|
||||
$this->discard_secret_chat($message['message']['chat_id']);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']);
|
||||
}
|
||||
}
|
||||
$message_key = substr($message['message']['bytes'], 8, 16);
|
||||
$encrypted_data = substr($message['message']['bytes'], 24);
|
||||
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
|
||||
\danog\MadelineProto\Logger::log(['Trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log(['Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
try {
|
||||
$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);
|
||||
\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);
|
||||
\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);
|
||||
\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);
|
||||
\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);
|
||||
\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);
|
||||
\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);
|
||||
\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;
|
||||
}
|
||||
}
|
||||
@ -105,6 +114,7 @@ trait MessageHandler
|
||||
$this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['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);
|
||||
@ -123,8 +133,10 @@ trait MessageHandler
|
||||
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']);
|
||||
@ -134,7 +146,7 @@ trait MessageHandler
|
||||
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)) {
|
||||
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) {
|
||||
@ -146,6 +158,7 @@ trait MessageHandler
|
||||
if (strlen($decrypted_data) % 16 != 0) {
|
||||
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']);
|
||||
}
|
||||
|
||||
return $message_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\SecretChats;
|
||||
|
||||
/**
|
||||
@ -28,12 +29,15 @@ trait ResponseHandler
|
||||
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'];
|
||||
@ -43,9 +47,11 @@ trait ResponseHandler
|
||||
if ($update['message']['decrypted_message']['action']['layer'] >= 73) {
|
||||
$this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2;
|
||||
}
|
||||
|
||||
return;
|
||||
case 'decryptedMessageActionSetMessageTTL':
|
||||
$this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds'];
|
||||
|
||||
return;
|
||||
case 'decryptedMessageActionNoop':
|
||||
return;
|
||||
@ -54,13 +60,14 @@ trait ResponseHandler
|
||||
$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);
|
||||
\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) {
|
||||
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']);
|
||||
$this->method_call('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
}
|
||||
|
||||
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']]);
|
||||
@ -84,8 +91,8 @@ trait ResponseHandler
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'] . var_export($update, true));
|
||||
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].var_export($update, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\SecretChats;
|
||||
|
||||
/**
|
||||
@ -25,6 +26,7 @@ trait SeqNoHandler
|
||||
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) {
|
||||
$this->discard_secret_chat($chat_id);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing');
|
||||
}
|
||||
$last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
|
||||
@ -32,10 +34,13 @@ trait SeqNoHandler
|
||||
}
|
||||
if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) {
|
||||
$this->discard_secret_chat($chat_id);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('in_seq_no is too big');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function check_secret_out_seq_no($chat_id, $seqno)
|
||||
{
|
||||
$seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2;
|
||||
@ -44,7 +49,8 @@ trait SeqNoHandler
|
||||
if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) {
|
||||
if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) {
|
||||
$this->discard_secret_chat($chat_id);
|
||||
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be ' . $C . ', is ' . ($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
||||
|
||||
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
|
||||
} else {
|
||||
$C++;
|
||||
}
|
||||
@ -53,22 +59,27 @@ trait SeqNoHandler
|
||||
//var_dump($C, $seqno);
|
||||
if ($seqno < $C) {
|
||||
// <= C
|
||||
\danog\MadelineProto\Logger::log(['WARNING: dropping repeated message with seqno ' . $seqno]);
|
||||
\danog\MadelineProto\Logger::log(['WARNING: dropping repeated message with seqno '.$seqno]);
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($seqno > $C) {
|
||||
// > C+1
|
||||
$this->discard_secret_chat($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.')!');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function generate_secret_in_seq_no($chat)
|
||||
{
|
||||
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1;
|
||||
}
|
||||
|
||||
public function generate_secret_out_seq_no($chat)
|
||||
{
|
||||
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class SecurityException extends \Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
/**
|
||||
@ -18,9 +19,11 @@ namespace danog\MadelineProto;
|
||||
class Serialization
|
||||
{
|
||||
public static $instances = [];
|
||||
|
||||
public static function serialize_all($exception)
|
||||
{
|
||||
echo $exception . PHP_EOL;
|
||||
echo $exception.PHP_EOL;
|
||||
|
||||
return;
|
||||
foreach (self::$instances as $instance) {
|
||||
if (isset($instance->session)) {
|
||||
@ -28,13 +31,16 @@ class Serialization
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function realpaths($file)
|
||||
{
|
||||
if ($file[0] !== '/') {
|
||||
$file = getcwd() . '/' . $file;
|
||||
$file = getcwd().'/'.$file;
|
||||
}
|
||||
return ['file' => $file, 'lockfile' => $file . '.lock', 'tempfile' => $file . '.temp.session'];
|
||||
|
||||
return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize API class.
|
||||
*
|
||||
@ -59,6 +65,7 @@ class Serialization
|
||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w');
|
||||
\danog\MadelineProto\Logger::log(['Waiting for exclusive lock of serialization lockfile...']);
|
||||
flock($realpaths['lockfile'], LOCK_EX);
|
||||
|
||||
try {
|
||||
$wrote = file_put_contents($realpaths['tempfile'], serialize($instance));
|
||||
rename($realpaths['tempfile'], $realpaths['file']);
|
||||
@ -66,8 +73,10 @@ class Serialization
|
||||
flock($realpaths['lockfile'], LOCK_UN);
|
||||
fclose($realpaths['lockfile']);
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize API class.
|
||||
*
|
||||
@ -88,6 +97,7 @@ class Serialization
|
||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'r');
|
||||
\danog\MadelineProto\Logger::log(['Waiting for shared lock of serialization lockfile...']);
|
||||
flock($realpaths['lockfile'], LOCK_SH);
|
||||
|
||||
try {
|
||||
$unserialized = file_get_contents($realpaths['file']);
|
||||
} finally {
|
||||
@ -96,10 +106,11 @@ class Serialization
|
||||
}
|
||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $unserialized);
|
||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||
class_exists('\\danog\\MadelineProto\\' . $class);
|
||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
||||
}
|
||||
class_exists('\\Volatile');
|
||||
\danog\MadelineProto\Logger::class_exists();
|
||||
|
||||
try {
|
||||
$unserialized = unserialize($tounserialize);
|
||||
} catch (\danog\MadelineProto\Bug74586Exception $e) {
|
||||
@ -124,6 +135,7 @@ class Serialization
|
||||
$unserialized->session = $filename;
|
||||
}
|
||||
self::$instances[spl_object_hash($unserialized)] = $unserialized;
|
||||
|
||||
return $unserialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
trait BotAPI
|
||||
@ -18,6 +19,7 @@ trait BotAPI
|
||||
{
|
||||
return html_entity_decode(preg_replace('#< *br */? *>#', "\n", $stuff));
|
||||
}
|
||||
|
||||
public function parse_buttons($rows)
|
||||
{
|
||||
$newrows = [];
|
||||
@ -53,8 +55,10 @@ trait BotAPI
|
||||
}
|
||||
$key++;
|
||||
}
|
||||
|
||||
return $newrows;
|
||||
}
|
||||
|
||||
public function parse_reply_markup($markup)
|
||||
{
|
||||
if (isset($markup['force_reply']) && $markup['force_reply']) {
|
||||
@ -83,8 +87,10 @@ trait BotAPI
|
||||
$markup['rows'] = $this->parse_buttons($markup['inline_keyboard']);
|
||||
unset($markup['inline_keyboard']);
|
||||
}
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
public function MTProto_to_botAPI($data, $sent_arguments = [])
|
||||
{
|
||||
$newd = [];
|
||||
@ -92,6 +98,7 @@ trait BotAPI
|
||||
foreach ($data as $key => $element) {
|
||||
$newd[$key] = $this->MTProto_to_botAPI($element, $sent_arguments);
|
||||
}
|
||||
|
||||
return $newd;
|
||||
}
|
||||
switch ($data['_']) {
|
||||
@ -109,6 +116,7 @@ trait BotAPI
|
||||
if (isset($data['media'])) {
|
||||
$newd = array_merge($newd, $this->MTProto_to_botAPI($data['media'], $sent_arguments));
|
||||
}
|
||||
|
||||
return $newd;
|
||||
case 'updateNewChannelMessage':
|
||||
case 'updateNewMessage':
|
||||
@ -150,52 +158,64 @@ trait BotAPI
|
||||
if (isset($data['media'])) {
|
||||
$newd = array_merge($newd, $this->MTProto_to_botAPI($data['media'], $sent_arguments));
|
||||
}
|
||||
|
||||
return $newd;
|
||||
case 'messageEntityMention':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'mention';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityHashtag':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'hashtag';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityBotCommand':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'bot_command';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityUrl':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'url';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityEmail':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'email';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityBold':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'bold';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityItalic':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'italic';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityCode':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'code';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityPre':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'pre';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityTextUrl':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'text_url';
|
||||
|
||||
return $data;
|
||||
case 'messageEntityMentionName':
|
||||
unset($data['_']);
|
||||
$data['type'] = 'text_mention';
|
||||
$data['user'] = $this->get_pwr_chat($data['user_id']);
|
||||
unset($data['user_id']);
|
||||
|
||||
return $data;
|
||||
case 'messageMediaPhoto':
|
||||
if (isset($data['caption'])) {
|
||||
@ -205,6 +225,7 @@ trait BotAPI
|
||||
foreach ($data['photo']['sizes'] as $key => $photo) {
|
||||
$res['photo'][$key] = $this->photosize_to_botapi($photo, $data['photo']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
case 'messageMediaEmpty':
|
||||
return [];
|
||||
@ -218,7 +239,7 @@ trait BotAPI
|
||||
switch ($attribute['_']) {
|
||||
case 'documentAttributeFilename':
|
||||
$pathinfo = pathinfo($attribute['file_name']);
|
||||
$res['ext'] = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';
|
||||
$res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
|
||||
$res['file_name'] = $pathinfo['filename'];
|
||||
break;
|
||||
case 'documentAttributeAudio':
|
||||
@ -269,29 +290,32 @@ trait BotAPI
|
||||
if (isset($audio) && isset($audio['title']) && !isset($res['file_name'])) {
|
||||
$res['file_name'] = $audio['title'];
|
||||
if (isset($audio['performer'])) {
|
||||
$res['file_name'] .= ' - ' . $audio['performer'];
|
||||
$res['file_name'] .= ' - '.$audio['performer'];
|
||||
}
|
||||
}
|
||||
if (!isset($res['file_name'])) {
|
||||
$res['file_name'] = $data['document']['access_hash'];
|
||||
}
|
||||
$res['file_name'] .= '_' . $data['document']['id'];
|
||||
$res['file_name'] .= '_'.$data['document']['id'];
|
||||
if (isset($res['ext'])) {
|
||||
$res['file_name'] .= $res['ext'];
|
||||
unset($res['ext']);
|
||||
} else {
|
||||
$res['file_name'] .= $this->get_extension_from_mime($data['document']['mime_type']);
|
||||
}
|
||||
$data['document']['_'] = 'bot_' . $type_name;
|
||||
$data['document']['_'] = 'bot_'.$type_name;
|
||||
$res['file_size'] = $data['document']['size'];
|
||||
$res['mime_type'] = $data['document']['mime_type'];
|
||||
$res['file_id'] = $this->base64url_encode($this->rle_encode($this->serialize_object(['type' => 'File'], $data['document'], 'File') . chr(2)));
|
||||
$res['file_id'] = $this->base64url_encode($this->rle_encode($this->serialize_object(['type' => 'File'], $data['document'], 'File').chr(2)));
|
||||
|
||||
return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : ''];
|
||||
default:
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_']));
|
||||
}
|
||||
}
|
||||
|
||||
public $botapi_params = ['disable_web_page_preview' => 'no_webpage', 'disable_notification' => 'silent', 'reply_to_message_id' => 'reply_to_msg_id', 'chat_id' => 'peer', 'text' => 'message'];
|
||||
|
||||
public function botAPI_to_MTProto($arguments)
|
||||
{
|
||||
foreach ($this->botapi_params as $bot => $mtproto) {
|
||||
@ -306,8 +330,10 @@ trait BotAPI
|
||||
if (isset($arguments['parse_mode'])) {
|
||||
$arguments = $this->parse_mode($arguments);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
public function parse_node($node, &$entities, &$nmessage, $recursive = true)
|
||||
{
|
||||
switch ($node->nodeName) {
|
||||
@ -374,6 +400,7 @@ trait BotAPI
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function parse_mode($arguments)
|
||||
{
|
||||
if (isset($arguments['parse_mode']['_'])) {
|
||||
@ -385,6 +412,7 @@ trait BotAPI
|
||||
}
|
||||
if (preg_match('/html/i', $arguments['parse_mode'])) {
|
||||
$nmessage = '';
|
||||
|
||||
try {
|
||||
$arguments['message'] = $this->html_fixtags($arguments['message']);
|
||||
$dom = new \DOMDocument();
|
||||
@ -405,8 +433,10 @@ trait BotAPI
|
||||
}
|
||||
$arguments['message'] = $nmessage;
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
public function split_to_chunks($text)
|
||||
{
|
||||
$max_length = 4096;
|
||||
@ -423,15 +453,17 @@ trait BotAPI
|
||||
$i = 0;
|
||||
$message = [''];
|
||||
foreach ($text_arr as $word) {
|
||||
if (strlen($message[$i] . $word) <= $max_length) {
|
||||
if (strlen($message[$i].$word) <= $max_length) {
|
||||
$message[$i] .= $word;
|
||||
} else {
|
||||
$i++;
|
||||
$message[$i] = $word;
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function multipleExplodeKeepDelimiters($delimiters, $string)
|
||||
{
|
||||
$initialArray = explode(chr(1), str_replace($delimiters, chr(1), $string));
|
||||
@ -440,15 +472,17 @@ trait BotAPI
|
||||
foreach ($initialArray as $item) {
|
||||
$delimOffset += strlen($item);
|
||||
if (strlen($item) > 0) {
|
||||
$finalArray[] = $item . ($delimOffset < strlen($string) ? $string[$delimOffset] : '');
|
||||
$finalArray[] = $item.($delimOffset < strlen($string) ? $string[$delimOffset] : '');
|
||||
}
|
||||
$delimOffset++;
|
||||
}
|
||||
|
||||
return $finalArray;
|
||||
}
|
||||
|
||||
public function html_fixtags($text)
|
||||
{
|
||||
preg_match_all("#(.*?)(<(a|b|strong|em|i|code|pre)[^>]*>)([^<]*?)(<\\/\\3>)(.*)?#is", $text, $matches, PREG_SET_ORDER);
|
||||
preg_match_all('#(.*?)(<(a|b|strong|em|i|code|pre)[^>]*>)([^<]*?)(<\\/\\3>)(.*)?#is', $text, $matches, PREG_SET_ORDER);
|
||||
if ($matches) {
|
||||
$last = count($matches) - 1;
|
||||
foreach ($matches as $val) {
|
||||
@ -460,15 +494,17 @@ trait BotAPI
|
||||
$text = str_replace($val[6], $this->html_fixtags($val[6]), $text);
|
||||
}
|
||||
}
|
||||
preg_match_all("#<a href=\"(.+?)\">#is", $text, $matches);
|
||||
preg_match_all('#<a href="(.+?)">#is', $text, $matches);
|
||||
foreach ($matches[1] as $match) {
|
||||
$text = str_replace($match, htmlentities($match), $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
} else {
|
||||
return htmlentities($text);
|
||||
}
|
||||
}
|
||||
|
||||
public function build_rows($button_list)
|
||||
{
|
||||
$end = false;
|
||||
@ -493,6 +529,7 @@ trait BotAPI
|
||||
$row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons];
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
return ['_' => 'replyInlineMarkup', 'rows' => $rows];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
trait BotAPIFiles
|
||||
@ -18,10 +19,12 @@ trait BotAPIFiles
|
||||
{
|
||||
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
|
||||
}
|
||||
|
||||
public function base64url_encode($data)
|
||||
{
|
||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
public function rle_decode($string)
|
||||
{
|
||||
$new = '';
|
||||
@ -36,9 +39,11 @@ trait BotAPIFiles
|
||||
$last = $cur;
|
||||
}
|
||||
}
|
||||
$string = $new . $last;
|
||||
$string = $new.$last;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function rle_encode($string)
|
||||
{
|
||||
$new = '';
|
||||
@ -49,23 +54,27 @@ trait BotAPIFiles
|
||||
$count++;
|
||||
} else {
|
||||
if ($count > 0) {
|
||||
$new .= $null . chr($count);
|
||||
$new .= $null.chr($count);
|
||||
$count = 0;
|
||||
}
|
||||
$new .= $cur;
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function photosize_to_botapi($photo, $message_media, $thumbnail = false)
|
||||
{
|
||||
$ext = $this->get_extension_from_location(['_' => 'inputFileLocation', 'volume_id' => $photo['location']['volume_id'], 'local_id' => $photo['location']['local_id'], 'secret' => $photo['location']['secret'], 'dc_id' => $photo['location']['dc_id']], '.jpg');
|
||||
$photo['location']['access_hash'] = isset($message_media['access_hash']) ? $message_media['access_hash'] : 0;
|
||||
$photo['location']['id'] = isset($message_media['id']) ? $message_media['id'] : 0;
|
||||
$photo['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo';
|
||||
$data = $this->serialize_object(['type' => 'File'], $photo['location'], 'File') . chr(2);
|
||||
return ['file_id' => $this->base64url_encode($this->rle_encode($data)), 'width' => $photo['w'], 'height' => $photo['h'], 'file_size' => isset($photo['size']) ? $photo['size'] : strlen($photo['bytes']), 'mime_type' => 'image/jpeg', 'file_name' => $photo['location']['volume_id'] . '_' . $photo['location']['local_id'] . $ext];
|
||||
$data = $this->serialize_object(['type' => 'File'], $photo['location'], 'File').chr(2);
|
||||
|
||||
return ['file_id' => $this->base64url_encode($this->rle_encode($data)), 'width' => $photo['w'], 'height' => $photo['h'], 'file_size' => isset($photo['size']) ? $photo['size'] : strlen($photo['bytes']), 'mime_type' => 'image/jpeg', 'file_name' => $photo['location']['volume_id'].'_'.$photo['location']['local_id'].$ext];
|
||||
}
|
||||
|
||||
public function unpack_file_id($file_id)
|
||||
{
|
||||
$file_id = $this->rle_decode($this->base64url_decode($file_id));
|
||||
@ -85,44 +94,52 @@ trait BotAPIFiles
|
||||
unset($deserialized['_']);
|
||||
$constructor['sizes'][0]['location'] = $deserialized;
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_voice':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true]]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_video':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => false]]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_video_note':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => true]]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_document':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => []]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_sticker':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeSticker']]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_gif':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAnimated']]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
case 'bot_audio':
|
||||
unset($deserialized['_']);
|
||||
$constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]]);
|
||||
$res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => ''];
|
||||
|
||||
return $res;
|
||||
default:
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['file_type_invalid'], $type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
/**
|
||||
@ -22,11 +23,13 @@ trait Extension
|
||||
{
|
||||
foreach (self::ALL_MIMES as $key => $value) {
|
||||
if (array_search($mime, (array) $value) !== false) {
|
||||
return '.' . $key;
|
||||
return '.'.$key;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function get_extension_from_location($location, $default)
|
||||
{
|
||||
return $default;
|
||||
@ -55,4 +58,4 @@ trait Extension
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
trait TD
|
||||
@ -21,6 +22,7 @@ trait TD
|
||||
}
|
||||
if (!isset($params['ID'])) {
|
||||
array_walk($params, [$this, 'tdcli_to_td']);
|
||||
|
||||
return $params;
|
||||
}
|
||||
foreach ($params as $key => $value) {
|
||||
@ -32,8 +34,10 @@ trait TD
|
||||
}
|
||||
$params['_'] = lcfirst($params['ID']);
|
||||
unset($params['ID']);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function td_to_mtproto($params)
|
||||
{
|
||||
$newparams = ['_' => self::REVERSE[$params['_']]];
|
||||
@ -61,12 +65,15 @@ trait TD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $newparams;
|
||||
}
|
||||
|
||||
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)) {
|
||||
@ -74,6 +81,7 @@ trait TD
|
||||
}
|
||||
if (!isset($params['_'])) {
|
||||
array_walk($params, [$this, 'mtproto_to_td']);
|
||||
|
||||
return $params;
|
||||
}
|
||||
$newparams = ['_' => $params['_']];
|
||||
@ -101,7 +109,7 @@ trait TD
|
||||
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']];
|
||||
$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'])) {
|
||||
@ -145,8 +153,10 @@ trait TD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $newparams;
|
||||
}
|
||||
|
||||
public function td_to_tdcli($params)
|
||||
{
|
||||
if (!is_array($params)) {
|
||||
@ -158,11 +168,12 @@ trait TD
|
||||
$newparams['ID'] = ucfirst($value);
|
||||
} else {
|
||||
if (!is_numeric($key) && !preg_match('/_^/', $key)) {
|
||||
$key = $key . '_';
|
||||
$key = $key.'_';
|
||||
}
|
||||
$newparams[$key] = $this->td_to_tdcli($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $newparams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,18 +10,21 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
use PrettyException;
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . @file_get_contents(__DIR__ . '/../../../.git/refs/heads/master') . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL;
|
||||
return get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.@file_get_contents(__DIR__.'/../../../.git/refs/heads/master').PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||
}
|
||||
|
||||
public function __construct($message, $file = '')
|
||||
{
|
||||
parent::__construct($message);
|
||||
$this->prettify_tl($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,22 +10,25 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
trait PrettyException
|
||||
{
|
||||
public $tl_trace;
|
||||
|
||||
public function getTLTrace()
|
||||
{
|
||||
return $this->tl_trace;
|
||||
}
|
||||
|
||||
public function prettify_tl($init = '')
|
||||
{
|
||||
$tl = false;
|
||||
foreach (array_reverse($this->getTrace()) as $k => $frame) {
|
||||
if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
|
||||
if ($frame['args'][2] !== '') {
|
||||
$this->tl_trace .= $tl ? "['" . $frame['args'][2] . "']" : "While serializing: \t" . $frame['args'][2] . PHP_EOL;
|
||||
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2].PHP_EOL;
|
||||
$tl = true;
|
||||
}
|
||||
} else {
|
||||
@ -35,15 +38,15 @@ trait PrettyException
|
||||
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
|
||||
continue;
|
||||
}
|
||||
$this->tl_trace .= isset($frame['file']) ? str_pad(basename($frame['file']) . '(' . $frame['line'] . '):', 20) . "\t" : '';
|
||||
$this->tl_trace .= isset($frame['function']) ? $frame['function'] . '(' : '';
|
||||
$this->tl_trace .= isset($frame['file']) ? str_pad(basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : '';
|
||||
$this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : '';
|
||||
$this->tl_trace .= isset($frame['args']) ? substr(json_encode($frame['args']), 1, -1) : '';
|
||||
$this->tl_trace .= ')';
|
||||
$this->tl_trace .= PHP_EOL;
|
||||
$tl = false;
|
||||
}
|
||||
}
|
||||
$this->tl_trace .= $init !== '' ? "['" . $init . "']" : '';
|
||||
$this->tl_trace .= $init !== '' ? "['".$init."']" : '';
|
||||
$this->tl_trace = implode(PHP_EOL, array_reverse(explode(PHP_EOL, $this->tl_trace)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
trait TL
|
||||
@ -20,6 +21,7 @@ trait TL
|
||||
public $td_constructors;
|
||||
public $td_methods;
|
||||
public $td_descriptions;
|
||||
|
||||
public function construct_tl($files)
|
||||
{
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['TL_loading']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
@ -139,7 +141,7 @@ trait TL
|
||||
}
|
||||
}
|
||||
if (empty($TL_dict) || empty($TL_dict['constructors']) || !isset($TL_dict['methods'])) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'] . $file);
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'].$file);
|
||||
}
|
||||
$orig = $this->encrypted_layer;
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['translating_obj']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
@ -147,11 +149,11 @@ trait TL
|
||||
if ($scheme_type === 'secret') {
|
||||
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
||||
}
|
||||
$this->{($scheme_type === 'td' ? 'td_' : '') . 'constructors'}->add($elem, $scheme_type);
|
||||
$this->{($scheme_type === 'td' ? 'td_' : '').'constructors'}->add($elem, $scheme_type);
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['translating_methods']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
foreach ($TL_dict['methods'] as $elem) {
|
||||
$this->{($scheme_type === 'td' ? 'td_' : '') . 'methods'}->add($elem);
|
||||
$this->{($scheme_type === 'td' ? 'td_' : '').'methods'}->add($elem);
|
||||
if ($scheme_type === 'secret') {
|
||||
$this->encrypted_layer = max($this->encrypted_layer, $elem['layer']);
|
||||
}
|
||||
@ -183,6 +185,7 @@ trait TL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_method_namespaces()
|
||||
{
|
||||
$res = [];
|
||||
@ -190,20 +193,25 @@ trait TL
|
||||
$a = key($pair);
|
||||
$res[$a] = $a;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function get_methods_namespaced()
|
||||
{
|
||||
return $this->methods->method_namespace;
|
||||
}
|
||||
|
||||
public function deserialize_bool($id)
|
||||
{
|
||||
$tl_elem = $this->constructors->find_by_id($id);
|
||||
if ($tl_elem === false) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['bool_error']);
|
||||
}
|
||||
|
||||
return $tl_elem['predicate'] === 'boolTrue';
|
||||
}
|
||||
|
||||
public function serialize_object($type, $object, $ctx, $layer = -1)
|
||||
{
|
||||
switch ($type['type']) {
|
||||
@ -211,11 +219,13 @@ trait TL
|
||||
if (!is_numeric($object)) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||
}
|
||||
|
||||
return $this->pack_signed_int($object);
|
||||
case '#':
|
||||
if (!is_numeric($object)) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||
}
|
||||
|
||||
return $this->pack_unsigned_int($object);
|
||||
case 'long':
|
||||
if (is_object($object)) {
|
||||
@ -230,21 +240,25 @@ trait TL
|
||||
if (!is_numeric($object)) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']);
|
||||
}
|
||||
|
||||
return $this->pack_signed_long($object);
|
||||
case 'int128':
|
||||
if (strlen($object) !== 16) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_16']);
|
||||
}
|
||||
|
||||
return (string) $object;
|
||||
case 'int256':
|
||||
if (strlen($object) !== 32) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_32']);
|
||||
}
|
||||
|
||||
return (string) $object;
|
||||
case 'int512':
|
||||
if (strlen($object) !== 64) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_64']);
|
||||
}
|
||||
|
||||
return (string) $object;
|
||||
case 'double':
|
||||
return $this->pack_double($object);
|
||||
@ -258,13 +272,14 @@ trait TL
|
||||
if ($l <= 253) {
|
||||
$concat .= chr($l);
|
||||
$concat .= $object;
|
||||
$concat .= pack('@' . $this->posmod(-$l - 1, 4));
|
||||
$concat .= pack('@'.$this->posmod(-$l - 1, 4));
|
||||
} else {
|
||||
$concat .= chr(254);
|
||||
$concat .= substr($this->pack_signed_int($l), 0, 3);
|
||||
$concat .= $object;
|
||||
$concat .= pack('@' . $this->posmod(-$l, 4));
|
||||
$concat .= pack('@'.$this->posmod(-$l, 4));
|
||||
}
|
||||
|
||||
return $concat;
|
||||
case 'bytes':
|
||||
if (!is_string($object) && !$object instanceof \danog\MadelineProto\TL\Types\Bytes) {
|
||||
@ -275,13 +290,14 @@ trait TL
|
||||
if ($l <= 253) {
|
||||
$concat .= chr($l);
|
||||
$concat .= $object;
|
||||
$concat .= pack('@' . $this->posmod(-$l - 1, 4));
|
||||
$concat .= pack('@'.$this->posmod(-$l - 1, 4));
|
||||
} else {
|
||||
$concat .= chr(254);
|
||||
$concat .= substr($this->pack_signed_int($l), 0, 3);
|
||||
$concat .= $object;
|
||||
$concat .= pack('@' . $this->posmod(-$l, 4));
|
||||
$concat .= pack('@'.$this->posmod(-$l, 4));
|
||||
}
|
||||
|
||||
return $concat;
|
||||
case 'Bool':
|
||||
return $this->constructors->find_by_predicate((bool) $object ? 'boolTrue' : 'boolFalse')['id'];
|
||||
@ -298,6 +314,7 @@ trait TL
|
||||
foreach ($object as $k => $current_object) {
|
||||
$concat .= $this->serialize_object(['type' => $type['subtype']], $current_object, $k);
|
||||
}
|
||||
|
||||
return $concat;
|
||||
case 'vector':
|
||||
if (!is_array($object)) {
|
||||
@ -307,6 +324,7 @@ trait TL
|
||||
foreach ($object as $k => $current_object) {
|
||||
$concat .= $this->serialize_object(['type' => $type['subtype']], $current_object, $k);
|
||||
}
|
||||
|
||||
return $concat;
|
||||
case 'Object':
|
||||
if (is_string($object)) {
|
||||
@ -333,6 +351,7 @@ trait TL
|
||||
$constructorData = $this->constructors->find_by_predicate($predicate, $layer);
|
||||
if ($constructorData === false) {
|
||||
\danog\MadelineProto\Logger::log([$object], \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error'], $predicate));
|
||||
}
|
||||
if ($bare = $type['type'] != '' && $type['type'][0] === '%') {
|
||||
@ -348,16 +367,20 @@ trait TL
|
||||
if (!$bare) {
|
||||
$concat = $constructorData['id'];
|
||||
}
|
||||
return $concat . $this->serialize_params($constructorData, $object, '', $layer);
|
||||
|
||||
return $concat.$this->serialize_params($constructorData, $object, '', $layer);
|
||||
}
|
||||
|
||||
public function serialize_method($method, $arguments)
|
||||
{
|
||||
$tl = $this->methods->find_by_method($method);
|
||||
if ($tl === false) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['method_not_found'] . $method);
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['method_not_found'].$method);
|
||||
}
|
||||
return $tl['id'] . $this->serialize_params($tl, $arguments, $method);
|
||||
|
||||
return $tl['id'].$this->serialize_params($tl, $arguments, $method);
|
||||
}
|
||||
|
||||
public function serialize_params($tl, $arguments, $ctx, $layer = -1)
|
||||
{
|
||||
$serialized = '';
|
||||
@ -415,10 +438,11 @@ trait TL
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($id = $this->constructors->find_by_predicate(lcfirst($current_argument['type']) . 'Empty')) {
|
||||
if ($id = $this->constructors->find_by_predicate(lcfirst($current_argument['type']).'Empty')) {
|
||||
$serialized .= $id['id'];
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['params_missing'], $current_argument['name']);
|
||||
}
|
||||
if (!is_array($arguments[$current_argument['name']]) && $current_argument['type'] === 'InputEncryptedChat') {
|
||||
@ -433,8 +457,10 @@ trait TL
|
||||
//\danog\MadelineProto\Logger::log(['Serializing '.$current_argument['name'].' of type '.$current_argument['type']);
|
||||
$serialized .= $this->serialize_object($current_argument, $arguments[$current_argument['name']], $current_argument['name'], $layer);
|
||||
}
|
||||
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
public function get_length($stream, $type = ['type' => ''])
|
||||
{
|
||||
if (is_string($stream)) {
|
||||
@ -446,8 +472,10 @@ trait TL
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
|
||||
}
|
||||
$this->deserialize($stream, $type);
|
||||
|
||||
return ftell($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* :type stream: io.BytesIO object.
|
||||
*/
|
||||
@ -472,6 +500,7 @@ trait TL
|
||||
if (isset($type['idstrlong'])) {
|
||||
return stream_get_contents($stream, 8);
|
||||
}
|
||||
|
||||
return \danog\MadelineProto\Logger::$bigint || isset($type['strlong']) ? stream_get_contents($stream, 8) : $this->unpack_signed_long(stream_get_contents($stream, 8));
|
||||
case 'double':
|
||||
return $this->unpack_double(stream_get_contents($stream, 8));
|
||||
@ -488,7 +517,7 @@ trait TL
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']);
|
||||
}
|
||||
if ($l === 254) {
|
||||
$long_len = unpack('V', stream_get_contents($stream, 3) . chr(0))[1];
|
||||
$long_len = unpack('V', stream_get_contents($stream, 3).chr(0))[1];
|
||||
$x = stream_get_contents($stream, $long_len);
|
||||
$resto = $this->posmod(-$long_len, 4);
|
||||
if ($resto > 0) {
|
||||
@ -504,13 +533,14 @@ trait TL
|
||||
if (!is_string($x)) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']);
|
||||
}
|
||||
|
||||
return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x;
|
||||
case 'Vector t':
|
||||
$id = stream_get_contents($stream, 4);
|
||||
$constructorData = $this->constructors->find_by_id($id);
|
||||
if ($constructorData === false) {
|
||||
$constructorData = $this->methods->find_by_id($id);
|
||||
$constructorData['predicate'] = 'method_' . $constructorData['method'];
|
||||
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
||||
}
|
||||
if ($constructorData === false) {
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
|
||||
@ -522,7 +552,7 @@ trait TL
|
||||
case 'vector':
|
||||
break;
|
||||
default:
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'] . $constructorData['predicate']);
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']);
|
||||
}
|
||||
case 'vector':
|
||||
$count = unpack('V', stream_get_contents($stream, 4))[1];
|
||||
@ -531,13 +561,14 @@ trait TL
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$result[] = $this->deserialize($stream, $type);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
if ($type['type'] != '' && $type['type'][0] === '%') {
|
||||
$checkType = substr($type['type'], 1);
|
||||
$constructorData = $this->constructors->find_by_type($checkType);
|
||||
if ($constructorData === false) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'] . $checkType);
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType);
|
||||
}
|
||||
} else {
|
||||
$constructorData = $this->constructors->find_by_predicate($type['type']);
|
||||
@ -549,7 +580,7 @@ trait TL
|
||||
if ($constructorData === false) {
|
||||
throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
|
||||
}
|
||||
$constructorData['predicate'] = 'method_' . $constructorData['method'];
|
||||
$constructorData['predicate'] = 'method_'.$constructorData['method'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -557,12 +588,14 @@ trait TL
|
||||
if (!isset($type['subtype'])) {
|
||||
$type['subtype'] = '';
|
||||
}
|
||||
|
||||
return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'datacenter' => $type['datacenter'], 'subtype' => $type['subtype']]);
|
||||
}
|
||||
if ($constructorData['type'] === 'Vector t') {
|
||||
$constructorData['datacenter'] = $type['datacenter'];
|
||||
$constructorData['subtype'] = isset($type['subtype']) ? $type['subtype'] : '';
|
||||
$constructorData['type'] = 'vector';
|
||||
|
||||
return $this->deserialize($stream, $constructorData);
|
||||
}
|
||||
if ($constructorData['predicate'] === 'boolTrue') {
|
||||
@ -628,6 +661,7 @@ trait TL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class TLConstructor
|
||||
@ -20,6 +21,7 @@ class TLConstructor
|
||||
public $by_id = [];
|
||||
public $by_predicate_and_layer = [];
|
||||
public $layers = [];
|
||||
|
||||
//public $type = [];
|
||||
//public $params = [];
|
||||
//public $layer = [];
|
||||
@ -28,10 +30,11 @@ class TLConstructor
|
||||
{
|
||||
return ['by_predicate_and_layer', 'by_id', 'layers'];
|
||||
}
|
||||
|
||||
public function add($json_dict, $scheme_type)
|
||||
{
|
||||
$predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '') . $json_dict['predicate']);
|
||||
$this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '') . $json_dict['type']];
|
||||
$predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '').$json_dict['predicate']);
|
||||
$this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '').$json_dict['type']];
|
||||
if ($scheme_type === 'secret') {
|
||||
$this->by_id[$json_dict['id']]['layer'] = $json_dict['layer'];
|
||||
$this->layers[$json_dict['layer']] = $json_dict['layer'];
|
||||
@ -39,30 +42,34 @@ class TLConstructor
|
||||
} else {
|
||||
$json_dict['layer'] = '';
|
||||
}
|
||||
$this->by_predicate_and_layer[$predicate . $json_dict['layer']] = $json_dict['id'];
|
||||
$this->by_predicate_and_layer[$predicate.$json_dict['layer']] = $json_dict['id'];
|
||||
$this->parse_params($json_dict['id'], $scheme_type === 'mtproto');
|
||||
}
|
||||
|
||||
public function find_by_type($type)
|
||||
{
|
||||
foreach ($this->by_id as $id => $constructor) {
|
||||
if ($constructor['type'] === $type) {
|
||||
$constructor['id'] = $id;
|
||||
$constructor['params'] = $constructor['params'];
|
||||
|
||||
return $constructor;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function find_by_predicate($predicate, $layer = -1)
|
||||
{
|
||||
if ($layer !== -1) {
|
||||
foreach ($this->layers as $alayer) {
|
||||
if ($alayer <= $layer) {
|
||||
if (isset($this->by_predicate_and_layer[$predicate . $alayer])) {
|
||||
$chosenid = $this->by_predicate_and_layer[$predicate . $alayer];
|
||||
if (isset($this->by_predicate_and_layer[$predicate.$alayer])) {
|
||||
$chosenid = $this->by_predicate_and_layer[$predicate.$alayer];
|
||||
}
|
||||
} elseif (!isset($chosenid)) {
|
||||
$chosenid = $this->by_predicate_and_layer[$predicate . $alayer];
|
||||
$chosenid = $this->by_predicate_and_layer[$predicate.$alayer];
|
||||
}
|
||||
}
|
||||
if (!isset($chosenid)) {
|
||||
@ -71,24 +78,30 @@ class TLConstructor
|
||||
$constructor = $this->by_id[$chosenid];
|
||||
$constructor['id'] = $chosenid;
|
||||
$constructor['params'] = $constructor['params'];
|
||||
|
||||
return $constructor;
|
||||
}
|
||||
if (isset($this->by_predicate_and_layer[$predicate])) {
|
||||
$constructor = $this->by_id[$this->by_predicate_and_layer[$predicate]];
|
||||
$constructor['id'] = $this->by_predicate_and_layer[$predicate];
|
||||
$constructor['params'] = $constructor['params'];
|
||||
|
||||
return $constructor;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function find_by_id($id)
|
||||
{
|
||||
if (isset($this->by_id[$id])) {
|
||||
$constructor = $this->by_id[$id];
|
||||
$constructor['id'] = $id;
|
||||
$constructor['params'] = $constructor['params'];
|
||||
|
||||
return $constructor;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class TLMethod
|
||||
@ -20,10 +21,12 @@ class TLMethod
|
||||
public $by_id = [];
|
||||
public $by_method = [];
|
||||
public $method_namespace = [];
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['by_id', 'by_method', 'method_namespace'];
|
||||
}
|
||||
|
||||
public function add($json_dict)
|
||||
{
|
||||
$this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']];
|
||||
@ -34,24 +37,30 @@ class TLMethod
|
||||
}
|
||||
$this->parse_params($json_dict['id']);
|
||||
}
|
||||
|
||||
public function find_by_id($id)
|
||||
{
|
||||
if (isset($this->by_id[$id])) {
|
||||
$method = $this->by_id[$id];
|
||||
$method['id'] = $id;
|
||||
$method['params'] = $method['params'];
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function find_by_method($method_name)
|
||||
{
|
||||
if (isset($this->by_method[$method_name])) {
|
||||
$method = $this->by_id[$this->by_method[$method_name]];
|
||||
$method['id'] = $this->by_method[$method_name];
|
||||
$method['params'] = $method['params'];
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
trait TLParams
|
||||
@ -31,12 +32,12 @@ trait TLParams
|
||||
$param['subtype'] = preg_replace(['/.*</', '/>$/'], '', $param['type']);
|
||||
$param['type'] = 'Vector t';
|
||||
}
|
||||
$param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '') . $param['subtype'];
|
||||
$param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype'];
|
||||
$param['subtype'] = $mtproto && $param['subtype'] === '%Message' ? '%MTMessage' : $param['subtype'];
|
||||
}
|
||||
$param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '') . $param['type'];
|
||||
$param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '').$param['type'];
|
||||
$param['type'] = $mtproto && $param['type'] === '%Message' ? '%MTMessage' : $param['type'];
|
||||
$this->by_id[$key]['params'][$kkey] = $param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Types;
|
||||
|
||||
class Button extends \Volatile implements \JsonSerializable
|
||||
@ -17,6 +18,7 @@ class Button extends \Volatile implements \JsonSerializable
|
||||
use \danog\Serializable;
|
||||
private $info = [];
|
||||
private $data = [];
|
||||
|
||||
public function __magic_construct($API, $message, $button)
|
||||
{
|
||||
$this->data = $button;
|
||||
@ -24,10 +26,12 @@ class Button extends \Volatile implements \JsonSerializable
|
||||
$this->info['id'] = $message['id'];
|
||||
$this->info['API'] = $API;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['data', 'info'];
|
||||
}
|
||||
|
||||
public function click($donotwait = false)
|
||||
{
|
||||
switch ($this->data['_']) {
|
||||
@ -43,12 +47,14 @@ class Button extends \Volatile implements \JsonSerializable
|
||||
return $this->info['API']->method_call('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['noResponse' => $donotwait, 'datacenter' => $this->info['API']->datacenter->curdc]);
|
||||
}
|
||||
}
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
return ['data' => $this->data, 'info' => ['peer' => $this->info['peer'], 'id' => $this->info['id']]];
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return (array) $this->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,26 +10,31 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\TL\Types;
|
||||
|
||||
class Bytes extends \Volatile implements \JsonSerializable
|
||||
{
|
||||
use \danog\Serializable;
|
||||
private $bytes = [];
|
||||
|
||||
public function __magic_construct($bytes)
|
||||
{
|
||||
$this->bytes = $bytes;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['bytes'];
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->bytes;
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return utf8_encode($this->bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\Threads;
|
||||
|
||||
/**
|
||||
@ -23,33 +24,39 @@ class SocketHandler extends \Threaded implements \Collectable
|
||||
$this->current = $current;
|
||||
$this->error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading connection and receiving message from server. Check the CRC32.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
require __DIR__ . '/../../../../vendor/autoload.php';
|
||||
require __DIR__.'/../../../../vendor/autoload.php';
|
||||
if ($this->error !== true) {
|
||||
if ($this->error === -404) {
|
||||
if ($this->API->datacenter->sockets[$this->current]->temp_auth_key !== null) {
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['resetting_auth_key']], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->API->datacenter->sockets[$this->current]->temp_auth_key = null;
|
||||
$this->API->init_authorization();
|
||||
|
||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['recreate_temp_auth_key']);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \danog\MadelineProto\RPCErrorException($this->error, $this->error);
|
||||
}
|
||||
$this->API->handle_messages($this->current);
|
||||
$this->setGarbage();
|
||||
}
|
||||
|
||||
protected $garbage = false;
|
||||
|
||||
public function setGarbage()
|
||||
{
|
||||
$this->garbage = true;
|
||||
}
|
||||
|
||||
public function isGarbage()
|
||||
{
|
||||
return $this->garbage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\Threads;
|
||||
|
||||
/**
|
||||
@ -18,25 +19,29 @@ namespace danog\MadelineProto\Threads;
|
||||
class SocketReader extends \Threaded implements \Collectable
|
||||
{
|
||||
public $ready = false;
|
||||
|
||||
public function __construct($me, $current)
|
||||
{
|
||||
$this->API = $me;
|
||||
$this->current = $current;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return ['current', 'API', 'garbage'];
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['shutting_down_reader_pool'] . $this->current], \danog\MadelineProto\Logger::NOTICE);
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['shutting_down_reader_pool'].$this->current], \danog\MadelineProto\Logger::NOTICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading connection and receiving message from server. Check the CRC32.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
require __DIR__ . '/../../../../vendor/autoload.php';
|
||||
require __DIR__.'/../../../../vendor/autoload.php';
|
||||
$handler_pool = new \Pool($this->API->settings['threading']['handler_workers']);
|
||||
$this->ready = true;
|
||||
while ($this->API->run_workers) {
|
||||
@ -57,13 +62,16 @@ class SocketReader extends \Threaded implements \Collectable
|
||||
}
|
||||
$this->setGarbage();
|
||||
}
|
||||
|
||||
public $garbage = false;
|
||||
|
||||
public function setGarbage()
|
||||
{
|
||||
$this->garbage = true;
|
||||
}
|
||||
|
||||
public function isGarbage()
|
||||
{
|
||||
return $this->garbage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ See the GNU Affero General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with the MadelineProto.
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
/**
|
||||
@ -21,6 +22,7 @@ trait Tools
|
||||
{
|
||||
return $length === 0 ? '' : \phpseclib\Crypt\Random::string($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* posmod(numeric,numeric) : numeric
|
||||
* Works just like the % (modulus) operator, only returns always a postive number.
|
||||
@ -28,8 +30,10 @@ trait Tools
|
||||
public function posmod($a, $b)
|
||||
{
|
||||
$resto = $a % $b;
|
||||
|
||||
return $resto < 0 ? $resto + abs($b) : $resto;
|
||||
}
|
||||
|
||||
public function array_cast_recursive($array, $force = false)
|
||||
{
|
||||
if (!\danog\MadelineProto\Logger::$has_thread && !$force) {
|
||||
@ -43,22 +47,28 @@ trait Tools
|
||||
$array[$key] = $this->array_cast_recursive($value, $force);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function unpack_signed_int($value)
|
||||
{
|
||||
if (strlen($value) !== 4) {
|
||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']);
|
||||
}
|
||||
|
||||
return unpack('l', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
|
||||
public function unpack_signed_long($value)
|
||||
{
|
||||
if (strlen($value) !== 8) {
|
||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||
}
|
||||
|
||||
return unpack('q', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
|
||||
public function pack_signed_int($value)
|
||||
{
|
||||
if ($value > 2147483647) {
|
||||
@ -68,8 +78,10 @@ trait Tools
|
||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value));
|
||||
}
|
||||
$res = pack('l', $value);
|
||||
|
||||
return \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($res) : $res;
|
||||
}
|
||||
|
||||
public function pack_signed_long($value)
|
||||
{
|
||||
if ($value > 9223372036854775807) {
|
||||
@ -78,9 +90,11 @@ trait Tools
|
||||
if ($value < -9.223372036854776E+18) {
|
||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_9223372036854775808'], $value));
|
||||
}
|
||||
$res = \danog\MadelineProto\Logger::$bigint ? $this->pack_signed_int($value) . "\0\0\0\0" : (\danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev(pack('q', $value)) : pack('q', $value));
|
||||
$res = \danog\MadelineProto\Logger::$bigint ? $this->pack_signed_int($value)."\0\0\0\0" : (\danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev(pack('q', $value)) : pack('q', $value));
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function pack_unsigned_int($value)
|
||||
{
|
||||
if ($value > 4294967295) {
|
||||
@ -89,21 +103,26 @@ trait Tools
|
||||
if ($value < 0) {
|
||||
throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_0'], $value));
|
||||
}
|
||||
|
||||
return pack('V', $value);
|
||||
}
|
||||
|
||||
public function pack_double($value)
|
||||
{
|
||||
$res = pack('d', $value);
|
||||
if (strlen($res) !== 8) {
|
||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['encode_double_error']);
|
||||
}
|
||||
|
||||
return \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($res) : $res;
|
||||
}
|
||||
|
||||
public function unpack_double($value)
|
||||
{
|
||||
if (strlen($value) !== 8) {
|
||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||
}
|
||||
|
||||
return unpack('d', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\VoIP;
|
||||
|
||||
/**
|
||||
@ -21,6 +22,7 @@ namespace danog\MadelineProto\VoIP;
|
||||
trait AuthKeyHandler
|
||||
{
|
||||
private $calls = [];
|
||||
|
||||
public function request_call($user)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -48,8 +50,10 @@ trait AuthKeyHandler
|
||||
$controller->storage = ['a' => $a, 'g_a' => str_pad($g_a->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
public function accept_call($call)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -62,6 +66,7 @@ trait AuthKeyHandler
|
||||
});
|
||||
if ($this->call_status($call['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED) {
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_1'], $call['id'])]);
|
||||
|
||||
return false;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['accepting_call'], $this->calls[$call['id']]->getOtherID())], \danog\MadelineProto\Logger::VERBOSE);
|
||||
@ -70,25 +75,31 @@ trait AuthKeyHandler
|
||||
$b = \phpseclib\Math\BigInteger::randomRange($this->two, $dh_config['p']->subtract($this->two));
|
||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||
$this->check_G($g_b, $dh_config['p']);
|
||||
|
||||
try {
|
||||
$res = $this->method_call('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => 65]], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id'])]);
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($e->rpc === 'CALL_ALREADY_DECLINED') {
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['call_already_declined']]);
|
||||
$this->discard_call($call['id'], 'phoneCallDiscardReasonHangup');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
$this->calls[$res['phone_call']['id']]->storage['b'] = $b;
|
||||
$this->handle_pending_updates();
|
||||
$this->get_updates_difference();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function confirm_call($params)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -101,6 +112,7 @@ trait AuthKeyHandler
|
||||
});
|
||||
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED) {
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_2'], $params['id'])]);
|
||||
|
||||
return false;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID())], \danog\MadelineProto\Logger::VERBOSE);
|
||||
@ -111,7 +123,7 @@ trait AuthKeyHandler
|
||||
$res = $this->method_call('phone.confirmCall', ['key_fingerprint' => substr(sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => 65]], ['datacenter' => $this->datacenter->curdc])['phone_call'];
|
||||
$visualization = [];
|
||||
$length = new \phpseclib\Math\BigInteger(count($this->emojis));
|
||||
foreach (str_split(hash('sha256', $key . str_pad($this->calls[$params['id']]->storage['g_a'], 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||
foreach (str_split(hash('sha256', $key.str_pad($this->calls[$params['id']]->storage['g_a'], 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||
$number[0] = chr(ord($number[0]) & 0x7f);
|
||||
$visualization[] = $this->emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
||||
}
|
||||
@ -122,8 +134,10 @@ trait AuthKeyHandler
|
||||
$this->calls[$params['id']]->parseConfig();
|
||||
$res = $this->calls[$params['id']]->startTheMagic();
|
||||
$this->handle_pending_updates();
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function complete_call($params)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -136,6 +150,7 @@ trait AuthKeyHandler
|
||||
});
|
||||
if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED || !isset($this->calls[$params['id']]->storage['b'])) {
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_3'], $params['id'])]);
|
||||
|
||||
return false;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_completing'], $this->calls[$params['id']]->getOtherID())], \danog\MadelineProto\Logger::VERBOSE);
|
||||
@ -151,7 +166,7 @@ trait AuthKeyHandler
|
||||
}
|
||||
$visualization = [];
|
||||
$length = new \phpseclib\Math\BigInteger(count($this->emojis));
|
||||
foreach (str_split(hash('sha256', $key . str_pad($params['g_a_or_b']->toBytes(), 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||
foreach (str_split(hash('sha256', $key.str_pad($params['g_a_or_b']->toBytes(), 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
|
||||
$number[0] = chr(ord($number[0]) & 0x7f);
|
||||
$visualization[] = $this->emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
|
||||
}
|
||||
@ -160,8 +175,10 @@ trait AuthKeyHandler
|
||||
$this->calls[$params['id']]->configuration['endpoints'] = array_merge([$params['connection']], $params['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']);
|
||||
$this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
|
||||
$this->calls[$params['id']]->parseConfig();
|
||||
|
||||
return $this->calls[$params['id']]->startTheMagic();
|
||||
}
|
||||
|
||||
public function call_status($id)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -175,8 +192,10 @@ trait AuthKeyHandler
|
||||
if (isset($this->calls[$id])) {
|
||||
return $this->calls[$id]->getCallState();
|
||||
}
|
||||
|
||||
return \danog\MadelineProto\VoIP::CALL_STATE_NONE;
|
||||
}
|
||||
|
||||
public function get_call($call)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -187,8 +206,10 @@ trait AuthKeyHandler
|
||||
$controller->discard();
|
||||
}
|
||||
});
|
||||
|
||||
return $this->calls[$call];
|
||||
}
|
||||
|
||||
public function discard_call($call, $reason, $rating = [], $need_debug = true)
|
||||
{
|
||||
if (!class_exists('\\danog\\MadelineProto\\VoIP')) {
|
||||
@ -198,6 +219,7 @@ trait AuthKeyHandler
|
||||
return;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['call_discarding'], $call['id'])], \danog\MadelineProto\Logger::VERBOSE);
|
||||
|
||||
try {
|
||||
$res = $this->method_call('phone.discardCall', ['peer' => $call, 'duration' => time() - $this->calls[$call['id']]->whenCreated(), 'connection_id' => $this->calls[$call['id']]->getPreferredRelayID(), 'reason' => $reason], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -227,4 +249,4 @@ trait AuthKeyHandler
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
trait DialogHandler
|
||||
@ -24,6 +25,7 @@ trait DialogHandler
|
||||
$datacenter = $this->datacenter->curdc;
|
||||
$peers = [];
|
||||
$this->postpone_updates = true;
|
||||
|
||||
try {
|
||||
while ($this->dialog_params['count'] < $res['count']) {
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['getting_dialogs']]);
|
||||
@ -45,6 +47,7 @@ trait DialogHandler
|
||||
$this->postpone_updates = false;
|
||||
$this->updates_state['sync_loading'] = false;
|
||||
}
|
||||
|
||||
return $peers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
/**
|
||||
@ -34,8 +35,10 @@ trait Login
|
||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['logout_error']);
|
||||
}
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['logout_ok']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function bot_login($token)
|
||||
{
|
||||
if ($this->authorized === self::LOGGED_IN) {
|
||||
@ -50,12 +53,14 @@ trait Login
|
||||
$this->updates = [];
|
||||
$this->updates_key = 0;
|
||||
if (!isset($this->settings['pwr']['pwr']) || !$this->settings['pwr']['pwr']) {
|
||||
@file_get_contents('https://api.pwrtelegram.xyz/bot' . $token . '/getme');
|
||||
@file_get_contents('https://api.pwrtelegram.xyz/bot'.$token.'/getme');
|
||||
}
|
||||
$this->init_authorization();
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_ok']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $this->authorization;
|
||||
}
|
||||
|
||||
public function phone_login($number, $sms_type = 5)
|
||||
{
|
||||
if ($this->authorized === self::LOGGED_IN) {
|
||||
@ -71,8 +76,10 @@ trait Login
|
||||
$this->updates = [];
|
||||
$this->updates_key = 0;
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_code_sent']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $this->authorization;
|
||||
}
|
||||
|
||||
public function complete_phone_login($code)
|
||||
{
|
||||
if ($this->authorized !== self::WAITING_CODE) {
|
||||
@ -80,6 +87,7 @@ trait Login
|
||||
}
|
||||
$this->authorized = self::NOT_LOGGED_IN;
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_user']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
try {
|
||||
$authorization = $this->method_call('auth.signIn', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => $code], ['datacenter' => $this->datacenter->curdc]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -94,8 +102,10 @@ trait Login
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_need_signup']], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->authorized = self::WAITING_SIGNUP;
|
||||
$this->authorization['phone_code'] = $code;
|
||||
|
||||
return ['_' => 'account.needSignup'];
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
$this->authorized = self::LOGGED_IN;
|
||||
@ -103,8 +113,10 @@ trait Login
|
||||
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
|
||||
$this->init_authorization();
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_ok']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $this->authorization;
|
||||
}
|
||||
|
||||
public function import_authorization($authorization)
|
||||
{
|
||||
if ($this->authorized === self::LOGGED_IN) {
|
||||
@ -129,8 +141,10 @@ trait Login
|
||||
$this->datacenter->sockets[$dc_id]->authorized = true;
|
||||
$this->authorized = self::LOGGED_IN;
|
||||
$this->init_authorization();
|
||||
|
||||
return $this->get_self();
|
||||
}
|
||||
|
||||
public function export_authorization()
|
||||
{
|
||||
if ($this->authorized !== self::LOGGED_IN) {
|
||||
@ -138,8 +152,10 @@ trait Login
|
||||
}
|
||||
$this->get_self();
|
||||
$this->authorized_dc = $this->datacenter->curdc;
|
||||
|
||||
return [$this->datacenter->curdc, $this->datacenter->sockets[$this->datacenter->curdc]->auth_key['auth_key']];
|
||||
}
|
||||
|
||||
public function complete_signup($first_name, $last_name)
|
||||
{
|
||||
if ($this->authorized !== self::WAITING_SIGNUP) {
|
||||
@ -152,8 +168,10 @@ trait Login
|
||||
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
|
||||
$this->init_authorization();
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['signup_ok']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $this->authorization;
|
||||
}
|
||||
|
||||
public function complete_2fa_login($password)
|
||||
{
|
||||
if ($this->authorized !== self::WAITING_PASSWORD) {
|
||||
@ -161,11 +179,12 @@ trait Login
|
||||
}
|
||||
$this->authorized = self::NOT_LOGGED_IN;
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_user']], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->authorization = $this->method_call('auth.checkPassword', ['password_hash' => hash('sha256', $this->authorization['current_salt'] . $password . $this->authorization['current_salt'], true)], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->authorization = $this->method_call('auth.checkPassword', ['password_hash' => hash('sha256', $this->authorization['current_salt'].$password.$this->authorization['current_salt'], true)], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->authorized = self::LOGGED_IN;
|
||||
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
|
||||
$this->init_authorization();
|
||||
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['login_ok']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return $this->authorization;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user