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.
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
+