Failed Conditions
Push — v7 ( 530848...f7cc18 )
by Florent
03:53 queued 01:57
created

JWSParser::parse()   D

Complexity

Conditions 9
Paths 68

Size

Total Lines 45
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 4.909
c 0
b 0
f 0
cc 9
eloc 32
nc 68
nop 1
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;
15
16
use Base64Url\Base64Url;
17
18
/**
19
 * Class able to parse JWS.
20
 */
21
final class JWSParser
22
{
23
    /**
24
     * Load data and return a JWS object.
25
     * Compact, Flattened or complete serialization formats are supported.
26
     *
27
     * @param string $input A string that represents a JWS
28
     *
29
     * @return JWS
30
     */
31
    public static function parse(string $input): JWS
32
    {
33
        $json = JWSConverter::convert($input);
34
        $isPayloadEncoded = null;
35
36
        if (array_key_exists('payload', $json)) {
37
            $rawPayload = $json['payload'];
38
        } else {
39
            $rawPayload = null;
40
        }
41
        $signatures = [];
42
        foreach ($json['signatures'] as $signature) {
43
            $encodedProtectedHeaders = self::getProtectedHeaders($signature);
44
            $protectedHeaders = null !== $encodedProtectedHeaders ? json_decode(Base64Url::decode($encodedProtectedHeaders), true) : [];
45
            $signatures[] = [
46
                'signature' => Base64Url::decode($signature['signature']),
47
                'protected' => $protectedHeaders,
48
                'encoded_protected' => $encodedProtectedHeaders,
49
                'header' => self::getHeaders($signature),
50
            ];
51
            if (null === $isPayloadEncoded) {
52
                $isPayloadEncoded = self::isPayloadEncoded($protectedHeaders);
53
            }
54
            if (self::isPayloadEncoded($protectedHeaders) !== $isPayloadEncoded) {
55
                throw new \InvalidArgumentException('Foreign payload encoding detected.');
56
            }
57
        }
58
59
        if (null === $rawPayload) {
60
            $payload = null;
61
        } else {
62
            $payload = false === $isPayloadEncoded ? $rawPayload : Base64Url::decode($rawPayload);
63
        }
64
        $jws = JWS::create($payload, $rawPayload);
65
        foreach ($signatures as $signature) {
66
            $jws = $jws->addSignature(
67
                $signature['signature'],
68
                $signature['protected'],
69
                $signature['encoded_protected'],
70
                $signature['header']
71
            );
72
        }
73
74
        return $jws;
75
    }
76
77
    /**
78
     * @param array $data
79
     *
80
     * @return string|null
81
     */
82
    private static function getProtectedHeaders(array $data): ?string
83
    {
84
        if (array_key_exists('protected', $data)) {
85
            return $data['protected'];
86
        }
87
88
        return null;
89
    }
90
91
    /**
92
     * @param array $data
93
     *
94
     * @return array
95
     */
96
    private static function getHeaders(array $data): array
97
    {
98
        if (array_key_exists('header', $data)) {
99
            return $data['header'];
100
        }
101
102
        return [];
103
    }
104
105
    /**
106
     * @param array $protectedHeaders
107
     *
108
     * @return bool
109
     */
110
    private static function isPayloadEncoded(array $protectedHeaders): bool
111
    {
112
        return !array_key_exists('b64', $protectedHeaders) || true === $protectedHeaders['b64'];
113
    }
114
}
115