Completed
Push — master ( c10a26...3a195b )
by Mr
11:23
created

Config::setRemote()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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
     * Array with all certificates
76
     *
77
     * @var array
78
     */
79
    private $certs = [];
80
81
    /**
82
     * List of all routes available on server
83
     *
84
     * @var array
85
     */
86
    private $routes = [];
87
88
    /**
89
     * List of lines which must be pushed to clients
90
     *
91
     * @var array
92
     */
93
    private $pushes = [];
94
95
    /**
96
     * List of lines which can be used as remotes
97
     *
98
     * @var array
99
     */
100
    private $remotes = [];
101
102
    /**
103
     * All parameters added via addParam method
104
     *
105
     * @var array
106
     */
107
    private $parameters = [];
108
109
    /**
110
     * Config constructor.
111
     *
112
     * @param array $parameters List of default parameters
113
     */
114 6
    public function __construct(array $parameters = [])
115
    {
116 6
        $this->setParams($parameters);
117 6
    }
118
119
    /**
120
     * Alias for client line of config
121
     *
122
     * @return \OpenVPN\Interfaces\ConfigInterface
123
     */
124
    public function client(): ConfigInterface
125
    {
126
        return $this->set('client');
127
    }
128
129
    /**
130
     * Import content of all listed certificates
131
     *
132
     * @return void
133
     */
134
    public function loadCertificates(): void
135
    {
136
        foreach ($this->certs as &$cert) {
137
            $cert['content'] = rtrim(file_get_contents($cert['path']));
138
        }
139
    }
140
141
    /**
142
     * Alias to setCert
143
     *
144
     * @deprecated TODO: Delete in future releases
145
     */
146
    public function addCert(string $type, string $pathOrContent, bool $isContent = false): ConfigInterface
147
    {
148
        return $this->setCert($type, $pathOrContent, $isContent);
149
    }
150
151
    /**
152
     * Add new cert into the configuration
153
     *
154
     * @param string    $type      Type of certificate [ca, cert, key, dh, tls-auth]
155
     * @param string    $path      Absolute or relative path to certificate or content of this file
156
     * @param bool|null $isContent If true, then script will try to load file from dist by $path
157
     *
158
     * @return \OpenVPN\Interfaces\ConfigInterface
159
     * @throws \RuntimeException
160
     */
161 6
    public function setCert(string $type, string $path, bool $isContent = null): ConfigInterface
162
    {
163 6
        $type = mb_strtolower($type);
164 6
        Helpers::isCertAllowed($type);
165 6
        if (true === $isContent) {
166 1
            $this->certs[$type]['content'] = $path;
167
        } else {
168 6
            $this->certs[$type]['path'] = $path;
169
        }
170 6
        return $this;
171
    }
172
173
    /**
174
     * Return information about specified certificate
175
     *
176
     * @param string $type
177
     *
178
     * @return array
179
     * @throws \RuntimeException
180
     */
181
    public function getCert(string $type): array
182
    {
183
        $type = mb_strtolower($type);
184
        Helpers::isCertAllowed($type);
185
        return $this->certs[$type] ?? [];
186
    }
187
188
    /**
189
     * Alias to setPush
190
     *
191
     * @deprecated TODO: Delete in future releases
192
     */
193
    public function addPush(string $line): ConfigInterface
194
    {
195
        return $this->setPush($line);
196
    }
197
198
    /**
199
     * Append new push into the array
200
     *
201
     * @param string $line String with line which must be pushed
202
     *
203
     * @return \OpenVPN\Interfaces\ConfigInterface
204
     */
205 3
    public function setPush(string $line): ConfigInterface
206
    {
207 3
        $this->pushes[] = trim($line, '"');
208 3
        return $this;
209
    }
210
211
    /**
212
     * Remove route line from push array
213
     *
214
     * @param string $line String with line which must be pushed
215
     *
216
     * @return \OpenVPN\Interfaces\ConfigInterface
217
     */
218
    public function unsetPush(string $line): ConfigInterface
219
    {
220
        unset($this->pushes[$line]);
221
        return $this;
222
    }
223
224
    /**
225
     * Append new route into the array
226
     *
227
     * @param string $line String with route
228
     *
229
     * @return \OpenVPN\Interfaces\ConfigInterface
230
     */
231 3
    public function setRoute(string $line): ConfigInterface
232
    {
233 3
        $this->routes[] = trim($line, '"');
234 3
        return $this;
235
    }
236
237
    /**
238
     * Remove route line from routes array
239
     *
240
     * @param string $line String with route
241
     *
242
     * @return \OpenVPN\Interfaces\ConfigInterface
243
     */
244
    public function unsetRoute(string $line): ConfigInterface
245
    {
246
        unset($this->routes[$line]);
247
        return $this;
248
    }
249
250
    /**
251
     * Append new push into the array
252
     *
253
     * @param string $line String with line which must be added as remote
254
     *
255
     * @return \OpenVPN\Interfaces\ConfigInterface
256
     */
257
    public function setRemote(string $line): ConfigInterface
258
    {
259
        $this->remotes[] = trim($line, '"');
260
        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
        return $this;
274
    }
275
276
    /**
277
     * Alias to set
278
     *
279
     * @deprecated TODO: Delete in future releases
280
     */
281
    public function add(string $name, $value = null): ConfigInterface
282
    {
283
        return $this->set($name, $value);
284
    }
285
286
    /**
287
     * Add some new parameter to the list of parameters
288
     *
289
     * @param string           $name  Name of parameter
290
     * @param string|bool|null $value Value of parameter
291
     *
292
     * @return \OpenVPN\Interfaces\ConfigInterface
293
     * @example $this->add('client')->add('remote', 'vpn.example.com');
294
     */
295 3
    public function set(string $name, $value = null): ConfigInterface
296
    {
297 3
        $name = mb_strtolower($name);
298
299
        // Check if key is certificate or push, or classic parameter
300 3
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
301 3
            return $this->setCert($name, $value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 295 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...
302
        }
303
304
        // If is push then use add push method
305 3
        if ($name === 'remote') {
306
            return $this->setRemote($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 295 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...
307
        }
308
309
        // If is push then use add push method
310 3
        if ($name === 'push') {
311 3
            return $this->setPush($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 295 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...
312
        }
313
314
        // If is push then use add push method
315 3
        if ($name === 'route') {
316 3
            return $this->setRoute($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 295 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...
317
        }
318
319
        // Check if provided value is boolean and if it's true, then set null (that mean parameter without value)
320 3
        if (is_bool($value) && $value) {
321 3
            if ($value) {
322 3
                $value = null;
323
            } else {
324
                // If false then skip this step
325
                return $this;
326
            }
327
        }
328
329
        // Set new value
330 3
        $this->parameters[$name] = $value;
331
332 3
        return $this;
333
    }
334
335
    /**
336
     * Get some custom element
337
     *
338
     * @param string|null $name Name of parameter
339
     *
340
     * @return mixed
341
     */
342
    public function get(string $name)
343
    {
344
        return $this->parameters[$name] ?? null;
345
    }
346
347
    /**
348
     * Generate config by parameters in memory
349
     *
350
     * @param string $type Type of generated config: raw (default), json
351
     *
352
     * @return array|string|null
353
     */
354 1
    public function generate(string $type = 'raw')
355
    {
356 1
        $generator = new Generator($this);
357 1
        return $generator->generate($type);
358
    }
359
360
    /**
361
     * @param string $name
362
     *
363
     * @return bool
364
     */
365
    public function __isset(string $name): bool
366
    {
367
        // Inform about deleting push
368
        if ($name === 'push') {
369
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
370
        }
371
372
        // Inform about deleting route
373
        if ($name === 'route') {
374
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
375
        }
376
377
        // Inform about deleting route
378
        if ($name === 'remote') {
379
            throw new RuntimeException("Not possible to remove remote, use 'unsetRemote' instead");
380
        }
381
382
        return isset($this->parameters[$name]);
383
    }
384
385
    /**
386
     * @param string                   $name
387
     * @param string|bool|integer|null $value
388
     */
389 3
    public function __set(string $name, $value = null): void
390
    {
391 3
        $name = Helpers::decamelize($name);
392 3
        $this->set($name, $value);
393 3
    }
394
395
    /**
396
     * @param string $name
397
     *
398
     * @return string|bool|null
399
     */
400
    public function __get(string $name)
401
    {
402
        return $this->get($name);
403
    }
404
405
    /**
406
     * Remove some parameter from array by name
407
     *
408
     * @param string $name Name of parameter
409
     *
410
     * @return void
411
     * @throws \RuntimeException
412
     */
413
    public function __unset(string $name)
414
    {
415
        // Inform about deleting push
416
        if ($name === 'push') {
417
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
418
        }
419
420
        // Inform about deleting route
421
        if ($name === 'route') {
422
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
423
        }
424
425
        // Inform about deleting route
426
        if ($name === 'remote') {
427
            throw new RuntimeException("Not possible to remove remote, use 'unsetRemote' instead");
428
        }
429
430
        // Check if key is certificate or push, or classic parameter
431
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
432
            $this->unsetCert($name);
433
            return;
434
        }
435
436
        // Update list of parameters
437
        $this->parameters = array_map(
438
            static function ($param) use ($name) {
439
                return ($param['name'] === $name) ? null : $param;
440
            },
441
            $this->parameters
442
        );
443
    }
444
445
    /**
446
     * Remove selected certificate from array
447
     *
448
     * @param string $type Type of certificate [ca, cert, key, dh, tls-auth]
449
     *
450
     * @return \OpenVPN\Interfaces\ConfigInterface
451
     * @throws \RuntimeException
452
     */
453 2
    public function unsetCert(string $type): ConfigInterface
454
    {
455 2
        $type = mb_strtolower($type);
456 2
        Helpers::isCertAllowed($type);
457 2
        unset($this->certs[$type]);
458 2
        return $this;
459
    }
460
461
    /**
462
     * Set scope of certs
463
     *
464
     * @param \OpenVPN\Types\Cert[] $certs
465
     * @param bool                  $loadCertificates
466
     *
467
     * @return \OpenVPN\Interfaces\ConfigInterface
468
     */
469 3
    public function setCerts(array $certs, bool $loadCertificates = false): ConfigInterface
470
    {
471
        // Pass list of certs from array to variable
472 3
        foreach ($certs as $type => $path) {
473 3
            $this->setCert($type, $path);
0 ignored issues
show
Documentation introduced by
$path is of type object<OpenVPN\Types\Cert>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
474
        }
475
476
        // If need to load content of files from disk
477 3
        if ($loadCertificates) {
478
            $this->loadCertificates();
479
        }
480
481 3
        return $this;
482
    }
483
484
    /**
485
     * Set scope of unique pushes
486
     *
487
     * @param \OpenVPN\Types\Push[] $pushes
488
     *
489
     * @return \OpenVPN\Interfaces\ConfigInterface
490
     */
491 3
    public function setPushes(array $pushes): ConfigInterface
492
    {
493 3
        foreach ($pushes as $push) {
494 3
            $this->setPush($push);
0 ignored issues
show
Documentation introduced by
$push is of type object<OpenVPN\Types\Push>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
495
        }
496
497 3
        return $this;
498
    }
499
500
    /**
501
     * Set scope of unique routes
502
     *
503
     * @param \OpenVPN\Types\Route[] $routes
504
     *
505
     * @return \OpenVPN\Interfaces\ConfigInterface
506
     */
507 3
    public function setRoutes(array $routes): ConfigInterface
508
    {
509 3
        foreach ($routes as $route) {
510 3
            $this->setRoute($route);
0 ignored issues
show
Documentation introduced by
$route is of type object<OpenVPN\Types\Route>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
511
        }
512
513 3
        return $this;
514
    }
515
516
    /**
517
     * Set scope of unique remotes
518
     *
519
     * @param \OpenVPN\Types\Remote[] $remotes
520
     *
521
     * @return \OpenVPN\Interfaces\ConfigInterface
522
     */
523
    public function setRemotes(array $remotes): ConfigInterface
524
    {
525
        foreach ($remotes as $remote) {
526
            $this->setRemote($remote);
0 ignored issues
show
Documentation introduced by
$remote is of type object<OpenVPN\Types\Remote>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
527
        }
528
529
        return $this;
530
    }
531
532
    /**
533
     * Set scope of unique parameters
534
     *
535
     * @param \OpenVPN\Types\Parameter[] $parameters
536
     *
537
     * @return \OpenVPN\Interfaces\ConfigInterface
538
     */
539 6
    public function setParams(array $parameters): ConfigInterface
540
    {
541 6
        foreach ($parameters as $name => $value) {
542
            $this->set($name, $value);
0 ignored issues
show
Documentation introduced by
$value is of type object<OpenVPN\Types\Parameter>, but the function expects a string|boolean|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
543
        }
544
545 6
        return $this;
546
    }
547
548
    /**
549
     * Export array of all certificates
550
     *
551
     * @return array
552
     */
553 6
    public function getCerts(): array
554
    {
555 6
        return $this->certs;
556
    }
557
558
    /**
559
     * Export array of all pushes
560
     *
561
     * @return array
562
     */
563 3
    public function getPushes(): array
564
    {
565 3
        return $this->pushes;
566
    }
567
568
    /**
569
     * Export array of all routes
570
     *
571
     * @return array
572
     */
573 3
    public function getRoutes(): array
574
    {
575 3
        return $this->routes;
576
    }
577
578
    /**
579
     * Export array of all remotes
580
     *
581
     * @return array
582
     */
583 1
    public function getRemotes(): array
584
    {
585 1
        return $this->remotes;
586
    }
587
588
    /**
589
     * Export array of all parameters
590
     *
591
     * @return array
592
     */
593 3
    public function getParameters(): array
594
    {
595 3
        return $this->parameters;
596
    }
597
}
598