feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.
Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
- Provider key: s3compatible
- Reads user-configured endpoint URL from settings
- Uses path-style URL access (required by most S3-compatible services)
- Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
- Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
170
vendor/Gcp/firebase/php-jwt/CHANGELOG.md
vendored
Normal file
170
vendor/Gcp/firebase/php-jwt/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
# Changelog
|
||||
|
||||
## [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.
|
||||
30
vendor/Gcp/firebase/php-jwt/LICENSE
vendored
Normal file
30
vendor/Gcp/firebase/php-jwt/LICENSE
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
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.
|
||||
16
vendor/Gcp/firebase/php-jwt/src/BeforeValidException.php
vendored
Normal file
16
vendor/Gcp/firebase/php-jwt/src/BeforeValidException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
class BeforeValidException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
|
||||
{
|
||||
private object $payload;
|
||||
public function setPayload(object $payload) : void
|
||||
{
|
||||
$this->payload = $payload;
|
||||
}
|
||||
public function getPayload() : object
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
}
|
||||
226
vendor/Gcp/firebase/php-jwt/src/CachedKeySet.php
vendored
Normal file
226
vendor/Gcp/firebase/php-jwt/src/CachedKeySet.php
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use OutOfBoundsException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Cache\CacheItemInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Cache\CacheItemPoolInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Client\ClientInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestFactoryInterface;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
/**
|
||||
* @implements ArrayAccess<string, Key>
|
||||
*/
|
||||
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<string, array<mixed>>
|
||||
*/
|
||||
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<mixed>
|
||||
*/
|
||||
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<kid, jwk> 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);
|
||||
if (!$cacheItem->isHit()) {
|
||||
$cacheItem->expiresAfter(1);
|
||||
// # of calls are cached each minute
|
||||
}
|
||||
$callsPerMinute = (int) $cacheItem->get();
|
||||
if (++$callsPerMinute > $this->maxCallsPerMinute) {
|
||||
return \true;
|
||||
}
|
||||
$cacheItem->set($callsPerMinute);
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
vendor/Gcp/firebase/php-jwt/src/ExpiredException.php
vendored
Normal file
16
vendor/Gcp/firebase/php-jwt/src/ExpiredException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
class ExpiredException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
|
||||
{
|
||||
private object $payload;
|
||||
public function setPayload(object $payload) : void
|
||||
{
|
||||
$this->payload = $payload;
|
||||
}
|
||||
public function getPayload() : object
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
}
|
||||
267
vendor/Gcp/firebase/php-jwt/src/JWK.php
vendored
Normal file
267
vendor/Gcp/firebase/php-jwt/src/JWK.php
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
use DomainException;
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
/**
|
||||
* JSON Web Key implementation, based on this spec:
|
||||
* https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Authentication
|
||||
* @package Authentication_JWT
|
||||
* @author Bui Sy Nguyen <nguyenbs@gmail.com>
|
||||
* @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 = 0x6;
|
||||
private const ASN1_SEQUENCE = 0x10;
|
||||
// also defined in JWT
|
||||
private const ASN1_BIT_STRING = 0x3;
|
||||
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',
|
||||
];
|
||||
// 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];
|
||||
/**
|
||||
* Parse a set of JWK keys
|
||||
*
|
||||
* @param array<mixed> $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<string, Key> 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(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<mixed> $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(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']);
|
||||
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(0x0) . \chr(0x4) . 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);
|
||||
$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(0x0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
572
vendor/Gcp/firebase/php-jwt/src/JWT.php
vendored
Normal file
572
vendor/Gcp/firebase/php-jwt/src/JWT.php
vendored
Normal file
@@ -0,0 +1,572 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
use ArrayAccess;
|
||||
use DateTime;
|
||||
use DomainException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use OpenSSLAsymmetricKey;
|
||||
use OpenSSLCertificate;
|
||||
use stdClass;
|
||||
use UnexpectedValueException;
|
||||
/**
|
||||
* JSON Web Token implementation, based on this spec:
|
||||
* https://tools.ietf.org/html/rfc7519
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Authentication
|
||||
* @package Authentication_JWT
|
||||
* @author Neuman Vong <neuman@twilio.com>
|
||||
* @author Anant Narayanan <anant@php.net>
|
||||
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
|
||||
* @link https://github.com/firebase/php-jwt
|
||||
*/
|
||||
class JWT
|
||||
{
|
||||
private const ASN1_INTEGER = 0x2;
|
||||
private const ASN1_SEQUENCE = 0x10;
|
||||
private const ASN1_BIT_STRING = 0x3;
|
||||
/**
|
||||
* 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<string, string[]>
|
||||
*/
|
||||
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<string,Key>|array<string,Key> $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, $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');
|
||||
}
|
||||
$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::ISO8601, (int) $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::ISO8601, (int) $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);
|
||||
throw $ex;
|
||||
}
|
||||
return $payload;
|
||||
}
|
||||
/**
|
||||
* Converts and signs a PHP array into a JWT string.
|
||||
*
|
||||
* @param array<mixed> $payload PHP array
|
||||
* @param string|resource|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<string, string> $head An array with header elements to attach
|
||||
*
|
||||
* @return string A signed JWT
|
||||
*
|
||||
* @uses jsonEncode
|
||||
* @uses urlsafeB64Encode
|
||||
*/
|
||||
public static function encode(array $payload, $key, string $alg, string $keyId = null, array $head = null) : string
|
||||
{
|
||||
$header = ['typ' => 'JWT'];
|
||||
if (isset($head) && \is_array($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|resource|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, $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');
|
||||
}
|
||||
return \hash_hmac($algorithm, $msg, $key, \true);
|
||||
case 'openssl':
|
||||
$signature = '';
|
||||
$success = \openssl_sign($msg, $signature, $key, $algorithm);
|
||||
// @phpstan-ignore-line
|
||||
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':
|
||||
if (!\function_exists('sodium_crypto_sign_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException('key must be a string when using EdDSA');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = \array_filter(\explode("\n", $key));
|
||||
$key = \base64_decode((string) \end($lines));
|
||||
if (\strlen($key) === 0) {
|
||||
throw new DomainException('Key cannot be empty string');
|
||||
}
|
||||
return \sodium_crypto_sign_detached($msg, $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|resource|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, $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':
|
||||
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
|
||||
// @phpstan-ignore-line
|
||||
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':
|
||||
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');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = \array_filter(\explode("\n", $keyMaterial));
|
||||
$key = \base64_decode((string) \end($lines));
|
||||
if (\strlen($key) === 0) {
|
||||
throw new DomainException('Key cannot be empty string');
|
||||
}
|
||||
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');
|
||||
}
|
||||
$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<mixed> $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
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 50400) {
|
||||
$json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
|
||||
} else {
|
||||
// PHP 5.3 only
|
||||
$json = \json_encode($input);
|
||||
}
|
||||
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<string,Key>|array<string,Key> $keyOrKeyArray
|
||||
* @param string|null $kid
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @return Key
|
||||
*/
|
||||
private static function getKey($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'];
|
||||
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 & 0x1;
|
||||
$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];
|
||||
}
|
||||
}
|
||||
20
vendor/Gcp/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php
vendored
Normal file
20
vendor/Gcp/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
interface JWTExceptionWithPayloadInterface
|
||||
{
|
||||
/**
|
||||
* Get the payload that caused this exception.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getPayload() : object;
|
||||
/**
|
||||
* Get the payload that caused this exception.
|
||||
*
|
||||
* @param object $payload
|
||||
* @return void
|
||||
*/
|
||||
public function setPayload(object $payload) : void;
|
||||
}
|
||||
50
vendor/Gcp/firebase/php-jwt/src/Key.php
vendored
Normal file
50
vendor/Gcp/firebase/php-jwt/src/Key.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OpenSSLAsymmetricKey;
|
||||
use OpenSSLCertificate;
|
||||
use TypeError;
|
||||
class Key
|
||||
{
|
||||
/** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */
|
||||
private $keyMaterial;
|
||||
/** @var string */
|
||||
private $algorithm;
|
||||
/**
|
||||
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
|
||||
* @param string $algorithm
|
||||
*/
|
||||
public function __construct($keyMaterial, string $algorithm)
|
||||
{
|
||||
if (!\is_string($keyMaterial) && !$keyMaterial instanceof OpenSSLAsymmetricKey && !$keyMaterial instanceof OpenSSLCertificate && !\is_resource($keyMaterial)) {
|
||||
throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
|
||||
}
|
||||
if (empty($keyMaterial)) {
|
||||
throw new InvalidArgumentException('Key material must not be empty');
|
||||
}
|
||||
if (empty($algorithm)) {
|
||||
throw new InvalidArgumentException('Algorithm must not be empty');
|
||||
}
|
||||
// TODO: Remove in PHP 8.0 in favor of class constructor property promotion
|
||||
$this->keyMaterial = $keyMaterial;
|
||||
$this->algorithm = $algorithm;
|
||||
}
|
||||
/**
|
||||
* Return the algorithm valid for this key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlgorithm() : string
|
||||
{
|
||||
return $this->algorithm;
|
||||
}
|
||||
/**
|
||||
* @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
|
||||
*/
|
||||
public function getKeyMaterial()
|
||||
{
|
||||
return $this->keyMaterial;
|
||||
}
|
||||
}
|
||||
7
vendor/Gcp/firebase/php-jwt/src/SignatureInvalidException.php
vendored
Normal file
7
vendor/Gcp/firebase/php-jwt/src/SignatureInvalidException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Firebase\JWT;
|
||||
|
||||
class SignatureInvalidException extends \UnexpectedValueException
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user