mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-30 14:38:36 +00:00
Added JwtUtils::parse(), make ProcessLoginTask more robust
This commit is contained in:
parent
c69411c984
commit
8c2878fe5b
@ -38,22 +38,28 @@ use function strtr;
|
|||||||
final class JwtUtils{
|
final class JwtUtils{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed[] array of claims
|
* TODO: replace this result with an object
|
||||||
* @phpstan-return array<string, mixed>
|
*
|
||||||
|
* @return mixed[]
|
||||||
|
* @phpstan-return array{mixed[], mixed[], string}
|
||||||
*
|
*
|
||||||
* @throws \UnexpectedValueException
|
* @throws \UnexpectedValueException
|
||||||
*/
|
*/
|
||||||
public static function getClaims(string $token) : array{
|
public static function parse(string $token) : array{
|
||||||
$v = explode(".", $token);
|
$v = explode(".", $token);
|
||||||
if(count($v) !== 3){
|
if(count($v) !== 3){
|
||||||
throw new \UnexpectedValueException("Expected exactly 3 JWT parts, got " . count($v));
|
throw new \UnexpectedValueException("Expected exactly 3 JWT parts, got " . count($v));
|
||||||
}
|
}
|
||||||
$result = json_decode(self::b64UrlDecode($v[1]), true);
|
$header = json_decode(self::b64UrlDecode($v[0]), true);
|
||||||
if(!is_array($result)){
|
if(!is_array($header)){
|
||||||
|
throw new \UnexpectedValueException("Failed to decode JWT header JSON: ". json_last_error_msg());
|
||||||
|
}
|
||||||
|
$body = json_decode(self::b64UrlDecode($v[1]), true);
|
||||||
|
if(!is_array($body)){
|
||||||
throw new \UnexpectedValueException("Failed to decode JWT payload JSON: " . json_last_error_msg());
|
throw new \UnexpectedValueException("Failed to decode JWT payload JSON: " . json_last_error_msg());
|
||||||
}
|
}
|
||||||
|
$signature = self::b64UrlDecode($v[2]);
|
||||||
return $result;
|
return [$header, $body, $signature];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function b64UrlEncode(string $str) : string{
|
public static function b64UrlEncode(string $str) : string{
|
||||||
|
@ -36,7 +36,6 @@ use function base64_decode;
|
|||||||
use function bin2hex;
|
use function bin2hex;
|
||||||
use function explode;
|
use function explode;
|
||||||
use function gmp_init;
|
use function gmp_init;
|
||||||
use function json_decode;
|
|
||||||
use function openssl_verify;
|
use function openssl_verify;
|
||||||
use function str_split;
|
use function str_split;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
@ -115,7 +114,11 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
* @throws VerifyLoginException if errors are encountered
|
* @throws VerifyLoginException if errors are encountered
|
||||||
*/
|
*/
|
||||||
private function validateToken(string $jwt, ?string &$currentPublicKey, bool $first = false) : void{
|
private function validateToken(string $jwt, ?string &$currentPublicKey, bool $first = false) : void{
|
||||||
[$headB64, $payloadB64, $sigB64] = explode('.', $jwt);
|
try{
|
||||||
|
[$headers, $claims, $plainSignature] = JwtUtils::parse($jwt);
|
||||||
|
}catch(\UnexpectedValueException $e){
|
||||||
|
throw new VerifyLoginException("Failed to parse JWT: " . $e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
|
||||||
if($currentPublicKey === null){
|
if($currentPublicKey === null){
|
||||||
if(!$first){
|
if(!$first){
|
||||||
@ -123,7 +126,6 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//First link, check that it is self-signed
|
//First link, check that it is self-signed
|
||||||
$headers = json_decode(JwtUtils::b64UrlDecode($headB64), true);
|
|
||||||
$currentPublicKey = $headers["x5u"];
|
$currentPublicKey = $headers["x5u"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +150,6 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
$this->authenticated = true; //we're signed into xbox live
|
$this->authenticated = true; //we're signed into xbox live
|
||||||
}
|
}
|
||||||
|
|
||||||
$claims = json_decode(JwtUtils::b64UrlDecode($payloadB64), true);
|
|
||||||
|
|
||||||
$time = time();
|
$time = time();
|
||||||
if(isset($claims["nbf"]) and $claims["nbf"] > $time + self::CLOCK_DRIFT_MAX){
|
if(isset($claims["nbf"]) and $claims["nbf"] > $time + self::CLOCK_DRIFT_MAX){
|
||||||
throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.tooEarly");
|
throw new VerifyLoginException("%pocketmine.disconnect.invalidSession.tooEarly");
|
||||||
|
@ -88,7 +88,7 @@ class LoginPacket extends DataPacket implements ServerboundPacket{
|
|||||||
foreach($this->chainDataJwt->chain as $k => $chain){
|
foreach($this->chainDataJwt->chain as $k => $chain){
|
||||||
//validate every chain element
|
//validate every chain element
|
||||||
try{
|
try{
|
||||||
$claims = JwtUtils::getClaims($chain);
|
[, $claims, ] = JwtUtils::parse($chain);
|
||||||
}catch(\UnexpectedValueException $e){
|
}catch(\UnexpectedValueException $e){
|
||||||
throw new PacketDecodeException($e->getMessage(), 0, $e);
|
throw new PacketDecodeException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ class LoginPacket extends DataPacket implements ServerboundPacket{
|
|||||||
|
|
||||||
$this->clientDataJwt = $buffer->get($buffer->getLInt());
|
$this->clientDataJwt = $buffer->get($buffer->getLInt());
|
||||||
try{
|
try{
|
||||||
$clientData = JwtUtils::getClaims($this->clientDataJwt);
|
[, $clientData, ] = JwtUtils::parse($this->clientDataJwt);
|
||||||
}catch(\UnexpectedValueException $e){
|
}catch(\UnexpectedValueException $e){
|
||||||
throw new PacketDecodeException($e->getMessage(), 0, $e);
|
throw new PacketDecodeException($e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user