Test Failed
Pull Request — master (#54)
by Robin
03:46
created

CertificateBuilder::caPaths()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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