diff --git a/analytics/meta/dashboard.php b/analytics/meta/dashboard.php
new file mode 100644
index 00000000..b8e3ea5b
--- /dev/null
+++ b/analytics/meta/dashboard.php
@@ -0,0 +1,72 @@
+add(new DateInterval('PT10M')); // Token expires in 10 minutes
+
+// You can add parameters if needed for filtering or other purposes
+$params = (object)[
+ // Add any parameters required by your dashboard or charts here
+ // For example: 'region' => 'North', 'date' => '2024-01-01'
+ // Leave this as an empty object if there are no params
+];
+
+$token = $config->builder()
+ ->issuedBy($metabaseSiteUrl) // Configures the issuer (iss claim)
+ ->issuedAt($now) // Configures the time that the token was issued (iat claim)
+ ->expiresAt($exp) // Configures the expiration time of the token (exp claim)
+ ->withClaim('resource', ['dashboard' => $dashboardId]) // Add resource claim
+ ->withClaim('params', $params) // Add params claim as an object
+ ->getToken($config->signer(), $config->signingKey()); // Retrieves the generated token
+
+// Generate iframe URL
+$iframeUrl = $metabaseSiteUrl . "/embed/dashboard/" . $token->toString() . "#theme=transparent&bordered=false&titled=true";
+?>
+
+
+
+
+
+
+ Embedded Metabase Dashboard
+
+
+
+
+
+
diff --git a/analytics/meta/embed.php b/analytics/meta/embed.php
new file mode 100644
index 00000000..e2c2def2
--- /dev/null
+++ b/analytics/meta/embed.php
@@ -0,0 +1,16 @@
+ 'past26weeks'];
+
+$metabase = new \Metabase\Embed($metabaseUrl, $metabaseKey);
+// Generate the HTML to create an iframe with the embedded dashboard
+echo $metabase->dashboardIframe($dashboardId, $params);
+?>
\ No newline at end of file
diff --git a/analytics/meta/metabase.php b/analytics/meta/metabase.php
new file mode 100644
index 00000000..8ba1218b
--- /dev/null
+++ b/analytics/meta/metabase.php
@@ -0,0 +1,188 @@
+url = $url;
+ $this->key = $key;
+ $this->border = $border;
+ $this->title = $title;
+ $this->width = $width;
+ $this->height = $height;
+ $this->expirationSeconds = $expirationSeconds;
+
+ $this->jwtConfig = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($this->key));
+ }
+
+ /**
+ * Get the embed URL for a Metabase question
+ *
+ * @param int $questionId The id of the question to embed
+ * @param array $params An associate array with variables to be passed to the question
+ *
+ * @return string Embed URL
+ */
+ public function questionUrl($questionId, $params = [])
+ {
+ return $this->url('question', $questionId, $params);
+ }
+
+ /**
+ * Get the embed URL for a Metabase dashboard
+ *
+ * @param int $dashboardId The id of the dashboard to embed
+ * @param array $params An associate array with variables to be passed to the dashboard
+ *
+ * @return string Embed URL
+ */
+ public function dashboardUrl($dashboardId, $params = [])
+ {
+ return $this->url('dashboard', $dashboardId, $params);
+ }
+
+ /**
+ * Use JWT to encode tokens
+ *
+ * @param array $resource Resource to encode (question or dashboard)
+ * @param array $params An associate array with variables to be passed to the dashboard
+ *
+ * @return string Token
+ */
+ private function encode($resource, $params)
+ {
+ $jwt = $this->jwtConfig->builder();
+ $jwt->withClaim('resource', $resource);
+ if (empty($params)) {
+ $jwt->withClaim('params', (object)[]);
+ } else {
+ $jwt->withClaim('params', $params);
+ }
+ if (!is_null($this->expirationSeconds)) {
+ $jwt->expiresAt((new DateTimeImmutable())->modify('+' . $this->expirationSeconds . ' seconds'));
+ }
+
+ return $jwt->getToken($this->jwtConfig->signer(), $this->jwtConfig->signingKey());
+ }
+
+ protected function url($resource, $id, $params)
+ {
+ // Generate auth token, using JWT
+ $token = $this->encode([$resource => $id], $params);
+
+ // Generate embed URL
+ $url = $this->url . '/embed/' . $resource . '/' . $token->toString() . '#';
+
+ // Should border be included
+ if ($this->border) {
+ $url .= 'bordered=true&';
+ } else {
+ $url .= 'bordered=false&';
+ }
+
+ // Should title be included
+ if ($this->title) {
+ $url .= 'titled=true&';
+ } else {
+ $url .= 'titled=false&';
+ }
+
+ // Set selected theme (if any)
+ if (!empty($this->theme)) {
+ $url .= 'theme=' . $this->theme . '&';
+ }
+
+ // Remove trailing &
+ $url = rtrim($url, '&');
+
+ return $url;
+ }
+
+ /**
+ * Generate the HTML to embed a question iframe with a given question id.
+ * It assumes no iframe border. Size can be manipulated via
+ * class $width/$height
+ *
+ * @param int $questionId The id of the question to embed
+ * @param array $params An associate array with variables to be passed to the question
+ *
+ * @return string Code to embed
+ */
+ public function questionIFrame($questionId, $params = [])
+ {
+ $url = $this->questionUrl($questionId, $params);
+ return $this->iframe($url);
+ }
+
+ /**
+ * Generate the HTML to embed a dashboard iframe with a given dashboard id.
+ * It assumes no iframe border. Size can be manipulated via
+ * class $width/$height
+ *
+ * @param int $dashboardId The id of the dashboard to embed
+ * @param array $params An associate array with variables to be passed to the dashboard
+ *
+ * @return string Code to embed
+ */
+ public function dashboardIFrame($dashboardId, $params = [])
+ {
+ $url = $this->dashboardUrl($dashboardId, $params);
+ return $this->iframe($url);
+ }
+
+ /**
+ * Generate the HTML to embed an iframe with a given URL.
+ * It assumes no iframe border. Size can be manipulated via
+ * class $width/$height
+ *
+ * @param string $iframeUrl The URL to create an iframe for
+ *
+ * @return string Code to embed
+ */
+ protected function iframe($iframeUrl)
+ {
+ return '';
+ }
+}
\ No newline at end of file
diff --git a/analytics/tests/index.php b/analytics/tests/index.php
new file mode 100644
index 00000000..de69ced5
--- /dev/null
+++ b/analytics/tests/index.php
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
index d7c6bb72..cf40a678 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,25 @@
{
+ "name": "mikeintoshsystems/hispmd",
+ "type": "library",
+ "description": "HISPMD",
+ "keywords": ["metabase, HISPMD"],
+ "homepage": "https://github.com/mikeintoshsystems/hispmd",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Kifle Teferra",
+ "email": "mikeintoshsys@gmail.com",
+ "homepage": "https://mikeintoshsys.com",
+ "role": "Developer"
+ }
+ ],
"require": {
- "vlucas/phpdotenv": "^5.6"
- }
+ "vlucas/phpdotenv": "^5.6",
+ "lcobucci/jwt": "^5.3"
+ },
+ "autoload": {
+ "psr-4": {
+ "Metabase\\": "analytics"
+ }
+ }
}
diff --git a/composer.lock b/composer.lock
index 093122ee..f897e9c1 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "108be68e4e2b97fed51d36a10eed0849",
+ "content-hash": "0b8a074fb783e46f6e4d1090fe323914",
"packages": [
{
"name": "graham-campbell/result-type",
@@ -68,6 +68,79 @@
],
"time": "2023-11-12T22:16:48+00:00"
},
+ {
+ "name": "lcobucci/jwt",
+ "version": "5.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lcobucci/jwt.git",
+ "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
+ "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-sodium": "*",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "psr/clock": "^1.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.27.0",
+ "lcobucci/clock": "^3.0",
+ "lcobucci/coding-standard": "^11.0",
+ "phpbench/phpbench": "^1.2.9",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.10.7",
+ "phpstan/phpstan-deprecation-rules": "^1.1.3",
+ "phpstan/phpstan-phpunit": "^1.3.10",
+ "phpstan/phpstan-strict-rules": "^1.5.0",
+ "phpunit/phpunit": "^10.2.6"
+ },
+ "suggest": {
+ "lcobucci/clock": ">= 3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+ "keywords": [
+ "JWS",
+ "jwt"
+ ],
+ "support": {
+ "issues": "https://github.com/lcobucci/jwt/issues",
+ "source": "https://github.com/lcobucci/jwt/tree/5.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/lcobucci",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/lcobucci",
+ "type": "patreon"
+ }
+ ],
+ "time": "2024-04-11T23:07:54+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.2",
@@ -143,6 +216,54 @@
],
"time": "2023-11-12T21:59:55+00:00"
},
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00"
+ },
{
"name": "symfony/polyfill-ctype",
"version": "v1.30.0",
diff --git a/docker-compose.yml b/docker-compose.yml
index 02ff271a..a5de3b3e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -16,7 +16,7 @@ services:
- ./.env:/var/www/html/.env
- ./index.php:/var/www/html/index.php
- ./LICENSE:/var/www/html/LICENSE
- - ./map_files:/var/www/html/map_files
+ - ./maps:/var/www/html/maps
- ./mysql-init:/var/www/html/mysql-init
- ./README.md:/var/www/html/README.md
- ./server.html:/var/www/html/server.html
@@ -115,7 +115,7 @@ services:
container_name: hispmd_viz
hostname: metabase
volumes:
- - hispmd_vizdata:/metabase-data
+ - ./src/hispmd_vizdata:/metabase-data
ports:
- "4004:3000"
environment:
diff --git a/map_files/MIKEINTOSH_ethiopia_region_Zone_map_MAIN.geojson b/maps/ethiopia_region_Zone_map_MAIN.geojson
similarity index 100%
rename from map_files/MIKEINTOSH_ethiopia_region_Zone_map_MAIN.geojson
rename to maps/ethiopia_region_Zone_map_MAIN.geojson
diff --git a/map_files/mikeintosh_ethiopia_regions_map_simple.geojson b/maps/ethiopia_regions_map_simple.geojson
similarity index 100%
rename from map_files/mikeintosh_ethiopia_regions_map_simple.geojson
rename to maps/ethiopia_regions_map_simple.geojson
diff --git a/maps/mapbox/index.html b/maps/mapbox/index.html
new file mode 100644
index 00000000..83608891
--- /dev/null
+++ b/maps/mapbox/index.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Change a map's style
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index bb79e2a5..0f06ef54 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -9,7 +9,10 @@
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
+ 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),
+ 'Metabase\\' => array($baseDir . '/analytics'),
+ 'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'),
'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'),
);
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index 6668bae5..219a4401 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -21,8 +21,17 @@ class ComposerStaticInite875ae8441d070d7dda5f4b47a2117aa
),
'P' =>
array (
+ 'Psr\\Clock\\' => 10,
'PhpOption\\' => 10,
),
+ 'M' =>
+ array (
+ 'Metabase\\' => 9,
+ ),
+ 'L' =>
+ array (
+ 'Lcobucci\\JWT\\' => 13,
+ ),
'G' =>
array (
'GrahamCampbell\\ResultType\\' => 26,
@@ -46,10 +55,22 @@ class ComposerStaticInite875ae8441d070d7dda5f4b47a2117aa
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
+ 'Psr\\Clock\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/clock/src',
+ ),
'PhpOption\\' =>
array (
0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption',
),
+ 'Metabase\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/analytics',
+ ),
+ 'Lcobucci\\JWT\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/lcobucci/jwt/src',
+ ),
'GrahamCampbell\\ResultType\\' =>
array (
0 => __DIR__ . '/..' . '/graham-campbell/result-type/src',
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 53ec7b41..8f73bf03 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -65,6 +65,82 @@
],
"install-path": "../graham-campbell/result-type"
},
+ {
+ "name": "lcobucci/jwt",
+ "version": "5.3.0",
+ "version_normalized": "5.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lcobucci/jwt.git",
+ "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
+ "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-sodium": "*",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "psr/clock": "^1.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.27.0",
+ "lcobucci/clock": "^3.0",
+ "lcobucci/coding-standard": "^11.0",
+ "phpbench/phpbench": "^1.2.9",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.10.7",
+ "phpstan/phpstan-deprecation-rules": "^1.1.3",
+ "phpstan/phpstan-phpunit": "^1.3.10",
+ "phpstan/phpstan-strict-rules": "^1.5.0",
+ "phpunit/phpunit": "^10.2.6"
+ },
+ "suggest": {
+ "lcobucci/clock": ">= 3.0"
+ },
+ "time": "2024-04-11T23:07:54+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+ "keywords": [
+ "JWS",
+ "jwt"
+ ],
+ "support": {
+ "issues": "https://github.com/lcobucci/jwt/issues",
+ "source": "https://github.com/lcobucci/jwt/tree/5.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/lcobucci",
+ "type": "github"
+ },
+ {
+ "url": "https://www.patreon.com/lcobucci",
+ "type": "patreon"
+ }
+ ],
+ "install-path": "../lcobucci/jwt"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.2",
@@ -143,6 +219,57 @@
],
"install-path": "../phpoption/phpoption"
},
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "install-path": "../psr/clock"
+ },
{
"name": "symfony/polyfill-ctype",
"version": "v1.30.0",
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index 55d26a5d..95e2cda9 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -1,24 +1,15 @@
array(
- 'name' => '__root__',
+ 'name' => 'mikeintoshsystems/hispmd',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
- 'reference' => '95455018a2dc4b6b98a0a3922c2621621955fdba',
+ 'reference' => '7f82c073b142b223f67ebbb2c18014835aab71fb',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
- '__root__' => array(
- 'pretty_version' => 'dev-main',
- 'version' => 'dev-main',
- 'reference' => '95455018a2dc4b6b98a0a3922c2621621955fdba',
- 'type' => 'library',
- 'install_path' => __DIR__ . '/../../',
- 'aliases' => array(),
- 'dev_requirement' => false,
- ),
'graham-campbell/result-type' => array(
'pretty_version' => 'v1.1.2',
'version' => '1.1.2.0',
@@ -28,6 +19,24 @@
'aliases' => array(),
'dev_requirement' => false,
),
+ 'lcobucci/jwt' => array(
+ 'pretty_version' => '5.3.0',
+ 'version' => '5.3.0.0',
+ 'reference' => '08071d8d2c7f4b00222cc4b1fb6aa46990a80f83',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../lcobucci/jwt',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'mikeintoshsystems/hispmd' => array(
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'reference' => '7f82c073b142b223f67ebbb2c18014835aab71fb',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
'phpoption/phpoption' => array(
'pretty_version' => '1.9.2',
'version' => '1.9.2.0',
@@ -37,6 +46,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
+ 'psr/clock' => array(
+ 'pretty_version' => '1.0.0',
+ 'version' => '1.0.0.0',
+ 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/clock',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.30.0',
'version' => '1.30.0.0',
diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php
index a8b98d5c..4c3a5d68 100644
--- a/vendor/composer/platform_check.php
+++ b/vendor/composer/platform_check.php
@@ -4,8 +4,8 @@
$issues = array();
-if (!(PHP_VERSION_ID >= 70205)) {
- $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 80100)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
diff --git a/vendor/lcobucci/jwt/.readthedocs.yaml b/vendor/lcobucci/jwt/.readthedocs.yaml
new file mode 100644
index 00000000..aa49c943
--- /dev/null
+++ b/vendor/lcobucci/jwt/.readthedocs.yaml
@@ -0,0 +1,9 @@
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3"
+
+mkdocs:
+ configuration: mkdocs.yml
diff --git a/vendor/lcobucci/jwt/LICENSE b/vendor/lcobucci/jwt/LICENSE
new file mode 100644
index 00000000..cc7e28f1
--- /dev/null
+++ b/vendor/lcobucci/jwt/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014, Luís Cobucci
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/lcobucci/jwt/composer.json b/vendor/lcobucci/jwt/composer.json
new file mode 100644
index 00000000..a6186894
--- /dev/null
+++ b/vendor/lcobucci/jwt/composer.json
@@ -0,0 +1,63 @@
+{
+ "name": "lcobucci/jwt",
+ "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "type": "library",
+ "keywords": [
+ "JWT",
+ "JWS"
+ ],
+ "authors": [
+ {
+ "name": "Luís Cobucci",
+ "email": "lcobucci@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "require": {
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "ext-openssl": "*",
+ "ext-sodium": "*",
+ "psr/clock": "^1.0"
+ },
+ "require-dev": {
+ "infection/infection": "^0.27.0",
+ "lcobucci/clock": "^3.0",
+ "lcobucci/coding-standard": "^11.0",
+ "phpbench/phpbench": "^1.2.9",
+ "phpstan/extension-installer": "^1.2",
+ "phpstan/phpstan": "^1.10.7",
+ "phpstan/phpstan-deprecation-rules": "^1.1.3",
+ "phpstan/phpstan-phpunit": "^1.3.10",
+ "phpstan/phpstan-strict-rules": "^1.5.0",
+ "phpunit/phpunit": "^10.2.6"
+ },
+ "suggest": {
+ "lcobucci/clock": ">= 3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Lcobucci\\JWT\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Lcobucci\\JWT\\Tests\\": "tests"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "infection/extension-installer": true,
+ "ocramius/package-versions": true,
+ "phpstan/extension-installer": true
+ },
+ "platform": {
+ "php": "8.1.99"
+ },
+ "preferred-install": "dist",
+ "sort-packages": true
+ }
+}
diff --git a/vendor/lcobucci/jwt/renovate.json b/vendor/lcobucci/jwt/renovate.json
new file mode 100644
index 00000000..d0adcc3a
--- /dev/null
+++ b/vendor/lcobucci/jwt/renovate.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ "local>lcobucci/.github:renovate-config"
+ ]
+}
diff --git a/vendor/lcobucci/jwt/src/Builder.php b/vendor/lcobucci/jwt/src/Builder.php
new file mode 100644
index 00000000..4295e3f0
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Builder.php
@@ -0,0 +1,85 @@
+ $claims
+ *
+ * @return array
+ */
+ public function formatClaims(array $claims): array;
+}
diff --git a/vendor/lcobucci/jwt/src/Configuration.php b/vendor/lcobucci/jwt/src/Configuration.php
new file mode 100644
index 00000000..488ea3e2
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Configuration.php
@@ -0,0 +1,131 @@
+parser = new Token\Parser($decoder);
+ $this->validator = new Validation\Validator();
+
+ $this->builderFactory = static function (ClaimsFormatter $claimFormatter) use ($encoder): Builder {
+ return new Token\Builder($encoder, $claimFormatter);
+ };
+ }
+
+ public static function forAsymmetricSigner(
+ Signer $signer,
+ Key $signingKey,
+ Key $verificationKey,
+ Encoder $encoder = new JoseEncoder(),
+ Decoder $decoder = new JoseEncoder(),
+ ): self {
+ return new self(
+ $signer,
+ $signingKey,
+ $verificationKey,
+ $encoder,
+ $decoder,
+ );
+ }
+
+ public static function forSymmetricSigner(
+ Signer $signer,
+ Key $key,
+ Encoder $encoder = new JoseEncoder(),
+ Decoder $decoder = new JoseEncoder(),
+ ): self {
+ return new self(
+ $signer,
+ $key,
+ $key,
+ $encoder,
+ $decoder,
+ );
+ }
+
+ /** @param callable(ClaimsFormatter): Builder $builderFactory */
+ public function setBuilderFactory(callable $builderFactory): void
+ {
+ $this->builderFactory = $builderFactory(...);
+ }
+
+ public function builder(?ClaimsFormatter $claimFormatter = null): Builder
+ {
+ return ($this->builderFactory)($claimFormatter ?? ChainedFormatter::default());
+ }
+
+ public function parser(): Parser
+ {
+ return $this->parser;
+ }
+
+ public function setParser(Parser $parser): void
+ {
+ $this->parser = $parser;
+ }
+
+ public function signer(): Signer
+ {
+ return $this->signer;
+ }
+
+ public function signingKey(): Key
+ {
+ return $this->signingKey;
+ }
+
+ public function verificationKey(): Key
+ {
+ return $this->verificationKey;
+ }
+
+ public function validator(): Validator
+ {
+ return $this->validator;
+ }
+
+ public function setValidator(Validator $validator): void
+ {
+ $this->validator = $validator;
+ }
+
+ /** @return Constraint[] */
+ public function validationConstraints(): array
+ {
+ return $this->validationConstraints;
+ }
+
+ public function setValidationConstraints(Constraint ...$validationConstraints): void
+ {
+ $this->validationConstraints = $validationConstraints;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Decoder.php b/vendor/lcobucci/jwt/src/Decoder.php
new file mode 100644
index 00000000..6b24b926
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Decoder.php
@@ -0,0 +1,29 @@
+ */
+ private array $formatters;
+
+ public function __construct(ClaimsFormatter ...$formatters)
+ {
+ $this->formatters = $formatters;
+ }
+
+ public static function default(): self
+ {
+ return new self(new UnifyAudience(), new MicrosecondBasedDateConversion());
+ }
+
+ public static function withUnixTimestampDates(): self
+ {
+ return new self(new UnifyAudience(), new UnixTimestampDates());
+ }
+
+ /** @inheritdoc */
+ public function formatClaims(array $claims): array
+ {
+ foreach ($this->formatters as $formatter) {
+ $claims = $formatter->formatClaims($claims);
+ }
+
+ return $claims;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php b/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php
new file mode 100644
index 00000000..0d904442
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php
@@ -0,0 +1,56 @@
+convertDate($claims[$claim]);
+ }
+
+ return $claims;
+ }
+
+ private function convertDate(DateTimeImmutable $date): int|float
+ {
+ if ($date->format('u') === '000000') {
+ return (int) $date->format('U');
+ }
+
+ return (float) $date->format('U.u');
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php b/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php
new file mode 100644
index 00000000..cf57252e
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php
@@ -0,0 +1,29 @@
+convertDate($claims[$claim]);
+ }
+
+ return $claims;
+ }
+
+ private function convertDate(DateTimeImmutable $date): int
+ {
+ return $date->getTimestamp();
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Exception.php b/vendor/lcobucci/jwt/src/Exception.php
new file mode 100644
index 00000000..4b3916e6
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Exception.php
@@ -0,0 +1,10 @@
+clock = $clock ?? new class implements Clock {
+ public function now(): DateTimeImmutable
+ {
+ return new DateTimeImmutable();
+ }
+ };
+ }
+
+ /** @param Closure(Builder, DateTimeImmutable):Builder $customiseBuilder */
+ public function issue(
+ Signer $signer,
+ Key $signingKey,
+ Closure $customiseBuilder,
+ ): UnencryptedToken {
+ $builder = new Token\Builder(new JoseEncoder(), ChainedFormatter::withUnixTimestampDates());
+
+ $now = $this->clock->now();
+ $builder = $builder
+ ->issuedAt($now)
+ ->canOnlyBeUsedAfter($now)
+ ->expiresAt($now->modify('+5 minutes'));
+
+ return $customiseBuilder($builder, $now)->getToken($signer, $signingKey);
+ }
+
+ /** @param non-empty-string $jwt */
+ public function parse(
+ string $jwt,
+ SignedWith $signedWith,
+ ValidAt $validAt,
+ Constraint ...$constraints,
+ ): UnencryptedToken {
+ $token = $this->parser->parse($jwt);
+ assert($token instanceof UnencryptedToken);
+
+ (new Validator())->assert(
+ $token,
+ $signedWith,
+ $validAt,
+ ...$constraints,
+ );
+
+ return $token;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Parser.php b/vendor/lcobucci/jwt/src/Parser.php
new file mode 100644
index 00000000..fa77f04e
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Parser.php
@@ -0,0 +1,22 @@
+contents());
+
+ if ($actualKeyLength < self::MINIMUM_KEY_LENGTH_IN_BITS) {
+ throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH_IN_BITS, $actualKeyLength);
+ }
+
+ return sodium_crypto_generichash($payload, $key->contents());
+ }
+
+ public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return hash_equals($expected, $this->sign($payload, $key));
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php b/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php
new file mode 100644
index 00000000..35cc4d6d
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php
@@ -0,0 +1,15 @@
+converter->fromAsn1(
+ $this->createSignature($key->contents(), $key->passphrase(), $payload),
+ $this->pointLength(),
+ );
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return $this->verifySignature(
+ $this->converter->toAsn1($expected, $this->pointLength()),
+ $payload,
+ $key->contents(),
+ );
+ }
+
+ /** {@inheritDoc} */
+ final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
+ {
+ if ($type !== OPENSSL_KEYTYPE_EC) {
+ throw InvalidKeyProvided::incompatibleKeyType(
+ self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_EC],
+ self::KEY_TYPE_MAP[$type],
+ );
+ }
+
+ $expectedKeyLength = $this->expectedKeyLength();
+
+ if ($lengthInBits !== $expectedKeyLength) {
+ throw InvalidKeyProvided::incompatibleKeyLength($expectedKeyLength, $lengthInBits);
+ }
+ }
+
+ /**
+ * @internal
+ *
+ * @return positive-int
+ */
+ abstract public function expectedKeyLength(): int;
+
+ /**
+ * Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
+ *
+ * @internal
+ *
+ * @return positive-int
+ */
+ abstract public function pointLength(): int;
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php b/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php
new file mode 100644
index 00000000..d9ca751d
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php
@@ -0,0 +1,25 @@
+ self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
+
+ $asn1 = hex2bin(
+ self::ASN1_SEQUENCE
+ . $lengthPrefix . dechex($totalLength)
+ . self::ASN1_INTEGER . dechex($lengthR) . $pointR
+ . self::ASN1_INTEGER . dechex($lengthS) . $pointS,
+ );
+ assert(is_string($asn1));
+ assert($asn1 !== '');
+
+ return $asn1;
+ }
+
+ private static function octetLength(string $data): int
+ {
+ return (int) (strlen($data) / self::BYTE_SIZE);
+ }
+
+ private static function preparePositiveInteger(string $data): string
+ {
+ if (substr($data, 0, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT) {
+ return self::ASN1_NEGATIVE_INTEGER . $data;
+ }
+
+ while (
+ substr($data, 0, self::BYTE_SIZE) === self::ASN1_NEGATIVE_INTEGER
+ && substr($data, 2, self::BYTE_SIZE) <= self::ASN1_BIG_INTEGER_LIMIT
+ ) {
+ $data = substr($data, 2, null);
+ }
+
+ return $data;
+ }
+
+ public function fromAsn1(string $signature, int $length): string
+ {
+ $message = bin2hex($signature);
+ $position = 0;
+
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
+ throw ConversionFailed::incorrectStartSequence();
+ }
+
+ // @phpstan-ignore-next-line
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
+ $position += self::BYTE_SIZE;
+ }
+
+ $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
+ $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
+
+ $points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
+ assert(is_string($points));
+ assert($points !== '');
+
+ return $points;
+ }
+
+ private static function readAsn1Content(string $message, int &$position, int $length): string
+ {
+ $content = substr($message, $position, $length);
+ $position += $length;
+
+ return $content;
+ }
+
+ private static function readAsn1Integer(string $message, int &$position): string
+ {
+ if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) {
+ throw ConversionFailed::integerExpected();
+ }
+
+ $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
+
+ return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
+ }
+
+ private static function retrievePositiveInteger(string $data): string
+ {
+ while (
+ substr($data, 0, self::BYTE_SIZE) === self::ASN1_NEGATIVE_INTEGER
+ && substr($data, 2, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT
+ ) {
+ $data = substr($data, 2, null);
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
new file mode 100644
index 00000000..ff00f4d4
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
@@ -0,0 +1,31 @@
+contents());
+ } catch (SodiumException $sodiumException) {
+ throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException);
+ }
+ }
+
+ public function verify(string $expected, string $payload, Key $key): bool
+ {
+ try {
+ return sodium_crypto_sign_verify_detached($expected, $payload, $key->contents());
+ } catch (SodiumException $sodiumException) {
+ throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Hmac.php b/vendor/lcobucci/jwt/src/Signer/Hmac.php
new file mode 100644
index 00000000..815f84c3
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Hmac.php
@@ -0,0 +1,44 @@
+contents());
+ $expectedKeyLength = $this->minimumBitsLengthForKey();
+
+ if ($actualKeyLength < $expectedKeyLength) {
+ throw InvalidKeyProvided::tooShort($expectedKeyLength, $actualKeyLength);
+ }
+
+ return hash_hmac($this->algorithm(), $payload, $key->contents(), true);
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return hash_equals($expected, $this->sign($payload, $key));
+ }
+
+ /**
+ * @internal
+ *
+ * @return non-empty-string
+ */
+ abstract public function algorithm(): string;
+
+ /**
+ * @internal
+ *
+ * @return positive-int
+ */
+ abstract public function minimumBitsLengthForKey(): int;
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
new file mode 100644
index 00000000..e19992ec
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
@@ -0,0 +1,24 @@
+getSize();
+ $contents = $fileSize > 0 ? $file->fread($file->getSize()) : '';
+ assert(is_string($contents));
+
+ self::guardAgainstEmptyKey($contents);
+
+ return new self($contents, $passphrase);
+ }
+
+ /** @phpstan-assert non-empty-string $contents */
+ private static function guardAgainstEmptyKey(string $contents): void
+ {
+ if ($contents === '') {
+ throw InvalidKeyProvided::cannotBeEmpty();
+ }
+ }
+
+ public function contents(): string
+ {
+ return $this->contents;
+ }
+
+ public function passphrase(): string
+ {
+ return $this->passphrase;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/OpenSSL.php b/vendor/lcobucci/jwt/src/Signer/OpenSSL.php
new file mode 100644
index 00000000..bcc7065c
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/OpenSSL.php
@@ -0,0 +1,126 @@
+ 'RSA',
+ OPENSSL_KEYTYPE_DSA => 'DSA',
+ OPENSSL_KEYTYPE_DH => 'DH',
+ OPENSSL_KEYTYPE_EC => 'EC',
+ ];
+
+ /**
+ * @return non-empty-string
+ *
+ * @throws CannotSignPayload
+ * @throws InvalidKeyProvided
+ */
+ final protected function createSignature(
+ string $pem,
+ string $passphrase,
+ string $payload,
+ ): string {
+ $key = $this->getPrivateKey($pem, $passphrase);
+
+ $signature = '';
+
+ if (! openssl_sign($payload, $signature, $key, $this->algorithm())) {
+ throw CannotSignPayload::errorHappened($this->fullOpenSSLErrorString());
+ }
+
+ return $signature;
+ }
+
+ /** @throws CannotSignPayload */
+ private function getPrivateKey(string $pem, string $passphrase): OpenSSLAsymmetricKey
+ {
+ return $this->validateKey(openssl_pkey_get_private($pem, $passphrase));
+ }
+
+ /** @throws InvalidKeyProvided */
+ final protected function verifySignature(
+ string $expected,
+ string $payload,
+ string $pem,
+ ): bool {
+ $key = $this->getPublicKey($pem);
+ $result = openssl_verify($payload, $expected, $key, $this->algorithm());
+
+ return $result === 1;
+ }
+
+ /** @throws InvalidKeyProvided */
+ private function getPublicKey(string $pem): OpenSSLAsymmetricKey
+ {
+ return $this->validateKey(openssl_pkey_get_public($pem));
+ }
+
+ /**
+ * Raises an exception when the key type is not the expected type
+ *
+ * @throws InvalidKeyProvided
+ */
+ private function validateKey(OpenSSLAsymmetricKey|bool $key): OpenSSLAsymmetricKey
+ {
+ if (is_bool($key)) {
+ throw InvalidKeyProvided::cannotBeParsed($this->fullOpenSSLErrorString());
+ }
+
+ $details = openssl_pkey_get_details($key);
+ assert(is_array($details));
+
+ assert(array_key_exists('bits', $details));
+ assert(is_int($details['bits']));
+ assert(array_key_exists('type', $details));
+ assert(is_int($details['type']));
+
+ $this->guardAgainstIncompatibleKey($details['type'], $details['bits']);
+
+ return $key;
+ }
+
+ private function fullOpenSSLErrorString(): string
+ {
+ $error = '';
+
+ while ($msg = openssl_error_string()) {
+ $error .= PHP_EOL . '* ' . $msg;
+ }
+
+ return $error;
+ }
+
+ /** @throws InvalidKeyProvided */
+ abstract protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void;
+
+ /**
+ * Returns which algorithm to be used to create/verify the signature (using OpenSSL constants)
+ *
+ * @internal
+ */
+ abstract public function algorithm(): int;
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Rsa.php b/vendor/lcobucci/jwt/src/Signer/Rsa.php
new file mode 100644
index 00000000..ba7d72d5
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Rsa.php
@@ -0,0 +1,35 @@
+createSignature($key->contents(), $key->passphrase(), $payload);
+ }
+
+ final public function verify(string $expected, string $payload, Key $key): bool
+ {
+ return $this->verifySignature($expected, $payload, $key->contents());
+ }
+
+ final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
+ {
+ if ($type !== OPENSSL_KEYTYPE_RSA) {
+ throw InvalidKeyProvided::incompatibleKeyType(
+ self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_RSA],
+ self::KEY_TYPE_MAP[$type],
+ );
+ }
+
+ if ($lengthInBits < self::MINIMUM_KEY_LENGTH) {
+ throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH, $lengthInBits);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
new file mode 100644
index 00000000..9e56c70f
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
@@ -0,0 +1,21 @@
+ */
+ private array $headers = ['typ' => 'JWT', 'alg' => null];
+
+ /** @var array */
+ private array $claims = [];
+
+ public function __construct(private readonly Encoder $encoder, private readonly ClaimsFormatter $claimFormatter)
+ {
+ }
+
+ public function permittedFor(string ...$audiences): BuilderInterface
+ {
+ $configured = $this->claims[RegisteredClaims::AUDIENCE] ?? [];
+ $toAppend = array_diff($audiences, $configured);
+
+ return $this->setClaim(RegisteredClaims::AUDIENCE, array_merge($configured, $toAppend));
+ }
+
+ public function expiresAt(DateTimeImmutable $expiration): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration);
+ }
+
+ public function identifiedBy(string $id): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ID, $id);
+ }
+
+ public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt);
+ }
+
+ public function issuedBy(string $issuer): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::ISSUER, $issuer);
+ }
+
+ public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore);
+ }
+
+ public function relatedTo(string $subject): BuilderInterface
+ {
+ return $this->setClaim(RegisteredClaims::SUBJECT, $subject);
+ }
+
+ public function withHeader(string $name, mixed $value): BuilderInterface
+ {
+ $new = clone $this;
+ $new->headers[$name] = $value;
+
+ return $new;
+ }
+
+ public function withClaim(string $name, mixed $value): BuilderInterface
+ {
+ if (in_array($name, RegisteredClaims::ALL, true)) {
+ throw RegisteredClaimGiven::forClaim($name);
+ }
+
+ return $this->setClaim($name, $value);
+ }
+
+ /** @param non-empty-string $name */
+ private function setClaim(string $name, mixed $value): BuilderInterface
+ {
+ $new = clone $this;
+ $new->claims[$name] = $value;
+
+ return $new;
+ }
+
+ /**
+ * @param array $items
+ *
+ * @throws CannotEncodeContent When data cannot be converted to JSON.
+ */
+ private function encode(array $items): string
+ {
+ return $this->encoder->base64UrlEncode(
+ $this->encoder->jsonEncode($items),
+ );
+ }
+
+ public function getToken(Signer $signer, Key $key): UnencryptedToken
+ {
+ $headers = $this->headers;
+ $headers['alg'] = $signer->algorithmId();
+
+ $encodedHeaders = $this->encode($headers);
+ $encodedClaims = $this->encode($this->claimFormatter->formatClaims($this->claims));
+
+ $signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key);
+ $encodedSignature = $this->encoder->base64UrlEncode($signature);
+
+ return new Plain(
+ new DataSet($headers, $encodedHeaders),
+ new DataSet($this->claims, $encodedClaims),
+ new Signature($signature, $encodedSignature),
+ );
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Token/DataSet.php b/vendor/lcobucci/jwt/src/Token/DataSet.php
new file mode 100644
index 00000000..6c0b98ab
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Token/DataSet.php
@@ -0,0 +1,37 @@
+ $data */
+ public function __construct(private readonly array $data, private readonly string $encoded)
+ {
+ }
+
+ /** @param non-empty-string $name */
+ public function get(string $name, mixed $default = null): mixed
+ {
+ return $this->data[$name] ?? $default;
+ }
+
+ /** @param non-empty-string $name */
+ public function has(string $name): bool
+ {
+ return array_key_exists($name, $this->data);
+ }
+
+ /** @return array */
+ public function all(): array
+ {
+ return $this->data;
+ }
+
+ public function toString(): string
+ {
+ return $this->encoded;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php b/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php
new file mode 100644
index 00000000..abba344b
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php
@@ -0,0 +1,41 @@
+splitJwt($jwt);
+
+ if ($encodedHeaders === '') {
+ throw InvalidTokenStructure::missingHeaderPart();
+ }
+
+ if ($encodedClaims === '') {
+ throw InvalidTokenStructure::missingClaimsPart();
+ }
+
+ if ($encodedSignature === '') {
+ throw InvalidTokenStructure::missingSignaturePart();
+ }
+
+ $header = $this->parseHeader($encodedHeaders);
+
+ return new Plain(
+ new DataSet($header, $encodedHeaders),
+ new DataSet($this->parseClaims($encodedClaims), $encodedClaims),
+ $this->parseSignature($encodedSignature),
+ );
+ }
+
+ /**
+ * Splits the JWT string into an array
+ *
+ * @param non-empty-string $jwt
+ *
+ * @return string[]
+ *
+ * @throws InvalidTokenStructure When JWT doesn't have all parts.
+ */
+ private function splitJwt(string $jwt): array
+ {
+ $data = explode('.', $jwt);
+
+ if (count($data) !== 3) {
+ throw InvalidTokenStructure::missingOrNotEnoughSeparators();
+ }
+
+ return $data;
+ }
+
+ /**
+ * Parses the header from a string
+ *
+ * @param non-empty-string $data
+ *
+ * @return array
+ *
+ * @throws UnsupportedHeaderFound When an invalid header is informed.
+ * @throws InvalidTokenStructure When parsed content isn't an array.
+ */
+ private function parseHeader(string $data): array
+ {
+ $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
+
+ if (! is_array($header)) {
+ throw InvalidTokenStructure::arrayExpected('headers');
+ }
+
+ $this->guardAgainstEmptyStringKeys($header, 'headers');
+
+ if (array_key_exists('enc', $header)) {
+ throw UnsupportedHeaderFound::encryption();
+ }
+
+ if (! array_key_exists('typ', $header)) {
+ $header['typ'] = 'JWT';
+ }
+
+ return $header;
+ }
+
+ /**
+ * Parses the claim set from a string
+ *
+ * @param non-empty-string $data
+ *
+ * @return array
+ *
+ * @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates.
+ */
+ private function parseClaims(string $data): array
+ {
+ $claims = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
+
+ if (! is_array($claims)) {
+ throw InvalidTokenStructure::arrayExpected('claims');
+ }
+
+ $this->guardAgainstEmptyStringKeys($claims, 'claims');
+
+ if (array_key_exists(RegisteredClaims::AUDIENCE, $claims)) {
+ $claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE];
+ }
+
+ foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
+ if (! array_key_exists($claim, $claims)) {
+ continue;
+ }
+
+ $claims[$claim] = $this->convertDate($claims[$claim]);
+ }
+
+ return $claims;
+ }
+
+ /**
+ * @param array $array
+ * @param non-empty-string $part
+ *
+ * @phpstan-assert array $array
+ */
+ private function guardAgainstEmptyStringKeys(array $array, string $part): void
+ {
+ foreach ($array as $key => $value) {
+ if ($key === '') {
+ throw InvalidTokenStructure::arrayExpected($part);
+ }
+ }
+ }
+
+ /** @throws InvalidTokenStructure */
+ private function convertDate(int|float|string $timestamp): DateTimeImmutable
+ {
+ if (! is_numeric($timestamp)) {
+ throw InvalidTokenStructure::dateIsNotParseable($timestamp);
+ }
+
+ $normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', '');
+
+ $date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp);
+
+ if ($date === false) {
+ throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp);
+ }
+
+ return $date;
+ }
+
+ /**
+ * Returns the signature from given data
+ *
+ * @param non-empty-string $data
+ */
+ private function parseSignature(string $data): Signature
+ {
+ $hash = $this->decoder->base64UrlDecode($data);
+
+ return new Signature($hash, $data);
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Token/Plain.php b/vendor/lcobucci/jwt/src/Token/Plain.php
new file mode 100644
index 00000000..6af388d5
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Token/Plain.php
@@ -0,0 +1,85 @@
+headers;
+ }
+
+ public function claims(): DataSet
+ {
+ return $this->claims;
+ }
+
+ public function signature(): Signature
+ {
+ return $this->signature;
+ }
+
+ public function payload(): string
+ {
+ return $this->headers->toString() . '.' . $this->claims->toString();
+ }
+
+ public function isPermittedFor(string $audience): bool
+ {
+ return in_array($audience, $this->claims->get(RegisteredClaims::AUDIENCE, []), true);
+ }
+
+ public function isIdentifiedBy(string $id): bool
+ {
+ return $this->claims->get(RegisteredClaims::ID) === $id;
+ }
+
+ public function isRelatedTo(string $subject): bool
+ {
+ return $this->claims->get(RegisteredClaims::SUBJECT) === $subject;
+ }
+
+ public function hasBeenIssuedBy(string ...$issuers): bool
+ {
+ return in_array($this->claims->get(RegisteredClaims::ISSUER), $issuers, true);
+ }
+
+ public function hasBeenIssuedBefore(DateTimeInterface $now): bool
+ {
+ return $now >= $this->claims->get(RegisteredClaims::ISSUED_AT);
+ }
+
+ public function isMinimumTimeBefore(DateTimeInterface $now): bool
+ {
+ return $now >= $this->claims->get(RegisteredClaims::NOT_BEFORE);
+ }
+
+ public function isExpired(DateTimeInterface $now): bool
+ {
+ if (! $this->claims->has(RegisteredClaims::EXPIRATION_TIME)) {
+ return false;
+ }
+
+ return $now >= $this->claims->get(RegisteredClaims::EXPIRATION_TIME);
+ }
+
+ public function toString(): string
+ {
+ return $this->headers->toString() . '.'
+ . $this->claims->toString() . '.'
+ . $this->signature->toString();
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php b/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php
new file mode 100644
index 00000000..ce40a6ab
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php
@@ -0,0 +1,21 @@
+hash;
+ }
+
+ /**
+ * Returns the encoded version of the signature
+ *
+ * @return non-empty-string
+ */
+ public function toString(): string
+ {
+ return $this->encoded;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php b/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php
new file mode 100644
index 00000000..18240784
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php
@@ -0,0 +1,15 @@
+claims();
+
+ if (! $claims->has($this->claim)) {
+ throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php b/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php
new file mode 100644
index 00000000..d3ba1d6e
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php
@@ -0,0 +1,42 @@
+claims();
+
+ if (! $claims->has($this->claim)) {
+ throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this);
+ }
+
+ if ($claims->get($this->claim) !== $this->expectedValue) {
+ throw ConstraintViolation::error(
+ 'The claim "' . $this->claim . '" does not have the expected value',
+ $this,
+ );
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php b/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php
new file mode 100644
index 00000000..44541a75
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php
@@ -0,0 +1,26 @@
+isIdentifiedBy($this->id)) {
+ throw ConstraintViolation::error(
+ 'The token is not identified with the expected ID',
+ $this,
+ );
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php b/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php
new file mode 100644
index 00000000..8ba3890d
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php
@@ -0,0 +1,30 @@
+issuers = $issuers;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token->hasBeenIssuedBy(...$this->issuers)) {
+ throw ConstraintViolation::error(
+ 'The token was not issued by the given issuers',
+ $this,
+ );
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php b/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php
new file mode 100644
index 00000000..53abc0d4
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php
@@ -0,0 +1,15 @@
+leeway = $this->guardLeeway($leeway);
+ }
+
+ private function guardLeeway(?DateInterval $leeway): DateInterval
+ {
+ if ($leeway === null) {
+ return new DateInterval('PT0S');
+ }
+
+ if ($leeway->invert === 1) {
+ throw LeewayCannotBeNegative::create();
+ }
+
+ return $leeway;
+ }
+
+ public function assert(Token $token): void
+ {
+ $now = $this->clock->now();
+
+ $this->assertIssueTime($token, $now->add($this->leeway));
+ $this->assertMinimumTime($token, $now->add($this->leeway));
+ $this->assertExpiration($token, $now->sub($this->leeway));
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertExpiration(Token $token, DateTimeInterface $now): void
+ {
+ if ($token->isExpired($now)) {
+ throw ConstraintViolation::error('The token is expired', $this);
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertMinimumTime(Token $token, DateTimeInterface $now): void
+ {
+ if (! $token->isMinimumTimeBefore($now)) {
+ throw ConstraintViolation::error('The token cannot be used yet', $this);
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertIssueTime(Token $token, DateTimeInterface $now): void
+ {
+ if (! $token->hasBeenIssuedBefore($now)) {
+ throw ConstraintViolation::error('The token was issued in the future', $this);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php b/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php
new file mode 100644
index 00000000..48544c9a
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php
@@ -0,0 +1,26 @@
+isPermittedFor($this->audience)) {
+ throw ConstraintViolation::error(
+ 'The token is not allowed to be used by this audience',
+ $this,
+ );
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php b/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php
new file mode 100644
index 00000000..16493623
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php
@@ -0,0 +1,26 @@
+isRelatedTo($this->subject)) {
+ throw ConstraintViolation::error(
+ 'The token is not related to the expected subject',
+ $this,
+ );
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php
new file mode 100644
index 00000000..5c8e2656
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php
@@ -0,0 +1,32 @@
+headers()->get('alg') !== $this->signer->algorithmId()) {
+ throw ConstraintViolation::error('Token signer mismatch', $this);
+ }
+
+ if (! $this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) {
+ throw ConstraintViolation::error('Token signature mismatch', $this);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php
new file mode 100644
index 00000000..fb542fb3
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php
@@ -0,0 +1,38 @@
+ */
+ private readonly array $constraints;
+
+ public function __construct(SignedWithUntilDate ...$constraints)
+ {
+ $this->constraints = $constraints;
+ }
+
+ public function assert(Token $token): void
+ {
+ $errorMessage = 'It was not possible to verify the signature of the token, reasons:';
+
+ foreach ($this->constraints as $constraint) {
+ try {
+ $constraint->assert($token);
+
+ return;
+ } catch (ConstraintViolation $violation) {
+ $errorMessage .= PHP_EOL . '- ' . $violation->getMessage();
+ }
+ }
+
+ throw ConstraintViolation::error($errorMessage, $this);
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php
new file mode 100644
index 00000000..85429e89
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php
@@ -0,0 +1,47 @@
+verifySignature = new SignedWith($signer, $key);
+
+ $this->clock = $clock ?? new class () implements ClockInterface {
+ public function now(): DateTimeImmutable
+ {
+ return new DateTimeImmutable();
+ }
+ };
+ }
+
+ public function assert(Token $token): void
+ {
+ if ($this->validUntil < $this->clock->now()) {
+ throw ConstraintViolation::error(
+ 'This constraint was only usable until '
+ . $this->validUntil->format(DateTimeInterface::RFC3339),
+ $this,
+ );
+ }
+
+ $this->verifySignature->assert($token);
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php b/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php
new file mode 100644
index 00000000..93db0a3a
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php
@@ -0,0 +1,84 @@
+leeway = $this->guardLeeway($leeway);
+ }
+
+ private function guardLeeway(?DateInterval $leeway): DateInterval
+ {
+ if ($leeway === null) {
+ return new DateInterval('PT0S');
+ }
+
+ if ($leeway->invert === 1) {
+ throw LeewayCannotBeNegative::create();
+ }
+
+ return $leeway;
+ }
+
+ public function assert(Token $token): void
+ {
+ if (! $token instanceof UnencryptedToken) {
+ throw ConstraintViolation::error('You should pass a plain token', $this);
+ }
+
+ $now = $this->clock->now();
+
+ $this->assertIssueTime($token, $now->add($this->leeway));
+ $this->assertMinimumTime($token, $now->add($this->leeway));
+ $this->assertExpiration($token, $now->sub($this->leeway));
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertExpiration(UnencryptedToken $token, DateTimeInterface $now): void
+ {
+ if (! $token->claims()->has(Token\RegisteredClaims::EXPIRATION_TIME)) {
+ throw ConstraintViolation::error('"Expiration Time" claim missing', $this);
+ }
+
+ if ($token->isExpired($now)) {
+ throw ConstraintViolation::error('The token is expired', $this);
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertMinimumTime(UnencryptedToken $token, DateTimeInterface $now): void
+ {
+ if (! $token->claims()->has(Token\RegisteredClaims::NOT_BEFORE)) {
+ throw ConstraintViolation::error('"Not Before" claim missing', $this);
+ }
+
+ if (! $token->isMinimumTimeBefore($now)) {
+ throw ConstraintViolation::error('The token cannot be used yet', $this);
+ }
+ }
+
+ /** @throws ConstraintViolation */
+ private function assertIssueTime(UnencryptedToken $token, DateTimeInterface $now): void
+ {
+ if (! $token->claims()->has(Token\RegisteredClaims::ISSUED_AT)) {
+ throw ConstraintViolation::error('"Issued At" claim missing', $this);
+ }
+
+ if (! $token->hasBeenIssuedBefore($now)) {
+ throw ConstraintViolation::error('The token was issued in the future', $this);
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php b/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php
new file mode 100644
index 00000000..17c75468
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php
@@ -0,0 +1,24 @@
+|null $constraint */
+ public function __construct(
+ string $message = '',
+ public readonly ?string $constraint = null,
+ ) {
+ parent::__construct($message);
+ }
+
+ /** @param non-empty-string $message */
+ public static function error(string $message, Constraint $constraint): self
+ {
+ return new self(message: $message, constraint: $constraint::class);
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php b/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php
new file mode 100644
index 00000000..0ef80d25
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php
@@ -0,0 +1,11 @@
+getMessage();
+ },
+ $violations,
+ );
+
+ $message = "The token violates some mandatory constraints, details:\n";
+ $message .= implode("\n", $violations);
+
+ return $message;
+ }
+
+ /** @return ConstraintViolation[] */
+ public function violations(): array
+ {
+ return $this->violations;
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validation/SignedWith.php b/vendor/lcobucci/jwt/src/Validation/SignedWith.php
new file mode 100644
index 00000000..e721095f
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validation/SignedWith.php
@@ -0,0 +1,8 @@
+checkConstraint($constraint, $token, $violations);
+ }
+
+ if ($violations) {
+ throw RequiredConstraintsViolated::fromViolations(...$violations);
+ }
+ }
+
+ /** @param ConstraintViolation[] $violations */
+ private function checkConstraint(
+ Constraint $constraint,
+ Token $token,
+ array &$violations,
+ ): void {
+ try {
+ $constraint->assert($token);
+ } catch (ConstraintViolation $e) {
+ $violations[] = $e;
+ }
+ }
+
+ public function validate(Token $token, Constraint ...$constraints): bool
+ {
+ if ($constraints === []) {
+ throw new NoConstraintsGiven('No constraint given.');
+ }
+
+ try {
+ foreach ($constraints as $constraint) {
+ $constraint->assert($token);
+ }
+
+ return true;
+ } catch (ConstraintViolation) {
+ return false;
+ }
+ }
+}
diff --git a/vendor/lcobucci/jwt/src/Validator.php b/vendor/lcobucci/jwt/src/Validator.php
new file mode 100644
index 00000000..d0ce4b8c
--- /dev/null
+++ b/vendor/lcobucci/jwt/src/Validator.php
@@ -0,0 +1,20 @@
+clock = $clock;
+ }
+
+ public function doSomething()
+ {
+ /** @var DateTimeImmutable $currentDateAndTime */
+ $currentDateAndTime = $this->clock->now();
+ // do something useful with that information
+ }
+}
+```
+
+You can then pick one of the [implementations][implementation-url] of the interface to get a clock.
+
+If you want to implement the interface, you can require this package and
+implement `Psr\Clock\ClockInterface` in your code.
+
+Don't forget to add `psr/clock-implementation` to your `composer.json`s `provides`-section like this:
+
+```json
+{
+ "provides": {
+ "psr/clock-implementation": "1.0"
+ }
+}
+```
+
+And please read the [specification text][specification-url] for details on the interface.
+
+[psr-url]: https://www.php-fig.org/psr/psr-20
+[package-url]: https://packagist.org/packages/psr/clock
+[implementation-url]: https://packagist.org/providers/psr/clock-implementation
+[specification-url]: https://github.com/php-fig/fig-standards/blob/master/proposed/clock.md
diff --git a/vendor/psr/clock/composer.json b/vendor/psr/clock/composer.json
new file mode 100644
index 00000000..77992eda
--- /dev/null
+++ b/vendor/psr/clock/composer.json
@@ -0,0 +1,21 @@
+{
+ "name": "psr/clock",
+ "description": "Common interface for reading the clock.",
+ "keywords": ["psr", "psr-20", "time", "clock", "now"],
+ "homepage": "https://github.com/php-fig/clock",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ }
+}
diff --git a/vendor/psr/clock/src/ClockInterface.php b/vendor/psr/clock/src/ClockInterface.php
new file mode 100644
index 00000000..7b6d8d8a
--- /dev/null
+++ b/vendor/psr/clock/src/ClockInterface.php
@@ -0,0 +1,13 @@
+