Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/tutor-pro/vendor/web-token/jwt-core/JWKSet.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + declare(strict_types=1);
4 +
5 + /*
6 + * The MIT License (MIT)
7 + *
8 + * Copyright (c) 2014-2020 Spomky-Labs
9 + *
10 + * This software may be modified and distributed under the terms
11 + * of the MIT license. See the LICENSE file for details.
12 + */
13 +
14 + namespace Jose\Component\Core;
15 +
16 + use function array_key_exists;
17 + use ArrayIterator;
18 + use function count;
19 + use Countable;
20 + use function in_array;
21 + use InvalidArgumentException;
22 + use function is_array;
23 + use IteratorAggregate;
24 + use JsonSerializable;
25 + use Traversable;
26 +
27 + class JWKSet implements Countable, IteratorAggregate, JsonSerializable
28 + {
29 + /**
30 + * @var array
31 + */
32 + private $keys = [];
33 +
34 + /**
35 + * @param JWK[] $keys
36 + *
37 + * @throws InvalidArgumentException if the list is invalid
38 + */
39 + public function __construct(array $keys)
40 + {
41 + foreach ($keys as $k => $key) {
42 + if (!$key instanceof JWK) {
43 + throw new InvalidArgumentException('Invalid list. Should only contains JWK objects');
44 + }
45 +
46 + if ($key->has('kid')) {
47 + unset($keys[$k]);
48 + $this->keys[$key->get('kid')] = $key;
49 + } else {
50 + $this->keys[] = $key;
51 + }
52 + }
53 + }
54 +
55 + /**
56 + * Creates a JWKSet object using the given values.
57 + *
58 + * @throws InvalidArgumentException if the keyset is not valid
59 + *
60 + * @return JWKSet
61 + */
62 + public static function createFromKeyData(array $data): self
63 + {
64 + if (!isset($data['keys'])) {
65 + throw new InvalidArgumentException('Invalid data.');
66 + }
67 + if (!is_array($data['keys'])) {
68 + throw new InvalidArgumentException('Invalid data.');
69 + }
70 +
71 + $jwkset = new self([]);
72 + foreach ($data['keys'] as $key) {
73 + $jwk = new JWK($key);
74 + if ($jwk->has('kid')) {
75 + $jwkset->keys[$jwk->get('kid')] = $jwk;
76 + } else {
77 + $jwkset->keys[] = $jwk;
78 + }
79 + }
80 +
81 + return $jwkset;
82 + }
83 +
84 + /**
85 + * Creates a JWKSet object using the given Json string.
86 + *
87 + * @throws InvalidArgumentException if the data is not valid
88 + *
89 + * @return JWKSet
90 + */
91 + public static function createFromJson(string $json): self
92 + {
93 + $data = json_decode($json, true);
94 + if (!is_array($data)) {
95 + throw new InvalidArgumentException('Invalid argument.');
96 + }
97 +
98 + return self::createFromKeyData($data);
99 + }
100 +
101 + /**
102 + * Returns an array of keys stored in the key set.
103 + *
104 + * @return JWK[]
105 + */
106 + public function all(): array
107 + {
108 + return $this->keys;
109 + }
110 +
111 + /**
112 + * Add key to store in the key set.
113 + * This method is immutable and will return a new object.
114 + *
115 + * @return JWKSet
116 + */
117 + public function with(JWK $jwk): self
118 + {
119 + $clone = clone $this;
120 +
121 + if ($jwk->has('kid')) {
122 + $clone->keys[$jwk->get('kid')] = $jwk;
123 + } else {
124 + $clone->keys[] = $jwk;
125 + }
126 +
127 + return $clone;
128 + }
129 +
130 + /**
131 + * Remove key from the key set.
132 + * This method is immutable and will return a new object.
133 + *
134 + * @param int|string $key Key to remove from the key set
135 + *
136 + * @return JWKSet
137 + */
138 + public function without($key): self
139 + {
140 + if (!$this->has($key)) {
141 + return $this;
142 + }
143 +
144 + $clone = clone $this;
145 + unset($clone->keys[$key]);
146 +
147 + return $clone;
148 + }
149 +
150 + /**
151 + * Returns true if the key set contains a key with the given index.
152 + *
153 + * @param int|string $index
154 + */
155 + public function has($index): bool
156 + {
157 + return array_key_exists($index, $this->keys);
158 + }
159 +
160 + /**
161 + * Returns the key with the given index. Throws an exception if the index is not present in the key store.
162 + *
163 + * @param int|string $index
164 + *
165 + * @throws InvalidArgumentException if the index is not defined
166 + */
167 + public function get($index): JWK
168 + {
169 + if (!$this->has($index)) {
170 + throw new InvalidArgumentException('Undefined index.');
171 + }
172 +
173 + return $this->keys[$index];
174 + }
175 +
176 + /**
177 + * Returns the values to be serialized.
178 + */
179 + public function jsonSerialize(): array
180 + {
181 + return ['keys' => array_values($this->keys)];
182 + }
183 +
184 + /**
185 + * Returns the number of keys in the key set.
186 + *
187 + * @param int $mode
188 + */
189 + public function count($mode = COUNT_NORMAL): int
190 + {
191 + return count($this->keys, $mode);
192 + }
193 +
194 + /**
195 + * Try to find a key that fits on the selected requirements.
196 + * Returns null if not found.
197 + *
198 + * @param string $type Must be 'sig' (signature) or 'enc' (encryption)
199 + * @param null|Algorithm $algorithm Specifies the algorithm to be used
200 + * @param array $restrictions More restrictions such as 'kid' or 'kty'
201 + *
202 + * @throws InvalidArgumentException if the key type is not valid (must be "sig" or "enc")
203 + */
204 + public function selectKey(string $type, ?Algorithm $algorithm = null, array $restrictions = []): ?JWK
205 + {
206 + if (!in_array($type, ['enc', 'sig'], true)) {
207 + throw new InvalidArgumentException('Allowed key types are "sig" or "enc".');
208 + }
209 +
210 + $result = [];
211 + foreach ($this->keys as $key) {
212 + $ind = 0;
213 +
214 + $can_use = $this->canKeyBeUsedFor($type, $key);
215 + if (false === $can_use) {
216 + continue;
217 + }
218 + $ind += $can_use;
219 +
220 + $alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key);
221 + if (false === $alg) {
222 + continue;
223 + }
224 + $ind += $alg;
225 +
226 + if (false === $this->doesKeySatisfyRestrictions($restrictions, $key)) {
227 + continue;
228 + }
229 +
230 + $result[] = ['key' => $key, 'ind' => $ind];
231 + }
232 +
233 + if (0 === count($result)) {
234 + return null;
235 + }
236 +
237 + usort($result, [$this, 'sortKeys']);
238 +
239 + return $result[0]['key'];
240 + }
241 +
242 + /**
243 + * Internal method only. Should not be used.
244 + *
245 + * @internal
246 + * @internal
247 + */
248 + public static function sortKeys(array $a, array $b): int
249 + {
250 + if ($a['ind'] === $b['ind']) {
251 + return 0;
252 + }
253 +
254 + return ($a['ind'] > $b['ind']) ? -1 : 1;
255 + }
256 +
257 + /**
258 + * Internal method only. Should not be used.
259 + *
260 + * @internal
261 + */
262 + public function getIterator(): Traversable
263 + {
264 + return new ArrayIterator($this->keys);
265 + }
266 +
267 + /**
268 + * @throws InvalidArgumentException if the key does not fulfill with the "key_ops" constraint
269 + *
270 + * @return bool|int
271 + */
272 + private function canKeyBeUsedFor(string $type, JWK $key)
273 + {
274 + if ($key->has('use')) {
275 + return $type === $key->get('use') ? 1 : false;
276 + }
277 + if ($key->has('key_ops')) {
278 + $key_ops = $key->get('key_ops');
279 + if (!is_array($key_ops)) {
280 + throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations');
281 + }
282 +
283 + return $type === self::convertKeyOpsToKeyUse($key_ops) ? 1 : false;
284 + }
285 +
286 + return 0;
287 + }
288 +
289 + /**
290 + * @return bool|int
291 + */
292 + private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key)
293 + {
294 + if (null === $algorithm) {
295 + return 0;
296 + }
297 + if (!in_array($key->get('kty'), $algorithm->allowedKeyTypes(), true)) {
298 + return false;
299 + }
300 + if ($key->has('alg')) {
301 + return $algorithm->name() === $key->get('alg') ? 2 : false;
302 + }
303 +
304 + return 1;
305 + }
306 +
307 + private function doesKeySatisfyRestrictions(array $restrictions, JWK $key): bool
308 + {
309 + foreach ($restrictions as $k => $v) {
310 + if (!$key->has($k) || $v !== $key->get($k)) {
311 + return false;
312 + }
313 + }
314 +
315 + return true;
316 + }
317 +
318 + /**
319 + * @throws InvalidArgumentException if the key operation is not supported
320 + */
321 + private static function convertKeyOpsToKeyUse(array $key_ops): string
322 + {
323 + switch (true) {
324 + case in_array('verify', $key_ops, true):
325 + case in_array('sign', $key_ops, true):
326 + return 'sig';
327 +
328 + case in_array('encrypt', $key_ops, true):
329 + case in_array('decrypt', $key_ops, true):
330 + case in_array('wrapKey', $key_ops, true):
331 + case in_array('unwrapKey', $key_ops, true):
332 + case in_array('deriveKey', $key_ops, true):
333 + case in_array('deriveBits', $key_ops, true):
334 + return 'enc';
335 +
336 + default:
337 + throw new InvalidArgumentException(sprintf('Unsupported key operation value "%s"', implode(', ', $key_ops)));
338 + }
339 + }
340 + }
341 +