Failed Conditions
Push — v7 ( a94305...5a1c51 )
by Florent
02:15
created

JWE::getClaims()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
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 string|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(): ?string
115
    {
116
        return $this->payload;
117
    }
118
119
    /**
120
     * @param string $payload
121
     *
122
     * @return JWE
123
     */
124
    public function withPayload(string $payload): JWE
125
    {
126
        $clone = clone $this;
127
        $clone->payload = $payload;
128
129
        return $clone;
130
    }
131
132
    /**
133
     * Returns the number of recipients associated with the JWS.
134
     *
135
     * @return int
136
     */
137
    public function countRecipients(): int
138
    {
139
        return count($this->recipients);
140
    }
141
142
    /**
143
     * @return bool
144
     */
145
    public function isEncrypted(): bool
146
    {
147
        return null !== $this->getCiphertext();
148
    }
149
150
    /**
151
     * Returns the recipients associated with the JWS.
152
     *
153
     * @return Recipient[]
154
     */
155
    public function getRecipients(): array
156
    {
157
        return $this->recipients;
158
    }
159
160
    /**
161
     * @param int $id
162
     *
163
     * @return Recipient
164
     */
165
    public function getRecipient(int $id): Recipient
166
    {
167
        Assertion::keyExists($this->recipients, $id, 'The recipient does not exist.');
168
169
        return $this->recipients[$id];
170
    }
171
172
    /**
173
     * @return string|null The cyphertext
174
     */
175
    public function getCiphertext(): ?string
176
    {
177
        return $this->ciphertext;
178
    }
179
180
    /**
181
     * @return string|null
182
     */
183
    public function getAAD(): ?string
184
    {
185
        return $this->aad;
186
    }
187
188
    /**
189
     * @return string|null
190
     */
191
    public function getIV(): ?string
192
    {
193
        return $this->iv;
194
    }
195
196
    /**
197
     * @return string|null
198
     */
199
    public function getTag(): ?string
200
    {
201
        return $this->tag;
202
    }
203
204
    /**
205
     * @return string
206
     */
207
    public function getEncodedSharedProtectedHeaders(): string
208
    {
209
        return $this->encodedSharedProtectedHeaders ?? '';
210
    }
211
212
    /**
213
     * @return array
214
     */
215
    public function getSharedProtectedHeaders(): array
216
    {
217
        return $this->sharedProtectedHeaders;
218
    }
219
220
    /**
221
     * @param string $key The key
222
     *
223
     * @return mixed|null Header value
224
     */
225
    public function getSharedProtectedHeader(string $key)
226
    {
227
        if ($this->hasSharedProtectedHeader($key)) {
228
            return $this->sharedProtectedHeaders[$key];
229
        }
230
        throw new \InvalidArgumentException(sprintf('The shared protected header "%s" does not exist.', $key));
231
    }
232
233
    /**
234
     * @param string $key The key
235
     *
236
     * @return bool
237
     */
238
    public function hasSharedProtectedHeader(string $key): bool
239
    {
240
        return array_key_exists($key, $this->sharedProtectedHeaders);
241
    }
242
243
    /**
244
     * @return array
245
     */
246
    public function getSharedHeaders(): array
247
    {
248
        return $this->sharedHeaders;
249
    }
250
251
    /**
252
     * @param string $key The key
253
     *
254
     * @return mixed|null Header value
255
     */
256
    public function getSharedHeader(string $key)
257
    {
258
        if ($this->hasSharedHeader($key)) {
259
            return $this->sharedHeaders[$key];
260
        }
261
        throw new \InvalidArgumentException(sprintf('The shared header "%s" does not exist.', $key));
262
    }
263
264
    /**
265
     * @param string $key The key
266
     *
267
     * @return bool
268
     */
269
    public function hasSharedHeader(string $key): bool
270
    {
271
        return array_key_exists($key, $this->sharedHeaders);
272
    }
273
274
    /**
275
     * @param int $id
276
     *
277
     * @return string
278
     */
279
    public function toCompactJSON(int $id): string
280
    {
281
        $recipient = $this->getRecipient($id);
282
283
        $this->checkHasNoAAD();
284
        $this->checkHasSharedProtectedHeaders();
285
        $this->checkRecipientHasNoHeaders($id);
286
287
        return sprintf(
288
            '%s.%s.%s.%s.%s',
289
            $this->getEncodedSharedProtectedHeaders(),
290
            Base64Url::encode(null === $recipient->getEncryptedKey() ? '' : $recipient->getEncryptedKey()),
291
            Base64Url::encode(null === $this->getIV() ? '' : $this->getIV()),
292
            Base64Url::encode($this->getCiphertext()),
293
            Base64Url::encode(null === $this->getTag() ? '' : $this->getTag())
294
        );
295
    }
296
297
    private function checkHasNoAAD()
298
    {
299
        Assertion::true(empty($this->getAAD()), 'This JWE has AAD and cannot be converted into Compact JSON.');
300
    }
301
302
    /**
303
     * @param int $id
304
     */
305
    private function checkRecipientHasNoHeaders(int $id)
306
    {
307
        Assertion::true(
308
            empty($this->getSharedHeaders()) && empty($this->getRecipient($id)->getHeaders()),
309
            'This JWE has shared headers or recipient headers and cannot be converted into Compact JSON.'
310
        );
311
    }
312
313
    private function checkHasSharedProtectedHeaders()
314
    {
315
        Assertion::notEmpty(
316
            $this->getSharedProtectedHeaders(),
317
            'This JWE does not have shared protected headers and cannot be converted into Compact JSON.'
318
        );
319
    }
320
321
    /**
322
     * @param int $id
323
     *
324
     * @return string
325
     */
326
    public function toFlattenedJSON(int $id): string
327
    {
328
        $recipient = $this->getRecipient($id);
329
330
        $json = $this->getJSONBase();
331
332
        if (!empty($recipient->getHeaders())) {
333
            $json['header'] = $recipient->getHeaders();
334
        }
335
        if (!empty($recipient->getEncryptedKey())) {
336
            $json['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
337
        }
338
339
        return json_encode($json);
340
    }
341
342
    /**
343
     * @return string
344
     */
345
    public function toJSON(): string
346
    {
347
        $json = $this->getJSONBase();
348
        $json['recipients'] = [];
349
350
        foreach ($this->getRecipients() as $recipient) {
351
            $temp = [];
352
            if (!empty($recipient->getHeaders())) {
353
                $temp['header'] = $recipient->getHeaders();
354
            }
355
            if (!empty($recipient->getEncryptedKey())) {
356
                $temp['encrypted_key'] = Base64Url::encode($recipient->getEncryptedKey());
357
            }
358
            $json['recipients'][] = $temp;
359
        }
360
361
        return json_encode($json);
362
    }
363
364
    /**
365
     * @return array
366
     */
367
    private function getJSONBase(): array
368
    {
369
        $json = [
370
            'ciphertext' => Base64Url::encode($this->getCiphertext()),
371
        ];
372
        if (null !== $this->getIV()) {
373
            $json['iv'] = Base64Url::encode($this->getIV());
374
        }
375
        if (null !== $this->getTag()) {
376
            $json['tag'] = Base64Url::encode($this->getTag());
377
        }
378
        if (null !== $this->getAAD()) {
379
            $json['aad'] = Base64Url::encode($this->getAAD());
380
        }
381
        if (!empty($this->getSharedProtectedHeaders())) {
382
            $json['protected'] = $this->getEncodedSharedProtectedHeaders();
383
        }
384
        if (!empty($this->getSharedHeaders())) {
385
            $json['unprotected'] = $this->getSharedHeaders();
386
        }
387
388
        return $json;
389
    }
390
}
391