1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* src/SecurityTxtHelper.php. |
4
|
|
|
* |
5
|
|
|
* @author Austin Heap <[email protected]> |
6
|
|
|
* @version v0.3.2 |
7
|
|
|
*/ |
8
|
|
|
declare(strict_types = 1); |
9
|
|
|
|
10
|
|
|
namespace AustinHeap\Security\Txt; |
11
|
|
|
|
12
|
|
|
use Exception; |
13
|
|
|
use Log; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* SecurityTxtHelper. |
17
|
|
|
* |
18
|
|
|
* @link https://github.com/austinheap/laravel-security-txt |
19
|
|
|
* @link https://packagist.org/packages/austinheap/laravel-security-txt |
20
|
|
|
* @link https://austinheap.github.io/laravel-security-txt/classes/AustinHeap.Security.Txt.SecurityTxtHelper.html |
21
|
|
|
*/ |
22
|
|
|
class SecurityTxtHelper |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* Internal version number. |
26
|
|
|
* |
27
|
|
|
* @var string |
28
|
|
|
*/ |
29
|
|
|
const VERSION = '0.3.0'; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Enable the package. |
33
|
|
|
* |
34
|
|
|
* @var bool |
35
|
|
|
*/ |
36
|
|
|
protected $enabled = null; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Internal SecurityTxt object. |
40
|
|
|
* |
41
|
|
|
* @var \AustinHeap\Security\Txt\Writer |
42
|
|
|
*/ |
43
|
|
|
protected $writer = null; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Internal array of log entries. |
47
|
|
|
* |
48
|
|
|
* @var array |
49
|
|
|
*/ |
50
|
|
|
protected $logEntries = []; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Enable built-in cache. |
54
|
|
|
* |
55
|
|
|
* @var bool |
56
|
|
|
*/ |
57
|
|
|
protected $cache = false; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Minutes to cache output. |
61
|
|
|
* |
62
|
|
|
* @var int |
63
|
|
|
*/ |
64
|
|
|
protected $cacheTime = null; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Cache key to use. |
68
|
|
|
* |
69
|
|
|
* @var string |
70
|
|
|
*/ |
71
|
|
|
protected $cacheKey = 'cache:AustinHeap\Security\Txt\SecurityTxt'; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Create a new SecurityTxtHelper instance. |
75
|
|
|
* |
76
|
|
|
* @return SecurityTxtHelper |
77
|
|
|
*/ |
78
|
|
|
public function __construct() |
79
|
|
|
{ |
80
|
|
|
$this->buildWriter(); |
81
|
|
|
|
82
|
|
|
return $this; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Returns the default config key => php-security-txt mappings. |
87
|
|
|
* |
88
|
|
|
* @return array |
89
|
|
|
*/ |
90
|
|
|
public static function buildWriterDefaultKeys() |
91
|
|
|
{ |
92
|
|
|
return [ |
93
|
|
|
'security-txt.enabled' => ['validator' => 'is_bool', 'setter' => 'setEnabled', 'self' => true], |
94
|
|
|
'security-txt.debug' => ['validator' => 'is_bool', 'setter' => 'setDebug'], |
95
|
|
|
'security-txt.cache' => ['validator' => 'is_bool', 'setter' => 'setCache', 'self' => true], |
96
|
|
|
'security-txt.cache-time' => ['validator' => 'is_numeric', 'setter' => 'setCacheTime', 'self' => true], |
97
|
|
|
'security-txt.cache-key' => ['validator' => 'is_string', 'setter' => 'setCacheKey', 'self' => true], |
98
|
|
|
'security-txt.comments' => ['validator' => 'is_bool', 'setter' => 'setComments'], |
99
|
|
|
'security-txt.contacts' => ['validator' => 'is_array', 'setter' => 'addContacts'], |
100
|
|
|
'security-txt.encryption' => ['validator' => 'is_string', 'setter' => 'setEncryption'], |
101
|
|
|
'security-txt.disclosure' => ['validator' => 'is_string', 'setter' => 'setDisclosure'], |
102
|
|
|
'security-txt.acknowledgement' => ['validator' => 'is_string', 'setter' => 'setAcknowledgement'], |
103
|
|
|
]; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Builds the internal SecurityTxt Writer. |
108
|
|
|
* |
109
|
|
|
* @param array $keys |
110
|
|
|
* |
111
|
|
|
* @return SecurityTxtHelper |
112
|
|
|
*/ |
113
|
|
|
public function buildWriter(array $keys = null): self |
114
|
|
|
{ |
115
|
|
|
$this->writer = new Writer(); |
116
|
|
|
|
117
|
|
|
$keys = is_array($keys) ? $keys : self::buildWriterDefaultKeys(); |
118
|
|
|
|
119
|
|
|
foreach ($keys as $key => $mapping) { |
120
|
|
|
if (is_null(config($key, null))) { |
121
|
|
|
$this->addLogEntry('"' . __CLASS__ . '" cannot process null value for key "' . $key . '".', 'debug'); |
122
|
|
|
continue; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
View Code Duplication |
if (!function_exists($mapping['validator'])) { |
|
|
|
|
126
|
|
|
$this->addLogEntry('"' . __CLASS__ . '" cannot find "validator" function named "' . $mapping['validator'] . '".', |
127
|
|
|
'warning'); |
128
|
|
|
continue; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
View Code Duplication |
if (!$mapping['validator'](config($key))) { |
|
|
|
|
132
|
|
|
$this->addLogEntry('"' . __CLASS__ . '" failed the "validator" function named "' . $mapping['validator'] . '".', |
133
|
|
|
'warning'); |
134
|
|
|
continue; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
if (array_key_exists('self', $mapping) && |
138
|
|
|
is_bool($mapping['self']) && |
139
|
|
|
$mapping['self'] === true) { |
140
|
|
View Code Duplication |
if (!method_exists($this, $mapping['setter'])) { |
|
|
|
|
141
|
|
|
$this->addLogEntry('"' . __CLASS__ . '" cannot find mapping "setter" method on object "' . get_class($this) . '" named "' . $mapping['setter'] . '".', |
142
|
|
|
'error'); |
143
|
|
|
continue; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
$this->{$mapping['setter']}(config($key)); |
147
|
|
|
} else { |
148
|
|
View Code Duplication |
if (!method_exists($this->writer, $mapping['setter'])) { |
|
|
|
|
149
|
|
|
$this->addLogEntry('"' . __CLASS__ . '" cannot find mapping "setter" method on object "' . get_class($this->writer) . '" named "' . $mapping['setter'] . '".', |
150
|
|
|
'error'); |
151
|
|
|
continue; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
$this->writer->{$mapping['setter']}(config($key)); |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
return $this; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Add log entry. |
163
|
|
|
* |
164
|
|
|
* @param string $text |
165
|
|
|
* @param string $level |
166
|
|
|
* |
167
|
|
|
* @return SecurityTxtHelper |
168
|
|
|
*/ |
169
|
|
|
public function addLogEntry(string $text, string $level = 'debug'): self |
170
|
|
|
{ |
171
|
|
|
Log::$level($text); |
172
|
|
|
|
173
|
|
|
$this->logEntries[] = ['text' => $text, 'level' => $level]; |
174
|
|
|
|
175
|
|
|
return $this; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Add log entries. |
180
|
|
|
* |
181
|
|
|
* @return array |
182
|
|
|
*/ |
183
|
|
|
public function getLogEntries(): array |
184
|
|
|
{ |
185
|
|
|
return $this->logEntries; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Clears log entries. |
190
|
|
|
* |
191
|
|
|
* @return SecurityTxtHelper |
192
|
|
|
*/ |
193
|
|
|
public function clearLogEntries(): self |
194
|
|
|
{ |
195
|
|
|
$this->logEntries = []; |
196
|
|
|
|
197
|
|
|
return $this; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Fetches the raw text of the document. |
202
|
|
|
* |
203
|
|
|
* @return SecurityTxtHelper |
204
|
|
|
*/ |
205
|
|
|
public function fetch(): string |
206
|
|
|
{ |
207
|
|
|
if ($this->cache) { |
208
|
|
|
$text = cache($this->cacheKey, null); |
209
|
|
|
|
210
|
|
|
if (!is_null($text)) { |
211
|
|
|
return $text; |
|
|
|
|
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
$text = $this->writer |
216
|
|
|
->execute() |
217
|
|
|
->getText(); |
218
|
|
|
|
219
|
|
|
if ($this->writer->getDebug()) { |
220
|
|
|
$text .= '# Cache is ' . ($this->cache ? 'enabled with key "' . $this->cacheKey . '"' : 'disabled') . '.' . PHP_EOL . |
221
|
|
|
'#' . PHP_EOL; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
if ($this->cache) { |
225
|
|
|
cache([$this->cacheKey => $text], now()->addMinutes($this->cacheTime)); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
return empty($text) ? '' : $text; |
|
|
|
|
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Enable the enabled flag. |
233
|
|
|
* |
234
|
|
|
* @return SecurityTxtHelper |
235
|
|
|
*/ |
236
|
|
|
public function enable(): self |
237
|
|
|
{ |
238
|
|
|
return $this->setEnabled(true); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Disable the enabled flag. |
243
|
|
|
* |
244
|
|
|
* @return SecurityTxtHelper |
245
|
|
|
*/ |
246
|
|
|
public function disable(): self |
247
|
|
|
{ |
248
|
|
|
return $this->setEnabled(false); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Set the enabled flag. |
253
|
|
|
* |
254
|
|
|
* @param bool $enabled |
255
|
|
|
* |
256
|
|
|
* @return SecurityTxtHelper |
257
|
|
|
*/ |
258
|
|
|
public function setEnabled(bool $enabled): self |
259
|
|
|
{ |
260
|
|
|
$this->enabled = $enabled; |
261
|
|
|
|
262
|
|
|
return $this; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Get the enabled flag. |
267
|
|
|
* |
268
|
|
|
* @return bool |
269
|
|
|
*/ |
270
|
|
|
public function getEnabled(): bool |
271
|
|
|
{ |
272
|
|
|
return is_null($this->enabled) ? false : $this->enabled; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Enable the cache flag. |
277
|
|
|
* |
278
|
|
|
* @return SecurityTxtHelper |
279
|
|
|
*/ |
280
|
|
|
public function enableCache(): self |
281
|
|
|
{ |
282
|
|
|
return $this->setCache(true); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Disable the cache flag. |
287
|
|
|
* |
288
|
|
|
* @return SecurityTxtHelper |
289
|
|
|
*/ |
290
|
|
|
public function disableCache(): self |
291
|
|
|
{ |
292
|
|
|
return $this->setCache(false); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Set the cache flag. |
297
|
|
|
* |
298
|
|
|
* @param bool $cache |
299
|
|
|
* |
300
|
|
|
* @return SecurityTxtHelper |
301
|
|
|
*/ |
302
|
|
|
public function setCache(bool $cache): self |
303
|
|
|
{ |
304
|
|
|
$this->cache = $cache; |
305
|
|
|
|
306
|
|
|
return $this; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Get the cache flag. |
311
|
|
|
* |
312
|
|
|
* @return bool |
313
|
|
|
*/ |
314
|
|
|
public function getCache(): bool |
315
|
|
|
{ |
316
|
|
|
return $this->cache; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Clear the cache. |
321
|
|
|
* |
322
|
|
|
* @return SecurityTxtHelper |
323
|
|
|
*/ |
324
|
|
|
public function clearCache(): self |
325
|
|
|
{ |
326
|
|
|
cache()->delete($this->cacheKey); |
327
|
|
|
|
328
|
|
|
return $this; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* Set the cache key. |
333
|
|
|
* |
334
|
|
|
* @param string $cacheKey |
335
|
|
|
* |
336
|
|
|
* @return SecurityTxtHelper |
337
|
|
|
*/ |
338
|
|
|
public function setCacheKey(string $cacheKey): self |
339
|
|
|
{ |
340
|
|
|
$this->cacheKey = $cacheKey; |
341
|
|
|
|
342
|
|
|
return $this; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Get the cache key. |
347
|
|
|
* |
348
|
|
|
* @return string |
349
|
|
|
*/ |
350
|
|
|
public function getCacheKey(): string |
351
|
|
|
{ |
352
|
|
|
return $this->cacheKey; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Set the cache time. |
357
|
|
|
* |
358
|
|
|
* @param int $cacheTime |
359
|
|
|
* |
360
|
|
|
* @return SecurityTxtHelper |
361
|
|
|
*/ |
362
|
|
|
public function setCacheTime(int $cacheTime): self |
363
|
|
|
{ |
364
|
|
|
$this->cacheTime = $cacheTime; |
365
|
|
|
|
366
|
|
|
return $this; |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
/** |
370
|
|
|
* Get the cache time. |
371
|
|
|
* |
372
|
|
|
* @return int |
373
|
|
|
*/ |
374
|
|
|
public function getCacheTime(): int |
375
|
|
|
{ |
376
|
|
|
return $this->cacheTime; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* Determines if a SecurityTxt Writer is set. |
381
|
|
|
* |
382
|
|
|
* @return bool |
383
|
|
|
*/ |
384
|
|
|
public function hasWriter(): bool |
385
|
|
|
{ |
386
|
|
|
return !is_null($this->writer); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Gets the internal SecurityTxt Writer. |
391
|
|
|
* |
392
|
|
|
* @return Writer |
393
|
|
|
*/ |
394
|
|
|
public function getWriter(): Writer |
395
|
|
|
{ |
396
|
|
|
if (!$this->hasWriter()) { |
397
|
|
|
throw new Exception('Writer not set.'); |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
return $this->writer; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* Sets the internal SecurityTxt Writer. |
405
|
|
|
* |
406
|
|
|
* @param Writer|null $writer |
407
|
|
|
* |
408
|
|
|
* @return SecurityTxtHelper |
409
|
|
|
*/ |
410
|
|
|
public function setWriter($writer): self |
411
|
|
|
{ |
412
|
|
|
$this->writer = $writer; |
413
|
|
|
|
414
|
|
|
return $this; |
415
|
|
|
} |
416
|
|
|
} |
417
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.