Failed Conditions
Push — JWKSet ( 3580c0 )
by Florent
04:07
created

StorableJWKSet::key()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\Object;
13
14
use Assert\Assertion;
15
use Base64Url\Base64Url;
16
use Jose\Factory\JWKFactory;
17
18
/**
19
 * Class StorableJWKSet.
20
 */
21
class StorableJWKSet implements StorableJWKSetInterface
22
{
23
    /**
24
     * @var \Jose\Object\JWKSetInterface
25
     */
26
    protected $jwkset;
27
28
    /**
29
     * @var string
30
     */
31
    protected $filename;
32
33
    /**
34
     * @var array
35
     */
36
    protected $parameters;
37
38
    /**
39
     * @var array
40
     */
41
    protected $nb_keys;
42
43
    /**
44
     * StorableJWKSet constructor.
45
     *
46
     * @param string $filename
47
     * @param array  $parameters
48
     * @param int    $nb_keys
49
     */
50
    public function __construct($filename, array $parameters, $nb_keys)
51
    {
52
        Assertion::directory(dirname($filename), 'The selected directory does not exist.');
53
        Assertion::writeable(dirname($filename), 'The selected directory is not writable.');
54
        Assertion::integer($nb_keys, 'The key set must contain at least one key.');
55
        Assertion::greaterThan($nb_keys, 0, 'The key set must contain at least one key.');
56
        $this->filename = $filename;
57
        $this->parameters = $parameters;
58
        $this->nb_keys = $nb_keys;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nb_keys of type integer is incompatible with the declared type array of property $nb_keys.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function current()
65
    {
66
        return $this->getJWKSet()->current();
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function next()
73
    {
74
        $this->getJWKSet()->next();
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function key()
81
    {
82
        return $this->getJWKSet()->key();
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function valid()
89
    {
90
        return $this->getJWKSet()->valid();
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function rewind()
97
    {
98
        $this->getJWKSet()->rewind();
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function offsetExists($offset)
105
    {
106
        return $this->getJWKSet()->offsetExists($offset);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function offsetGet($offset)
113
    {
114
        return $this->getJWKSet()->offsetGet($offset);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function offsetSet($offset, $value)
121
    {
122
        return $this->getJWKSet()->offsetSet($offset, $value);
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function offsetUnset($offset)
129
    {
130
        return $this->getJWKSet()->offsetUnset($offset);
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function getKey($index)
137
    {
138
        return $this->getJWKSet()->getKey($index);
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function hasKey($index)
145
    {
146
        return $this->getJWKSet()->hasKey($index);
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function getKeys()
153
    {
154
        return $this->getJWKSet()->getKeys();
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function addKey(JWKInterface $key)
161
    {
162
        return $this->getJWKSet()->addKey($key);
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function removeKey($index)
169
    {
170
        return $this->getJWKSet()->removeKey($index);
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function countKeys()
177
    {
178
        return $this->getJWKSet()->countKeys();
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function selectKey($type, $algorithm = null, array $restrictions = [])
185
    {
186
        return $this->getJWKSet()->selectKey($type, $algorithm, $restrictions);
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192
    public function count()
193
    {
194
        return $this->getJWKSet()->count();
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function jsonSerialize()
201
    {
202
        return $this->getJWKSet()->jsonSerialize();
203
    }
204
205
    /**
206
     * @return string
207
     */
208
    protected function getFilename()
209
    {
210
        return $this->filename;
211
    }
212
213
    /**
214
     * @return \Jose\Object\JWKSetInterface
215
     */
216
    protected function getJWKSet()
217
    {
218
        $this->loadJWKSetIfNeeded();
219
220
        return $this->jwkset;
221
    }
222
223
    /**
224
     * This function loads or creates it the file if needed
225
     */
226
    protected function loadJWKSetIfNeeded()
227
    {
228
        $content = $this->getFileContent();
229
        if (null === $content) {
230
            $this->createJWKSet();
231
        } else {
232
            $this->jwkset = new JWKSet($content);
233
        }
234
    }
235
236
    /**
237
     * This function returns the content of the file only if it is an array
238
     *
239
     * @return null|array
240
     */
241
    protected function getFileContent()
242
    {
243
        if (!file_exists($this->getFilename())) {
244
            return;
245
        }
246
        $content = file_get_contents($this->getFilename());
247
        if (false === $content) {
248
            return;
249
        }
250
        $content = json_decode($content, true);
251
        if (!is_array($content)) {
252
            return;
253
        }
254
255
        return $content;
256
    }
257
258
    /**
259
     * This method creates the JWKSet and populate it with keys
260
     */
261
    protected function createJWKSet()
262
    {
263
        $this->jwkset = new JWKSet();
264
        for ($i = 0; $i < $this->nb_keys; $i++) {
265
            $key = $this->createJWK();
266
            $this->jwkset->addKey($key);
0 ignored issues
show
Bug introduced by
It seems like $key defined by $this->createJWK() on line 265 can also be of type object<Jose\Object\JWKSet>; however, Jose\Object\JWKSet::addKey() does only seem to accept object<Jose\Object\JWKInterface>, 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...
267
        }
268
269
        $this->save();
270
    }
271
272
    /**
273
     * @return \Jose\Object\JWKInterface
274
     */
275
    protected function createJWK()
276
    {
277
        $data = JWKFactory::createKey($this->parameters)->getAll();
278
        $data['kid'] = Base64Url::encode(random_bytes(64));
279
280
        return JWKFactory::createFromValues($data);
281
    }
282
283
    /**
284
     * This method saves the JWKSet in the file.
285
     */
286
    protected function save()
287
    {
288
        @unlink($this->getFilename());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
289
        file_put_contents($this->getFilename(), json_encode($this->jwkset));
290
    }
291
}
292