Implemented many unit tests.
The following tests for classes have been implemented: - Security - Input - Encryption Library - Utf8 A mocking autoloader has been added (but is not yet configured correctly)
This commit is contained in:
parent
96ca890656
commit
5df6b733d0
|
@ -12,7 +12,7 @@ return array(
|
|||
'default_function' => 'index',
|
||||
'application_prefix' => 'MY_',
|
||||
|
||||
'charset' => 'utf-8',
|
||||
'charset' => 'UTF-8',
|
||||
'language' => 'english',
|
||||
|
||||
/*
|
||||
|
|
|
@ -476,7 +476,7 @@ class FW_Zip {
|
|||
* Lets you clear current zip data. Useful if you need to create
|
||||
* multiple zips with different data.
|
||||
*
|
||||
* @return CI_Zip
|
||||
* @return FW_Zip
|
||||
*/
|
||||
public function clear_data()
|
||||
{
|
||||
|
|
|
@ -115,6 +115,13 @@ class Input {
|
|||
*/
|
||||
protected $_input_stream;
|
||||
|
||||
/**
|
||||
* Factory object, allows this class to communicate with everything in FuzeWorks
|
||||
*
|
||||
* @var Factory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -127,6 +134,9 @@ class Input {
|
|||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// First load the factory so contact can be made with everything in FuzeWorks
|
||||
$this->factory = Factory::getInstance();
|
||||
|
||||
$this->_allow_get_array = (Config::get('routing')->allow_get_array === TRUE);
|
||||
$this->_enable_xss = (Config::get('security')->global_xss_filtering === TRUE);
|
||||
$this->_enable_csrf = (Config::get('security')->csrf_protection === TRUE);
|
||||
|
@ -138,7 +148,7 @@ class Input {
|
|||
// CSRF Protection check
|
||||
if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
|
||||
{
|
||||
Security::csrf_verify();
|
||||
$this->factory->security->csrf_verify();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +214,7 @@ class Input {
|
|||
}
|
||||
|
||||
return ($xss_clean === TRUE)
|
||||
? Security::xss_clean($value)
|
||||
? $this->factory->security->xss_clean($value)
|
||||
: $value;
|
||||
}
|
||||
|
||||
|
@ -801,7 +811,7 @@ class Input {
|
|||
}
|
||||
|
||||
return ($xss_clean === TRUE)
|
||||
? Security::xss_clean($headers[$index])
|
||||
? $this->factory->security->xss_clean($headers[$index])
|
||||
: $headers[$index];
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Security {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $filename_bad_chars = array(
|
||||
public $filename_bad_chars = array(
|
||||
'../', '<!--', '-->', '<', '>',
|
||||
"'", '"', '&', '$', '#',
|
||||
'{', '}', '[', ']', '=',
|
||||
|
@ -72,7 +72,7 @@ class Security {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $charset = 'UTF-8';
|
||||
public $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* XSS Hash
|
||||
|
@ -81,7 +81,7 @@ class Security {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_xss_hash;
|
||||
protected $_xss_hash;
|
||||
|
||||
/**
|
||||
* CSRF Hash
|
||||
|
@ -90,7 +90,7 @@ class Security {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_csrf_hash;
|
||||
protected $_csrf_hash;
|
||||
|
||||
/**
|
||||
* CSRF Expire time
|
||||
|
@ -100,7 +100,7 @@ class Security {
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $_csrf_expire = 7200;
|
||||
protected $_csrf_expire = 7200;
|
||||
|
||||
/**
|
||||
* CSRF Token name
|
||||
|
@ -109,7 +109,7 @@ class Security {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_csrf_token_name = 'ci_csrf_token';
|
||||
protected $_csrf_token_name = 'fw_csrf_token';
|
||||
|
||||
/**
|
||||
* CSRF Cookie name
|
||||
|
@ -118,14 +118,14 @@ class Security {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_csrf_cookie_name = 'ci_csrf_token';
|
||||
protected $_csrf_cookie_name = 'fw_csrf_token';
|
||||
|
||||
/**
|
||||
* List of never allowed strings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_never_allowed_str = array(
|
||||
protected $_never_allowed_str = array(
|
||||
'document.cookie' => '[removed]',
|
||||
'document.write' => '[removed]',
|
||||
'.parentNode' => '[removed]',
|
||||
|
@ -142,7 +142,7 @@ class Security {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_never_allowed_regex = array(
|
||||
protected $_never_allowed_regex = array(
|
||||
'javascript\s*:',
|
||||
'(document|(document\.)?window)\.(location|on\w*)',
|
||||
'expression\s*(\(|&\#40;)', // CSS and IE
|
||||
|
@ -159,7 +159,7 @@ class Security {
|
|||
*
|
||||
* @var ConfigORM
|
||||
*/
|
||||
private static $config;
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
|
@ -168,31 +168,31 @@ class Security {
|
|||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::$config = Config::get('security');
|
||||
$this->config = Config::get('security');
|
||||
|
||||
// Is CSRF protection enabled?
|
||||
if (self::$config->csrf_protection)
|
||||
if ($this->config->csrf_protection)
|
||||
{
|
||||
// CSRF config
|
||||
foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
|
||||
{
|
||||
if (NULL !== ($val = self::$config->$key))
|
||||
if (NULL !== ($val = $this->config->$key))
|
||||
{
|
||||
self::${'_'.$key} = $val;
|
||||
$this->{'_'.$key} = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// Append application specific cookie prefix
|
||||
if ($cookie_prefix = Config::get('main')->cookie_prefix)
|
||||
{
|
||||
self::$_csrf_cookie_name = $cookie_prefix.self::$_csrf_cookie_name;
|
||||
$this->_csrf_cookie_name = $cookie_prefix.$this->_csrf_cookie_name;
|
||||
}
|
||||
|
||||
// Set the CSRF hash
|
||||
self::_csrf_set_hash();
|
||||
$this->_csrf_set_hash();
|
||||
}
|
||||
|
||||
self::$charset = strtoupper(Config::get('main')->charset);
|
||||
$this->charset = strtoupper(Config::get('main')->charset);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -200,51 +200,51 @@ class Security {
|
|||
/**
|
||||
* CSRF Verify
|
||||
*
|
||||
* @return CI_Security
|
||||
* @return Security
|
||||
*/
|
||||
public static function csrf_verify()
|
||||
public function csrf_verify()
|
||||
{
|
||||
// If it's not a POST request we will set the CSRF cookie
|
||||
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
|
||||
{
|
||||
return self::csrf_set_cookie();
|
||||
return $this->csrf_set_cookie();
|
||||
}
|
||||
|
||||
// Check if URI has been whitelisted from CSRF checks
|
||||
if ($exclude_uris = self::$config->csrf_exclude_uris)
|
||||
if ($exclude_uris = $this->config->csrf_exclude_uris)
|
||||
{
|
||||
foreach ($exclude_uris as $excluded)
|
||||
{
|
||||
if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), URI::uri_string()))
|
||||
{
|
||||
return true;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do the tokens exist in both the _POST and _COOKIE arrays?
|
||||
if ( ! isset($_POST[self::$_csrf_token_name], $_COOKIE[self::$_csrf_cookie_name])
|
||||
OR $_POST[self::$_csrf_token_name] !== $_COOKIE[self::$_csrf_cookie_name]) // Do the tokens match?
|
||||
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
|
||||
OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
|
||||
{
|
||||
self::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[self::$_csrf_token_name]);
|
||||
unset($_POST[$this->_csrf_token_name]);
|
||||
|
||||
// Regenerate on every submission?
|
||||
if (self::$config->csrf_regenerate)
|
||||
if ($this->config->csrf_regenerate)
|
||||
{
|
||||
// Nothing should last forever
|
||||
unset($_COOKIE[self::$_csrf_cookie_name]);
|
||||
self::$_csrf_hash = NULL;
|
||||
unset($_COOKIE[$this->_csrf_cookie_name]);
|
||||
$this->_csrf_hash = NULL;
|
||||
}
|
||||
|
||||
self::_csrf_set_hash();
|
||||
self::csrf_set_cookie();
|
||||
$this->_csrf_set_hash();
|
||||
$this->csrf_set_cookie();
|
||||
|
||||
Logger::log('CSRF token verified');
|
||||
return true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -253,22 +253,22 @@ class Security {
|
|||
* CSRF Set Cookie
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return CI_Security
|
||||
* @return Security
|
||||
*/
|
||||
public static function csrf_set_cookie()
|
||||
public function csrf_set_cookie()
|
||||
{
|
||||
$expire = time() + self::$_csrf_expire;
|
||||
$expire = time() + $this->_csrf_expire;
|
||||
$cfg = Config::get('main');
|
||||
$secure_cookie = (bool) $cfg->cookie_secure;
|
||||
|
||||
if ($secure_cookie && ! is_https())
|
||||
{
|
||||
return FALSE;
|
||||
return $this;
|
||||
}
|
||||
|
||||
setcookie(
|
||||
self::$_csrf_cookie_name,
|
||||
self::$_csrf_hash,
|
||||
$this->_csrf_cookie_name,
|
||||
$this->_csrf_hash,
|
||||
$expire,
|
||||
$cfg->cookie_path,
|
||||
$cfg->cookie_domain,
|
||||
|
@ -276,8 +276,7 @@ class Security {
|
|||
$cfg->cookie_httponly
|
||||
);
|
||||
Logger::log('CSRF cookie sent');
|
||||
|
||||
return true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -287,7 +286,7 @@ class Security {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function csrf_show_error()
|
||||
public function csrf_show_error()
|
||||
{
|
||||
throw new SecurityException('The action you have requested is not allowed.', 1);
|
||||
}
|
||||
|
@ -297,12 +296,12 @@ class Security {
|
|||
/**
|
||||
* Get CSRF Hash
|
||||
*
|
||||
* @see CI_Security::$_csrf_hash
|
||||
* @see Security::$_csrf_hash
|
||||
* @return string CSRF hash
|
||||
*/
|
||||
public static function get_csrf_hash()
|
||||
public function get_csrf_hash()
|
||||
{
|
||||
return self::$_csrf_hash;
|
||||
return $this->_csrf_hash;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -310,12 +309,12 @@ class Security {
|
|||
/**
|
||||
* Get CSRF Token Name
|
||||
*
|
||||
* @see CI_Security::$_csrf_token_name
|
||||
* @see Security::$_csrf_token_name
|
||||
* @return string CSRF token name
|
||||
*/
|
||||
public static function get_csrf_token_name()
|
||||
public function get_csrf_token_name()
|
||||
{
|
||||
return self::$_csrf_token_name;
|
||||
return $this->_csrf_token_name;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -346,14 +345,14 @@ class Security {
|
|||
* @param bool $is_image Whether the input is an image
|
||||
* @return string
|
||||
*/
|
||||
public static function xss_clean($str, $is_image = FALSE)
|
||||
public function xss_clean($str, $is_image = FALSE)
|
||||
{
|
||||
// Is the string an array?
|
||||
if (is_array($str))
|
||||
{
|
||||
while (list($key) = each($str))
|
||||
{
|
||||
$str[$key] = self::xss_clean($str[$key]);
|
||||
$str[$key] = $this->xss_clean($str[$key]);
|
||||
}
|
||||
|
||||
return $str;
|
||||
|
@ -404,7 +403,7 @@ class Security {
|
|||
$converted_string = $str;
|
||||
|
||||
// Remove Strings that are never allowed
|
||||
$str = self::_do_never_allowed($str);
|
||||
$str = $this->_do_never_allowed($str);
|
||||
|
||||
/*
|
||||
* Makes PHP tags safe
|
||||
|
@ -536,7 +535,7 @@ class Security {
|
|||
// Final clean up
|
||||
// This adds a bit of extra precaution in case
|
||||
// something got through the above filters
|
||||
$str = self::_do_never_allowed($str);
|
||||
$str = $this->_do_never_allowed($str);
|
||||
|
||||
/*
|
||||
* Images are Handled in a Special Way
|
||||
|
@ -562,20 +561,20 @@ class Security {
|
|||
*
|
||||
* Generates the XSS hash if needed and returns it.
|
||||
*
|
||||
* @see CI_Security::$_xss_hash
|
||||
* @see Security::$_xss_hash
|
||||
* @return string XSS hash
|
||||
*/
|
||||
public static function xss_hash()
|
||||
public function xss_hash()
|
||||
{
|
||||
if (self::$_xss_hash === NULL)
|
||||
if ($this->_xss_hash === NULL)
|
||||
{
|
||||
$rand = self::get_random_bytes(16);
|
||||
self::$_xss_hash = ($rand === FALSE)
|
||||
$rand = $this->get_random_bytes(16);
|
||||
$this->_xss_hash = ($rand === FALSE)
|
||||
? md5(uniqid(mt_rand(), TRUE))
|
||||
: bin2hex($rand);
|
||||
}
|
||||
|
||||
return self::$_xss_hash;
|
||||
return $this->_xss_hash;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -586,7 +585,7 @@ class Security {
|
|||
* @param int $length Output length
|
||||
* @return string
|
||||
*/
|
||||
public static function get_random_bytes($length)
|
||||
public function get_random_bytes($length)
|
||||
{
|
||||
if (empty($length) OR ! ctype_digit((string) $length))
|
||||
{
|
||||
|
@ -655,7 +654,7 @@ class Security {
|
|||
* @param string $charset Character set
|
||||
* @return string
|
||||
*/
|
||||
public static function entity_decode($str, $charset = NULL)
|
||||
public function entity_decode($str, $charset = NULL)
|
||||
{
|
||||
if (strpos($str, '&') === FALSE)
|
||||
{
|
||||
|
@ -664,7 +663,7 @@ class Security {
|
|||
|
||||
static $_entities;
|
||||
|
||||
isset($charset) OR $charset = self::$charset;
|
||||
isset($charset) OR $charset = $this->charset;
|
||||
$flag = Core::isPHP('5.4')
|
||||
? ENT_COMPAT | ENT_HTML5
|
||||
: ENT_COMPAT;
|
||||
|
@ -730,9 +729,9 @@ class Security {
|
|||
* @param bool $relative_path Whether to preserve paths
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitize_filename($str, $relative_path = FALSE)
|
||||
public function sanitize_filename($str, $relative_path = FALSE)
|
||||
{
|
||||
$bad = self::$filename_bad_chars;
|
||||
$bad = $this->filename_bad_chars;
|
||||
|
||||
if ( ! $relative_path)
|
||||
{
|
||||
|
@ -760,7 +759,7 @@ class Security {
|
|||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public static function strip_image_tags($str)
|
||||
public function strip_image_tags($str)
|
||||
{
|
||||
return preg_replace(
|
||||
array(
|
||||
|
@ -780,11 +779,11 @@ class Security {
|
|||
* Callback method for xss_clean() to remove whitespace from
|
||||
* things like 'j a v a s c r i p t'.
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $matches
|
||||
* @return string
|
||||
*/
|
||||
protected static function _compact_exploded_words($matches)
|
||||
protected function _compact_exploded_words($matches)
|
||||
{
|
||||
return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
|
||||
}
|
||||
|
@ -796,11 +795,11 @@ class Security {
|
|||
*
|
||||
* Callback method for xss_clean() to remove naughty HTML elements.
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $matches
|
||||
* @return string
|
||||
*/
|
||||
protected static function _sanitize_naughty_html($matches)
|
||||
protected function _sanitize_naughty_html($matches)
|
||||
{
|
||||
static $naughty_tags = array(
|
||||
'alert', 'prompt', 'confirm', 'applet', 'audio', 'basefont', 'base', 'behavior', 'bgsound',
|
||||
|
@ -891,18 +890,18 @@ class Security {
|
|||
* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
|
||||
* PHP 5.2+ on link-heavy strings.
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $match
|
||||
* @return string
|
||||
*/
|
||||
protected static function _js_link_removal($match)
|
||||
protected function _js_link_removal($match)
|
||||
{
|
||||
return str_replace(
|
||||
$match[1],
|
||||
preg_replace(
|
||||
'#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
|
||||
'',
|
||||
self::_filter_attributes($match[1])
|
||||
$this->_filter_attributes($match[1])
|
||||
),
|
||||
$match[0]
|
||||
);
|
||||
|
@ -919,18 +918,18 @@ class Security {
|
|||
* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
|
||||
* PHP 5.2+ on image tag heavy strings.
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $match
|
||||
* @return string
|
||||
*/
|
||||
protected static function _js_img_removal($match)
|
||||
protected function _js_img_removal($match)
|
||||
{
|
||||
return str_replace(
|
||||
$match[1],
|
||||
preg_replace(
|
||||
'#src=.*?(?:(?:alert|prompt|confirm|eval)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
|
||||
'',
|
||||
self::_filter_attributes($match[1])
|
||||
$this->_filter_attributes($match[1])
|
||||
),
|
||||
$match[0]
|
||||
);
|
||||
|
@ -941,11 +940,11 @@ class Security {
|
|||
/**
|
||||
* Attribute Conversion
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $match
|
||||
* @return string
|
||||
*/
|
||||
protected static function _convert_attribute($match)
|
||||
protected function _convert_attribute($match)
|
||||
{
|
||||
return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]);
|
||||
}
|
||||
|
@ -957,12 +956,12 @@ class Security {
|
|||
*
|
||||
* Filters tag attributes for consistency and safety.
|
||||
*
|
||||
* @used-by CI_Security::_js_img_removal()
|
||||
* @used-by CI_Security::_js_link_removal()
|
||||
* @used-by Security::_js_img_removal()
|
||||
* @used-by Security::_js_link_removal()
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected static function _filter_attributes($str)
|
||||
protected function _filter_attributes($str)
|
||||
{
|
||||
$out = '';
|
||||
if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
|
||||
|
@ -981,21 +980,21 @@ class Security {
|
|||
/**
|
||||
* HTML Entity Decode Callback
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param array $match
|
||||
* @return string
|
||||
*/
|
||||
protected static function _decode_entity($match)
|
||||
protected function _decode_entity($match)
|
||||
{
|
||||
// Protect GET variables in URLs
|
||||
// 901119URL5918AMP18930PROTECT8198
|
||||
$match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', self::xss_hash().'\\1=\\2', $match[0]);
|
||||
$match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', $this->xss_hash().'\\1=\\2', $match[0]);
|
||||
|
||||
// Decode, then un-protect URL GET vars
|
||||
return str_replace(
|
||||
self::xss_hash(),
|
||||
$this->xss_hash(),
|
||||
'&',
|
||||
self::entity_decode($match, self::$charset)
|
||||
$this->entity_decode($match, $this->charset)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1004,15 +1003,15 @@ class Security {
|
|||
/**
|
||||
* Do Never Allowed
|
||||
*
|
||||
* @used-by CI_Security::xss_clean()
|
||||
* @used-by Security::xss_clean()
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected static function _do_never_allowed($str)
|
||||
protected function _do_never_allowed($str)
|
||||
{
|
||||
$str = str_replace(array_keys(self::$_never_allowed_str), self::$_never_allowed_str, $str);
|
||||
$str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str);
|
||||
|
||||
foreach (self::$_never_allowed_regex as $regex)
|
||||
foreach ($this->_never_allowed_regex as $regex)
|
||||
{
|
||||
$str = preg_replace('#'.$regex.'#is', '[removed]', $str);
|
||||
}
|
||||
|
@ -1027,27 +1026,27 @@ class Security {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function _csrf_set_hash()
|
||||
protected function _csrf_set_hash()
|
||||
{
|
||||
if (self::$_csrf_hash === NULL)
|
||||
if ($this->_csrf_hash === NULL)
|
||||
{
|
||||
// If the cookie exists we will use its value.
|
||||
// We don't necessarily want to regenerate it with
|
||||
// each page load since a page could contain embedded
|
||||
// sub-pages causing this feature to fail
|
||||
if (isset($_COOKIE[self::$_csrf_cookie_name]) && is_string($_COOKIE[self::$_csrf_cookie_name])
|
||||
&& preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[self::$_csrf_cookie_name]) === 1)
|
||||
if (isset($_COOKIE[$this->_csrf_cookie_name]) && is_string($_COOKIE[$this->_csrf_cookie_name])
|
||||
&& preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1)
|
||||
{
|
||||
return self::$_csrf_hash = $_COOKIE[self::$_csrf_cookie_name];
|
||||
return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
|
||||
}
|
||||
|
||||
$rand = self::get_random_bytes(16);
|
||||
self::$_csrf_hash = ($rand === FALSE)
|
||||
$rand = $this->get_random_bytes(16);
|
||||
$this->_csrf_hash = ($rand === FALSE)
|
||||
? md5(uniqid(mt_rand(), TRUE))
|
||||
: bin2hex($rand);
|
||||
}
|
||||
|
||||
return self::$_csrf_hash;
|
||||
return $this->_csrf_hash;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,9 @@ restore_exception_handler();
|
|||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// Set localhost "remote" IP
|
||||
isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
|
||||
// Load the vfsStream class either through PEAR installed library or through composer
|
||||
if ( ! class_exists('vfsStream') && file_exists('vendor/autoload.php'))
|
||||
{
|
||||
|
@ -64,4 +67,7 @@ if ( ! class_exists('vfsStream') && file_exists('vendor/autoload.php'))
|
|||
class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper');
|
||||
}
|
||||
|
||||
Logger::setLoggerTemplate('logger_cli');
|
||||
Logger::setLoggerTemplate('logger_cli');
|
||||
|
||||
require_once('mocks/autoloader.php');
|
||||
spl_autoload_register('autoload');
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
/**
|
||||
* FuzeWorks.
|
||||
*
|
||||
* The FuzeWorks MVC PHP FrameWork
|
||||
*
|
||||
* Copyright (C) 2015 TechFuze
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author TechFuze
|
||||
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
||||
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
||||
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
||||
*
|
||||
* @link http://fuzeworks.techfuze.net
|
||||
* @since Version 0.0.1
|
||||
*
|
||||
* @version Version 0.0.1
|
||||
*/
|
||||
|
||||
use FuzeWorks\Factory;
|
||||
|
||||
/**
|
||||
* Class InputTest.
|
||||
*
|
||||
* Core testing suite, will test basic input class functionality
|
||||
*/
|
||||
class inputTest extends CoreTestAbstract
|
||||
{
|
||||
|
||||
protected $factory;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
// Load the factory first
|
||||
$this->factory = Factory::getInstance();
|
||||
|
||||
// Set server variable to GET as default, since this will leave unset in STDIN env
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
|
||||
// Set config for Input class
|
||||
$this->factory->config->getConfig('routing')->allow_get_array = TRUE;
|
||||
$this->factory->config->getConfig('security')->global_xss_filtering = FALSE;
|
||||
$this->factory->config->getConfig('security')->csrf_protection = FALSE;
|
||||
|
||||
$security = new Mock_Core_Security();
|
||||
|
||||
$this->factory->config->getConfig('main')->charset = 'UTF-8';
|
||||
$utf8 = new Mock_Core_Utf8();
|
||||
|
||||
$this->input = new Mock_Core_Input($security, $utf8);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_not_exists()
|
||||
{
|
||||
$this->assertTrue($this->input->get() === array());
|
||||
$this->assertTrue($this->input->get('foo') === NULL);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_exist()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_GET['foo'] = 'bar';
|
||||
|
||||
$this->assertArrayHasKey('foo', $this->input->get());
|
||||
$this->assertEquals('bar', $this->input->get('foo'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_exist_with_xss_clean()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_GET['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
|
||||
|
||||
$this->assertArrayHasKey('harm', $this->input->get());
|
||||
$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->get('harm'));
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $this->input->get('harm', TRUE));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_post_not_exists()
|
||||
{
|
||||
$this->assertTrue($this->input->post() === array());
|
||||
$this->assertTrue($this->input->post('foo') === NULL);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_post_exist()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST['foo'] = 'bar';
|
||||
|
||||
$this->assertArrayHasKey('foo', $this->input->post());
|
||||
$this->assertEquals('bar', $this->input->post('foo'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_post_exist_with_xss_clean()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
|
||||
|
||||
$this->assertArrayHasKey('harm', $this->input->post());
|
||||
$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->post('harm'));
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $this->input->post('harm', TRUE));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_post_get()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST['foo'] = 'bar';
|
||||
|
||||
$this->assertEquals('bar', $this->input->post_get('foo'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_post()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_GET['foo'] = 'bar';
|
||||
|
||||
$this->assertEquals('bar', $this->input->get_post('foo'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_cookie()
|
||||
{
|
||||
$_COOKIE['foo'] = 'bar';
|
||||
$this->assertEquals('bar', $this->input->cookie('foo'));
|
||||
$this->assertNull($this->input->cookie('bar'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_server()
|
||||
{
|
||||
$this->assertEquals('GET', $this->input->server('REQUEST_METHOD'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_fetch_from_array()
|
||||
{
|
||||
$data = array(
|
||||
'foo' => 'bar',
|
||||
'harm' => 'Hello, i try to <script>alert(\'Hack\');</script> your site',
|
||||
);
|
||||
|
||||
$foo = $this->input->fetch_from_array($data, 'foo');
|
||||
$harm = $this->input->fetch_from_array($data, 'harm');
|
||||
$harmless = $this->input->fetch_from_array($data, 'harm', TRUE);
|
||||
|
||||
$this->assertEquals('bar', $foo);
|
||||
$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm);
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless);
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST['foo']['bar'] = 'baz';
|
||||
$barArray = array('bar' => 'baz');
|
||||
|
||||
$this->assertEquals('baz', $this->input->post('foo[bar]'));
|
||||
$this->assertEquals($barArray, $this->input->post('foo[]'));
|
||||
$this->assertNull($this->input->post('foo[baz]'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_valid_ip()
|
||||
{
|
||||
$this->assertTrue($this->input->valid_ip('192.18.0.1'));
|
||||
$this->assertTrue($this->input->valid_ip('192.18.0.1', 'ipv4'));
|
||||
$this->assertFalse($this->input->valid_ip('555.0.0.0'));
|
||||
$this->assertFalse($this->input->valid_ip('2001:db8:0:85a3::ac1f:8001', 'ipv4'));
|
||||
|
||||
// v6 tests
|
||||
$this->assertFalse($this->input->valid_ip('192.18.0.1', 'ipv6'));
|
||||
|
||||
$ip_v6 = array(
|
||||
'2001:0db8:0000:85a3:0000:0000:ac1f:8001',
|
||||
'2001:db8:0:85a3:0:0:ac1f:8001',
|
||||
'2001:db8:0:85a3::ac1f:8001'
|
||||
);
|
||||
|
||||
foreach ($ip_v6 as $ip)
|
||||
{
|
||||
$this->assertTrue($this->input->valid_ip($ip));
|
||||
$this->assertTrue($this->input->valid_ip($ip, 'ipv6'));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_method()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$this->assertEquals('get', $this->input->method());
|
||||
$this->assertEquals('GET', $this->input->method(TRUE));
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$this->assertEquals('post', $this->input->method());
|
||||
$this->assertEquals('POST', $this->input->method(TRUE));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_is_ajax_request()
|
||||
{
|
||||
$this->assertFalse($this->input->is_ajax_request());
|
||||
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'test';
|
||||
$this->assertFalse($this->input->is_ajax_request());
|
||||
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
|
||||
$this->assertTrue($this->input->is_ajax_request());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_ip_address()
|
||||
{
|
||||
$this->input->ip_address = '127.0.0.1';
|
||||
$this->assertEquals('127.0.0.1', $this->input->ip_address());
|
||||
|
||||
// 127.0.0.1 is set in our Bootstrap file
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->assertEquals('127.0.0.1', $this->input->ip_address());
|
||||
|
||||
// Invalid
|
||||
$_SERVER['REMOTE_ADDR'] = 'invalid_ip_address';
|
||||
$this->input->ip_address = FALSE; // reset cached value
|
||||
$this->assertEquals('0.0.0.0', $this->input->ip_address());
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
|
||||
// Proxy_ips tests
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->factory->config->getConfig('security')->proxy_ips = array('127.0.0.3', '127.0.0.4', '127.0.0.2');
|
||||
$_SERVER['HTTP_CLIENT_IP'] = '127.0.0.2';
|
||||
$this->assertEquals('127.0.0.1', $this->input->ip_address());
|
||||
|
||||
// Invalid spoof
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->factory->config->getConfig('security')->proxy_ips = 'invalid_ip_address';
|
||||
$_SERVER['HTTP_CLIENT_IP'] = 'invalid_ip_address';
|
||||
$this->assertEquals('127.0.0.1', $this->input->ip_address());
|
||||
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->factory->config->getConfig('security')->proxy_ips = array('http://foo/bar/baz', '127.0.0.1/1');
|
||||
$_SERVER['HTTP_CLIENT_IP'] = '127.0.0.1';
|
||||
$this->assertEquals('127.0.0.1', $this->input->ip_address());
|
||||
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->factory->config->getConfig('security')->proxy_ips = array('http://foo/bar/baz', '127.0.0.2');
|
||||
$_SERVER['HTTP_CLIENT_IP'] = '127.0.0.2';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.2';
|
||||
$this->assertEquals('127.0.0.2', $this->input->ip_address());
|
||||
|
||||
//IPv6
|
||||
$this->input->ip_address = FALSE;
|
||||
$this->factory->config->getConfig('security')->proxy_ips = array('FE80:0000:0000:0000:0202:B3FF:FE1E:8329/1', 'FE80:0000:0000:0000:0202:B3FF:FE1E:8300/2');
|
||||
$_SERVER['HTTP_CLIENT_IP'] = 'FE80:0000:0000:0000:0202:B3FF:FE1E:8300';
|
||||
$_SERVER['REMOTE_ADDR'] = 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329';
|
||||
$this->assertEquals('FE80:0000:0000:0000:0202:B3FF:FE1E:8300', $this->input->ip_address());
|
||||
|
||||
$this->input->ip_address = FALSE;
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // back to reality
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_user_agent()
|
||||
{
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'test';
|
||||
$this->assertEquals('test', $this->input->user_agent());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,385 @@
|
|||
<?php
|
||||
/**
|
||||
* FuzeWorks.
|
||||
*
|
||||
* The FuzeWorks MVC PHP FrameWork
|
||||
*
|
||||
* Copyright (C) 2015 TechFuze
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author TechFuze
|
||||
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
||||
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
||||
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
||||
*
|
||||
* @link http://fuzeworks.techfuze.net
|
||||
* @since Version 0.0.1
|
||||
*
|
||||
* @version Version 0.0.1
|
||||
*/
|
||||
|
||||
use FuzeWorks\Factory;
|
||||
|
||||
/**
|
||||
* Class SecurityTest.
|
||||
*
|
||||
* Core testing suite, will test security class functionality
|
||||
*/
|
||||
class securityTest extends CoreTestAbstract
|
||||
{
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
// Set cookie for security test
|
||||
$_COOKIE['fw_csrf_cookie'] = md5(uniqid(mt_rand(), TRUE));
|
||||
|
||||
// Set config for Security class
|
||||
$config = Factory::getInstance()->config->getConfig('security');
|
||||
|
||||
$config->csrf_protection = true;
|
||||
$config->csrf_token_name = 'fw_csrf_token';
|
||||
$config->csrf_cookie_name = 'fw_csrf_cookie';
|
||||
|
||||
$this->security = new Mock_Core_Security();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_csrf_verify()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
|
||||
$this->assertInstanceOf('FuzeWorks\Security', $this->security->csrf_verify());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @expectedException FuzeWorks\SecurityException
|
||||
*/
|
||||
public function test_csrf_verify_invalid()
|
||||
{
|
||||
// Without issuing $_POST[csrf_token_name], this request will triggering CSRF error
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
||||
$this->security->csrf_verify();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_csrf_verify_valid()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST[$this->security->csrf_token_name] = $this->security->csrf_hash;
|
||||
|
||||
$this->assertInstanceOf('FuzeWorks\Security', $this->security->csrf_verify());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_csrf_hash()
|
||||
{
|
||||
$this->assertEquals($this->security->csrf_hash, $this->security->get_csrf_hash());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_csrf_token_name()
|
||||
{
|
||||
$this->assertEquals('fw_csrf_token', $this->security->get_csrf_token_name());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean()
|
||||
{
|
||||
$harm_string = "Hello, i try to <script>alert('Hack');</script> your site";
|
||||
|
||||
$harmless_string = $this->security->xss_clean($harm_string);
|
||||
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless_string);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_string_array()
|
||||
{
|
||||
$harm_strings = array(
|
||||
"Hello, i try to <script>alert('Hack');</script> your site",
|
||||
"Simple clean string",
|
||||
"Hello, i try to <script>alert('Hack');</script> your site"
|
||||
);
|
||||
|
||||
$harmless_strings = $this->security->xss_clean($harm_strings);
|
||||
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless_strings[0]);
|
||||
$this->assertEquals("Simple clean string", $harmless_strings[1]);
|
||||
$this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless_strings[2]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_image_valid()
|
||||
{
|
||||
$harm_string = '<img src="test.png">';
|
||||
|
||||
$xss_clean_return = $this->security->xss_clean($harm_string, TRUE);
|
||||
|
||||
// $this->assertTrue($xss_clean_return);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_image_invalid()
|
||||
{
|
||||
$harm_string = '<img src=javascript:alert(String.fromCharCode(88,83,83))>';
|
||||
|
||||
$xss_clean_return = $this->security->xss_clean($harm_string, TRUE);
|
||||
|
||||
$this->assertFalse($xss_clean_return);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_entity_double_encoded()
|
||||
{
|
||||
$input = '<a href="&#106&#97&#118&#97&#115&#99&#114&#105&#112&#116&#58&#99&#111&#110&#102&#105&#114&#109&#40&#49&#41">Clickhere</a>';
|
||||
$this->assertEquals('<a>Clickhere</a>', $this->security->xss_clean($input));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function text_xss_clean_js_link_removal()
|
||||
{
|
||||
// This one is to prevent a false positive
|
||||
$this->assertEquals(
|
||||
"<a href=\"javascrip\n<t\n:alert\n(1)\"\n>",
|
||||
$this->security->xss_clean("<a href=\"javascrip\n<t\n:alert\n(1)\"\n>")
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_js_img_removal()
|
||||
{
|
||||
$input = '<img src="&#106&#97&#118&#97&#115&#99&#114&#105&#112&#116&#58&#99&#111&#110&#102&#105&#114&#109&#40&#49&#41">Clickhere';
|
||||
$this->assertEquals('<img>', $this->security->xss_clean($input));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_sanitize_naughty_html_tags()
|
||||
{
|
||||
$this->assertEquals('<unclosedTag', $this->security->xss_clean('<unclosedTag'));
|
||||
$this->assertEquals('<blink>', $this->security->xss_clean('<blink>'));
|
||||
$this->assertEquals('<fubar>', $this->security->xss_clean('<fubar>'));
|
||||
|
||||
$this->assertEquals(
|
||||
'<img svg=""> src="x">',
|
||||
$this->security->xss_clean('<img <svg=""> src="x">')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<img src="b on=">on=">"x onerror="alert(1)">',
|
||||
$this->security->xss_clean('<img src="b on="<x">on=">"x onerror="alert(1)">')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_clean_sanitize_naughty_html_attributes()
|
||||
{
|
||||
$this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttribute="bar">'));
|
||||
$this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttributeNoQuotes=bar>'));
|
||||
$this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttributeWithSpaces = bar>'));
|
||||
$this->assertEquals('<foo prefixOnAttribute="bar">', $this->security->xss_clean('<foo prefixOnAttribute="bar">'));
|
||||
$this->assertEquals('<foo>onOutsideOfTag=test</foo>', $this->security->xss_clean('<foo>onOutsideOfTag=test</foo>'));
|
||||
$this->assertEquals('onNoTagAtAll = true', $this->security->xss_clean('onNoTagAtAll = true'));
|
||||
$this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo fscommand=case-insensitive>'));
|
||||
$this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo seekSegmentTime=whatever>'));
|
||||
|
||||
$this->assertEquals(
|
||||
'<foo bar=">" baz=\'>\' xss=removed>',
|
||||
$this->security->xss_clean('<foo bar=">" baz=\'>\' onAfterGreaterThan="quotes">')
|
||||
);
|
||||
$this->assertEquals(
|
||||
'<foo bar=">" baz=\'>\' xss=removed>',
|
||||
$this->security->xss_clean('<foo bar=">" baz=\'>\' onAfterGreaterThan=noQuotes>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<img src="x" on=""> on=<svg> onerror=alert(1)>',
|
||||
$this->security->xss_clean('<img src="x" on=""> on=<svg> onerror=alert(1)>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<img src="on=\'">"<svg> onerror=alert(1) onmouseover=alert(1)>',
|
||||
$this->security->xss_clean('<img src="on=\'">"<svg> onerror=alert(1) onmouseover=alert(1)>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<img src="x"> on=\'x\' onerror=``,alert(1)>',
|
||||
$this->security->xss_clean('<img src="x"> on=\'x\' onerror=``,alert(1)>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<a xss=removed>',
|
||||
$this->security->xss_clean('<a< onmouseover="alert(1)">')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<img src="x"> on=\'x\' onerror=,xssm()>',
|
||||
$this->security->xss_clean('<img src="x"> on=\'x\' onerror=,xssm()>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<image src="<>" xss=removed>',
|
||||
$this->security->xss_clean('<image src="<>" onerror=\'alert(1)\'>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<b xss=removed>',
|
||||
$this->security->xss_clean('<b "=<= onmouseover=alert(1)>')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<b xss=removed xss=removed>1">',
|
||||
$this->security->xss_clean('<b a=<=" onmouseover="alert(1),1>1">')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'<b x=" onmouseover=alert(1)//">',
|
||||
$this->security->xss_clean('<b "="< x=" onmouseover=alert(1)//">')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @depends test_xss_clean_sanitize_naughty_html_tags
|
||||
* @depends test_xss_clean_sanitize_naughty_html_attributes
|
||||
*/
|
||||
public function test_naughty_html_plus_evil_attributes()
|
||||
{
|
||||
$this->assertEquals(
|
||||
'<svg<img src="x" xss=removed>',
|
||||
$this->security->xss_clean('<svg<img > src="x" onerror="location=/javascript/.source+/:alert/.source+/(1)/.source">')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_xss_hash()
|
||||
{
|
||||
$this->assertEmpty($this->security->xss_hash);
|
||||
|
||||
// Perform hash
|
||||
$this->security->xss_hash();
|
||||
|
||||
$this->assertTrue(preg_match('#^[0-9a-f]{32}$#iS', $this->security->xss_hash) === 1);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_get_random_bytes()
|
||||
{
|
||||
$length = "invalid";
|
||||
$this->assertFalse($this->security->get_random_bytes($length));
|
||||
|
||||
$length = 10;
|
||||
$this->assertNotEmpty($this->security->get_random_bytes($length));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_entity_decode()
|
||||
{
|
||||
$encoded = '<div>Hello <b>Booya</b></div>';
|
||||
$decoded = $this->security->entity_decode($encoded);
|
||||
|
||||
$this->assertEquals('<div>Hello <b>Booya</b></div>', $decoded);
|
||||
|
||||
// Issue #3057 (https://github.com/bcit-ci/CodeIgniter/issues/3057)
|
||||
$this->assertEquals(
|
||||
'&foo should not include a semicolon',
|
||||
$this->security->entity_decode('&foo should not include a semicolon')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_sanitize_filename()
|
||||
{
|
||||
$filename = './<!--foo-->';
|
||||
$safe_filename = $this->security->sanitize_filename($filename);
|
||||
|
||||
$this->assertEquals('foo', $safe_filename);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_strip_image_tags()
|
||||
{
|
||||
$imgtags = array(
|
||||
'<img src="smiley.gif" alt="Smiley face" height="42" width="42">',
|
||||
'<img alt="Smiley face" height="42" width="42" src="smiley.gif">',
|
||||
'<img src="http://www.w3schools.com/images/w3schools_green.jpg">',
|
||||
'<img src="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img src="mdn-logo-sm.png" alt="MD Logo" srcset="mdn-logo-HD.png 2x, mdn-logo-small.png 15w, mdn-banner-HD.png 100w 2x" />',
|
||||
'<img sqrc="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img srqc="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img srcq="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img src=non-quoted.attribute foo="bar">'
|
||||
);
|
||||
|
||||
$urls = array(
|
||||
'smiley.gif',
|
||||
'smiley.gif',
|
||||
'http://www.w3schools.com/images/w3schools_green.jpg',
|
||||
'/img/sunset.gif',
|
||||
'mdn-logo-sm.png',
|
||||
'<img sqrc="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img srqc="/img/sunset.gif" height="100%" width="100%">',
|
||||
'<img srcq="/img/sunset.gif" height="100%" width="100%">',
|
||||
'non-quoted.attribute'
|
||||
);
|
||||
|
||||
for ($i = 0; $i < count($imgtags); $i++)
|
||||
{
|
||||
$this->assertEquals($urls[$i], $this->security->strip_image_tags($imgtags[$i]));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
public function test_csrf_set_hash()
|
||||
{
|
||||
// Set cookie for security test
|
||||
$_COOKIE['fw_csrf_cookie'] = md5(uniqid(mt_rand(), TRUE));
|
||||
|
||||
// Set config for Security class
|
||||
$config = Factory::getInstance()->config->getConfig('security');
|
||||
|
||||
$config->csrf_protection = true;
|
||||
$config->csrf_token_name = 'fw_csrf_token';
|
||||
|
||||
// leave csrf_cookie_name as blank to test _csrf_set_hash function
|
||||
$config->csrf_cookie_name = '';
|
||||
|
||||
$this->security = new Mock_Core_Security();
|
||||
|
||||
$this->assertNotEmpty($this->security->get_csrf_hash());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* FuzeWorks.
|
||||
*
|
||||
* The FuzeWorks MVC PHP FrameWork
|
||||
*
|
||||
* Copyright (C) 2015 TechFuze
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author TechFuze
|
||||
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
||||
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
||||
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
||||
*
|
||||
* @link http://fuzeworks.techfuze.net
|
||||
* @since Version 0.0.1
|
||||
*
|
||||
* @version Version 0.0.1
|
||||
*/
|
||||
|
||||
use FuzeWorks\Factory;
|
||||
|
||||
/**
|
||||
* Class Utf8Test.
|
||||
*
|
||||
* Core testing suite, will test UTF8 class functionality
|
||||
*/
|
||||
class utf8Test extends CoreTestAbstract
|
||||
{
|
||||
|
||||
protected $factory;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->factory = Factory::getInstance();
|
||||
|
||||
$this->factory->config->getConfig('main')->charset = 'UTF-8';
|
||||
$this->utf8 = new Mock_Core_Utf8();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __construct() test
|
||||
*
|
||||
* @covers Utf8::__construct
|
||||
*/
|
||||
public function test___construct()
|
||||
{
|
||||
if (defined('PREG_BAD_UTF8_ERROR') && (ICONV_ENABLED === TRUE OR MB_ENABLED === TRUE) && strtoupper($this->factory->config->getConfig('main')->charset) === 'UTF-8')
|
||||
{
|
||||
$this->assertTrue(UTF8_ENABLED);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->assertFalse(UTF8_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* is_ascii() test
|
||||
*
|
||||
* Note: DO NOT move this below test_clean_string()
|
||||
*/
|
||||
public function test_is_ascii()
|
||||
{
|
||||
$this->assertTrue($this->utf8->is_ascii('foo bar'));
|
||||
$this->assertFalse($this->utf8->is_ascii('тест'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* clean_string() test
|
||||
*
|
||||
* @depends test_is_ascii
|
||||
* @covers Utf8::clean_string
|
||||
*/
|
||||
public function test_clean_string()
|
||||
{
|
||||
$this->assertEquals('foo bar', $this->utf8->clean_string('foo bar'));
|
||||
|
||||
$illegal_utf8 = "\xc0тест";
|
||||
if (MB_ENABLED)
|
||||
{
|
||||
$this->assertEquals('тест', $this->utf8->clean_string($illegal_utf8));
|
||||
}
|
||||
elseif (ICONV_ENABLED)
|
||||
{
|
||||
// This is a known issue, iconv doesn't always work with //IGNORE
|
||||
$this->assertTrue(in_array($this->utf8->clean_string($illegal_utf8), array('тест', ''), TRUE));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->assertEquals($illegal_utf8, $this->utf8->clean_string($illegal_utf8));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* convert_to_utf8() test
|
||||
*
|
||||
* @covers Utf8::convert_to_utf8
|
||||
*/
|
||||
public function test_convert_to_utf8()
|
||||
{
|
||||
$this->markTestSkipped("Does not work properly yet. See issue #95");
|
||||
if (MB_ENABLED OR ICONV_ENABLED)
|
||||
{
|
||||
$this->assertEquals('тест', $this->utf8->convert_to_utf8('<27><><EFBFBD><EFBFBD>', 'WINDOWS-1251'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->assertFalse($this->utf8->convert_to_utf8('<27><><EFBFBD><EFBFBD>', 'WINDOWS-1251'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use FuzeWorks\Library\FW_Encryption;
|
||||
|
||||
class Mock_Libraries_Encryption extends FW_Encryption {
|
||||
|
||||
/**
|
||||
* __get_params()
|
||||
*
|
||||
* Allows public calls to the otherwise protected _get_params().
|
||||
*/
|
||||
public function __get_params($params)
|
||||
{
|
||||
return $this->_get_params($params);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* get_key()
|
||||
*
|
||||
* Allows checking for key changes.
|
||||
*/
|
||||
public function get_key()
|
||||
{
|
||||
return $this->_key;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __driver_get_handle()
|
||||
*
|
||||
* Allows checking for _mcrypt_get_handle(), _openssl_get_handle()
|
||||
*/
|
||||
public function __driver_get_handle($driver, $cipher, $mode)
|
||||
{
|
||||
return $this->{'_'.$driver.'_get_handle'}($cipher, $mode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,423 @@
|
|||
<?php
|
||||
/**
|
||||
* FuzeWorks.
|
||||
*
|
||||
* The FuzeWorks MVC PHP FrameWork
|
||||
*
|
||||
* Copyright (C) 2015 TechFuze
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author TechFuze
|
||||
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
||||
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
||||
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
||||
*
|
||||
* @link http://fuzeworks.techfuze.net
|
||||
* @since Version 0.0.1
|
||||
*
|
||||
* @version Version 0.0.1
|
||||
*/
|
||||
|
||||
use FuzeWorks\Factory;
|
||||
|
||||
/**
|
||||
* Class FactoryTest.
|
||||
*
|
||||
* Will test the FuzeWorks Factory.
|
||||
*/
|
||||
class encryptionTest extends CoreTestAbstract
|
||||
{
|
||||
|
||||
protected $factory;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->factory = Factory::getInstance();
|
||||
$this->factory->libraries->get('encryption');
|
||||
require_once('encryption/mock_encryption.php');
|
||||
$this->encryption = new Mock_Libraries_Encryption();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __construct test
|
||||
*
|
||||
* Covers behavior with $config['encryption_key'] set or not
|
||||
*/
|
||||
public function test___construct()
|
||||
{
|
||||
// Assume no configuration from set_up()
|
||||
$this->assertNull($this->encryption->get_key());
|
||||
|
||||
// Try with an empty value
|
||||
$this->factory->config->getConfig('encryption')->encryption_key = '';
|
||||
$this->encrypt = new Mock_Libraries_Encryption();
|
||||
$this->assertNull($this->encrypt->get_key());
|
||||
|
||||
$this->factory->config->getConfig('encryption')->encryption_key = str_repeat("\x0", 16);
|
||||
$this->encrypt = new Mock_Libraries_Encryption();
|
||||
$this->assertEquals(str_repeat("\x0", 16), $this->encrypt->get_key());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* hkdf() test
|
||||
*
|
||||
* Applies test vectors described in Appendix A(1-3) RFC5869.
|
||||
* Described vectors 4-7 SHA-1, which we don't support and are
|
||||
* therefore excluded.
|
||||
*
|
||||
* Because our implementation is a single method instead of being
|
||||
* split into hkdf_extract() and hkdf_expand(), we cannot test for
|
||||
* the PRK value. As long as the OKM is correct though, it's fine.
|
||||
*
|
||||
* @link https://tools.ietf.org/rfc/rfc5869.txt
|
||||
*/
|
||||
public function test_hkdf()
|
||||
{
|
||||
$vectors = array(
|
||||
// A.1: Basic test case with SHA-256
|
||||
array(
|
||||
'digest' => 'sha256',
|
||||
'ikm' => "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
|
||||
'salt' => "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c",
|
||||
'length' => 42,
|
||||
'info' => "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9",
|
||||
// 'prk' => "\x07\x77\x09\x36\x2c\x2e\x32\xdf\x0d\xdc\x3f\x0d\xc4\x7b\xba\x63\x90\xb6\xc7\x3b\xb5\x0f\x9c\x31\x22\xec\x84\x4a\xd7\xc2\xb3\xe5",
|
||||
'okm' => "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65"
|
||||
),
|
||||
// A.2: Test with SHA-256 and longer inputs/outputs
|
||||
array(
|
||||
'digest' => 'sha256',
|
||||
'ikm' => "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
|
||||
'salt' => "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
|
||||
'length' => 82,
|
||||
'info' => "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
|
||||
// 'prk' => "\x06\xa6\xb8\x8c\x58\x53\x36\x1a\x06\x10\x4c\x9c\xeb\x35\xb4\x5c\xef\x76\x00\x14\x90\x46\x71\x01\x4a\x19\x3f\x40\xc1\x5f\xc2\x44",
|
||||
'okm' => "\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a\x49\x34\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c\x19\xaf\xa9\x7c\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb\x41\xc6\x5e\x59\x0e\x09\xda\x32\x75\x60\x0c\x2f\x09\xb8\x36\x77\x93\xa9\xac\xa3\xdb\x71\xcc\x30\xc5\x81\x79\xec\x3e\x87\xc1\x4c\x01\xd5\xc1\xf3\x43\x4f\x1d\x87",
|
||||
),
|
||||
// A.3: Test with SHA-256 and zero-length salt/info
|
||||
array(
|
||||
'digest' => 'sha256',
|
||||
'ikm' => "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
|
||||
'salt' => '',
|
||||
'length' => 42,
|
||||
'info' => '',
|
||||
// 'prk' => "\x19\xef\x24\xa3\x2c\x71\x7b\x16\x7f\x33\xa9\x1d\x6f\x64\x8b\xdf\x96\x59\x67\x76\xaf\xdb\x63\x77\xac\x43\x4c\x1c\x29\x3c\xcb\x04",
|
||||
'okm' => "\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f\x71\x5f\x80\x2a\x06\x3c\x5a\x31\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d\x9d\x20\x13\x95\xfa\xa4\xb6\x1a\x96\xc8",
|
||||
)
|
||||
);
|
||||
|
||||
foreach ($vectors as $test)
|
||||
{
|
||||
$this->assertEquals(
|
||||
$test['okm'],
|
||||
$this->encryption->hkdf(
|
||||
$test['ikm'],
|
||||
$test['digest'],
|
||||
$test['salt'],
|
||||
$test['length'],
|
||||
$test['info']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Test default length, it must match the digest size
|
||||
$this->assertEquals(64, strlen($this->encryption->hkdf('foobar', 'sha512')));
|
||||
|
||||
// Test maximum length (RFC5869 says that it must be up to 255 times the digest size)
|
||||
$this->assertEquals(12240, strlen($this->encryption->hkdf('foobar', 'sha384', NULL, 48 * 255)));
|
||||
$this->assertFalse($this->encryption->hkdf('foobar', 'sha224', NULL, 28 * 255 + 1));
|
||||
|
||||
// CI-specific test for an invalid digest
|
||||
$this->assertFalse($this->encryption->hkdf('fobar', 'sha1'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* _get_params() test
|
||||
*/
|
||||
public function test__get_params()
|
||||
{
|
||||
$key = str_repeat("\x0", 16);
|
||||
|
||||
// Invalid custom parameters
|
||||
$params = array(
|
||||
// No cipher, mode or key
|
||||
array('cipher' => 'aes-128', 'mode' => 'cbc'),
|
||||
array('cipher' => 'aes-128', 'key' => $key),
|
||||
array('mode' => 'cbc', 'key' => $key),
|
||||
// No HMAC key or not a valid digest
|
||||
array('cipher' => 'aes-128', 'mode' => 'cbc', 'key' => $key),
|
||||
array('cipher' => 'aes-128', 'mode' => 'cbc', 'key' => $key, 'hmac_digest' => 'sha1', 'hmac_key' => $key),
|
||||
// Invalid mode
|
||||
array('cipher' => 'aes-128', 'mode' => 'foo', 'key' => $key, 'hmac_digest' => 'sha256', 'hmac_key' => $key)
|
||||
);
|
||||
|
||||
for ($i = 0, $c = count($params); $i < $c; $i++)
|
||||
{
|
||||
$this->assertFalse($this->encryption->__get_params($params[$i]));
|
||||
}
|
||||
|
||||
// Valid parameters
|
||||
$params = array(
|
||||
'cipher' => 'aes-128',
|
||||
'mode' => 'cbc',
|
||||
'key' => str_repeat("\x0", 16),
|
||||
'hmac_key' => str_repeat("\x0", 16)
|
||||
);
|
||||
|
||||
$this->assertTrue(is_array($this->encryption->__get_params($params)));
|
||||
|
||||
$params['base64'] = TRUE;
|
||||
$params['hmac_digest'] = 'sha512';
|
||||
|
||||
// Including all parameters
|
||||
$params = array(
|
||||
'cipher' => 'aes-128',
|
||||
'mode' => 'cbc',
|
||||
'key' => str_repeat("\x0", 16),
|
||||
'raw_data' => TRUE,
|
||||
'hmac_key' => str_repeat("\x0", 16),
|
||||
'hmac_digest' => 'sha256'
|
||||
);
|
||||
|
||||
$output = $this->encryption->__get_params($params);
|
||||
unset($output['handle'], $output['cipher'], $params['raw_data'], $params['cipher']);
|
||||
$params['base64'] = FALSE;
|
||||
$this->assertEquals($params, $output);
|
||||
|
||||
// HMAC disabled
|
||||
unset($params['hmac_key'], $params['hmac_digest']);
|
||||
$params['hmac'] = $params['raw_data'] = FALSE;
|
||||
$params['cipher'] = 'aes-128';
|
||||
$output = $this->encryption->__get_params($params);
|
||||
unset($output['handle'], $output['cipher'], $params['hmac'], $params['raw_data'], $params['cipher']);
|
||||
$params['base64'] = TRUE;
|
||||
$params['hmac_digest'] = $params['hmac_key'] = NULL;
|
||||
$this->assertEquals($params, $output);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* initialize(), encrypt(), decrypt() test
|
||||
*
|
||||
* Testing the three methods separately is not realistic as they are
|
||||
* designed to work together. A more thorough test for initialize()
|
||||
* though is the OpenSSL/MCrypt compatibility test.
|
||||
*
|
||||
* @depends test_hkdf
|
||||
* @depends test__get_params
|
||||
*/
|
||||
public function test_initialize_encrypt_decrypt()
|
||||
{
|
||||
$message = 'This is a plain-text message.';
|
||||
$key = "\xd0\xc9\x08\xc4\xde\x52\x12\x6e\xf8\xcc\xdb\x03\xea\xa0\x3a\x5c";
|
||||
|
||||
// Default state (AES-128/Rijndael-128 in CBC mode)
|
||||
$this->encryption->initialize(array('key' => $key));
|
||||
|
||||
// Was the key properly set?
|
||||
$this->assertEquals($key, $this->encryption->get_key());
|
||||
|
||||
$this->assertEquals($message, $this->encryption->decrypt($this->encryption->encrypt($message)));
|
||||
|
||||
// Try DES in ECB mode, just for the sake of changing stuff
|
||||
$this->encryption->initialize(array('cipher' => 'des', 'mode' => 'ecb', 'key' => substr($key, 0, 8)));
|
||||
$this->assertEquals($message, $this->encryption->decrypt($this->encryption->encrypt($message)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* encrypt(), decrypt test with custom parameters
|
||||
*
|
||||
* @depends test__get_params
|
||||
*/
|
||||
public function test_encrypt_decrypt_custom()
|
||||
{
|
||||
$message = 'Another plain-text message.';
|
||||
|
||||
// A random invalid parameter
|
||||
$this->assertFalse($this->encryption->encrypt($message, array('foo')));
|
||||
$this->assertFalse($this->encryption->decrypt($message, array('foo')));
|
||||
|
||||
// No HMAC, binary output
|
||||
$params = array(
|
||||
'cipher' => 'tripledes',
|
||||
'mode' => 'cfb',
|
||||
'key' => str_repeat("\x1", 16),
|
||||
'base64' => FALSE,
|
||||
'hmac' => FALSE
|
||||
);
|
||||
|
||||
$ciphertext = $this->encryption->encrypt($message, $params);
|
||||
|
||||
$this->assertEquals($message, $this->encryption->decrypt($ciphertext, $params));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* _mcrypt_get_handle() test
|
||||
*/
|
||||
public function test__mcrypt_get_handle()
|
||||
{
|
||||
if ($this->encryption->drivers['mcrypt'] === FALSE)
|
||||
{
|
||||
return $this->markTestSkipped('Cannot test MCrypt because it is not available.');
|
||||
}
|
||||
|
||||
$this->assertTrue(is_resource($this->encryption->__driver_get_handle('mcrypt', 'rijndael-128', 'cbc')));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* _openssl_get_handle() test
|
||||
*/
|
||||
public function test__openssl_mcrypt_get_handle()
|
||||
{
|
||||
if ($this->encryption->drivers['openssl'] === FALSE)
|
||||
{
|
||||
return $this->markTestSkipped('Cannot test OpenSSL because it is not available.');
|
||||
}
|
||||
|
||||
$this->assertEquals('aes-128-cbc', $this->encryption->__driver_get_handle('openssl', 'aes-128', 'cbc'));
|
||||
$this->assertEquals('rc4-40', $this->encryption->__driver_get_handle('openssl', 'rc4-40', 'stream'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* OpenSSL/MCrypt portability test
|
||||
*
|
||||
* Amongst the obvious stuff, _cipher_alias() is also tested here.
|
||||
*/
|
||||
public function test_portability()
|
||||
{
|
||||
if ( ! $this->encryption->drivers['mcrypt'] OR ! $this->encryption->drivers['openssl'])
|
||||
{
|
||||
$this->markTestSkipped('Both MCrypt and OpenSSL support are required for portability tests.');
|
||||
return;
|
||||
}
|
||||
|
||||
$message = 'This is a message encrypted via MCrypt and decrypted via OpenSSL, or vice-versa.';
|
||||
|
||||
// Format is: <Cipher name>, <Cipher mode>, <Key size>
|
||||
$portable = array(
|
||||
array('aes-128', 'cbc', 16),
|
||||
array('aes-128', 'cfb', 16),
|
||||
array('aes-128', 'cfb8', 16),
|
||||
array('aes-128', 'ofb', 16),
|
||||
array('aes-128', 'ecb', 16),
|
||||
array('aes-128', 'ctr', 16),
|
||||
array('aes-192', 'cbc', 24),
|
||||
array('aes-192', 'cfb', 24),
|
||||
array('aes-192', 'cfb8', 24),
|
||||
array('aes-192', 'ofb', 24),
|
||||
array('aes-192', 'ecb', 24),
|
||||
array('aes-192', 'ctr', 24),
|
||||
array('aes-256', 'cbc', 32),
|
||||
array('aes-256', 'cfb', 32),
|
||||
array('aes-256', 'cfb8', 32),
|
||||
array('aes-256', 'ofb', 32),
|
||||
array('aes-256', 'ecb', 32),
|
||||
array('aes-256', 'ctr', 32),
|
||||
array('des', 'cbc', 7),
|
||||
array('des', 'cfb', 7),
|
||||
array('des', 'cfb8', 7),
|
||||
array('des', 'ofb', 7),
|
||||
array('des', 'ecb', 7),
|
||||
array('tripledes', 'cbc', 7),
|
||||
array('tripledes', 'cfb', 7),
|
||||
array('tripledes', 'cfb8', 7),
|
||||
array('tripledes', 'ofb', 7),
|
||||
array('tripledes', 'cbc', 14),
|
||||
array('tripledes', 'cfb', 14),
|
||||
array('tripledes', 'cfb8', 14),
|
||||
array('tripledes', 'ofb', 14),
|
||||
array('tripledes', 'cbc', 21),
|
||||
array('tripledes', 'cfb', 21),
|
||||
array('tripledes', 'cfb8', 21),
|
||||
array('tripledes', 'ofb', 21),
|
||||
array('blowfish', 'cbc', 16),
|
||||
array('blowfish', 'cfb', 16),
|
||||
array('blowfish', 'ofb', 16),
|
||||
array('blowfish', 'ecb', 16),
|
||||
array('blowfish', 'cbc', 56),
|
||||
array('blowfish', 'cfb', 56),
|
||||
array('blowfish', 'ofb', 56),
|
||||
array('blowfish', 'ecb', 56),
|
||||
array('cast5', 'cbc', 11),
|
||||
array('cast5', 'cfb', 11),
|
||||
array('cast5', 'ofb', 11),
|
||||
array('cast5', 'ecb', 11),
|
||||
array('cast5', 'cbc', 16),
|
||||
array('cast5', 'cfb', 16),
|
||||
array('cast5', 'ofb', 16),
|
||||
array('cast5', 'ecb', 16),
|
||||
array('rc4', 'stream', 5),
|
||||
array('rc4', 'stream', 8),
|
||||
array('rc4', 'stream', 16),
|
||||
array('rc4', 'stream', 32),
|
||||
array('rc4', 'stream', 64),
|
||||
array('rc4', 'stream', 128),
|
||||
array('rc4', 'stream', 256)
|
||||
);
|
||||
$driver_index = array('mcrypt', 'openssl');
|
||||
|
||||
foreach ($portable as &$test)
|
||||
{
|
||||
// Add some randomness to the selected driver
|
||||
$driver = mt_rand(0,1);
|
||||
$params = array(
|
||||
'driver' => $driver_index[$driver],
|
||||
'cipher' => $test[0],
|
||||
'mode' => $test[1],
|
||||
'key' => openssl_random_pseudo_bytes($test[2])
|
||||
);
|
||||
|
||||
$this->encryption->initialize($params);
|
||||
$ciphertext = $this->encryption->encrypt($message);
|
||||
|
||||
$driver = (int) ! $driver;
|
||||
$params['driver'] = $driver_index[$driver];
|
||||
|
||||
$this->encryption->initialize($params);
|
||||
$this->assertEquals($message, $this->encryption->decrypt($ciphertext));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __get() test
|
||||
*/
|
||||
public function test_magic_get()
|
||||
{
|
||||
$this->assertNull($this->encryption->foo);
|
||||
$this->assertEquals(array('mcrypt', 'openssl'), array_keys($this->encryption->drivers));
|
||||
|
||||
// 'stream' mode is translated into an empty string for OpenSSL
|
||||
$this->encryption->initialize(array('cipher' => 'rc4', 'mode' => 'stream'));
|
||||
$this->assertEquals('stream', $this->encryption->mode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
// This autoloader provide convinient way to working with mock object
|
||||
// make the test looks natural. This autoloader support cascade file loading as well
|
||||
// within mocks directory.
|
||||
//
|
||||
// Prototype :
|
||||
//
|
||||
// $mock_table = new Mock_Libraries_Table(); // Will load ./mocks/libraries/table.php
|
||||
// $mock_database_driver = new Mock_Database_Driver(); // Will load ./mocks/database/driver.php
|
||||
// and so on...
|
||||
function autoload($class)
|
||||
{
|
||||
$dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
|
||||
|
||||
$fw_core = array(
|
||||
'Benchmark',
|
||||
'Config',
|
||||
'Controller',
|
||||
'Exceptions',
|
||||
'Hooks',
|
||||
'Input',
|
||||
'Lang',
|
||||
'Loader',
|
||||
'Log',
|
||||
'Model',
|
||||
'Output',
|
||||
'Router',
|
||||
'Security',
|
||||
'URI',
|
||||
'Utf8'
|
||||
);
|
||||
|
||||
$fw_libraries = array(
|
||||
'Calendar',
|
||||
'Cart',
|
||||
'Driver_Library',
|
||||
'Email',
|
||||
'Encrypt',
|
||||
'Encryption',
|
||||
'Form_validation',
|
||||
'Ftp',
|
||||
'Image_lib',
|
||||
'Javascript',
|
||||
'Migration',
|
||||
'Pagination',
|
||||
'Parser',
|
||||
'Profiler',
|
||||
'Table',
|
||||
'Trackback',
|
||||
'Typography',
|
||||
'Unit_test',
|
||||
'Upload',
|
||||
'User_agent',
|
||||
'Xmlrpc',
|
||||
'Zip'
|
||||
);
|
||||
|
||||
$fw_drivers = array('Session', 'Cache');
|
||||
|
||||
if (strpos($class, 'Mock_') === 0)
|
||||
{
|
||||
$class = strtolower(str_replace(array('Mock_', '_'), array('', DIRECTORY_SEPARATOR), $class));
|
||||
}
|
||||
elseif (strpos($class, 'FW_') === 0)
|
||||
{
|
||||
$subclass = substr($class, 3);
|
||||
|
||||
if (in_array($subclass, $fw_core))
|
||||
{
|
||||
$dir = 'Core'.DIRECTORY_SEPARATOR.'System'.DIRECTORY_SEPARATOR;
|
||||
$class = $subclass;
|
||||
}
|
||||
elseif (in_array($subclass, $fw_libraries))
|
||||
{
|
||||
$dir = 'Core'.DIRECTORY_SEPARATOR.'Libraries'.DIRECTORY_SEPARATOR;
|
||||
$class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass;
|
||||
}
|
||||
elseif (in_array($subclass, $fw_drivers))
|
||||
{
|
||||
$dir = 'Core'.DIRECTORY_SEPARATOR.'Libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR;
|
||||
$class = $subclass;
|
||||
}
|
||||
elseif (in_array(($parent = strtok($subclass, '_')), $fw_drivers)) {
|
||||
$dir = 'Core'.DIRECTORY_SEPARATOR.'Libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
|
||||
$class = $subclass;
|
||||
}
|
||||
elseif (preg_match('/^FW_DB_(.+)_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 4)
|
||||
{
|
||||
$driver_path = 'Core'.DIRECTORY_SEPARATOR.'Database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
|
||||
$dir = $driver_path.$m[1].DIRECTORY_SEPARATOR.'subdrivers'.DIRECTORY_SEPARATOR;
|
||||
$file = $dir.$m[1].'_'.$m[2].'_'.$m[3].'.php';
|
||||
}
|
||||
elseif (preg_match('/^FW_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3)
|
||||
{
|
||||
$driver_path = 'Core'.DIRECTORY_SEPARATOR.'Database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
|
||||
$dir = $driver_path.$m[1].DIRECTORY_SEPARATOR;
|
||||
$file = $dir.$m[1].'_'.$m[2].'.php';
|
||||
}
|
||||
elseif (strpos($class, 'FW_DB') === 0)
|
||||
{
|
||||
$dir = 'Core'.DIRECTORY_SEPARATOR.'Database'.DIRECTORY_SEPARATOR;
|
||||
$file = $dir.str_replace(array('FW_DB','active_record'), array('DB', 'active_rec'), $subclass).'.php';
|
||||
}
|
||||
else
|
||||
{
|
||||
$class = strtolower($class);
|
||||
}
|
||||
}
|
||||
|
||||
$file = isset($file) ? $file : $dir.$class.'.php';
|
||||
|
||||
if ( ! file_exists($file))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
include_once($file);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
use FuzeWorks\Input;
|
||||
use FuzeWorks\Factory;
|
||||
|
||||
class Mock_Core_Input extends Input {
|
||||
|
||||
/**
|
||||
* Since we use GLOBAL to fetch Security and Utf8 classes,
|
||||
* we need to use inversion of control to mock up
|
||||
* the same process within CI_Input class constructor.
|
||||
*
|
||||
* @covers CI_Input::__construct()
|
||||
*/
|
||||
public function __construct($security, $utf8)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->_allow_get_array = ($this->factory->config->getConfig('routing')->allow_get_array === TRUE);
|
||||
$this->_enable_xss = ($this->factory->config->getConfig('security')->global_xss_filtering === TRUE);
|
||||
$this->_enable_csrf = ($this->factory->config->getConfig('security')->csrf_protection === TRUE);
|
||||
|
||||
// Assign Security and Utf8 classes
|
||||
$this->security = $security;
|
||||
$this->uni = $utf8;
|
||||
|
||||
// Sanitize global arrays
|
||||
$this->_sanitize_globals();
|
||||
}
|
||||
|
||||
public function fetch_from_array($array, $index = '', $xss_clean = FALSE)
|
||||
{
|
||||
return parent::_fetch_from_array($array, $index, $xss_clean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lie about being a CLI request
|
||||
*
|
||||
* We take advantage of this in libraries/Session_test
|
||||
*/
|
||||
public function is_cli_request()
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($name === 'ip_address')
|
||||
{
|
||||
$this->ip_address = $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use FuzeWorks\Security;
|
||||
|
||||
class Mock_Core_Security extends Security {
|
||||
|
||||
public function csrf_set_cookie()
|
||||
{
|
||||
// We cannot set cookie in CLI mode, so for csrf test, who rely on $_COOKIE,
|
||||
// we superseded set_cookie with directly set the cookie variable,
|
||||
// @see : ./tests/codeigniter/core/Security_test.php, line 8
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Override inaccessible protected properties
|
||||
public function __get($property)
|
||||
{
|
||||
return isset($this->{'_'.$property}) ? $this->{'_'.$property} : NULL;
|
||||
}
|
||||
|
||||
public function remove_evil_attributes($str, $is_image)
|
||||
{
|
||||
return $this->_remove_evil_attributes($str, $is_image);
|
||||
}
|
||||
|
||||
// Override inaccessible protected method
|
||||
public function __call($method, $params)
|
||||
{
|
||||
if (is_callable(array($this, '_'.$method)))
|
||||
{
|
||||
return call_user_func_array(array($this, '_'.$method), $params);
|
||||
}
|
||||
|
||||
throw new BadMethodCallException('Method '.$method.' was not found');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
use FuzeWorks\Utf8;
|
||||
|
||||
class Mock_Core_Utf8 extends Utf8 {
|
||||
|
||||
/**
|
||||
* We need to define UTF8_ENABLED the same way that
|
||||
* CI_Utf8 constructor does.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (defined('UTF8_ENABLED'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue