Failed Conditions
Push — v7 ( 044b56...cc2410 )
by Florent
02:06
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\JWTInterface;
19
20
/**
21
 * Class JWE.
22
 */
23
final class JWE implements JWTInterface
24
{
25
    /**
26
     * @var Recipient[]
27
     */
28
    private $recipients = [];
29
30
    /**
31
     * @var string|null
32
     */
33
    private $ciphertext = null;
34
35
    /**
36
     * @var string|null
37
     */
38
    private $iv = null;
39
40
    /**
41
     * @var string|null
42
     */
43
    private $aad = null;
44
45
    /**
46
     * @var string|null
47
     */
48
    private $tag = null;
49
50
    /**
51
     * @var array
52
     */
53
    private $sharedHeaders = [];
54
55
    /**
56
     * @var array
57
     */
58
    private $sharedProtectedHeaders = [];
59
60
    /**
61
     * @var string|null
62
     */
63
    private $encodedSharedProtectedHeaders = null;
64
65
    /**
66
     * @var mixed|null
67
     */
68
    private $payload = null;
69
70
    /**
71
     * JWE constructor.
72
     *
73
     * @param string      $ciphertext
74
     * @param null|string $iv
75
     * @param null|string $aad
76
     * @param null|string $tag
77
     * @param array       $sharedHeaders
78
     * @param array       $sharedProtectedHeaders
79
     * @param null|string $encodedSharedProtectedHeaders
80
     * @param array       $recipients
81
     */
82
    private function __construct(string $ciphertext, ?string $iv = null, ?string $aad = null, ?string $tag = null, array $sharedHeaders = [], array $sharedProtectedHeaders = [], ?string $encodedSharedProtectedHeaders = null, array $recipients = [])
83
    {
84
        $this->ciphertext = $ciphertext;
85
        $this->iv = $iv;
86
        $this->aad = $aad;
87
        $this->tag = $tag;
88
        $this->sharedHeaders = $sharedHeaders;
89
        $this->sharedProtectedHeaders = $sharedProtectedHeaders;
90
        $this->encodedSharedProtectedHeaders = $encodedSharedProtectedHeaders;
91
        $this->recipients = $recipients;
92
    }
93
94
    /**
95
     * @param string      $ciphertext
96
     * @param null|string $iv
97
     * @param null|string $aad
98
     * @param null|string $tag
99
     * @param array       $sharedHeaders
100
     * @param array       $sharedProtectedHeaders
101
     * @param null|string $encodedSharedProtectedHeaders
102
     * @param array       $recipients
103
     *
104
     * @return JWE
105
     */
106
    public static function create(string $ciphertext, ?string $iv = null, ?string $aad = null, ?string $tag = null, array $sharedHeaders = [], array $sharedProtectedHeaders = [], ?string $encodedSharedProtectedHeaders = null, array $recipients = []): JWE
107
    {
108
        return new self($ciphertext, $iv, $aad, $tag, $sharedHeaders, $sharedProtectedHeaders, $encodedSharedProtectedHeaders, $recipients);
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function getPayload()
115
    {
116
        return $this->payload;
117
    }
118
119
    /**
120
     * @param $payload
121
     *
122
     * @return JWE
123
     */
124
    public function withPayload($payload): JWE
125
    {
126
        $clone = clone $this;
127
        $clone->payload = $payload;
128
129
        return $clone;
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function getClaim(string $key)
136
    {
137
        if ($this->hasClaim($key)) {
138
            return $this->payload[$key];
139
        }
140
        throw new \InvalidArgumentException(sprintf('The payload does not contain claim "%s".', $key));
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function getClaims(): array
147
    {
148
        if (!$this->hasClaims()) {
149
            throw new \InvalidArgumentException('The payload does not contain claims.');
150
        }
151
152
        return $this->payload;
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function hasClaim(string $key): bool
159
    {
160
        return $this->hasClaims() && array_key_exists($key, $this->payload);
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166
    public function hasClaims(): bool
167
    {
168
        return is_array($this->payload);
169
    }
170
171
    /**
172
     * Returns the number of recipients associated with the JWS.
173
     *
174
     * @return int
175
     */
176
    public function countRecipients(): int
177
    {
178
        return count($this->recipients);
179
    }
180
181
    /**
182
     * @return bool
183
     */
184
    public function isEncrypted(): bool
185
    {
186
        return null !== $this->getCiphertext();
187
    }
188
189
    /**
190
     * Returns the recipients associated with the JWS.
191
     *
192
     * @return Recipient[]
193
     */
194
    public function getRecipients(): array
195
    {
196
        return $this->recipients;
197
    }
198
199
    /**
200
     * @param int $id
201
     *
202
     * @return Recipient
203
     */
204
    public function getRecipient(int $id): Recipient
205
    {
206
        Assertion::keyExists($this->recipients, $id, 'The recipient does not exist.');
207
208
        return $this->recipients[$id];
209
    }
210
211
    /**
212
     * @return string|null The cyphertext
213
     */
214
    public function getCiphertext(): ?string
215
    {
216
        return $this->ciphertext;
217
    }
218
219
    /**
220
     * @return string|null
221
     */
222
    public function getAAD(): ?string
223
    {
224
        return $this->aad;
225
    }
226
227
    /**
228
     * @return string|null
229
     */
230
    public function getIV(): ?string
231
    {
232
        return $this->iv;
233
    }
234
235
    /**
236
     * @return string|null
237
     */
238
    public function getTag(): ?string
239
    {
240
        return $this->tag;
241
    }
242
243
    /**
244
     * @return string
245
     */
246
    public function getEncodedSharedProtectedHeaders(): string
247
    {
248
        return $this->encodedSharedProtectedHeaders ?? '';
249
    }
250
251
    /**
252
     * @return array
253
     */
254
    public function getSharedProtectedHeaders(): array
255
    {
256
        return $this->sharedProtectedHeaders;
257
    }
258
259
    /**
260
     * @param string $key The key
261
     *
262
     * @return mixed|null Header value
263
     */
264
    public function getSharedProtectedHeader(string $key)
265
    {
266
        if ($this->hasSharedProtectedHeader($key)) {
267
            return $this->sharedProtectedHeaders[$key];
268
        }
269
        throw new \InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key));
270
    }
271
272
    /**
273
     * @param string $key The key
274
     *
275
     * @return bool
276
     */
277
    public function hasSharedProtectedHeader(string $key): bool
278
    {
279
        return array_key_exists($key, $this->sharedProtectedHeaders);
280
    }
281
282
    /**
283
     * @return array
284
     */
285
    public function getSharedHeaders(): array
286
    {
287
        return $this->sharedHeaders;
288
    }
289
290
    /**
291
     * @param string $key The key
292
     *
293
     * @return mixed|null Header value
294
     */
295
    public function getSharedHeader(string $key)
296
    {
297
        if ($this->hasSharedHeader($key)) {
298
            return $this->sharedHeaders[$key];
299
        }
300
        throw new \InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key));
301
    }
302
303
    /**
304
     * @param string $key The key
305
     *
306
     * @return bool
307
     */
308
    public function hasSharedHeader(string $key): bool
309
    {
310
        return array_key_exists($key, $this->sharedHeaders);
311
    }
312
313
    /**
314
     * @param int $id
315
     *
316
     * @return string
317
     */
318
    public function toCompactJSON(int $id): string
319
    {
320
        $recipient = $this->getRecipient($id);
321
322
        $this->checkHasNoAAD();
323
        $this->checkHasSharedProtectedHeaders();
324
        $this->checkRecipientHasNoHeaders($id);
325
326
        return sprintf(
327
            '%s.%s.%s.%s.%s',
328
            $this->getEncodedSharedProtectedHeaders(),
329
            Base64Url::encode(null === $recipient->getEncryptedKey() ? '' : $recipient->getEncryptedKey()),
330
            Base64Url::encode(null === $this->getIV() ? '' : $this->getIV()),
331
            Base64Url::encode($this->getCiphertext()),
332
            Base64Url::encode(null === $this->getTag() ? '' : $this->getTag())
333
        );
334
    }
335
336
    private function checkHasNoAAD()
337
    {
338
        Assertion::true(empty($this->getAAD()), 'This JWE has AAD and cannot be converted into Compact JSON.');
339
    }
340
341
    /**
342
     * @param int $id
343
     */
344
    private function checkRecipientHasNoHeaders(int $id)
345
    {
346
        Assertion::true(
347
            empty($this->getSharedHeaders()) && empty($this->getRecipient($id)->getHeaders()),
348
            'This JWE has shared headers or recipient headers and cannot be converted into Compact JSON.'
349
        );
350
    }
351
352
    private function checkHasSharedProtectedHeaders()
353
    {
354
        Assertion::notEmpty(
355
            $this->getSharedProtectedHeaders(),
356
            'This JWE does not have shared protected headers and cannot be converted into Compact JSON.'
357
        );
358
    }
359
360
    /**
361
     * @param int $id
362
     *
363
     * @return string
364
     */
365
    public function toFlattenedJSON(int $id): string
366
    {
367
        $recipient = $this->getRecipient($id);
368
369
        $json = $this->getJSONBase();
370
371
        if (!empty($recipient->getHeaders())) {
372
            $json['header'] = $recipient->getHeaders();
373
        }
374
        if (!empty($recipient->getEncryptedKey())) {
375
            $json['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
376
        }
377
378
        return json_encode($json);
379
    }
380
381
    /**
382
     * @return string
383
     */
384
    public function toJSON(): string
385
    {
386
        $json = $this->getJSONBase();
387
        $json['recipients'] = [];
388
389
        foreach ($this->getRecipients() as $recipient) {
390
            $temp = [];
391
            if (!empty($recipient->getHeaders())) {
392
                $temp['header'] = $recipient->getHeaders();
393
            }
394
            if (!empty($recipient->getEncryptedKey())) {
395
                $temp['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
396
            }
397
            $json['recipients'][] = $temp;
398
        }
399
400
        return json_encode($json);
401
    }
402
403
    /**
404
     * @return array
405
     */
406
    private function getJSONBase(): array
407
    {
408
        $json = [
409
            'ciphertext' => Base64Url::encode($this->getCiphertext()),
410
        ];
411
        if (null !== $this->getIV()) {
412
            $json['iv'] = Base64Url::encode($this->getIV());
413
        }
414
        if (null !== $this->getTag()) {
415
            $json['tag'] = Base64Url::encode($this->getTag());
416
        }
417
        if (null !== $this->getAAD()) {
418
            $json['aad'] = Base64Url::encode($this->getAAD());
419
        }
420
        if (!empty($this->getSharedProtectedHeaders())) {
421
            $json['protected'] = $this->getEncodedSharedProtectedHeaders();
422
        }
423
        if (!empty($this->getSharedHeaders())) {
424
            $json['unprotected'] = $this->getSharedHeaders();
425
        }
426
427
        return $json;
428
    }
429
}
430