64 private \Closure $playerInfoConsumer,
65 private \Closure $authCallback
68 public function handleLogin(
LoginPacket $packet) : bool{
73 if(!Player::isValidUserName($extraData->displayName)){
74 $this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_invalidName());
83 }
catch(\InvalidArgumentException | InvalidSkinException $e){
84 $this->session->disconnectWithError(
85 reason:
"Invalid skin: " . $e->getMessage(),
86 disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_invalidSkin()
92 if(!Uuid::isValid($extraData->identity)){
93 throw new PacketHandlingException(
"Invalid login UUID");
95 $uuid = Uuid::fromString($extraData->identity);
96 $arrClientData = (array) $clientData;
97 $arrClientData[
"TitleID"] = $extraData->titleId;
99 if($extraData->XUID !==
""){
100 $playerInfo =
new XboxLivePlayerInfo(
102 $extraData->displayName,
105 $clientData->LanguageCode,
109 $playerInfo =
new PlayerInfo(
110 $extraData->displayName,
113 $clientData->LanguageCode,
117 ($this->playerInfoConsumer)($playerInfo);
119 $ev =
new PlayerPreLoginEvent(
121 $this->session->getIp(),
122 $this->session->getPort(),
123 $this->server->requiresAuthentication()
125 if($this->
server->getNetwork()->getValidConnectionCount() > $this->server->getMaxPlayers()){
126 $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_SERVER_FULL, KnownTranslationFactory::disconnectionScreen_serverFull());
128 if(!$this->
server->isWhitelisted($playerInfo->getUsername())){
129 $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_SERVER_WHITELISTED, KnownTranslationFactory::pocketmine_disconnect_whitelisted());
133 if(($banEntry = $this->
server->getNameBans()->getEntry($playerInfo->getUsername())) !==
null){
134 $banReason = $banEntry->getReason();
135 $banMessage = $banReason ===
"" ? KnownTranslationFactory::pocketmine_disconnect_ban_noReason() : KnownTranslationFactory::pocketmine_disconnect_ban($banReason);
136 }elseif(($banEntry = $this->
server->getIPBans()->getEntry($this->session->getIp())) !==
null){
137 $banReason = $banEntry->getReason();
138 $banMessage = KnownTranslationFactory::pocketmine_disconnect_ban($banReason !==
"" ? $banReason : KnownTranslationFactory::pocketmine_disconnect_ban_ip());
140 if($banMessage !==
null){
141 $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_BANNED, $banMessage);
145 if(!$ev->isAllowed()){
146 $this->session->disconnect($ev->getFinalDisconnectReason(), $ev->getFinalDisconnectScreenMessage());
150 $this->
processLogin($authInfo->Token, AuthenticationType::from($authInfo->AuthenticationType), $jwtChain->chain, $packet->clientDataJwt, $ev->isAuthRequired());
160 $authInfoJson = json_decode($authInfo, associative: false, flags: JSON_THROW_ON_ERROR);
161 }
catch(\JsonException $e){
162 throw PacketHandlingException::wrap($e);
164 if(!is_object($authInfoJson)){
165 throw new \RuntimeException(
"Unexpected type for auth info data: " . gettype($authInfoJson) .
", expected object");
168 $mapper = new \JsonMapper();
169 $mapper->bExceptionOnMissingData =
true;
170 $mapper->bExceptionOnUndefinedProperty =
true;
171 $mapper->bStrictObjectTypeChecking =
true;
173 $clientData = $mapper->map($authInfoJson,
new AuthenticationInfo());
174 }
catch(\JsonMapper_Exception $e){
175 throw PacketHandlingException::wrap($e);
185 $jwtChainJson = json_decode($chainDataJwt, associative: false, flags: JSON_THROW_ON_ERROR);
186 }
catch(\JsonException $e){
187 throw PacketHandlingException::wrap($e);
189 if(!is_object($jwtChainJson)){
190 throw new \RuntimeException(
"Unexpected type for JWT chain data: " . gettype($jwtChainJson) .
", expected object");
193 $mapper = new \JsonMapper();
194 $mapper->bExceptionOnMissingData =
true;
195 $mapper->bExceptionOnUndefinedProperty =
true;
196 $mapper->bStrictObjectTypeChecking =
true;
198 $clientData = $mapper->map($jwtChainJson,
new JwtChain());
199 }
catch(\JsonMapper_Exception $e){
200 throw PacketHandlingException::wrap($e);
211 foreach($chain->chain as $jwt){
214 [, $claims, ] = JwtUtils::parse($jwt);
216 throw PacketHandlingException::wrap($e);
218 if(isset($claims[
"extraData"])){
219 if($extraData !==
null){
223 if(!is_array($claims[
"extraData"])){
226 $mapper = new \JsonMapper();
227 $mapper->bEnforceMapType =
false;
228 $mapper->bExceptionOnMissingData =
true;
229 $mapper->bExceptionOnUndefinedProperty =
true;
230 $mapper->bStrictObjectTypeChecking =
true;
234 }
catch(\JsonMapper_Exception $e){
235 throw PacketHandlingException::wrap($e);
239 if($extraData ===
null){
250 [, $clientDataClaims, ] =
JwtUtils::parse($clientDataJwt);
252 throw PacketHandlingException::wrap($e);
255 $mapper = new \JsonMapper();
256 $mapper->bEnforceMapType =
false;
257 $mapper->bExceptionOnMissingData =
true;
258 $mapper->bExceptionOnUndefinedProperty =
true;
259 $mapper->bStrictObjectTypeChecking =
true;
261 $clientData = $mapper->map($clientDataClaims,
new ClientData());
262 }
catch(\JsonMapper_Exception $e){
263 throw PacketHandlingException::wrap($e);
276 protected function processLogin(
string $token, AuthenticationType $authType, ?array $legacyCertificate,
string $clientData,
bool $authRequired) : void{
277 if($legacyCertificate === null){
280 $this->
server->getAsyncPool()->submitTask(
new ProcessLoginTask($legacyCertificate, $clientData, $authRequired, $this->authCallback));
281 $this->session->setHandler(
null);