1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace OpenVPN; |
4
|
|
|
|
5
|
|
|
use OpenVPN\Interfaces\ConfigInterface; |
6
|
|
|
|
7
|
|
|
class Config implements ConfigInterface |
8
|
|
|
{ |
9
|
|
|
/** |
10
|
|
|
* Array with all certificates |
11
|
|
|
* @var array |
12
|
|
|
*/ |
13
|
|
|
private $_certs = []; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* List of lines which must be pushed to clients |
17
|
|
|
* @var array |
18
|
|
|
*/ |
19
|
|
|
private $_pushes = []; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* All parameters added via addParam method |
23
|
|
|
* @var array |
24
|
|
|
*/ |
25
|
|
|
private $_params = []; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Generate config by parameters in memory |
29
|
|
|
* |
30
|
|
|
* @return string |
31
|
|
|
*/ |
32
|
|
|
public function generate(): string |
33
|
|
|
{ |
34
|
|
|
// Init the variable |
35
|
|
|
$config = ''; |
36
|
|
|
|
37
|
|
|
foreach ($this->getParams() as $key => $value) { |
38
|
|
|
$config .= $key . ((\strlen($value) > 0) ? ' ' . $value : '') . "\n"; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
$certs = $this->getCerts(); |
42
|
|
|
if (\count($certs) > 0) { |
43
|
|
|
$config .= "\n### Certificates\n"; |
44
|
|
|
foreach ($this->getCerts() as $key => $value) { |
45
|
|
|
$config .= isset($value['content']) |
46
|
|
|
? "<$key>\n{$value['content']}\n</$key>\n" |
47
|
|
|
: "$key {$value['path']}\n"; |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
$pushes = $this->getPushes(); |
52
|
|
|
if (\count($pushes) > 0) { |
53
|
|
|
$config .= "\n### Networking\n"; |
54
|
|
|
foreach ($this->getPushes() as $push) { |
55
|
|
|
$config .= 'push "' . $push . "\"\n"; |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
return $config; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Import content of all listed certificates |
64
|
|
|
*/ |
65
|
|
|
public function importCerts() |
66
|
|
|
{ |
67
|
|
|
foreach ($this->_certs as $cert) { |
68
|
|
|
$cert['content'] = rtrim(file_get_contents($cert['path'])); |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
|
72
|
3 |
|
private function throwIfNotInArray($key, $array) |
73
|
|
|
{ |
74
|
3 |
|
if (!\in_array($key, $array, true)) { |
75
|
|
|
throw new \RuntimeException("Key '$key' not in list of allowed [" . implode(',', $array) . ']'); |
76
|
|
|
} |
77
|
3 |
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Add new cert into the configuration |
81
|
|
|
* |
82
|
|
|
* @param string $type Type of certificate [ca, cert, key, dh, tls-auth] |
83
|
|
|
* @param string $pathOrContent Absolute or relative path to certificate or content of this file |
84
|
|
|
* @param bool if content of file is provided |
85
|
|
|
* @throws \RuntimeException |
86
|
|
|
* @return ConfigInterface |
87
|
|
|
*/ |
88
|
3 |
|
public function addCert(string $type, string $pathOrContent, bool $isContent = false): ConfigInterface |
89
|
|
|
{ |
90
|
3 |
|
$type = mb_strtolower($type); |
91
|
3 |
|
$this->throwIfNotInArray($type, self::CERTS); |
92
|
3 |
|
if (true === $isContent) { |
93
|
1 |
|
$this->_certs[$type]['content'] = $pathOrContent; |
94
|
|
|
} else { |
95
|
3 |
|
$this->_certs[$type]['path'] = $pathOrContent; |
96
|
|
|
} |
97
|
3 |
|
return $this; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Remove selected certificate from array |
102
|
|
|
* |
103
|
|
|
* @param string $type Type of certificate [ca, cert, key, dh, tls-auth] |
104
|
|
|
* @throws \RuntimeException |
105
|
|
|
* @return ConfigInterface |
106
|
|
|
*/ |
107
|
2 |
|
public function delCert(string $type): ConfigInterface |
108
|
|
|
{ |
109
|
2 |
|
$type = mb_strtolower($type); |
110
|
2 |
|
$this->throwIfNotInArray($type, self::CERTS); |
111
|
2 |
|
unset($this->_certs[$type]); |
112
|
2 |
|
return $this; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Return information about specified certificate |
117
|
|
|
* |
118
|
|
|
* @param string $type |
119
|
|
|
* @throws \RuntimeException |
120
|
|
|
* @return array |
121
|
|
|
*/ |
122
|
|
|
public function getCert(string $type): array |
123
|
|
|
{ |
124
|
|
|
$type = mb_strtolower($type); |
125
|
|
|
$this->throwIfNotInArray($type, self::CERTS); |
126
|
|
|
return $this->_certs[$type] ?? []; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Get full list of certificates |
131
|
|
|
* |
132
|
|
|
* @return array |
133
|
|
|
*/ |
134
|
3 |
|
public function getCerts(): array |
135
|
|
|
{ |
136
|
3 |
|
return $this->_certs; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Append new push into the array |
141
|
|
|
* |
142
|
|
|
* @param string $line String with line which must be pushed |
143
|
|
|
* @return ConfigInterface |
144
|
|
|
*/ |
145
|
|
|
public function addPush(string $line): ConfigInterface |
146
|
|
|
{ |
147
|
|
|
$this->_pushes[] = trim($line, '"'); |
148
|
|
|
return $this; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Remove route line from push array |
153
|
|
|
* |
154
|
|
|
* @param string $line String with line which must be pushed |
155
|
|
|
* @return ConfigInterface |
156
|
|
|
*/ |
157
|
|
|
public function delPush(string $line): ConfigInterface |
158
|
|
|
{ |
159
|
|
|
unset($this->_pushes[$line]); |
160
|
|
|
return $this; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Get all pushes from array |
165
|
|
|
* |
166
|
|
|
* @return array |
167
|
|
|
*/ |
168
|
|
|
public function getPushes(): array |
169
|
|
|
{ |
170
|
|
|
return $this->_pushes; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Check if value is boolean, if not then return same string |
175
|
|
|
* |
176
|
|
|
* @param mixed $value |
177
|
|
|
* @return mixed |
178
|
|
|
*/ |
179
|
|
|
private function isBool($value) |
180
|
|
|
{ |
181
|
|
|
if (\is_bool($value)) { |
182
|
|
|
$value = $value ? 'true' : 'false'; |
183
|
|
|
} |
184
|
|
|
return $value; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Add some new parameter to the list of parameters |
189
|
|
|
* |
190
|
|
|
* @example $this->add('client')->add('remote', 'vpn.example.com'); |
191
|
|
|
* @param string $name Name of parameter |
192
|
|
|
* @param string|bool|null $value Value of parameter |
193
|
|
|
* @return ConfigInterface |
194
|
|
|
*/ |
195
|
|
|
public function add(string $name, $value = null): ConfigInterface |
196
|
|
|
{ |
197
|
|
|
$name = mb_strtolower($name); |
198
|
|
|
|
199
|
|
|
// Check if key is certificate or push, or classic parameter |
200
|
|
|
if (\in_array($name, self::CERTS, true)) { |
201
|
|
|
$this->addCert($name, $value); |
|
|
|
|
202
|
|
|
} elseif ($name === 'push') { |
203
|
|
|
$this->addPush($value); |
|
|
|
|
204
|
|
|
} else { |
205
|
|
|
$this->_params[$name] = $this->isBool($value); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
return $this; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Get some custom element |
213
|
|
|
* |
214
|
|
|
* @param string|null $name Name of parameter |
215
|
|
|
* @return mixed |
216
|
|
|
*/ |
217
|
|
|
public function get(string $name) |
218
|
|
|
{ |
219
|
|
|
return $this->_params[$name] ?? null; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Get full list of parameters, or some custom element |
224
|
|
|
* |
225
|
|
|
* @return array |
226
|
|
|
*/ |
227
|
|
|
public function getParams(): array |
228
|
|
|
{ |
229
|
|
|
return $this->_params; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Remove some parameter from array by name |
234
|
|
|
* |
235
|
|
|
* @param string $name Name of parameter |
236
|
|
|
* @throws \RuntimeException |
237
|
|
|
* @return ConfigInterface |
238
|
|
|
*/ |
239
|
|
|
public function del(string $name): ConfigInterface |
240
|
|
|
{ |
241
|
|
|
// Check if key is certificate or push, or classic parameter |
242
|
|
|
if (\in_array($name, self::CERTS, true)) { |
243
|
|
|
$this->delCert($name); |
244
|
|
|
} elseif ($name === 'push') { |
245
|
|
|
throw new \RuntimeException("Not possible to remove push, use 'delPush' instead"); |
246
|
|
|
} else { |
247
|
|
|
$this->_params = array_map( |
248
|
|
|
function($param) use ($name) { |
249
|
|
|
return ($param['name'] === $name) ? null : $param; |
250
|
|
|
}, |
251
|
|
|
$this->_params |
252
|
|
|
); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
return $this; |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|
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.