Test Failed
Branch feature__set_up_scrutinizer (ea6624)
by Robin
06:04 queued 02:46
created

CertificateBuilder::clearDirectory()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 16
ccs 0
cts 9
cp 0
rs 8.8333
c 0
b 0
f 0
cc 7
nc 4
nop 1
crap 56
1
<?php
2
3
namespace App\Support\Ssl;
4
5
use App\Support\Mechanics\ChooseMechanic;
6
7
class CertificateBuilder
8
{
9
    protected $certificatesPath;
10
    protected $oName;
11
    protected $cName;
12
    protected $domain;
13
    protected $email;
14
15 7
    public function __construct($certificatesPath)
16
    {
17 7
        $this->certificatesPath = $certificatesPath;
18
19 7
        $this->oName = 'Klever Porter CA Self Signed Organization';
20 7
        $this->cName = 'Klever Porter CA Self Signed CN';
21 7
        $this->domain = 'klever.porter';
22 7
        $this->email = 'rootcertificate@'.$this->domain;
23 7
    }
24
25
    /**
26
     * List the certificate authority paths
27
     *
28
     * @return object
29
     */
30 1
    public function caPaths()
31
    {
32
        return (object) [
33 1
            'key' => $this->certificatesPath.'/KleverPorterSelfSigned.key',
34 1
            'pem' => $this->certificatesPath.'/KleverPorterSelfSigned.pem',
35 1
            'srl' => $this->certificatesPath.'/KleverPorterCASelfSigned.srl',
36
        ];
37
    }
38
39
    /**
40
     * List paths based on the certificate url
41
     *
42
     * @param $url
43
     * @return object
44
     */
45 2
    public function paths($url)
46
    {
47
        return (object) [
48 2
            'key' => $this->certificatesPath.'/'.$url.'.key',
49 2
            'csr' => $this->certificatesPath.'/'.$url.'.csr',
50 2
            'crt' => $this->certificatesPath.'/'.$url.'.crt',
51 2
            'conf' => $this->certificatesPath.'/'.$url.'.conf',
52
        ];
53
    }
54
55
    /**
56
     * Build a certificate based on the url.  Create CA if needed.
57
     *
58
     * @param $url
59
     */
60 1
    public function build($url)
61
    {
62 1
        $this->destroy($url);
63 1
        $this->createCa();
64 1
        $this->createCertificate($url);
65 1
    }
66
67
    /**
68
     * Destroy certificate for site based on url
69
     *
70
     * @param $url
71
     */
72 2
    public function destroy($url)
73
    {
74 2
        foreach ($this->paths($url) as $path) {
75 2
            @unlink($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

75
            /** @scrutinizer ignore-unhandled */ @unlink($path);

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...
76
        }
77 2
    }
78
79
    /**
80
     * Create certificate authority
81
     */
82 1
    public function createCa()
83
    {
84 1
        $paths = $this->caPaths();
85
86 1
        if (file_exists($paths->key) || file_exists($paths->pem)) {
87
            return;
88
        }
89
90 1
        exec(sprintf(
91 1
            'openssl req -new -newkey rsa:2048 -days 730 -nodes -x509 -subj "/C=GB/ST=Berks/O=%s/localityName=Reading/commonName=%s/organizationalUnitName=Developers/emailAddress=%s/" -keyout %s -out %s',
92 1
            $this->oName, $this->cName, $this->email, $paths->key, $paths->pem
93
        ));
94
95 1
        ChooseMechanic::forOS()->trustCA($paths->pem);
96 1
    }
97
98
    /**
99
     * Create a certificate for the given URL.
100
     *
101
     * @param  string  $url
102
     * @return void
103
     */
104 1
    public function createCertificate($url)
105
    {
106 1
        $paths = $this->paths($url);
107 1
        $caPaths = $this->caPaths();
108
109 1
        $this->createConf($paths->conf, $url);
110 1
        $this->createPrivateKey($paths->key);
111 1
        $this->createSigningRequest($url, $paths->key, $paths->csr, $paths->conf);
112
113 1
        $caSrlParam = ' -CAcreateserial';
114 1
        if (file_exists($caPaths->srl)) {
115
            $caSrlParam = ' -CAserial ' . $caPaths->srl;
116
        }
117
118 1
        exec(sprintf(
119 1
            'openssl x509 -req -sha256 -days 730 -CA %s -CAkey %s%s -in %s -out %s -extensions v3_req -extfile %s',
120 1
            $caPaths->pem, $caPaths->key, $caSrlParam, $paths->csr, $paths->crt, $paths->conf
121
        ));
122
123
        // Trusting the certificate shouldn't be necessary once the CA is trusted.
124
        // ChooseMechanic::forOS()->trustCertificate($paths->crt);
125 1
    }
126
127
    /**
128
     * Build the SSL config for the given URL.
129
     *
130
     * @param $path
131
     * @param $url
132
     */
133 1
    public function createConf($path, $url)
134
    {
135 1
        file_put_contents($path, view('ssl.conf')->withUrl($url)->render());
136 1
    }
137
138
    /**
139
     * Create the private key for the TLS certificate.
140
     *
141
     * @param  string  $keyPath
142
     * @return void
143
     */
144 1
    public function createPrivateKey($keyPath)
145
    {
146 1
        exec(sprintf('openssl genrsa -out %s 2048', $keyPath));
147 1
    }
148
149
    /**
150
     * Create the signing request for the TLS certificate.
151
     *
152
     * @param $url
153
     * @param  string $keyPath
154
     * @param $csrPath
155
     * @param $confPath
156
     * @return void
157
     */
158 1
    public function createSigningRequest($url, $keyPath, $csrPath, $confPath)
159
    {
160 1
        exec(sprintf(
161 1
            'openssl req -new -key %s -out %s -subj "/C=GB/ST=Berks/O=%s/localityName=Reading/commonName=%s/organizationalUnitName=Developers/emailAddress=%s%s/" -config %s',
162 1
            $keyPath, $csrPath, $this->domain, $url, $url, '@'.$this->domain, $confPath
163
        ));
164 1
    }
165
166
    /**
167
     * Clear generated certs. Optionally clear CA too.
168
     *
169
     * @param bool $dropCA
170
     */
171
    public function clearDirectory($dropCA = false)
172
    {
173
        $caPaths = (array) $this->caPaths();
174
175
        foreach (scandir($this->certificatesPath) as $item) {
176
            if ($item == '.' || $item == '..' || $item == '.gitkeep') {
177
                continue;
178
            }
179
180
            $current = $this->certificatesPath.'/'.$item;
181
182
            if (! $dropCA && in_array($current, $caPaths)) {
183
                continue;
184
            }
185
186
            unlink($current);
187
        }
188
    }
189
}
190