Completed
Push — master ( 65e224...f25ceb )
by Florent
03:47
created

Loader   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 13
Bugs 2 Features 1
Metric Value
wmc 36
c 13
b 2
f 1
lcom 1
cbo 6
dl 0
loc 259
rs 8.8

15 Methods

Rating   Name   Duplication   Size   Complexity  
A loadAndDecryptUsingKey() 0 7 1
A loadAndDecryptUsingKeySet() 0 4 1
A loadAndVerifySignatureUsingKey() 0 7 1
A loadAndVerifySignatureUsingKeySet() 0 4 1
A loadAndVerifySignatureUsingKeyAndDetachedPayload() 0 7 1
A loadAndVerifySignatureUsingKeySetAndDetachedPayload() 0 4 1
A loadAndDecrypt() 0 10 1
A loadAndVerifySignature() 0 10 1
A load() 0 12 3
B convert() 0 19 7
B fromFlattenedSerializationRecipientToSerialization() 0 21 5
A fromFlattenedSerializationSignatureToSerialization() 0 20 4
A fromCompactSerializationToSerialization() 0 14 3
A fromCompactSerializationRecipientToSerialization() 0 19 4
A fromCompactSerializationSignatureToSerialization() 0 15 2
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;
13
14
use Assert\Assertion;
15
use Jose\Object\JWEInterface;
16
use Jose\Object\JWKInterface;
17
use Jose\Object\JWKSet;
18
use Jose\Object\JWKSetInterface;
19
use Jose\Object\JWSInterface;
20
use Jose\Util\JWELoader;
21
use Jose\Util\JWSLoader;
22
23
/**
24
 * Class able to load JWS or JWE.
25
 * JWS object can also be verified.
26
 */
27
final class Loader implements LoaderInterface
28
{
29
    /**
30
     * {@inheritdoc}
31
     */
32
    public function loadAndDecryptUsingKey($input, JWKInterface $jwk, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, &$recipient_index = null)
33
    {
34
        $jwk_set = new JWKSet();
35
        $jwk_set->addKey($jwk);
36
37
        return $this->loadAndDecrypt($input, $jwk_set, $allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, $recipient_index);
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function loadAndDecryptUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, &$recipient_index = null)
44
    {
45
        return $this->loadAndDecrypt($input, $jwk_set, $allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, $recipient_index);
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function loadAndVerifySignatureUsingKey($input, JWKInterface $jwk, array $allowed_algorithms, &$signature_index = null)
52
    {
53
        $jwk_set = new JWKSet();
54
        $jwk_set->addKey($jwk);
55
56
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $signature_index);
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function loadAndVerifySignatureUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_algorithms, &$signature_index = null)
63
    {
64
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $signature_index);
65
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function loadAndVerifySignatureUsingKeyAndDetachedPayload($input, JWKInterface $jwk, array $allowed_algorithms, $detached_payload, &$signature_index = null)
71
    {
72
        $jwk_set = new JWKSet();
73
        $jwk_set->addKey($jwk);
74
75
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $signature_index);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function loadAndVerifySignatureUsingKeySetAndDetachedPayload($input, JWKSetInterface $jwk_set, array $allowed_algorithms, $detached_payload, &$signature_index = null)
82
    {
83
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $signature_index);
84
    }
85
86
    /**
87
     * @param string                        $input
88
     * @param \Jose\Object\JWKSetInterface  $jwk_set
89
     * @param array                         $allowed_key_encryption_algorithms
90
     * @param array                         $allowed_content_encryption_algorithms
91
     * @param null|int                      $recipient_index
92
     *
93
     * @return \Jose\Object\JWEInterface
94
     */
95
    private function loadAndDecrypt($input, JWKSetInterface $jwk_set, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, &$recipient_index = null)
96
    {
97
        $jwt = $this->load($input);
98
        Assertion::isInstanceOf($jwt, JWEInterface::class, 'The input is not a valid JWE');
99
        $decrypted = Decrypter::createDecrypter($allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, ['DEF', 'ZLIB', 'GZ']);
100
101
        $decrypted->decryptUsingKeySet($jwt, $jwk_set, $recipient_index);
0 ignored issues
show
Bug introduced by
It seems like $jwt defined by $this->load($input) on line 97 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
102
103
        return $jwt;
104
    }
105
106
    /**
107
     * @param string                        $input
108
     * @param \Jose\Object\JWKSetInterface  $jwk_set
109
     * @param array                         $allowed_algorithms
110
     * @param string|null                   $detached_payload
111
     * @param null|int                      $signature_index
112
     *
113
     * @return \Jose\Object\JWSInterface
114
     */
115
    private function loadAndVerifySignature($input, JWKSetInterface $jwk_set, array $allowed_algorithms, $detached_payload = null, &$signature_index = null)
116
    {
117
        $jwt = $this->load($input);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->load($input); of type Jose\Object\JWSInterface|Jose\Object\JWEInterface adds the type Jose\Object\JWEInterface to the return on line 123 which is incompatible with the return type documented by Jose\Loader::loadAndVerifySignature of type Jose\Object\JWSInterface.
Loading history...
118
        Assertion::isInstanceOf($jwt, JWSInterface::class, 'The input is not a valid JWS.');
119
        $verifier = Verifier::createVerifier($allowed_algorithms);
120
121
        $verifier->verifyWithKeySet($jwt, $jwk_set, $detached_payload, $signature_index);
0 ignored issues
show
Bug introduced by
It seems like $jwt defined by $this->load($input) on line 117 can also be of type object<Jose\Object\JWEInterface>; however, Jose\Verifier::verifyWithKeySet() does only seem to accept object<Jose\Object\JWSInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
122
123
        return $jwt;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function load($input)
130
    {
131
        $json = $this->convert($input);
132
        if (array_key_exists('signatures', $json)) {
133
134
            return JWSLoader::loadSerializedJsonJWS($json);
135
        }
136
        if (array_key_exists('recipients', $json)) {
137
138
            return JWELoader::loadSerializedJsonJWE($json);
139
        }
140
    }
141
142
    /**
143
     * @param string $input
144
     *
145
     * @return array
146
     */
147
    private function convert($input)
148
    {
149
        if (is_array($data = json_decode($input, true))) {
150
            if (array_key_exists('signatures', $data) || array_key_exists('recipients', $data)) {
151
152
                return $data;
153
            } elseif (array_key_exists('signature', $data)) {
154
155
                return $this->fromFlattenedSerializationSignatureToSerialization($data);
156
            } elseif (array_key_exists('ciphertext', $data)) {
157
158
                return $this->fromFlattenedSerializationRecipientToSerialization($data);
159
            }
160
        } elseif (is_string($input)) {
161
162
            return $this->fromCompactSerializationToSerialization($input);
163
        }
164
        throw new \InvalidArgumentException('Unsupported input');
165
    }
166
167
    /**
168
     * @param $input
169
     *
170
     * @return array
171
     */
172
    private function fromFlattenedSerializationRecipientToSerialization($input)
173
    {
174
        $recipient = [];
175
        foreach (['header', 'encrypted_key'] as $key) {
176
            if (array_key_exists($key, $input)) {
177
                $recipient[$key] = $input[$key];
178
            }
179
        }
180
        $recipients = [
181
            'ciphertext' => $input['ciphertext'],
182
            'recipients' => [$recipient],
183
        ];
184
        foreach (['protected', 'unprotected', 'iv', 'aad', 'tag'] as $key) {
185
            if (array_key_exists($key, $input)) {
186
                $recipients[$key] = $input[$key];
187
            }
188
        }
189
190
191
        return $recipients;
192
    }
193
194
    /**
195
     * @param $input
196
     *
197
     * @return array
198
     */
199
    private function fromFlattenedSerializationSignatureToSerialization($input)
200
    {
201
        $signature = [
202
            'signature' => $input['signature'],
203
        ];
204
        foreach (['protected', 'header'] as $key) {
205
            if (array_key_exists($key, $input)) {
206
                $signature[$key] = $input[$key];
207
            }
208
        }
209
210
        $temp = [];
211
        if (!empty($input['payload'])) {
212
            $temp['payload'] = $input['payload'];
213
        }
214
        $temp['signatures'] = [$signature];
215
216
217
        return $temp;
218
    }
219
220
    /**
221
     * @param string $input
222
     *
223
     * @return array
224
     */
225
    private function fromCompactSerializationToSerialization($input)
226
    {
227
        $parts = explode('.', $input);
228
        switch (count($parts)) {
229
            case 3:
230
231
                return $this->fromCompactSerializationSignatureToSerialization($parts);
232
            case 5:
233
234
                return $this->fromCompactSerializationRecipientToSerialization($parts);
235
            default:
236
                throw new \InvalidArgumentException('Unsupported input');
237
        }
238
    }
239
240
    /**
241
     * @param array $parts
242
     *
243
     * @return array
244
     */
245
    private function fromCompactSerializationRecipientToSerialization(array $parts)
246
    {
247
        $recipient = [];
248
        if (!empty($parts[1])) {
249
            $recipient['encrypted_key'] = $parts[1];
250
        }
251
252
        $recipients = [
253
            'recipients' => [$recipient],
254
        ];
255
        foreach ([0 => 'protected', 2 => 'iv', 3 => 'ciphertext', 4 => 'tag'] as $part => $key) {
256
            if (!empty($parts[$part])) {
257
                $recipients[$key] = $parts[$part];
258
            }
259
        }
260
261
262
        return $recipients;
263
    }
264
265
    /**
266
     * @param array $parts
267
     *
268
     * @return array
269
     */
270
    private function fromCompactSerializationSignatureToSerialization(array $parts)
271
    {
272
        $temp = [];
273
274
        if (!empty($parts[1])) {
275
            $temp['payload'] = $parts[1];
276
        }
277
        $temp['signatures'] = [[
278
            'protected' => $parts[0],
279
            'signature' => $parts[2],
280
        ]];
281
282
283
        return $temp;
284
    }
285
}
286