1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-12-02 12:37:47 +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" convertNoticesToExceptions="true"
convertWarningsToExceptions="true" convertWarningsToExceptions="true"
processIsolation="false" processIsolation="false"
stopOnFailure="true"> >
<coverage> <coverage>
<include> <include>
<directory suffix=".php">src</directory> <directory suffix=".php">src</directory>

View File

@ -101,6 +101,12 @@ final class API extends AbstractAPI
* @var int * @var int
*/ */
public const LOGGED_IN = 3; 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. * This peer is a user.
* *

View File

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

View File

@ -1269,6 +1269,11 @@ abstract class InternalDoc
{ {
$this->wrapper->getAPI()->logger($param, $level, $file); $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. * 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; return true;
} }
public function getLogger(): Logger
{
return $this->logger;
}
/** @internal */ /** @internal */
public function getQrLoginCancellation(): Cancellation public function getQrLoginCancellation(): Cancellation
{ {

View File

@ -137,7 +137,10 @@ use Webmozart\Assert\Assert;
Logger::log("$e", Logger::FATAL_ERROR); Logger::log("$e", Logger::FATAL_ERROR);
Logger::log('Got exception in IPC server, exiting...', Logger::FATAL_ERROR); Logger::log('Got exception in IPC server, exiting...', Logger::FATAL_ERROR);
$ipc = $session->getIpcState(); $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!'); Logger::log('Reporting error!');
$session->storeIpcState(new IpcState($runnerId, $e)); $session->storeIpcState(new IpcState($runnerId, $e));
Logger::log('Reported error!'); Logger::log('Reported error!');

View File

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

View File

@ -326,6 +326,7 @@ trait ResponseHandler
$phone = isset($this->API->authorization['user']['phone']) ? '+' . $this->API->authorization['user']['phone'] : '???'; $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->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()); return fn () => new RPCErrorException($response['error_message'], $response['error_code'], $request->getConstructor());
case 'AUTH_KEY_UNREGISTERED': case 'AUTH_KEY_UNREGISTERED':
case 'AUTH_KEY_INVALID': 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); $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'; $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->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()); return fn () => new RPCErrorException($response['error_message'], $response['error_code'], $request->getConstructor());
} }
EventLoop::queue(function () use ($request): void { EventLoop::queue(function () use ($request): void {

View File

@ -21,6 +21,8 @@ declare(strict_types=1);
namespace danog\MadelineProto; namespace danog\MadelineProto;
use danog\MadelineProto\Ipc\IpcState; use danog\MadelineProto\Ipc\IpcState;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use const LOCK_EX; use const LOCK_EX;
use const LOCK_SH; use const LOCK_SH;
@ -29,10 +31,12 @@ use const PHP_MINOR_VERSION;
use const PHP_VERSION; use const PHP_VERSION;
use function Amp\File\createDirectory; use function Amp\File\createDirectory;
use function Amp\File\deleteDirectory;
use function Amp\File\deleteFile; use function Amp\File\deleteFile;
use function Amp\File\exists; use function Amp\File\exists;
use function Amp\File\isDirectory; use function Amp\File\isDirectory;
use function Amp\File\isFile; use function Amp\File\isFile;
use function Amp\File\listFiles;
use function Amp\File\move; use function Amp\File\move;
use function Amp\File\openFile; use function Amp\File\openFile;
use function Amp\File\write; 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. * Serialize object to file.
*/ */

View File

@ -24,15 +24,19 @@ use Amp\Cancellation;
use Amp\CancelledException; use Amp\CancelledException;
use Amp\DeferredCancellation; use Amp\DeferredCancellation;
use Amp\DeferredFuture; use Amp\DeferredFuture;
use Amp\SignalException;
use AssertionError; use AssertionError;
use danog\MadelineProto\API; use danog\MadelineProto\API;
use danog\MadelineProto\Exception; use danog\MadelineProto\Exception;
use danog\MadelineProto\Lang; use danog\MadelineProto\Lang;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\LogoutException;
use danog\MadelineProto\Magic;
use danog\MadelineProto\MTProto\PermAuthKey; use danog\MadelineProto\MTProto\PermAuthKey;
use danog\MadelineProto\MTProtoTools\PasswordCalculator; use danog\MadelineProto\MTProtoTools\PasswordCalculator;
use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\RPCErrorException;
use danog\MadelineProto\Settings; use danog\MadelineProto\Settings;
use danog\MadelineProto\Shutdown;
use danog\MadelineProto\TL\Types\LoginQrCode; use danog\MadelineProto\TL\Types\LoginQrCode;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
@ -142,6 +146,19 @@ trait Login
$c->cancel(); $c->cancel();
return $c->getCancellation(); 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 */ /** @internal */
public function waitQrLogin(): void public function waitQrLogin(): void
{ {

View File

@ -5,8 +5,8 @@ declare(strict_types=1);
namespace danog\MadelineProto\Test; namespace danog\MadelineProto\Test;
use Amp\PHPUnit\AsyncTestCase; use Amp\PHPUnit\AsyncTestCase;
use danog\MadelineProto\API;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\Settings; use danog\MadelineProto\Settings;
use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream; use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream;
use danog\MadelineProto\Stream\MTProtoTransport\FullStream; 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 public function testCanUseProtocol(string $transport, bool $obfuscated, string $protocol, bool $test_mode, bool $ipv6): void
{ {
$this->markTestSkipped();
return;/*
$settings = new Settings; $settings = new Settings;
$settings->getAppInfo() $settings->getAppInfo()
->setApiHash(\getenv('API_HASH')) ->setApiHash(\getenv('API_HASH'))
@ -54,11 +52,17 @@ final class DataCenterTest extends AsyncTestCase
->setTransport($transport) ->setTransport($transport)
->setRetry(false) ->setRetry(false)
->setTimeout(10); ->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); // Init session
$this->assertEquals($ping, $API->methodCallAsyncRead('ping', ['ping_id' => $ping])['ping_id']);*/ $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 public function protocolProvider(): Generator