Config::getCerts()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace OpenVPN;
4
5
use OpenVPN\Interfaces\ConfigInterface;
6
use OpenVPN\Interfaces\GeneratorInterface;
7
use RuntimeException;
8
use function in_array;
9
use function is_bool;
10
11
/**
12
 * Class Config
13
 *
14
 * @property string    $modeSet             OpenVPN major mode: p2p, server
15
 * @property string    $local               Local host name or IP address
16
 * @property string    $remote              Remote host name or IP address
17
 * @property bool|null $remoteRandom        When multiple --remote address/ports are specified, initially randomize the order of the list
18
 * @property string    $proto               Protocol for communicating with remote host: tcp, udp, tcp-client
19
 * @property integer   $connectRetry        For --proto tcp-client, take n as the number of seconds to wait between connection retries (default=5)
20
 * @property string    $httpProxy           Connect to remote host through an HTTP proxy
21
 * @property bool|null $httpProxyRetry      Retry indefinitely on HTTP proxy errors. If an HTTP proxy error occurs, simulate a SIGUSR1 reset.
22
 * @property integer   $httpProxyTimeout    Set proxy timeout to n seconds, default=5.
23
 * @property string    $httpProxyOption     Set extended HTTP proxy options
24
 * @property string    $socksProxy          Connect to remote host through a Socks5 proxy
25
 * @property bool|null $socksProxyRetry     Retry indefinitely on Socks proxy errors. If a Socks proxy error occurs, simulate a SIGUSR1 reset.
26
 * @property string    $resolvRetry         If hostname resolve fails for --remote, retry resolve for n seconds before failing
27
 * @property bool|null $float               Allow remote peer to change its IP address and/or port number, such as due to DHCP
28
 * @property string    $ipchange            Execute shell command, format: cmd ip_address port_number
29
 * @property integer   $port                TCP/UDP port number for both local and remote: 1194
30
 * @property integer   $lport               TCP/UDP port number for local
31
 * @property integer   $rport               TCP/UDP port number for remote
32
 * @property bool|null $nobind              Do not bind to local address and port
33
 * @property string    $dev                 TUN/TAP virtual network device: tunX, tapX, null
34
 * @property string    $devType             Which device type are we using? device-type should be tun or tap
35
 * @property bool|null $tunIpv6             Build a tun link capable of forwarding IPv6 traffic
36
 * @property string    $devNode             Explicitly set the device node rather than using /dev/net/tun, /dev/tun, /dev/tap, etc.
37
 * @property string    $ifconfig            Set TUN/TAP adapter IP address of the local VPN endpoint.
38
 * @property bool|null $ifconfigNoexec      Don’t actually execute ifconfig/netsh commands, instead pass –ifconfig parameters to scripts using environmental variables.
39
 * @property bool|null $ifconfigNowarn      Don’t output an options consistency check warning
40
 * @property string    $ifconfigPool        Set aside a pool of subnets to be dynamically allocated to connecting clients, similar to a DHCP server.
41
 * @property string    $ifconfigPoolPersist Persist/unpersist ifconfig-pool data to file, at secondsintervals (default=600),
42
 * @property string    $cipher              Encrypt packets with cipher algorithm alg. The default is BF-CBC,an abbreviation for Blowfish in Cipher Block Chaining mode.
43
 * @property bool|null $redirectGateway
44
 * @property integer   $keyDirection
45
 * @property string    $remoteCertTls
46
 * @property string    $auth                Authenticate packets with HMAC using message digest algorithm alg. (The default is SHA1).
47
 * @property bool|null $authUserPass
48
 * @property bool|null $authNocache
49
 * @property string    $authUserPassVerify  Path to login script
50
 * @property bool|null $duplicateCn         You may need this if everyone is using same certificate
51
 * @property bool|null $persistKey
52
 * @property bool|null $persistTun
53
 * @property bool|null $compLzo             Use fast LZO compression — may add up to 1 byte per packet for incompressible data.
54
 * @property bool|null $compNoadapt         When used in conjunction with –comp-lzo, this option will disable OpenVPN’s adaptive compression algorithm.
55
 * @property integer   $verb                Set output verbosity to n(default=1). Each level shows all info from the previous levels: 0,1,2 ... 11
56
 * @property string    $server              A helper directive designed to simplify the configuration of OpenVPN’s server mode.
57
 * @property string    $serverBridge        A helper directive similar to --server which is designed to simplify the configuration of OpenVPN’s server mode in ethernet bridging configurations.
58
 * @property string    $keepalive
59
 * @property integer   $renegSec
60
 * @property string    $user
61
 * @property string    $group
62
 * @property string    $mute
63
 * @property string    $status
64
 * @property string    $logAppend
65
 * @property string    $clientConfigDir
66
 * @property string    $scriptSecurity
67
 * @property string    $usernameAsCommonName
68
 * @property string    $verifyClientCert
69
 *
70
 * @package OpenVPN
71
 */
72
class Config implements ConfigInterface, GeneratorInterface
73
{
74
    /**
75
     * List of types of certs, for validation
76
     */
77
    public const ALLOWED_TYPES_OF_CERTS = [
78
        'ca',
79
        'cert',
80
        'key',
81
        'dh',
82
        'tls-auth',
83
        'secret',
84
        'pkcs12'
85
    ];
86
87
    /**
88
     * Array with all certificates
89
     *
90
     * @var array
91
     */
92
    private $certs = [];
93
94
    /**
95
     * List of all routes available on server
96
     *
97
     * @var array
98
     */
99
    private $routes = [];
100
101
    /**
102
     * List of lines which must be pushed to clients
103
     *
104
     * @var array
105
     */
106
    private $pushes = [];
107
108
    /**
109
     * List of lines which can be used as remotes
110
     *
111
     * @var array
112
     */
113
    private $remotes = [];
114
115
    /**
116
     * All parameters added via addParam method
117
     *
118
     * @var array
119
     */
120
    private $parameters = [];
121
122
    /**
123
     * Config constructor.
124
     *
125
     * @param array $parameters List of default parameters
126
     */
127 8
    public function __construct(array $parameters = [])
128
    {
129 8
        $this->setParams($parameters);
130 8
    }
131
132
    /**
133
     * Alias for client line of config
134
     *
135
     * @return \OpenVPN\Interfaces\ConfigInterface
136
     */
137 1
    public function client(): ConfigInterface
138
    {
139 1
        return $this->set('client');
140
    }
141
142
    /**
143
     * Import content of all listed certificates
144
     *
145
     * @return void
146
     */
147
    public function loadCertificates(): void
148
    {
149
        foreach ($this->certs as &$cert) {
150
            $cert['content'] = rtrim(file_get_contents($cert['path']));
151
        }
152
    }
153
154
    /**
155
     * Add new cert into the configuration
156
     *
157
     * @param string    $type      Type of certificate [ca, cert, key, dh, tls-auth]
158
     * @param string    $path      Absolute or relative path to certificate or content of this file
159
     * @param bool|null $isContent If true, then script will try to load file from dist by $path
160
     *
161
     * @return \OpenVPN\Interfaces\ConfigInterface
162
     * @throws \RuntimeException
163
     */
164 6
    public function setCert(string $type, string $path, bool $isContent = null): ConfigInterface
165
    {
166 6
        $type = mb_strtolower($type);
167 6
        Helpers::isCertAllowed($type);
168 6
        if (true === $isContent) {
169 1
            $this->certs[$type]['content'] = $path;
170
        } else {
171 6
            $this->certs[$type]['path'] = $path;
172
        }
173
174 6
        return $this;
175
    }
176
177
    /**
178
     * Return information about specified certificate
179
     *
180
     * @param string $type
181
     *
182
     * @return array
183
     * @throws \RuntimeException
184
     */
185
    public function getCert(string $type): array
186
    {
187
        $type = mb_strtolower($type);
188
        Helpers::isCertAllowed($type);
189
190
        return $this->certs[$type] ?? [];
191
    }
192
193
    /**
194
     * Append new push into the array
195
     *
196
     * @param string $line String with line which must be pushed
197
     *
198
     * @return \OpenVPN\Interfaces\ConfigInterface
199
     */
200 4
    public function setPush(string $line): ConfigInterface
201
    {
202 4
        $this->pushes[] = trim($line, '"');
203
204 4
        return $this;
205
    }
206
207
    /**
208
     * Remove route line from push array
209
     *
210
     * @param string $line String with line which must be pushed
211
     *
212
     * @return \OpenVPN\Interfaces\ConfigInterface
213
     */
214
    public function unsetPush(string $line): ConfigInterface
215
    {
216
        unset($this->pushes[$line]);
217
218
        return $this;
219
    }
220
221
    /**
222
     * Append new route into the array
223
     *
224
     * @param string $line String with route
225
     *
226
     * @return \OpenVPN\Interfaces\ConfigInterface
227
     */
228 3
    public function setRoute(string $line): ConfigInterface
229
    {
230 3
        $this->routes[] = trim($line, '"');
231
232 3
        return $this;
233
    }
234
235
    /**
236
     * Remove route line from routes array
237
     *
238
     * @param string $line String with route
239
     *
240
     * @return \OpenVPN\Interfaces\ConfigInterface
241
     */
242
    public function unsetRoute(string $line): ConfigInterface
243
    {
244
        unset($this->routes[$line]);
245
246
        return $this;
247
    }
248
249
    /**
250
     * Append new push into the array
251
     *
252
     * @param string $line String with line which must be added as remote
253
     *
254
     * @return \OpenVPN\Interfaces\ConfigInterface
255
     */
256 1
    public function setRemote(string $line): ConfigInterface
257
    {
258 1
        $this->remotes[] = trim($line, '"');
259
260 1
        return $this;
261
    }
262
263
    /**
264
     * Remove remote line from remotes array
265
     *
266
     * @param string $line String with line which must be added as remote
267
     *
268
     * @return \OpenVPN\Interfaces\ConfigInterface
269
     */
270
    public function unsetRemote(string $line): ConfigInterface
271
    {
272
        unset($this->remotes[$line]);
273
274
        return $this;
275
    }
276
277
    /**
278
     * Add some new parameter to the list of parameters
279
     *
280
     * @param string           $name  Name of parameter
281
     * @param string|bool|null $value Value of parameter
282
     *
283
     * @return \OpenVPN\Interfaces\ConfigInterface
284
     * @example $this->add('client')->add('remote', 'vpn.example.com');
285
     */
286 5
    public function set(string $name, $value = null): ConfigInterface
287
    {
288 5
        $name = mb_strtolower($name);
289
290
        // Check if key is certificate or push, or classic parameter
291 5
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
292 3
            return $this->setCert($name, $value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 286 can also be of type boolean or null; however, OpenVPN\Config::setCert() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
293
        }
294
295
        // If is push then use add push method
296 5
        if ($name === 'remote') {
297 1
            return $this->setRemote($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 286 can also be of type boolean or null; however, OpenVPN\Config::setRemote() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
298
        }
299
300
        // If is push then use add push method
301 5
        if ($name === 'push') {
302 4
            return $this->setPush($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 286 can also be of type boolean or null; however, OpenVPN\Config::setPush() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
303
        }
304
305
        // If is push then use add push method
306 4
        if ($name === 'route') {
307 3
            return $this->setRoute($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 286 can also be of type boolean or null; however, OpenVPN\Config::setRoute() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
308
        }
309
310
        // Check if provided value is boolean and if it's true, then set null (that mean parameter without value)
311 4
        if (is_bool($value) && $value) {
312 3
            if ($value) {
313 3
                $value = null;
314
            } else {
315
                // If false then skip this step
316
                return $this;
317
            }
318
        }
319
320
        // Set new value
321 4
        $this->parameters[$name] = $value;
322
323 4
        return $this;
324
    }
325
326
    /**
327
     * Get some custom element
328
     *
329
     * @param string|null $name Name of parameter
330
     *
331
     * @return mixed
332
     */
333
    public function get(string $name)
334
    {
335
        return $this->parameters[$name] ?? null;
336
    }
337
338
    /**
339
     * Generate config by parameters in memory
340
     *
341
     * @param string $type Type of generated config: raw (default), json
342
     *
343
     * @return array|string|null
344
     */
345 1
    public function generate(string $type = 'raw')
346
    {
347 1
        $generator = new Generator($this);
348
349 1
        return $generator->generate($type);
350
    }
351
352
    /**
353
     * @param string $name
354
     *
355
     * @return bool
356
     */
357
    public function __isset(string $name): bool
358
    {
359
        // Inform about deleting push
360
        if ($name === 'push') {
361
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
362
        }
363
364
        // Inform about deleting route
365
        if ($name === 'route') {
366
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
367
        }
368
369
        // Inform about deleting route
370
        if ($name === 'remote') {
371
            throw new RuntimeException("Not possible to remove remote, use 'unsetRemote' instead");
372
        }
373
374
        return isset($this->parameters[$name]);
375
    }
376
377
    /**
378
     * @param string                   $name
379
     * @param string|bool|integer|null $value
380
     */
381 3
    public function __set(string $name, $value = null): void
382
    {
383 3
        $name = Helpers::decamelize($name);
384 3
        $this->set($name, $value);
385 3
    }
386
387
    /**
388
     * @param string $name
389
     *
390
     * @return string|bool|null
391
     */
392
    public function __get(string $name)
393
    {
394
        return $this->get($name);
395
    }
396
397
    /**
398
     * Remove some parameter from array by name
399
     *
400
     * @param string $name Name of parameter
401
     *
402
     * @return void
403
     * @throws \RuntimeException
404
     */
405
    public function __unset(string $name): void
406
    {
407
        // Inform about deleting push
408
        if ($name === 'push') {
409
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
410
        }
411
412
        // Inform about deleting route
413
        if ($name === 'route') {
414
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
415
        }
416
417
        // Inform about deleting route
418
        if ($name === 'remote') {
419
            throw new RuntimeException("Not possible to remove remote, use 'unsetRemote' instead");
420
        }
421
422
        // Check if key is certificate or push, or classic parameter
423
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
424
            $this->unsetCert($name);
425
            return;
426
        }
427
428
        // Update list of parameters
429
        $this->parameters = array_map(
430
            static function ($param) use ($name) {
431
                return ($param['name'] === $name) ? null : $param;
432
            },
433
            $this->parameters
434
        );
435
    }
436
437
    /**
438
     * Remove selected certificate from array
439
     *
440
     * @param string $type Type of certificate [ca, cert, key, dh, tls-auth]
441
     *
442
     * @return \OpenVPN\Interfaces\ConfigInterface
443
     * @throws \RuntimeException
444
     */
445 2
    public function unsetCert(string $type): ConfigInterface
446
    {
447 2
        $type = mb_strtolower($type);
448 2
        Helpers::isCertAllowed($type);
449 2
        unset($this->certs[$type]);
450
451 2
        return $this;
452
    }
453
454
    /**
455
     * Set scope of certs
456
     *
457
     * @param \OpenVPN\Types\Cert[]|string[] $certs
458
     * @param bool                           $loadCertificates
459
     *
460
     * @return \OpenVPN\Interfaces\ConfigInterface
461
     */
462 3
    public function setCerts(array $certs, bool $loadCertificates = false): ConfigInterface
463
    {
464
        // Pass list of certs from array to variable
465 3
        foreach ($certs as $type => $path) {
466 3
            $this->setCert($type, $path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $path on line 465 can also be of type object<OpenVPN\Types\Cert>; however, OpenVPN\Config::setCert() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
467
        }
468
469
        // If need to load content of files from disk
470 3
        if ($loadCertificates) {
471
            $this->loadCertificates();
472
        }
473
474 3
        return $this;
475
    }
476
477
    /**
478
     * Set scope of unique pushes
479
     *
480
     * @param \OpenVPN\Types\Push[]|string[] $pushes
481
     *
482
     * @return \OpenVPN\Interfaces\ConfigInterface
483
     */
484 3
    public function setPushes(array $pushes): ConfigInterface
485
    {
486 3
        foreach ($pushes as $push) {
487 3
            $this->setPush($push);
0 ignored issues
show
Bug introduced by
It seems like $push defined by $push on line 486 can also be of type object<OpenVPN\Types\Push>; however, OpenVPN\Config::setPush() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
488
        }
489
490 3
        return $this;
491
    }
492
493
    /**
494
     * Set scope of unique routes
495
     *
496
     * @param \OpenVPN\Types\Route[]|string[] $routes
497
     *
498
     * @return \OpenVPN\Interfaces\ConfigInterface
499
     */
500 3
    public function setRoutes(array $routes): ConfigInterface
501
    {
502 3
        foreach ($routes as $route) {
503 3
            $this->setRoute($route);
0 ignored issues
show
Bug introduced by
It seems like $route defined by $route on line 502 can also be of type object<OpenVPN\Types\Route>; however, OpenVPN\Config::setRoute() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
504
        }
505
506 3
        return $this;
507
    }
508
509
    /**
510
     * Set scope of unique remotes
511
     *
512
     * @param \OpenVPN\Types\Remote[]|string[] $remotes
513
     *
514
     * @return \OpenVPN\Interfaces\ConfigInterface
515
     */
516
    public function setRemotes(array $remotes): ConfigInterface
517
    {
518
        foreach ($remotes as $remote) {
519
            $this->setRemote($remote);
0 ignored issues
show
Bug introduced by
It seems like $remote defined by $remote on line 518 can also be of type object<OpenVPN\Types\Remote>; however, OpenVPN\Config::setRemote() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
520
        }
521
522
        return $this;
523
    }
524
525
    /**
526
     * Set scope of unique parameters
527
     *
528
     * @param \OpenVPN\Types\Parameter[]|string[] $parameters
529
     *
530
     * @return \OpenVPN\Interfaces\ConfigInterface
531
     */
532 8
    public function setParams(array $parameters): ConfigInterface
533
    {
534 8
        foreach ($parameters as $name => $value) {
535 1
            $this->set($name, $value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by $value on line 534 can also be of type object<OpenVPN\Types\Parameter>; however, OpenVPN\Config::set() does only seem to accept string|boolean|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
536
        }
537
538 8
        return $this;
539
    }
540
541
    /**
542
     * Export array of all certificates
543
     *
544
     * @return array
545
     */
546 7
    public function getCerts(): array
547
    {
548 7
        return $this->certs;
549
    }
550
551
    /**
552
     * Export array of all pushes
553
     *
554
     * @return array
555
     */
556 4
    public function getPushes(): array
557
    {
558 4
        return $this->pushes;
559
    }
560
561
    /**
562
     * Export array of all routes
563
     *
564
     * @return array
565
     */
566 4
    public function getRoutes(): array
567
    {
568 4
        return $this->routes;
569
    }
570
571
    /**
572
     * Export array of all remotes
573
     *
574
     * @return array
575
     */
576 2
    public function getRemotes(): array
577
    {
578 2
        return $this->remotes;
579
    }
580
581
    /**
582
     * Export array of all parameters
583
     *
584
     * @return array
585
     */
586 5
    public function getParameters(): array
587
    {
588 5
        return $this->parameters;
589
    }
590
}
591