1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 04:08:59 +01:00

Fix logout in case of session termination

This commit is contained in:
Daniil Gentili 2023-08-06 16:29:29 +02:00
parent 50145665cd
commit a3094016e8
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
12 changed files with 81 additions and 10 deletions

2
docs

@ -1 +1 @@
Subproject commit a0aae4d1e264c9b56469a47d67780b7c345c4672
Subproject commit 07535f4de8d8ee6b845ef36ff572bbc2ff1d6fe5

View File

@ -9,7 +9,7 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="true">
>
<coverage>
<include>
<directory suffix=".php">src</directory>

View File

@ -101,6 +101,12 @@ final class API extends AbstractAPI
* @var int
*/
public const LOGGED_IN = 3;
/**
* We're logged out, the session will be deleted ASAP.
*
* @var int
*/
public const LOGGED_OUT = 4;
/**
* This peer is a user.
*

View File

@ -98,6 +98,10 @@ final class APIWrapper
$this->API->waitForInit();
$API = $this->API;
if ($API->authorized === API::LOGGED_OUT) {
return false;
}
$this->session->serialize(
$API->serializeSession($this),
$this->session->getSessionPath(),

View File

@ -1269,6 +1269,11 @@ abstract class InternalDoc
{
$this->wrapper->getAPI()->logger($param, $level, $file);
}
public function logout(): void
{
$this->wrapper->getAPI()->logout();
}
/**
* Start MadelineProto's update handling loop, or run the provided async callable.
*

View File

@ -141,6 +141,11 @@ final class Client extends ClientAbstract
return true;
}
public function getLogger(): Logger
{
return $this->logger;
}
/** @internal */
public function getQrLoginCancellation(): Cancellation
{

View File

@ -137,7 +137,10 @@ use Webmozart\Assert\Assert;
Logger::log("$e", Logger::FATAL_ERROR);
Logger::log('Got exception in IPC server, exiting...', Logger::FATAL_ERROR);
$ipc = $session->getIpcState();
if (!($ipc && $ipc->getStartupId() === $runnerId && !$ipc->getException())) {
if (!($ipc && $ipc->getStartupId() === $runnerId && !$ipc->getException())
&& $API
&& $API->getAuthorization() !== API::LOGGED_OUT
) {
Logger::log('Reporting error!');
$session->storeIpcState(new IpcState($runnerId, $e));
Logger::log('Reported error!');

View File

@ -475,6 +475,9 @@ final class MTProto implements TLCallback, LoggerGetter
if (self::$references) {
Logger::log('Prompting final serialization (SHUTDOWN)...');
foreach (self::$references as $instance) {
if ($instance->authorized === API::LOGGED_OUT) {
continue;
}
$instance->wrapper->serialize();
}
Logger::log('Done final serialization (SHUTDOWN)!');
@ -1122,6 +1125,9 @@ final class MTProto implements TLCallback, LoggerGetter
}
}
$this->logger->logger('Unreferenced instance');
if ($this->authorized === API::LOGGED_OUT) {
$this->wrapper->getSession()->delete();
}
}
/**
* Destructor.

View File

@ -326,6 +326,7 @@ trait ResponseHandler
$phone = isset($this->API->authorization['user']['phone']) ? '+' . $this->API->authorization['user']['phone'] : '???';
$this->logger->logger(\sprintf(Lang::$current_lang['account_banned'], $phone), Logger::FATAL_ERROR);
}
$this->API->logout();
return fn () => new RPCErrorException($response['error_message'], $response['error_code'], $request->getConstructor());
case 'AUTH_KEY_UNREGISTERED':
case 'AUTH_KEY_INVALID':
@ -345,6 +346,7 @@ trait ResponseHandler
$this->logger->logger('Permanent auth key was main authorized key, logging out...', Logger::FATAL_ERROR);
$phone = isset($this->API->authorization['user']['phone']) ? '+' . $this->API->authorization['user']['phone'] : 'you are currently using';
$this->logger->logger(\sprintf(Lang::$current_lang['account_banned'], $phone), Logger::FATAL_ERROR);
$this->API->logout();
return fn () => new RPCErrorException($response['error_message'], $response['error_code'], $request->getConstructor());
}
EventLoop::queue(function () use ($request): void {

View File

@ -21,6 +21,8 @@ declare(strict_types=1);
namespace danog\MadelineProto;
use danog\MadelineProto\Ipc\IpcState;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use const LOCK_EX;
use const LOCK_SH;
@ -29,10 +31,12 @@ use const PHP_MINOR_VERSION;
use const PHP_VERSION;
use function Amp\File\createDirectory;
use function Amp\File\deleteDirectory;
use function Amp\File\deleteFile;
use function Amp\File\exists;
use function Amp\File\isDirectory;
use function Amp\File\isFile;
use function Amp\File\listFiles;
use function Amp\File\move;
use function Amp\File\openFile;
use function Amp\File\write;
@ -109,6 +113,21 @@ final class SessionPaths
}
}
}
/**
* Deletes session.
*/
public function delete(): void
{
if (file_exists($this->sessionDirectoryPath)) {
foreach (scandir($this->sessionDirectoryPath) as $f) {
if ($f === '.' || $f === '..') {
continue;
}
unlink($this->sessionDirectoryPath.DIRECTORY_SEPARATOR.$f);
}
rmdir($this->sessionDirectoryPath);
}
}
/**
* Serialize object to file.
*/

View File

@ -24,15 +24,19 @@ use Amp\Cancellation;
use Amp\CancelledException;
use Amp\DeferredCancellation;
use Amp\DeferredFuture;
use Amp\SignalException;
use AssertionError;
use danog\MadelineProto\API;
use danog\MadelineProto\Exception;
use danog\MadelineProto\Lang;
use danog\MadelineProto\Logger;
use danog\MadelineProto\LogoutException;
use danog\MadelineProto\Magic;
use danog\MadelineProto\MTProto\PermAuthKey;
use danog\MadelineProto\MTProtoTools\PasswordCalculator;
use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Shutdown;
use danog\MadelineProto\TL\Types\LoginQrCode;
use danog\MadelineProto\Tools;
@ -142,6 +146,19 @@ trait Login
$c->cancel();
return $c->getCancellation();
}
public function logout(): void
{
if ($this->authorized === API::LOGGED_IN) {
$this->authorized = API::LOGGED_OUT;
$this->methodCallAsyncRead('auth.logOut');
}
$this->authorized = API::LOGGED_OUT;
if ($this->hasEventHandler()) {
$this->stop();
} else {
$this->ipcServer?->stop();
}
}
/** @internal */
public function waitQrLogin(): void
{

View File

@ -5,8 +5,8 @@ declare(strict_types=1);
namespace danog\MadelineProto\Test;
use Amp\PHPUnit\AsyncTestCase;
use danog\MadelineProto\API;
use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream;
use danog\MadelineProto\Stream\MTProtoTransport\FullStream;
@ -36,8 +36,6 @@ final class DataCenterTest extends AsyncTestCase
*/
public function testCanUseProtocol(string $transport, bool $obfuscated, string $protocol, bool $test_mode, bool $ipv6): void
{
$this->markTestSkipped();
return;/*
$settings = new Settings;
$settings->getAppInfo()
->setApiHash(\getenv('API_HASH'))
@ -54,11 +52,17 @@ final class DataCenterTest extends AsyncTestCase
->setTransport($transport)
->setRetry(false)
->setTimeout(10);
$API = new MTProto($settings);
$API->getLogger()->logger("Testing protocol $protocol using transport $transport, ".($obfuscated ? 'obfuscated ' : 'not obfuscated ').($test_mode ? 'test DC ' : 'main DC ').($ipv6 ? 'IPv6 ' : 'IPv4 '));
$ping = \random_bytes(8);
$this->assertEquals($ping, $API->methodCallAsyncRead('ping', ['ping_id' => $ping])['ping_id']);*/
// Init session
$API = new API(\sys_get_temp_dir()."/{$transport}_{$obfuscated}_{$protocol}_{$test_mode}_$ipv6", $settings);
unset($API);
// Fork
$API = new API(\sys_get_temp_dir()."/{$transport}_{$obfuscated}_{$protocol}_{$test_mode}_$ipv6", $settings);
$API->logger("Testing protocol $protocol using transport $transport, ".($obfuscated ? 'obfuscated ' : 'not obfuscated ').($test_mode ? 'test DC ' : 'main DC ').($ipv6 ? 'IPv6 ' : 'IPv4 '));
$this->assertIsArray($API->help->getConfig());
$API->logout();
}
public function protocolProvider(): Generator