Completed
Push — master ( 35e232...de1564 )
by Florent
02:34
created

RandomKey   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 108
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 14
c 1
b 0
f 1
lcom 1
cbo 3
dl 0
loc 108
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 14 3
B getValuesFromFileContent() 0 18 7
A generateKey() 0 16 2
createNewKey() 0 1 ?
A createKeyDefinition() 0 11 1
A addConfiguration() 0 13 1
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 SpomkyLabs\JoseBundle\DependencyInjection\Source\JWKSource;
13
14
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
15
use Symfony\Component\DependencyInjection\ContainerBuilder;
16
use Symfony\Component\DependencyInjection\Definition;
17
use Symfony\Component\DependencyInjection\Reference;
18
19
abstract class RandomKey implements JWKSourceInterface
20
{
21
    /**
22
     * {@inheritdoc}
23
     */
24
    public function create(ContainerBuilder $container, $id, array $config)
25
    {
26
        if (file_exists($config['storage_path'])) {
27
            $values = $this->getValuesFromFileContent($config['storage_path'], $config['ttl']);
28
            if (null === $values) {
29
                $values = $this->generateKey($config);
30
            }
31
        } else {
32
            $values = $this->generateKey($config);
33
        }
34
35
        $this->createKeyDefinition($container, $id, $values);
36
37
    }
38
39
    /**
40
     * @param string   $storage_path
41
     * @param int|null $ttl
42
     *
43
     * @return null|array
44
     */
45
    private function getValuesFromFileContent($storage_path, $ttl)
46
    {
47
        $content = file_get_contents($storage_path);
48
        if (false === $content) {
49
            return;
50
        }
51
52
        $data = json_decode($content, true);
53
        if (!is_array($data) || !array_key_exists('jwk', $data)) {
54
            return;
55
        }
56
57
        if (null !== $ttl && (!array_key_exists('expires_at', $data) || time() > $data['expires_at'])) {
58
            return;
59
        }
60
61
        return $data['jwk'];
62
    }
63
64
    /**
65
     * @param array $config
66
     *
67
     * @return array
68
     */
69
    private function generateKey(array $config)
70
    {
71
        $values = $this->createNewKey($config);
72
        $values['kid'] = hash('sha512', random_bytes(64));
73
74
        $to_file = [
75
            'jwk' => $values
76
        ];
77
        if (0 !== $config['ttl']) {
78
            $to_file['expires_at'] = time() + $config['ttl'];
79
        }
80
81
        file_put_contents($config['storage_path'], json_encode($to_file));
82
83
        return $values;
84
    }
85
86
    /**
87
     * @param array $config
88
     *
89
     * @return array
90
     */
91
    abstract protected function createNewKey(array $config);
92
93
    /**
94
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
95
     * @param string                                                  $id
96
     * @param array                                                   $values
97
     */
98
    private function createKeyDefinition(ContainerBuilder $container, $id, array $values)
99
    {
100
        $definition = new Definition('Jose\Object\JWK');
101
        $definition->setFactory([
102
            new Reference('jose.factory.jwk'),
103
            'createFromValues',
104
        ]);
105
        
106
        $definition->setArguments([$values]);
107
        $container->setDefinition($id, $definition);
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function addConfiguration(NodeDefinition $node)
114
    {
115
        $node
116
            ->children()
117
                ->scalarNode('storage_path')->isRequired()->end()
118
                ->integerNode('ttl')->defaultValue(0)->min(0)->end()
119
                ->arrayNode('additional_values')
120
                    ->defaultValue([])
121
                    ->useAttributeAsKey('key')
122
                    ->prototype('variable')->end()
123
                ->end()
124
            ->end();
125
    }
126
}
127