Issues (4)

src/SecurityTxtHelper.php (3 issues)

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