From a8a5065553da55a31a57c059326b9cf4115487c9 Mon Sep 17 00:00:00 2001 From: Meghdad Fadaee Date: Sun, 31 May 2026 12:49:27 +0330 Subject: [PATCH] Implement Custom autoloader and JwtDecoder --- .gitignore | 3 +- composer.json | 16 - composer.lock | 85 -- dabestaniha-authenticate-bridge.php | 15 +- src/Autoloader.php | 47 ++ .../Controllers/AuthenticateController.php | 18 +- src/app/Http/Requests/BaseFormRequest.php | 5 +- src/app/Support/JwtDecoder.php | 134 ++++ vendor/autoload.php | 22 - vendor/composer/ClassLoader.php | 579 -------------- vendor/composer/InstalledVersions.php | 396 ---------- vendor/composer/LICENSE | 21 - vendor/composer/autoload_classmap.php | 10 - vendor/composer/autoload_files.php | 10 - vendor/composer/autoload_namespaces.php | 9 - vendor/composer/autoload_psr4.php | 12 - vendor/composer/autoload_real.php | 50 -- vendor/composer/autoload_static.php | 53 -- vendor/composer/installed.json | 73 -- vendor/composer/installed.php | 32 - vendor/composer/platform_check.php | 25 - vendor/firebase/php-jwt/CHANGELOG.md | 251 ------ vendor/firebase/php-jwt/LICENSE | 30 - vendor/firebase/php-jwt/README.md | 425 ---------- vendor/firebase/php-jwt/composer.json | 43 - .../php-jwt/src/BeforeValidException.php | 18 - vendor/firebase/php-jwt/src/CachedKeySet.php | 275 ------- .../firebase/php-jwt/src/ExpiredException.php | 30 - vendor/firebase/php-jwt/src/JWK.php | 363 --------- vendor/firebase/php-jwt/src/JWT.php | 745 ------------------ .../src/JWTExceptionWithPayloadInterface.php | 20 - vendor/firebase/php-jwt/src/Key.php | 54 -- .../php-jwt/src/SignatureInvalidException.php | 7 - 33 files changed, 208 insertions(+), 3668 deletions(-) delete mode 100644 composer.json delete mode 100644 composer.lock create mode 100644 src/Autoloader.php create mode 100644 src/app/Support/JwtDecoder.php delete mode 100644 vendor/autoload.php delete mode 100644 vendor/composer/ClassLoader.php delete mode 100644 vendor/composer/InstalledVersions.php delete mode 100644 vendor/composer/LICENSE delete mode 100644 vendor/composer/autoload_classmap.php delete mode 100644 vendor/composer/autoload_files.php delete mode 100644 vendor/composer/autoload_namespaces.php delete mode 100644 vendor/composer/autoload_psr4.php delete mode 100644 vendor/composer/autoload_real.php delete mode 100644 vendor/composer/autoload_static.php delete mode 100644 vendor/composer/installed.json delete mode 100644 vendor/composer/installed.php delete mode 100644 vendor/composer/platform_check.php delete mode 100755 vendor/firebase/php-jwt/CHANGELOG.md delete mode 100755 vendor/firebase/php-jwt/LICENSE delete mode 100755 vendor/firebase/php-jwt/README.md delete mode 100755 vendor/firebase/php-jwt/composer.json delete mode 100755 vendor/firebase/php-jwt/src/BeforeValidException.php delete mode 100755 vendor/firebase/php-jwt/src/CachedKeySet.php delete mode 100755 vendor/firebase/php-jwt/src/ExpiredException.php delete mode 100755 vendor/firebase/php-jwt/src/JWK.php delete mode 100755 vendor/firebase/php-jwt/src/JWT.php delete mode 100755 vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php delete mode 100755 vendor/firebase/php-jwt/src/Key.php delete mode 100755 vendor/firebase/php-jwt/src/SignatureInvalidException.php diff --git a/.gitignore b/.gitignore index 9ee4551..b31cbac 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,5 @@ wp-config.php *.zip .DS_Store .idea/ -!vendor/ node_modules/ -.env \ No newline at end of file +.env diff --git a/composer.json b/composer.json deleted file mode 100644 index eeee359..0000000 --- a/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "dabestaniha/authenticate-bridge", - "require": { - "php": "^8.0", - "firebase/php-jwt": "^7.0" - }, - "autoload": { - "psr-4": { - "Dabestaniha\\AuthenticateBridge\\App\\": "src/app/", - "Dabestaniha\\AuthenticateBridge\\": "src/" - }, - "files": [ - "src/helpers.php" - ] - } -} diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 9b94142..0000000 --- a/composer.lock +++ /dev/null @@ -1,85 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "1fdc3a2c72edb2354d568e34dfeb297d", - "packages": [ - { - "name": "firebase/php-jwt", - "version": "v7.0.5", - "source": { - "type": "git", - "url": "https://github.com/googleapis/php-jwt.git", - "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/47ad26bab5e7c70ae8a6f08ed25ff83631121380", - "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "guzzlehttp/guzzle": "^7.4", - "phpfastcache/phpfastcache": "^9.2", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "psr/cache": "^2.0||^3.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0" - }, - "suggest": { - "ext-sodium": "Support EdDSA (Ed25519) signatures", - "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" - }, - "type": "library", - "autoload": { - "psr-4": { - "Firebase\\JWT\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Neuman Vong", - "email": "neuman+pear@twilio.com", - "role": "Developer" - }, - { - "name": "Anant Narayanan", - "email": "anant@php.net", - "role": "Developer" - } - ], - "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", - "homepage": "https://github.com/firebase/php-jwt", - "keywords": [ - "jwt", - "php" - ], - "support": { - "issues": "https://github.com/googleapis/php-jwt/issues", - "source": "https://github.com/googleapis/php-jwt/tree/v7.0.5" - }, - "time": "2026-04-01T20:38:03+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^8.0" - }, - "platform-dev": {}, - "plugin-api-version": "2.9.0" -} diff --git a/dabestaniha-authenticate-bridge.php b/dabestaniha-authenticate-bridge.php index 78125f0..5c425a5 100644 --- a/dabestaniha-authenticate-bridge.php +++ b/dabestaniha-authenticate-bridge.php @@ -4,18 +4,29 @@ * Plugin Name: Mahak Authenticate Bridge * Description: Authenticate WordPress user via json web token from Mahakiha Application. * Version: 1.0 + * Requires PHP: 8.0 * Author: Dabestaniha * * Example: https://wordpress.test/mahak/login/?token=eyJ0... */ -require_once __DIR__.'/vendor/autoload.php'; - +use Dabestaniha\AuthenticateBridge\Autoloader; use Dabestaniha\AuthenticateBridge\App\Http\Controllers\AuthenticateController; use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageMenuController; use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageFormController; +require_once __DIR__.'/src/Autoloader.php'; + +Autoloader::register([ + 'Dabestaniha\\AuthenticateBridge\\App\\' => __DIR__.'/src/app', + 'Dabestaniha\\AuthenticateBridge\\' => __DIR__.'/src', +]); + +require_once __DIR__.'/src/helpers.php'; + add_action('init', fn() => AuthenticateController::resolve()); add_action('admin_menu', fn() => SettingsPageMenuController::resolve()); add_action('admin_init', fn() => SettingsPageFormController::resolve()); + +echo true; \ No newline at end of file diff --git a/src/Autoloader.php b/src/Autoloader.php new file mode 100644 index 0000000..4db2572 --- /dev/null +++ b/src/Autoloader.php @@ -0,0 +1,47 @@ + $baseDir) { + $prefix = rtrim($prefix, '\\').'\\'; + $normalized[$prefix] = rtrim($baseDir, DIRECTORY_SEPARATOR); + } + + uksort($normalized, fn (string $a, string $b) => strlen($b) <=> strlen($a)); + + $this->prefixes = $normalized; + } + + public function load(string $class): void + { + foreach ($this->prefixes as $prefix => $baseDir) { + if (strncmp($class, $prefix, strlen($prefix)) !== 0) { + continue; + } + + $relativeClass = substr($class, strlen($prefix)); + $file = $baseDir.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass).'.php'; + + if (is_file($file)) { + require_once $file; + } + + return; + } + } +} diff --git a/src/app/Http/Controllers/AuthenticateController.php b/src/app/Http/Controllers/AuthenticateController.php index e9d57f1..93c0d57 100644 --- a/src/app/Http/Controllers/AuthenticateController.php +++ b/src/app/Http/Controllers/AuthenticateController.php @@ -3,8 +3,8 @@ namespace Dabestaniha\AuthenticateBridge\App\Http\Controllers; use Dabestaniha\AuthenticateBridge\App\Http\Requests\MahakAuthenticateRequest; -use ReflectionMethod; -use Firebase\JWT; +use Dabestaniha\AuthenticateBridge\App\Support\JwtDecoder; +use UnexpectedValueException; class AuthenticateController extends InvocableController { @@ -32,9 +32,15 @@ class AuthenticateController extends InvocableController $jwt_secret = get_configured_option('jwt-secret'); try { - $decoded = (array) JWT\JWT::decode($token, new JWT\Key($jwt_secret, 'HS256')); - return (array) $decoded['data']; - } catch (\Exception $e) { + $decoded = JwtDecoder::decodeHs256($token, $jwt_secret); + $data = $decoded['data'] ?? null; + + if (!is_array($data)) { + throw new UnexpectedValueException('JWT data must be an object.'); + } + + return $data; + } catch (\Throwable $e) { wp_die(view('invalid-token'), 'Invalid Token', ['response' => 500]); } } @@ -75,4 +81,4 @@ class AuthenticateController extends InvocableController do_action('wp_login', get_userdata($user_id)->user_login, get_userdata($user_id)); return true; } -} \ No newline at end of file +} diff --git a/src/app/Http/Requests/BaseFormRequest.php b/src/app/Http/Requests/BaseFormRequest.php index ab53860..58f30b8 100644 --- a/src/app/Http/Requests/BaseFormRequest.php +++ b/src/app/Http/Requests/BaseFormRequest.php @@ -18,10 +18,7 @@ abstract class BaseFormRequest public function __construct() { $this->url = parse_url($_SERVER['REQUEST_URI']); - $this->form = [ - ...$_GET, - ...$_POST, - ]; + $this->form = array_merge($_GET, $_POST); } public function isRequestForThisRoute(): bool diff --git a/src/app/Support/JwtDecoder.php b/src/app/Support/JwtDecoder.php new file mode 100644 index 0000000..46da01b --- /dev/null +++ b/src/app/Support/JwtDecoder.php @@ -0,0 +1,134 @@ + 0) { + $value .= str_repeat('=', 4 - $remainder); + } + + $decoded = base64_decode(strtr($value, '-_', '+/'), true); + + if ($decoded === false) { + throw new UnexpectedValueException('JWT base64 encoding is invalid.'); + } + + return $decoded; + } + + private static function decodeJsonObject(string $json, string $section): array + { + try { + $decoded = json_decode($json, false, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $exception) { + throw new UnexpectedValueException("$section is not valid JSON.", 0, $exception); + } + + if (!$decoded instanceof stdClass) { + throw new UnexpectedValueException("$section must be a JSON object."); + } + + return self::objectToArray($decoded); + } + + private static function objectToArray(mixed $value): mixed + { + if ($value instanceof stdClass) { + $items = []; + + foreach (get_object_vars($value) as $key => $item) { + $items[$key] = self::objectToArray($item); + } + + return $items; + } + + if (is_array($value)) { + foreach ($value as $key => $item) { + $value[$key] = self::objectToArray($item); + } + } + + return $value; + } + + private static function validateTimestamps(array $payload): void + { + $now = time(); + + if (isset($payload['nbf']) && self::numericDate($payload['nbf'], 'nbf') > $now) { + throw new UnexpectedValueException('JWT cannot be used before nbf.'); + } + + if (isset($payload['iat']) && self::numericDate($payload['iat'], 'iat') > $now) { + throw new UnexpectedValueException('JWT cannot be used before iat.'); + } + + if (isset($payload['exp']) && self::numericDate($payload['exp'], 'exp') <= $now) { + throw new UnexpectedValueException('JWT has expired.'); + } + } + + private static function numericDate(mixed $value, string $claim): int + { + if (is_int($value) || is_float($value)) { + return (int) $value; + } + + if (is_string($value) && is_numeric($value)) { + return (int) $value; + } + + throw new UnexpectedValueException("JWT $claim claim must be numeric."); + } +} diff --git a/vendor/autoload.php b/vendor/autoload.php deleted file mode 100644 index 54f57ae..0000000 --- a/vendor/autoload.php +++ /dev/null @@ -1,22 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see https://www.php-fig.org/psr/psr-0/ - * @see https://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - /** @var \Closure(string):void */ - private static $includeFile; - - /** @var string|null */ - private $vendorDir; - - // PSR-4 - /** - * @var array> - */ - private $prefixLengthsPsr4 = array(); - /** - * @var array> - */ - private $prefixDirsPsr4 = array(); - /** - * @var list - */ - private $fallbackDirsPsr4 = array(); - - // PSR-0 - /** - * List of PSR-0 prefixes - * - * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) - * - * @var array>> - */ - private $prefixesPsr0 = array(); - /** - * @var list - */ - private $fallbackDirsPsr0 = array(); - - /** @var bool */ - private $useIncludePath = false; - - /** - * @var array - */ - private $classMap = array(); - - /** @var bool */ - private $classMapAuthoritative = false; - - /** - * @var array - */ - private $missingClasses = array(); - - /** @var string|null */ - private $apcuPrefix; - - /** - * @var array - */ - private static $registeredLoaders = array(); - - /** - * @param string|null $vendorDir - */ - public function __construct($vendorDir = null) - { - $this->vendorDir = $vendorDir; - self::initializeIncludeClosure(); - } - - /** - * @return array> - */ - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); - } - - return array(); - } - - /** - * @return array> - */ - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - /** - * @return list - */ - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - /** - * @return list - */ - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - /** - * @return array Array of classname => path - */ - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - * - * @return void - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void - */ - public function add($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 base directories - * - * @return void - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - * - * @return void - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - * - * @return void - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - * - * @return void - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - - if (null === $this->vendorDir) { - return; - } - - if ($prepend) { - self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; - } else { - unset(self::$registeredLoaders[$this->vendorDir]); - self::$registeredLoaders[$this->vendorDir] = $this; - } - } - - /** - * Unregisters this instance as an autoloader. - * - * @return void - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - - if (null !== $this->vendorDir) { - unset(self::$registeredLoaders[$this->vendorDir]); - } - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return true|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - $includeFile = self::$includeFile; - $includeFile($file); - - return true; - } - - return null; - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - /** - * Returns the currently registered loaders keyed by their corresponding vendor directories. - * - * @return array - */ - public static function getRegisteredLoaders() - { - return self::$registeredLoaders; - } - - /** - * @param string $class - * @param string $ext - * @return string|false - */ - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - $subPath = $class; - while (false !== $lastPos = strrpos($subPath, '\\')) { - $subPath = substr($subPath, 0, $lastPos); - $search = $subPath . '\\'; - if (isset($this->prefixDirsPsr4[$search])) { - $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); - foreach ($this->prefixDirsPsr4[$search] as $dir) { - if (file_exists($file = $dir . $pathEnd)) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } - - /** - * @return void - */ - private static function initializeIncludeClosure() - { - if (self::$includeFile !== null) { - return; - } - - /** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - */ - self::$includeFile = \Closure::bind(static function($file) { - include $file; - }, null, null); - } -} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php deleted file mode 100644 index 2052022..0000000 --- a/vendor/composer/InstalledVersions.php +++ /dev/null @@ -1,396 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer; - -use Composer\Autoload\ClassLoader; -use Composer\Semver\VersionParser; - -/** - * This class is copied in every Composer installed project and available to all - * - * See also https://getcomposer.org/doc/07-runtime.md#installed-versions - * - * To require its presence, you can require `composer-runtime-api ^2.0` - * - * @final - */ -class InstalledVersions -{ - /** - * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to - * @internal - */ - private static $selfDir = null; - - /** - * @var mixed[]|null - * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null - */ - private static $installed; - - /** - * @var bool - */ - private static $installedIsLocalDir; - - /** - * @var bool|null - */ - private static $canGetVendors; - - /** - * @var array[] - * @psalm-var array}> - */ - private static $installedByVendor = array(); - - /** - * Returns a list of all package names which are present, either by being installed, replaced or provided - * - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackages() - { - $packages = array(); - foreach (self::getInstalled() as $installed) { - $packages[] = array_keys($installed['versions']); - } - - if (1 === \count($packages)) { - return $packages[0]; - } - - return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); - } - - /** - * Returns a list of all package names with a specific type e.g. 'library' - * - * @param string $type - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackagesByType($type) - { - $packagesByType = array(); - - foreach (self::getInstalled() as $installed) { - foreach ($installed['versions'] as $name => $package) { - if (isset($package['type']) && $package['type'] === $type) { - $packagesByType[] = $name; - } - } - } - - return $packagesByType; - } - - /** - * Checks whether the given package is installed - * - * This also returns true if the package name is provided or replaced by another package - * - * @param string $packageName - * @param bool $includeDevRequirements - * @return bool - */ - public static function isInstalled($packageName, $includeDevRequirements = true) - { - foreach (self::getInstalled() as $installed) { - if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; - } - } - - return false; - } - - /** - * Checks whether the given package satisfies a version constraint - * - * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: - * - * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') - * - * @param VersionParser $parser Install composer/semver to have access to this class and functionality - * @param string $packageName - * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package - * @return bool - */ - public static function satisfies(VersionParser $parser, $packageName, $constraint) - { - $constraint = $parser->parseConstraints((string) $constraint); - $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - - return $provided->matches($constraint); - } - - /** - * Returns a version constraint representing all the range(s) which are installed for a given package - * - * It is easier to use this via isInstalled() with the $constraint argument if you need to check - * whether a given version of a package is installed, and not just whether it exists - * - * @param string $packageName - * @return string Version constraint usable with composer/semver - */ - public static function getVersionRanges($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - $ranges = array(); - if (isset($installed['versions'][$packageName]['pretty_version'])) { - $ranges[] = $installed['versions'][$packageName]['pretty_version']; - } - if (array_key_exists('aliases', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); - } - if (array_key_exists('replaced', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); - } - if (array_key_exists('provided', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); - } - - return implode(' || ', $ranges); - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['version'])) { - return null; - } - - return $installed['versions'][$packageName]['version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getPrettyVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['pretty_version'])) { - return null; - } - - return $installed['versions'][$packageName]['pretty_version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference - */ - public static function getReference($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['reference'])) { - return null; - } - - return $installed['versions'][$packageName]['reference']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. - */ - public static function getInstallPath($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @return array - * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} - */ - public static function getRootPackage() - { - $installed = self::getInstalled(); - - return $installed[0]['root']; - } - - /** - * Returns the raw installed.php data for custom implementations - * - * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. - * @return array[] - * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} - */ - public static function getRawData() - { - @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = include __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } - - return self::$installed; - } - - /** - * Returns the raw data of all installed.php which are currently loaded for custom implementations - * - * @return array[] - * @psalm-return list}> - */ - public static function getAllRawData() - { - return self::getInstalled(); - } - - /** - * Lets you reload the static array from another file - * - * This is only useful for complex integrations in which a project needs to use - * this class but then also needs to execute another project's autoloader in process, - * and wants to ensure both projects have access to their version of installed.php. - * - * A typical case would be PHPUnit, where it would need to make sure it reads all - * the data it needs from this class, then call reload() with - * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure - * the project in which it runs can then also use this class safely, without - * interference between PHPUnit's dependencies and the project's dependencies. - * - * @param array[] $data A vendor/composer/installed.php data set - * @return void - * - * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data - */ - public static function reload($data) - { - self::$installed = $data; - self::$installedByVendor = array(); - - // when using reload, we disable the duplicate protection to ensure that self::$installed data is - // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, - // so we have to assume it does not, and that may result in duplicate data being returned when listing - // all installed packages for example - self::$installedIsLocalDir = false; - } - - /** - * @return string - */ - private static function getSelfDir() - { - if (self::$selfDir === null) { - self::$selfDir = strtr(__DIR__, '\\', '/'); - } - - return self::$selfDir; - } - - /** - * @return array[] - * @psalm-return list}> - */ - private static function getInstalled() - { - if (null === self::$canGetVendors) { - self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); - } - - $installed = array(); - $copiedLocalDir = false; - - if (self::$canGetVendors) { - $selfDir = self::getSelfDir(); - foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { - $vendorDir = strtr($vendorDir, '\\', '/'); - if (isset(self::$installedByVendor[$vendorDir])) { - $installed[] = self::$installedByVendor[$vendorDir]; - } elseif (is_file($vendorDir.'/composer/installed.php')) { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require $vendorDir.'/composer/installed.php'; - self::$installedByVendor[$vendorDir] = $required; - $installed[] = $required; - if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { - self::$installed = $required; - self::$installedIsLocalDir = true; - } - } - if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { - $copiedLocalDir = true; - } - } - } - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require __DIR__ . '/installed.php'; - self::$installed = $required; - } else { - self::$installed = array(); - } - } - - if (self::$installed !== array() && !$copiedLocalDir) { - $installed[] = self::$installed; - } - - return $installed; - } -} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE deleted file mode 100644 index f27399a..0000000 --- a/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) Nils Adermann, Jordi Boggiano - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php deleted file mode 100644 index 0fb0a2c..0000000 --- a/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,10 +0,0 @@ - $vendorDir . '/composer/InstalledVersions.php', -); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php deleted file mode 100644 index 66d28d9..0000000 --- a/vendor/composer/autoload_files.php +++ /dev/null @@ -1,10 +0,0 @@ - $baseDir . '/src/helpers.php', -); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php deleted file mode 100644 index 15a2ff3..0000000 --- a/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,9 +0,0 @@ - array($vendorDir . '/firebase/php-jwt/src'), - 'Dabestaniha\\AuthenticateBridge\\App\\' => array($baseDir . '/src/app'), - 'Dabestaniha\\AuthenticateBridge\\' => array($baseDir . '/src'), -); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php deleted file mode 100644 index e77bcdc..0000000 --- a/vendor/composer/autoload_real.php +++ /dev/null @@ -1,50 +0,0 @@ -register(true); - - $filesToLoad = \Composer\Autoload\ComposerStaticInit1fdc3a2c72edb2354d568e34dfeb297d::$files; - $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } - }, null, null); - foreach ($filesToLoad as $fileIdentifier => $file) { - $requireFile($fileIdentifier, $file); - } - - return $loader; - } -} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php deleted file mode 100644 index 3a6c10a..0000000 --- a/vendor/composer/autoload_static.php +++ /dev/null @@ -1,53 +0,0 @@ - __DIR__ . '/../..' . '/src/helpers.php', - ); - - public static $prefixLengthsPsr4 = array ( - 'F' => - array ( - 'Firebase\\JWT\\' => 13, - ), - 'D' => - array ( - 'Dabestaniha\\AuthenticateBridge\\App\\' => 35, - 'Dabestaniha\\AuthenticateBridge\\' => 31, - ), - ); - - public static $prefixDirsPsr4 = array ( - 'Firebase\\JWT\\' => - array ( - 0 => __DIR__ . '/..' . '/firebase/php-jwt/src', - ), - 'Dabestaniha\\AuthenticateBridge\\App\\' => - array ( - 0 => __DIR__ . '/../..' . '/src/app', - ), - 'Dabestaniha\\AuthenticateBridge\\' => - array ( - 0 => __DIR__ . '/../..' . '/src', - ), - ); - - public static $classMap = array ( - 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit1fdc3a2c72edb2354d568e34dfeb297d::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit1fdc3a2c72edb2354d568e34dfeb297d::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit1fdc3a2c72edb2354d568e34dfeb297d::$classMap; - - }, null, ClassLoader::class); - } -} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json deleted file mode 100644 index 75235b2..0000000 --- a/vendor/composer/installed.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "packages": [ - { - "name": "firebase/php-jwt", - "version": "v7.0.5", - "version_normalized": "7.0.5.0", - "source": { - "type": "git", - "url": "https://github.com/googleapis/php-jwt.git", - "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/47ad26bab5e7c70ae8a6f08ed25ff83631121380", - "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "guzzlehttp/guzzle": "^7.4", - "phpfastcache/phpfastcache": "^9.2", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "psr/cache": "^2.0||^3.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0" - }, - "suggest": { - "ext-sodium": "Support EdDSA (Ed25519) signatures", - "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" - }, - "time": "2026-04-01T20:38:03+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Firebase\\JWT\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Neuman Vong", - "email": "neuman+pear@twilio.com", - "role": "Developer" - }, - { - "name": "Anant Narayanan", - "email": "anant@php.net", - "role": "Developer" - } - ], - "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", - "homepage": "https://github.com/firebase/php-jwt", - "keywords": [ - "jwt", - "php" - ], - "support": { - "issues": "https://github.com/googleapis/php-jwt/issues", - "source": "https://github.com/googleapis/php-jwt/tree/v7.0.5" - }, - "install-path": "../firebase/php-jwt" - } - ], - "dev": true, - "dev-package-names": [] -} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php deleted file mode 100644 index a40ca27..0000000 --- a/vendor/composer/installed.php +++ /dev/null @@ -1,32 +0,0 @@ - array( - 'name' => 'dabestaniha/authenticate-bridge', - 'pretty_version' => 'dev-main', - 'version' => 'dev-main', - 'reference' => '97b39bda75a620048b6186351b47b42a74cecb19', - 'type' => 'library', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev' => true, - ), - 'versions' => array( - 'dabestaniha/authenticate-bridge' => array( - 'pretty_version' => 'dev-main', - 'version' => 'dev-main', - 'reference' => '97b39bda75a620048b6186351b47b42a74cecb19', - 'type' => 'library', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'firebase/php-jwt' => array( - 'pretty_version' => 'v7.0.5', - 'version' => '7.0.5.0', - 'reference' => '47ad26bab5e7c70ae8a6f08ed25ff83631121380', - 'type' => 'library', - 'install_path' => __DIR__ . '/../firebase/php-jwt', - 'aliases' => array(), - 'dev_requirement' => false, - ), - ), -); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php deleted file mode 100644 index a70ba47..0000000 --- a/vendor/composer/platform_check.php +++ /dev/null @@ -1,25 +0,0 @@ -= 80000)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.'; -} - -if ($issues) { - if (!headers_sent()) { - header('HTTP/1.1 500 Internal Server Error'); - } - if (!ini_get('display_errors')) { - if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { - fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); - } elseif (!headers_sent()) { - echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; - } - } - throw new \RuntimeException( - 'Composer detected issues in your platform: ' . implode(' ', $issues) - ); -} diff --git a/vendor/firebase/php-jwt/CHANGELOG.md b/vendor/firebase/php-jwt/CHANGELOG.md deleted file mode 100755 index 498fb00..0000000 --- a/vendor/firebase/php-jwt/CHANGELOG.md +++ /dev/null @@ -1,251 +0,0 @@ -# Changelog - -## [7.0.5](https://github.com/firebase/php-jwt/compare/v7.0.4...v7.0.5) (2026-03-31) - - -### Bug Fixes - -* RSA from JWK sometimes returns empty Instance ([#628](https://github.com/firebase/php-jwt/issues/628)) ([b4c78aa](https://github.com/firebase/php-jwt/commit/b4c78aa731664122198ad36c0033aa29e807397a)) - -## [7.0.4](https://github.com/firebase/php-jwt/compare/v7.0.3...v7.0.4) (2026-03-27) - - -### Bug Fixes - -* readme examples, add tests for all examples ([#626](https://github.com/firebase/php-jwt/issues/626)) ([510a00c](https://github.com/firebase/php-jwt/commit/510a00c0e6353bc7d68412fab67e57a13954cb46)) -* use urlsafeB64Decode everywhere ([#627](https://github.com/firebase/php-jwt/issues/627)) ([b889495](https://github.com/firebase/php-jwt/commit/b889495c83ddc3f3885ca3f0b65b41b1cb37a3b1)) - -## [7.0.3](https://github.com/firebase/php-jwt/compare/v7.0.2...v7.0.3) (2026-02-18) - - -### Miscellaneous Chores - -* add environment for Release Please job ([#619](https://github.com/firebase/php-jwt/issues/619)) ([300fd02](https://github.com/firebase/php-jwt/commit/300fd02c883f096c9067df652dbd23f62cb5e2a7)) - -## [7.0.2](https://github.com/firebase/php-jwt/compare/v7.0.1...v7.0.2) (2025-12-16) - - -### Bug Fixes - -* add key length validation for ec keys ([#615](https://github.com/firebase/php-jwt/issues/615)) ([7044f9a](https://github.com/firebase/php-jwt/commit/7044f9ae7e7d175d28cca71714feb236f1c0e252)) - -## [7.0.0](https://github.com/firebase/php-jwt/compare/v6.11.1...v7.0.0) (2025-12-15) - - -### ⚠️ ⚠️ ⚠️ Security Fixes ⚠️ ⚠️ ⚠️ - * add key size validation ([#613](https://github.com/firebase/php-jwt/issues/613)) ([6b80341](https://github.com/firebase/php-jwt/commit/6b80341bf57838ea2d011487917337901cd71576)) - **NOTE**: This fix will cause keys with a size below the minimally allowed size to break. - -### Features - -* add SensitiveParameter attribute to security-critical parameters ([#603](https://github.com/firebase/php-jwt/issues/603)) ([4dbfac0](https://github.com/firebase/php-jwt/commit/4dbfac0260eeb0e9e643063c99998e3219cc539b)) -* store timestamp in `ExpiredException` ([#604](https://github.com/firebase/php-jwt/issues/604)) ([f174826](https://github.com/firebase/php-jwt/commit/f1748260d218a856b6a0c23715ac7fae1d7ca95b)) - - -### Bug Fixes - -* validate iat and nbf on payload ([#568](https://github.com/firebase/php-jwt/issues/568)) ([953b2c8](https://github.com/firebase/php-jwt/commit/953b2c88bb445b7e3bb82a5141928f13d7343afd)) - -## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09) - - -### Bug Fixes - -* update error text for consistency ([#528](https://github.com/firebase/php-jwt/issues/528)) ([c11113a](https://github.com/firebase/php-jwt/commit/c11113afa13265e016a669e75494b9203b8a7775)) - -## [6.11.0](https://github.com/firebase/php-jwt/compare/v6.10.2...v6.11.0) (2025-01-23) - - -### Features - -* support octet typed JWK ([#587](https://github.com/firebase/php-jwt/issues/587)) ([7cb8a26](https://github.com/firebase/php-jwt/commit/7cb8a265fa81edf2fa6ef8098f5bc5ae573c33ad)) - - -### Bug Fixes - -* refactor constructor Key to use PHP 8.0 syntax ([#577](https://github.com/firebase/php-jwt/issues/577)) ([29fa2ce](https://github.com/firebase/php-jwt/commit/29fa2ce9e0582cd397711eec1e80c05ce20fabca)) - -## [6.10.2](https://github.com/firebase/php-jwt/compare/v6.10.1...v6.10.2) (2024-11-24) - - -### Bug Fixes - -* Mitigate PHP8.4 deprecation warnings ([#570](https://github.com/firebase/php-jwt/issues/570)) ([76808fa](https://github.com/firebase/php-jwt/commit/76808fa227f3811aa5cdb3bf81233714b799a5b5)) -* support php 8.4 ([#583](https://github.com/firebase/php-jwt/issues/583)) ([e3d68b0](https://github.com/firebase/php-jwt/commit/e3d68b044421339443c74199edd020e03fb1887e)) - -## [6.10.1](https://github.com/firebase/php-jwt/compare/v6.10.0...v6.10.1) (2024-05-18) - - -### Bug Fixes - -* ensure ratelimit expiry is set every time ([#556](https://github.com/firebase/php-jwt/issues/556)) ([09cb208](https://github.com/firebase/php-jwt/commit/09cb2081c2c3bc0f61e2f2a5fbea5741f7498648)) -* ratelimit cache expiration ([#550](https://github.com/firebase/php-jwt/issues/550)) ([dda7250](https://github.com/firebase/php-jwt/commit/dda725033585ece30ff8cae8937320d7e9f18bae)) - -## [6.10.0](https://github.com/firebase/php-jwt/compare/v6.9.0...v6.10.0) (2023-11-28) - - -### Features - -* allow typ header override ([#546](https://github.com/firebase/php-jwt/issues/546)) ([79cb30b](https://github.com/firebase/php-jwt/commit/79cb30b729a22931b2fbd6b53f20629a83031ba9)) - -## [6.9.0](https://github.com/firebase/php-jwt/compare/v6.8.1...v6.9.0) (2023-10-04) - - -### Features - -* add payload to jwt exception ([#521](https://github.com/firebase/php-jwt/issues/521)) ([175edf9](https://github.com/firebase/php-jwt/commit/175edf958bb61922ec135b2333acf5622f2238a2)) - -## [6.8.1](https://github.com/firebase/php-jwt/compare/v6.8.0...v6.8.1) (2023-07-14) - - -### Bug Fixes - -* accept float claims but round down to ignore them ([#492](https://github.com/firebase/php-jwt/issues/492)) ([3936842](https://github.com/firebase/php-jwt/commit/39368423beeaacb3002afa7dcb75baebf204fe7e)) -* different BeforeValidException messages for nbf and iat ([#526](https://github.com/firebase/php-jwt/issues/526)) ([0a53cf2](https://github.com/firebase/php-jwt/commit/0a53cf2986e45c2bcbf1a269f313ebf56a154ee4)) - -## [6.8.0](https://github.com/firebase/php-jwt/compare/v6.7.0...v6.8.0) (2023-06-14) - - -### Features - -* add support for P-384 curve ([#515](https://github.com/firebase/php-jwt/issues/515)) ([5de4323](https://github.com/firebase/php-jwt/commit/5de4323f4baf4d70bca8663bd87682a69c656c3d)) - - -### Bug Fixes - -* handle invalid http responses ([#508](https://github.com/firebase/php-jwt/issues/508)) ([91c39c7](https://github.com/firebase/php-jwt/commit/91c39c72b22fc3e1191e574089552c1f2041c718)) - -## [6.7.0](https://github.com/firebase/php-jwt/compare/v6.6.0...v6.7.0) (2023-06-14) - - -### Features - -* add ed25519 support to JWK (public keys) ([#452](https://github.com/firebase/php-jwt/issues/452)) ([e53979a](https://github.com/firebase/php-jwt/commit/e53979abae927de916a75b9d239cfda8ce32be2a)) - -## [6.6.0](https://github.com/firebase/php-jwt/compare/v6.5.0...v6.6.0) (2023-06-13) - - -### Features - -* allow get headers when decoding token ([#442](https://github.com/firebase/php-jwt/issues/442)) ([fb85f47](https://github.com/firebase/php-jwt/commit/fb85f47cfaeffdd94faf8defdf07164abcdad6c3)) - - -### Bug Fixes - -* only check iat if nbf is not used ([#493](https://github.com/firebase/php-jwt/issues/493)) ([398ccd2](https://github.com/firebase/php-jwt/commit/398ccd25ea12fa84b9e4f1085d5ff448c21ec797)) - -## [6.5.0](https://github.com/firebase/php-jwt/compare/v6.4.0...v6.5.0) (2023-05-12) - - -### Bug Fixes - -* allow KID of '0' ([#505](https://github.com/firebase/php-jwt/issues/505)) ([9dc46a9](https://github.com/firebase/php-jwt/commit/9dc46a9c3e5801294249cfd2554c5363c9f9326a)) - - -### Miscellaneous Chores - -* drop support for PHP 7.3 ([#495](https://github.com/firebase/php-jwt/issues/495)) - -## [6.4.0](https://github.com/firebase/php-jwt/compare/v6.3.2...v6.4.0) (2023-02-08) - - -### Features - -* add support for W3C ES256K ([#462](https://github.com/firebase/php-jwt/issues/462)) ([213924f](https://github.com/firebase/php-jwt/commit/213924f51936291fbbca99158b11bd4ae56c2c95)) -* improve caching by only decoding jwks when necessary ([#486](https://github.com/firebase/php-jwt/issues/486)) ([78d3ed1](https://github.com/firebase/php-jwt/commit/78d3ed1073553f7d0bbffa6c2010009a0d483d5c)) - -## [6.3.2](https://github.com/firebase/php-jwt/compare/v6.3.1...v6.3.2) (2022-11-01) - - -### Bug Fixes - -* check kid before using as array index ([bad1b04](https://github.com/firebase/php-jwt/commit/bad1b040d0c736bbf86814c6b5ae614f517cf7bd)) - -## [6.3.1](https://github.com/firebase/php-jwt/compare/v6.3.0...v6.3.1) (2022-11-01) - - -### Bug Fixes - -* casing of GET for PSR compat ([#451](https://github.com/firebase/php-jwt/issues/451)) ([60b52b7](https://github.com/firebase/php-jwt/commit/60b52b71978790eafcf3b95cfbd83db0439e8d22)) -* string interpolation format for php 8.2 ([#446](https://github.com/firebase/php-jwt/issues/446)) ([2e07d8a](https://github.com/firebase/php-jwt/commit/2e07d8a1524d12b69b110ad649f17461d068b8f2)) - -## 6.3.0 / 2022-07-15 - - - Added ES256 support to JWK parsing ([#399](https://github.com/firebase/php-jwt/pull/399)) - - Fixed potential caching error in `CachedKeySet` by caching jwks as strings ([#435](https://github.com/firebase/php-jwt/pull/435)) - -## 6.2.0 / 2022-05-14 - - - Added `CachedKeySet` ([#397](https://github.com/firebase/php-jwt/pull/397)) - - Added `$defaultAlg` parameter to `JWT::parseKey` and `JWT::parseKeySet` ([#426](https://github.com/firebase/php-jwt/pull/426)). - -## 6.1.0 / 2022-03-23 - - - Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0 - - Add parameter typing and return types where possible - -## 6.0.0 / 2022-01-24 - - - **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) for more information. - - New Key object to prevent key/algorithm type confusion (#365) - - Add JWK support (#273) - - Add ES256 support (#256) - - Add ES384 support (#324) - - Add Ed25519 support (#343) - -## 5.0.0 / 2017-06-26 -- Support RS384 and RS512. - See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)! -- Add an example for RS256 openssl. - See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)! -- Detect invalid Base64 encoding in signature. - See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)! -- Update `JWT::verify` to handle OpenSSL errors. - See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)! -- Add `array` type hinting to `decode` method - See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)! -- Add all JSON error types. - See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)! -- Bugfix 'kid' not in given key list. - See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)! -- Miscellaneous cleanup, documentation and test fixes. - See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115), - [#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and - [#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman), - [@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)! - -## 4.0.0 / 2016-07-17 -- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)! -- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)! -- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)! -- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)! - -## 3.0.0 / 2015-07-22 -- Minimum PHP version updated from `5.2.0` to `5.3.0`. -- Add `\Firebase\JWT` namespace. See -[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to -[@Dashron](https://github.com/Dashron)! -- Require a non-empty key to decode and verify a JWT. See -[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to -[@sjones608](https://github.com/sjones608)! -- Cleaner documentation blocks in the code. See -[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to -[@johanderuijter](https://github.com/johanderuijter)! - -## 2.2.0 / 2015-06-22 -- Add support for adding custom, optional JWT headers to `JWT::encode()`. See -[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to -[@mcocaro](https://github.com/mcocaro)! - -## 2.1.0 / 2015-05-20 -- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew -between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)! -- Add support for passing an object implementing the `ArrayAccess` interface for -`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)! - -## 2.0.0 / 2015-04-01 -- **Note**: It is strongly recommended that you update to > v2.0.0 to address - known security vulnerabilities in prior versions when both symmetric and - asymmetric keys are used together. -- Update signature for `JWT::decode(...)` to require an array of supported - algorithms to use when verifying token signatures. diff --git a/vendor/firebase/php-jwt/LICENSE b/vendor/firebase/php-jwt/LICENSE deleted file mode 100755 index 11c0146..0000000 --- a/vendor/firebase/php-jwt/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2011, Neuman Vong - -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 copyright holder nor the names of other - 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 -OWNER 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/firebase/php-jwt/README.md b/vendor/firebase/php-jwt/README.md deleted file mode 100755 index 2ca7162..0000000 --- a/vendor/firebase/php-jwt/README.md +++ /dev/null @@ -1,425 +0,0 @@ -![Build Status](https://github.com/firebase/php-jwt/actions/workflows/tests.yml/badge.svg) -[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt) -[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt) -[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt) - -PHP-JWT -======= -A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519). - -Installation ------------- - -Use composer to manage your dependencies and download PHP-JWT: - -```bash -composer require firebase/php-jwt -``` - -Optionally, install the `paragonie/sodium_compat` package from composer if your -php env does not have libsodium installed: - -```bash -composer require paragonie/sodium_compat -``` - -## Example - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\Key; - -$key = 'example_key_of_sufficient_length'; -$payload = [ - 'iss' => 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -/** - * IMPORTANT: - * You must specify supported algorithms for your application. See - * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 - * for a list of spec-compliant algorithms. - */ -$jwt = JWT::encode($payload, $key, 'HS256'); -$decoded = JWT::decode($jwt, new Key($key, 'HS256')); -print_r($decoded); - -// Pass a stdClass in as the third parameter to get the decoded header values -$headers = new stdClass(); -$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers); -print_r($headers); - -/* - NOTE: This will now be an object instead of an associative array. To get - an associative array, you will need to cast it as such: -*/ - -$decoded_array = (array) $decoded; - -/** - * You can add a leeway to account for when there is a clock skew times between - * the signing and verifying servers. It is recommended that this leeway should - * not be bigger than a few minutes. - * - * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef - */ -JWT::$leeway = 60; // $leeway in seconds -$decoded = JWT::decode($jwt, new Key($key, 'HS256')); -``` - -## Example encode/decode headers - -Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by -this library. This is because without verifying the JWT, the header values could have been tampered with. -Any value pulled from an unverified header should be treated as if it could be any string sent in from an -attacker. If this is something you still want to do in your application for whatever reason, it's possible to -decode the header values manually simply by calling `json_decode` and `base64_decode` on the JWT -header part: -```php -use Firebase\JWT\JWT; - -$key = 'example_key_of_sufficient_length'; -$payload = [ - 'iss' => 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -$headers = [ - 'x-forwarded-for' => 'www.google.com' -]; - -// Encode headers in the JWT string -$jwt = JWT::encode($payload, $key, 'HS256', null, $headers); - -// Decode headers from the JWT string WITHOUT validation -// **IMPORTANT**: This operation is vulnerable to attacks, as the JWT has not yet been verified. -// These headers could be any value sent by an attacker. -list($headersB64, $payloadB64, $sig) = explode('.', $jwt); -$decoded = json_decode(base64_decode($headersB64), true); - -print_r($decoded); -``` - -## Example with RS256 (openssl) - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\Key; - -$privateKey = << 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -$jwt = JWT::encode($payload, $privateKey, 'RS256'); -echo "Encode:\n" . print_r($jwt, true) . "\n"; - -$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); - -/* - NOTE: This will now be an object instead of an associative array. To get - an associative array, you will need to cast it as such: -*/ - -$decoded_array = (array) $decoded; -echo "Decode:\n" . print_r($decoded_array, true) . "\n"; -``` - -## Example with a passphrase - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\Key; - -// Your passphrase -$passphrase = '[YOUR_PASSPHRASE]'; - -// Your private key file with passphrase -// Can be generated with "ssh-keygen -t rsa -m pem" -$privateKeyFile = '/path/to/key-with-passphrase.pem'; - -/** @var OpenSSLAsymmetricKey $privateKey */ -$privateKey = openssl_pkey_get_private( - file_get_contents($privateKeyFile), - $passphrase -); - -$payload = [ - 'iss' => 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -$jwt = JWT::encode($payload, $privateKey, 'RS256'); -echo "Encode:\n" . print_r($jwt, true) . "\n"; - -// Get public key from the private key, or pull from from a file. -$publicKey = openssl_pkey_get_details($privateKey)['key']; - -$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); -echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; -``` - -## Example with EdDSA (libsodium and Ed25519 signature) - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\Key; - -// Public and private keys are expected to be Base64 encoded. The last -// non-empty line is used so that keys can be generated with -// sodium_crypto_sign_keypair(). The secret keys generated by other tools may -// need to be adjusted to match the input expected by libsodium. - -$keyPair = sodium_crypto_sign_keypair(); - -$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair)); - -$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair)); - -$payload = [ - 'iss' => 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -$jwt = JWT::encode($payload, $privateKey, 'EdDSA'); -echo "Encode:\n" . print_r($jwt, true) . "\n"; - -$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA')); -echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; -``` - -## Example with multiple keys - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\Key; - -// Example RSA keys from previous example -// $privateRsKey = '...'; -// $publicRsKey = '...'; - -// Example EdDSA keys from previous example -// $privateEcKey = '...'; -// $publicEcKey = '...'; - -$payload = [ - 'iss' => 'example.org', - 'aud' => 'example.com', - 'iat' => 1356999524, - 'nbf' => 1357000000 -]; - -$jwt1 = JWT::encode($payload, $privateRsKey, 'RS256', 'kid1'); -$jwt2 = JWT::encode($payload, $privateEcKey, 'EdDSA', 'kid2'); -echo "Encode 1:\n" . print_r($jwt1, true) . "\n"; -echo "Encode 2:\n" . print_r($jwt2, true) . "\n"; - -$keys = [ - 'kid1' => new Key($publicRsKey, 'RS256'), - 'kid2' => new Key($publicEcKey, 'EdDSA'), -]; - -$decoded1 = JWT::decode($jwt1, $keys); -$decoded2 = JWT::decode($jwt2, $keys); - -echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n"; -echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n"; -``` - -## Using JWKs - -```php -use Firebase\JWT\JWK; -use Firebase\JWT\JWT; - -// Set of keys. The "keys" key is required. For example, the JSON response to -// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk -$jwks = ['keys' => []]; - -// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key -// objects. Pass this as the second parameter to JWT::decode. -$decoded = JWT::decode($jwt, JWK::parseKeySet($jwks)); -print_r($decoded); -``` - -## Using Cached Key Sets - -The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI. -This has the following advantages: - -1. The results are cached for performance. -2. If an unrecognized key is requested, the cache is refreshed, to accomodate for key rotation. -3. If rate limiting is enabled, the JWKS URI will not make more than 10 requests a second. - -```php -use Firebase\JWT\CachedKeySet; -use Firebase\JWT\JWT; - -// The URI for the JWKS you wish to cache the results from -$jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk'; - -// Create an HTTP client (can be any PSR-7 compatible HTTP client) -$httpClient = new GuzzleHttp\Client(); - -// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory) -$httpFactory = new GuzzleHttp\Psr7\HttpFactory(); - -// Create a cache item pool (can be any PSR-6 compatible cache item pool) -$cacheItemPool = Phpfastcache\CacheManager::getInstance('files'); - -$keySet = new CachedKeySet( - $jwksUri, - $httpClient, - $httpFactory, - $cacheItemPool, - null, // $expiresAfter int seconds to set the JWKS to expire - true // $rateLimit true to enable rate limit of 10 RPS on lookup of invalid keys -); - -$jwt = 'eyJhbGci...'; // Some JWT signed by a key from the $jwkUri above -$decoded = JWT::decode($jwt, $keySet); -``` - -Miscellaneous -------------- - -#### Exception Handling - -When a call to `JWT::decode` is invalid, it will throw one of the following exceptions: - -```php -use Firebase\JWT\JWT; -use Firebase\JWT\SignatureInvalidException; -use Firebase\JWT\BeforeValidException; -use Firebase\JWT\ExpiredException; -use DomainException; -use InvalidArgumentException; -use UnexpectedValueException; - -try { - $decoded = JWT::decode($jwt, $keys); -} catch (InvalidArgumentException $e) { - // provided key/key-array is empty or malformed. -} catch (DomainException $e) { - // provided algorithm is unsupported OR - // provided key is invalid OR - // unknown error thrown in openSSL or libsodium OR - // libsodium is required but not available. -} catch (SignatureInvalidException $e) { - // provided JWT signature verification failed. -} catch (BeforeValidException $e) { - // provided JWT is trying to be used before "nbf" claim OR - // provided JWT is trying to be used before "iat" claim. -} catch (ExpiredException $e) { - // provided JWT is trying to be used after "exp" claim. -} catch (UnexpectedValueException $e) { - // provided JWT is malformed OR - // provided JWT is missing an algorithm / using an unsupported algorithm OR - // provided JWT algorithm does not match provided key OR - // provided key ID in key/key-array is empty or invalid. -} -``` - -All exceptions in the `Firebase\JWT` namespace extend `UnexpectedValueException`, and can be simplified -like this: - -```php -use Firebase\JWT\JWT; -use UnexpectedValueException; -try { - $decoded = JWT::decode($jwt, $keys); -} catch (LogicException $e) { - // errors having to do with environmental setup or malformed JWT Keys -} catch (UnexpectedValueException $e) { - // errors having to do with JWT signature and claims -} -``` - -#### Casting to array - -The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays -instead, you can do the following: - -```php -// return type is stdClass -$decoded = JWT::decode($jwt, $keys); - -// cast to array -$decoded = json_decode(json_encode($decoded), true); -``` - -Tests ------ -Run the tests using phpunit: - -```bash -$ composer update -$ vendor/bin/phpunit -c phpunit.xml.dist -PHPUnit 3.7.10 by Sebastian Bergmann. -..... -Time: 0 seconds, Memory: 2.50Mb -OK (5 tests, 5 assertions) -``` - -New Lines in private keys ------ - -If your private key contains `\n` characters, be sure to wrap it in double quotes `""` -and not single quotes `''` in order to properly interpret the escaped characters. - -License -------- -[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause). diff --git a/vendor/firebase/php-jwt/composer.json b/vendor/firebase/php-jwt/composer.json deleted file mode 100755 index 4b98863..0000000 --- a/vendor/firebase/php-jwt/composer.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "firebase/php-jwt", - "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", - "homepage": "https://github.com/firebase/php-jwt", - "keywords": [ - "php", - "jwt" - ], - "authors": [ - { - "name": "Neuman Vong", - "email": "neuman+pear@twilio.com", - "role": "Developer" - }, - { - "name": "Anant Narayanan", - "email": "anant@php.net", - "role": "Developer" - } - ], - "license": "BSD-3-Clause", - "require": { - "php": "^8.0" - }, - "suggest": { - "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present", - "ext-sodium": "Support EdDSA (Ed25519) signatures" - }, - "autoload": { - "psr-4": { - "Firebase\\JWT\\": "src" - } - }, - "require-dev": { - "guzzlehttp/guzzle": "^7.4", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "psr/cache": "^2.0||^3.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "phpfastcache/phpfastcache": "^9.2" - } -} diff --git a/vendor/firebase/php-jwt/src/BeforeValidException.php b/vendor/firebase/php-jwt/src/BeforeValidException.php deleted file mode 100755 index 595164b..0000000 --- a/vendor/firebase/php-jwt/src/BeforeValidException.php +++ /dev/null @@ -1,18 +0,0 @@ -payload = $payload; - } - - public function getPayload(): object - { - return $this->payload; - } -} diff --git a/vendor/firebase/php-jwt/src/CachedKeySet.php b/vendor/firebase/php-jwt/src/CachedKeySet.php deleted file mode 100755 index 37c3f94..0000000 --- a/vendor/firebase/php-jwt/src/CachedKeySet.php +++ /dev/null @@ -1,275 +0,0 @@ - - */ -class CachedKeySet implements ArrayAccess -{ - /** - * @var string - */ - private $jwksUri; - /** - * @var ClientInterface - */ - private $httpClient; - /** - * @var RequestFactoryInterface - */ - private $httpFactory; - /** - * @var CacheItemPoolInterface - */ - private $cache; - /** - * @var ?int - */ - private $expiresAfter; - /** - * @var ?CacheItemInterface - */ - private $cacheItem; - /** - * @var array> - */ - private $keySet; - /** - * @var string - */ - private $cacheKey; - /** - * @var string - */ - private $cacheKeyPrefix = 'jwks'; - /** - * @var int - */ - private $maxKeyLength = 64; - /** - * @var bool - */ - private $rateLimit; - /** - * @var string - */ - private $rateLimitCacheKey; - /** - * @var int - */ - private $maxCallsPerMinute = 10; - /** - * @var string|null - */ - private $defaultAlg; - - public function __construct( - string $jwksUri, - ClientInterface $httpClient, - RequestFactoryInterface $httpFactory, - CacheItemPoolInterface $cache, - ?int $expiresAfter = null, - bool $rateLimit = false, - ?string $defaultAlg = null - ) { - $this->jwksUri = $jwksUri; - $this->httpClient = $httpClient; - $this->httpFactory = $httpFactory; - $this->cache = $cache; - $this->expiresAfter = $expiresAfter; - $this->rateLimit = $rateLimit; - $this->defaultAlg = $defaultAlg; - $this->setCacheKeys(); - } - - /** - * @param string $keyId - * @return Key - */ - public function offsetGet($keyId): Key - { - if (!$this->keyIdExists($keyId)) { - throw new OutOfBoundsException('Key ID not found'); - } - return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg); - } - - /** - * @param string $keyId - * @return bool - */ - public function offsetExists($keyId): bool - { - return $this->keyIdExists($keyId); - } - - /** - * @param string $offset - * @param Key $value - */ - public function offsetSet($offset, $value): void - { - throw new LogicException('Method not implemented'); - } - - /** - * @param string $offset - */ - public function offsetUnset($offset): void - { - throw new LogicException('Method not implemented'); - } - - /** - * @return array - */ - private function formatJwksForCache(string $jwks): array - { - $jwks = json_decode($jwks, true); - - if (!isset($jwks['keys'])) { - throw new UnexpectedValueException('"keys" member must exist in the JWK Set'); - } - - if (empty($jwks['keys'])) { - throw new InvalidArgumentException('JWK Set did not contain any keys'); - } - - $keys = []; - foreach ($jwks['keys'] as $k => $v) { - $kid = isset($v['kid']) ? $v['kid'] : $k; - $keys[(string) $kid] = $v; - } - - return $keys; - } - - private function keyIdExists(string $keyId): bool - { - if (null === $this->keySet) { - $item = $this->getCacheItem(); - // Try to load keys from cache - if ($item->isHit()) { - // item found! retrieve it - $this->keySet = $item->get(); - // If the cached item is a string, the JWKS response was cached (previous behavior). - // Parse this into expected format array instead. - if (\is_string($this->keySet)) { - $this->keySet = $this->formatJwksForCache($this->keySet); - } - } - } - - if (!isset($this->keySet[$keyId])) { - if ($this->rateLimitExceeded()) { - return false; - } - $request = $this->httpFactory->createRequest('GET', $this->jwksUri); - $jwksResponse = $this->httpClient->sendRequest($request); - if ($jwksResponse->getStatusCode() !== 200) { - throw new UnexpectedValueException( - \sprintf( - 'HTTP Error: %d %s for URI "%s"', - $jwksResponse->getStatusCode(), - $jwksResponse->getReasonPhrase(), - $this->jwksUri, - ), - $jwksResponse->getStatusCode() - ); - } - $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody()); - - if (!isset($this->keySet[$keyId])) { - return false; - } - - $item = $this->getCacheItem(); - $item->set($this->keySet); - if ($this->expiresAfter) { - $item->expiresAfter($this->expiresAfter); - } - $this->cache->save($item); - } - - return true; - } - - private function rateLimitExceeded(): bool - { - if (!$this->rateLimit) { - return false; - } - - $cacheItem = $this->cache->getItem($this->rateLimitCacheKey); - - $cacheItemData = []; - if ($cacheItem->isHit() && \is_array($data = $cacheItem->get())) { - $cacheItemData = $data; - } - - $callsPerMinute = $cacheItemData['callsPerMinute'] ?? 0; - $expiry = $cacheItemData['expiry'] ?? new \DateTime('+60 seconds', new \DateTimeZone('UTC')); - - if (++$callsPerMinute > $this->maxCallsPerMinute) { - return true; - } - - $cacheItem->set(['expiry' => $expiry, 'callsPerMinute' => $callsPerMinute]); - $cacheItem->expiresAt($expiry); - $this->cache->save($cacheItem); - return false; - } - - private function getCacheItem(): CacheItemInterface - { - if (\is_null($this->cacheItem)) { - $this->cacheItem = $this->cache->getItem($this->cacheKey); - } - - return $this->cacheItem; - } - - private function setCacheKeys(): void - { - if (empty($this->jwksUri)) { - throw new RuntimeException('JWKS URI is empty'); - } - - // ensure we do not have illegal characters - $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $this->jwksUri); - - // add prefix - $key = $this->cacheKeyPrefix . $key; - - // Hash keys if they exceed $maxKeyLength of 64 - if (\strlen($key) > $this->maxKeyLength) { - $key = substr(hash('sha256', $key), 0, $this->maxKeyLength); - } - - $this->cacheKey = $key; - - if ($this->rateLimit) { - // add prefix - $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key; - - // Hash keys if they exceed $maxKeyLength of 64 - if (\strlen($rateLimitKey) > $this->maxKeyLength) { - $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength); - } - - $this->rateLimitCacheKey = $rateLimitKey; - } - } -} diff --git a/vendor/firebase/php-jwt/src/ExpiredException.php b/vendor/firebase/php-jwt/src/ExpiredException.php deleted file mode 100755 index 25f4451..0000000 --- a/vendor/firebase/php-jwt/src/ExpiredException.php +++ /dev/null @@ -1,30 +0,0 @@ -payload = $payload; - } - - public function getPayload(): object - { - return $this->payload; - } - - public function setTimestamp(int $timestamp): void - { - $this->timestamp = $timestamp; - } - - public function getTimestamp(): ?int - { - return $this->timestamp; - } -} diff --git a/vendor/firebase/php-jwt/src/JWK.php b/vendor/firebase/php-jwt/src/JWK.php deleted file mode 100755 index e083c22..0000000 --- a/vendor/firebase/php-jwt/src/JWK.php +++ /dev/null @@ -1,363 +0,0 @@ - - * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD - * @link https://github.com/firebase/php-jwt - */ -class JWK -{ - private const OID = '1.2.840.10045.2.1'; - private const ASN1_OBJECT_IDENTIFIER = 0x06; - private const ASN1_SEQUENCE = 0x10; // also defined in JWT - private const ASN1_BIT_STRING = 0x03; - private const EC_CURVES = [ - 'P-256' => '1.2.840.10045.3.1.7', // Len: 64 - 'secp256k1' => '1.3.132.0.10', // Len: 64 - 'P-384' => '1.3.132.0.34', // Len: 96 - // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported) - ]; - - // For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype. - // This library supports the following subtypes: - private const OKP_SUBTYPES = [ - 'Ed25519' => true, // RFC 8037 - ]; - - /** - * Parse a set of JWK keys - * - * @param array $jwks The JSON Web Key Set as an associative array - * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the - * JSON Web Key Set - * - * @return array An associative array of key IDs (kid) to Key objects - * - * @throws InvalidArgumentException Provided JWK Set is empty - * @throws UnexpectedValueException Provided JWK Set was invalid - * @throws DomainException OpenSSL failure - * - * @uses parseKey - */ - public static function parseKeySet(#[\SensitiveParameter] array $jwks, ?string $defaultAlg = null): array - { - $keys = []; - - if (!isset($jwks['keys'])) { - throw new UnexpectedValueException('"keys" member must exist in the JWK Set'); - } - - if (empty($jwks['keys'])) { - throw new InvalidArgumentException('JWK Set did not contain any keys'); - } - - foreach ($jwks['keys'] as $k => $v) { - $kid = isset($v['kid']) ? $v['kid'] : $k; - if ($key = self::parseKey($v, $defaultAlg)) { - $keys[(string) $kid] = $key; - } - } - - if (0 === \count($keys)) { - throw new UnexpectedValueException('No supported algorithms found in JWK Set'); - } - - return $keys; - } - - /** - * Parse a JWK key - * - * @param array $jwk An individual JWK - * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the - * JSON Web Key Set - * - * @return Key The key object for the JWK - * - * @throws InvalidArgumentException Provided JWK is empty - * @throws UnexpectedValueException Provided JWK was invalid - * @throws DomainException OpenSSL failure - * - * @uses createPemFromModulusAndExponent - */ - public static function parseKey(#[\SensitiveParameter] array $jwk, ?string $defaultAlg = null): ?Key - { - if (empty($jwk)) { - throw new InvalidArgumentException('JWK must not be empty'); - } - - if (!isset($jwk['kty'])) { - throw new UnexpectedValueException('JWK must contain a "kty" parameter'); - } - - if (!isset($jwk['alg'])) { - if (\is_null($defaultAlg)) { - // The "alg" parameter is optional in a KTY, but an algorithm is required - // for parsing in this library. Use the $defaultAlg parameter when parsing the - // key set in order to prevent this error. - // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4 - throw new UnexpectedValueException('JWK must contain an "alg" parameter'); - } - $jwk['alg'] = $defaultAlg; - } - - switch ($jwk['kty']) { - case 'RSA': - if (!empty($jwk['d'])) { - throw new UnexpectedValueException('RSA private keys are not supported'); - } - if (!isset($jwk['n']) || !isset($jwk['e'])) { - throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"'); - } - - $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']); - $publicKey = \openssl_pkey_get_public($pem); - if (false === $publicKey) { - throw new DomainException( - 'OpenSSL error: ' . \openssl_error_string() - ); - } - return new Key($publicKey, $jwk['alg']); - case 'EC': - if (isset($jwk['d'])) { - // The key is actually a private key - throw new UnexpectedValueException('Key data must be for a public key'); - } - - if (empty($jwk['crv'])) { - throw new UnexpectedValueException('crv not set'); - } - - if (!isset(self::EC_CURVES[$jwk['crv']])) { - throw new DomainException('Unrecognised or unsupported EC curve'); - } - - if (empty($jwk['x']) || empty($jwk['y'])) { - throw new UnexpectedValueException('x and y not set'); - } - - $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']); - return new Key($publicKey, $jwk['alg']); - case 'OKP': - if (isset($jwk['d'])) { - // The key is actually a private key - throw new UnexpectedValueException('Key data must be for a public key'); - } - - if (!isset($jwk['crv'])) { - throw new UnexpectedValueException('crv not set'); - } - - if (empty(self::OKP_SUBTYPES[$jwk['crv']])) { - throw new DomainException('Unrecognised or unsupported OKP key subtype'); - } - - if (empty($jwk['x'])) { - throw new UnexpectedValueException('x not set'); - } - - // This library works internally with EdDSA keys (Ed25519) encoded in standard base64. - $publicKey = JWT::convertBase64urlToBase64($jwk['x']); - return new Key($publicKey, $jwk['alg']); - case 'oct': - if (!isset($jwk['k'])) { - throw new UnexpectedValueException('k not set'); - } - - return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']); - default: - break; - } - - return null; - } - - /** - * Converts the EC JWK values to pem format. - * - * @param string $crv The EC curve (only P-256 & P-384 is supported) - * @param string $x The EC x-coordinate - * @param string $y The EC y-coordinate - * - * @return string - */ - private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y): string - { - $pem = - self::encodeDER( - self::ASN1_SEQUENCE, - self::encodeDER( - self::ASN1_SEQUENCE, - self::encodeDER( - self::ASN1_OBJECT_IDENTIFIER, - self::encodeOID(self::OID) - ) - . self::encodeDER( - self::ASN1_OBJECT_IDENTIFIER, - self::encodeOID(self::EC_CURVES[$crv]) - ) - ) . - self::encodeDER( - self::ASN1_BIT_STRING, - \chr(0x00) . \chr(0x04) - . JWT::urlsafeB64Decode($x) - . JWT::urlsafeB64Decode($y) - ) - ); - - return \sprintf( - "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", - wordwrap(base64_encode($pem), 64, "\n", true) - ); - } - - /** - * Create a public key represented in PEM format from RSA modulus and exponent information - * - * @param string $n The RSA modulus encoded in Base64 - * @param string $e The RSA exponent encoded in Base64 - * - * @return string The RSA public key represented in PEM format - * - * @uses encodeLength - */ - private static function createPemFromModulusAndExponent( - string $n, - string $e - ): string { - $mod = JWT::urlsafeB64Decode($n); - $exp = JWT::urlsafeB64Decode($e); - // Correct encoding for ASN1, as ints are represented as unsigned in jwk - // but signed in ASN1. Prepending null byte makes it unsigned. - if (\strlen($mod) > 0 && \ord($mod[0]) >= 128) { - $mod = \chr(0) . $mod; - } - if (\strlen($exp) > 0 && \ord($exp[0]) >= 128) { - $exp = \chr(0) . $exp; - } - - $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod); - $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp); - - $rsaPublicKey = \pack( - 'Ca*a*a*', - 48, - self::encodeLength(\strlen($modulus) + \strlen($publicExponent)), - $modulus, - $publicExponent - ); - - // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. - $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA - $rsaPublicKey = \chr(0) . $rsaPublicKey; - $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey; - - $rsaPublicKey = \pack( - 'Ca*a*', - 48, - self::encodeLength(\strlen($rsaOID . $rsaPublicKey)), - $rsaOID . $rsaPublicKey - ); - - return "-----BEGIN PUBLIC KEY-----\r\n" . - \chunk_split(\base64_encode($rsaPublicKey), 64) . - '-----END PUBLIC KEY-----'; - } - - /** - * DER-encode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. - * - * @param int $length - * @return string - */ - private static function encodeLength(int $length): string - { - if ($length <= 0x7F) { - return \chr($length); - } - - $temp = \ltrim(\pack('N', $length), \chr(0)); - - return \pack('Ca*', 0x80 | \strlen($temp), $temp); - } - - /** - * Encodes a value into a DER object. - * Also defined in Firebase\JWT\JWT - * - * @param int $type DER tag - * @param string $value the value to encode - * @return string the encoded object - */ - private static function encodeDER(int $type, string $value): string - { - $tag_header = 0; - if ($type === self::ASN1_SEQUENCE) { - $tag_header |= 0x20; - } - - // Type - $der = \chr($tag_header | $type); - - // Length - $der .= \chr(\strlen($value)); - - return $der . $value; - } - - /** - * Encodes a string into a DER-encoded OID. - * - * @param string $oid the OID string - * @return string the binary DER-encoded OID - */ - private static function encodeOID(string $oid): string - { - $octets = explode('.', $oid); - - // Get the first octet - $first = (int) array_shift($octets); - $second = (int) array_shift($octets); - $oid = \chr($first * 40 + $second); - - // Iterate over subsequent octets - foreach ($octets as $octet) { - if ($octet == 0) { - $oid .= \chr(0x00); - continue; - } - $bin = ''; - - while ($octet) { - $bin .= \chr(0x80 | ($octet & 0x7f)); - $octet >>= 7; - } - $bin[0] = $bin[0] & \chr(0x7f); - - // Convert to big endian if necessary - if (pack('V', 65534) == pack('L', 65534)) { - $oid .= strrev($bin); - } else { - $oid .= $bin; - } - } - - return $oid; - } -} diff --git a/vendor/firebase/php-jwt/src/JWT.php b/vendor/firebase/php-jwt/src/JWT.php deleted file mode 100755 index 0d2e47c..0000000 --- a/vendor/firebase/php-jwt/src/JWT.php +++ /dev/null @@ -1,745 +0,0 @@ - - * @author Anant Narayanan - * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD - * @link https://github.com/firebase/php-jwt - */ -class JWT -{ - private const ASN1_INTEGER = 0x02; - private const ASN1_SEQUENCE = 0x10; - private const ASN1_BIT_STRING = 0x03; - - private const RSA_KEY_MIN_LENGTH = 2048; - - /** - * When checking nbf, iat or expiration times, - * we want to provide some extra leeway time to - * account for clock skew. - * - * @var int - */ - public static $leeway = 0; - - /** - * Allow the current timestamp to be specified. - * Useful for fixing a value within unit testing. - * Will default to PHP time() value if null. - * - * @var ?int - */ - public static $timestamp = null; - - /** - * @var array - */ - public static $supported_algs = [ - 'ES384' => ['openssl', 'SHA384'], - 'ES256' => ['openssl', 'SHA256'], - 'ES256K' => ['openssl', 'SHA256'], - 'HS256' => ['hash_hmac', 'SHA256'], - 'HS384' => ['hash_hmac', 'SHA384'], - 'HS512' => ['hash_hmac', 'SHA512'], - 'RS256' => ['openssl', 'SHA256'], - 'RS384' => ['openssl', 'SHA384'], - 'RS512' => ['openssl', 'SHA512'], - 'EdDSA' => ['sodium_crypto', 'EdDSA'], - ]; - - /** - * Decodes a JWT string into a PHP object. - * - * @param string $jwt The JWT - * @param Key|ArrayAccess|array $keyOrKeyArray The Key or associative array of key IDs - * (kid) to Key objects. - * If the algorithm used is asymmetric, this is - * the public key. - * Each Key object contains an algorithm and - * matching key. - * Supported algorithms are 'ES384','ES256', - * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384' - * and 'RS512'. - * @param stdClass $headers Optional. Populates stdClass with headers. - * - * @return stdClass The JWT's payload as a PHP object - * - * @throws InvalidArgumentException Provided key/key-array was empty or malformed - * @throws DomainException Provided JWT is malformed - * @throws UnexpectedValueException Provided JWT was invalid - * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed - * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' - * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat' - * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim - * - * @uses jsonDecode - * @uses urlsafeB64Decode - */ - public static function decode( - string $jwt, - #[\SensitiveParameter] $keyOrKeyArray, - ?stdClass &$headers = null - ): stdClass { - // Validate JWT - $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp; - - if (empty($keyOrKeyArray)) { - throw new InvalidArgumentException('Key may not be empty'); - } - $tks = \explode('.', $jwt); - if (\count($tks) !== 3) { - throw new UnexpectedValueException('Wrong number of segments'); - } - list($headb64, $bodyb64, $cryptob64) = $tks; - $headerRaw = static::urlsafeB64Decode($headb64); - if (null === ($header = static::jsonDecode($headerRaw))) { - throw new UnexpectedValueException('Invalid header encoding'); - } - if ($headers !== null) { - $headers = $header; - } - $payloadRaw = static::urlsafeB64Decode($bodyb64); - if (null === ($payload = static::jsonDecode($payloadRaw))) { - throw new UnexpectedValueException('Invalid claims encoding'); - } - if (\is_array($payload)) { - // prevent PHP Fatal Error in edge-cases when payload is empty array - $payload = (object) $payload; - } - if (!$payload instanceof stdClass) { - throw new UnexpectedValueException('Payload must be a JSON object'); - } - if (isset($payload->iat) && !\is_numeric($payload->iat)) { - throw new UnexpectedValueException('Payload iat must be a number'); - } - if (isset($payload->nbf) && !\is_numeric($payload->nbf)) { - throw new UnexpectedValueException('Payload nbf must be a number'); - } - if (isset($payload->exp) && !\is_numeric($payload->exp)) { - throw new UnexpectedValueException('Payload exp must be a number'); - } - - $sig = static::urlsafeB64Decode($cryptob64); - if (empty($header->alg)) { - throw new UnexpectedValueException('Empty algorithm'); - } - if (empty(static::$supported_algs[$header->alg])) { - throw new UnexpectedValueException('Algorithm not supported'); - } - - $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null); - - // Check the algorithm - if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) { - // See issue #351 - throw new UnexpectedValueException('Incorrect key for this algorithm'); - } - if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) { - // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures - $sig = self::signatureToDER($sig); - } - if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) { - throw new SignatureInvalidException('Signature verification failed'); - } - - // Check the nbf if it is defined. This is the time that the - // token can actually be used. If it's not yet that time, abort. - if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) { - $ex = new BeforeValidException( - 'Cannot handle token with nbf prior to ' . \date(DateTime::ATOM, (int) floor($payload->nbf)) - ); - $ex->setPayload($payload); - throw $ex; - } - - // Check that this token has been created before 'now'. This prevents - // using tokens that have been created for later use (and haven't - // correctly used the nbf claim). - if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) { - $ex = new BeforeValidException( - 'Cannot handle token with iat prior to ' . \date(DateTime::ATOM, (int) floor($payload->iat)) - ); - $ex->setPayload($payload); - throw $ex; - } - - // Check if this token has expired. - if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) { - $ex = new ExpiredException('Expired token'); - $ex->setPayload($payload); - $ex->setTimestamp($timestamp); - throw $ex; - } - - return $payload; - } - - /** - * Converts and signs a PHP array into a JWT string. - * - * @param array $payload PHP array - * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256', - * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' - * @param string $keyId - * @param array $head An array with header elements to attach - * - * @return string A signed JWT - * - * @uses jsonEncode - * @uses urlsafeB64Encode - */ - public static function encode( - array $payload, - #[\SensitiveParameter] $key, - string $alg, - ?string $keyId = null, - ?array $head = null - ): string { - $header = ['typ' => 'JWT']; - if (isset($head)) { - $header = \array_merge($header, $head); - } - $header['alg'] = $alg; - if ($keyId !== null) { - $header['kid'] = $keyId; - } - $segments = []; - $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header)); - $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload)); - $signing_input = \implode('.', $segments); - - $signature = static::sign($signing_input, $key, $alg); - $segments[] = static::urlsafeB64Encode($signature); - - return \implode('.', $segments); - } - - /** - * Sign a string with a given key and algorithm. - * - * @param string $msg The message to sign - * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256', - * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' - * - * @return string An encrypted message - * - * @throws DomainException Unsupported algorithm or bad key was specified - */ - public static function sign( - string $msg, - #[\SensitiveParameter] $key, - string $alg - ): string { - if (empty(static::$supported_algs[$alg])) { - throw new DomainException('Algorithm not supported'); - } - list($function, $algorithm) = static::$supported_algs[$alg]; - switch ($function) { - case 'hash_hmac': - if (!\is_string($key)) { - throw new InvalidArgumentException('key must be a string when using hmac'); - } - self::validateHmacKeyLength($key, $algorithm); - return \hash_hmac($algorithm, $msg, $key, true); - case 'openssl': - $signature = ''; - if (!$key = openssl_pkey_get_private($key)) { - throw new DomainException('OpenSSL unable to validate key'); - } - if (str_starts_with($alg, 'RS')) { - self::validateRsaKeyLength($key); - } elseif (str_starts_with($alg, 'ES')) { - self::validateEcKeyLength($key, $alg); - } - $success = \openssl_sign($msg, $signature, $key, $algorithm); - if (!$success) { - throw new DomainException('OpenSSL unable to sign data'); - } - if ($alg === 'ES256' || $alg === 'ES256K') { - $signature = self::signatureFromDER($signature, 256); - } elseif ($alg === 'ES384') { - $signature = self::signatureFromDER($signature, 384); - } - return $signature; - case 'sodium_crypto': - try { - return sodium_crypto_sign_detached($msg, self::validateEdDSAKey($key)); - } catch (Exception $e) { - throw new DomainException($e->getMessage(), 0, $e); - } - } - - throw new DomainException('Algorithm not supported'); - } - - /** - * Verify a signature with the message, key and method. Not all methods - * are symmetric, so we must have a separate verify and sign method. - * - * @param string $msg The original message (header and body) - * @param string $signature The original signature - * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey - * @param string $alg The algorithm - * - * @return bool - * - * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure - */ - private static function verify( - string $msg, - string $signature, - #[\SensitiveParameter] $keyMaterial, - string $alg - ): bool { - if (empty(static::$supported_algs[$alg])) { - throw new DomainException('Algorithm not supported'); - } - - list($function, $algorithm) = static::$supported_algs[$alg]; - switch ($function) { - case 'openssl': - if (!$key = openssl_pkey_get_public($keyMaterial)) { - throw new DomainException('OpenSSL unable to validate key'); - } - if (str_starts_with($alg, 'RS')) { - self::validateRsaKeyLength($key); - } elseif (str_starts_with($alg, 'ES')) { - self::validateEcKeyLength($key, $alg); - } - $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); - if ($success === 1) { - return true; - } - if ($success === 0) { - return false; - } - // returns 1 on success, 0 on failure, -1 on error. - throw new DomainException( - 'OpenSSL error: ' . \openssl_error_string() - ); - case 'sodium_crypto': - try { - $key = self::validateEdDSAKey($keyMaterial); - if (\strlen($signature) === 0) { - throw new DomainException('Signature cannot be empty string'); - } - return sodium_crypto_sign_verify_detached($signature, $msg, $key); - } catch (Exception $e) { - throw new DomainException($e->getMessage(), 0, $e); - } - case 'hash_hmac': - default: - if (!\is_string($keyMaterial)) { - throw new InvalidArgumentException('key must be a string when using hmac'); - } - self::validateHmacKeyLength($keyMaterial, $algorithm); - $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true); - return self::constantTimeEquals($hash, $signature); - } - } - - /** - * Decode a JSON string into a PHP object. - * - * @param string $input JSON string - * - * @return mixed The decoded JSON string - * - * @throws DomainException Provided string was invalid JSON - */ - public static function jsonDecode(string $input) - { - $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING); - - if ($errno = \json_last_error()) { - self::handleJsonError($errno); - } elseif ($obj === null && $input !== 'null') { - throw new DomainException('Null result with non-null input'); - } - return $obj; - } - - /** - * Encode a PHP array into a JSON string. - * - * @param array $input A PHP array - * - * @return string JSON representation of the PHP array - * - * @throws DomainException Provided object could not be encoded to valid JSON - */ - public static function jsonEncode(array $input): string - { - $json = \json_encode($input, \JSON_UNESCAPED_SLASHES); - if ($errno = \json_last_error()) { - self::handleJsonError($errno); - } elseif ($json === 'null') { - throw new DomainException('Null result with non-null input'); - } - if ($json === false) { - throw new DomainException('Provided object could not be encoded to valid JSON'); - } - return $json; - } - - /** - * Decode a string with URL-safe Base64. - * - * @param string $input A Base64 encoded string - * - * @return string A decoded string - * - * @throws InvalidArgumentException invalid base64 characters - */ - public static function urlsafeB64Decode(string $input): string - { - return \base64_decode(self::convertBase64UrlToBase64($input)); - } - - /** - * Convert a string in the base64url (URL-safe Base64) encoding to standard base64. - * - * @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding) - * - * @return string A Base64 encoded string with standard characters (+/) and padding (=), when - * needed. - * - * @see https://www.rfc-editor.org/rfc/rfc4648 - */ - public static function convertBase64UrlToBase64(string $input): string - { - $remainder = \strlen($input) % 4; - if ($remainder) { - $padlen = 4 - $remainder; - $input .= \str_repeat('=', $padlen); - } - return \strtr($input, '-_', '+/'); - } - - /** - * Encode a string with URL-safe Base64. - * - * @param string $input The string you want encoded - * - * @return string The base64 encode of what you passed in - */ - public static function urlsafeB64Encode(string $input): string - { - return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_')); - } - - /** - * Determine if an algorithm has been provided for each Key - * - * @param Key|ArrayAccess|array $keyOrKeyArray - * @param string|null $kid - * - * @throws UnexpectedValueException - * - * @return Key - */ - private static function getKey( - #[\SensitiveParameter] $keyOrKeyArray, - ?string $kid - ): Key { - if ($keyOrKeyArray instanceof Key) { - return $keyOrKeyArray; - } - - if (empty($kid) && $kid !== '0') { - throw new UnexpectedValueException('"kid" empty, unable to lookup correct key'); - } - - if ($keyOrKeyArray instanceof CachedKeySet) { - // Skip "isset" check, as this will automatically refresh if not set - return $keyOrKeyArray[$kid]; - } - - if (!isset($keyOrKeyArray[$kid])) { - throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key'); - } - - return $keyOrKeyArray[$kid]; - } - - /** - * @param string $left The string of known length to compare against - * @param string $right The user-supplied string - * @return bool - */ - public static function constantTimeEquals(string $left, string $right): bool - { - if (\function_exists('hash_equals')) { - return \hash_equals($left, $right); - } - $len = \min(self::safeStrlen($left), self::safeStrlen($right)); - - $status = 0; - for ($i = 0; $i < $len; $i++) { - $status |= (\ord($left[$i]) ^ \ord($right[$i])); - } - $status |= (self::safeStrlen($left) ^ self::safeStrlen($right)); - - return ($status === 0); - } - - /** - * Helper method to create a JSON error. - * - * @param int $errno An error number from json_last_error() - * - * @throws DomainException - * - * @return void - */ - private static function handleJsonError(int $errno): void - { - $messages = [ - JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', - JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', - JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', - JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', - JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3 - ]; - throw new DomainException( - isset($messages[$errno]) - ? $messages[$errno] - : 'Unknown JSON error: ' . $errno - ); - } - - /** - * Get the number of bytes in cryptographic strings. - * - * @param string $str - * - * @return int - */ - private static function safeStrlen(string $str): int - { - if (\function_exists('mb_strlen')) { - return \mb_strlen($str, '8bit'); - } - return \strlen($str); - } - - /** - * Convert an ECDSA signature to an ASN.1 DER sequence - * - * @param string $sig The ECDSA signature to convert - * @return string The encoded DER object - */ - private static function signatureToDER(string $sig): string - { - // Separate the signature into r-value and s-value - $length = max(1, (int) (\strlen($sig) / 2)); - list($r, $s) = \str_split($sig, $length); - - // Trim leading zeros - $r = \ltrim($r, "\x00"); - $s = \ltrim($s, "\x00"); - - // Convert r-value and s-value from unsigned big-endian integers to - // signed two's complement - if (\ord($r[0]) > 0x7f) { - $r = "\x00" . $r; - } - if (\ord($s[0]) > 0x7f) { - $s = "\x00" . $s; - } - - return self::encodeDER( - self::ASN1_SEQUENCE, - self::encodeDER(self::ASN1_INTEGER, $r) . - self::encodeDER(self::ASN1_INTEGER, $s) - ); - } - - /** - * Encodes a value into a DER object. - * - * @param int $type DER tag - * @param string $value the value to encode - * - * @return string the encoded object - */ - private static function encodeDER(int $type, string $value): string - { - $tag_header = 0; - if ($type === self::ASN1_SEQUENCE) { - $tag_header |= 0x20; - } - - // Type - $der = \chr($tag_header | $type); - - // Length - $der .= \chr(\strlen($value)); - - return $der . $value; - } - - /** - * Encodes signature from a DER object. - * - * @param string $der binary signature in DER format - * @param int $keySize the number of bits in the key - * - * @return string the signature - */ - private static function signatureFromDER(string $der, int $keySize): string - { - // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE - list($offset, $_) = self::readDER($der); - list($offset, $r) = self::readDER($der, $offset); - list($offset, $s) = self::readDER($der, $offset); - - // Convert r-value and s-value from signed two's compliment to unsigned - // big-endian integers - $r = \ltrim($r, "\x00"); - $s = \ltrim($s, "\x00"); - - // Pad out r and s so that they are $keySize bits long - $r = \str_pad($r, $keySize / 8, "\x00", STR_PAD_LEFT); - $s = \str_pad($s, $keySize / 8, "\x00", STR_PAD_LEFT); - - return $r . $s; - } - - /** - * Reads binary DER-encoded data and decodes into a single object - * - * @param string $der the binary data in DER format - * @param int $offset the offset of the data stream containing the object - * to decode - * - * @return array{int, string|null} the new offset and the decoded object - */ - private static function readDER(string $der, int $offset = 0): array - { - $pos = $offset; - $size = \strlen($der); - $constructed = (\ord($der[$pos]) >> 5) & 0x01; - $type = \ord($der[$pos++]) & 0x1f; - - // Length - $len = \ord($der[$pos++]); - if ($len & 0x80) { - $n = $len & 0x1f; - $len = 0; - while ($n-- && $pos < $size) { - $len = ($len << 8) | \ord($der[$pos++]); - } - } - - // Value - if ($type === self::ASN1_BIT_STRING) { - $pos++; // Skip the first contents octet (padding indicator) - $data = \substr($der, $pos, $len - 1); - $pos += $len - 1; - } elseif (!$constructed) { - $data = \substr($der, $pos, $len); - $pos += $len; - } else { - $data = null; - } - - return [$pos, $data]; - } - - /** - * Validate HMAC key length - * - * @param string $key HMAC key material - * @param string $algorithm The algorithm - * - * @throws DomainException Provided key is too short - */ - private static function validateHmacKeyLength(string $key, string $algorithm): void - { - $keyLength = \strlen($key) * 8; - $minKeyLength = (int) \str_replace('SHA', '', $algorithm); - if ($keyLength < $minKeyLength) { - throw new DomainException('Provided key is too short'); - } - } - - /** - * Validate RSA key length - * - * @param OpenSSLAsymmetricKey $key RSA key material - * @throws DomainException Provided key is too short - */ - private static function validateRsaKeyLength(#[\SensitiveParameter] OpenSSLAsymmetricKey $key): void - { - if (!$keyDetails = openssl_pkey_get_details($key)) { - throw new DomainException('Unable to validate key'); - } - if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) { - throw new DomainException('Provided key is too short'); - } - } - - /** - * Validate RSA key length - * - * @param OpenSSLAsymmetricKey $key RSA key material - * @param string $algorithm The algorithm - * @throws DomainException Provided key is too short - */ - private static function validateEcKeyLength( - #[\SensitiveParameter] OpenSSLAsymmetricKey $key, - string $algorithm - ): void { - if (!$keyDetails = openssl_pkey_get_details($key)) { - throw new DomainException('Unable to validate key'); - } - $minKeyLength = (int) \str_replace('ES', '', $algorithm); - if ($keyDetails['bits'] < $minKeyLength) { - throw new DomainException('Provided key is too short'); - } - } - - /** - * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial - * @return non-empty-string - */ - private static function validateEdDSAKey(#[\SensitiveParameter] $keyMaterial): string - { - if (!\function_exists('sodium_crypto_sign_verify_detached')) { - throw new DomainException('libsodium is not available'); - } - if (!\is_string($keyMaterial)) { - throw new InvalidArgumentException('key must be a string when using EdDSA'); - } - // The last non-empty line is used as the key. - $lines = array_filter(explode("\n", $keyMaterial)); - $key = self::urlsafeB64Decode((string) end($lines)); - if (\strlen($key) === 0) { - throw new DomainException('Key cannot be empty string'); - } - return $key; - } -} diff --git a/vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php b/vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php deleted file mode 100755 index 7933ed6..0000000 --- a/vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -algorithm; - } - - /** - * @return string|OpenSSLAsymmetricKey|OpenSSLCertificate - */ - public function getKeyMaterial() - { - return $this->keyMaterial; - } -} diff --git a/vendor/firebase/php-jwt/src/SignatureInvalidException.php b/vendor/firebase/php-jwt/src/SignatureInvalidException.php deleted file mode 100755 index d35dee9..0000000 --- a/vendor/firebase/php-jwt/src/SignatureInvalidException.php +++ /dev/null @@ -1,7 +0,0 @@ -