More type improvements

This commit is contained in:
Daniil Gentili 2020-10-03 15:36:03 +02:00
parent 4f69701cfc
commit 118cf244b1
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
22 changed files with 178 additions and 127 deletions

View File

@ -51,7 +51,7 @@ abstract class AbstractAPIFactory extends AsyncConstruct
/**
* Method list.
*
* @var string[]
* @var array<string, callable>
*/
protected array $methods = [];

View File

@ -56,6 +56,7 @@ class AnnotationsBuilder
$this->reflectionClasses = $reflectionClasses;
$this->logger = $logger;
$this->namespace = $namespace;
/** @psalm-suppress InvalidArgument */
$this->TL = new TL(new class($logger) {
public function __construct($logger)
{

View File

@ -157,8 +157,9 @@ class DoHConnector implements Connector
// This is reached if either all URIs failed or the maximum number of attempts is reached.
/** @noinspection PhpUndefinedVariableInspection */
throw $e;
if ($e) {
throw $e;
}
})());
}
}

View File

@ -39,10 +39,16 @@ class DocsBuilder
use \danog\MadelineProto\DocsBuilder\Methods;
use \danog\MadelineProto\DocsBuilder\Constructors;
public $td = false;
public function __construct($logger, $settings)
protected array $settings;
protected string $index;
protected Logger $logger;
protected TL $TL;
protected array $tdDescriptions;
public function __construct(Logger $logger, array $settings)
{
$this->logger = $logger;
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
/** @psalm-suppress InvalidArgument */
$this->TL = new TL(new class($logger) {
public function __construct($logger)
{
@ -119,8 +125,8 @@ class DocsBuilder
}
}
}
if (isset($this->td_descriptions['types'][$otype])) {
$header = "{$this->td_descriptions['types'][$otype]}\n\n$header";
if (isset($this->tdDescriptions['types'][$otype])) {
$header = "{$this->tdDescriptions['types'][$otype]}\n\n$header";
}
$header = \sprintf(
$this->templates['Type'],

View File

@ -84,22 +84,22 @@ trait Methods
$param[$type_or_subtype] = '['.StrTools::markdownEscape($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]).', ';
}
if (!isset($this->td_descriptions['methods'][$method])) {
if (!isset($this->tdDescriptions['methods'][$method])) {
$this->addToLang('method_'.$method);
if (\danog\MadelineProto\Lang::$lang['en']['method_'.$method] !== '') {
$this->td_descriptions['methods'][$method]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$method];
$this->tdDescriptions['methods'][$method]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$method];
}
}
$md_method = '['.$phpMethod.']('.$method.'.md)';
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.StrTools::markdownEscape($type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
';
if (isset($this->td_descriptions['methods'][$method])) {
$desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->td_descriptions['methods'][$method]['description'])[0], '.'));
if (isset($this->tdDescriptions['methods'][$method])) {
$desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->tdDescriptions['methods'][$method]['description'])[0], '.'));
$dom = new \DOMDocument();
$dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8'));
$desc = $dom->textContent;
$this->human_docs_methods[$this->td_descriptions['methods'][$method]['description'].': '.$method] = '* <a href="'.$method.'.html" name="'.$method.'">'.$desc.': '.$method.'</a>
$this->human_docs_methods[$this->tdDescriptions['methods'][$method]['description'].': '.$method] = '* <a href="'.$method.'.html" name="'.$method.'">'.$desc.': '.$method.'</a>
';
}
@ -112,7 +112,7 @@ trait Methods
| Name | Type | Required |
|----------|---------------|----------|
';
if (isset($this->td_descriptions['methods'][$method]) && !empty($data['params'])) {
if (isset($this->tdDescriptions['methods'][$method]) && !empty($data['params'])) {
$table = '### Parameters:
| Name | Type | Description | Required |
@ -164,13 +164,13 @@ trait Methods
$human_ptype = 'File path or '.$ptype;
}
$type_or_bare_type = \ctype_upper(Tools::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';
if (!isset($this->td_descriptions['methods'][$method]['params'][$param['name']])) {
if (isset($this->td_descriptions['methods'][$method]['description'])) {
$this->td_descriptions['methods'][$method]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$method.'_param_'.$param['name'].'_type_'.$param['type']] ?? '';
if (!isset($this->tdDescriptions['methods'][$method]['params'][$param['name']])) {
if (isset($this->tdDescriptions['methods'][$method]['description'])) {
$this->tdDescriptions['methods'][$method]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$method.'_param_'.$param['name'].'_type_'.$param['type']] ?? '';
}
}
if (isset($this->td_descriptions['methods'][$method])) {
$table .= '|'.StrTools::markdownEscape($param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.StrTools::markdownEscape($human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$method]['params'][$param['name']].' | '.(isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes').'|';
if (isset($this->tdDescriptions['methods'][$method])) {
$table .= '|'.StrTools::markdownEscape($param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.StrTools::markdownEscape($human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->tdDescriptions['methods'][$method]['params'][$param['name']].' | '.(isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes').'|';
} else {
$table .= '|'.StrTools::markdownEscape($param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.StrTools::markdownEscape($human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes').'|';
}
@ -200,7 +200,7 @@ trait Methods
$pwr_params = "parseMode - string\n";
}
}
$description = isset($this->td_descriptions['methods'][$method]) ? $this->td_descriptions['methods'][$method]['description'] : $method.' parameters, return type and example';
$description = isset($this->tdDescriptions['methods'][$method]) ? $this->tdDescriptions['methods'][$method]['description'] : $method.' parameters, return type and example';
$symFile = \str_replace('.', '_', $method);
$redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : '';
$description = \rtrim(\explode("\n", $description)[0], ':');
@ -208,7 +208,7 @@ trait Methods
if ($this->td) {
$header .= "YOU CANNOT USE THIS METHOD IN MADELINEPROTO\n\n\n\n\n";
}
$header .= isset($this->td_descriptions['methods'][$method]) ? $this->td_descriptions['methods'][$method]['description'].PHP_EOL.PHP_EOL : '';
$header .= isset($this->tdDescriptions['methods'][$method]) ? $this->tdDescriptions['methods'][$method]['description'].PHP_EOL.PHP_EOL : '';
$table .= '
';

View File

@ -3,6 +3,7 @@
namespace danog\MadelineProto\Ipc\Wrapper;
use Amp\ByteStream\InputStream as AmpInputStream;
use Amp\ByteStream\PendingReadError;
use Amp\Promise;
use danog\MadelineProto\Tools;

View File

@ -36,7 +36,7 @@ class Obj
* @param string $name
* @param array $arguments
*
* @return \Generator
* @return \Generator<mixed, mixed, mixed, mixed>
*/
public function __call(string $name, array $arguments = []): \Generator
{

View File

@ -2,7 +2,9 @@
namespace danog\MadelineProto\Ipc\Wrapper;
use Amp\ByteStream\ClosedException;
use Amp\ByteStream\OutputStream as AmpOutputStream;
use Amp\ByteStream\StreamException;
use Amp\Promise;
use danog\MadelineProto\Tools;

View File

@ -22,6 +22,7 @@ namespace danog\MadelineProto\Loop\Update;
use danog\Loop\ResumableSignalLoop;
use danog\MadelineProto\Loop\InternalLoop;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\MTProtoTools\UpdatesState;
/**
* Update feed loop.
@ -55,6 +56,10 @@ class FeedLoop extends ResumableSignalLoop
* @var UpdateLoop
*/
private ?UpdateLoop $updater = null;
/**
* Update state
*/
private ?UpdatesState $state = null;
/**
* Constructor.
*

View File

@ -267,14 +267,14 @@ trait AuthKeyHandler
$server_time = $server_DH_inner_data['server_time'];
$connection->time_delta = $server_time - \time();
$this->logger->logger(\sprintf('Server-client time delta = %.1f s', $connection->time_delta), \danog\MadelineProto\Logger::VERBOSE);
$this->checkPG($dh_prime, $g);
$this->checkG($g_a, $dh_prime);
Crypt::checkPG($dh_prime, $g);
Crypt::checkG($g_a, $dh_prime);
for ($retry_id = 0; $retry_id <= $this->settings->getAuth()->getMaxAuthTries(); $retry_id++) {
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$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);
Crypt::checkG($g_b, $dh_prime);
/*
* ***********************************************************************
* Check validity of g_b
@ -401,87 +401,6 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\SecurityException('Auth Failed');
}
}
/**
* Check validity of g_a parameters.
*
* @param BigInteger $g_a
* @param BigInteger $p
*
* @internal
*
* @return bool
*/
public function checkG(BigInteger $g_a, BigInteger $p): bool
{
/*
* ***********************************************************************
* Check validity of g_a
* 1 < g_a < p - 1
*/
$this->logger->logger('Executing g_a check (1/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($g_a->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g_a is invalid (1 < g_a < p - 1 is false).');
}
$this->logger->logger('Executing g_a check (2/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).');
}
return true;
}
/**
* Check validity of p and g parameters.
*
* @param BigInteger $p
* @param BigInteger $g
*
* @internal
*
* @return boolean
*/
public function checkPG(BigInteger $p, BigInteger $g): bool
{
/*
* ***********************************************************************
* Check validity of dh_prime
* Is it a prime?
*/
$this->logger->logger('Executing p/g checks (1/2)...', \danog\MadelineProto\Logger::VERBOSE);
if (!$p->isPrime()) {
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime (p isn't a prime).");
}
/*
* ***********************************************************************
* Check validity of p
* Is (p - 1) / 2 a prime?
*
* Almost always fails
*/
/*
$this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE);
if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) {
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime).");
}
*/
/*
* ***********************************************************************
* Check validity of p
* 2^2047 < p < 2^2048
*/
$this->logger->logger('Executing p/g checks (2/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($p->compare(\danog\MadelineProto\Magic::$twoe2047) <= 0 || $p->compare(\danog\MadelineProto\Magic::$twoe2048) >= 0) {
throw new \danog\MadelineProto\SecurityException("g isn't a safe 2048-bit prime (2^2047 < p < 2^2048 is false).");
}
/*
* ***********************************************************************
* Check validity of g
* 1 < g < p - 1
*/
$this->logger->logger('Executing g check...', \danog\MadelineProto\Logger::VERBOSE);
if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
}
return true;
}
/**
* Get diffie-hellman configuration.
*
@ -498,7 +417,7 @@ trait AuthKeyHandler
}
$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']);
Crypt::checkPG($dh_config['p'], $dh_config['g']);
return $this->dh_config = $dh_config;
}
/**

View File

@ -19,6 +19,9 @@
namespace danog\MadelineProto\MTProtoTools;
use danog\MadelineProto\Logger;
use tgseclib\Math\BigInteger;
abstract class Crypt
{
/**
@ -117,4 +120,85 @@ abstract class Crypt
$cipher->setIV($iv);
return @$cipher->decrypt($message);
}
/**
* Check validity of g_a parameters.
*
* @param BigInteger $g_a
* @param BigInteger $p
*
* @internal
*
* @return bool
*/
public static function checkG(BigInteger $g_a, BigInteger $p): bool
{
/*
* ***********************************************************************
* Check validity of g_a
* 1 < g_a < p - 1
*/
Logger::log('Executing g_a check (1/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($g_a->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g_a is invalid (1 < g_a < p - 1 is false).');
}
Logger::log('Executing g_a check (2/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).');
}
return true;
}
/**
* Check validity of p and g parameters.
*
* @param BigInteger $p
* @param BigInteger $g
*
* @internal
*
* @return boolean
*/
public static function checkPG(BigInteger $p, BigInteger $g): bool
{
/*
* ***********************************************************************
* Check validity of dh_prime
* Is it a prime?
*/
Logger::log('Executing p/g checks (1/2)...', \danog\MadelineProto\Logger::VERBOSE);
if (!$p->isPrime()) {
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime (p isn't a prime).");
}
/*
* ***********************************************************************
* Check validity of p
* Is (p - 1) / 2 a prime?
*
* Almost always fails
*/
/*
$this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE);
if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) {
throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime).");
}
*/
/*
* ***********************************************************************
* Check validity of p
* 2^2047 < p < 2^2048
*/
Logger::log('Executing p/g checks (2/2)...', \danog\MadelineProto\Logger::VERBOSE);
if ($p->compare(\danog\MadelineProto\Magic::$twoe2047) <= 0 || $p->compare(\danog\MadelineProto\Magic::$twoe2048) >= 0) {
throw new \danog\MadelineProto\SecurityException("g isn't a safe 2048-bit prime (2^2047 < p < 2^2048 is false).");
}
/*
* ***********************************************************************
* Check validity of g
* 1 < g < p - 1
*/
Logger::log('Executing g check...', \danog\MadelineProto\Logger::VERBOSE);
if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) {
throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).');
}
return true;
}
}

View File

@ -19,6 +19,8 @@ use Amp\Http\Status;
use Amp\Producer;
use danog\MadelineProto\Exception;
use danog\MadelineProto\FileCallbackInterface;
use danog\MadelineProto\Ipc\Client;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Stream\Common\BufferedRawStream;
use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream;
use danog\MadelineProto\Stream\ConnectionContext;
@ -225,7 +227,9 @@ trait FilesLogic
if (\is_resource($file) || (\is_object($file) && $file instanceof InputStream)) {
return yield from $this->uploadFromStream($file, 0, '', $fileName, $cb, $encrypted);
}
if (!$this->settings->getFiles()->getAllowAutomaticUpload()) {
/** @var Settings */
$settings = $this instanceof Client ? yield $this->getSettings() : $this->settings;
if (!$settings->getFiles()->getAllowAutomaticUpload()) {
return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted);
}
$file = Tools::absolute($file);

View File

@ -32,8 +32,6 @@ use tgseclib\Math\BigInteger;
*/
class PasswordCalculator
{
use AuthKeyHandler;
/**
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
*
@ -107,7 +105,7 @@ class PasswordCalculator
case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow':
$object['current_algo']['g'] = new BigInteger($object['current_algo']['g']);
$object['current_algo']['p'] = new BigInteger((string) $object['current_algo']['p'], 256);
$this->checkPG($object['current_algo']['p'], $object['current_algo']['g']);
Crypt::checkPG($object['current_algo']['p'], $object['current_algo']['g']);
$object['current_algo']['gForHash'] = \str_pad($object['current_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
$object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
break;
@ -137,7 +135,7 @@ class PasswordCalculator
case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow':
$object['new_algo']['g'] = new BigInteger($object['new_algo']['g']);
$object['new_algo']['p'] = new BigInteger((string) $object['new_algo']['p'], 256);
$this->checkPG($object['new_algo']['p'], $object['new_algo']['g']);
Crypt::checkPG($object['new_algo']['p'], $object['new_algo']['g']);
$object['new_algo']['gForHash'] = \str_pad($object['new_algo']['g']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
$object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
break;
@ -211,7 +209,7 @@ class PasswordCalculator
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
$a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256);
$A = $g->powMod($a, $p);
$this->checkG($A, $p);
Crypt::checkG($A, $p);
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
$u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256);

View File

@ -636,7 +636,21 @@ trait PeerHandler
/**
* @return (((mixed|string)[]|mixed|string)[]|int|mixed|string)[]
*
* @psalm-return array{InputPeer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}, Peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}, DialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}}, NotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}}, InputDialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}}, InputNotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}}, bot_api_id: int|mixed, type: string}
* @psalm-return array{
* InputPeer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed},
* Peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed},
* DialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}},
* NotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, chat_id?: mixed, channel_id?: mixed}},
* InputDialogPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}},
* InputNotifyPeer: array{_: string, peer: array{_: string, user_id?: mixed, access_hash?: mixed, min?: mixed, chat_id?: mixed, channel_id?: mixed}},
* bot_api_id: int|string,
* user_id?: int,
* chat_id?: int,
* channel_id?: int,
* InputUser?: {_: string, user_id?: int, access_hash?: mixed, min?: bool},
* InputChannel?: {_: string, channel_id: int, access_hash: mixed, min: bool},
* type: string
* }
*/
private function genAll($constructor, $folder_id = null): array
{

View File

@ -504,6 +504,7 @@ class ReferenceDatabase implements TLCallback
$local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']);
return $locationType.$dc_id.$volume_id.$local_id;
}
throw new \danog\MadelineProto\Exception("Invalid location type specified!");
}
public function __debugInfo()
{

View File

@ -86,6 +86,11 @@ class MyTelegramOrgWrapper
public function __construct($settings)
{
$this->settings = Settings::parseFromLegacy($settings);
if (!$this->settings instanceof Settings) {
$settings = new Settings;
$settings->merge($this->settings);
$this->settings = $settings;
}
$this->__wakeup();
}
/**

View File

@ -21,6 +21,7 @@ namespace danog\MadelineProto\SecretChats;
use danog\MadelineProto\Loop\Update\UpdateLoop;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\MTProtoTools\Crypt;
/**
* Manages secret chats.
@ -60,7 +61,7 @@ trait AuthKeyHandler
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$params['g_a'] = new \tgseclib\Math\BigInteger((string) $params['g_a'], 256);
$this->checkG($params['g_a'], $dh_config['p']);
Crypt::checkG($params['g_a'], $dh_config['p']);
$key = ['auth_key' => \str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
//$this->logger->logger($key);
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
@ -68,7 +69,7 @@ trait AuthKeyHandler
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'from server', 'mtproto' => 1];
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
$this->checkG($g_b, $dh_config['p']);
Crypt::checkG($g_b, $dh_config['p']);
yield from $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
yield from $this->notifyLayer($params['id']);
$this->logger->logger('Secret chat '.$params['id'].' accepted successfully!', \danog\MadelineProto\Logger::NOTICE);
@ -93,7 +94,7 @@ trait AuthKeyHandler
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$this->logger->logger('Generating g_a...', \danog\MadelineProto\Logger::VERBOSE);
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
$this->checkG($g_a, $dh_config['p']);
Crypt::checkG($g_a, $dh_config['p']);
$res = yield from $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]);
$this->temp_requested_secret_chats[$res['id']] = $a;
$this->updaters[UpdateLoop::GENERIC]->resume();
@ -116,7 +117,7 @@ trait AuthKeyHandler
}
$dh_config = (yield from $this->getDhConfig());
$params['g_a_or_b'] = new \tgseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
$this->checkG($params['g_a_or_b'], $dh_config['p']);
Crypt::checkG($params['g_a_or_b'], $dh_config['p']);
$key = ['auth_key' => \str_pad($params['g_a_or_b']->powMod($this->temp_requested_secret_chats[$params['id']], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
unset($this->temp_requested_secret_chats[$params['id']]);
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
@ -159,7 +160,7 @@ trait AuthKeyHandler
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$this->logger->logger('Generating g_a...', \danog\MadelineProto\Logger::VERBOSE);
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
$this->checkG($g_a, $dh_config['p']);
Crypt::checkG($g_a, $dh_config['p']);
$e = \danog\MadelineProto\Tools::random(8);
$this->temp_rekeyed_secret_chats[$e] = $a;
$this->secret_chats[$chat]['rekeying'] = [1, $e];
@ -194,7 +195,7 @@ trait AuthKeyHandler
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
$params['g_a'] = new \tgseclib\Math\BigInteger((string) $params['g_a'], 256);
$this->checkG($params['g_a'], $dh_config['p']);
Crypt::checkG($params['g_a'], $dh_config['p']);
$key = ['auth_key' => \str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];
@ -202,7 +203,7 @@ trait AuthKeyHandler
$this->temp_rekeyed_secret_chats[$params['exchange_id']] = $key;
$this->secret_chats[$chat]['rekeying'] = [2, $params['exchange_id']];
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
$this->checkG($g_b, $dh_config['p']);
Crypt::checkG($g_b, $dh_config['p']);
yield from $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]);
$this->updaters[UpdateLoop::GENERIC]->resume();
}
@ -223,7 +224,7 @@ trait AuthKeyHandler
$this->logger->logger('Committing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig());
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256);
$this->checkG($params['g_b'], $dh_config['p']);
Crypt::checkG($params['g_b'], $dh_config['p']);
$key = ['auth_key' => \str_pad($params['g_b']->powMod($this->temp_rekeyed_secret_chats[$params['exchange_id']], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
$key['fingerprint'] = \substr(\sha1($key['auth_key'], true), -8);
$key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig'];

View File

@ -191,6 +191,7 @@ class SessionPaths
/**
* Get IPC state.
*
* @psalm-suppress InvalidReturnType
* @return Promise<?IpcState>
*/
public function getIpcState(): Promise
@ -222,6 +223,7 @@ class SessionPaths
/**
* Get light state.
*
* @psalm-suppress InvalidReturnType
* @return Promise<LightState>
*/
public function getLightState(): Promise

View File

@ -40,6 +40,12 @@ trait RawStream
}
public function end(string $finalData = ''): Promise
{
return \danog\MadelineProto\Tools::call($this->endGenerator($finalData));
if (\method_exists($this, 'endGenerator')) {
return \danog\MadelineProto\Tools::call($this->endGenerator($finalData));
} else {
$promise = $this->write($finalData);
$promise->onResolve(fn () => $this->disconnect());
return $promise;
}
}
}

View File

@ -122,7 +122,7 @@ trait TD
} else {
switch (\end($mtproto)) {
case 'choose_chat_id_from_botapi':
$newparams[$td] = (yield from $this->getInfo($params[$mtproto[0]]))['bot_api_id'] == $this->authorization['user']['id'] ? $this->getId($params['from_id']) : (yield from $this->getInfo($params[$mtproto[0]])['bot_api_id']);
$newparams[$td] = (yield from $this->getInfo($params[$mtproto[0]]))['bot_api_id'] == $this->authorization['user']['id'] ? $this->getId($params['from_id']) : (yield from $this->getInfo($params[$mtproto[0]]))['bot_api_id'];
break;
case 'choose_incoming_or_sent':
$newparams[$td] = ['_' => $params['out'] ? 'messageIsSuccessfullySent' : 'messageIsIncoming'];

View File

@ -427,7 +427,7 @@ abstract class Tools extends StrTools
* @param mixed $default
*
* @psalm-param Promise<TReturn>|TGenerator $promise Promise to which the timeout is applied.
* @psalm-param TReturnAlt $timeout
* @psalm-param TReturnAlt $default
*
* @return Promise<TReturn|TReturnAlt>
*

View File

@ -20,6 +20,7 @@
namespace danog\MadelineProto\VoIP;
use danog\MadelineProto\Loop\Update\UpdateLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\Tools;
/**
@ -104,7 +105,7 @@ trait AuthKeyHandler
$a = \tgseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_g_a'], \danog\MadelineProto\Logger::VERBOSE);
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
$this->checkG($g_a, $dh_config['p']);
Crypt::checkG($g_a, $dh_config['p']);
$controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED);
$controller->storage = ['a' => $a, 'g_a' => \str_pad($g_a->toBytes(), 256, \chr(0), \STR_PAD_LEFT)];
$res = yield from $this->methodCallAsyncRead('phone.requestCall', ['user_id' => $user, 'g_a_hash' => \hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
@ -134,7 +135,7 @@ trait AuthKeyHandler
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_b'], \danog\MadelineProto\Logger::VERBOSE);
$b = \tgseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two));
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
$this->checkG($g_b, $dh_config['p']);
Crypt::checkG($g_b, $dh_config['p']);
try {
$res = yield from $this->methodCallAsyncRead('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
@ -172,7 +173,7 @@ trait AuthKeyHandler
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig());
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256);
$this->checkG($params['g_b'], $dh_config['p']);
Crypt::checkG($params['g_b'], $dh_config['p']);
$key = \str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
try {
$res = (yield from $this->methodCallAsyncRead('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' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]))['phone_call'];
@ -224,7 +225,7 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['invalid_g_a']);
}
$params['g_a_or_b'] = new \tgseclib\Math\BigInteger((string) $params['g_a_or_b'], 256);
$this->checkG($params['g_a_or_b'], $dh_config['p']);
Crypt::checkG($params['g_a_or_b'], $dh_config['p']);
$key = \str_pad($params['g_a_or_b']->powMod($this->calls[$params['id']]->storage['b'], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
if (\substr(\sha1($key, true), -8) != $params['key_fingerprint']) {
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']);