Completed
Push — master ( 1a59c2...c73113 )
by Florent
02:55
created

Loader   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 16
Bugs 6 Features 1
Metric Value
wmc 36
c 16
b 6
f 1
lcom 1
cbo 6
dl 0
loc 246
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 10 3
B convert() 0 15 7
B fromFlattenedSerializationRecipientToSerialization() 0 20 5
A fromFlattenedSerializationSignatureToSerialization() 0 19 4
A fromCompactSerializationToSerialization() 0 12 3
A fromCompactSerializationRecipientToSerialization() 0 18 4
A fromCompactSerializationSignatureToSerialization() 0 14 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\Factory\VerifierFactory;
16
use Jose\Object\JWKInterface;
17
use Jose\Object\JWKSet;
18
use Jose\Object\JWKSetInterface;
19
use Jose\Object\JWSInterface;
20
use Jose\Object\JWEInterface;
21
use Jose\Util\JWELoader;
22
use Jose\Util\JWSLoader;
23
use Psr\Log\LoggerInterface;
24
25
/**
26
 * Class able to load JWS or JWE.
27
 * JWS object can also be verified.
28
 */
29
final class Loader implements LoaderInterface
30
{
31
    /**
32
     * {@inheritdoc}
33
     */
34
    public static function loadAndDecryptUsingKey($input, JWKInterface $jwk, array $allowed_algorithms, LoggerInterface $logger = null)
35
    {
36
        $jwk_set = new JWKSet();
37
        $jwk_set = $jwk_set->addKey($jwk);
38
39
        return self::loadAndDecrypt($input, $jwk_set, $allowed_algorithms, $logger);
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public static function loadAndDecryptUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_algorithms, LoggerInterface $logger = null)
46
    {
47
        return self::loadAndDecrypt($input, $jwk_set, $allowed_algorithms, $logger);
48
    }
49
    
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public static function loadAndVerifySignatureUsingKey($input, JWKInterface $jwk, array $allowed_algorithms, LoggerInterface $logger = null)
54
    {
55
        $jwk_set = new JWKSet();
56
        $jwk_set = $jwk_set->addKey($jwk);
57
58
        return self::loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $logger);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public static function loadAndVerifySignatureUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_algorithms, LoggerInterface $logger = null)
65
    {
66
        return self::loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $logger);
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public static function loadAndVerifySignatureUsingKeyAndDetachedPayload($input, JWKInterface $jwk, array $allowed_algorithms, $detached_payload, LoggerInterface $logger = null)
73
    {
74
        $jwk_set = new JWKSet();
75
        $jwk_set = $jwk_set->addKey($jwk);
76
77
        return self::loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $logger);
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public static function loadAndVerifySignatureUsingKeySetAndDetachedPayload($input, JWKSetInterface $jwk_set, array $allowed_algorithms, $detached_payload, LoggerInterface $logger = null)
84
    {
85
        return self::loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $logger);
86
    }
87
88
    /**
89
     * @param string                        $input
90
     * @param \Jose\Object\JWKSetInterface  $jwk_set
91
     * @param array                         $allowed_algorithms
92
     * @param \Psr\Log\LoggerInterface|null $logger
93
     *
94
     * @return \Jose\Object\JWEInterface
95
     */
96
    private static function loadAndDecrypt($input, JWKSetInterface $jwk_set, array $allowed_algorithms, LoggerInterface $logger = null)
97
    {
98
        $jwt = self::load($input);
0 ignored issues
show
Bug Compatibility introduced by
The expression self::load($input); of type Jose\Object\JWSInterface|Jose\Object\JWEInterface adds the type Jose\Object\JWSInterface to the return on line 104 which is incompatible with the return type documented by Jose\Loader::loadAndDecrypt of type Jose\Object\JWEInterface.
Loading history...
99
        Assertion::isInstanceOf($jwt, JWEInterface::class, 'The input is not a valid JWE');
100
        $decrypted = DecrypterFactory::createDecrypter($allowed_algorithms, ['DEF', 'ZLIB', 'GZ'], $logger);
101
102
        $decrypted->decryptUsingKeySet($jwt, $jwk_set);
103
104
        return $jwt;
105
    }
106
107
    /**
108
     * @param string                        $input
109
     * @param \Jose\Object\JWKSetInterface  $jwk_set
110
     * @param array                         $allowed_algorithms
111
     * @param string|null                   $detached_payload
112
     * @param \Psr\Log\LoggerInterface|null $logger
113
     *
114
     * @return \Jose\Object\JWSInterface
115
     */
116
    private static function loadAndVerifySignature($input, JWKSetInterface $jwk_set, array $allowed_algorithms, $detached_payload = null, LoggerInterface $logger = null)
117
    {
118
        $jwt = self::load($input);
0 ignored issues
show
Bug Compatibility introduced by
The expression self::load($input); of type Jose\Object\JWSInterface|Jose\Object\JWEInterface adds the type Jose\Object\JWEInterface to the return on line 124 which is incompatible with the return type documented by Jose\Loader::loadAndVerifySignature of type Jose\Object\JWSInterface.
Loading history...
119
        Assertion::isInstanceOf($jwt, JWSInterface::class, 'The input is not a valid JWS');
120
        $verifier = VerifierFactory::createVerifier($allowed_algorithms, $logger);
121
122
        $verifier->verifyWithKeySet($jwt, $jwk_set, $detached_payload);
0 ignored issues
show
Bug introduced by
It seems like $jwt defined by self::load($input) on line 118 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...
123
124
        return $jwt;
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public static function load($input)
131
    {
132
        $json = self::convert($input);
133
        if (array_key_exists('signatures', $json)) {
134
            return JWSLoader::loadSerializedJsonJWS($json);
135
        }
136
        if (array_key_exists('recipients', $json)) {
137
            return JWELoader::loadSerializedJsonJWE($json);
138
        }
139
    }
140
141
    /**
142
     * @param string $input
143
     *
144
     * @return array
145
     */
146
    private static function convert($input)
147
    {
148
        if (is_array($data = json_decode($input, true))) {
149
            if (array_key_exists('signatures', $data) || array_key_exists('recipients', $data)) {
150
                return $data;
151
            } elseif (array_key_exists('signature', $data)) {
152
                return self::fromFlattenedSerializationSignatureToSerialization($data);
153
            } elseif (array_key_exists('ciphertext', $data)) {
154
                return self::fromFlattenedSerializationRecipientToSerialization($data);
155
            }
156
        } elseif (is_string($input)) {
157
            return self::fromCompactSerializationToSerialization($input);
158
        }
159
        throw new \InvalidArgumentException('Unsupported input');
160
    }
161
162
    /**
163
     * @param $input
164
     *
165
     * @return array
166
     */
167
    private static function fromFlattenedSerializationRecipientToSerialization($input)
168
    {
169
        $recipient = [];
170
        foreach (['header', 'encrypted_key'] as $key) {
171
            if (array_key_exists($key, $input)) {
172
                $recipient[$key] = $input[$key];
173
            }
174
        }
175
        $recipients = [
176
            'ciphertext' => $input['ciphertext'],
177
            'recipients' => [$recipient],
178
        ];
179
        foreach (['ciphertext', 'protected', 'unprotected', 'iv', 'aad', 'tag'] as $key) {
180
            if (array_key_exists($key, $input)) {
181
                $recipients[$key] = $input[$key];
182
            }
183
        }
184
185
        return $recipients;
186
    }
187
188
    /**
189
     * @param $input
190
     *
191
     * @return array
192
     */
193
    private static function fromFlattenedSerializationSignatureToSerialization($input)
194
    {
195
        $signature = [
196
            'signature' => $input['signature'],
197
        ];
198
        foreach (['protected', 'header'] as $key) {
199
            if (array_key_exists($key, $input)) {
200
                $signature[$key] = $input[$key];
201
            }
202
        }
203
204
        $temp = [];
205
        if (!empty($input['payload'])) {
206
            $temp['payload'] = $input['payload'];
207
        }
208
        $temp['signatures'] = [$signature];
209
210
        return $temp;
211
    }
212
213
    /**
214
     * @param string $input
215
     *
216
     * @return array
217
     */
218
    private static function fromCompactSerializationToSerialization($input)
219
    {
220
        $parts = explode('.', $input);
221
        switch (count($parts)) {
222
            case 3:
223
                return self::fromCompactSerializationSignatureToSerialization($parts);
224
            case 5:
225
                return self::fromCompactSerializationRecipientToSerialization($parts);
226
            default:
227
                throw new \InvalidArgumentException('Unsupported input');
228
        }
229
    }
230
231
    /**
232
     * @param array $parts
233
     *
234
     * @return array
235
     */
236
    private static function fromCompactSerializationRecipientToSerialization(array $parts)
237
    {
238
        $recipient = [];
239
        if (!empty($parts[1])) {
240
            $recipient['encrypted_key'] = $parts[1];
241
        }
242
243
        $recipients = [
244
            'recipients' => [$recipient],
245
        ];
246
        foreach ([3 => 'ciphertext', 0 => 'protected', 2 => 'iv', 4 => 'tag'] as $part => $key) {
247
            if (!empty($parts[$part])) {
248
                $recipients[$key] = $parts[$part];
249
            }
250
        }
251
252
        return $recipients;
253
    }
254
255
    /**
256
     * @param array $parts
257
     *
258
     * @return array
259
     */
260
    private static function fromCompactSerializationSignatureToSerialization(array $parts)
261
    {
262
        $temp = [];
263
264
        if (!empty($parts[1])) {
265
            $temp['payload'] = $parts[1];
266
        }
267
        $temp['signatures'] = [[
268
            'protected' => $parts[0],
269
            'signature' => $parts[2],
270
        ]];
271
272
        return $temp;
273
    }
274
}
275