Failed Conditions
Push — v7 ( ebb162...ca0cc9 )
by Florent
01:56
created

JSONGeneralSerializer::unserialize()   F

Complexity

Conditions 15
Paths 239

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 47
rs 3.9217
c 0
b 0
f 0
cc 15
eloc 33
nc 239
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Signature\Serializer;
15
16
use Base64Url\Base64Url;
17
use Jose\Component\Signature\JWS;
18
19
/**
20
 * Class JSONGeneralSerializer.
21
 */
22
final class JSONGeneralSerializer extends AbstractSerializer
23
{
24
    public const NAME = 'jws_json_general';
25
26
    /**
27
     * {@inheritdoc}
28
     */
29
    public function name(): string
30
    {
31
        return self::NAME;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function serialize(JWS $jws, ?int $signatureIndex = null): string
38
    {
39
        if (0 === $jws->countSignatures()) {
40
            throw new \LogicException('No signature.');
41
        }
42
43
        $data = [];
44
        $this->checkPayloadEncoding($jws);
45
46
        if (false === $jws->isPayloadDetached()) {
47
            $data['payload'] = $jws->getEncodedPayload();
48
        }
49
50
        $data['signatures'] = [];
51
        foreach ($jws->getSignatures() as $signature) {
52
            $tmp = ['signature' => Base64Url::encode($signature->getSignature())];
53
            $values = [
54
                'protected' => $signature->getEncodedProtectedHeaders(),
55
                'header' => $signature->getHeaders(),
56
            ];
57
58
            foreach ($values as $key => $value) {
59
                if (!empty($value)) {
60
                    $tmp[$key] = $value;
61
                }
62
            }
63
            $data['signatures'][] = $tmp;
64
        }
65
66
        return json_encode($data);
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function unserialize(string $input): JWS
73
    {
74
        $data = json_decode($input, true);
75
        if (!is_array($data) || !array_key_exists('signatures', $data)) {
76
            throw new \InvalidArgumentException('Unsupported input.');
77
        }
78
79
        $isPayloadEncoded = null;
80
        $rawPayload = array_key_exists('payload', $data) ? $data['payload'] : null;
81
        $signatures = [];
82
        foreach ($data['signatures'] as $signature) {
83
            if (!is_array($signature) || !array_key_exists('signature', $signature)) {
84
                throw new \InvalidArgumentException('Unsupported input.');
85
            }
86
            $encodedProtectedHeaders = array_key_exists('protected', $signature) ? $signature['protected'] : null;
87
            $protectedHeaders = null !== $encodedProtectedHeaders ? json_decode(Base64Url::decode($encodedProtectedHeaders), true) : [];
88
            $signatures[] = [
89
                'signature' => Base64Url::decode($signature['signature']),
90
                'protected' => $protectedHeaders,
91
                'encoded_protected' => $encodedProtectedHeaders,
92
                'header' => array_key_exists('header', $signature) ? $signature['header'] : [],
93
            ];
94
            if (null === $isPayloadEncoded) {
95
                $isPayloadEncoded = self::isPayloadEncoded($protectedHeaders);
96
            }
97
            if ($this->isPayloadEncoded($protectedHeaders) !== $isPayloadEncoded) {
98
                throw new \InvalidArgumentException('Foreign payload encoding detected.');
99
            }
100
        }
101
102
        if (null === $rawPayload) {
103
            $payload = null;
104
        } else {
105
            $payload = false === $isPayloadEncoded ? $rawPayload : Base64Url::decode($rawPayload);
106
        }
107
        $jws = JWS::create($payload, $rawPayload);
108
        foreach ($signatures as $signature) {
109
            $jws = $jws->addSignature(
110
                $signature['signature'],
111
                $signature['protected'],
112
                $signature['encoded_protected'],
113
                $signature['header']
114
            );
115
        }
116
117
        return $jws;
118
    }
119
120
    /**
121
     * @param JWS $jws
122
     */
123
    private function checkPayloadEncoding(JWS $jws)
124
    {
125
        if ($jws->isPayloadDetached()) {
126
            return;
127
        }
128
        $is_encoded = null;
129
        foreach ($jws->getSignatures() as $signature) {
130
            if (null === $is_encoded) {
131
                $is_encoded = $this->isPayloadEncoded($signature->getProtectedHeaders());
132
            }
133
            if (false === $jws->isPayloadDetached()) {
134
                if ($is_encoded !== $this->isPayloadEncoded($signature->getProtectedHeaders())) {
135
                    throw new \LogicException('Foreign payload encoding detected.');
136
                }
137
            }
138
        }
139
    }
140
}
141