Firewall   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 267
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 21
eloc 81
c 6
b 0
f 0
dl 0
loc 267
ccs 85
cts 85
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setupChannel() 0 7 2
A run() 0 35 6
A controlPanel() 0 9 2
A configure() 0 24 5
A enablePerformanceReport() 0 13 1
A setup() 0 29 2
A add() 0 3 1
A refreshRequest() 0 3 1
1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * php version 7.1.0
11
 *
12
 * @category  Web-security
13
 * @package   Shieldon
14
 * @author    Terry Lin <[email protected]>
15
 * @copyright 2019 terrylinooo
16
 * @license   https://github.com/terrylinooo/shieldon/blob/2.x/LICENSE MIT
17
 * @link      https://github.com/terrylinooo/shieldon
18
 * @see       https://shieldon.io
19
 */
20
21
declare(strict_types=1);
22
23
namespace Shieldon\Firewall;
24
25
use Psr\Http\Message\ServerRequestInterface;
26
use Psr\Http\Message\ResponseInterface;
27
use Psr\Http\Server\MiddlewareInterface;
28
use Shieldon\Firewall\Kernel\Enum;
29
use Shieldon\Firewall\HttpFactory;
30
use Shieldon\Firewall\Container;
31
use Shieldon\Firewall\FirewallTrait;
32
use Shieldon\Firewall\Firewall\SetupTrait;
33
use Shieldon\Firewall\Firewall\Messenger\MessengerTrait;
34
use Shieldon\Firewall\Firewall\XssProtectionTrait;
35
use Shieldon\Psr15\RequestHandler;
36
use Shieldon\Event\Event;
37
use function Shieldon\Firewall\get_request;
38
use function defined;
39
use function file_exists;
40
use function file_get_contents;
41
use function json_decode;
42
use function rtrim;
43
44
/**
45
 * Managed Firewall.
46
 */
47
class Firewall
48
{
49
    /**
50
     *   Public methods       | Desctiotion
51
     *  ----------------------|---------------------------------------------
52
     *   setup                | Apply all setup proccesses.
53
     *   configure            | The absolute path of a dictionary for storing data.
54
     *   run                  | Execute the firewall.
55
     *   add                  | Add a PRS-15 middleware used before firewall.
56
     *   controlPanel         | Set the base URL of the control panel.
57
     *   enablePerformanceRe- | Display the performance report when dialog is showed.
58
     *   port                 |
59
     *  ----------------------|---------------------------------------------
60
     */
61
62
    /**
63
     *   Public methods       | Desctiotion
64
     *  ----------------------|---------------------------------------------
65
     *   getKernel            | Get the Shieldon Kernel instance.
66
     *   getConfiguration     | Get the configuration data.
67
     *   getDirectory         | Get the dictionary where the data is stored.
68
     *   getFileName          | Get the path of the configuration file.
69
     *   getConfig            | Get the value by identification string.
70
     *   setConfig            | Set the value by identification string.
71
     *  ----------------------|---------------------------------------------
72
     */
73
    use FirewallTrait;
74
75
    /**
76
     *   Public methods       | Desctiotion
77
     *  ----------------------|---------------------------------------------
78
     *                        | No public methods.
79
     *  ----------------------|---------------------------------------------
80
     */
81
    use SetupTrait;
82
83
    /**
84
     *   Public methods       | Desctiotion
85
     *  ----------------------|---------------------------------------------
86
     *                        | No public methods.
87
     *  ----------------------|---------------------------------------------
88
     */
89
    use XssProtectionTrait;
90
91
    /**
92
     *   Public methods       | Desctiotion
93
     *  ----------------------|---------------------------------------------
94
     *                        | No public methods.
95
     *  ----------------------|---------------------------------------------
96
     */
97
    use MessengerTrait;
98
99
    /**
100
     * Collection of PSR-7 or PSR-15 middlewares.
101
     *
102
     * @var array
103
     */
104
    protected $middlewares = [];
105
106
    /**
107
     * The URI of the control panel.
108
     *
109
     * @var string
110
     */
111
    protected $controlPanelUri = '';
112
113
    /**
114
     * Constructor.
115
     *
116
     * @param ServerRequestInterface|null $request  A PSR-7 server request.
117
     * @param ResponseInterface|null      $response A PSR-7 server response.
118
     */
119 106
    public function __construct(?ServerRequestInterface $request = null, ?ResponseInterface $response = null)
120
    {
121 106
        Container::set('firewall', $this);
122
123 106
        $this->kernel = new Kernel($request, $response);
124
    }
125
126
    /**
127
     * Display the performance report as showing dialogs.
128
     *
129
     * @return void
130
     */
131 1
    public function enablePerformanceReport(): void
132
    {
133 1
        Container::set('shieldon_start', [
134 1
            'time'   => microtime(),
135 1
            'memory' => memory_get_usage(),
136 1
        ]);
137
138 1
        Event::AddListener(
139 1
            'dialog_output',
140 1
            function () {
141 1
                Container::set('shieldon_end', [
142 1
                    'time'   => microtime(),
143 1
                    'memory' => memory_get_usage(),
144 1
                ]);
145 1
            }
146
        );
147
    }
148
149
    /**
150
     * Set up everything we need.
151
     *
152
     * @return void
153 83
     */
154
    public function setup(): void
155 83
    {
156 83
        $setupFunctions = [
157 83
            'IpSource',
158 83
            'Driver',
159 83
            'Channel',
160 83
            'Filters',
161 83
            'Components',
162 83
            'Logger',
163 83
            'LimitSession',
164 83
            'CronJob',
165 83
            'ExcludedUrls',
166 83
            'XssProtection',
167 83
            'PageAuthentication',
168 83
            'DialogUserInterface',
169 83
            'Messengers',
170 83
            'Captchas',
171 83
            'MessageEvents',
172 83
            'DenyTooManyAttempts',
173 83
            'iptablesBridgeDirectory',
174
        ];
175 83
176 83
        foreach ($setupFunctions as $func) {
177
            $function = 'setup' . $func;
178 83
179
            $this->{$function}();
180
        }
181 83
182
        $this->status = $this->getOption('daemon');
183
    }
184
185
    /**
186
     * Set up the path of the configuration file.
187
     *
188
     * @param string $source The path.
189
     * @param string $type   The type.
190
     *
191
     * @return void
192 83
     */
193
    public function configure(string $source, string $type = 'json'): void
194 83
    {
195 82
        if ($type === 'json') {
196 82
            $this->directory = rtrim($source, '\\/');
197
            $configFilePath = $this->directory . '/' . $this->filename;
198 82
199 71
            if (file_exists($configFilePath)) {
200
                $jsonString = file_get_contents($configFilePath);
201
            } else {
202 11
                $jsonString = file_get_contents(__DIR__ . '/../../config.json');
203
204 11
                if (defined('PHP_UNIT_TEST')) {
205 11
                    $jsonString = file_get_contents(__DIR__ . '/../../tests/config.json');
206
                }
207
            }
208
209 82
            $this->configuration = json_decode($jsonString, true);
210 82
            $this->kernel->managedBy('managed');
211
        } elseif ($type === 'php') {
212 1
            $this->configuration = include $source;
213 1
            $this->kernel->managedBy('config');
214 1
        }
215
216
        $this->setup();
217 83
    }
218
219
    /**
220
     * Just, run!
221
     *
222
     * @return ResponseInterface
223
     */
224
    public function run(): ResponseInterface
225 16
    {
226
        // If settings are ready, let's start monitoring requests.
227
        if ($this->status) {
228 16
            $response = get_request();
229
230 15
            // PSR-15 request handler.
231
            $requestHandler = new RequestHandler();
232
233 15
            foreach ($this->middlewares as $middleware) {
234
                $requestHandler->add($middleware);
235 15
            }
236 15
237
            $response = $requestHandler->handle($response);
238
239 15
            // Something is detected by Middlewares, return.
240
            if ($response->getStatusCode() !== Enum::HTTP_STATUS_OK) {
241
                return $response;
242 15
            }
243 5
244
            $result = $this->kernel->run();
245
246 10
            if ($result !== Enum::RESPONSE_ALLOW) {
247
                if ($this->kernel->captchaResponse()) {
248 10
                    $this->kernel->unban();
249
250 2
                    $response = $response->withHeader('Location', $this->kernel->getCurrentUrl());
251 1
                    $response = $response->withStatus(Enum::HTTP_STATUS_SEE_OTHER);
0 ignored issues
show
Bug introduced by
The method withStatus() does not exist on Psr\Http\Message\MessageInterface. It seems like you code against a sub-type of Psr\Http\Message\MessageInterface such as Psr\Http\Message\ResponseInterface or Shieldon\Psr7\Response. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

251
                    /** @scrutinizer ignore-call */ 
252
                    $response = $response->withStatus(Enum::HTTP_STATUS_SEE_OTHER);
Loading history...
252
253 1
                    return $response;
254 1
                }
255
            }
256 1
        }
257
258
        return $this->kernel->respond();
259
    }
260
261 11
    /**
262
     * Add middlewares and use them before going into Shieldon kernal.
263
     *
264
     * @param MiddlewareInterface $middleware A PSR-15 middlewares.
265
     *
266
     * @return void
267
     */
268
    public function add(MiddlewareInterface $middleware): void
269
    {
270
        $this->middlewares[] = $middleware;
271 88
    }
272
273 88
    /**
274
     * The base URL for control panel.
275
     *
276
     * @param string $uri The path component of a URI
277
     *
278
     * @return string
279
     */
280
    public function controlPanel(string $uri = ''): string
281
    {
282
        if (!empty($uri)) {
283 5
            $uri = '/' . trim($uri, '/');
284
            $this->controlPanelUri = $uri;
285 5
            $this->getKernel()->exclude($this->controlPanelUri);
286 3
        }
287 3
288 3
        return $this->controlPanelUri;
289
    }
290
291 5
    /**
292
     * Set the channel ID.
293
     *
294
     * @return void
295
     */
296
    protected function setupChannel(): void
297
    {
298
        $channelId = $this->getOption('channel_id');
299 83
300
        if ($channelId) {
301 83
            $this->kernel->setChannel($channelId);
302
            $this->channel = $channelId;
303 83
        }
304 10
    }
305 10
306
    /**
307
     * Refresh / refetch the server request if needed.
308
     *
309
     * @return void
310
     */
311
    protected function refreshRequest(): void
312
    {
313
        Container::set('request', HttpFactory::createRequest(), true);
314 83
    }
315
}
316