1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <contact@terryl.in>
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 <contact@terryl.in>
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
     *   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 3
    public function __construct(?ServerRequestInterface $request = null, ?ResponseInterface $response = null) 
120
    {
121 3
        Container::set('firewall', $this);
122

123 3
        $this->kernel = new Kernel($request, $response);
124
    }
125

126
    /**
127
     * Display the performance report as showing dialogs.
128
     *
129
     * @return void
130
     */
131 3
    public function enablePerformanceReport(): void
132
    {
133 3
        Container::set('shieldon_start', [
134 3
            'time'   => microtime(),
135 3
            'memory' => memory_get_usage(),
136
        ]);
137

138 3
        Event::AddListener('dialog_output',
139
            function() {
140 3
                Container::set('shieldon_end', [
141 3
                    'time'   => microtime(),
142 3
                    'memory' => memory_get_usage(),
143
                ]);
144
            }
145
        );
146
    }
147

148
    /**
149
     * Set up everything we need.
150
     *
151
     * @return void
152
     */
153 3
    public function setup(): void
154
    {
155
        $setupFunctions = [
156 3
            'IpSource',
157
            'Driver',
158
            'Channel',
159
            'Filters',
160
            'Components',
161
            'Logger',
162
            'LimitSession',
163
            'CronJob',
164
            'ExcludedUrls',
165
            'XssProtection',
166
            'PageAuthentication',
167
            'DialogUserInterface',
168
            'Messengers',
169
            'Captchas',
170
            'MessageEvents',
171
            'DenyTooManyAttempts',
172
            'iptablesBridgeDirectory',
173
        ];
174

175 3
        foreach ($setupFunctions as $func) {
176 3
            $function = 'setup' . $func;
177

178 3
            $this->{$function}();
179
        }
180

181 3
        $this->status = $this->getOption('daemon');
182
    }
183

184
    /**
185
     * Set up the path of the configuration file.
186
     *
187
     * @param string $source The path.
188
     * @param string $type   The type.
189
     * 
190
     * @return void
191
     */
192 3
    public function configure(string $source, string $type = 'json'): void
193
    {
194 3
        if ($type === 'json') {
195 3
            $this->directory = rtrim($source, '\\/');
196 3
            $configFilePath = $this->directory . '/' . $this->filename;
197

198 3
            if (file_exists($configFilePath)) {
199 3
                $jsonString = file_get_contents($configFilePath);
200

201
            } else {
202 3
                $jsonString = file_get_contents(__DIR__ . '/../../config.json');
203

204 3
                if (defined('PHP_UNIT_TEST')) {
205 3
                    $jsonString = file_get_contents(__DIR__ . '/../../tests/config.json');
206
                }
207
            }
208

209 3
            $this->configuration = json_decode($jsonString, true);
210 3
            $this->kernel->managedBy('managed');
211

212 3
        } elseif ($type === 'php') {
213 3
            $this->configuration = include $source;
214 3
            $this->kernel->managedBy('config');
215
        }
216

217 3
        $this->setup();
218
    }
219

220
    /**
221
     * Just, run!
222
     *
223
     * @return ResponseInterface
224
     */
225 3
    public function run(): ResponseInterface
226
    {
227
        // If settings are ready, let's start monitoring requests.
228 3
        if ($this->status) {
229

230 3
            $response = get_request();
231

232
            // PSR-15 request handler.
233 3
            $requestHandler = new RequestHandler();
234

235 3
            foreach ($this->middlewares as $middleware) {
236 3
                $requestHandler->add($middleware);
237
            }
238

239 3
            $response = $requestHandler->handle($response);
240

241
            // Something is detected by Middlewares, return.
242 3
            if ($response->getStatusCode() !== $this->kernel::HTTP_STATUS_OK) {
243 3
                return $response;
244
            }
245

246 3
            $result = $this->kernel->run();
247

248 3
            if ($result !== $this->kernel::RESPONSE_ALLOW) {
249

250 3
                if ($this->kernel->captchaResponse()) {
251 3
                    $this->kernel->unban();
252

253 3
                    $response = $response->withHeader('Location', $this->kernel->getCurrentUrl());
254 3
                    $response = $response->withStatus($this->kernel::HTTP_STATUS_SEE_OTHER);
255

256 3
                    return $response;
257
                }
258
            }
259
        }
260

261 3
        return $this->kernel->respond();
262
    }
263

264
    /**
265
     * Add middlewares and use them before going into Shieldon kernal.
266
     *
267
     * @param MiddlewareInterface $middleware A PSR-15 middlewares.
268
     *
269
     * @return void
270
     */
271 3
    public function add(MiddlewareInterface $middleware): void
272
    {
273 3
        $this->middlewares[] = $middleware;
274
    }
275

276
    /**
277
     * The base URL for control panel.
278
     *
279
     * @param string $uri The path component of a URI
280
     *
281
     * @return string
282
     */
283 3
    public function controlPanel(string $uri = ''): string
284
    {
285 3
        if (!empty($uri)) {
286 3
            $uri = '/' . trim($uri, '/');
287 3
            $this->controlPanelUri = $uri;
288 3
            $this->getKernel()->exclude($this->controlPanelUri);
289
        }
290

291 3
        return $this->controlPanelUri;
292
    }
293

294
    /**
295
     * Set the channel ID.
296
     *
297
     * @return void
298
     */
299 3
    protected function setupChannel(): void
300
    {
301 3
        $channelId = $this->getOption('channel_id');
302

303 3
        if ($channelId) {
304 3
            $this->kernel->setChannel($channelId);
305 3
            $this->channel = $channelId;
306
        }
307
    }
308

309
    /**
310
     * Refresh / refetch the server request if needed.
311
     *
312
     * @return void
313
     */
314 3
    protected function refreshRequest(): void
315
    {
316 3
        Container::set('request', HttpFactory::createRequest(), true);
317
    }
318
}

Read our documentation on viewing source code .

Loading