Completed
Push — master ( 34f908...4c48cd )
by Florent
02:40
created

CollectedClientData::optionalData()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 1
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 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 U2FAuthentication\Fido2;
15
16
use Base64Url\Base64Url;
17
18
class CollectedClientData
19
{
20
    private $rawData;
21
    private $data;
22
    private $type;
23
    private $challenge;
24
    private $origin;
25
    private $tokenBinding;
26
27
    public function __construct(string $rawData, array $data)
28
    {
29
        $validators = $this->dataValidators();
30
        foreach ($validators as $parameter => $validator) {
31
            $this->$parameter = $validator($data);
32
        }
33
        $this->rawData = $rawData;
34
        $this->data = $data;
35
    }
36
37
    public static function createFormJson(string $data): self
38
    {
39
        $rawData = Base64Url::decode($data);
40
        $json = \Safe\json_decode($rawData, true);
41
        if (!\is_array($json)) {
42
            throw new \InvalidArgumentException('Invalid collected client data');
43
        }
44
45
        return new self($rawData, $json);
46
    }
47
48
    public function getType(): string
49
    {
50
        return $this->type;
51
    }
52
53
    public function getChallenge(): string
54
    {
55
        return $this->challenge;
56
    }
57
58
    public function getOrigin(): string
59
    {
60
        return $this->origin;
61
    }
62
63
    public function getTokenBinding(): ?TokenBinding
64
    {
65
        return $this->tokenBinding ? TokenBinding::createFormJson($this->tokenBinding) : null;
66
    }
67
68
    public function getRawData(): string
69
    {
70
        return $this->rawData;
71
    }
72
73
    /**
74
     * @return string[]
75
     */
76
    public function all(): array
77
    {
78
        return array_keys($this->data);
79
    }
80
81
    public function has(string $key): bool
82
    {
83
        return array_key_exists($key, $this->data);
84
    }
85
86
    public function get(string $key)
87
    {
88
        if (!$this->has($key)) {
89
            throw new \InvalidArgumentException(\Safe\sprintf('The key "%s" is missing', $key));
90
        }
91
92
        return $this->data[$key];
93
    }
94
95
    /**
96
     * @return callable[]
97
     */
98
    private function dataValidators(): array
99
    {
100
        return [
101
            'type' => $this->requiredData('type'),
102
            'challenge' => $this->requiredData('challenge', true),
103
            'origin' => $this->requiredData('origin'),
104
            'tokenBinding' => $this->optionalData('tokenBinding'),
105
        ];
106
    }
107
108
    private function requiredData($key, bool $isB64 = false): callable
109
    {
110
        return function ($json) use ($key, $isB64) {
111
            if (!array_key_exists($key, $json)) {
112
                throw new \InvalidArgumentException(\Safe\sprintf('The key "%s" is missing', $key));
113
            }
114
115
            return $isB64 ? Base64Url::decode($json[$key]) : $json[$key];
116
        };
117
    }
118
119
    private function optionalData($key): callable
120
    {
121
        return function ($json) use ($key) {
122
            if (!array_key_exists($key, $json)) {
123
                return;
124
            }
125
126
            return $json[$key];
127
        };
128
    }
129
}
130