sessionless-1.x-dev/src/Utility/UnauthenticatedFooterParser.php
src/Utility/UnauthenticatedFooterParser.php
<?php
declare(strict_types=1);
namespace Drupal\sessionless\Utility;
use ParagonIE\ConstantTime\Binary;
use ParagonIE\Paseto\Exception\ExceptionCode;
use ParagonIE\Paseto\Exception\SecurityException;
use ParagonIE\Paseto\Parsing\PasetoMessage;
use ParagonIE\Paseto\Util;
final class UnauthenticatedFooterParser {
protected ?int $maxClaimCount = null;
protected ?int $maxClaimDepth = null;
protected ?int $maxJsonLength = null;
private readonly string $footer;
public function __construct(string $tainted) {
$this->footer = PasetoMessage::fromString($tainted)->footer();
}
/**
* Get footer array without checking signature.
*
* @see \ParagonIE\Paseto\Parser::extractKeyIdFromFooterJson
*/
public function getFooterArray(): ?array {
$length = Binary::safeStrlen($this->footer);
if ($length < 6) {
// Too short to be JSON
return NULL;
}
if ($this->footer[0] !== '{' || $this->footer[$length - 1] !== '}') {
// Not JSON
return NULL;
}
// Perform safety checks before invoking json_decode()
if (!is_null($this->maxJsonLength) && $length > $this->maxJsonLength) {
throw new SecurityException(
"Footer JSON is too long",
ExceptionCode::FOOTER_JSON_ERROR
);
}
if (!is_null($this->maxClaimDepth)) {
if (Util::calculateJsonDepth($this->footer) > $this->maxClaimDepth) {
throw new SecurityException(
"Footer JSON is has too much recursion",
ExceptionCode::FOOTER_JSON_ERROR
);
}
}
if (!is_null($this->maxClaimCount)) {
if (Util::countJsonKeys($this->footer) > $this->maxClaimCount) {
throw new SecurityException(
"Footer JSON is has too many keys",
ExceptionCode::FOOTER_JSON_ERROR
);
}
}
$decode = json_decode($this->footer, TRUE, $this->maxClaimDepth ?? 512);
// @todo Consider throwing if not an array.
return is_array($decode) ? $decode : NULL;
}
}
