Implemented changes requested by FuzeWorks\Application
- CSRF Verification is now functional again - CSRF throws CSRFException - XSS clean can now be disabled in the config globally. Once disabled, this can't be overridden - X-Powered-By header is now always suppressed - WebComponent now assigns global variables to the LayoutEngine. - CSRF Exceptions can be handled by a view, if this one implements the securityExceptionHandler() method - Error403 page added
This commit is contained in:
parent
fb733077ee
commit
416d3895d0
|
@ -51,8 +51,14 @@ return [
|
||||||
*/
|
*/
|
||||||
'csrf_protection' => true,
|
'csrf_protection' => true,
|
||||||
'csrf_token_name' => 'fw_csrf_token',
|
'csrf_token_name' => 'fw_csrf_token',
|
||||||
'csrf_cookie_name' => 'fw_csrf_cookie',
|
|
||||||
'csrf_expire' => 7200,
|
'csrf_expire' => 7200,
|
||||||
'csrf_regenerate' => TRUE,
|
|
||||||
'csrf_exclude_uris' => array(),
|
'csrf_exclude_uris' => array(),
|
||||||
|
|
||||||
|
// CSRF Cookie information
|
||||||
|
'csrf_cookie_name' => 'fw_csrf_cookie',
|
||||||
|
'csrf_cookie_prefix' => '',
|
||||||
|
'csrf_cookie_domain' => '',
|
||||||
|
'csrf_cookie_path' => '/',
|
||||||
|
'csrf_cookie_secure' => false,
|
||||||
|
'csrf_cookie_httponly' => false
|
||||||
];
|
];
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FuzeWorks Component.
|
||||||
|
*
|
||||||
|
* The FuzeWorks PHP FrameWork
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013-2019 TechFuze
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author TechFuze
|
||||||
|
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
|
||||||
|
* @license https://opensource.org/licenses/MIT MIT License
|
||||||
|
*
|
||||||
|
* @link http://techfuze.net/fuzeworks
|
||||||
|
* @since Version 1.2.0
|
||||||
|
*
|
||||||
|
* @version Version 1.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FuzeWorks\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class CSRFException extends SecurityException
|
||||||
|
{
|
||||||
|
}
|
|
@ -256,8 +256,8 @@ class Input
|
||||||
*/
|
*/
|
||||||
protected function getFromInputArray(string $arrayName, $index = null, bool $xssClean = true)
|
protected function getFromInputArray(string $arrayName, $index = null, bool $xssClean = true)
|
||||||
{
|
{
|
||||||
// Clean XSS if requested manually or forced through configuration
|
// Never run XSS clean if disabled by config
|
||||||
$xssClean = $xssClean || $this->webConfig->get('xss_clean');
|
$xssClean = ($this->webConfig->get('xss_clean') == true ? $xssClean : false);
|
||||||
|
|
||||||
// If the index is null, the entire array is requested
|
// If the index is null, the entire array is requested
|
||||||
$index = (!is_null($index) ? $index : array_keys($this->inputArray[$arrayName]));
|
$index = (!is_null($index) ? $index : array_keys($this->inputArray[$arrayName]));
|
||||||
|
@ -376,5 +376,28 @@ class Input
|
||||||
return $this->getFromInputArray('server', 'REQUEST_METHOD', $xssClean);
|
return $this->getFromInputArray('server', 'REQUEST_METHOD', $xssClean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is HTTPS?
|
||||||
|
*
|
||||||
|
* Determines if the application is accessed via an encrypted
|
||||||
|
* (HTTPS) connection.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isHttps(): bool
|
||||||
|
{
|
||||||
|
if (!empty($this->inputArray['server']['HTTPS']) && strtolower($this->inputArray['server']['HTTPS']) !== 'off')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
elseif (isset($this->inputArray['server']['HTTP_X_FORWARDED_PROTO']) && $this->inputArray['server']['HTTP_X_FORWARDED_PROTO'] === 'https')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
elseif ( ! empty($this->inputArray['server']['HTTP_FRONT_END_HTTPS']) && strtolower($this->inputArray['server']['HTTP_FRONT_END_HTTPS']) !== 'off')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -163,6 +163,9 @@ class Output
|
||||||
ob_start('ob_gzhandler');
|
ob_start('ob_gzhandler');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the X-Powered-By header, since it's a security risk
|
||||||
|
header_remove("X-Powered-By");
|
||||||
|
|
||||||
// Send all available headers
|
// Send all available headers
|
||||||
if (!empty($this->headers))
|
if (!empty($this->headers))
|
||||||
foreach ($this->headers as $header)
|
foreach ($this->headers as $header)
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
namespace FuzeWorks;
|
namespace FuzeWorks;
|
||||||
use FuzeWorks\ConfigORM\ConfigORM;
|
use FuzeWorks\ConfigORM\ConfigORM;
|
||||||
use FuzeWorks\Exception\{ConfigException, SecurityException, Exception};
|
use FuzeWorks\Exception\{ConfigException, CSRFException, Exception};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Security Class
|
* Security Class
|
||||||
|
@ -169,6 +169,13 @@ class Security {
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input. A dependency for this class
|
||||||
|
*
|
||||||
|
* @var Input
|
||||||
|
*/
|
||||||
|
private $input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*
|
*
|
||||||
|
@ -178,6 +185,7 @@ class Security {
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
$this->config = Factory::getInstance()->config->get('security');
|
$this->config = Factory::getInstance()->config->get('security');
|
||||||
|
$this->input = Factory::getInstance()->input;
|
||||||
|
|
||||||
// Is CSRF protection enabled?
|
// Is CSRF protection enabled?
|
||||||
if ($this->config->csrf_protection)
|
if ($this->config->csrf_protection)
|
||||||
|
@ -210,14 +218,13 @@ class Security {
|
||||||
* CSRF Verify
|
* CSRF Verify
|
||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
|
* @throws CSRFException
|
||||||
*/
|
*/
|
||||||
public function csrf_verify(): self
|
public function csrf_verify(): self
|
||||||
{
|
{
|
||||||
// If it's not a POST request we will set the CSRF cookie
|
// If it's not a POST request we will set the CSRF cookie
|
||||||
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
|
if (strtoupper($this->input->server('REQUEST_METHOD')) !== 'POST')
|
||||||
{
|
|
||||||
return $this->csrf_set_cookie();
|
return $this->csrf_set_cookie();
|
||||||
}
|
|
||||||
|
|
||||||
// Check if URI has been whitelisted from CSRF checks
|
// Check if URI has been whitelisted from CSRF checks
|
||||||
if ($exclude_uris = $this->config->csrf_exclude_uris)
|
if ($exclude_uris = $this->config->csrf_exclude_uris)
|
||||||
|
@ -232,22 +239,10 @@ class Security {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the tokens exist in both the _POST and _COOKIE arrays?
|
// Do the tokens exist in both the _POST and _COOKIE arrays?
|
||||||
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
|
$token = $this->input->post($this->_csrf_token_name);
|
||||||
OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
|
$cookie = $this->input->cookie($this->_csrf_cookie_name);
|
||||||
{
|
if ($token == null || $cookie == null || $token !== $cookie)
|
||||||
$this->csrf_show_error();
|
$this->csrf_show_error();
|
||||||
}
|
|
||||||
|
|
||||||
// We kill this since we're done and we don't want to polute the _POST array
|
|
||||||
unset($_POST[$this->_csrf_token_name]);
|
|
||||||
|
|
||||||
// Regenerate on every submission?
|
|
||||||
if ($this->config->csrf_regenerate)
|
|
||||||
{
|
|
||||||
// Nothing should last forever
|
|
||||||
unset($_COOKIE[$this->_csrf_cookie_name]);
|
|
||||||
$this->_csrf_hash = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_csrf_set_hash();
|
$this->_csrf_set_hash();
|
||||||
$this->csrf_set_cookie();
|
$this->csrf_set_cookie();
|
||||||
|
@ -258,6 +253,22 @@ class Security {
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSRF Regenerate
|
||||||
|
*
|
||||||
|
* @throws ConfigException
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function csrf_regenerate()
|
||||||
|
{
|
||||||
|
Logger::log("CSRF Hash is being regenerated...");
|
||||||
|
$this->_csrf_hash = null;
|
||||||
|
$this->_csrf_set_hash();
|
||||||
|
$this->csrf_set_cookie();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSRF Set Cookie
|
* CSRF Set Cookie
|
||||||
*
|
*
|
||||||
|
@ -267,24 +278,25 @@ class Security {
|
||||||
public function csrf_set_cookie()
|
public function csrf_set_cookie()
|
||||||
{
|
{
|
||||||
$expire = time() + $this->_csrf_expire;
|
$expire = time() + $this->_csrf_expire;
|
||||||
$cfg = Factory::getInstance()->config->get('main');
|
$cfg = Factory::getInstance()->config->get('security');
|
||||||
$secure_cookie = (bool) $cfg->cookie_secure;
|
$secure_cookie = (bool) $cfg->csrf_cookie_secure;
|
||||||
|
|
||||||
if ($secure_cookie && ! Core::isHttps())
|
if ($secure_cookie && !$this->input->isHttps())
|
||||||
{
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
|
||||||
|
|
||||||
setcookie(
|
setcookie(
|
||||||
$this->_csrf_cookie_name,
|
$this->_csrf_cookie_name,
|
||||||
$this->_csrf_hash,
|
$this->_csrf_hash,
|
||||||
$expire,
|
$expire,
|
||||||
$cfg->cookie_path,
|
$cfg->csrf_cookie_path,
|
||||||
$cfg->cookie_domain,
|
$cfg->csrf_cookie_domain,
|
||||||
$secure_cookie,
|
$secure_cookie,
|
||||||
$cfg->cookie_httponly
|
$cfg->csrf_cookie_httponly
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger::log('CSRF cookie sent');
|
Logger::log('CSRF cookie sent');
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
@ -293,11 +305,11 @@ class Security {
|
||||||
* Show CSRF Error
|
* Show CSRF Error
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @throws SecurityException
|
* @throws CSRFException
|
||||||
*/
|
*/
|
||||||
public function csrf_show_error()
|
public function csrf_show_error()
|
||||||
{
|
{
|
||||||
throw new SecurityException('The action you have requested is not allowed.', 1);
|
throw new CSRFException('This action resulted in a Cross Site Reference Forgery warning. Request will be blocked...', 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
@ -728,57 +740,6 @@ class Security {
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitize Filename
|
|
||||||
*
|
|
||||||
* @param string $str Input file name
|
|
||||||
* @param bool $relative_path Whether to preserve paths
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function sanitize_filename($str, $relative_path = FALSE): string
|
|
||||||
{
|
|
||||||
$bad = $this->filename_bad_chars;
|
|
||||||
|
|
||||||
if ( ! $relative_path)
|
|
||||||
{
|
|
||||||
$bad[] = './';
|
|
||||||
$bad[] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
$str = UTF8::removeInvisibleCharacters($str, FALSE);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
$old = $str;
|
|
||||||
$str = str_replace($bad, '', $str);
|
|
||||||
}
|
|
||||||
while ($old !== $str);
|
|
||||||
|
|
||||||
return stripslashes($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip Image Tags
|
|
||||||
*
|
|
||||||
* @param string $str
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function strip_image_tags($str): string
|
|
||||||
{
|
|
||||||
return preg_replace(
|
|
||||||
array(
|
|
||||||
'#<img[\s/]+.*?src\s*=\s*(["\'])([^\\1]+?)\\1.*?\>#i',
|
|
||||||
'#<img[\s/]+.*?src\s*=\s*?(([^\s"\'=<>`]+)).*?\>#i'
|
|
||||||
),
|
|
||||||
'\\2',
|
|
||||||
$str
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -84,7 +84,7 @@ class URI
|
||||||
|
|
||||||
$scriptName = $this->input->server('SCRIPT_NAME');
|
$scriptName = $this->input->server('SCRIPT_NAME');
|
||||||
$scriptFilename = $this->input->server('SCRIPT_FILENAME');
|
$scriptFilename = $this->input->server('SCRIPT_FILENAME');
|
||||||
$baseUrl = ($this->isHttps() ? 'https' : 'http') .
|
$baseUrl = ($this->input->isHttps() ? 'https' : 'http') .
|
||||||
"://" . $serverAddr .
|
"://" . $serverAddr .
|
||||||
substr($scriptName, 0, strpos($scriptName, basename($scriptFilename)));
|
substr($scriptName, 0, strpos($scriptName, basename($scriptFilename)));
|
||||||
}
|
}
|
||||||
|
@ -222,31 +222,4 @@ class URI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is HTTPS?
|
|
||||||
*
|
|
||||||
* Determines if the application is accessed via an encrypted
|
|
||||||
* (HTTPS) connection.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isHttps(): bool
|
|
||||||
{
|
|
||||||
$https = $this->input->server('HTTPS');
|
|
||||||
if (!is_null($https) && strtolower($https) !== 'off')
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
elseif (!is_null($this->input->server('HTTP_X_FORWARDED_PROTO')) && $this->input->server('HTTP_X_FORWARDED_PROTO') === 'https')
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
elseif ( ! is_null($this->input->server('HTTP_FRONT_END_HTTPS')) && strtolower($this->input->server('HTTP_FRONT_END_HTTPS')) !== 'off')
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -36,12 +36,17 @@
|
||||||
|
|
||||||
namespace FuzeWorks;
|
namespace FuzeWorks;
|
||||||
|
|
||||||
|
use FuzeWorks\Event\HaltExecutionEvent;
|
||||||
|
use FuzeWorks\Event\LayoutLoadEvent;
|
||||||
|
use FuzeWorks\Event\RouterCallViewEvent;
|
||||||
|
use FuzeWorks\Exception\CSRFException;
|
||||||
use FuzeWorks\Exception\EventException;
|
use FuzeWorks\Exception\EventException;
|
||||||
use FuzeWorks\Exception\Exception;
|
use FuzeWorks\Exception\Exception;
|
||||||
use FuzeWorks\Exception\HaltException;
|
use FuzeWorks\Exception\HaltException;
|
||||||
use FuzeWorks\Exception\NotFoundException;
|
use FuzeWorks\Exception\NotFoundException;
|
||||||
use FuzeWorks\Exception\OutputException;
|
use FuzeWorks\Exception\OutputException;
|
||||||
use FuzeWorks\Exception\RouterException;
|
use FuzeWorks\Exception\RouterException;
|
||||||
|
use FuzeWorks\Exception\SecurityException;
|
||||||
use FuzeWorks\Exception\WebException;
|
use FuzeWorks\Exception\WebException;
|
||||||
|
|
||||||
class WebComponent implements iComponent
|
class WebComponent implements iComponent
|
||||||
|
@ -100,6 +105,9 @@ class WebComponent implements iComponent
|
||||||
{
|
{
|
||||||
// First init UTF8
|
// First init UTF8
|
||||||
UTF8::init();
|
UTF8::init();
|
||||||
|
|
||||||
|
// Register some base events
|
||||||
|
Events::addListener([$this, 'layoutLoadEventListener'], 'layoutLoadEvent', Priority::NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,7 +145,7 @@ class WebComponent implements iComponent
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Set the output to display when shutting down
|
// Set the output to display when shutting down
|
||||||
Events::addListener(function () {
|
Events::addListener(function ($event) {
|
||||||
/** @var Output $output */
|
/** @var Output $output */
|
||||||
Logger::logInfo("Parsing output...");
|
Logger::logInfo("Parsing output...");
|
||||||
$output = Factory::getInstance()->output;
|
$output = Factory::getInstance()->output;
|
||||||
|
@ -153,9 +161,25 @@ class WebComponent implements iComponent
|
||||||
/** @var Router $router */
|
/** @var Router $router */
|
||||||
/** @var URI $uri */
|
/** @var URI $uri */
|
||||||
/** @var Output $output */
|
/** @var Output $output */
|
||||||
|
/** @var Security $security */
|
||||||
$router = Factory::getInstance()->router;
|
$router = Factory::getInstance()->router;
|
||||||
$uri = Factory::getInstance()->uri;
|
$uri = Factory::getInstance()->uri;
|
||||||
$output = Factory::getInstance()->output;
|
$output = Factory::getInstance()->output;
|
||||||
|
$security = Factory::getInstance()->security;
|
||||||
|
|
||||||
|
// And start logging the request
|
||||||
|
Logger::newLevel("Routing web request...");
|
||||||
|
|
||||||
|
// First test for Cross Site Request Forgery
|
||||||
|
try {
|
||||||
|
$security->csrf_verify();
|
||||||
|
} catch (SecurityException $exception) {
|
||||||
|
// If a SecurityException is thrown, first log it
|
||||||
|
Logger::logWarning("SecurityException thrown. Registering listener to verify handler in View");
|
||||||
|
|
||||||
|
// Register a listener
|
||||||
|
Events::addListener([$this, 'callViewEventListener'], 'routerCallViewEvent', Priority::HIGHEST, $exception);
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to load the requested page
|
// Attempt to load the requested page
|
||||||
try {
|
try {
|
||||||
|
@ -165,6 +189,9 @@ class WebComponent implements iComponent
|
||||||
Logger::logWarning("Requested page not found. Requesting Error/error404 View");
|
Logger::logWarning("Requested page not found. Requesting Error/error404 View");
|
||||||
$output->setStatusHeader(404);
|
$output->setStatusHeader(404);
|
||||||
|
|
||||||
|
// Remove listener so that error pages won't be intercepted
|
||||||
|
Events::removeListener([$this, 'callViewEventListener'], 'routerCallViewEvent',Priority::HIGHEST);
|
||||||
|
|
||||||
// Request 404 page=
|
// Request 404 page=
|
||||||
try {
|
try {
|
||||||
$viewOutput = $router->route('Error/error404');
|
$viewOutput = $router->route('Error/error404');
|
||||||
|
@ -175,15 +202,54 @@ class WebComponent implements iComponent
|
||||||
Logger::exceptionHandler($e, false);
|
Logger::exceptionHandler($e, false);
|
||||||
$viewOutput = 'ERROR 404. Page was not found.';
|
$viewOutput = 'ERROR 404. Page was not found.';
|
||||||
}
|
}
|
||||||
|
} catch (HaltException $e) {
|
||||||
|
Logger::logWarning("Requested page was denied. Requesting Error/error403 View.");
|
||||||
|
$output->setStatusHeader(403);
|
||||||
|
|
||||||
|
// Remove listener so that error pages won't be intercepted
|
||||||
|
Events::removeListener([$this, 'callViewEventListener'], 'routerCallViewEvent',Priority::HIGHEST);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$viewOutput = $router->route('Error/error403');
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// If still resulting in an error, do something else
|
||||||
|
$viewOutput = 'ERROR 403. Forbidden.';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Logger::exceptionHandler($e, false);
|
||||||
|
$viewOutput = 'ERROR 403. Forbidden.';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the output
|
// Append the output
|
||||||
if (!empty($viewOutput))
|
if (!empty($viewOutput))
|
||||||
$output->appendOutput($viewOutput);
|
$output->appendOutput($viewOutput);
|
||||||
|
|
||||||
|
Logger::stopLevel();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for routerCallViewEvent
|
||||||
|
*
|
||||||
|
* Fired when a SecurityException is thrown. Verifies if a securityExceptionHandler() method exists.
|
||||||
|
* If not, the calling of the view is cancelled. If yes, the calling of the view depends on the
|
||||||
|
* result of the method
|
||||||
|
*
|
||||||
|
* @param RouterCallViewEvent $event
|
||||||
|
* @param SecurityException $exception
|
||||||
|
*/
|
||||||
|
public function callViewEventListener(RouterCallViewEvent $event, SecurityException $exception)
|
||||||
|
{
|
||||||
|
/** @var RouterCallViewEvent $event */
|
||||||
|
// If the securityExceptionHandler method exists, cancel based on that methods output
|
||||||
|
if (method_exists($event->view, 'securityExceptionHandler'))
|
||||||
|
$event->setCancelled(!$event->view->securityExceptionHandler($exception));
|
||||||
|
|
||||||
|
// If not, cancel it immediately
|
||||||
|
else
|
||||||
|
$event->setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for haltExecutionEvent
|
* Listener for haltExecutionEvent
|
||||||
*
|
*
|
||||||
|
@ -191,7 +257,7 @@ class WebComponent implements iComponent
|
||||||
*
|
*
|
||||||
* @param $event
|
* @param $event
|
||||||
*/
|
*/
|
||||||
public function haltEventListener($event)
|
public function haltEventListener(HaltExecutionEvent $event)
|
||||||
{
|
{
|
||||||
// Dependencies
|
// Dependencies
|
||||||
/** @var Output $output */
|
/** @var Output $output */
|
||||||
|
@ -203,6 +269,9 @@ class WebComponent implements iComponent
|
||||||
// Cancel event
|
// Cancel event
|
||||||
$event->setCancelled(true);
|
$event->setCancelled(true);
|
||||||
|
|
||||||
|
// Remove listener so that error pages won't be intercepted
|
||||||
|
Events::removeListener([$this, 'callViewEventListener'], 'routerCallViewEvent',Priority::HIGHEST);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// And handle consequences
|
// And handle consequences
|
||||||
Logger::logError("Execution halted. Providing error 500 page.");
|
Logger::logError("Execution halted. Providing error 500 page.");
|
||||||
|
@ -216,4 +285,28 @@ class WebComponent implements iComponent
|
||||||
// Finally append output and shutdown
|
// Finally append output and shutdown
|
||||||
$output->appendOutput($viewOutput);
|
$output->appendOutput($viewOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for layoutLoadEvent
|
||||||
|
*
|
||||||
|
* Assigns variables from the WebComponent to Layout engines.
|
||||||
|
*
|
||||||
|
* @param $event
|
||||||
|
* @throws Exception\ConfigException
|
||||||
|
*/
|
||||||
|
public function layoutLoadEventListener(LayoutLoadEvent $event)
|
||||||
|
{
|
||||||
|
// Dependencies
|
||||||
|
/** @var Security $security */
|
||||||
|
/** @var Config $config */
|
||||||
|
$security = Factory::getInstance()->security;
|
||||||
|
$config = Factory::getInstance()->config;
|
||||||
|
|
||||||
|
/** @var LayoutLoadEvent $event */
|
||||||
|
$event->assign('csrfHash', $security->get_csrf_hash());
|
||||||
|
$event->assign('csrfTokenName', $security->get_csrf_token_name());
|
||||||
|
$event->assign('siteURL', $config->getConfig('web')->get('base_url'));
|
||||||
|
|
||||||
|
Logger::logInfo("Assigned variables to TemplateEngine from WebComponent");
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue