PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.19
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.19
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / vendor_prefixed / firebase / php-jwt / src / CachedKeySet.php

CachedKeySet.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.19, at vendor_prefixed/firebase/php-jwt/src/CachedKeySet.php

227 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WCPOS\Vendor\Firebase\JWT;
4
5 use ArrayAccess;
6 use InvalidArgumentException;
7 use LogicException;
8 use OutOfBoundsException;
9 use WCPOS\Vendor\Psr\Cache\CacheItemInterface;
10 use WCPOS\Vendor\Psr\Cache\CacheItemPoolInterface;
11 use WCPOS\Vendor\Psr\Http\Client\ClientInterface;
12 use WCPOS\Vendor\Psr\Http\Message\RequestFactoryInterface;
13 use RuntimeException;
14 use UnexpectedValueException;
15 /**
16 * @implements ArrayAccess<string, Key>
17 */
18 class CachedKeySet implements ArrayAccess
19 {
20 /**
21 * @var string
22 */
23 private $jwksUri;
24 /**
25 * @var ClientInterface
26 */
27 private $httpClient;
28 /**
29 * @var RequestFactoryInterface
30 */
31 private $httpFactory;
32 /**
33 * @var CacheItemPoolInterface
34 */
35 private $cache;
36 /**
37 * @var ?int
38 */
39 private $expiresAfter;
40 /**
41 * @var ?CacheItemInterface
42 */
43 private $cacheItem;
44 /**
45 * @var array<string, array<mixed>>
46 */
47 private $keySet;
48 /**
49 * @var string
50 */
51 private $cacheKey;
52 /**
53 * @var string
54 */
55 private $cacheKeyPrefix = 'jwks';
56 /**
57 * @var int
58 */
59 private $maxKeyLength = 64;
60 /**
61 * @var bool
62 */
63 private $rateLimit;
64 /**
65 * @var string
66 */
67 private $rateLimitCacheKey;
68 /**
69 * @var int
70 */
71 private $maxCallsPerMinute = 10;
72 /**
73 * @var string|null
74 */
75 private $defaultAlg;
76 public function __construct(string $jwksUri, ClientInterface $httpClient, RequestFactoryInterface $httpFactory, CacheItemPoolInterface $cache, int $expiresAfter = null, bool $rateLimit = \false, string $defaultAlg = null)
77 {
78 $this->jwksUri = $jwksUri;
79 $this->httpClient = $httpClient;
80 $this->httpFactory = $httpFactory;
81 $this->cache = $cache;
82 $this->expiresAfter = $expiresAfter;
83 $this->rateLimit = $rateLimit;
84 $this->defaultAlg = $defaultAlg;
85 $this->setCacheKeys();
86 }
87 /**
88 * @param string $keyId
89 * @return Key
90 */
91 public function offsetGet($keyId) : Key
92 {
93 if (!$this->keyIdExists($keyId)) {
94 throw new OutOfBoundsException('Key ID not found');
95 }
96 return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
97 }
98 /**
99 * @param string $keyId
100 * @return bool
101 */
102 public function offsetExists($keyId) : bool
103 {
104 return $this->keyIdExists($keyId);
105 }
106 /**
107 * @param string $offset
108 * @param Key $value
109 */
110 public function offsetSet($offset, $value) : void
111 {
112 throw new LogicException('Method not implemented');
113 }
114 /**
115 * @param string $offset
116 */
117 public function offsetUnset($offset) : void
118 {
119 throw new LogicException('Method not implemented');
120 }
121 /**
122 * @return array<mixed>
123 */
124 private function formatJwksForCache(string $jwks) : array
125 {
126 $jwks = \json_decode($jwks, \true);
127 if (!isset($jwks['keys'])) {
128 throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
129 }
130 if (empty($jwks['keys'])) {
131 throw new InvalidArgumentException('JWK Set did not contain any keys');
132 }
133 $keys = [];
134 foreach ($jwks['keys'] as $k => $v) {
135 $kid = isset($v['kid']) ? $v['kid'] : $k;
136 $keys[(string) $kid] = $v;
137 }
138 return $keys;
139 }
140 private function keyIdExists(string $keyId) : bool
141 {
142 if (null === $this->keySet) {
143 $item = $this->getCacheItem();
144 // Try to load keys from cache
145 if ($item->isHit()) {
146 // item found! retrieve it
147 $this->keySet = $item->get();
148 // If the cached item is a string, the JWKS response was cached (previous behavior).
149 // Parse this into expected format array<kid, jwk> instead.
150 if (\is_string($this->keySet)) {
151 $this->keySet = $this->formatJwksForCache($this->keySet);
152 }
153 }
154 }
155 if (!isset($this->keySet[$keyId])) {
156 if ($this->rateLimitExceeded()) {
157 return \false;
158 }
159 $request = $this->httpFactory->createRequest('GET', $this->jwksUri);
160 $jwksResponse = $this->httpClient->sendRequest($request);
161 if ($jwksResponse->getStatusCode() !== 200) {
162 throw new UnexpectedValueException(\sprintf('HTTP Error: %d %s for URI "%s"', $jwksResponse->getStatusCode(), $jwksResponse->getReasonPhrase(), $this->jwksUri), $jwksResponse->getStatusCode());
163 }
164 $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
165 if (!isset($this->keySet[$keyId])) {
166 return \false;
167 }
168 $item = $this->getCacheItem();
169 $item->set($this->keySet);
170 if ($this->expiresAfter) {
171 $item->expiresAfter($this->expiresAfter);
172 }
173 $this->cache->save($item);
174 }
175 return \true;
176 }
177 private function rateLimitExceeded() : bool
178 {
179 if (!$this->rateLimit) {
180 return \false;
181 }
182 $cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
183 if (!$cacheItem->isHit()) {
184 $cacheItem->expiresAfter(1);
185 // # of calls are cached each minute
186 }
187 $callsPerMinute = (int) $cacheItem->get();
188 if (++$callsPerMinute > $this->maxCallsPerMinute) {
189 return \true;
190 }
191 $cacheItem->set($callsPerMinute);
192 $this->cache->save($cacheItem);
193 return \false;
194 }
195 private function getCacheItem() : CacheItemInterface
196 {
197 if (\is_null($this->cacheItem)) {
198 $this->cacheItem = $this->cache->getItem($this->cacheKey);
199 }
200 return $this->cacheItem;
201 }
202 private function setCacheKeys() : void
203 {
204 if (empty($this->jwksUri)) {
205 throw new RuntimeException('JWKS URI is empty');
206 }
207 // ensure we do not have illegal characters
208 $key = \preg_replace('|[^a-zA-Z0-9_\\.!]|', '', $this->jwksUri);
209 // add prefix
210 $key = $this->cacheKeyPrefix . $key;
211 // Hash keys if they exceed $maxKeyLength of 64
212 if (\strlen($key) > $this->maxKeyLength) {
213 $key = \substr(\hash('sha256', $key), 0, $this->maxKeyLength);
214 }
215 $this->cacheKey = $key;
216 if ($this->rateLimit) {
217 // add prefix
218 $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key;
219 // Hash keys if they exceed $maxKeyLength of 64
220 if (\strlen($rateLimitKey) > $this->maxKeyLength) {
221 $rateLimitKey = \substr(\hash('sha256', $rateLimitKey), 0, $this->maxKeyLength);
222 }
223 $this->rateLimitCacheKey = $rateLimitKey;
224 }
225 }
226 }
227