JSONGeneralSerializer::unserialize()   F
last analyzed

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