Apply misc fixes

This commit is contained in:
Daniil Gentili 2020-04-05 14:57:33 +02:00
parent 979d7575fc
commit 23e3c5b12c
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
43 changed files with 188 additions and 231 deletions

2
docs

@ -1 +1 @@
Subproject commit eda40443bf6215bc8eff7842a5eaaae70b4c4ee3
Subproject commit f49ae1bcb6ade347ed852d7c588c740d595b09aa

View File

@ -21,10 +21,6 @@ namespace danog\MadelineProto;
use Amp\Promise;
if (!\defined('MADELINEPROTO_TEST')) {
\define('MADELINEPROTO_TEST', 'NOT PONY');
}
/**
* Main API wrapper for MadelineProto.
*/

View File

@ -26,7 +26,6 @@ use phpDocumentor\Reflection\DocBlockFactory;
class AnnotationsBuilder
{
use Tools;
public function __construct(Logger $logger, array $settings, string $output, array $reflectionClasses, string $namespace)
{
$this->reflectionClasses = $reflectionClasses;
@ -145,6 +144,8 @@ class AnnotationsBuilder
}
$class = new \ReflectionClass($this->reflectionClasses['MTProto']);
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
$class = new \ReflectionClass(Tools::class);
$methods = \array_merge($methods, $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC));
foreach ($methods as $key => $method) {
$name = $method->getName();
if ($method == 'methodCallAsyncRead') {

View File

@ -25,7 +25,6 @@ use function Amp\Promise\all;
class CombinedAPI
{
use \danog\Serializable;
use Tools;
public $session;
public $instance_paths = [];
public $instances = [];

View File

@ -44,7 +44,6 @@ use danog\MadelineProto\Stream\Transport\WsStream;
class Connection extends Session
{
use \danog\Serializable;
use Tools;
/**
* Writer loop.
*

View File

@ -55,7 +55,7 @@ class ContextConnector implements Connector
$this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
return $result->getSocket();
} catch (\Throwable $e) {
if (\MADELINEPROTO_TEST === 'pony') {
if (\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e;
}
$this->logger->logger('Connection failed: ' . $e, \danog\MadelineProto\Logger::ERROR);

View File

@ -59,7 +59,6 @@ use danog\MadelineProto\Stream\Transport\WsStream;
*/
class DataCenter
{
use \danog\MadelineProto\Tools;
use \danog\Serializable;
/**
* All socket connections to DCs.
@ -265,7 +264,7 @@ class DataCenter
$this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
return true;
} catch (\Throwable $e) {
if (\MADELINEPROTO_TEST === 'pony') {
if (\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e;
}
$this->API->logger->logger("Connection failed ({$dc_number}): ".$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
@ -489,7 +488,7 @@ class DataCenter
if (empty($ctxs)) {
unset($this->sockets[$dc_number]);
$this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR);
} elseif (\MADELINEPROTO_TEST === 'pony') {
} elseif (\constant("MADELINEPROTO_TEST") === 'pony') {
return [$ctxs[0]];
}
return $ctxs;

View File

@ -26,7 +26,6 @@ class DocsBuilder
{
use \danog\MadelineProto\DocsBuilder\Methods;
use \danog\MadelineProto\DocsBuilder\Constructors;
use Tools;
public $td = false;
public function __construct($logger, $settings)
{

View File

@ -22,7 +22,6 @@ 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.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace:'.PHP_EOL.$this->getTLTrace();
@ -48,9 +47,6 @@ class Exception extends \Exception
if (\strpos($message, 'pg_query') !== false || \strpos($message, 'Undefined variable: ') !== false || \strpos($message, 'socket_write') !== false || \strpos($message, 'socket_read') !== false || \strpos($message, 'Received request to switch to DC ') !== false || \strpos($message, "Couldn't get response") !== false || \strpos($message, 'Re-executing query...') !== false || \strpos($message, "Couldn't find peer by provided") !== false || \strpos($message, 'id.pwrtelegram.xyz') !== false || \strpos($message, 'Please update ') !== false || \strpos($message, 'posix_isatty') !== false) {
return;
}
if (self::$rollbar && \class_exists('\\Rollbar\\Rollbar')) {
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0));
}
}
/**
* Complain about missing extensions.

View File

@ -29,7 +29,6 @@ use function Amp\ByteStream\getStdout;
*/
class Logger
{
use Tools;
const FOREGROUND = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97];
const BACKGROUND = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107];
const SET = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6];
@ -123,12 +122,6 @@ class Logger
*/
public static function getLoggerFromSettings(array $settings, string $prefix = ''): self
{
if (isset($settings['logger']['rollbar_token']) && $settings['logger']['rollbar_token'] !== '' && \class_exists(\Rollbar\Rollbar::class)) {
@\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($settings['logger']['rollbar_token']) && !\in_array($settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $settings['pwr']['pwr'] ? $settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false);
} else {
Exception::$rollbar = false;
RPCErrorException::$rollbar = false;
}
if (!isset($settings['logger']['logger_param']) && isset($settings['logger']['param'])) {
$settings['logger']['logger_param'] = $settings['logger']['param'];
}
@ -264,9 +257,6 @@ class Logger
return;
}
$prefix = $this->prefix;
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {
$prefix .= ' (t)';
}
if ($param instanceof \Throwable) {
$param = (string) $param;
} elseif (!\is_string($param)) {

View File

@ -26,7 +26,6 @@ use Amp\Websocket\ClosedException;
use danog\MadelineProto\Connection;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\SignalLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\NothingInTheSocketException;
use danog\MadelineProto\Tools;
@ -37,8 +36,6 @@ use danog\MadelineProto\Tools;
*/
class ReadLoop extends SignalLoop
{
use Tools;
use Crypt;
/**
* Connection instance.
*
@ -140,14 +137,14 @@ class ReadLoop extends SignalLoop
$API->logger->logger($e->getReason());
if (\strpos($e->getReason(), ' ') === 0) {
$payload = -\substr($e->getReason(), 7);
$API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ERROR);
$API->logger->logger("Received {$payload} from DC ".$datacenter, \danog\MadelineProto\Logger::ERROR);
return $payload;
}
throw $e;
}
if ($payload_length === 4) {
$payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4));
$API->logger->logger("Received {$payload} from DC " . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$API->logger->logger("Received {$payload} from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
return $payload;
}
$connection->reading(true);
@ -210,7 +207,7 @@ class ReadLoop extends SignalLoop
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($shared->getTempAuthKey()->getAuthKey(), 96, 32) . $decrypted_data, true), 8, 16)) {
if ($message_key != \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 96, 32).$decrypted_data, true), 8, 16)) {
throw new \danog\MadelineProto\SecurityException('msg_key mismatch');
}
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
@ -224,7 +221,7 @@ class ReadLoop extends SignalLoop
$connection->incoming_messages[$message_id]['response'] = -1;
$connection->new_incoming[$message_id] = $message_id;
//$connection->last_http_wait = 0;
$API->logger->logger('Received payload from DC ' . $datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} finally {
$connection->reading(false);
}

View File

@ -23,7 +23,6 @@ use Amp\ByteStream\StreamException;
use danog\MadelineProto\Connection;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\Tools;
/**
@ -33,8 +32,6 @@ use danog\MadelineProto\Tools;
*/
class WriteLoop extends ResumableSignalLoop
{
use Crypt;
use Tools;
/**
* Connection instance.
*
@ -128,7 +125,7 @@ class WriteLoop extends ResumableSignalLoop
$pad_length += 16 * \danog\MadelineProto\Tools::randomInt($modulus = 16);
$pad = \danog\MadelineProto\Tools::random($pad_length);
$buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length);
yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0" . $message_id . \danog\MadelineProto\Tools::packUnsignedInt($length) . $message['serialized_body'] . $pad);
yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0".$message_id.\danog\MadelineProto\Tools::packUnsignedInt($length).$message['serialized_body'].$pad);
//var_dump("plain ".bin2hex($message_id));
$connection->httpSent();
$connection->outgoing_messages[$message_id] = $message;
@ -280,15 +277,15 @@ class WriteLoop extends ResumableSignalLoop
return true;
}
unset($messages);
$plaintext = $shared->getTempAuthKey()->getServerSalt() . $connection->session_id . $message_id . \pack('VV', $seq_no, $message_data_length) . $message_data;
$plaintext = $shared->getTempAuthKey()->getServerSalt().$connection->session_id.$message_id.\pack('VV', $seq_no, $message_data_length).$message_data;
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($plaintext), 16);
if ($padding < 12) {
$padding += 16;
}
$padding = \danog\MadelineProto\Tools::random($padding);
$message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32) . $plaintext . $padding, true), 8, 16);
$message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32).$plaintext.$padding, true), 8, 16);
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey());
$message = $shared->getTempAuthKey()->getID() . $message_key . $this->igeEncrypt($plaintext . $padding, $aes_key, $aes_iv);
$message = $shared->getTempAuthKey()->getID().$message_key.$this->igeEncrypt($plaintext.$padding, $aes_key, $aes_iv);
$buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message));
//$t = \microtime(true);
yield $buffer->bufferWrite($message);

View File

@ -32,7 +32,6 @@ use danog\MadelineProto\Loop\LoopInterface;
*/
abstract class Loop implements LoopInterface
{
use \danog\MadelineProto\Tools;
private $count = 0;
/**
* MTProto instance.

View File

@ -24,7 +24,6 @@ use Amp\Loop;
use Amp\Promise;
use Amp\Success;
use danog\MadelineProto\Loop\ResumableLoopInterface;
use danog\MadelineProto\Tools;
/**
* Resumable signal loop helper trait.
@ -33,7 +32,6 @@ use danog\MadelineProto\Tools;
*/
abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopInterface
{
use Tools;
private $resume;
private $pause;
protected $resumeWatcher;

View File

@ -29,7 +29,6 @@ use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
*/
class FeedLoop extends ResumableSignalLoop
{
use \danog\MadelineProto\Tools;
private $incomingUpdates = [];
private $parsedUpdates = [];
private $channelId;

View File

@ -28,7 +28,6 @@ use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
*/
class SeqLoop extends ResumableSignalLoop
{
use \danog\MadelineProto\Tools;
private $incomingUpdates = [];
private $feeder;
private $pendingWakeups = [];

View File

@ -31,7 +31,6 @@ use danog\MadelineProto\RPCErrorException;
*/
class UpdateLoop extends ResumableSignalLoop
{
use \danog\MadelineProto\Tools;
private $toPts;
private $channelId;
private $feeder;

View File

@ -42,6 +42,9 @@ class Lua
}
public function __wakeup()
{
if (!\class_exists(\Lua::class)) {
throw Exception::extension('lua');
}
$this->Lua = new \Lua($this->script);
$this->madelineproto_lua = 1;
$this->Lua->registerCallback('tdcliFunction', [$this, 'tdcliFunction']);

View File

@ -46,7 +46,6 @@ class MTProto extends AsyncConstruct implements TLCallback
use \danog\Serializable;
use \danog\MadelineProto\MTProtoTools\AuthKeyHandler;
use \danog\MadelineProto\MTProtoTools\CallHandler;
use \danog\MadelineProto\MTProtoTools\Crypt;
use \danog\MadelineProto\MTProtoTools\PeerHandler;
use \danog\MadelineProto\MTProtoTools\UpdateHandler;
use \danog\MadelineProto\MTProtoTools\Files;
@ -58,7 +57,6 @@ class MTProto extends AsyncConstruct implements TLCallback
use \danog\MadelineProto\TL\Conversion\BotAPIFiles;
use \danog\MadelineProto\TL\Conversion\Extension;
use \danog\MadelineProto\TL\Conversion\TD;
use \danog\MadelineProto\Tools;
use \danog\MadelineProto\VoIP\AuthKeyHandler;
use \danog\MadelineProto\Wrappers\DialogHandler;
use \danog\MadelineProto\Wrappers\Events;
@ -858,10 +856,6 @@ class MTProto extends AsyncConstruct implements TLCallback
Magic::classExists();
// Setup logger
$this->setupLogger();
// We don't like threads
if (Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {
return;
}
// Setup language
Lang::$current_lang =& Lang::$lang['en'];
if (Lang::$lang[$this->settings['app_info']['lang_code'] ?? 'en'] ?? false) {
@ -1218,7 +1212,6 @@ class MTProto extends AsyncConstruct implements TLCallback
'logger_level' => Logger::VERBOSE,
'max_size' => 100 * 1024 * 1024,
// Logging level, available logging levels are: ULTRA_VERBOSE, VERBOSE, NOTICE, WARNING, ERROR, FATAL_ERROR. Can be provided as last parameter to the logging function.
'rollbar_token' => '',
], 'max_tries' => [
'query' => 5,
// How many times should I try to call a method or send an object before throwing an exception

View File

@ -50,13 +50,12 @@ trait CallHandler
foreach ($message_ids as $message_id) {
if (isset($this->outgoing_messages[$message_id]['body'])) {
if ($datacenter) {
$res = Tools::call($this->API->datacenter->waitGetConnection($datacenter))->onResolve(function ($e, $r) use ($message_id) {
return $r->sendMessage($this->outgoing_messages[$message_id], false);
Tools::call($this->API->datacenter->waitGetConnection($datacenter))->onResolve(function ($e, $r) use ($message_id) {
Tools::callFork($r->sendMessage($this->outgoing_messages[$message_id], false));
});
} else {
$res = $this->sendMessage($this->outgoing_messages[$message_id], false);
Tools::callFork($this->sendMessage($this->outgoing_messages[$message_id], false));
}
\danog\MadelineProto\Tools::callFork($res);
$this->ackOutgoingMessageId($message_id);
$this->gotResponseForOutgoingMessageId($message_id);
} else {

View File

@ -20,6 +20,7 @@
namespace danog\MadelineProto\MTProtoSession\MsgIdHandler;
use danog\MadelineProto\MTProtoSession\MsgIdHandler;
use tgseclib\Math\BigInteger;
/**
* Manages message ids.
@ -48,13 +49,13 @@ class MsgIdHandler32 extends MsgIdHandler
*/
public function checkMessageId($newMessageId, array $aargs): void
{
$newMessageId = \is_object($newMessageId) ? $newMessageId : new \tgseclib\Math\BigInteger(\strrev($newMessageId), 256);
$newMessageId = \is_object($newMessageId) ? $newMessageId : new BigInteger(\strrev($newMessageId), 256);
$minMessageId = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta - 300))->bitwise_leftShift(32);
$minMessageId = (new BigInteger(\time() + $this->session->time_delta - 300))->bitwise_leftShift(32);
if ($minMessageId->compare($newMessageId) > 0) {
$this->session->API->logger->logger('Given message id ('.$newMessageId.') is too old compared to the min value ('.$minMessageId.').', \danog\MadelineProto\Logger::WARNING);
}
$maxMessageId = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta + 30))->bitwise_leftShift(32);
$maxMessageId = (new BigInteger(\time() + $this->session->time_delta + 30))->bitwise_leftShift(32);
if ($maxMessageId->compare($newMessageId) < 0) {
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is too new compared to the max value ('.$maxMessageId.'). Consider syncing your date.');
}
@ -106,7 +107,7 @@ class MsgIdHandler32 extends MsgIdHandler
*/
public function generateMessageId(): string
{
$message_id = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta))->bitwise_leftShift(32);
$message_id = (new BigInteger(\time() + $this->session->time_delta))->bitwise_leftShift(32);
if ($message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
}

View File

@ -42,8 +42,6 @@ trait SeqNoHandler
$type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-';
if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) {
$this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} elseif (isset($seq_no)) {
$this->API->logger->logger('Seqno OK (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
}
}
public function generateInSeqNo($contentRelated)

View File

@ -28,14 +28,59 @@ abstract class Session
use ResponseHandler;
use SeqNoHandler;
use CallHandler;
/**
* Incoming message array.
*
* @var array
*/
public $incoming_messages = [];
/**
* Outgoing message array.
*
* @var array
*/
public $outgoing_messages = [];
/**
* New incoming message ID array.
*
* @var array
*/
public $new_incoming = [];
/**
* New outgoing message ID array.
*
* @var array
*/
public $new_outgoing = [];
/**
* Pending outgoing messages.
*
* @var array
*/
public $pending_outgoing = [];
/**
* Pending outgoing key.
*
* @var string
*/
public $pending_outgoing_key = 'a';
/**
* Time delta with server.
*
* @var integer
*/
public $time_delta = 0;
/**
* Call queue.
*
* @var array
*/
public $call_queue = [];
/**
* Ack queue.
*
* @var array
*/
public $ack_queue = [];
/**
* Message ID handler.

View File

@ -21,9 +21,11 @@ namespace danog\MadelineProto\MTProtoTools;
use Amp\Http\Client\Request;
use danog\MadelineProto\DataCenterConnection;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\MTProto\AuthKey;
use danog\MadelineProto\MTProto\PermAuthKey;
use danog\MadelineProto\MTProto\TempAuthKey;
use danog\PrimeModule;
use tgseclib\Math\BigInteger;
/**
@ -108,69 +110,41 @@ trait AuthKeyHandler
* ***********************************************************************
* Compute p and q
*/
$pq = new \tgseclib\Math\BigInteger((string) $pq_bytes, 256);
$q = new \tgseclib\Math\BigInteger(0);
$p = new \tgseclib\Math\BigInteger(@\danog\PrimeModule::auto_single($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
$pq = (string) new BigInteger((string) $pq_bytes, 256);
foreach ([
'auto_single',
'native_single_cpp',
'python_single_alt',
'python_single',
'native_single',
'wolfram'
] as $method) {
$this->logger->logger("Factorizing with $method");
$q = new BigInteger(0);
try {
if ($method === 'wolfram') {
$p = new BigInteger(yield from $this->wolframSingle($pq));
} else {
$p = new BigInteger(@PrimeModule::$method($pq));
}
} catch (\Throwable $e) {
$this->logger->logger("While factorizing with $method: $e");
}
}
if (!$pq->equals($p->multiply($q))) {
$this->logger->logger('Automatic factorization failed, trying native CPP module', \danog\MadelineProto\Logger::ERROR);
$p = new \tgseclib\Math\BigInteger(@\danog\PrimeModule::native_single_cpp($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
}
}
if (!$pq->equals($p->multiply($q))) {
$this->logger->logger('Automatic factorization failed, trying alt py module', \danog\MadelineProto\Logger::ERROR);
$p = new \tgseclib\Math\BigInteger(@\danog\PrimeModule::python_single_alt($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
}
}
if (!$pq->equals($p->multiply($q))) {
$this->logger->logger('Automatic factorization failed, trying py module', \danog\MadelineProto\Logger::ERROR);
$p = new \tgseclib\Math\BigInteger(@\danog\PrimeModule::python_single($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
}
}
if (!$pq->equals($p->multiply($q))) {
$this->logger->logger('Automatic factorization failed, trying native module', \danog\MadelineProto\Logger::ERROR);
$p = new \tgseclib\Math\BigInteger(@\danog\PrimeModule::native_single($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
}
}
if (!$pq->equals($p->multiply($q))) {
$this->logger->logger('Automatic factorization failed, trying wolfram module', \danog\MadelineProto\Logger::ERROR);
$p = new \tgseclib\Math\BigInteger(yield from $this->wolframSingle($pq->__toString()));
if (!$p->equals(\danog\MadelineProto\Magic::$zero)) {
$q = $pq->divide($p)[0];
if ($p->compare($q) > 0) {
list($p, $q) = [$q, $p];
}
}
if (!$pq->equals($p->multiply($q))) {
throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: " . $p->multiply($q));
}
}
}
}
if ($pq->equals($p->multiply($q))) {
break;
}
}
$this->logger->logger('Factorization ' . $pq . ' = ' . $p . ' * ' . $q, \danog\MadelineProto\Logger::VERBOSE);
if (!$pq->equals($p->multiply($q))) {
throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: ".$p->multiply($q));
}
$this->logger->logger('Factorization '.$pq.' = '.$p.' * '.$q, \danog\MadelineProto\Logger::VERBOSE);
/*
* ***********************************************************************
* Serialize object for req_DH_params
@ -178,7 +152,7 @@ trait AuthKeyHandler
$p_bytes = $p->toBytes();
$q_bytes = $q->toBytes();
$new_nonce = \danog\MadelineProto\Tools::random(32);
$data_unserialized = ['_' => 'p_q_inner_data' . ($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)];
$data_unserialized = ['_' => 'p_q_inner_data'.($expires_in < 0 ? '' : '_temp'), 'pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => \preg_replace('|_.*|', '', $datacenter)];
$p_q_inner_data = (yield from $this->TL->serializeObject(['type' => ''], $data_unserialized, 'p_q_inner_data'));
/*
* ***********************************************************************
@ -186,7 +160,7 @@ trait AuthKeyHandler
*/
$sha_digest = \sha1($p_q_inner_data, true);
$random_bytes = \danog\MadelineProto\Tools::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);
$this->logger->logger('Starting Diffie Hellman key exchange', \danog\MadelineProto\Logger::VERBOSE);
/*
@ -237,8 +211,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->igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv);
/*
* ***********************************************************************
@ -273,9 +247,9 @@ trait AuthKeyHandler
if ($server_nonce != $server_DH_inner_data['server_nonce']) {
throw new \danog\MadelineProto\SecurityException('wrong server nonce');
}
$g = new \tgseclib\Math\BigInteger($server_DH_inner_data['g']);
$g_a = new \tgseclib\Math\BigInteger((string) $server_DH_inner_data['g_a'], 256);
$dh_prime = new \tgseclib\Math\BigInteger((string) $server_DH_inner_data['dh_prime'], 256);
$g = new BigInteger($server_DH_inner_data['g']);
$g_a = new BigInteger((string) $server_DH_inner_data['g_a'], 256);
$dh_prime = new BigInteger((string) $server_DH_inner_data['dh_prime'], 256);
/*
* ***********************************************************************
* Time delta
@ -287,7 +261,7 @@ trait AuthKeyHandler
$this->checkG($g_a, $dh_prime);
for ($retry_id = 0; $retry_id <= $this->settings['max_tries']['authorization']; $retry_id++) {
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$b = new BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$this->logger->logger('Generating g_b...', \danog\MadelineProto\Logger::VERBOSE);
$g_b = $g->powMod($b, $dh_prime);
$this->checkG($g_b, $dh_prime);
@ -318,8 +292,8 @@ trait AuthKeyHandler
* ***********************************************************************
* encrypt client_DH_inner_data
*/
$data_with_sha = \sha1($data, true) . $data;
$data_with_sha_padded = $data_with_sha . \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16));
$data_with_sha = \sha1($data, true).$data;
$data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16));
$encrypted_data = $this->igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
$this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE);
/*
@ -349,9 +323,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
@ -403,14 +377,14 @@ trait AuthKeyHandler
}
}
} catch (\danog\MadelineProto\SecurityException $e) {
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('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) {
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' in ' . \basename($e->getFile(), '.php') . ' on line ' . $e->getLine() . '. Retrying...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('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) {
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
} catch (\Throwable $e) {
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e . PHP_EOL . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('An exception occurred while generating the authorization key: '.$e.PHP_EOL.' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
}
}
if (!$cdn) {
@ -512,8 +486,8 @@ trait AuthKeyHandler
$this->logger->logger('DH configuration not modified', \danog\MadelineProto\Logger::VERBOSE);
return $this->dh_config;
}
$dh_config['p'] = new \tgseclib\Math\BigInteger((string) $dh_config['p'], 256);
$dh_config['g'] = new \tgseclib\Math\BigInteger($dh_config['g']);
$dh_config['p'] = new BigInteger((string) $dh_config['p'], 256);
$dh_config['g'] = new BigInteger($dh_config['g']);
$this->checkPG($dh_config['p'], $dh_config['g']);
return $this->dh_config = $dh_config;
}
@ -542,24 +516,24 @@ trait AuthKeyHandler
$message_data = (yield from $this->TL->serializeObject(['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], 'bindTempAuthKey_inner'));
$message_id = $connection->msgIdHandler->generateMessageId();
$seq_no = 0;
$encrypted_data = \danog\MadelineProto\Tools::random(16) . $message_id . \pack('VV', $seq_no, \strlen($message_data)) . $message_data;
$encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\pack('VV', $seq_no, \strlen($message_data)).$message_data;
$message_key = \substr(\sha1($encrypted_data, true), -16);
$padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16));
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey());
$encrypted_message = $datacenterConnection->getPermAuthKey()->getID() . $message_key . $this->igeEncrypt($encrypted_data . $padding, $aes_key, $aes_iv);
$encrypted_message = $datacenterConnection->getPermAuthKey()->getID().$message_key.$this->igeEncrypt($encrypted_data.$padding, $aes_key, $aes_iv);
$res = yield from $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]);
if ($res === true) {
$this->logger->logger('Bound temporary and permanent authorization keys, DC ' . $datacenter, \danog\MadelineProto\Logger::NOTICE);
$this->logger->logger('Bound temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE);
$datacenterConnection->bind();
$datacenterConnection->flush();
return true;
}
} catch (\danog\MadelineProto\SecurityException $e) {
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('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) {
$this->logger->logger('An exception occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('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) {
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: ' . $e->getMessage() . ' Retrying (try number ' . $retry_id_total . ')...', \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING);
}
}
throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.');
@ -574,11 +548,11 @@ trait AuthKeyHandler
private function wolframSingle($what): \Generator
{
$code = (yield from $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code'));
$query = 'Do prime factorization of ' . $what;
$query = 'Do prime factorization of '.$what;
$params = ['async' => true, 'banners' => 'raw', 'debuggingdata' => false, 'format' => 'moutput', 'formattimeout' => 8, 'input' => $query, 'output' => 'JSON', 'proxycode' => \json_decode($code, true)['code']];
$url = 'https://www.wolframalpha.com/input/json.jsp?' . \http_build_query($params);
$url = 'https://www.wolframalpha.com/input/json.jsp?'.\http_build_query($params);
$request = new Request($url);
$request->setHeader('referer', 'https://www.wolframalpha.com/input/?i=' . \urlencode($query));
$request->setHeader('referer', 'https://www.wolframalpha.com/input/?i='.\urlencode($query));
$res = \json_decode(yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(), true);
if (!isset($res['queryresult']['pods'])) {
return false;
@ -737,22 +711,22 @@ trait AuthKeyHandler
return false;
}
$socket = $this->datacenter->getDataCenterConnection($id);
if ($this->authorized === self::LOGGED_IN && !$socket->isAuthorized()) {
if ($this->authorized === MTProto::LOGGED_IN && !$socket->isAuthorized()) {
foreach ($this->datacenter->getDataCenterConnections() as $authorized_dc_id => $authorized_socket) {
if ($this->authorized_dc !== -1 && $authorized_dc_id !== $this->authorized_dc) {
continue;
}
if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === self::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) {
if ($authorized_socket->hasTempAuthKey() && $authorized_socket->hasPermAuthKey() && $authorized_socket->isAuthorized() && $this->authorized === MTProto::LOGGED_IN && !$socket->isAuthorized() && !$authorized_socket->isCDN()) {
try {
$this->logger->logger('Trying to copy authorization from dc ' . $authorized_dc_id . ' to dc ' . $id);
$this->logger->logger('Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id);
$exported_authorization = yield from $this->methodCallAsyncRead('auth.exportAuthorization', ['dc_id' => \preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]);
$authorization = yield from $this->methodCallAsyncRead('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]);
$socket->authorized(true);
break;
} catch (\danog\MadelineProto\Exception $e) {
$this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
$this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger->logger('Failure while syncing authorization from DC ' . $authorized_dc_id . ' to DC ' . $id . ': ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
$this->logger->logger('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;
}

View File

@ -19,7 +19,7 @@
namespace danog\MadelineProto\MTProtoTools;
trait Crypt
abstract class Crypt
{
/**
* AES KDF function for MTProto v2.
@ -35,10 +35,10 @@ trait Crypt
public static function aesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
{
$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];
}
/**
@ -55,12 +55,12 @@ trait Crypt
public static function oldAesCalculate(string $msg_key, string $auth_key, bool $to_server = true): array
{
$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];
}
/**

View File

@ -44,6 +44,7 @@ use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream;
use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\Transport\PremadeStream;
use danog\MadelineProto\Tools;
use tgseclib\Crypt\AES;
use const danog\Decoder\TYPES;
@ -744,7 +745,7 @@ trait Files
return $res;
// Wallpapers
case 'wallPaper':
return $this->getDownloadInfo($res['document']);
return $this->getDownloadInfo($messageMedia['document']);
// Photos
case 'photo':
case 'messageMediaPhoto':
@ -1204,7 +1205,7 @@ trait Files
if ($fingerprint !== $messageMedia['key_fingerprint']) {
throw new \danog\MadelineProto\Exception('Fingerprint mismatch!');
}
$ige = new \tgseclib\Crypt\AES('ige');
$ige = new AES('ige');
$ige->setIV($messageMedia['iv']);
$ige->setKey($messageMedia['key']);
$ige->enableContinuousBuffer();

View File

@ -21,14 +21,12 @@ namespace danog\MadelineProto\MTProtoTools;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\TL\TLCallback;
use danog\MadelineProto\Tools;
/**
* Manages min peers.
*/
class MinDatabase implements TLCallback
{
use Tools;
const SWITCH_CONSTRUCTORS = ['inputChannel', 'inputUser', 'inputPeerUser', 'inputPeerChannel'];
const CATCH_PEERS = ['message', 'messageService', 'peerUser', 'peerChannel', 'messageEntityMentionName', 'messageFwdHeader', 'messageActionChatCreate', 'messageActionChatAddUser', 'messageActionChatDeleteUser', 'messageActionChatJoinedByLink'];
const ORIGINS = ['message', 'messageService'];

View File

@ -22,7 +22,6 @@ namespace danog\MadelineProto\MTProtoTools;
use danog\MadelineProto\Exception;
use danog\MadelineProto\Magic;
use danog\MadelineProto\SecurityException;
use danog\MadelineProto\Tools;
use tgseclib\Math\BigInteger;
/**
@ -34,7 +33,7 @@ use tgseclib\Math\BigInteger;
class PasswordCalculator
{
use AuthKeyHandler;
use Tools;
/**
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
*

View File

@ -188,9 +188,6 @@ trait PeerHandler
}
}
break;
default:
throw new \danog\MadelineProto\Exception('Invalid chat provided at key ' . $key . ': ' . \var_export($chat, true));
break;
}
}
private function cachePwrChat($id, $full_fetch, $send)
@ -199,9 +196,9 @@ trait PeerHandler
try {
yield from $this->getPwrChat($id, $full_fetch, $send);
} catch (\danog\MadelineProto\Exception $e) {
$this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger->logger('While caching: ' . $e->getMessage(), \danog\MadelineProto\Logger::WARNING);
$this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
}
})());
}
@ -409,7 +406,7 @@ trait PeerHandler
case 'updateEditChannelMessage':
return $this->getId($id['message']);
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));
}
}
if (\is_string($id)) {
@ -418,7 +415,7 @@ trait PeerHandler
return $this->toSupergroup($matches[1]);
}
if (\preg_match('/^chat#(\\d*)/', $id, $matches)) {
$id = '-' . $matches[1];
$id = '-'.$matches[1];
}
if (\preg_match('/^user#(\\d*)/', $id, $matches)) {
return $matches[1];
@ -527,12 +524,12 @@ trait PeerHandler
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) {
$dbres = [];
try {
$dbres = \json_decode(yield from $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id=' . $id), true);
$dbres = \json_decode(yield from $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true);
} catch (\Throwable $e) {
$this->logger->logger($e);
}
if (isset($dbres['ok']) && $dbres['ok']) {
yield from $this->resolveUsername('@' . $dbres['result']);
yield from $this->resolveUsername('@'.$dbres['result']);
return yield from $this->getInfo($id, false);
}
}
@ -646,7 +643,7 @@ trait PeerHandler
case 'channelForbidden':
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
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));
}
if ($folder_id) {
$res['FolderPeer'] = ['_' => 'folderPeer', 'peer' => $res['Peer'], 'folder_id' => $folder_id];
@ -832,7 +829,7 @@ trait PeerHandler
foreach ($filters as $filter) {
yield from $this->recurseAlphabetSearchParticipants($full['InputChannel'], $filter, $q, $total_count, $res);
}
$this->logger->logger('Fetched ' . \count($res['participants']) . " out of {$total_count}");
$this->logger->logger('Fetched '.\count($res['participants'])." out of {$total_count}");
$res['participants'] = \array_values($res['participants']);
}
if (!$fullfetch) {
@ -877,7 +874,7 @@ trait PeerHandler
return false;
}
for ($x = 'a'; $x !== 'aa' && $total_count > \count($res['participants']); $x++) {
yield from $this->recurseAlphabetSearchParticipants($channel, $filter, $q . $x, $total_count, $res);
yield from $this->recurseAlphabetSearchParticipants($channel, $filter, $q.$x, $total_count, $res);
}
}
private function fetchParticipants($channel, $filter, $q, $total_count, &$res): \Generator
@ -925,15 +922,15 @@ trait PeerHandler
if (isset($participant['rank'])) {
$newres['rank'] = $participant['rank'];
}
if (isset($participant['admin_rights'])) {
$newres['admin_rights'] = $participant['admin_rights'];
}
if (isset($participant['banned_rights'])) {
$newres['banned_rights'] = $participant['banned_rights'];
}
switch ($participant['_']) {
case 'channelParticipantSelf':
$newres['role'] = 'user';
if (isset($newres['admin_rights'])) {
$newres['admin_rights'] = $full['Chat']['admin_rights'];
}
if (isset($newres['banned_rights'])) {
$newres['banned_rights'] = $full['Chat']['banned_rights'];
}
break;
case 'channelParticipant':
$newres['role'] = 'user';
@ -950,7 +947,7 @@ trait PeerHandler
}
$res['participants'][$participant['user_id']] = $newres;
}
$this->logger->logger('Fetched ' . \count($gres['participants']) . " channel participants with filter {$filter}, query {$q}, offset {$offset}, limit {$limit}, hash {$hash}: " . ($cached ? 'cached' : 'not cached') . ', ' . ($offset + \count($gres['participants'])) . ' participants out of ' . $gres['count'] . ', in total fetched ' . \count($res['participants']) . ' out of ' . $total_count);
$this->logger->logger('Fetched '.\count($gres['participants'])." channel participants with filter {$filter}, query {$q}, offset {$offset}, limit {$limit}, hash {$hash}: ".($cached ? 'cached' : 'not cached').', '.($offset + \count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.\count($res['participants']).' out of '.$total_count);
$offset += \count($gres['participants']);
} while (\count($gres['participants']));
if ($offset === $limit) {
@ -1002,7 +999,7 @@ trait PeerHandler
//$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'];
$request = new Request('https://id.pwrtelegram.xyz/db' . $this->settings['pwr']['db_token'] . '/addnewmadeline?d=pls&from=' . $id, 'POST');
$request = new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST');
$request->setHeader('content-type', 'application/json');
$request->setBody($payload);
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer();
@ -1010,7 +1007,7 @@ trait PeerHandler
$this->qres = [];
$this->last_stored = \time() + 10;
} catch (\danog\MadelineProto\Exception $e) {
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO ' . $e->getMessage() . ' =============', \danog\MadelineProto\Logger::VERBOSE);
$this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE);
}
}
/**
@ -1026,7 +1023,7 @@ trait PeerHandler
$this->caching_simple_username[$username] = true;
$res = yield from $this->methodCallAsyncRead('contacts.resolveUsername', ['username' => \str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger->logger('Username resolution failed with error ' . $e->getMessage(), \danog\MadelineProto\Logger::ERROR);
$this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') {
throw $e;
}

View File

@ -22,14 +22,13 @@ namespace danog\MadelineProto\MTProtoTools;
use danog\MadelineProto\Exception;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\TL\TLCallback;
use danog\MadelineProto\Tools;
/**
* Manages upload and download of files.
*/
class ReferenceDatabase implements TLCallback
{
use Tools;
// Reference from a document
const DOCUMENT_LOCATION = 0;
// Reference from a photo

View File

@ -25,7 +25,6 @@ use Amp\DoH\Rfc8484StubResolver;
use Amp\Loop;
use Amp\Loop\Driver;
use ReflectionClass;
use function Amp\ByteStream\getInputBufferStream;
use function Amp\ByteStream\getStdin;
use function Amp\Dns\resolver;
use function Amp\Promise\wait;
@ -236,7 +235,7 @@ class Magic
throw Exception::extension($extension);
}
}
self::$has_thread = \class_exists('\\Thread') && \method_exists('\\Thread', 'getCurrentThread');
self::$has_thread = \class_exists(\Thread::class) && \method_exists(\Thread::class, 'getCurrentThread');
self::$BIG_ENDIAN = \pack('L', 1) === \pack('N', 1);
self::$bigint = PHP_INT_SIZE < 8;
self::$ipv6 = (bool) \strlen(@\file_get_contents('http://ipv6.google.com', false, \stream_context_create(['http' => ['timeout' => 1]]))) > 0;
@ -390,10 +389,9 @@ class Magic
public static function shutdown(int $code = 0)
{
self::$signaled = true;
if (\defined(STDIN::class)) {
if (\defined('STDIN')) {
getStdin()->unreference();
}
getInputBufferStream()->unreference();
if ($code !== 0) {
$driver = Loop::get();
$reflectionClass = new ReflectionClass(Driver::class);

View File

@ -27,7 +27,6 @@ use Amp\Http\Client\Request;
*/
class MyTelegramOrgWrapper
{
use Tools;
private $logged = false;
private $hash = '';
private $number;

View File

@ -23,8 +23,7 @@ class RPCErrorException extends \Exception
{
use TL\PrettyException;
private $fetched = false;
public static $rollbar = true;
public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'PHONE_CODE_EXPIRED' => 'The confirmation code has expired', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"];
public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"];
public static $errorMethodMap = [];
private $caller = '';
public static function localizeMessage($method, $code, $error)
@ -69,9 +68,7 @@ class RPCErrorException extends \Exception
$additional = $level['args'];
}
}
if (!self::$rollbar || !\class_exists(\Rollbar\Rollbar::class)) {
return;
}
/*
if (\in_array($this->rpc, ['CHANNEL_PRIVATE', -404, -429, 'USERNAME_NOT_OCCUPIED', 'ACCESS_TOKEN_INVALID', 'AUTH_KEY_UNREGISTERED', 'SESSION_PASSWORD_NEEDED', 'PHONE_NUMBER_UNOCCUPIED', 'PEER_ID_INVALID', 'CHAT_ID_INVALID', 'USERNAME_INVALID', 'CHAT_WRITE_FORBIDDEN', 'CHAT_ADMIN_REQUIRED', 'PEER_FLOOD'])) {
return;
}
@ -79,5 +76,6 @@ class RPCErrorException extends \Exception
return;
}
$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);
*/
}
}

View File

@ -26,7 +26,6 @@ use danog\MadelineProto\TL\TL;
*/
class RSA
{
use \danog\MadelineProto\Tools;
use \danog\Serializable;
/**
* Exponent.

View File

@ -43,7 +43,7 @@ class Serialization
public static function realpaths(string $file): array
{
$file = Absolute::absolute($file);
return ['file' => $file, 'lockfile' => $file . '.lock', 'tempfile' => $file . '.temp.session'];
return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session'];
}
/**
* Unserialize legacy session.
@ -80,7 +80,7 @@ class Serialization
if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) {
throw $e;
}
if (\MADELINEPROTO_TEST === 'pony') {
if (\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e;
}
\class_exists('\\Volatile');

View File

@ -59,7 +59,7 @@ class Shutdown
* @param callable $callback The callback to set
* @param null|string $id The optional callback ID
*
* @return The callback ID
* @return int The callback ID
*/
public static function addCallback($callback, $id = null)
{

View File

@ -109,8 +109,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
*
* @param Promise $promise Promise that resolves with a string when new data is available or `null` if the stream has closed.
*
* @throws PendingReadError Thrown if another read operation is still pending.
*
* @return \Generator That resolves with a string when the provided promise is resolved and the data is decrypted
*/
public function bufferReadGenerator(int $length): \Generator
@ -122,8 +120,6 @@ class CtrStream implements BufferedProxyStreamInterface, BufferInterface
*
* @param string $data Bytes to write.
*
* @throws ClosedException If the stream has already been closed.
*
* @return Promise Succeeds once the data has been successfully written to the stream.
*/
public function bufferWrite(string $data): Promise

View File

@ -140,8 +140,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
*
* @param int $length Read and hash $length bytes
*
* @throws PendingReadError Thrown if another read operation is still pending.
*
* @return \Generator That resolves with a string when the provided promise is resolved and the data is added to the hashing context
*/
public function bufferReadGenerator(int $length): \Generator
@ -241,8 +239,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
/**
* Reads data from the stream.
*
* @throws PendingReadError Thrown if another read operation is still pending.
*
* @return Promise Resolves with a string when new data is available or `null` if the stream has closed.
*/
public function bufferRead(int $length): Promise
@ -257,8 +253,6 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
*
* @param string $data Bytes to write.
*
* @throws ClosedException If the stream has already been closed.
*
* @return Promise Succeeds once the data has been successfully written to the stream.
*/
public function bufferWrite(string $data): Promise

View File

@ -648,10 +648,10 @@ class TL
/**
* Serialize parameters.
*
* @param array $tl TL object definition
* @param arrayLike $arguments Arguments
* @param string $ctx Context
* @param integer $layer Layer
* @param array $tl TL object definition
* @param array $arguments Arguments
* @param string $ctx Context
* @param integer $layer Layer
*
* @return \Generator<string>
*/

View File

@ -22,7 +22,6 @@ namespace danog\MadelineProto\TL;
class TLConstructors
{
use \danog\Serializable;
use \danog\MadelineProto\Tools;
use TLParams;
public $by_id = [];
public $by_predicate_and_layer = [];
@ -36,8 +35,8 @@ class TLConstructors
if (isset($this->by_id[$json_dict['id']]) && (!isset($this->by_id[$json_dict['id']]['layer']) || $this->by_id[$json_dict['id']]['layer'] > $json_dict['layer'])) {
return false;
}
$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'];
@ -45,7 +44,7 @@ class TLConstructors
} 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->parseParams($json_dict['id'], $scheme_type === 'mtproto');
}
public function findByType($type)
@ -61,13 +60,14 @@ class TLConstructors
public function findByPredicate($predicate, $layer = -1)
{
if ($layer !== -1) {
$chosenid = null;
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)) {

View File

@ -22,7 +22,6 @@ namespace danog\MadelineProto\TL;
class TLMethods
{
use \danog\Serializable;
use \danog\MadelineProto\Tools;
use TLParams;
public $by_id = [];
public $by_method = [];

View File

@ -41,7 +41,7 @@ use function Amp\Promise\wait;
/**
* Some tools.
*/
trait Tools
abstract class Tools
{
/**
* Sanify TL obtained from JSON for TL serialization.
@ -614,7 +614,7 @@ trait Tools
/**
* Check if is array or similar (traversable && countable && arrayAccess).
*
* @param arraylike $var Value to check
* @param mixed $var Value to check
*
* @return boolean
*/

View File

@ -26,7 +26,7 @@ trait DialogHandler
*
* @param boolean $force Whether to refetch all dialogs ignoring cache
*
* @return \Generator<array<Peer>>
* @return \Generator<array<array>>
*/
public function getDialogs(bool $force = true): \Generator
{