mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-08 04:38:35 +00:00
Introduce support for Translatable disconnection messages
this allows localizing disconnection screens (at least, once #4512 has been addressed) and the disconnect reasons shown on the console. We already had disconnect messages implicitly localized in a few places, so this is just formalizing it. This does break BC with any code that previously passed translation keys as the disconnect screen message, because they'll no longer be translated (only Translatables will be translatated now).
This commit is contained in:
parent
9796dfd4d9
commit
f173b91ca1
@ -26,6 +26,7 @@ namespace pocketmine\event\player;
|
|||||||
use pocketmine\event\Cancellable;
|
use pocketmine\event\Cancellable;
|
||||||
use pocketmine\event\CancellableTrait;
|
use pocketmine\event\CancellableTrait;
|
||||||
use pocketmine\event\Event;
|
use pocketmine\event\Event;
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +36,7 @@ use pocketmine\network\mcpe\NetworkSession;
|
|||||||
class PlayerDuplicateLoginEvent extends Event implements Cancellable{
|
class PlayerDuplicateLoginEvent extends Event implements Cancellable{
|
||||||
use CancellableTrait;
|
use CancellableTrait;
|
||||||
|
|
||||||
private string $disconnectMessage = "Logged in from another location";
|
private Translatable|string $disconnectMessage = "Logged in from another location";
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private NetworkSession $connectingSession,
|
private NetworkSession $connectingSession,
|
||||||
@ -53,11 +54,11 @@ class PlayerDuplicateLoginEvent extends Event implements Cancellable{
|
|||||||
/**
|
/**
|
||||||
* Returns the message shown to the session which gets disconnected.
|
* Returns the message shown to the session which gets disconnected.
|
||||||
*/
|
*/
|
||||||
public function getDisconnectMessage() : string{
|
public function getDisconnectMessage() : Translatable|string{
|
||||||
return $this->disconnectMessage;
|
return $this->disconnectMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDisconnectMessage(string $message) : void{
|
public function setDisconnectMessage(Translatable|string $message) : void{
|
||||||
$this->disconnectMessage = $message;
|
$this->disconnectMessage = $message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ class PlayerKickEvent extends PlayerEvent implements Cancellable{
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Player $player,
|
Player $player,
|
||||||
protected string $reason,
|
protected Translatable|string $reason,
|
||||||
protected Translatable|string $quitMessage
|
protected Translatable|string $quitMessage
|
||||||
){
|
){
|
||||||
$this->player = $player;
|
$this->player = $player;
|
||||||
@ -46,7 +46,7 @@ class PlayerKickEvent extends PlayerEvent implements Cancellable{
|
|||||||
* Sets the message shown on the kicked player's disconnection screen.
|
* Sets the message shown on the kicked player's disconnection screen.
|
||||||
* This message is also displayed in the console and server log.
|
* This message is also displayed in the console and server log.
|
||||||
*/
|
*/
|
||||||
public function setReason(string $reason) : void{
|
public function setReason(Translatable|string $reason) : void{
|
||||||
$this->reason = $reason;
|
$this->reason = $reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class PlayerKickEvent extends PlayerEvent implements Cancellable{
|
|||||||
* This message is also displayed in the console and server log.
|
* This message is also displayed in the console and server log.
|
||||||
* When kicked by the /kick command, the default is something like "Kicked by admin.".
|
* When kicked by the /kick command, the default is something like "Kicked by admin.".
|
||||||
*/
|
*/
|
||||||
public function getReason() : string{
|
public function getReason() : Translatable|string{
|
||||||
return $this->reason;
|
return $this->reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine\event\player;
|
|||||||
|
|
||||||
use pocketmine\event\Cancellable;
|
use pocketmine\event\Cancellable;
|
||||||
use pocketmine\event\Event;
|
use pocketmine\event\Event;
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\player\PlayerInfo;
|
use pocketmine\player\PlayerInfo;
|
||||||
use function array_keys;
|
use function array_keys;
|
||||||
use function count;
|
use function count;
|
||||||
@ -52,7 +53,7 @@ class PlayerPreLoginEvent extends Event implements Cancellable{
|
|||||||
self::KICK_REASON_BANNED
|
self::KICK_REASON_BANNED
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var string[] reason const => associated message */
|
/** @var Translatable[]|string[] reason const => associated message */
|
||||||
protected array $kickReasons = [];
|
protected array $kickReasons = [];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -107,7 +108,7 @@ class PlayerPreLoginEvent extends Event implements Cancellable{
|
|||||||
* Sets a reason to disallow the player to continue continue authenticating, with a message.
|
* Sets a reason to disallow the player to continue continue authenticating, with a message.
|
||||||
* This can also be used to change kick messages for already-set flags.
|
* This can also be used to change kick messages for already-set flags.
|
||||||
*/
|
*/
|
||||||
public function setKickReason(int $flag, string $message) : void{
|
public function setKickReason(int $flag, Translatable|string $message) : void{
|
||||||
$this->kickReasons[$flag] = $message;
|
$this->kickReasons[$flag] = $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +139,7 @@ class PlayerPreLoginEvent extends Event implements Cancellable{
|
|||||||
/**
|
/**
|
||||||
* Returns the kick message provided for the given kick flag, or null if not set.
|
* Returns the kick message provided for the given kick flag, or null if not set.
|
||||||
*/
|
*/
|
||||||
public function getKickMessage(int $flag) : ?string{
|
public function getKickMessage(int $flag) : Translatable|string|null{
|
||||||
return $this->kickReasons[$flag] ?? null;
|
return $this->kickReasons[$flag] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +151,7 @@ class PlayerPreLoginEvent extends Event implements Cancellable{
|
|||||||
*
|
*
|
||||||
* @see PlayerPreLoginEvent::KICK_REASON_PRIORITY
|
* @see PlayerPreLoginEvent::KICK_REASON_PRIORITY
|
||||||
*/
|
*/
|
||||||
public function getFinalKickMessage() : string{
|
public function getFinalKickMessage() : Translatable|string{
|
||||||
foreach(self::KICK_REASON_PRIORITY as $p){
|
foreach(self::KICK_REASON_PRIORITY as $p){
|
||||||
if(isset($this->kickReasons[$p])){
|
if(isset($this->kickReasons[$p])){
|
||||||
return $this->kickReasons[$p];
|
return $this->kickReasons[$p];
|
||||||
|
@ -40,7 +40,7 @@ class PlayerQuitEvent extends PlayerEvent{
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
Player $player,
|
Player $player,
|
||||||
protected Translatable|string $quitMessage,
|
protected Translatable|string $quitMessage,
|
||||||
protected string $quitReason
|
protected Translatable|string $quitReason
|
||||||
){
|
){
|
||||||
$this->player = $player;
|
$this->player = $player;
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ class PlayerQuitEvent extends PlayerEvent{
|
|||||||
/**
|
/**
|
||||||
* Returns the disconnect reason shown in the server log and on the console.
|
* Returns the disconnect reason shown in the server log and on the console.
|
||||||
*/
|
*/
|
||||||
public function getQuitReason() : string{
|
public function getQuitReason() : Translatable|string{
|
||||||
return $this->quitReason;
|
return $this->quitReason;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network;
|
namespace pocketmine\network;
|
||||||
|
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use function count;
|
use function count;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
@ -74,7 +75,7 @@ class NetworkSessionManager{
|
|||||||
/**
|
/**
|
||||||
* Terminates all connected sessions with the given reason.
|
* Terminates all connected sessions with the given reason.
|
||||||
*/
|
*/
|
||||||
public function close(string $reason = "") : void{
|
public function close(Translatable|string $reason = "") : void{
|
||||||
foreach($this->sessions as $session){
|
foreach($this->sessions as $session){
|
||||||
$session->disconnect($reason);
|
$session->disconnect($reason);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ use pocketmine\event\server\DataPacketReceiveEvent;
|
|||||||
use pocketmine\event\server\DataPacketSendEvent;
|
use pocketmine\event\server\DataPacketSendEvent;
|
||||||
use pocketmine\form\Form;
|
use pocketmine\form\Form;
|
||||||
use pocketmine\lang\KnownTranslationFactory;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
|
||||||
use pocketmine\lang\Translatable;
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
@ -230,9 +229,7 @@ class NetworkSession{
|
|||||||
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
|
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
|
||||||
$this->logger->setPrefix($this->getLogPrefix());
|
$this->logger->setPrefix($this->getLogPrefix());
|
||||||
},
|
},
|
||||||
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
|
\Closure::fromCallable([$this, "setAuthenticationStatus"])
|
||||||
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
|
|
||||||
}
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +539,7 @@ class NetworkSession{
|
|||||||
/**
|
/**
|
||||||
* @phpstan-param \Closure() : void $func
|
* @phpstan-param \Closure() : void $func
|
||||||
*/
|
*/
|
||||||
private function tryDisconnect(\Closure $func, string $reason) : void{
|
private function tryDisconnect(\Closure $func, Translatable|string $reason) : void{
|
||||||
if($this->connected && !$this->disconnectGuard){
|
if($this->connected && !$this->disconnectGuard){
|
||||||
$this->disconnectGuard = true;
|
$this->disconnectGuard = true;
|
||||||
$func();
|
$func();
|
||||||
@ -555,7 +552,14 @@ class NetworkSession{
|
|||||||
$this->disposeHooks->clear();
|
$this->disposeHooks->clear();
|
||||||
$this->setHandler(null);
|
$this->setHandler(null);
|
||||||
$this->connected = false;
|
$this->connected = false;
|
||||||
$this->logger->info("Session closed due to $reason");
|
|
||||||
|
if($reason instanceof Translatable){
|
||||||
|
$translated = $this->server->getLanguage()->translate($reason);
|
||||||
|
}else{
|
||||||
|
$translated = $reason;
|
||||||
|
}
|
||||||
|
//TODO: l10n
|
||||||
|
$this->logger->info("Session closed due to $translated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,13 +571,22 @@ class NetworkSession{
|
|||||||
$this->invManager = null;
|
$this->invManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function sendDisconnectPacket(Translatable|string $reason) : void{
|
||||||
|
if($reason instanceof Translatable){
|
||||||
|
$translated = $this->server->getLanguage()->translate($reason);
|
||||||
|
}else{
|
||||||
|
$translated = $reason;
|
||||||
|
}
|
||||||
|
$this->sendDataPacket(DisconnectPacket::create($translated));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects the session, destroying the associated player (if it exists).
|
* Disconnects the session, destroying the associated player (if it exists).
|
||||||
*/
|
*/
|
||||||
public function disconnect(string $reason, bool $notify = true) : void{
|
public function disconnect(Translatable|string $reason, bool $notify = true) : void{
|
||||||
$this->tryDisconnect(function() use ($reason, $notify) : void{
|
$this->tryDisconnect(function() use ($reason, $notify) : void{
|
||||||
if($notify){
|
if($notify){
|
||||||
$this->sendDataPacket(DisconnectPacket::create($reason));
|
$this->sendDisconnectPacket($reason);
|
||||||
}
|
}
|
||||||
if($this->player !== null){
|
if($this->player !== null){
|
||||||
$this->player->onPostDisconnect($reason, null);
|
$this->player->onPostDisconnect($reason, null);
|
||||||
@ -593,7 +606,7 @@ class NetworkSession{
|
|||||||
/**
|
/**
|
||||||
* Instructs the remote client to connect to a different server.
|
* Instructs the remote client to connect to a different server.
|
||||||
*/
|
*/
|
||||||
public function transfer(string $ip, int $port, string $reason = "transfer") : void{
|
public function transfer(string $ip, int $port, Translatable|string $reason = "transfer") : void{
|
||||||
$this->tryDisconnect(function() use ($ip, $port, $reason) : void{
|
$this->tryDisconnect(function() use ($ip, $port, $reason) : void{
|
||||||
$this->sendDataPacket(TransferPacket::create($ip, $port), true);
|
$this->sendDataPacket(TransferPacket::create($ip, $port), true);
|
||||||
if($this->player !== null){
|
if($this->player !== null){
|
||||||
@ -605,9 +618,9 @@ class NetworkSession{
|
|||||||
/**
|
/**
|
||||||
* Called by the Player when it is closed (for example due to getting kicked).
|
* Called by the Player when it is closed (for example due to getting kicked).
|
||||||
*/
|
*/
|
||||||
public function onPlayerDestroyed(string $reason) : void{
|
public function onPlayerDestroyed(Translatable|string $reason) : void{
|
||||||
$this->tryDisconnect(function() use ($reason) : void{
|
$this->tryDisconnect(function() use ($reason) : void{
|
||||||
$this->sendDataPacket(DisconnectPacket::create($reason));
|
$this->sendDisconnectPacket($reason);
|
||||||
}, $reason);
|
}, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,7 +636,7 @@ class NetworkSession{
|
|||||||
}, $reason);
|
}, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAuthenticationStatus(bool $authenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
|
private function setAuthenticationStatus(bool $authenticated, bool $authRequired, Translatable|string|null $error, ?string $clientPubKey) : void{
|
||||||
if(!$this->connected){
|
if(!$this->connected){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -636,7 +649,7 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($error !== null){
|
if($error !== null){
|
||||||
$this->disconnect($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_disconnect_invalidSession($this->server->getLanguage()->translateString($error))));
|
$this->disconnect(KnownTranslationFactory::pocketmine_disconnect_invalidSession($error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -645,7 +658,7 @@ class NetworkSession{
|
|||||||
|
|
||||||
if(!$this->authenticated){
|
if(!$this->authenticated){
|
||||||
if($authRequired){
|
if($authRequired){
|
||||||
$this->disconnect(KnownTranslationKeys::DISCONNECTIONSCREEN_NOTAUTHENTICATED);
|
$this->disconnect(KnownTranslationFactory::disconnectionScreen_notAuthenticated());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if($this->info instanceof XboxLivePlayerInfo){
|
if($this->info instanceof XboxLivePlayerInfo){
|
||||||
|
@ -23,7 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe\auth;
|
namespace pocketmine\network\mcpe\auth;
|
||||||
|
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\network\mcpe\JwtException;
|
use pocketmine\network\mcpe\JwtException;
|
||||||
use pocketmine\network\mcpe\JwtUtils;
|
use pocketmine\network\mcpe\JwtUtils;
|
||||||
use pocketmine\network\mcpe\protocol\types\login\JwtChainLinkBody;
|
use pocketmine\network\mcpe\protocol\types\login\JwtChainLinkBody;
|
||||||
@ -49,7 +50,7 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
* keychain is invalid for whatever reason (bad signature, not in nbf-exp window, etc). If this is non-null, the
|
* keychain is invalid for whatever reason (bad signature, not in nbf-exp window, etc). If this is non-null, the
|
||||||
* keychain might have been tampered with. The player will always be disconnected if this is non-null.
|
* keychain might have been tampered with. The player will always be disconnected if this is non-null.
|
||||||
*/
|
*/
|
||||||
private ?string $error = "Unknown";
|
private Translatable|string|null $error = "Unknown";
|
||||||
/**
|
/**
|
||||||
* Whether the player is logged into Xbox Live. This is true if any link in the keychain is signed with the Mojang
|
* Whether the player is logged into Xbox Live. This is true if any link in the keychain is signed with the Mojang
|
||||||
* root public key.
|
* root public key.
|
||||||
@ -59,7 +60,7 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $chainJwts
|
* @param string[] $chainJwts
|
||||||
* @phpstan-param \Closure(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPublicKey) : void $onCompletion
|
* @phpstan-param \Closure(bool $isAuthenticated, bool $authRequired, Translatable|string|null $error, ?string $clientPublicKey) : void $onCompletion
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
array $chainJwts,
|
array $chainJwts,
|
||||||
@ -76,7 +77,7 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
$this->clientPublicKey = $this->validateChain();
|
$this->clientPublicKey = $this->validateChain();
|
||||||
$this->error = null;
|
$this->error = null;
|
||||||
}catch(VerifyLoginException $e){
|
}catch(VerifyLoginException $e){
|
||||||
$this->error = $e->getMessage();
|
$this->error = $e->getDisconnectMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +110,8 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
try{
|
try{
|
||||||
[$headersArray, $claimsArray, ] = JwtUtils::parse($jwt);
|
[$headersArray, $claimsArray, ] = JwtUtils::parse($jwt);
|
||||||
}catch(JwtException $e){
|
}catch(JwtException $e){
|
||||||
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), 0, $e);
|
//TODO: we shouldn't be showing internal information like this to the client
|
||||||
|
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$mapper = new \JsonMapper();
|
$mapper = new \JsonMapper();
|
||||||
@ -121,21 +123,23 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
/** @var JwtHeader $headers */
|
/** @var JwtHeader $headers */
|
||||||
$headers = $mapper->map($headersArray, new JwtHeader());
|
$headers = $mapper->map($headersArray, new JwtHeader());
|
||||||
}catch(\JsonMapper_Exception $e){
|
}catch(\JsonMapper_Exception $e){
|
||||||
throw new VerifyLoginException("Invalid JWT header: " . $e->getMessage(), 0, $e);
|
//TODO: we shouldn't be showing internal information like this to the client
|
||||||
|
throw new VerifyLoginException("Invalid JWT header: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$headerDerKey = base64_decode($headers->x5u, true);
|
$headerDerKey = base64_decode($headers->x5u, true);
|
||||||
if($headerDerKey === false){
|
if($headerDerKey === false){
|
||||||
|
//TODO: we shouldn't be showing internal information like this to the client
|
||||||
throw new VerifyLoginException("Invalid JWT public key: base64 decoding error decoding x5u");
|
throw new VerifyLoginException("Invalid JWT public key: base64 decoding error decoding x5u");
|
||||||
}
|
}
|
||||||
|
|
||||||
if($currentPublicKey === null){
|
if($currentPublicKey === null){
|
||||||
if(!$first){
|
if(!$first){
|
||||||
throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_MISSINGKEY);
|
throw new VerifyLoginException("Missing JWT public key", KnownTranslationFactory::pocketmine_disconnect_invalidSession_missingKey());
|
||||||
}
|
}
|
||||||
}elseif($headerDerKey !== $currentPublicKey){
|
}elseif($headerDerKey !== $currentPublicKey){
|
||||||
//Fast path: if the header key doesn't match what we expected, the signature isn't going to validate anyway
|
//Fast path: if the header key doesn't match what we expected, the signature isn't going to validate anyway
|
||||||
throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_BADSIGNATURE);
|
throw new VerifyLoginException("Invalid JWT signature", KnownTranslationFactory::pocketmine_disconnect_invalidSession_badSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@ -145,10 +149,10 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
if(!JwtUtils::verify($jwt, $signingKeyOpenSSL)){
|
if(!JwtUtils::verify($jwt, $signingKeyOpenSSL)){
|
||||||
throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_BADSIGNATURE);
|
throw new VerifyLoginException("Invalid JWT signature", KnownTranslationFactory::pocketmine_disconnect_invalidSession_badSignature());
|
||||||
}
|
}
|
||||||
}catch(JwtException $e){
|
}catch(JwtException $e){
|
||||||
throw new VerifyLoginException($e->getMessage(), 0, $e);
|
throw new VerifyLoginException($e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($headers->x5u === self::MOJANG_ROOT_PUBLIC_KEY){
|
if($headers->x5u === self::MOJANG_ROOT_PUBLIC_KEY){
|
||||||
@ -164,16 +168,16 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
/** @var JwtChainLinkBody $claims */
|
/** @var JwtChainLinkBody $claims */
|
||||||
$claims = $mapper->map($claimsArray, new JwtChainLinkBody());
|
$claims = $mapper->map($claimsArray, new JwtChainLinkBody());
|
||||||
}catch(\JsonMapper_Exception $e){
|
}catch(\JsonMapper_Exception $e){
|
||||||
throw new VerifyLoginException("Invalid chain link body: " . $e->getMessage(), 0, $e);
|
throw new VerifyLoginException("Invalid chain link body: " . $e->getMessage(), null, 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$time = time();
|
$time = time();
|
||||||
if(isset($claims->nbf) && $claims->nbf > $time + self::CLOCK_DRIFT_MAX){
|
if(isset($claims->nbf) && $claims->nbf > $time + self::CLOCK_DRIFT_MAX){
|
||||||
throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_TOOEARLY);
|
throw new VerifyLoginException("JWT not yet valid", KnownTranslationFactory::pocketmine_disconnect_invalidSession_tooEarly());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($claims->exp) && $claims->exp < $time - self::CLOCK_DRIFT_MAX){
|
if(isset($claims->exp) && $claims->exp < $time - self::CLOCK_DRIFT_MAX){
|
||||||
throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_TOOLATE);
|
throw new VerifyLoginException("JWT expired", KnownTranslationFactory::pocketmine_disconnect_invalidSession_tooLate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($claims->identityPublicKey)){
|
if(isset($claims->identityPublicKey)){
|
||||||
@ -188,7 +192,7 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
public function onCompletion() : void{
|
public function onCompletion() : void{
|
||||||
/**
|
/**
|
||||||
* @var \Closure $callback
|
* @var \Closure $callback
|
||||||
* @phpstan-var \Closure(bool, bool, ?string, ?string) : void $callback
|
* @phpstan-var \Closure(bool, bool, Translatable|string|null, ?string) : void $callback
|
||||||
*/
|
*/
|
||||||
$callback = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
|
$callback = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
|
||||||
$callback($this->authenticated, $this->authRequired, $this->error, $this->clientPublicKey);
|
$callback($this->authenticated, $this->authRequired, $this->error, $this->clientPublicKey);
|
||||||
|
@ -23,6 +23,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe\auth;
|
namespace pocketmine\network\mcpe\auth;
|
||||||
|
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
|
|
||||||
class VerifyLoginException extends \RuntimeException{
|
class VerifyLoginException extends \RuntimeException{
|
||||||
|
|
||||||
|
private Translatable|string $disconnectMessage;
|
||||||
|
|
||||||
|
public function __construct(string $message, Translatable|string|null $disconnectMessage = null, int $code = 0, ?\Throwable $previous = null){
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
$this->disconnectMessage = $disconnectMessage ?? $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisconnectMessage() : Translatable|string{ return $this->disconnectMessage; }
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ namespace pocketmine\network\mcpe\handler;
|
|||||||
|
|
||||||
use pocketmine\entity\InvalidSkinException;
|
use pocketmine\entity\InvalidSkinException;
|
||||||
use pocketmine\event\player\PlayerPreLoginEvent;
|
use pocketmine\event\player\PlayerPreLoginEvent;
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\network\mcpe\auth\ProcessLoginTask;
|
use pocketmine\network\mcpe\auth\ProcessLoginTask;
|
||||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
||||||
use pocketmine\network\mcpe\JwtException;
|
use pocketmine\network\mcpe\JwtException;
|
||||||
@ -51,7 +52,7 @@ use function is_array;
|
|||||||
class LoginPacketHandler extends PacketHandler{
|
class LoginPacketHandler extends PacketHandler{
|
||||||
/**
|
/**
|
||||||
* @phpstan-param \Closure(PlayerInfo) : void $playerInfoConsumer
|
* @phpstan-param \Closure(PlayerInfo) : void $playerInfoConsumer
|
||||||
* @phpstan-param \Closure(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void $authCallback
|
* @phpstan-param \Closure(bool $isAuthenticated, bool $authRequired, Translatable|string|null $error, ?string $clientPubKey) : void $authCallback
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Server $server,
|
private Server $server,
|
||||||
@ -70,7 +71,7 @@ class LoginPacketHandler extends PacketHandler{
|
|||||||
$extraData = $this->fetchAuthData($packet->chainDataJwt);
|
$extraData = $this->fetchAuthData($packet->chainDataJwt);
|
||||||
|
|
||||||
if(!Player::isValidUserName($extraData->displayName)){
|
if(!Player::isValidUserName($extraData->displayName)){
|
||||||
$this->session->disconnect(KnownTranslationKeys::DISCONNECTIONSCREEN_INVALIDNAME);
|
$this->session->disconnect(KnownTranslationFactory::disconnectionScreen_invalidName());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ class LoginPacketHandler extends PacketHandler{
|
|||||||
$skin = SkinAdapterSingleton::get()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
$skin = SkinAdapterSingleton::get()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
||||||
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
||||||
$this->session->getLogger()->debug("Invalid skin: " . $e->getMessage());
|
$this->session->getLogger()->debug("Invalid skin: " . $e->getMessage());
|
||||||
$this->session->disconnect(KnownTranslationKeys::DISCONNECTIONSCREEN_INVALIDSKIN);
|
$this->session->disconnect(KnownTranslationFactory::disconnectionScreen_invalidSkin());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -116,12 +117,14 @@ class LoginPacketHandler extends PacketHandler{
|
|||||||
$this->server->requiresAuthentication()
|
$this->server->requiresAuthentication()
|
||||||
);
|
);
|
||||||
if($this->server->getNetwork()->getConnectionCount() > $this->server->getMaxPlayers()){
|
if($this->server->getNetwork()->getConnectionCount() > $this->server->getMaxPlayers()){
|
||||||
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_FULL, KnownTranslationKeys::DISCONNECTIONSCREEN_SERVERFULL);
|
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_FULL, KnownTranslationFactory::disconnectionScreen_serverFull());
|
||||||
}
|
}
|
||||||
if(!$this->server->isWhitelisted($playerInfo->getUsername())){
|
if(!$this->server->isWhitelisted($playerInfo->getUsername())){
|
||||||
|
//TODO: l10n
|
||||||
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED, "Server is whitelisted");
|
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED, "Server is whitelisted");
|
||||||
}
|
}
|
||||||
if($this->server->getNameBans()->isBanned($playerInfo->getUsername()) || $this->server->getIPBans()->isBanned($this->session->getIp())){
|
if($this->server->getNameBans()->isBanned($playerInfo->getUsername()) || $this->server->getIPBans()->isBanned($this->session->getIp())){
|
||||||
|
//TODO: l10n
|
||||||
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_BANNED, "You are banned");
|
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_BANNED, "You are banned");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe\handler;
|
namespace pocketmine\network\mcpe\handler;
|
||||||
|
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
|
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
|
||||||
@ -86,7 +86,7 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
|||||||
|
|
||||||
private function disconnectWithError(string $error) : void{
|
private function disconnectWithError(string $error) : void{
|
||||||
$this->session->getLogger()->error("Error downloading resource packs: " . $error);
|
$this->session->getLogger()->error("Error downloading resource packs: " . $error);
|
||||||
$this->session->disconnect(KnownTranslationKeys::DISCONNECTIONSCREEN_RESOURCEPACK);
|
$this->session->disconnect(KnownTranslationFactory::disconnectionScreen_resourcePack());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
|
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
|
||||||
|
@ -96,7 +96,6 @@ use pocketmine\item\Item;
|
|||||||
use pocketmine\item\ItemUseResult;
|
use pocketmine\item\ItemUseResult;
|
||||||
use pocketmine\item\Releasable;
|
use pocketmine\item\Releasable;
|
||||||
use pocketmine\lang\KnownTranslationFactory;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
|
||||||
use pocketmine\lang\Language;
|
use pocketmine\lang\Language;
|
||||||
use pocketmine\lang\Translatable;
|
use pocketmine\lang\Translatable;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
@ -2102,13 +2101,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
/**
|
/**
|
||||||
* Kicks a player from the server
|
* Kicks a player from the server
|
||||||
*/
|
*/
|
||||||
public function kick(string $reason = "", Translatable|string|null $quitMessage = null) : bool{
|
public function kick(Translatable|string $reason = "", Translatable|string|null $quitMessage = null) : bool{
|
||||||
$ev = new PlayerKickEvent($this, $reason, $quitMessage ?? $this->getLeaveMessage());
|
$ev = new PlayerKickEvent($this, $reason, $quitMessage ?? $this->getLeaveMessage());
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$reason = $ev->getReason();
|
$reason = $ev->getReason();
|
||||||
if($reason === ""){
|
if($reason === ""){
|
||||||
$reason = KnownTranslationKeys::DISCONNECTIONSCREEN_NOREASON;
|
$reason = KnownTranslationFactory::disconnectionScreen_noReason();
|
||||||
}
|
}
|
||||||
$this->disconnect($reason, $ev->getQuitMessage());
|
$this->disconnect($reason, $ev->getQuitMessage());
|
||||||
|
|
||||||
@ -2127,10 +2126,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
*
|
*
|
||||||
* Note for internals developers: Do not call this from network sessions. It will cause a feedback loop.
|
* Note for internals developers: Do not call this from network sessions. It will cause a feedback loop.
|
||||||
*
|
*
|
||||||
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
|
* @param Translatable|string $reason Shown on the disconnect screen, and in the server log
|
||||||
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
|
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
|
||||||
*/
|
*/
|
||||||
public function disconnect(string $reason, Translatable|string|null $quitMessage = null) : void{
|
public function disconnect(Translatable|string $reason, Translatable|string|null $quitMessage = null) : void{
|
||||||
if(!$this->isConnected()){
|
if(!$this->isConnected()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2143,10 +2142,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
* @internal
|
* @internal
|
||||||
* This method executes post-disconnect actions and cleanups.
|
* This method executes post-disconnect actions and cleanups.
|
||||||
*
|
*
|
||||||
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
|
|
||||||
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
|
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
|
||||||
*/
|
*/
|
||||||
public function onPostDisconnect(string $reason, Translatable|string|null $quitMessage) : void{
|
public function onPostDisconnect(Translatable|string $reason, Translatable|string|null $quitMessage) : void{
|
||||||
if($this->isConnected()){
|
if($this->isConnected()){
|
||||||
throw new \LogicException("Player is still connected");
|
throw new \LogicException("Player is still connected");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user