Passed
Branch master (0b4ab1)
by Esteban De La Fuente
74:02 queued 50:02
created

FakerWorker::createAsString()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 67
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 5.4742

Importance

Changes 0
Metric Value
cc 5
eloc 35
c 0
b 0
f 0
nc 5
nop 0
dl 0
loc 67
ccs 33
cts 45
cp 0.7332
crap 5.4742
rs 9.0488

How to fix   Long Method   

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
declare(strict_types=1);
4
5
/**
6
 * Derafu: Biblioteca PHP (Núcleo).
7
 * Copyright (C) Derafu <https://www.derafu.org>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la Licencia Pública General Affero de GNU publicada por
11
 * la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, o
12
 * (a su elección) cualquier versión posterior de la misma.
13
 *
14
 * Este programa se distribuye con la esperanza de que sea útil, pero SIN
15
 * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
16
 * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la Licencia Pública
17
 * General Affero de GNU para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace Derafu\Lib\Core\Package\Prime\Component\Certificate\Worker;
26
27
use Derafu\Lib\Core\Foundation\Abstract\AbstractWorker;
28
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Contract\FakerWorkerInterface;
29
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Contract\LoaderWorkerInterface;
30
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Entity\Certificate;
31
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Exception\CertificateException;
32
use OpenSSLAsymmetricKey;
33
34
/**
35
 * Clase que se encarga de generar certificados autofirmados y retornarlos como
36
 * un string de datos, un arreglo o una instancia de Certificate.
37
 */
38
class FakerWorker extends AbstractWorker implements FakerWorkerInterface
39
{
40
    /**
41
     * Datos del sujeto del certificado.
42
     *
43
     * @var array
44
     */
45
    private array $subject;
46
47
    /**
48
     * Datos del emisor del certificado.
49
     *
50
     * @var array
51
     */
52
    private array $issuer;
53
54
    /**
55
     * Validez del certificado en formato UNIX timestamp.
56
     *
57
     * @var array
58
     */
59
    private array $validity;
60
61
    /**
62
     * Contraseña para proteger la clave privada en el certificado.
63
     *
64
     * @var string
65
     */
66
    private string $password;
67
68
    /**
69
     * Instancia que permite cargar (crear) certificados a partir de sus datos.
70
     *
71
     * @var LoaderWorkerInterface
72
     */
73
    private LoaderWorkerInterface $loader;
74
75
    /**
76
     * Constructor de la clase.
77
     *
78
     * Establece valores por defecto para el sujeto, emisor, validez y
79
     * contraseña.
80
     *
81
     * @param LoaderWorkerInterface $loader
82
     */
83 26
    public function __construct(LoaderWorkerInterface $loader)
84
    {
85 26
        $this->loader = $loader;
86
87 26
        $this->setSubject();
88 26
        $this->setIssuer();
89 26
        $this->setValidity();
90 26
        $this->setPassword();
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96 26
    public function setSubject(
97
        string $C = 'CL',
98
        string $ST = 'Colchagua',
99
        string $L = 'Santa Cruz',
100
        string $O = 'Organización Intergaláctica de Robots',
101
        string $OU = 'Tecnología',
102
        string $CN = 'Daniel',
103
        string $emailAddress = '[email protected]',
104
        string $serialNumber = '11222333-9',
105
        string $title = 'Bot',
106
    ): static {
107 26
        if (empty($CN) || empty($emailAddress) || empty($serialNumber)) {
108 2
            throw new CertificateException(
109 2
                'El CN, emailAddress y serialNumber son obligatorios.'
110 2
            );
111
        }
112
113 26
        $this->subject = [
114 26
            'C' => $C,
115 26
            'ST' => $ST,
116 26
            'L' => $L,
117 26
            'O' => $O,
118 26
            'OU' => $OU,
119 26
            'CN' => $CN,
120 26
            'emailAddress' => $emailAddress,
121 26
            'serialNumber' => strtoupper($serialNumber),
122 26
            'title' => $title,
123 26
        ];
124
125 26
        return $this;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 26
    public function setIssuer(
132
        string $C = 'CL',
133
        string $ST = 'Colchagua',
134
        string $L = 'Santa Cruz',
135
        string $O = 'Derafu',
136
        string $OU = 'Tecnología',
137
        string $CN = 'Derafu Autoridad Certificadora de Pruebas',
138
        string $emailAddress = '[email protected]',
139
        string $serialNumber = '76192083-9',
140
    ): static {
141 26
        $this->issuer = [
142 26
            'C' => $C,
143 26
            'ST' => $ST,
144 26
            'L' => $L,
145 26
            'O' => $O,
146 26
            'OU' => $OU,
147 26
            'CN' => $CN,
148 26
            'emailAddress' => $emailAddress,
149 26
            'serialNumber' => strtoupper($serialNumber),
150 26
        ];
151
152 26
        return $this;
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158 26
    public function setValidity(int $days = 365): static
159
    {
160 26
        $this->validity = [
161 26
            'days' => $days,
162 26
        ];
163
164 26
        return $this;
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 26
    public function setPassword(string $password = 'i_love_derafu')
171
    {
172 26
        $this->password = $password;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178 2
    public function getPassword(): string
179
    {
180 2
        return $this->password;
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186 22
    public function createAsString(): string
187
    {
188
        // Días de validez del certificado (emisor y sujeto).
189 22
        $days = $this->validity['days'];
190
191
        // Crear clave privada y CSR para el emisor.
192 22
        $issuerPrivateKey = openssl_pkey_new();
193 22
        if (!$issuerPrivateKey instanceof OpenSSLAsymmetricKey) {
194
            throw new CertificateException(
195
                'No fue posible generar la llave privada del emisor del certificado.'
196
            );
197
        }
198 22
        $issuerCsr = openssl_csr_new($this->issuer, $issuerPrivateKey);
199
200
        // Crear certificado autofirmado para el emisor (CA).
201 22
        $issuerCert = openssl_csr_sign(
202 22
            $issuerCsr,         // CSR del emisor.
203 22
            null,               // Certificado emisor (null indica que es autofirmado).
204 22
            $issuerPrivateKey,  // Clave privada del emisor.
205 22
            $days,              // Número de días de validez (misma sujeto).
206 22
            [],                 // Opciones adicionales.
207 22
            666                 // Número de serie del certificado.
208 22
        );
209
210
        // Validar que se haya podido crear el certificado del emisor (CA).
211 22
        if ($issuerCert === false) {
212
            throw new CertificateException(
213
                'No fue posible generar el certificado del emisor (CA).'
214
            );
215
        }
216
217
        // Crear clave privada y CSR para el sujeto.
218 22
        $subjectPrivateKey = openssl_pkey_new();
219 22
        if (!$subjectPrivateKey instanceof OpenSSLAsymmetricKey) {
220
            throw new CertificateException(
221
                'No fue posible generar la llave privada del certificado.'
222
            );
223
        }
224 22
        $subjectCsr = openssl_csr_new($this->subject, $subjectPrivateKey);
225
226
        // Usar el certificado del emisor para firmar el CSR del sujeto.
227 22
        $subjectCert = openssl_csr_sign(
228 22
            $subjectCsr,        // La solicitud de firma del certificado (CSR).
229 22
            $issuerCert,        // Certificado emisor.
230 22
            $issuerPrivateKey,  // Clave privada del emisor.
231 22
            $days,              // Número de días de validez.
232 22
            [],                 // Opciones adicionales.
233 22
            69                  // Número de serie del certificado.
234 22
        );
235
236
        // Validar que se haya podido crear el certificado del usuario.
237 22
        if ($subjectCert === false) {
238
            throw new CertificateException(
239
                'No fue posible generar el certificado del usuario.'
240
            );
241
        }
242
243
        // Exportar el certificado final en formato PKCS#12.
244 22
        openssl_pkcs12_export(
245 22
            $subjectCert,
246 22
            $data,
247 22
            $subjectPrivateKey,
248 22
            $this->password
249 22
        );
250
251
        // Entregar los datos del certificado digital.
252 22
        return $data;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 20
    public function createAsArray(): array
259
    {
260 20
        $data = $this->createAsString();
261 20
        $array = [];
262 20
        openssl_pkcs12_read($data, $array, $this->password);
263
264 20
        return $array;
265
    }
266
267
    /**
268
     * {@inheritdoc}
269
     */
270 17
    public function create(): Certificate
271
    {
272 17
        $array = $this->createAsArray();
273
274 17
        return $this->loader->createFromArray($array);
275
    }
276
}
277