Passed
Pull Request — master (#1215)
by
unknown
61:51 queued 26:42
created

CryptKey::__construct()   B

Complexity

Conditions 11
Paths 30

Size

Total Lines 38
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 12.1286

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 11
eloc 24
c 2
b 0
f 0
nc 30
nop 3
dl 0
loc 38
ccs 15
cts 19
cp 0.7895
crap 12.1286
rs 7.3166

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
 * Cryptography key holder.
4
 *
5
 * @author      Julián Gutiérrez <[email protected]>
6
 * @copyright   Copyright (c) Alex Bilbie
7
 * @license     http://mit-license.org/
8
 *
9
 * @link        https://github.com/thephpleague/oauth2-server
10
 */
11
12
namespace League\OAuth2\Server;
13
14
use LogicException;
15
use phpseclib3\Crypt\EC;
16
use phpseclib3\Crypt\RSA;
17
use phpseclib3\Exception\NoKeyLoadedException;
18
use RuntimeException;
19
20
class CryptKey
21
{
22
    private const FILE_PREFIX = 'file://';
23
24
    /**
25
     * @var string
26
     */
27
    protected $keyPath;
28
29
    /**
30
     * @var null|string
31
     */
32
    protected $passPhrase;
33
34
    /**
35
     * @param string      $keyPath
36
     * @param null|string $passPhrase
37 56
     * @param bool        $keyPermissionsCheck
38
     */
39 56
    public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true)
40 1
    {
41 55
        $this->keyPath = $keyPath;
42 1
        $this->passPhrase = $passPhrase;
43 1
44
        if (\is_file($this->keyPath) && !$this->isFilePath()) {
45
            $this->keyPath = self::FILE_PREFIX . $this->keyPath;
46
        }
47 55
48 2
        if ($this->isFilePath()) {
49
            if (!\file_exists($this->keyPath) || !\is_readable($this->keyPath)) {
50
                throw new LogicException(\sprintf('Key path "%s" does not exist or is not readable', $this->keyPath));
51 55
            }
52 1
53
            $contents = \file_get_contents($this->keyPath);
54
        } else {
55 54
            $contents = $keyPath;
56
        }
57 54
58 54
        if ($this->isValidKey($contents, $this->passPhrase ?? '')) {
59
            if (!$this->isFilePath()) {
60
                $this->keyPath = $this->saveKeyToFile($keyPath);
61
            }
62
        } else {
63
            throw new LogicException('Unable to read key' . ($this->isFilePath() ? " from file $keyPath" : ''));
64
        }
65
66
        if ($keyPermissionsCheck === true) {
67 54
            // Verify the permissions of the key
68 54
            $keyPathPerms = \decoct(\fileperms($this->keyPath) & 0777);
69 54
            if (\in_array($keyPathPerms, ['400', '440', '600', '640', '660'], true) === false) {
70
                \trigger_error(
71
                    \sprintf(
72
                        'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
73
                        $this->keyPath,
74
                        $keyPathPerms
75
                    ),
76
                    E_USER_NOTICE
77
                );
78 1
            }
79
        }
80 1
    }
81 1
82
    /**
83 1
     * @param string $key
84
     *
85
     * @throws RuntimeException
86
     *
87 1
     * @return string
88
     */
89
    private function saveKeyToFile($key)
90
    {
91
        $tmpDir = \sys_get_temp_dir();
92
        $keyPath = $tmpDir . '/' . \sha1($key) . '.key';
93 1
94
        if (\file_exists($keyPath)) {
95
            return self::FILE_PREFIX . $keyPath;
96
        }
97
98
        if (\file_put_contents($keyPath, $key) === false) {
99 1
            // @codeCoverageIgnoreStart
100
            throw new RuntimeException(\sprintf('Unable to write key file to temporary directory "%s"', $tmpDir));
101
            // @codeCoverageIgnoreEnd
102
        }
103
104
        if (\chmod($keyPath, 0600) === false) {
105
            // @codeCoverageIgnoreStart
106
            throw new RuntimeException(\sprintf('The key file "%s" file mode could not be changed with chmod to 600', $keyPath));
107 19
            // @codeCoverageIgnoreEnd
108
        }
109 19
110
        return self::FILE_PREFIX . $keyPath;
111
    }
112
113
    /**
114
     * Validate key contents.
115
     *
116
     * @param string $contents
117 10
     * @param string $passPhrase
118
     *
119 10
     * @return bool
120
     */
121
    private function isValidKey($contents, $passPhrase)
122
    {
123
        try {
124
            RSA::load($contents, $passPhrase);
125
126
            return true;
127
        } catch (NoKeyLoadedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
128
        }
129
130
        try {
131
            EC::load($contents, $passPhrase);
132
133
            return true;
134
        } catch (NoKeyLoadedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
135
        }
136
137
        return false;
138
    }
139
140
    /**
141
     * Checks whether the key is a file.
142
     *
143
     * @return bool
144
     */
145
    private function isFilePath()
146
    {
147
        return \strpos($this->keyPath, self::FILE_PREFIX) === 0;
148
    }
149
150
    /**
151
     * Retrieve key path.
152
     *
153
     * @return string
154
     */
155
    public function getKeyPath()
156
    {
157
        return $this->keyPath;
158
    }
159
160
    /**
161
     * Retrieve key pass phrase.
162
     *
163
     * @return null|string
164
     */
165
    public function getPassPhrase()
166
    {
167
        return $this->passPhrase;
168
    }
169
}
170