Test Failed
Push — master ( e81f34...58150d )
by
unknown
19:06
created

ApiBase::isAuthFileData()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 11
ccs 0
cts 6
cp 0
crap 12
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * API Gateway: Cliente de API en PHP.
7
 * Copyright (C) API Gateway <https://www.apigateway.cl>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la GNU Lesser General Public License (LGPL) publicada
11
 * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia,
12
 * o (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 GNU Lesser General
17
 * Public License (LGPL) para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la GNU Lesser General Public License
20
 * (LGPL) junto a este programa. En caso contrario, consulte
21
 * <http://www.gnu.org/licenses/lgpl.html>.
22
 */
23
24
namespace apigatewaycl\api_client;
25
26
/**
27
 * Clase base para las clases que consumen la API (wrappers).
28
 */
29
class ApiBase extends ApiClient
30
{
31
    /**
32
     * Arreglo que contendrá el diccionario de autenticación.
33
     *
34
     * @var array
35
     */
36
    protected $auth = [];
37
38
    /**
39
     * Constructor de la clase base.
40
     *
41
     * @param array $credenciales Argumentos adicionales para la autenticación.
42
     * @param string|null $token Token de autenticación para la API.
43
     * @param string|null $url URL base para la API.
44
     */
45
    public function __construct(
46
        array $credenciales = [],
47
        string $token = null,
48
        string $url = null
49
    ) {
50
        parent::__construct($token, $url);
51
        $this->setupAuth($credenciales);
52
    }
53
54
    /**
55
     * Configura la autenticación específica para la aplicación.
56
     *
57
     * @param array $credenciales Parámetros de autenticación. Puede ser 'pass' o 'cert'.
58
     * @throws \apigatewaycl\api_client\ApiException
59
     * @return void
60
     */
61
    private function setupAuth(array $credenciales)
62
    {
63
        $tipo = key($credenciales); // Detecta si es 'pass' o 'cert'
64
        $datos = $credenciales[$tipo] ?? [];
65
66
        $identificador = $datos['rut'] ?? $datos['cert-data'] ?? $datos['file-data'] ?? null;
67
        $clave = $datos['clave'] ?? $datos['pkey-data'] ?? $datos['file-pass'] ?? null;
68
69
        if ($identificador && $clave) {
70
            if ($this->isAuthPass($identificador)) {
71
                $this->auth = ['pass' => ['rut' => $identificador, 'clave' => $clave]];
72
            } elseif ($this->isAuthCertData($identificador)) {
73
                $this->auth = ['cert' => ['cert-data' => $identificador, 'pkey-data' => $clave]];
74
            } elseif ($this->isAuthFileData($identificador)) {
75
                $this->auth = ['cert' => ['file-data' => $identificador, 'file-pass' => $clave]];
76
            } else {
77
                throw new ApiException('No se han proporcionado las credenciales de autentificación.');
78
            }
79
        }
80
    }
81
82
    /**
83
     * Valida la estructura de un RUT chileno utilizando una expresión regular.
84
     *
85
     * Este método verifica que el RUT cumpla con el formato estándar chileno, que incluye
86
     * puntos como separadores de miles opcionales y un guion antes del dígito verificador.
87
     * El dígito verificador puede ser un número o la letra 'K'.
88
     *
89
     * **Ejemplos de RUT válidos:**
90
     *
91
     *     - 12.345.678-5
92
     *     - 12345678-5
93
     *     - 9.876.543-K
94
     *     - 9876543-K
95
     *
96
     * **Ejemplos de RUT inválidos:**
97
     *
98
     *     - 12.345.678-9 (dígito verificador incorrecto)
99
     *     - 12345678- (falta dígito verificador)
100
     *     - 12345-6 (formato incorrecto)
101
     *     - 12.345.6785 (falta guion)
102
     *     - abcdefgh-i (caracteres no permitidos)
103
     *
104
     * @param string $rut El RUT a validar.
105
     * @return bool true si el RUT tiene un formato válido,false en caso contrario.
106
     */
107
    private function isAuthPass(string $rut)
108
    {
109
        if (is_null($rut)) {
0 ignored issues
show
introduced by
The condition is_null($rut) is always false.
Loading history...
110
            return false;
111
        }
112
        // Expresión regular para validar el formato del RUT chileno
113
        $pattern = '/^(\d{1,3}\.?)(\d{3}\.?)(\d{3,4})-([\dkK])$/';
114
        return preg_match($pattern, $rut) === 1;
115
    }
116
117
    /**
118
     * Verifica si una cadena es una cadena codificada en Base64 válida.
119
     *
120
     * @param string $firmaElectronicaBase64 La cadena a verificar.
121
     * @return bool true si la cadena es válida en Base64, false en caso contrario.
122
     */
123
    private function isAuthFileData(string $firmaElectronicaBase64)
124
    {
125
        if (is_null($firmaElectronicaBase64)) {
0 ignored issues
show
introduced by
The condition is_null($firmaElectronicaBase64) is always false.
Loading history...
126
            return false;
127
        }
128
        // Asegúrate de que la longitud de la cadena sea múltiplo de 4
129
        if (strlen($firmaElectronicaBase64) % 4 !== 0) {
130
            return false;
131
        }
132
        // Validar Base64
133
        return base64_decode($firmaElectronicaBase64, true) !== false;
134
    }
135
136
    /**
137
     * Valida si una cadena tiene formato PEM válido.
138
     *
139
     * El formato PEM debe cumplir con los siguientes criterios:
140
     *
141
     *      - Comienza con una línea "-----BEGIN [LABEL]-----"
142
     *      - Termina con una línea "-----END [LABEL]-----"
143
     *      - Contiene contenido Base64 válido entre las líneas BEGIN y END
144
     *
145
     * **Ejemplos de PEM Válidos:**
146
     *
147
     *      ```
148
     *      -----BEGIN CERTIFICATE-----
149
     *      MIIDdzCCAl+gAwIBAgIEbGzVnzANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJV
150
     *      ...
151
     *      -----END CERTIFICATE-----
152
     *      ```
153
     *
154
     * **Ejemplos de PEM Inválidos:**
155
     *
156
     *      - Falta la línea de inicio o fin.
157
     *      - Contenido no codificado en Base64.
158
     *      - Etiquetas de BEGIN y END que no coinciden.
159
     *
160
     * @param string $pemStr La cadena a validar.
161
     * @return bool true si la cadena tiene formato PEM válido, false en caso contrario.
162
     */
163
    private function isAuthCertData(string $pemStr)
164
    {
165
        if (is_null($pemStr)) {
0 ignored issues
show
introduced by
The condition is_null($pemStr) is always false.
Loading history...
166
            return false;
167
        }
168
        // Expresión regular para validar el formato PEM
169
        $pattern = '/-----BEGIN ([A-Z ]+)-----\s+([A-Za-z0-9+\/=\s]+)-----END \1-----$/m';
170
        if (!preg_match($pattern, trim($pemStr), $matches)) {
171
            return false;
172
        }
173
        // Validar contenido Base64
174
        $base64Content = preg_replace('/\s+/', '', $matches[2]);
175
        return base64_decode($base64Content, true) !== false;
176
    }
177
178
    /**
179
     * Obtiene la autenticación de tipo 'pass'.
180
     *
181
     * @throws \apigatewaycl\api_client\ApiException Si falta información de autenticación.
182
     * @return array Información de autenticación.
183
     */
184
    protected function getAuthPass()
185
    {
186
        if (isset($this->auth['pass'])) {
187
            if (empty($this->auth['pass']['rut'])) {
188
                throw new ApiException('auth.pass.rut empty.');
189
            }
190
            if (empty($this->auth['pass']['clave'])) {
191
                throw new ApiException('auth.pass.clave empty.');
192
            }
193
        } elseif (isset($this->auth['cert'])) {
194
            if (isset($this->auth['cert']['cert-data']) && empty($this->auth['cert']['cert-data'])) {
195
                throw new ApiException('auth.cert.cert-data empty.');
196
            }
197
            if (isset($this->auth['cert']['pkey-data']) && empty($this->auth['cert']['pkey-data'])) {
198
                throw new ApiException('auth.cert.pkey-data empty.');
199
            }
200
            if (isset($this->auth['cert']['file-data']) && empty($this->auth['cert']['file-data'])) {
201
                throw new ApiException('auth.cert.file-data empty.');
202
            }
203
            if (isset($this->auth['cert']['file-pass']) && empty($this->auth['cert']['file-pass'])) {
204
                throw new ApiException('auth.cert.file-pass empty.');
205
            }
206
        } else {
207
            throw new ApiException('auth.pass or auth.cert missing.');
208
        }
209
210
        return $this->auth;
211
    }
212
}
213