Merge
This commit is contained in:
commit
92e8b58bd9
1
bot.php
1
bot.php
@ -39,7 +39,6 @@ class EventHandler extends \danog\MadelineProto\EventHandler
|
||||
if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') {
|
||||
return;
|
||||
}
|
||||
|
||||
$res = json_encode($update, JSON_PRETTY_PRINT);
|
||||
|
||||
try {
|
||||
|
2
docs
2
docs
@ -1 +1 @@
|
||||
Subproject commit 7414ae3e537b26a15b75d2a00ef6f93e702d2cd8
|
||||
Subproject commit ddb2e4f76938b69ceac6e4615901c642accae1ef
|
@ -199,7 +199,13 @@ class Connection
|
||||
$this->disconnect();
|
||||
yield $this->API->datacenter->dcConnectAsync($this->ctx->getDc());
|
||||
if ($this->API->hasAllAuth() && !$this->hasPendingCalls()) {
|
||||
$this->callFork($this->API->method_call_async_read('ping', ['ping_id' => $this->random_int()], ['datacenter' => $this->datacenter]));
|
||||
$this->callFork((function () {
|
||||
try {
|
||||
$this->API->method_call_async_read('ping', ['ping_id' => $this->random_int()], ['datacenter' => $this->datacenter]);
|
||||
} catch (\Throwable $e) {
|
||||
$this->API->logger("Got an error while pinging on reconnect: $e", Logger::FATAL_ERROR);
|
||||
}
|
||||
})());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,18 +471,10 @@ class DataCenter
|
||||
}
|
||||
break;
|
||||
case 'wss':
|
||||
if ($this->settings[$dc_config_number]['obfuscated']) {
|
||||
$default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)];
|
||||
} else {
|
||||
$default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], end($default)];
|
||||
}
|
||||
$default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)];
|
||||
break;
|
||||
case 'ws':
|
||||
if ($this->settings[$dc_config_number]['obfuscated']) {
|
||||
$default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)];
|
||||
} else {
|
||||
$default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], end($default)];
|
||||
}
|
||||
$default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,9 @@ class Logger
|
||||
Exception::$rollbar = false;
|
||||
RPCErrorException::$rollbar = false;
|
||||
}
|
||||
|
||||
if (!isset($settings['logger']['logger_param']) && isset($settings['logger']['param'])) {
|
||||
$settings['logger']['logger_param'] = $settings['logger']['param'];
|
||||
}
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
if (isset($settings['logger']['logger_param']) && basename($settings['logger']['logger_param']) === 'MadelineProto.log') {
|
||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||
@ -179,6 +181,8 @@ class Logger
|
||||
{
|
||||
if (!is_null(self::$default)) {
|
||||
self::$default->logger($param, $level, basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
|
||||
} else {
|
||||
echo $param.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
namespace danog\MadelineProto\Loop\Connection;
|
||||
|
||||
use Amp\ByteStream\PendingReadError;
|
||||
use Amp\ByteStream\StreamException;
|
||||
use Amp\Loop;
|
||||
use Amp\Websocket\ClosedException;
|
||||
use danog\MadelineProto\Logger;
|
||||
@ -58,7 +60,7 @@ class ReadLoop extends SignalLoop
|
||||
while (true) {
|
||||
try {
|
||||
$error = yield $this->waitSignal($this->readMessage());
|
||||
} catch (NothingInTheSocketException|StreamException|PendingReadError $e) {
|
||||
} catch (NothingInTheSocketException | StreamException | PendingReadError | \Error $e) {
|
||||
if (isset($connection->old)) {
|
||||
return;
|
||||
}
|
||||
|
@ -287,9 +287,6 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
public function __wakeup_async($backtrace)
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
//set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']);
|
||||
Magic::class_exists();
|
||||
|
||||
$this->setup_logger();
|
||||
if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
|
@ -391,6 +391,8 @@ trait AuthKeyHandler
|
||||
$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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
if (strpos($datacenter, 'cdn') === false) {
|
||||
|
@ -41,6 +41,7 @@ use function Amp\File\exists;
|
||||
use function Amp\File\open;
|
||||
use function Amp\File\stat;
|
||||
use function Amp\File\touch;
|
||||
use danog\MadelineProto\Tools;
|
||||
use function Amp\Promise\all;
|
||||
use Amp\File\BlockingHandle;
|
||||
use Amp\Artax\Client;
|
||||
@ -566,7 +567,7 @@ trait Files
|
||||
$res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg');
|
||||
}
|
||||
if (!isset($res['name']) || $res['name'] === '') {
|
||||
$res['name'] = $message_media['file']['access_hash'];
|
||||
$res['name'] = Tools::unpack_signed_long_string($message_media['file']['access_hash']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
@ -636,7 +637,7 @@ trait Files
|
||||
$res['thumb_size'] = $message_media['type'];
|
||||
|
||||
if ($message_media['location']['_'] === 'fileLocationUnavailable') {
|
||||
$res['name'] = $message_media['volume_id'].'_'.$message_media['local_id'];
|
||||
$res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id'];
|
||||
$res['mime'] = $this->get_mime_from_buffer($res['data']);
|
||||
$res['ext'] = $this->get_extension_from_mime($res['mime']);
|
||||
} else {
|
||||
@ -658,7 +659,7 @@ trait Files
|
||||
case 'fileLocationUnavailable':
|
||||
throw new \danog\MadelineProto\Exception('File location unavailable');
|
||||
case 'fileLocation':
|
||||
$res['name'] = $message_media['volume_id'].'_'.$message_media['local_id'];
|
||||
$res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id'];
|
||||
$res['InputFileLocation'] = [
|
||||
'_' => 'inputFileLocation',
|
||||
'volume_id' => $message_media['volume_id'],
|
||||
@ -675,7 +676,7 @@ trait Files
|
||||
|
||||
return $res;
|
||||
case 'fileLocationToBeDeprecated':
|
||||
$res['name'] = $message_media['volume_id'].'_'.$message_media['local_id'];
|
||||
$res['name'] = Tools::unpack_signed_long_string($message_media['volume_id']).'_'.$message_media['local_id'];
|
||||
$res['ext'] = '.jpg';
|
||||
$res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg');
|
||||
$res['InputFileLocation'] = [
|
||||
@ -730,7 +731,7 @@ trait Files
|
||||
$res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], $this->get_extension_from_mime($message_media['document']['mime_type']));
|
||||
}
|
||||
if (!isset($res['name']) || $res['name'] === '') {
|
||||
$res['name'] = $message_media['document']['access_hash'];
|
||||
$res['name'] = Tools::unpack_signed_long_string($message_media['document']['access_hash']);
|
||||
}
|
||||
if (isset($message_media['document']['size'])) {
|
||||
$res['size'] = $message_media['document']['size'];
|
||||
|
@ -25,24 +25,77 @@ use danog\MadelineProto\Tools;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Manages password calculation.
|
||||
* Manages SRP password calculation
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
class PasswordCalculator
|
||||
{
|
||||
use AuthKeyHandler;
|
||||
use Tools;
|
||||
|
||||
/**
|
||||
* The algorithm to use for calculating the hash of new passwords (a PasswordKdfAlgo object)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $new_algo;
|
||||
/**
|
||||
* A secure random string that can be used to compute the password
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $secure_random = '';
|
||||
|
||||
/**
|
||||
* The algorithm to use for calculatuing the hash of the current password (a PasswordKdfAlgo object)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $current_algo;
|
||||
|
||||
/**
|
||||
* SRP b parameter
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
private $srp_B;
|
||||
/**
|
||||
* SRP b parameter for hashing
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
private $srp_BForHash;
|
||||
/**
|
||||
* SRP ID
|
||||
*
|
||||
* @var [type]
|
||||
*/
|
||||
private $srp_id;
|
||||
/**
|
||||
* Logger
|
||||
*
|
||||
* @var \danog\MadelineProto\Logger
|
||||
*/
|
||||
public $logger;
|
||||
|
||||
// This is needed do not remove this
|
||||
public function __construct($logger) { $this->logger = $logger; }
|
||||
/**
|
||||
* Initialize logger
|
||||
*
|
||||
* @param \danog\MadelineProto\Logger $logger
|
||||
*/
|
||||
public function __construct($logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Popupate 2FA configuration
|
||||
*
|
||||
* @param array $object 2FA configuration object obtained using account.getPassword
|
||||
* @return void
|
||||
*/
|
||||
public function addInfo(array $object)
|
||||
{
|
||||
if ($object['_'] !== 'account.password') {
|
||||
@ -101,16 +154,39 @@ class PasswordCalculator
|
||||
$this->secure_random = $object['secure_random'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random string (eventually prefixed by the specified string)
|
||||
*
|
||||
* @param string $prefix Prefix
|
||||
* @return string Salt
|
||||
*/
|
||||
public function createSalt(string $prefix = ''): string
|
||||
{
|
||||
return $prefix.$this->random(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash specified data using the salt with SHA256
|
||||
*
|
||||
* The result will be the SHA256 hash of the salt concatenated with the data concatenated with the salt
|
||||
*
|
||||
* @param string $data Data to hash
|
||||
* @param string $salt Salt
|
||||
* @return string Hash
|
||||
*/
|
||||
public function hashSha256(string $data, string $salt): string
|
||||
{
|
||||
return hash('sha256', $salt.$data.$salt, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes the specified password
|
||||
*
|
||||
* @param string $password Password
|
||||
* @param string $client_salt Client salt
|
||||
* @param string $server_salt Server salt
|
||||
* @return string Resulting hash
|
||||
*/
|
||||
public function hashPassword(string $password, string $client_salt, string $server_salt): string
|
||||
{
|
||||
$buf = $this->hashSha256($password, $client_salt);
|
||||
@ -120,9 +196,15 @@ class PasswordCalculator
|
||||
return $this->hashSha256($hash, $server_salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the InputCheckPassword object for checking the validity of a password using account.checkPassword
|
||||
*
|
||||
* @param string $password The password
|
||||
* @return array InputCheckPassword object
|
||||
*/
|
||||
public function getCheckPassword(string $password): array
|
||||
{
|
||||
if ($password === '') {
|
||||
if ($password === '' || !$this->current_algo) {
|
||||
return ['_' => 'inputCheckPasswordEmpty'];
|
||||
}
|
||||
$client_salt = $this->current_algo['salt1'];
|
||||
@ -131,6 +213,7 @@ class PasswordCalculator
|
||||
$gForHash = $this->current_algo['gForHash'];
|
||||
$p = $this->current_algo['p'];
|
||||
$pForHash = $this->current_algo['pForHash'];
|
||||
|
||||
$B = $this->srp_B;
|
||||
$BForHash = $this->srp_BForHash;
|
||||
$id = $this->srp_id;
|
||||
@ -166,9 +249,20 @@ class PasswordCalculator
|
||||
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parameters to be passed to the account.updatePasswordSettings to update/set a 2FA password
|
||||
*
|
||||
* The input params array can contain password, new_password, email and hint params.
|
||||
*
|
||||
* @param array $params Input params
|
||||
* @return array account.updatePasswordSettings parameters
|
||||
*/
|
||||
public function getPassword(array $params): array
|
||||
{
|
||||
$return = ['password' => $this->getCheckPassword(isset($params['password']) ? $params['password'] : ''), 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
||||
$oldPassword = $this->getCheckPassword($params['password'] ?? '');
|
||||
|
||||
$return = ['password' => $oldPassword, 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']];
|
||||
|
||||
$new_settings = &$return['new_settings'];
|
||||
|
||||
if (isset($params['new_password']) && $params['new_password'] !== '') {
|
||||
@ -183,11 +277,11 @@ class PasswordCalculator
|
||||
$vForHash = str_pad($v->toBytes(), 256, chr(0), \STR_PAD_LEFT);
|
||||
|
||||
$new_settings['new_algo'] = [
|
||||
'_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
||||
'_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
||||
'salt1' => $client_salt,
|
||||
'salt2' => $server_salt,
|
||||
'g' => (int) $g->toString(),
|
||||
'p' => $pForHash,
|
||||
'g' => (int) $g->toString(),
|
||||
'p' => $pForHash,
|
||||
];
|
||||
$new_settings['new_password_hash'] = $vForHash;
|
||||
$new_settings['hint'] = $params['hint'];
|
||||
|
@ -312,7 +312,15 @@ trait ResponseHandler
|
||||
if (isset($request['promise'])) {
|
||||
$promise = $request['promise'];
|
||||
unset($request['promise']);
|
||||
$promise->fail($data);
|
||||
try {
|
||||
$promise->fail($data);
|
||||
} catch (\Error $e) {
|
||||
if (strpos($e->getMessage(), "Promise has already been resolved") !== 0) {
|
||||
throw $e;
|
||||
}
|
||||
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-'));
|
||||
$this->logger->logger("Rejecting: $data");
|
||||
@ -580,7 +588,14 @@ trait ResponseHandler
|
||||
if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise'])) { // This should not happen but happens, should debug
|
||||
$promise = $this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise'];
|
||||
unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise']);
|
||||
$promise->resolve($response);
|
||||
try {
|
||||
$promise->resolve($response);
|
||||
} catch (\Error $e) {
|
||||
if (strpos($e->getMessage(), "Promise has already been resolved") !== 0) {
|
||||
throw $e;
|
||||
}
|
||||
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
)());
|
||||
|
@ -66,7 +66,7 @@ class Magic
|
||||
public static function class_exists()
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
//set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']);
|
||||
set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']);
|
||||
if (!self::$inited) {
|
||||
if (!defined('\\phpseclib\\Crypt\\Common\\SymmetricKey::MODE_IGE') || \phpseclib\Crypt\Common\SymmetricKey::MODE_IGE !== 7) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['phpseclib_fork']);
|
||||
@ -183,6 +183,12 @@ class Magic
|
||||
//$this->logger->logger('Could not enable PHP logging');
|
||||
}
|
||||
}
|
||||
|
||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?allv3'), true);
|
||||
if (isset($res['ok']) && $res['ok']) {
|
||||
RPCErrorException::$errorMethodMap = $res['result'];
|
||||
RPCErrorException::$descriptions += $res['human_result'];
|
||||
}
|
||||
self::$inited = true;
|
||||
}
|
||||
}
|
||||
|
@ -25,21 +25,86 @@ class RPCErrorException extends \Exception
|
||||
private $fetched = false;
|
||||
public static $rollbar = true;
|
||||
|
||||
public function getMess()
|
||||
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 $errorMethodMap = [];
|
||||
|
||||
private $caller = '';
|
||||
public static function localizeMessage($method, $code, $error)
|
||||
{
|
||||
if ($this->fetched === false) {
|
||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$additional[0].'&code='.$code.'&error='.$this->rpc), true);
|
||||
if (!$method || !$code || !$error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$error = preg_replace('/\d+$/', "X", $error);
|
||||
|
||||
$description = self::$descriptions[$error] ?? '';
|
||||
|
||||
|
||||
if (!isset(self::$errorMethodMap[$code][$method][$error])
|
||||
|| !isset(self::$descriptions[$error])
|
||||
|| $code === 500
|
||||
) {
|
||||
$res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error), true);
|
||||
if (isset($res['ok']) && $res['ok']) {
|
||||
$this->message = $res['result'];
|
||||
$description = $res['result'];
|
||||
|
||||
self::$descriptions[$error] = $description;
|
||||
self::$errorMethodMap[$code][$method][$error] = $error;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->message;
|
||||
if (!$description) {
|
||||
return $error;
|
||||
}
|
||||
return $description;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], $this->getMess()." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||
$result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
||||
}
|
||||
@ -50,147 +115,19 @@ class RPCErrorException extends \Exception
|
||||
public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null)
|
||||
{
|
||||
$this->rpc = $message;
|
||||
switch ($message) {
|
||||
case 'RPC_MCGET_FAIL':
|
||||
case 'RPC_CALL_FAIL':
|
||||
$message = 'Telegram is having internal issues, please try again later.';
|
||||
break;
|
||||
case 'USER_PRIVACY_RESTRICTED':
|
||||
$message = "The user's privacy settings do not allow you to do this";
|
||||
break;
|
||||
case 'CHANNEL_PRIVATE':
|
||||
$message = "You haven't joined this channel/supergroup";
|
||||
break;
|
||||
case 'FLOOD_WAIT_666':
|
||||
$message = 'Spooky af m8';
|
||||
break;
|
||||
case 'USER_IS_BOT':
|
||||
$message = "Bots can't send messages to other bots";
|
||||
break;
|
||||
case 'BOT_METHOD_INVALID':
|
||||
$message = 'This method cannot be run by a bot';
|
||||
break;
|
||||
case 'PHONE_CODE_EXPIRED':
|
||||
$message = '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)';
|
||||
break;
|
||||
case 'USERNAME_INVALID':
|
||||
$message = 'The provided username is not valid';
|
||||
break;
|
||||
case 'ACCESS_TOKEN_INVALID':
|
||||
$message = 'The provided token is not valid';
|
||||
break;
|
||||
case 'ACTIVE_USER_REQUIRED':
|
||||
$message = 'The method is only available to already activated users';
|
||||
break;
|
||||
case 'FIRSTNAME_INVALID':
|
||||
$message = 'The first name is invalid';
|
||||
break;
|
||||
case 'LASTNAME_INVALID':
|
||||
$message = 'The last name is invalid';
|
||||
break;
|
||||
case 'PHONE_NUMBER_INVALID':
|
||||
$message = 'The phone number is invalid';
|
||||
break;
|
||||
case 'PHONE_CODE_HASH_EMPTY':
|
||||
$message = 'phone_code_hash is missing';
|
||||
break;
|
||||
case 'PHONE_CODE_EMPTY':
|
||||
$message = 'phone_code is missing';
|
||||
break;
|
||||
case 'PHONE_CODE_EXPIRED':
|
||||
$message = 'The confirmation code has expired';
|
||||
break;
|
||||
case 'API_ID_INVALID':
|
||||
$message = 'The api_id/api_hash combination is invalid';
|
||||
break;
|
||||
case 'PHONE_NUMBER_OCCUPIED':
|
||||
$message = 'The phone number is already in use';
|
||||
break;
|
||||
case 'PHONE_NUMBER_UNOCCUPIED':
|
||||
$message = 'The phone number is not yet being used';
|
||||
break;
|
||||
case 'USERS_TOO_FEW':
|
||||
$message = 'Not enough users (to create a chat, for example)';
|
||||
break;
|
||||
case 'USERS_TOO_MUCH':
|
||||
$message = 'The maximum number of users has been exceeded (to create a chat, for example)';
|
||||
break;
|
||||
case 'TYPE_CONSTRUCTOR_INVALID':
|
||||
$message = 'The type constructor is invalid';
|
||||
break;
|
||||
case 'FILE_PART_INVALID':
|
||||
$message = 'The file part number is invalid';
|
||||
break;
|
||||
case 'FILE_PARTS_INVALID':
|
||||
$message = 'The number of file parts is invalid';
|
||||
break;
|
||||
case 'MD5_CHECKSUM_INVALID':
|
||||
$message = 'The MD5 checksums do not match';
|
||||
break;
|
||||
case 'PHOTO_INVALID_DIMENSIONS':
|
||||
$message = 'The photo dimensions are invalid';
|
||||
break;
|
||||
case 'FIELD_NAME_INVALID':
|
||||
$message = 'The field with the name FIELD_NAME is invalid';
|
||||
break;
|
||||
case 'FIELD_NAME_EMPTY':
|
||||
$message = 'The field with the name FIELD_NAME is missing';
|
||||
break;
|
||||
case 'MSG_WAIT_FAILED':
|
||||
$message = 'A waiting call returned an error';
|
||||
break;
|
||||
case 'USERNAME_NOT_OCCUPIED':
|
||||
$message = 'The provided username is not occupied';
|
||||
break;
|
||||
case 'PHONE_NUMBER_BANNED':
|
||||
$message = 'The provided phone number is banned from telegram';
|
||||
break;
|
||||
case 'AUTH_KEY_UNREGISTERED':
|
||||
$message = 'The authorization key has expired';
|
||||
break;
|
||||
case 'INVITE_HASH_EXPIRED':
|
||||
$message = 'The invite link has expired';
|
||||
break;
|
||||
case 'USER_DEACTIVATED':
|
||||
$message = 'The user was deactivated';
|
||||
break;
|
||||
case 'USER_ALREADY_PARTICIPANT':
|
||||
$message = 'The user is already in the group';
|
||||
break;
|
||||
case 'MESSAGE_ID_INVALID':
|
||||
$message = 'The provided message id is invalid';
|
||||
break;
|
||||
case 'PEER_ID_INVALID':
|
||||
$message = 'The provided peer id is invalid';
|
||||
break;
|
||||
case 'CHAT_ID_INVALID':
|
||||
$message = 'The provided chat id is invalid';
|
||||
break;
|
||||
case 'MESSAGE_DELETE_FORBIDDEN':
|
||||
$message = "You can't delete one of the messages you tried to delete, most likely because it is a service message.";
|
||||
break;
|
||||
case 'CHAT_ADMIN_REQUIRED':
|
||||
$message = 'You must be an admin in this chat to do this';
|
||||
break;
|
||||
case -429:
|
||||
case 'PEER_FLOOD':
|
||||
$message = 'Too many requests';
|
||||
break;
|
||||
}
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->prettify_tl($caller);
|
||||
$this->caller = $caller;
|
||||
|
||||
$additional = [];
|
||||
foreach ($this->getTrace() as $level) {
|
||||
if (isset($level['function']) && $level['function'] === 'method_call') {
|
||||
$this->line = $level['line'];
|
||||
$this->file = $level['file'];
|
||||
$additional = $level['args'];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if ($this->rpc !== $message) {
|
||||
$this->fetched = true;
|
||||
}
|
||||
if (!self::$rollbar || !class_exists('\\Rollbar\\Rollbar')) {
|
||||
return;
|
||||
}
|
||||
|
@ -24,11 +24,6 @@ namespace danog\MadelineProto;
|
||||
*/
|
||||
class Serialization
|
||||
{
|
||||
public static function serialize_all($exception)
|
||||
{
|
||||
echo $exception.PHP_EOL;
|
||||
}
|
||||
|
||||
public static function realpaths($file)
|
||||
{
|
||||
$file = Absolute::absolute($file);
|
||||
|
@ -194,6 +194,7 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
|
||||
$extra['secret'] = substr($extra['secret'], 1, 16);
|
||||
}
|
||||
}
|
||||
|
||||
$this->extra = $extra;
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ class WsStream implements RawStreamInterface
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->stream) {
|
||||
throw new ConnectionException('Failed to read response from server');
|
||||
}
|
||||
|
@ -1050,17 +1050,20 @@ invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
|
||||
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
|
||||
auth.logOut#5717da40 = Bool;
|
||||
|
||||
auth.resetAuthorizations#9fab0d1a = Bool;
|
||||
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
|
||||
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
|
||||
|
||||
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
|
||||
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
|
||||
auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
|
||||
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
|
||||
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
|
||||
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
|
||||
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
|
||||
|
||||
account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
|
||||
|
@ -23,6 +23,9 @@ use Amp\Failure;
|
||||
use Amp\Loop;
|
||||
use Amp\Promise;
|
||||
use Amp\Success;
|
||||
use function Amp\ByteStream\getOutputBufferStream;
|
||||
use function Amp\ByteStream\getStdin;
|
||||
use function Amp\ByteStream\getStdout;
|
||||
use function Amp\Promise\all;
|
||||
use function Amp\Promise\any;
|
||||
use function Amp\Promise\first;
|
||||
@ -35,6 +38,7 @@ use function Amp\ByteStream\getOutputBufferStream;
|
||||
use function Amp\File\exists;
|
||||
use function Amp\File\touch;
|
||||
use Amp\File\StatCache;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Some tools.
|
||||
@ -122,6 +126,16 @@ trait Tools
|
||||
return unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
|
||||
public static function unpack_signed_long_string($value)
|
||||
{
|
||||
if (strlen($value) !== 8) {
|
||||
throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']);
|
||||
}
|
||||
|
||||
$big = new BigInteger($value, -256);
|
||||
return (string) $big;
|
||||
}
|
||||
|
||||
public static function pack_signed_int($value)
|
||||
{
|
||||
if ($value > 2147483647) {
|
||||
@ -194,6 +208,7 @@ trait Tools
|
||||
try {
|
||||
Loop::run(function () use (&$resolved, &$value, &$exception, $promise) {
|
||||
$promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) {
|
||||
|
||||
Loop::stop();
|
||||
$resolved = true;
|
||||
$exception = $e;
|
||||
@ -308,12 +323,21 @@ trait Tools
|
||||
if ($file) {
|
||||
$file = " started @ $file";
|
||||
}
|
||||
if ($logger) $logger->logger("Got the following exception within a forked strand$file, trying to rethrow");
|
||||
if ($logger) {
|
||||
$logger->logger("Got the following exception within a forked strand$file, trying to rethrow");
|
||||
}
|
||||
|
||||
if ($e->getMessage() === "Cannot get return value of a generator that hasn't returned") {
|
||||
$logger->logger("Well you know, this might actually not be the actual exception, scroll up in the logs to see the actual exception");
|
||||
if (!$zis || !$zis->destructing) Promise\rethrow(new Failure($e));
|
||||
if (!$zis || !$zis->destructing) {
|
||||
Promise\rethrow(new Failure($e));
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($logger) $logger->logger($e);
|
||||
if ($logger) {
|
||||
$logger->logger($e);
|
||||
}
|
||||
|
||||
Promise\rethrow(new Failure($e));
|
||||
}
|
||||
}
|
||||
@ -332,7 +356,7 @@ trait Tools
|
||||
return;
|
||||
}
|
||||
$b = self::call($b());
|
||||
$b->onResolve(static function ($e, $res) use ($deferred) {
|
||||
$b->onResolve(function ($e, $res) use ($deferred) {
|
||||
if ($e) {
|
||||
if (isset($this)) {
|
||||
$this->rethrow($e, $file);
|
||||
@ -415,8 +439,7 @@ trait Tools
|
||||
return array_shift($lines);
|
||||
}
|
||||
|
||||
public static function echo($string)
|
||||
{
|
||||
public static function echo ($string) {
|
||||
return getOutputBufferStream()->write($string);
|
||||
}
|
||||
public static function is_array_or_alike($var)
|
||||
|
@ -205,7 +205,7 @@ trait Login
|
||||
/**
|
||||
* Update the 2FA password
|
||||
*
|
||||
* The params can contain password, new_password, email and hint params.
|
||||
* The params array can contain password, new_password, email and hint params.
|
||||
*
|
||||
* @param array $params The params
|
||||
* @return void
|
||||
|
@ -68,6 +68,9 @@ trait Loop
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$needs_restart = true;
|
||||
}
|
||||
if (isset($_REQUEST['MadelineSelfRestart'])) {
|
||||
$this->logger->logger("Self-restarted, restart token ".$_REQUEST['MadelineSelfRestart']);
|
||||
}
|
||||
$this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart');
|
||||
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
@ -105,9 +108,31 @@ trait Loop
|
||||
if ($needs_restart) {
|
||||
$logger = &$this->logger;
|
||||
Shutdown::addCallback(static function () use (&$logger) {
|
||||
$a = fsockopen((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']);
|
||||
fwrite($a, $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n");
|
||||
$logger->logger('Self-restarted');
|
||||
$address = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME'];
|
||||
$port = $_SERVER['SERVER_PORT'];
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
|
||||
$params = $_GET;
|
||||
$params['MadelineSelfRestart'] = $this->random_int();
|
||||
|
||||
list($url, $query) = explode($uri, '?', 2);
|
||||
$query = http_build_query($params);
|
||||
$uri = implode('?', [$url, $query]);
|
||||
|
||||
$payload = $_SERVER['REQUEST_METHOD'].' '.$uri.' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n";
|
||||
|
||||
$logger->logger("Connecting to $address:$port");
|
||||
$a = fsockopen($address, $port);
|
||||
|
||||
$logger->logger("Sending self-restart payload");
|
||||
$logger->logger($payload);
|
||||
fwrite($a, $payload);
|
||||
|
||||
$logger->logger("Payload sent with token {$params['MadelineSelfRestart']}, waiting for self-restart");
|
||||
|
||||
sleep(10);
|
||||
fclose($a);
|
||||
}, 'restarter');
|
||||
}
|
||||
|
||||
@ -164,5 +189,8 @@ trait Loop
|
||||
ob_end_flush();
|
||||
flush();
|
||||
$GLOBALS['exited'] = true;
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
\fastcgi_finish_request();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ cd ..
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install php7.3-cli php7.3-json php7.3-mbstring php7.3-curl php7.3-xml php7.3-json -y
|
||||
|
||||
composer global require spatie/7to5 dev-master#5c65f68
|
||||
composer global require spatie/7to5 dev-master#d4be6d0
|
||||
[ -f $HOME/.composer/vendor/bin/php7to5 ] && php7to5=$HOME/.composer/vendor/bin/php7to5
|
||||
[ -f $HOME/.config/composer/vendor/bin/php7to5 ] && php7to5=$HOME/.config/composer/vendor/bin/php7to5
|
||||
|
||||
|
@ -37,7 +37,7 @@ if (file_exists('.env')) {
|
||||
$dotenv->load();
|
||||
}
|
||||
if (getenv('TEST_SECRET_CHAT') == '') {
|
||||
echo('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL);
|
||||
echo ('TEST_SECRET_CHAT is not defined in .env, please define it (copy .env.example).'.PHP_EOL);
|
||||
die(1);
|
||||
}
|
||||
echo 'Loading settings...'.PHP_EOL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user