vendor/lcobucci/jwt/src/Token/Parser.php line 54

  1. <?php
  2. declare(strict_types=1);
  3. namespace Lcobucci\JWT\Token;
  4. use DateTimeImmutable;
  5. use Lcobucci\JWT\Decoder;
  6. use Lcobucci\JWT\Parser as ParserInterface;
  7. use Lcobucci\JWT\Token as TokenInterface;
  8. use function array_key_exists;
  9. use function count;
  10. use function explode;
  11. use function is_array;
  12. use function is_numeric;
  13. use function number_format;
  14. final class Parser implements ParserInterface
  15. {
  16.     private const MICROSECOND_PRECISION 6;
  17.     private Decoder $decoder;
  18.     public function __construct(Decoder $decoder)
  19.     {
  20.         $this->decoder $decoder;
  21.     }
  22.     public function parse(string $jwt): TokenInterface
  23.     {
  24.         [$encodedHeaders$encodedClaims$encodedSignature] = $this->splitJwt($jwt);
  25.         $header $this->parseHeader($encodedHeaders);
  26.         return new Plain(
  27.             new DataSet($header$encodedHeaders),
  28.             new DataSet($this->parseClaims($encodedClaims), $encodedClaims),
  29.             $this->parseSignature($header$encodedSignature)
  30.         );
  31.     }
  32.     /**
  33.      * Splits the JWT string into an array
  34.      *
  35.      * @return string[]
  36.      *
  37.      * @throws InvalidTokenStructure When JWT doesn't have all parts.
  38.      */
  39.     private function splitJwt(string $jwt): array
  40.     {
  41.         $data explode('.'$jwt);
  42.         if (count($data) !== 3) {
  43.             throw InvalidTokenStructure::missingOrNotEnoughSeparators();
  44.         }
  45.         return $data;
  46.     }
  47.     /**
  48.      * Parses the header from a string
  49.      *
  50.      * @return mixed[]
  51.      *
  52.      * @throws UnsupportedHeaderFound When an invalid header is informed.
  53.      * @throws InvalidTokenStructure  When parsed content isn't an array.
  54.      */
  55.     private function parseHeader(string $data): array
  56.     {
  57.         $header $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
  58.         if (! is_array($header)) {
  59.             throw InvalidTokenStructure::arrayExpected('headers');
  60.         }
  61.         if (array_key_exists('enc'$header)) {
  62.             throw UnsupportedHeaderFound::encryption();
  63.         }
  64.         if (! array_key_exists('typ'$header)) {
  65.             $header['typ'] = 'JWT';
  66.         }
  67.         return $header;
  68.     }
  69.     /**
  70.      * Parses the claim set from a string
  71.      *
  72.      * @return mixed[]
  73.      *
  74.      * @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates.
  75.      */
  76.     private function parseClaims(string $data): array
  77.     {
  78.         $claims $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
  79.         if (! is_array($claims)) {
  80.             throw InvalidTokenStructure::arrayExpected('claims');
  81.         }
  82.         if (array_key_exists(RegisteredClaims::AUDIENCE$claims)) {
  83.             $claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE];
  84.         }
  85.         foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
  86.             if (! array_key_exists($claim$claims)) {
  87.                 continue;
  88.             }
  89.             $claims[$claim] = $this->convertDate($claims[$claim]);
  90.         }
  91.         return $claims;
  92.     }
  93.     /**
  94.      * @param int|float|string $timestamp
  95.      *
  96.      * @throws InvalidTokenStructure
  97.      */
  98.     private function convertDate($timestamp): DateTimeImmutable
  99.     {
  100.         if (! is_numeric($timestamp)) {
  101.             throw InvalidTokenStructure::dateIsNotParseable($timestamp);
  102.         }
  103.         $normalizedTimestamp number_format((float) $timestampself::MICROSECOND_PRECISION'.''');
  104.         $date DateTimeImmutable::createFromFormat('U.u'$normalizedTimestamp);
  105.         if ($date === false) {
  106.             throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp);
  107.         }
  108.         return $date;
  109.     }
  110.     /**
  111.      * Returns the signature from given data
  112.      *
  113.      * @param mixed[] $header
  114.      */
  115.     private function parseSignature(array $headerstring $data): Signature
  116.     {
  117.         if ($data === '' || ! array_key_exists('alg'$header) || $header['alg'] === 'none') {
  118.             return Signature::fromEmptyData();
  119.         }
  120.         $hash $this->decoder->base64UrlDecode($data);
  121.         return new Signature($hash$data);
  122.     }
  123. }