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. * Method list.
* *
* @var string[] * @var array<string, callable>
*/ */
protected array $methods = []; protected array $methods = [];

View File

@ -56,6 +56,7 @@ class AnnotationsBuilder
$this->reflectionClasses = $reflectionClasses; $this->reflectionClasses = $reflectionClasses;
$this->logger = $logger; $this->logger = $logger;
$this->namespace = $namespace; $this->namespace = $namespace;
/** @psalm-suppress InvalidArgument */
$this->TL = new TL(new class($logger) { $this->TL = new TL(new class($logger) {
public function __construct($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. // This is reached if either all URIs failed or the maximum number of attempts is reached.
/** @noinspection PhpUndefinedVariableInspection */ /** @noinspection PhpUndefinedVariableInspection */
if ($e) {
throw $e; throw $e;
}
})()); })());
} }
} }

View File

@ -39,10 +39,16 @@ class DocsBuilder
use \danog\MadelineProto\DocsBuilder\Methods; use \danog\MadelineProto\DocsBuilder\Methods;
use \danog\MadelineProto\DocsBuilder\Constructors; use \danog\MadelineProto\DocsBuilder\Constructors;
public $td = false; 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; $this->logger = $logger;
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); \set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
/** @psalm-suppress InvalidArgument */
$this->TL = new TL(new class($logger) { $this->TL = new TL(new class($logger) {
public function __construct($logger) public function __construct($logger)
{ {
@ -119,8 +125,8 @@ class DocsBuilder
} }
} }
} }
if (isset($this->td_descriptions['types'][$otype])) { if (isset($this->tdDescriptions['types'][$otype])) {
$header = "{$this->td_descriptions['types'][$otype]}\n\n$header"; $header = "{$this->tdDescriptions['types'][$otype]}\n\n$header";
} }
$header = \sprintf( $header = \sprintf(
$this->templates['Type'], $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)'; $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]).', '; $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); $this->addToLang('method_'.$method);
if (\danog\MadelineProto\Lang::$lang['en']['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)'; $md_method = '['.$phpMethod.']('.$method.'.md)';
$this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.StrTools::markdownEscape($type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a> $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])) { if (isset($this->tdDescriptions['methods'][$method])) {
$desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->td_descriptions['methods'][$method]['description'])[0], '.')); $desc = \Parsedown::instance()->line(\trim(\explode("\n", $this->tdDescriptions['methods'][$method]['description'])[0], '.'));
$dom = new \DOMDocument(); $dom = new \DOMDocument();
$dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8')); $dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8'));
$desc = $dom->textContent; $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 | | Name | Type | Required |
|----------|---------------|----------| |----------|---------------|----------|
'; ';
if (isset($this->td_descriptions['methods'][$method]) && !empty($data['params'])) { if (isset($this->tdDescriptions['methods'][$method]) && !empty($data['params'])) {
$table = '### Parameters: $table = '### Parameters:
| Name | Type | Description | Required | | Name | Type | Description | Required |
@ -164,13 +164,13 @@ trait Methods
$human_ptype = 'File path or '.$ptype; $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'; $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->tdDescriptions['methods'][$method]['params'][$param['name']])) {
if (isset($this->td_descriptions['methods'][$method]['description'])) { if (isset($this->tdDescriptions['methods'][$method]['description'])) {
$this->td_descriptions['methods'][$method]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$method.'_param_'.$param['name'].'_type_'.$param['type']] ?? ''; $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])) { 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->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').'|'; $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 { } 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').'|'; $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"; $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); $symFile = \str_replace('.', '_', $method);
$redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : ''; $redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : '';
$description = \rtrim(\explode("\n", $description)[0], ':'); $description = \rtrim(\explode("\n", $description)[0], ':');
@ -208,7 +208,7 @@ trait Methods
if ($this->td) { if ($this->td) {
$header .= "YOU CANNOT USE THIS METHOD IN MADELINEPROTO\n\n\n\n\n"; $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 .= ' $table .= '
'; ';

View File

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

View File

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

View File

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

View File

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

View File

@ -267,14 +267,14 @@ trait AuthKeyHandler
$server_time = $server_DH_inner_data['server_time']; $server_time = $server_DH_inner_data['server_time'];
$connection->time_delta = $server_time - \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->logger->logger(\sprintf('Server-client time delta = %.1f s', $connection->time_delta), \danog\MadelineProto\Logger::VERBOSE);
$this->checkPG($dh_prime, $g); Crypt::checkPG($dh_prime, $g);
$this->checkG($g_a, $dh_prime); Crypt::checkG($g_a, $dh_prime);
for ($retry_id = 0; $retry_id <= $this->settings->getAuth()->getMaxAuthTries(); $retry_id++) { for ($retry_id = 0; $retry_id <= $this->settings->getAuth()->getMaxAuthTries(); $retry_id++) {
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$b = new 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); $this->logger->logger('Generating g_b...', \danog\MadelineProto\Logger::VERBOSE);
$g_b = $g->powMod($b, $dh_prime); $g_b = $g->powMod($b, $dh_prime);
$this->checkG($g_b, $dh_prime); Crypt::checkG($g_b, $dh_prime);
/* /*
* *********************************************************************** * ***********************************************************************
* Check validity of g_b * Check validity of g_b
@ -401,87 +401,6 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\SecurityException('Auth Failed'); 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. * Get diffie-hellman configuration.
* *
@ -498,7 +417,7 @@ trait AuthKeyHandler
} }
$dh_config['p'] = new BigInteger((string) $dh_config['p'], 256); $dh_config['p'] = new BigInteger((string) $dh_config['p'], 256);
$dh_config['g'] = new BigInteger($dh_config['g']); $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; return $this->dh_config = $dh_config;
} }
/** /**

View File

@ -19,6 +19,9 @@
namespace danog\MadelineProto\MTProtoTools; namespace danog\MadelineProto\MTProtoTools;
use danog\MadelineProto\Logger;
use tgseclib\Math\BigInteger;
abstract class Crypt abstract class Crypt
{ {
/** /**
@ -117,4 +120,85 @@ abstract class Crypt
$cipher->setIV($iv); $cipher->setIV($iv);
return @$cipher->decrypt($message); 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 Amp\Producer;
use danog\MadelineProto\Exception; use danog\MadelineProto\Exception;
use danog\MadelineProto\FileCallbackInterface; use danog\MadelineProto\FileCallbackInterface;
use danog\MadelineProto\Ipc\Client;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Stream\Common\BufferedRawStream; use danog\MadelineProto\Stream\Common\BufferedRawStream;
use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream; use danog\MadelineProto\Stream\Common\SimpleBufferedRawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
@ -225,7 +227,9 @@ trait FilesLogic
if (\is_resource($file) || (\is_object($file) && $file instanceof InputStream)) { if (\is_resource($file) || (\is_object($file) && $file instanceof InputStream)) {
return yield from $this->uploadFromStream($file, 0, '', $fileName, $cb, $encrypted); 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); return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted);
} }
$file = Tools::absolute($file); $file = Tools::absolute($file);

View File

@ -32,8 +32,6 @@ use tgseclib\Math\BigInteger;
*/ */
class PasswordCalculator class PasswordCalculator
{ {
use AuthKeyHandler;
/** /**
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object). * The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object).
* *
@ -107,7 +105,7 @@ class PasswordCalculator
case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow': case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow':
$object['current_algo']['g'] = new BigInteger($object['current_algo']['g']); $object['current_algo']['g'] = new BigInteger($object['current_algo']['g']);
$object['current_algo']['p'] = new BigInteger((string) $object['current_algo']['p'], 256); $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']['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); $object['current_algo']['pForHash'] = \str_pad($object['current_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
break; break;
@ -137,7 +135,7 @@ class PasswordCalculator
case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow': case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow':
$object['new_algo']['g'] = new BigInteger($object['new_algo']['g']); $object['new_algo']['g'] = new BigInteger($object['new_algo']['g']);
$object['new_algo']['p'] = new BigInteger((string) $object['new_algo']['p'], 256); $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']['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); $object['new_algo']['pForHash'] = \str_pad($object['new_algo']['p']->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
break; break;
@ -211,7 +209,7 @@ class PasswordCalculator
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p); $kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
$a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256); $a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256);
$A = $g->powMod($a, $p); $A = $g->powMod($a, $p);
$this->checkG($A, $p); Crypt::checkG($A, $p);
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT); $AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x); $b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
$u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256); $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)[] * @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 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']); $local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']);
return $locationType.$dc_id.$volume_id.$local_id; return $locationType.$dc_id.$volume_id.$local_id;
} }
throw new \danog\MadelineProto\Exception("Invalid location type specified!");
} }
public function __debugInfo() public function __debugInfo()
{ {

View File

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

View File

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

View File

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

View File

@ -40,6 +40,12 @@ trait RawStream
} }
public function end(string $finalData = ''): Promise 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 { } else {
switch (\end($mtproto)) { switch (\end($mtproto)) {
case 'choose_chat_id_from_botapi': 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; break;
case 'choose_incoming_or_sent': case 'choose_incoming_or_sent':
$newparams[$td] = ['_' => $params['out'] ? 'messageIsSuccessfullySent' : 'messageIsIncoming']; $newparams[$td] = ['_' => $params['out'] ? 'messageIsSuccessfullySent' : 'messageIsIncoming'];

View File

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

View File

@ -20,6 +20,7 @@
namespace danog\MadelineProto\VoIP; namespace danog\MadelineProto\VoIP;
use danog\MadelineProto\Loop\Update\UpdateLoop; use danog\MadelineProto\Loop\Update\UpdateLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\Tools; 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)); $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); $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']); $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 = 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)]; $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]); $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); $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)); $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']); $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 { 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]); $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) { } 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); $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()); $dh_config = (yield from $this->getDhConfig());
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256); $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); $key = \str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
try { 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']; $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']); 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); $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); $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']) { if (\substr(\sha1($key, true), -8) != $params['key_fingerprint']) {
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']); throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']);