Completed
Push — master ( 532b1f...89ab0b )
by Mr
04:53 queued 11s
created

Config   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 450
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 29.31%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 2
dl 0
loc 450
ccs 17
cts 58
cp 0.2931
rs 8.64
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A client() 0 4 1
A loadCertificates() 0 6 2
A addCert() 0 4 1
A setCert() 0 11 2
A getCert() 0 6 1
A addPush() 0 4 1
A setPush() 0 5 1
A unsetPush() 0 5 1
A setRoute() 0 5 1
A unsetRoute() 0 5 1
A add() 0 4 1
B set() 0 34 7
A get() 0 4 1
A generate() 0 5 1
A __isset() 0 14 3
A __set() 0 5 1
A __get() 0 4 1
A __unset() 0 26 5
A unsetCert() 0 7 1
A setCerts() 0 14 3
A setPushes() 0 8 2
A setRoutes() 0 8 2
A setParams() 0 8 2
A getCerts() 0 4 1
A getPushes() 0 4 1
A getRoutes() 0 4 1
A getParameters() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Config often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Config, and based on these observations, apply Extract Interface, too.

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 bool|null $persistKey
50
 * @property bool|null $persistTun
51
 * @property bool|null $compLzo             Use fast LZO compression — may add up to 1 byte per packet for incompressible data.
52
 * @property bool|null $compNoadapt         When used in conjunction with –comp-lzo, this option will disable OpenVPN’s adaptive compression algorithm.
53
 * @property integer   $verb                Set output verbosity to n(default=1). Each level shows all info from the previous levels: 0,1,2 ... 11
54
 * @property string    $server              A helper directive designed to simplify the configuration of OpenVPN’s server mode.
55
 * @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.
56
 * @property string    $keepalive
57
 * @property integer   $renegSec
58
 * @property string    $user
59
 * @property string    $group
60
 * @property string    $mute
61
 * @property string    $status
62
 * @property string    $logAppend
63
 * @property string    $clientConfigDir
64
 * @property string    $scriptSecurity
65
 * @property string    $usernameAsCommonName
66
 * @property string    $verifyClientCert
67
 *
68
 * @package OpenVPN
69
 */
70
class Config implements ConfigInterface, GeneratorInterface
71
{
72 3
    /**
73
     * Array with all certificates
74 3
     *
75
     * @var array
76
     */
77 3
    private $certs = [];
78
79
    /**
80
     * List of all routes available on server
81
     *
82
     * @var array
83
     */
84
    private $routes = [];
85
86
    /**
87
     * List of lines which must be pushed to clients
88 3
     *
89
     * @var array
90 3
     */
91 3
    private $pushes = [];
92 3
93 1
    /**
94
     * All parameters added via addParam method
95 3
     *
96
     * @var array
97 3
     */
98
    private $parameters = [];
99
100
    /**
101
     * Config constructor.
102
     *
103
     * @param array $parameters List of default parameters
104
     */
105
    public function __construct(array $parameters = [])
106
    {
107 2
        $this->setParams($parameters);
108
    }
109 2
110 2
    /**
111 2
     * Alias for client line of config
112 2
     *
113
     * @return \OpenVPN\Interfaces\ConfigInterface
114
     */
115
    public function client(): ConfigInterface
116
    {
117
        return $this->set('client');
118
    }
119
120
    /**
121
     * Import content of all listed certificates
122
     *
123
     * @return void
124
     */
125
    public function loadCertificates(): void
126
    {
127
        foreach ($this->certs as $cert) {
128
            $cert['content'] = rtrim(file_get_contents($cert['path']));
129
        }
130
    }
131
132
    /**
133
     * Alias to setCert
134 3
     *
135
     * @deprecated TODO: Delete in future releases
136 3
     */
137
    public function addCert(string $type, string $pathOrContent, bool $isContent = false): ConfigInterface
138
    {
139
        return $this->setCert($type, $pathOrContent, $isContent);
140
    }
141
142
    /**
143
     * Add new cert into the configuration
144
     *
145
     * @param string    $type      Type of certificate [ca, cert, key, dh, tls-auth]
146
     * @param string    $path      Absolute or relative path to certificate or content of this file
147
     * @param bool|null $isContent If true, then script will try to load file from dist by $path
148
     *
149
     * @return \OpenVPN\Interfaces\ConfigInterface
150
     * @throws \RuntimeException
151
     */
152
    public function setCert(string $type, string $path, bool $isContent = null): ConfigInterface
153
    {
154
        $type = mb_strtolower($type);
155
        Helpers::isCertAllowed($type);
156
        if (true === $isContent) {
157
            $this->certs[$type]['content'] = $path;
158
        } else {
159
            $this->certs[$type]['path'] = $path;
160
        }
161
        return $this;
162
    }
163
164
    /**
165
     * Return information about specified certificate
166
     *
167
     * @param string $type
168
     *
169
     * @return array
170
     * @throws \RuntimeException
171
     */
172
    public function getCert(string $type): array
173
    {
174
        $type = mb_strtolower($type);
175
        Helpers::isCertAllowed($type);
176
        return $this->certs[$type] ?? [];
177
    }
178
179
    /**
180
     * Alias to setPush
181
     *
182
     * @deprecated TODO: Delete in future releases
183
     */
184
    public function addPush(string $line): ConfigInterface
185
    {
186
        return $this->setPush($line);
187
    }
188
189
    /**
190
     * Append new push into the array
191
     *
192
     * @param string $line String with line which must be pushed
193
     *
194
     * @return \OpenVPN\Interfaces\ConfigInterface
195
     */
196
    public function setPush(string $line): ConfigInterface
197
    {
198
        $this->pushes[] = trim($line, '"');
199
        return $this;
200
    }
201
202
    /**
203
     * Remove route line from push array
204
     *
205
     * @param string $line String with line which must be pushed
206
     *
207
     * @return \OpenVPN\Interfaces\ConfigInterface
208
     */
209
    public function unsetPush(string $line): ConfigInterface
210
    {
211
        unset($this->pushes[$line]);
212
        return $this;
213
    }
214
215
    /**
216
     * Append new route into the array
217
     *
218
     * @param string $line String with route
219
     *
220
     * @return \OpenVPN\Interfaces\ConfigInterface
221
     */
222
    public function setRoute(string $line): ConfigInterface
223
    {
224
        $this->routes[] = trim($line, '"');
225
        return $this;
226
    }
227
228
    /**
229
     * Remove route line from routes array
230
     *
231
     * @param string $line String with route
232
     *
233
     * @return \OpenVPN\Interfaces\ConfigInterface
234
     */
235
    public function unsetRoute(string $line): ConfigInterface
236
    {
237
        unset($this->routes[$line]);
238
        return $this;
239
    }
240
241
    /**
242
     * Alias to set
243
     *
244
     * @deprecated TODO: Delete in future releases
245
     */
246
    public function add(string $name, $value = null): ConfigInterface
247
    {
248
        return $this->set($name, $value);
249
    }
250
251
    /**
252
     * Add some new parameter to the list of parameters
253
     *
254
     * @param string           $name  Name of parameter
255
     * @param string|bool|null $value Value of parameter
256
     *
257
     * @return \OpenVPN\Interfaces\ConfigInterface
258
     * @example $this->add('client')->add('remote', 'vpn.example.com');
259
     */
260
    public function set(string $name, $value = null): ConfigInterface
261
    {
262
        $name = mb_strtolower($name);
263
264
        // Check if key is certificate or push, or classic parameter
265
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
266
            return $this->setCert($name, $value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 260 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...
267
        }
268
269
        // If is push then use add push method
270
        if ($name === 'push') {
271
            return $this->setPush($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 260 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...
272
        }
273
274
        // If is push then use add push method
275
        if ($name === 'route') {
276
            return $this->setRoute($value);
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 260 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...
277
        }
278
279
        // Check if provided value is boolean and if it's true, then set null (that mean parameter without value)
280
        if (is_bool($value) && $value) {
281
            if ($value) {
282
                $value = null;
283
            } else {
284
                // If false then skip this step
285
                return $this;
286
            }
287
        }
288
289
        // Set new value
290
        $this->parameters[$name] = $value;
291
292
        return $this;
293
    }
294
295
    /**
296
     * Get some custom element
297
     *
298
     * @param string|null $name Name of parameter
299
     *
300
     * @return mixed
301
     */
302
    public function get(string $name)
303
    {
304
        return $this->parameters[$name] ?? null;
305
    }
306
307
    /**
308
     * Generate config by parameters in memory
309
     *
310
     * @return string
311
     */
312
    public function generate(): string
313
    {
314
        $generator = new Generator($this);
315
        return $generator->generate();
316
    }
317
318
    /**
319
     * @param string $name
320
     *
321
     * @return bool
322
     */
323
    public function __isset(string $name): bool
324
    {
325
        // Inform about deleting push
326
        if ($name === 'push') {
327
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
328
        }
329
330
        // Inform about deleting route
331
        if ($name === 'route') {
332
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
333
        }
334
335
        return isset($this->parameters[$name]);
336
    }
337
338
    /**
339
     * @param string                   $name
340
     * @param string|bool|integer|null $value
341
     */
342
    public function __set(string $name, $value = null): void
343
    {
344
        $name = Helpers::decamelize($name);
345
        $this->set($name, $value);
346
    }
347
348
    /**
349
     * @param string $name
350
     *
351
     * @return string|bool|null
352
     */
353
    public function __get(string $name)
354
    {
355
        return $this->get($name);
356
    }
357
358
    /**
359
     * Remove some parameter from array by name
360
     *
361
     * @param string $name Name of parameter
362
     *
363
     * @return void
364
     * @throws \RuntimeException
365
     */
366
    public function __unset(string $name)
367
    {
368
        // Inform about deleting push
369
        if ($name === 'push') {
370
            throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead");
371
        }
372
373
        // Inform about deleting route
374
        if ($name === 'route') {
375
            throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead");
376
        }
377
378
        // Check if key is certificate or push, or classic parameter
379
        if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) {
380
            $this->unsetCert($name);
381
            return;
382
        }
383
384
        // Update list of parameters
385
        $this->parameters = array_map(
386
            static function ($param) use ($name) {
387
                return ($param['name'] === $name) ? null : $param;
388
            },
389
            $this->parameters
390
        );
391
    }
392
393
    /**
394
     * Remove selected certificate from array
395
     *
396
     * @param string $type Type of certificate [ca, cert, key, dh, tls-auth]
397
     *
398
     * @return \OpenVPN\Interfaces\ConfigInterface
399
     * @throws \RuntimeException
400
     */
401
    public function unsetCert(string $type): ConfigInterface
402
    {
403
        $type = mb_strtolower($type);
404
        Helpers::isCertAllowed($type);
405
        unset($this->certs[$type]);
406
        return $this;
407
    }
408
409
    /**
410
     * Set scope of certs
411
     *
412
     * @param \OpenVPN\Types\Cert[] $certs
413
     * @param bool                  $loadCertificates
414
     *
415
     * @return \OpenVPN\Interfaces\ConfigInterface
416
     */
417
    public function setCerts(array $certs, bool $loadCertificates = false): ConfigInterface
418
    {
419
        // Pass list of certs from array to variable
420
        foreach ($certs as $type => $path) {
421
            $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...
422
        }
423
424
        // If need to load content of files from disk
425
        if ($loadCertificates) {
426
            $this->loadCertificates();
427
        }
428
429
        return $this;
430
    }
431
432
    /**
433
     * Set scope of unique pushes
434
     *
435
     * @param \OpenVPN\Types\Push[] $pushes
436
     *
437
     * @return \OpenVPN\Interfaces\ConfigInterface
438
     */
439
    public function setPushes(array $pushes): ConfigInterface
440
    {
441
        foreach ($pushes as $push) {
442
            $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...
443
        }
444
445
        return $this;
446
    }
447
448
    /**
449
     * Set scope of unique routes
450
     *
451
     * @param \OpenVPN\Types\Route[] $routes
452
     *
453
     * @return \OpenVPN\Interfaces\ConfigInterface
454
     */
455
    public function setRoutes(array $routes): ConfigInterface
456
    {
457
        foreach ($routes as $route) {
458
            $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...
459
        }
460
461
        return $this;
462
    }
463
464
    /**
465
     * Set scope of unique parameters
466
     *
467
     * @param \OpenVPN\Types\Parameter[] $parameters
468
     *
469
     * @return \OpenVPN\Interfaces\ConfigInterface
470
     */
471
    public function setParams(array $parameters): ConfigInterface
472
    {
473
        foreach ($parameters as $name => $value) {
474
            $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...
475
        }
476
477
        return $this;
478
    }
479
480
    /**
481
     * Export array of all certificates
482
     *
483
     * @return array
484
     */
485
    public function getCerts(): array
486
    {
487
        return $this->certs;
488
    }
489
490
    /**
491
     * Export array of all pushes
492
     *
493
     * @return array
494
     */
495
    public function getPushes(): array
496
    {
497
        return $this->pushes;
498
    }
499
500
    /**
501
     * Export array of all routes
502
     *
503
     * @return array
504
     */
505
    public function getRoutes(): array
506
    {
507
        return $this->routes;
508
    }
509
510
    /**
511
     * Export array of all parameters
512
     *
513
     * @return array
514
     */
515
    public function getParameters(): array
516
    {
517
        return $this->parameters;
518
    }
519
}
520