Failed Conditions
Push — v7 ( ae6905...7dd7be )
by Florent
03:50
created

JWE::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 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\Encryption;
15
16
use Assert\Assertion;
17
use Base64Url\Base64Url;
18
use Jose\Component\Core\JWK;
19
use Jose\Component\Core\JWTInterface;
20
21
/**
22
 * Class JWE.
23
 */
24
final class JWE implements JWTInterface
25
{
26
    /**
27
     * @var Recipient[]
28
     */
29
    private $recipients = [];
30
31
    /**
32
     * @var string|null
33
     */
34
    private $ciphertext = null;
35
36
    /**
37
     * @var string|null
38
     */
39
    private $iv = null;
40
41
    /**
42
     * @var string|null
43
     */
44
    private $aad = null;
45
46
    /**
47
     * @var string|null
48
     */
49
    private $tag = null;
50
51
    /**
52
     * @var array
53
     */
54
    private $sharedHeaders = [];
55
56
    /**
57
     * @var array
58
     */
59
    private $sharedProtectedKeaders = [];
60
61
    /**
62
     * @var string|null
63
     */
64
    private $encodedSharedProtectedKeaders = null;
65
66
    /**
67
     * @var mixed|null
68
     */
69
    private $payload = null;
70
71
    /**
72
     * JWE constructor.
73
     *
74
     * @param null|string $ciphertext
75
     * @param null|string $iv
76
     * @param null|string $aad
77
     * @param null|string $tag
78
     * @param array       $sharedHeaders
79
     * @param array       $sharedProtectedKeaders
80
     * @param null|string $encodedSharedProtectedKeaders
81
     * @param mixed|null  $payload
82
     * @param array       $recipients
83
     */
84
    private function __construct(?string $ciphertext = null, ?string $iv = null, ?string $aad = null, ?string $tag = null, array $sharedHeaders = [], array $sharedProtectedKeaders = [], ?string $encodedSharedProtectedKeaders = null, $payload = null, array $recipients = [])
85
    {
86
        $this->ciphertext = $ciphertext;
87
        $this->iv = $iv;
88
        $this->aad = $aad;
89
        $this->tag = $tag;
90
        $this->sharedHeaders = $sharedHeaders;
91
        $this->sharedProtectedKeaders = $sharedProtectedKeaders;
92
        $this->encodedSharedProtectedKeaders = $encodedSharedProtectedKeaders;
93
        $this->payload = $payload;
94
        $this->recipients = $recipients;
95
    }
96
97
    /**
98
     * @return JWE
99
     */
100
    public static function createEmpty(): JWE
101
    {
102
        return new self();
103
    }
104
105
    /**
106
     * @param null|string $ciphertext
107
     * @param null|string $iv
108
     * @param null|string $aad
109
     * @param null|string $tag
110
     * @param array       $sharedHeaders
111
     * @param array       $sharedProtectedKeaders
112
     * @param null|string $encodedSharedProtectedKeaders
113
     * @param array       $recipients
114
     *
115
     * @return JWE
116
     */
117
    public static function create(?string $ciphertext = null, ?string $iv = null, ?string $aad = null, ?string $tag = null, array $sharedHeaders = [], array $sharedProtectedKeaders = [], ?string $encodedSharedProtectedKeaders = null, array $recipients = []): JWE
118
    {
119
        return new self($ciphertext, $iv, $aad, $tag, $sharedHeaders, $sharedProtectedKeaders, $encodedSharedProtectedKeaders, null, $recipients);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function getPayload()
126
    {
127
        return $this->payload;
128
    }
129
130
    /**
131
     * @param mixed $payload
132
     *
133
     * @return JWE
134
     */
135
    public function withPayload($payload): JWE
136
    {
137
        $jwt = clone $this;
138
        $jwt->payload = $payload;
139
140
        return $jwt;
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function getClaim(string $key)
147
    {
148
        if ($this->hasClaim($key)) {
149
            return $this->payload[$key];
150
        }
151
        throw new \InvalidArgumentException(sprintf('The payload does not contain claim "%s".', $key));
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157
    public function getClaims(): array
158
    {
159
        if (!$this->hasClaims()) {
160
            throw new \InvalidArgumentException('The payload does not contain claims.');
161
        }
162
163
        return $this->payload;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function hasClaim(string $key): bool
170
    {
171
        return $this->hasClaims() && array_key_exists($key, $this->payload);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function hasClaims(): bool
178
    {
179
        return is_array($this->payload);
180
    }
181
182
    /**
183
     * Returns the number of recipients associated with the JWS.
184
     *
185
     * @return int
186
     */
187
    public function countRecipients(): int
188
    {
189
        return count($this->recipients);
190
    }
191
192
    /**
193
     * @return bool
194
     */
195
    public function isEncrypted(): bool
196
    {
197
        return null !== $this->getCiphertext();
198
    }
199
200
    /**
201
     * @param array       $recipientHeaders
202
     * @param string|null $encryptedKey
203
     *
204
     * @return JWE
205
     */
206
    public function addRecipient(array $recipientHeaders = [], ?string $encryptedKey = null): JWE
207
    {
208
        $clone = clone $this;
209
        $clone->recipients[] = Recipient::create($recipientHeaders, $encryptedKey);
210
211
        return $clone;
212
    }
213
214
    /**
215
     * Returns the recipients associated with the JWS.
216
     *
217
     * @return Recipient[]
218
     */
219
    public function getRecipients(): array
220
    {
221
        return $this->recipients;
222
    }
223
224
    /**
225
     * @param int $id
226
     *
227
     * @return Recipient
228
     */
229
    public function getRecipient(int $id): Recipient
230
    {
231
        Assertion::keyExists($this->recipients, $id, 'The recipient does not exist.');
232
233
        return $this->recipients[$id];
234
    }
235
236
    /**
237
     * @return string|null The cyphertext
238
     */
239
    public function getCiphertext(): ?string
240
    {
241
        return $this->ciphertext;
242
    }
243
244
    /**
245
     * @param string $ciphertext
246
     *
247
     * @return JWE
248
     */
249
    public function withCiphertext(string $ciphertext): JWE
250
    {
251
        $jwe = clone $this;
252
        $jwe->ciphertext = $ciphertext;
253
254
        return $jwe;
255
    }
256
257
    /**
258
     * @return string|null
259
     */
260
    public function getAAD(): ?string
261
    {
262
        return $this->aad;
263
    }
264
265
    /**
266
     * @param string $aad
267
     *
268
     * @return JWE
269
     */
270
    public function withAAD(string $aad): JWE
271
    {
272
        $jwe = clone $this;
273
        $jwe->aad = $aad;
274
275
        return $jwe;
276
    }
277
278
    /**
279
     * @return string|null
280
     */
281
    public function getIV(): ?string
282
    {
283
        return $this->iv;
284
    }
285
286
    /**
287
     * @param string $iv
288
     *
289
     * @return JWE
290
     */
291
    public function withIV(string $iv): JWE
292
    {
293
        $jwe = clone $this;
294
        $jwe->iv = $iv;
295
296
        return $jwe;
297
    }
298
299
    /**
300
     * @return string|null
301
     */
302
    public function getTag(): ?string
303
    {
304
        return $this->tag;
305
    }
306
307
    /**
308
     * @param string $tag
309
     *
310
     * @return JWE
311
     */
312
    public function withTag(string $tag): JWE
313
    {
314
        $jwe = clone $this;
315
        $jwe->tag = $tag;
316
317
        return $jwe;
318
    }
319
320
    /**
321
     * @return string
322
     */
323
    public function getEncodedSharedProtectedHeaders(): string
324
    {
325
        return $this->encodedSharedProtectedKeaders ?? '';
326
    }
327
328
    /**
329
     * @param string $encodedSharedProtectedKeaders
330
     *
331
     * @return JWE
332
     */
333
    public function withEncodedSharedProtectedHeaders(string $encodedSharedProtectedKeaders): JWE
334
    {
335
        $jwe = clone $this;
336
        $jwe->encodedSharedProtectedKeaders = $encodedSharedProtectedKeaders;
337
338
        return $jwe;
339
    }
340
341
    /**
342
     * @return array
343
     */
344
    public function getSharedProtectedHeaders(): array
345
    {
346
        return $this->sharedProtectedKeaders;
347
    }
348
349
    /**
350
     * @param array $sharedProtectedKeaders
351
     *
352
     * @return JWE
353
     */
354
    public function withSharedProtectedHeaders(array $sharedProtectedKeaders): JWE
355
    {
356
        $jwe = clone $this;
357
        $jwe->sharedProtectedKeaders = $sharedProtectedKeaders;
358
359
        return $jwe;
360
    }
361
362
    /**
363
     * @param string     $key
364
     * @param mixed|null $value
365
     *
366
     * @return JWE
367
     */
368
    public function withSharedProtectedHeader(string $key, $value): JWE
369
    {
370
        $jwe = clone $this;
371
        $jwe->sharedProtectedKeaders[$key] = $value;
372
373
        return $jwe;
374
    }
375
376
    /**
377
     * @param string $key The key
378
     *
379
     * @return mixed|null Header value
380
     */
381
    public function getSharedProtectedHeader(string $key)
382
    {
383
        if ($this->hasSharedProtectedHeader($key)) {
384
            return $this->sharedProtectedKeaders[$key];
385
        }
386
        throw new \InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key));
387
    }
388
389
    /**
390
     * @param string $key The key
391
     *
392
     * @return bool
393
     */
394
    public function hasSharedProtectedHeader(string $key): bool
395
    {
396
        return array_key_exists($key, $this->sharedProtectedKeaders);
397
    }
398
399
    /**
400
     * @param array $sharedHeaders
401
     *
402
     * @return JWE
403
     */
404
    public function withSharedHeaders(array $sharedHeaders): JWE
405
    {
406
        $jwe = clone $this;
407
        $jwe->sharedHeaders = $sharedHeaders;
408
409
        return $jwe;
410
    }
411
412
    /**
413
     * @param string     $key
414
     * @param mixed|null $value
415
     *
416
     * @return JWE
417
     */
418
    public function withSharedHeader(string $key, $value): JWE
419
    {
420
        $jwe = clone $this;
421
        $jwe->sharedHeaders[$key] = $value;
422
423
        return $jwe;
424
    }
425
426
    /**
427
     * @return array
428
     */
429
    public function getSharedHeaders(): array
430
    {
431
        return $this->sharedHeaders;
432
    }
433
434
    /**
435
     * @param string $key The key
436
     *
437
     * @return mixed|null Header value
438
     */
439
    public function getSharedHeader(string $key)
440
    {
441
        if ($this->hasSharedHeader($key)) {
442
            return $this->sharedHeaders[$key];
443
        }
444
        throw new \InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key));
445
    }
446
447
    /**
448
     * @param string $key The key
449
     *
450
     * @return bool
451
     */
452
    public function hasSharedHeader(string $key): bool
453
    {
454
        return array_key_exists($key, $this->sharedHeaders);
455
    }
456
457
    /**
458
     * @param int $id
459
     *
460
     * @return string
461
     */
462
    public function toCompactJSON(int $id): string
463
    {
464
        $recipient = $this->getRecipient($id);
465
466
        $this->checkHasNoAAD();
467
        $this->checkHasSharedProtectedHeaders();
468
        $this->checkRecipientHasNoHeaders($id);
469
470
        return sprintf(
471
            '%s.%s.%s.%s.%s',
472
            $this->getEncodedSharedProtectedHeaders(),
473
            Base64Url::encode(null === $recipient->getEncryptedKey() ? '' : $recipient->getEncryptedKey()),
474
            Base64Url::encode(null === $this->getIV() ? '' : $this->getIV()),
475
            Base64Url::encode($this->getCiphertext()),
476
            Base64Url::encode(null === $this->getTag() ? '' : $this->getTag())
477
        );
478
    }
479
480
    private function checkHasNoAAD()
481
    {
482
        Assertion::true(empty($this->getAAD()), 'This JWE has AAD and cannot be converted into Compact JSON.');
483
    }
484
485
    /**
486
     * @param int $id
487
     */
488
    private function checkRecipientHasNoHeaders(int $id)
489
    {
490
        Assertion::true(
491
            empty($this->getSharedHeaders()) && empty($this->getRecipient($id)->getHeaders()),
492
            'This JWE has shared headers or recipient headers and cannot be converted into Compact JSON.'
493
        );
494
    }
495
496
    private function checkHasSharedProtectedHeaders()
497
    {
498
        Assertion::notEmpty(
499
            $this->getSharedProtectedHeaders(),
500
            'This JWE does not have shared protected headers and cannot be converted into Compact JSON.'
501
        );
502
    }
503
504
    /**
505
     * @param int $id
506
     *
507
     * @return string
508
     */
509
    public function toFlattenedJSON(int $id): string
510
    {
511
        $recipient = $this->getRecipient($id);
512
513
        $json = $this->getJSONBase();
514
515
        if (!empty($recipient->getHeaders())) {
516
            $json['header'] = $recipient->getHeaders();
517
        }
518
        if (!empty($recipient->getEncryptedKey())) {
519
            $json['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
520
        }
521
522
        return json_encode($json);
523
    }
524
525
    /**
526
     * @return string
527
     */
528
    public function toJSON(): string
529
    {
530
        $json = $this->getJSONBase();
531
        $json['recipients'] = [];
532
533
        foreach ($this->getRecipients() as $recipient) {
534
            $temp = [];
535
            if (!empty($recipient->getHeaders())) {
536
                $temp['header'] = $recipient->getHeaders();
537
            }
538
            if (!empty($recipient->getEncryptedKey())) {
539
                $temp['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
540
            }
541
            $json['recipients'][] = $temp;
542
        }
543
544
        return json_encode($json);
545
    }
546
547
    /**
548
     * @return array
549
     */
550
    private function getJSONBase(): array
551
    {
552
        $json = [
553
            'ciphertext' => Base64Url::encode($this->getCiphertext()),
554
        ];
555
        if (null !== $this->getIV()) {
556
            $json['iv'] = Base64Url::encode($this->getIV());
557
        }
558
        if (null !== $this->getTag()) {
559
            $json['tag'] = Base64Url::encode($this->getTag());
560
        }
561
        if (null !== $this->getAAD()) {
562
            $json['aad'] = Base64Url::encode($this->getAAD());
563
        }
564
        if (!empty($this->getSharedProtectedHeaders())) {
565
            $json['protected'] = $this->getEncodedSharedProtectedHeaders();
566
        }
567
        if (!empty($this->getSharedHeaders())) {
568
            $json['unprotected'] = $this->getSharedHeaders();
569
        }
570
571
        return $json;
572
    }
573
}
574