Passed
Push — 2.x ( 3c49c1...b272d3 )
by Terry
02:18
created

Firewall::enablePerformanceReport()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 1
nc 1
nop 0
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;
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
     *  ----------------------|---------------------------------------------
58
     */
59
60
    /**
61
     *   Public methods       | Desctiotion
62
     *  ----------------------|---------------------------------------------
63
     *   getKernel            | Get the Shieldon Kernel instance.
64
     *   getConfiguration     | Get the configuration data.
65
     *   getDirectory         | Get the dictionary where the data is stored.
66
     *   getFileName          | Get the path of the configuration file.
67
     *   getConfig            | Get the value by identification string.
68
     *   setConfig            | Set the value by identification string.
69
     *  ----------------------|---------------------------------------------
70
     */
71
    use FirewallTrait;
72
73
    /**
74
     *   Public methods       | Desctiotion
75
     *  ----------------------|---------------------------------------------
76
     *                        | No public methods.
77
     *  ----------------------|---------------------------------------------
78
     */
79
    use SetupTrait;
1 ignored issue
show
introduced by
The trait Shieldon\Firewall\Firewall\SetupTrait requires some properties which are not provided by Shieldon\Firewall\Firewall: $component, $driver
Loading history...
80
81
    /**
82
     *   Public methods       | Desctiotion
83
     *  ----------------------|---------------------------------------------
84
     *                        | No public methods.
85
     *  ----------------------|---------------------------------------------
86
     */
87
    use XssProtectionTrait;
88
89
    /**
90
     *   Public methods       | Desctiotion
91
     *  ----------------------|---------------------------------------------
92
     *                        | No public methods.
93
     *  ----------------------|---------------------------------------------
94
     */
95
    use MessengerTrait;
96
97
    /**
98
     * Collection of PSR-7 or PSR-15 middlewares.
99
     *
100
     * @var array
101
     */
102
    protected $middlewares = [];
103
104
    /**
105
     * The URI of the control panel.
106
     *
107
     * @var string
108
     */
109
    protected $controlPanelUri = '';
110
111
    /**
112
     * Constructor.
113
     * 
114
     * @param ServerRequestInterface|null $request  A PSR-7 server request.
115
     * @param ResponseInterface|null      $response A PSR-7 server response.
116
     */
117
    public function __construct(?ServerRequestInterface $request = null, ?ResponseInterface $response = null) 
118
    {
119
        Container::set('firewall', $this);
120
121
        $this->kernel = new Kernel($request, $response);
122
    }
123
124
    /**
125
     * Display the performance report as showing dialogs.
126
     *
127
     * @return void
128
     */
129
    public function enablePerformanceReport(): void
130
    {
131
        Container::set('shieldon_start', [
132
            'time'   => microtime(),
133
            'memory' => memory_get_usage(),
134
        ]);
135
136
        Event::AddListener('dialog_output',
137
            function() {
138
                Container::set('shieldon_end', [
139
                    'time'   => microtime(),
140
                    'memory' => memory_get_usage(),
141
                ]);
142
            }
143
        );
144
    }
145
146
    /**
147
     * Set up everything we need.
148
     *
149
     * @return void
150
     */
151
    public function setup(): void
152
    {
153
        $setupFunctions = [
154
            'IpSource',
155
            'Driver',
156
            'Channel',
157
            'Filters',
158
            'Components',
159
            'Logger',
160
            'LimitSession',
161
            'CronJob',
162
            'ExcludedUrls',
163
            'XssProtection',
164
            'PageAuthentication',
165
            'DialogUserInterface',
166
            'Messengers',
167
            'Captchas',
168
            'MessageEvents',
169
            'DenyTooManyAttempts',
170
            'iptablesBridgeDirectory',
171
        ];
172
173
        foreach ($setupFunctions as $func) {
174
            $function = 'setup' . $func;
175
176
            $this->{$function}();
177
        }
178
179
        $this->status = $this->getOption('daemon');
180
    }
181
182
    /**
183
     * Set up the path of the configuration file.
184
     *
185
     * @param string $source The path.
186
     * @param string $type   The type.
187
     * 
188
     * @return void
189
     */
190
    public function configure(string $source, string $type = 'json'): void
191
    {
192
        if ($type === 'json') {
193
            $this->directory = rtrim($source, '\\/');
194
            $configFilePath = $this->directory . '/' . $this->filename;
195
196
            if (file_exists($configFilePath)) {
197
                $jsonString = file_get_contents($configFilePath);
198
199
            } else {
200
                $jsonString = file_get_contents(__DIR__ . '/../../config.json');
201
202
                if (defined('PHP_UNIT_TEST')) {
203
                    $jsonString = file_get_contents(__DIR__ . '/../../tests/config.json');
204
                }
205
            }
206
207
            $this->configuration = json_decode($jsonString, true);
208
            $this->kernel->managedBy('managed');
209
210
        } elseif ($type === 'php') {
211
            $this->configuration = include $source;
212
            $this->kernel->managedBy('config');
213
        }
214
215
        $this->setup();
216
    }
217
218
    /**
219
     * Just, run!
220
     *
221
     * @return ResponseInterface
222
     */
223
    public function run(): ResponseInterface
224
    {
225
        // If settings are ready, let's start monitoring requests.
226
        if ($this->status) {
227
228
            $response = get_request();
229
230
            // PSR-15 request handler.
231
            $requestHandler = new RequestHandler();
232
233
            foreach ($this->middlewares as $middleware) {
234
                $requestHandler->add($middleware);
235
            }
236
237
            $response = $requestHandler->handle($response);
238
239
            // Something is detected by Middlewares, return.
240
            if ($response->getStatusCode() !== $this->kernel::HTTP_STATUS_OK) {
241
                return $response;
242
            }
243
244
            $result = $this->kernel->run();
245
246
            if ($result !== $this->kernel::RESPONSE_ALLOW) {
247
248
                if ($this->kernel->captchaResponse()) {
249
                    $this->kernel->unban();
250
251
                    $response = $response->withHeader('Location', $this->kernel->getCurrentUrl());
252
                    $response = $response->withStatus($this->kernel::HTTP_STATUS_SEE_OTHER);
253
254
                    return $response;
255
                }
256
            }
257
        }
258
259
        return $this->kernel->respond();
260
    }
261
262
    /**
263
     * Add middlewares and use them before going into Shieldon kernal.
264
     *
265
     * @param MiddlewareInterface $middleware A PSR-15 middlewares.
266
     *
267
     * @return void
268
     */
269
    public function add(MiddlewareInterface $middleware): void
270
    {
271
        $this->middlewares[] = $middleware;
272
    }
273
274
    /**
275
     * The base URL for control panel.
276
     *
277
     * @param string $uri The path component of a URI
278
     *
279
     * @return string
280
     */
281
    public function controlPanel(string $uri = ''): string
282
    {
283
        if (!empty($uri)) {
284
            $uri = '/' . trim($uri, '/');
285
            $this->controlPanelUri = $uri;
286
            $this->getKernel()->exclude($this->controlPanelUri);
287
        }
288
289
        return $this->controlPanelUri;
290
    }
291
292
    /**
293
     * Set the channel ID.
294
     *
295
     * @return void
296
     */
297
    protected function setupChannel(): void
298
    {
299
        $channelId = $this->getOption('channel_id');
300
301
        if ($channelId) {
302
            $this->kernel->setChannel($channelId);
303
            $this->channel = $channelId;
304
        }
305
    }
306
307
    /**
308
     * Refresh / refetch the server request if needed.
309
     *
310
     * @return void
311
     */
312
    protected function refreshRequest(): void
313
    {
314
        Container::set('request', HttpFactory::createRequest(), true);
315
    }
316
}
317