CertificateBuilder::createCa()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0582

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 13
dl 0
loc 22
ccs 11
cts 13
cp 0.8462
rs 9.8333
c 2
b 1
f 0
cc 4
nc 3
nop 0
crap 4.0582
1
<?php
2
3
namespace App\Support\Ssl;
4
5
use App\Support\Contracts\Cli;
6
use App\Support\Mechanics\Mechanic;
7
use Illuminate\Filesystem\Filesystem;
8
use League\Flysystem\FileNotFoundException;
9
use Symfony\Component\Finder\SplFileInfo;
10
11
class CertificateBuilder
12
{
13
    protected $cli;
14
    protected $filesystem;
15
    protected $certificatesPath;
16
    protected $oName;
17
    protected $cName;
18
    protected $domain;
19
    protected $email;
20
21
    /**
22
     * Driver that will interact with the operating system.
23
     *
24
     * @var Mechanic
25
     */
26
    protected $mechanic;
27
28 12
    public function __construct(Cli $cli, Filesystem $filesystem, Mechanic $mechanic, $certificatesPath)
29
    {
30 12
        $this->cli = $cli;
31 12
        $this->filesystem = $filesystem;
32 12
        $this->mechanic = $mechanic;
33 12
        $this->certificatesPath = $certificatesPath;
34
35 12
        $this->oName = 'Klever Porter CA Self Signed Organization';
36 12
        $this->cName = 'Klever Porter CA Self Signed CN';
37 12
        $this->domain = 'klever.porter';
38 12
        $this->email = 'rootcertificate@'.$this->domain;
39
    }
40
41
    /**
42
     * List the certificate authority paths.
43
     *
44
     * @return object
45
     */
46 6
    public function caPaths()
47
    {
48
        return (object) [
49 6
            'key' => $this->certificatesPath.'/KleverPorterCASelfSigned.key',
50 6
            'pem' => $this->certificatesPath.'/KleverPorterCASelfSigned.pem',
51 6
            'srl' => $this->certificatesPath.'/KleverPorterCASelfSigned.srl',
52
        ];
53
    }
54
55
    /**
56
     * List paths based on the certificate url.
57
     *
58
     * @param $url
59
     *
60
     * @return object
61
     */
62 5
    public function paths($url)
63
    {
64
        return (object) [
65 5
            'key'  => $this->certificatesPath.'/'.$url.'.key',
66 5
            'csr'  => $this->certificatesPath.'/'.$url.'.csr',
67 5
            'crt'  => $this->certificatesPath.'/'.$url.'.crt',
68 5
            'conf' => $this->certificatesPath.'/'.$url.'.conf',
69
        ];
70
    }
71
72
    /**
73
     * Build a certificate based on the url.  Create CA if needed.
74
     *
75
     * @param $url
76
     */
77 4
    public function build($url)
78
    {
79 4
        $this->destroy($url);
80 4
        $this->createCa();
81 4
        $this->createCertificate($url);
82
    }
83
84
    /**
85
     * Destroy certificate for site based on url.
86
     *
87
     * @param $url
88
     */
89 5
    public function destroy($url)
90
    {
91 5
        foreach ($this->paths($url) as $path) {
92 5
            $this->filesystem->delete($path);
93
        }
94
    }
95
96
    /**
97
     * Create certificate authority.
98
     */
99 4
    public function createCa()
100
    {
101 4
        $paths = $this->caPaths();
102
103 4
        if ($this->filesystem->exists($paths->key) || $this->filesystem->exists($paths->pem)) {
104
            return;
105
        }
106
107 4
        $this->cli->exec(sprintf(
108
            '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',
109 4
            $this->oName,
110 4
            $this->cName,
111 4
            $this->email,
112 4
            $paths->key,
113 4
            $paths->pem
114
        ));
115
116 4
        if (!$this->filesystem->exists($paths->pem)) {
117
            throw new FileNotFoundException($paths->pem);
118
        }
119
120 4
        $this->mechanic->trustCA($paths->pem);
121
    }
122
123
    /**
124
     * Create a certificate for the given URL.
125
     *
126
     * @param string $url
127
     *
128
     * @return void
129
     */
130 4
    public function createCertificate($url)
131
    {
132 4
        $paths = $this->paths($url);
133 4
        $caPaths = $this->caPaths();
134
135 4
        $this->createConf($paths->conf, $url);
136 4
        $this->createPrivateKey($paths->key);
137 4
        $this->createSigningRequest($url, $paths->key, $paths->csr, $paths->conf);
138
139 4
        $caSrlParam = ' -CAcreateserial';
140 4
        if ($this->filesystem->exists($caPaths->srl)) {
141
            $caSrlParam = ' -CAserial '.$caPaths->srl;
142
        }
143
144 4
        $this->cli->exec(sprintf(
145
            'openssl x509 -req -sha256 -days 730 -CA %s -CAkey %s%s -in %s -out %s -extensions v3_req -extfile %s',
146 4
            $caPaths->pem,
147 4
            $caPaths->key,
148
            $caSrlParam,
149 4
            $paths->csr,
150 4
            $paths->crt,
151 4
            $paths->conf
152
        ));
153
154
        // Trusting the certificate shouldn't be necessary once the CA is trusted.
155
        // $this->mechanic->trustCertificate($paths->crt);
156
    }
157
158
    /**
159
     * Build the SSL config for the given URL.
160
     *
161
     * @param $path
162
     * @param $url
163
     */
164 4
    public function createConf($path, $url)
165
    {
166 4
        $this->filesystem->put($path, view('ssl.conf')->withUrl($url)->render());
167
    }
168
169
    /**
170
     * Create the private key for the TLS certificate.
171
     *
172
     * @param string $keyPath
173
     *
174
     * @return void
175
     */
176 4
    public function createPrivateKey($keyPath)
177
    {
178 4
        $this->cli->exec(sprintf('openssl genrsa -out %s 2048', $keyPath));
179
    }
180
181
    /**
182
     * Create the signing request for the TLS certificate.
183
     *
184
     * @param        $url
185
     * @param string $keyPath
186
     * @param        $csrPath
187
     * @param        $confPath
188
     *
189
     * @return void
190
     */
191 4
    public function createSigningRequest($url, $keyPath, $csrPath, $confPath)
192
    {
193 4
        $this->cli->exec(sprintf(
194
            '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',
195
            $keyPath,
196
            $csrPath,
197 4
            $this->domain,
198
            $url,
199
            $url,
200 4
            '@'.$this->domain,
201
            $confPath
202
        ));
203
    }
204
205
    /**
206
     * Clear generated certs. Optionally clear CA too.
207
     *
208
     * @param bool $dropCA
209
     */
210 2
    public function clearCertificates($dropCA = false)
211
    {
212 2
        $caPaths = (array) $this->caPaths();
213
214 2
        $files = $this->filesystem
215 2
            ->allFiles($this->certificatesPath);
216
217 2
        foreach ($files as $file) {
218
            /** @var SplFileInfo $file */
219 2
            if (!$dropCA && in_array($file->getPathname(), $caPaths)) {
220 1
                continue;
221
            }
222
223 2
            $this->filesystem->delete($file->getPathname());
224
        }
225
    }
226
}
227