Completed
Push — master ( d8c018...19ac78 )
by Florent
06:38
created

JWE   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 407
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 7
Bugs 4 Features 1
Metric Value
wmc 49
c 7
b 4
f 1
lcom 1
cbo 5
dl 0
loc 407
rs 8.5454

33 Methods

Rating   Name   Duplication   Size   Complexity  
A isEncrypted() 0 4 1
A addRecipientWithEncryptedKey() 0 7 1
A countRecipients() 0 4 1
A getRecipient() 0 6 1
B getJSONBase() 0 23 6
A checkHasNoAAD() 0 4 1
A checkRecipientHasNoHeaders() 0 7 2
A checkHasSharedProtectedHeaders() 0 7 1
A addRecipientInformation() 0 8 1
A getRecipients() 0 4 1
A getCiphertext() 0 4 1
A withCiphertext() 0 7 1
A getAAD() 0 4 1
A withAAD() 0 7 1
A getIV() 0 4 1
A withIV() 0 7 1
A getTag() 0 4 1
A withTag() 0 7 1
A getEncodedSharedProtectedHeaders() 0 4 1
A withEncodedSharedProtectedHeaders() 0 7 1
A getSharedProtectedHeaders() 0 4 1
A withSharedProtectedHeaders() 0 7 1
A withSharedProtectedHeader() 0 7 1
A getSharedProtectedHeader() 0 7 2
A hasSharedProtectedHeader() 0 4 1
A withSharedHeaders() 0 7 1
A withSharedHeader() 0 7 1
A getSharedHeaders() 0 4 1
A getSharedHeader() 0 7 2
A hasSharedHeader() 0 4 1
A toCompactJSON() 0 17 4
A toFlattenedJSON() 0 15 3
A toJSON() 0 18 4

How to fix   Complexity   

Complex Class

Complex classes like JWE often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JWE, and based on these observations, apply Extract Interface, too.

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