38    public const MOJANG_AUDIENCE = 
"api://auth-minecraft-services/multiplayer";
 
   40    private const CLOCK_DRIFT_MAX = 60;
 
   45    private static function checkExpiry(
JwtBodyRfc7519 $claims) : 
void{
 
   47        if(isset($claims->nbf) && $claims->nbf > $time + self::CLOCK_DRIFT_MAX){
 
   48            throw new VerifyLoginException(
"JWT not yet valid", KnownTranslationFactory::pocketmine_disconnect_invalidSession_tooEarly());
 
   51        if(isset($claims->exp) && $claims->exp < $time - self::CLOCK_DRIFT_MAX){
 
   52            throw new VerifyLoginException(
"JWT expired", KnownTranslationFactory::pocketmine_disconnect_invalidSession_tooLate());
 
   61            if(!
JwtUtils::verify($jwt, $signingKeyDer, ec: false)){
 
   62                throw new VerifyLoginException(
"Invalid JWT signature", KnownTranslationFactory::pocketmine_disconnect_invalidSession_badSignature());
 
   65            throw new VerifyLoginException($e->getMessage(), 
null, 0, $e);
 
   70        }
catch(JwtException $e){
 
   71            throw new VerifyLoginException(
"Failed to parse JWT: " . $e->getMessage(), 
null, 0, $e);
 
   74        $mapper = new \JsonMapper();
 
   75        $mapper->bExceptionOnUndefinedProperty = 
false; 
 
   76        $mapper->bExceptionOnMissingData = 
true;
 
   77        $mapper->bStrictObjectTypeChecking = 
true;
 
   78        $mapper->bEnforceMapType = 
false;
 
   79        $mapper->bRemoveUndefinedAttributes = 
true;
 
   83            $claims = $mapper->map($claimsArray, 
new XboxAuthJwtBody());
 
   84        }
catch(\JsonMapper_Exception $e){
 
   85            throw new VerifyLoginException(
"Invalid chain link body: " . $e->getMessage(), 
null, 0, $e);
 
   88        if(!isset($claims->iss) || $claims->iss !== $issuer){
 
   89            throw new VerifyLoginException(
"Invalid JWT issuer");
 
   92        if(!isset($claims->aud) || $claims->aud !== $audience){
 
   93            throw new VerifyLoginException(
"Invalid JWT audience");
 
   96        self::checkExpiry($claims);
 
 
  105        self::validateSelfSignedToken($jwt, $expectedKeyDer);
 
  108        [, $claimsArray, ] = JwtUtils::parse($jwt);
 
  110        $mapper = new \JsonMapper();
 
  111        $mapper->bExceptionOnUndefinedProperty = 
false; 
 
  112        $mapper->bExceptionOnMissingData = 
true;
 
  113        $mapper->bStrictObjectTypeChecking = 
true;
 
  114        $mapper->bEnforceMapType = 
false;
 
  115        $mapper->bRemoveUndefinedAttributes = 
true;
 
  119        }
catch(\JsonMapper_Exception $e){
 
  123        self::checkExpiry($claims);
 
 
  128    public static function validateSelfSignedToken(
string $jwt, ?
string $expectedKeyDer) : void{
 
  130            [$headersArray, ] = JwtUtils::parse($jwt);
 
  131        }
catch(JwtException $e){
 
  132            throw new VerifyLoginException(
"Failed to parse JWT: " . $e->getMessage(), 
null, 0, $e);
 
  135        $mapper = new \JsonMapper();
 
  136        $mapper->bExceptionOnMissingData = 
true;
 
  137        $mapper->bExceptionOnUndefinedProperty = 
true;
 
  138        $mapper->bStrictObjectTypeChecking = 
true;
 
  139        $mapper->bEnforceMapType = 
false;
 
  143            $headers = $mapper->map($headersArray, 
new SelfSignedJwtHeader());
 
  144        }
catch(\JsonMapper_Exception $e){
 
  145            throw new VerifyLoginException(
"Invalid JWT header: " . $e->getMessage(), 
null, 0, $e);
 
  148        $headerDerKey = base64_decode($headers->x5u, 
true);
 
  149        if($headerDerKey === 
false){
 
  150            throw new VerifyLoginException(
"Invalid JWT public key: base64 decoding error decoding x5u");
 
  152        if($expectedKeyDer !== 
null && $headerDerKey !== $expectedKeyDer){
 
  154            throw new VerifyLoginException(
"Invalid JWT signature", KnownTranslationFactory::pocketmine_disconnect_invalidSession_badSignature());
 
  158            if(!JwtUtils::verify($jwt, $headerDerKey, ec: 
true)){
 
  159                throw new VerifyLoginException(
"Invalid JWT signature", KnownTranslationFactory::pocketmine_disconnect_invalidSession_badSignature());
 
  161        }
catch(JwtException $e){
 
  162            throw new VerifyLoginException($e->getMessage(), 
null, 0, $e);