rebase from live enviornment

This commit is contained in:
Rachit Bhargava
2024-01-09 22:14:20 -05:00
parent ff0b49a046
commit 3a22fcaa4a
15968 changed files with 2344674 additions and 45234 deletions

16
wp/plugins/wordfence/vendor/.htaccess vendored Normal file
View File

@@ -0,0 +1,16 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} \.php$
RewriteRule .* - [F,L,NC]
</IfModule>
<IfModule !mod_rewrite.c>
<FilesMatch "\.php$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
</FilesMatch>
</IfModule>

View File

@@ -0,0 +1,9 @@
<?php
// autoload.php @generated by Composer
if (!class_exists('ComposerAutoloaderInit736008d0fa54169b3444ae0f3fc20155')) {
require_once __DIR__ . '/composer/autoload_real.php';
}
return ComposerAutoloaderInit736008d0fa54169b3444ae0f3fc20155::getLoader();

View File

@@ -0,0 +1,481 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
private $vendorDir;
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
private static $registeredLoaders = array();
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View File

@@ -0,0 +1,337 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require it's presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
private static $installed;
private static $canGetVendors;
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
}

View File

@@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
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.

View File

@@ -0,0 +1,10 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Wordfence\\MmdbReader\\' => array($vendorDir . '/wordfence/mmdb-reader/src'),
);

View File

@@ -0,0 +1,55 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit736008d0fa54169b3444ae0f3fc20155
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit736008d0fa54169b3444ae0f3fc20155', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit736008d0fa54169b3444ae0f3fc20155', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit736008d0fa54169b3444ae0f3fc20155::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
return $loader;
}
}

View File

@@ -0,0 +1,36 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit736008d0fa54169b3444ae0f3fc20155
{
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'Wordfence\\MmdbReader\\' => 21,
),
);
public static $prefixDirsPsr4 = array (
'Wordfence\\MmdbReader\\' =>
array (
0 => __DIR__ . '/..' . '/wordfence/mmdb-reader/src',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit736008d0fa54169b3444ae0f3fc20155::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit736008d0fa54169b3444ae0f3fc20155::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit736008d0fa54169b3444ae0f3fc20155::$classMap;
}, null, ClassLoader::class);
}
}

View File

@@ -0,0 +1,63 @@
{
"packages": [
{
"name": "wordfence/mmdb-reader",
"version": "v1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "git@github.com:wordfence/mmdb-reader.git",
"reference": "f72435e75f6654da08c2f0983e527cb207ef1f2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wordfence/mmdb-reader/zipball/f72435e75f6654da08c2f0983e527cb207ef1f2a",
"reference": "f72435e75f6654da08c2f0983e527cb207ef1f2a",
"shasum": ""
},
"time": "2022-09-23T20:02:31+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Wordfence\\MmdbReader\\": "src/"
}
},
"license": [
"proprietary"
],
"authors": [
{
"name": "Alex Kenion",
"email": "alexk@wordfence.com"
}
],
"description": "A MaxMind DB (MMDB) reader with no external dependencies that provides support for a wider range of PHP versions than the official library",
"support": {
"source": "https://github.com/wordfence/mmdb-reader/tree/v1.0.0",
"issues": "https://github.com/wordfence/mmdb-reader/issues"
},
"install-path": "../wordfence/mmdb-reader"
},
{
"name": "wordfence/wf-waf",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/wordfence/wf-waf.git",
"reference": "origin/master"
},
"dist": {
"type": "zip",
"url": "https://github.com/wordfence/wf-waf/zipball/master",
"reference": "origin/master"
},
"type": "library",
"installation-source": "source",
"install-path": "../wordfence/wf-waf"
}
],
"dev": true,
"dev-package-names": []
}

View File

@@ -0,0 +1,41 @@
<?php return array(
'root' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'f7e640f16c0caa9077e4eaf4f42a42c9d1c76a05',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'f7e640f16c0caa9077e4eaf4f42a42c9d1c76a05',
'dev_requirement' => false,
),
'wordfence/mmdb-reader' => array(
'pretty_version' => 'v1.0.0',
'version' => '1.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../wordfence/mmdb-reader',
'aliases' => array(),
'reference' => 'f72435e75f6654da08c2f0983e527cb207ef1f2a',
'dev_requirement' => false,
),
'wordfence/wf-waf' => array(
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../wordfence/wf-waf',
'aliases' => array(),
'reference' => 'origin/master',
'dev_requirement' => false,
),
),
);

View File

@@ -0,0 +1,118 @@
<?php
namespace Wordfence\MmdbReader;
class ControlByte {
const TYPE_EXTENDED = 0;
const TYPE_POINTER = 1;
const TYPE_UTF8_STRING = 2;
const TYPE_DOUBLE = 3;
const TYPE_BYTES = 4;
const TYPE_UINT16 = 5;
const TYPE_UINT32 = 6;
const TYPE_MAP = 7;
const TYPE_INT32 = 8;
const TYPE_UINT64 = 9;
const TYPE_UINT128 = 10;
const TYPE_ARRAY = 11;
const TYPE_CONTAINER = 12;
const TYPE_END_MARKER = 13;
const TYPE_BOOLEAN = 14;
const TYPE_FLOAT = 15;
const EXTENSION_OFFSET = 7;
const SIZE_MASK = 31;
const MAX_SINGLE_BYTE_SIZE = 28;
private $type;
private $size;
public function __construct($type, $size) {
$this->type = $type;
$this->size = $size;
}
public function getType() {
return $this->type;
}
public function getTypeName() {
return self::mapTypeName($this->getType());
}
public function getSize() {
return $this->size;
}
public function is($type) {
return $this->type === $type;
}
public static function consume($handle) {
$byte = $handle->readByte();
$type = $byte >> 5;
if ($type === self::TYPE_EXTENDED)
$type = $handle->readByte() + self::EXTENSION_OFFSET;
$size = $byte & self::SIZE_MASK;
if ($size > self::MAX_SINGLE_BYTE_SIZE) {
$bytes = $size - self::MAX_SINGLE_BYTE_SIZE;
switch ($size) {
case 30:
$size = 285;
break;
case 31:
$size = 65821;
break;
default:
break;
}
$size += IntegerParser::parseUnsigned($handle, $bytes);
}
return new self($type, $size);
}
public static function mapTypeName($type) {
switch ($type) {
case self::TYPE_EXTENDED:
return 'TYPE_EXTENDED';
case self::TYPE_POINTER:
return 'TYPE_POINTER';
case self::TYPE_UTF8_STRING:
return 'TYPE_UTF8_STRING';
case self::TYPE_DOUBLE:
return 'TYPE_DOUBLE';
case self::TYPE_BYTES:
return 'TYPE_BYTES';
case self::TYPE_UINT16:
return 'TYPE_UINT16';
case self::TYPE_UINT32:
return 'TYPE_UINT32';
case self::TYPE_MAP:
return 'TYPE_MAP';
case self::TYPE_INT32:
return 'TYPE_INT32';
case self::TYPE_UINT64:
return 'TYPE_UINT64';
case self::TYPE_UINT128:
return 'TYPE_UINT128';
case self::TYPE_ARRAY:
return 'TYPE_ARRAY';
case self::TYPE_CONTAINER:
return 'TYPE_CONTAINER';
case self::TYPE_END_MARKER:
return 'TYPE_END_MARKER';
case self::TYPE_BOOLEAN:
return 'TYPE_BOOLEAN';
case self::TYPE_FLOAT:
return 'TYPE_FLOAT';
default:
return 'UNKNOWN';
}
}
public function __toString() {
return sprintf('%s(%d) of size %d', $this->getTypeName(), $this->getType(), $this->getSize());
}
}

View File

@@ -0,0 +1,167 @@
<?php
namespace Wordfence\MmdbReader;
use Wordfence\MmdbReader\Exception\FormatException;
use Wordfence\MmdbReader\Exception\InvalidArgumentException;
class DataFieldParser {
private $handle;
private $sectionOffset;
public function __construct($handle, $sectionOffset = null) {
$this->handle = $handle;
$this->sectionOffset = $sectionOffset === null ? $this->handle->getPosition() : $sectionOffset;
}
public function processControlByte() {
return ControlByte::consume($this->handle);
}
private function readStandardField($controlByte) {
$size = $controlByte->getSize();
if ($size === 0)
return '';
return $this->handle->read($size);
}
private function parseUtf8String($controlByte) {
return $this->readStandardField($controlByte);
}
private function parseUnsignedInteger($controlByte) {
//TODO: Does this handle large-enough values gracefully?
return IntegerParser::parseUnsigned($this->handle, $controlByte->getSize());
}
private function parseMap($controlByte) {
$map = array();
for ($i = 0; $i < $controlByte->getSize(); $i++) {
$keyByte = $this->processControlByte();
$key = $this->parseField($keyByte);
if (!is_string($key))
throw new FormatException('Map keys must be strings, received ' . $keyByte . ' / ' . print_r($key, true) . ', map: ' . print_r($map, true));
$value = $this->parseField();
$map[$key] = $value;
}
return $map;
}
private function parseArray($controlByte) {
$array = array();
for ($i = 0; $i < $controlByte->getSize(); $i++) {
$array[$i] = $this->parseField();
}
return $array;
}
private function parseBoolean($controlByte) {
return (bool) $controlByte->getSize();
}
private static function unpackSingleValue($format, $data, $controlByte) {
$values = unpack($format, $data);
if ($values === false)
throw new FormatException("Unpacking field failed for {$controlByte}");
return reset($values);
}
private static function getPackedLength($formatCharacter) {
switch ($formatCharacter) {
case 'E':
return 8;
case 'G':
case 'l':
return 4;
}
throw new InvalidArgumentException("Unsupported format character: {$formatCharacter}");
}
private static function usesSystemByteOrder($formatCharacter) {
switch ($formatCharacter) {
case 'l':
return true;
default:
return false;
}
}
private function parseByUnpacking($controlByte, $format) {
//TODO: Is this reliable for float/double types, considering that the size for unpack is platform dependent?
$data = $this->readStandardField($controlByte);
$data = str_pad($data, self::getPackedLength($format), "\0", STR_PAD_LEFT);
if (self::usesSystemByteOrder($format))
$data = Endianness::convert($data, Endianness::BIG);
return $this->unpackSingleValue($format, $data, $controlByte);
}
private function parsePointer($controlByte) {
$data = $controlByte->getSize();
$size = $data >> 3;
$address = $data & 7;
if ($size === 3)
$address = 0;
for ($i = 0; $i < $size + 1; $i++) {
$address = ($address << 8) + $this->handle->readByte();
}
switch ($size) {
case 1:
$address += 2048;
break;
case 2:
$address += 526336;
break;
}
$previous = $this->handle->getPosition();
$this->handle->seek($this->sectionOffset + $address, SEEK_SET);
$referenceControlByte = $this->processControlByte();
if ($referenceControlByte->getType() === ControlByte::TYPE_POINTER)
throw new FormatException('Per the MMDB specification, pointers may not point to other pointers. This database does not comply with the specification.');
$value = $this->parseField($referenceControlByte);
$this->handle->seek($previous, SEEK_SET);
return $value;
}
private function parseSignedInteger($controlByte, $format) {
if ($controlByte->getSize() === 0)
return 0;
return $this->parseByUnpacking($controlByte, $format);
}
public function parseField(&$controlByte = null) {
if ($controlByte === null)
$controlByte = $this->processControlByte();
switch ($controlByte->getType()) {
case ControlByte::TYPE_POINTER:
return $this->parsePointer($controlByte);
case ControlByte::TYPE_UTF8_STRING:
return $this->parseUtf8String($controlByte);
case ControlByte::TYPE_DOUBLE:
$this->parseByUnpacking($controlByte, 'E');
case ControlByte::TYPE_BYTES:
case ControlByte::TYPE_CONTAINER:
return $this->readStandardField($controlByte);
case ControlByte::TYPE_UINT16:
case ControlByte::TYPE_UINT32:
case ControlByte::TYPE_UINT64:
case ControlByte::TYPE_UINT128:
return $this->parseUnsignedInteger($controlByte);
case ControlByte::TYPE_INT32:
return $this->parseSignedInteger($controlByte, 'l');
case ControlByte::TYPE_MAP:
return $this->parseMap($controlByte);
case ControlByte::TYPE_ARRAY:
return $this->parseArray($controlByte);
case ControlByte::TYPE_END_MARKER:
return null;
case ControlByte::TYPE_BOOLEAN:
return $this->parseBoolean($controlByte);
case ControlByte::TYPE_FLOAT:
$this->parseByUnpacking($controlByte, 'G');
default:
throw new FormatException("Unable to parse data field for {$controlByte}");
}
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace Wordfence\MmdbReader;
use Wordfence\MmdbReader\Exception\FormatException;
use Wordfence\MmdbReader\Exception\IncompatibleIpVersionException;
use Wordfence\MmdbReader\Exception\IncompatibleVersionException;
use Wordfence\MmdbReader\Exception\InvalidIpAddressException;
use Wordfence\MmdbReader\Exception\IoException;
use Wordfence\MmdbReader\Io\FileHandle;
class Database {
const SUPPORTED_MAJOR_VERSION = 2;
const DELIMITER_METADATA = "\xab\xcd\xefMaxMind.com";
private $handle;
private $metadata;
private $nodeSize;
private $nodeReader;
private $dataSectionParser;
private $startingNodes = array();
/**
* Bind to a MaxMind database using the provided handle
* @param resource $resource a valid stream resource that can be used to read the database
* @param bool $closeAutomtically if true, the provided resource will be closed automatically
* @throws MmdbThrowable if an error occurs while interacting with the database
*/
protected function __construct($resource, $closeAutomatically) {
$this->handle = new FileHandle($resource, $closeAutomatically);
$this->initialize();
}
private function initialize() {
$this->loadMetadata();
}
private function loadMetadata() {
$this->handle->seek(0, SEEK_END);
$position = $this->handle->locateString(self::DELIMITER_METADATA, FileHandle::DIRECTION_REVERSE, DatabaseMetadata::MAX_LENGTH, true);
if ($position === null)
throw new FormatException("Unable to locate metadata in MMDB file");
$this->metadata = DatabaseMetadata::parse($this->handle);
if ($this->metadata->getMajorVersion() !== self::SUPPORTED_MAJOR_VERSION)
throw new IncompatibleVersionException(sprintf('This library only supports parsing version %d of the MMDB format, a version %d database was provided', self::SUPPORTED_MAJOR_VERSION, $this->metadata->getMajorVersion()));
}
private function computeNodeSize() {
$nodeSize = ($this->metadata->getRecordSize() * 2) / 8;
if (!is_int($nodeSize))
throw new FormatException("Node size must be an even number of bytes, computed {$this->nodeSize}");
return $nodeSize;
}
private function getNodeReader() {
if ($this->nodeReader === null)
$this->nodeReader = new NodeReader($this->handle, $this->computeNodeSize(), $this->metadata->getNodeCount());
return $this->nodeReader;
}
private function getDataSectionParser() {
if ($this->dataSectionParser === null) {
$offset = $this->getNodeReader()->getSearchTreeSectionSize() + 16; //16 null bytes separate the two sections
$this->dataSectionParser = new DataFieldParser($this->handle, $offset);
}
return $this->dataSectionParser;
}
/**
* Retrieve the metadata for this database
* @return DatabaseMetadata
*/
public function getMetadata() {
return $this->metadata;
}
/**
* Search the database for the given IP address
* @param IpAddressInterface|string $ip the IP address for which to search
* A human readable (as accepted by inet_pton) or binary (as accepted by inet_ntop) string may be provided or an instance of IpAddressInterface
* @return array|null the matched record or null if no record was found
* @throws InvalidIpAddressException if $ip is a string that cannot be parsed as a valid IP address
* @throws IncompatibleVersionException if the database IP version and the version of the provided IP address are incompatible (specifically, if an IPv6 address is passed and the database only supports IPv4)
*/
public function search($ip) {
if (is_string($ip)) {
$ip = IpAddress::createFromString($ip);
}
elseif (!$ip instanceof IpAddressInterface) {
throw new InvalidIpAddressException('IP address must be either a human readable string (presentation format), a binary string (network format), or an instance of Wordfence\MmdbReader\IpAddressInterface, received: ' . print_r($ip, true));
}
if ($this->metadata->getIpVersion() === IpAddress::TYPE_IPV4 && $ip->getType() === IpAddress::TYPE_IPV6)
throw new IncompatibleIpVersionException('This database only support IPv4 addresses, but the provided address is an IPv6 address');
return $this->searchNodes($ip);
}
private function resolveStartingNode($type) {
$node = $this->getNodeReader()->read(0);
if ($type === IpAddress::TYPE_IPV4 && $this->metadata->getIpVersion() === IpAddress::TYPE_IPV6) {
$skippedBits = (IpAddress::LENGTH_IPV6 - IpAddress::LENGTH_IPV4) * 8;
while ($skippedBits-- > 0) {
$record = $node->getLeft();
if ($record->isNodePointer()) {
$node = $record->getNextNode();
}
else {
return $record;
}
}
}
return $node;
}
private function getStartingNode($type) {
if (!array_key_exists($type, $this->startingNodes)) {
$this->startingNodes[$type] = $this->resolveStartingNode($type);
}
return $this->startingNodes[$type];
}
private function searchNodes($ip) {
$key = $ip->getBinary();
$byteCount = strlen($key);
$nodeReader = $this->getNodeReader();
$node = $this->getStartingNode($ip->getType());
$bits = '';
$record = null;
if ($node instanceof Node) {
for ($byteIndex = 0; $byteIndex < $byteCount; $byteIndex++) {
$byte = ord($key[$byteIndex]);
for ($bitOffset = 7; $bitOffset >= 0; $bitOffset--) {
$bit = ($byte >> $bitOffset) & 1;
$record = $node->getRecord($bit);
if ($record->isNodePointer()) {
$node = $record->getNextNode();
}
else {
break 2;
}
}
}
}
else {
$record = $node;
}
if ($record->isNullPointer()) {
return null;
}
elseif ($record->isDataPointer()) {
$this->handle->seek($record->getDataAddress(), SEEK_SET);
$data = $this->getDataSectionParser()->parseField();
return $data;
}
else {
return null;
}
}
/**
* Open the MMDB file at the given path
* @param string $path the path of an MMDB file
* @throws IoException if unable to open the file at the provided path
* @throws MmdbThrowable if an error occurs while initializing the database
*/
public static function open($path) {
$handle = fopen($path, 'rb');
if ($handle === false)
throw new IoException("Unable to open MMDB file at {$path}");
return new self($handle, true);
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Wordfence\MmdbReader;
use Wordfence\MmdbReader\Exception\FormatException;
class DatabaseMetadata {
const MAX_LENGTH = 131072; //128 * 1024;
const FIELD_MAJOR_VERSION = 'binary_format_major_version';
const FIELD_NODE_COUNT = 'node_count';
const FIELD_RECORD_SIZE = 'record_size';
const FIELD_IP_VERSION = 'ip_version';
const FIELD_BUILD_EPOCH = 'build_epoch';
private $data;
public function __construct($data) {
$this->data = $data;
}
private function getField($key, $default = null, &$exists = null) {
if (!array_key_exists($key, $this->data)) {
$exists = false;
return $default;
}
$exists = true;
return $this->data[$key];
}
private function requireField($key) {
$value = $this->getField($key, null, $exists);
if (!$exists)
throw new FormatException("Metadata field {$key} is missing");
return $value;
}
public function requireInteger($key) {
$value = $this->requireField($key);
if (!is_int($value))
throw new FormatException("Field {$key} should be an integer, received: " . print_r($value, true));
return $value;
}
public function getMajorVersion() {
return $this->requireInteger(self::FIELD_MAJOR_VERSION);
}
public function getNodeCount() {
return $this->requireInteger(self::FIELD_NODE_COUNT);
}
public function getRecordSize() {
return $this->requireInteger(self::FIELD_RECORD_SIZE);
}
public function getIpVersion() {
return $this->requireInteger(self::FIELD_IP_VERSION);
}
public function getBuildEpoch() {
return $this->requireInteger(self::FIELD_BUILD_EPOCH);
}
public static function parse($handle) {
$offset = $handle->getPosition();
$parser = new DataFieldParser($handle, $offset);
$value = $parser->parseField();
if (!is_array($value))
throw new FormatException('Unexpected field type found when metadata map was expected: ' . print_r($value, true));
return new self($value);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Wordfence\MmdbReader;
class Endianness {
const BIG = 0;
const LITTLE = 1;
private static $SYSTEM = null;
private static function detect() {
$test = unpack('S', "\x00\x01");
return $test[1] >> 8;
}
public static function get() {
if (self::$SYSTEM === null)
self::$SYSTEM = self::detect();
return self::$SYSTEM;
}
public static function isBig() {
return self::get() === self::BIG;
}
public static function isLittle() {
return self::get() === self::LITTLE;
}
public static function convert($value, $source, $target = null) {
if ($target === null)
$target = self::get();
if ($target === $source)
return $value;
return strrev($value);
}
}

View File

@@ -0,0 +1,6 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class FormatException extends RuntimeMmdbException {
}

View File

@@ -0,0 +1,6 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class IncompatibleIpVersionException extends MmdbException {
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class IncompatibleVersionException extends RuntimeMmdbException {
}

View File

@@ -0,0 +1,6 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class InvalidArgumentException extends MmdbException {
}

View File

@@ -0,0 +1,6 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class InvalidIpAddressException extends MmdbException {
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class InvalidOperationException extends MmdbException {
}

View File

@@ -0,0 +1,6 @@
<?php
namespace Wordfence\MmdbReader\Exception;
class IoException extends RuntimeMmdbException {
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Wordfence\MmdbReader\Exception;
use Exception;
use Throwable;
class MmdbException extends Exception implements MmdbThrowable {
/**
* @param string $message
* @param ?Throwable $previous
*/
public function __construct($message, $previous = null) {
parent::__construct($message, 0, $previous);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Wordfence\MmdbReader\Exception;
use Throwable;
interface MmdbThrowable extends Throwable {
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Wordfence\MmdbReader\Exception;
use RuntimeException;
use Throwable;
class RuntimeMmdbException extends RuntimeException implements MmdbThrowable {
/**
* @param string $message
* @param ?Throwable $previous
*/
public function __construct($message, $previous = null) {
parent::__construct($message, 0, $previous);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Wordfence\MmdbReader;
class IntegerParser {
public static function parseUnsigned($handle, $length) {
$value = 0;
for ($i = 0; $i < $length; $i++) {
$byte = $handle->readByte();
$value = ($value << 8) + $byte;
}
return $value;
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Wordfence\MmdbReader\Io;
use Wordfence\MmdbReader\Exception\IoException;
class FileHandle {
const POSITION_START = 0;
const DIRECTION_FORWARD = 1;
const DIRECTION_REVERSE = -1;
const CHUNK_SIZE_DEFAULT = 1024;
private $resource;
private $close;
public function __construct($resource, $close = true) {
$this->resource = $resource;
$this->close = $close;
}
public function __destruct() {
if ($this->close)
fclose($this->resource);
}
public function seek($offset, $whence = SEEK_SET) {
if (fseek($this->resource, $offset, $whence) !== 0)
throw new IoException("Seeking file to offset {$offset} failed");
}
public function getPosition() {
$position = ftell($this->resource);
if ($position === false)
throw new IoException('Retrieving current position in file failed');
return $position;
}
public function isAtStart() {
return $this->getPosition() === self::POSITION_START;
}
public function isAtEnd() {
return feof($this->resource);
}
public function read($length) {
$read = fread($this->resource, $length);
if ($read === false)
throw new IoException("Reading {$length} byte(s) from file failed");
return $read;
}
public function readByte() {
return ord($this->read(1));
}
public function readAll($chunkSize = self::CHUNK_SIZE_DEFAULT) {
$data = '';
do {
$chunk = $this->read($chunkSize);
if (empty($chunk))
break;
$data .= $chunk;
} while (true);
return $data;
}
public function locateString($string, $direction, $limit = null, $after = false) {
$searchStart = $limit === null ? null : $this->getPosition();
$length = strlen($string);
$position = $searchStart;
if ($direction === self::DIRECTION_REVERSE)
$position -= $length;
do {
try {
$this->seek($position, SEEK_SET);
}
catch (IoException $e) {
//This assumes that a seek failure means that the target position is out of range (and hence the search just needs to stop rather than throwing an exception)
break;
}
$test = $this->read($length);
if ($test === $string) {
return $position + ($after ? $length : 0);
}
$position += $direction;
} while ($limit === null || abs($position - $searchStart) < $limit);
return null;
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Wordfence\MmdbReader;
use Wordfence\MmdbReader\Exception\InvalidIpAddressException;
class IpAddress implements IpAddressInterface {
const TYPE_IPV4 = 4;
const TYPE_IPV6 = 6;
const LENGTH_IPV4 = 4;
const LENGTH_IPV6 = 16;
const SEPARATOR_IPV4 = '.';
const SEPARATOR_IPV6 = ':';
private static $SEPARATORS = array(
self::SEPARATOR_IPV4,
self::SEPARATOR_IPV6
);
private $humanReadable;
private $binary;
private $type;
protected function __construct($humanReadable, $binary) {
$this->humanReadable = $humanReadable;
$this->binary = $binary;
$this->type = self::resolveType($binary);
}
public function getHumanReadable() {
return $this->humanReadable;
}
public function getBinary() {
return $this->binary;
}
public function getType() {
return $this->type;
}
private static function resolveType($binary) {
return strlen($binary) === self::LENGTH_IPV6 ? self::TYPE_IPV6 : self::TYPE_IPV4;
}
/**
* Create an IpAddress instance from a human-readable string
* @param string $humanReadable a human readable IP address
* @return IpAddress
* @throws InvalidIpAddressException if $humanReadable is not a valid human-readable IP address
*/
public static function createFromHumanReadable($humanReadable) {
$binary = inet_pton($humanReadable);
if ($binary === false)
throw new InvalidIpAddressException("IP address \"{$humanReadable}\" is malformed");
return new self($humanReadable, $binary);
}
/**
* Create an IpAddress instance from a binary string
* @param string $binary a binary IP address
* @return IpAddress
* @throws InvalidIpAddressException if $binary is not a valid binary IP address
*/
public static function createFromBinary($binary) {
$humanReadable = inet_ntop($binary);
if ($humanReadable === false)
throw new InvalidIpAddressException("Binary IP address data is invalid: " . bin2hex($binary));
return new self($humanReadable, $binary);
}
/**
* Create an IpAddress instance from an unknown string representation
* @param string $string either a human-readable or binary IP address
* @return IpAddress
* @throws InvalidIpAddressException if $string cannot be parsed as a valid IP address
*/
public static function createFromString($string) {
foreach (self::$SEPARATORS as $separator) {
if (strpos($string, $separator) !== false) {
try {
return self::createFromHumanReadable($string);
}
catch (InvalidIpAddressException $e) {
break;
}
}
}
return self::createFromBinary($string);
}
public function __toString() {
return $this->getHumanReadable();
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Wordfence\MmdbReader;
interface IpAddressInterface {
/**
* Get the human-readable (presentation format) version of the address
* @return string
* @see inet_ntop
*/
public function getHumanReadable();
/**
* Get the binary (network format) version of the address
* @return string
* @see inet_pton
*/
public function getBinary();
/**
* Get the type of the address (IPv4 or IPv6)
* @return int 4 for IPv4 and 6 for IPv6
*/
public function getType();
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Wordfence\MmdbReader;
class Node {
const SIDE_LEFT = 0;
const SIDE_RIGHT = 1;
private $reader;
private $data;
private $left, $right;
public function __construct($reader, $data) {
$this->reader = $reader;
$this->data = $data;
}
public function getRecord($side) {
$value = $this->reader->extractRecord($this->data, $side);
return new NodeRecord($this->reader, $value);
}
public function getLeft() {
return $this->getRecord(self::SIDE_LEFT);
}
public function getRight() {
return $this->getRecord(self::SIDE_RIGHT);
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Wordfence\MmdbReader;
class NodeReader {
const SHARED_MASK_LEFT = 240; //0b11110000
const SHARED_MASK_RIGHT = 15; //0b00001111
private $handle;
private $nodeSize, $nodeCount;
private $searchTreeSectionSize;
private $recordWholeBytes, $recordBits;
private $sharedByteOffset;
public function __construct($handle, $nodeSize, $nodeCount) {
$this->handle = $handle;
$this->nodeSize = $nodeSize;
$this->nodeCount = $nodeCount;
$this->searchTreeSectionSize = $nodeSize * $nodeCount;
$this->computeRecordSizes();
}
private function computeRecordSizes() {
$this->recordWholeBytes = (int) ($this->nodeSize / 2);
$this->recordBits = $this->nodeSize % 2;
if ($this->recordBits > 0)
$this->sharedByteOffset = $this->recordWholeBytes + 1;
}
public function read($position = 0) {
if ($position > $this->nodeCount)
throw new InvalidOperationException("Read requested for node at {$position}, but only {$this->nodeCount} nodes are present");
$offset = $position * $this->nodeSize;
$this->handle->seek($offset, SEEK_SET);
$data = $this->handle->read($this->nodeSize);
return new Node($this, $data);
}
private function hasSharedByte() {
return $this->sharedByteOffset !== null;
}
private function getWholeByteOffset($side) {
return $side === Node::SIDE_LEFT ? 0 : ($this->hasSharedByte() ? $this->sharedByteOffset : $this->recordWholeBytes);
}
public function extractRecord($nodeData, $side) {
if ($this->hasSharedByte()) {
$sharedByte = ord($nodeData[$this->sharedByteOffset]);
if ($side === Node::SIDE_LEFT) {
$value = $sharedByte >> 4;
}
else {
$value = $sharedByte & self::SHARED_MASK_RIGHT;
}
}
else {
$value = 0;
}
$offset = $this->getWholeByteOffset($side);
$end = $offset + $this->recordWholeBytes;
for ($i = $offset; $i < $end; $i++) {
$byte = ord($nodeData[$i]);
$value = ($value << 8) | $byte;
}
return $value;
}
public function getNodeCount() {
return $this->nodeCount;
}
public function getSearchTreeSectionSize() {
return $this->searchTreeSectionSize;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Wordfence\MmdbReader;
use Wordfence\MmdbReader\Exception\InvalidOperationException;
class NodeRecord {
private $reader;
private $value;
public function __construct($reader, $value) {
$this->reader = $reader;
$this->value = $value;
}
public function getValue() {
return $this->value;
}
public function isNodePointer() {
return $this->value < $this->reader->getNodeCount();
}
public function getNextNode() {
if (!$this->isNodePointer())
throw new InvalidOperationException('The next node was requested for a record that is not a node pointer');
try {
return $this->reader->read($this->getValue());
}
catch (InvalidOperationException $e) {
throw new FormatException('Invalid node pointer found in database', $e);
}
}
public function isNullPointer() {
return $this->value === $this->reader->getNodeCount();
}
public function isDataPointer() {
return $this->value > $this->reader->getNodeCount();
}
public function getDataAddress() {
if (!$this->isDataPointer())
throw new InvalidOperationException('The data address was requested for a record that is not a data pointer');
return $this->value - $this->reader->getNodeCount() + $this->reader->getSearchTreeSectionSize();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFI0faZb9T1jloaRMw4g
G/tW2CnYwYTpmXuQCphIrM6rYvjptYtlJBzy370sQovLIzHBiqAYc3Rv5FJBDQ0F
mTR/iF3Tm8YmxjqSuHECn8Q6KSPvaZyQFSM8vUmFjwVtTKgEjo4rFVrne8OOvQ4S
FRvWbeBvxoO6SfLArLK+hJAZSMRyzzfsNL1q5okZqLHQhdtkiFfPWJkXIEhL+vUK
U5SLZoFIh9hVImmJuXHBQ0qXRnTCQlpb80GrMD1CBYFFeHx8IOCZwWZ2ifIPL5n+
vxjZ30zH3DDhcwhQv3y2hJsedJ7w+7I7gs/jmECUG36rbGbpaXrQnwhaiGBdRoiv
awIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,37 @@
<?php
if (defined('WFWAF_VERSION')) { exit(); }
define('WFWAF_VERSION', '1.1.0');
define('WFWAF_PATH', dirname(__FILE__) . '/');
define('WFWAF_LIB_PATH', WFWAF_PATH . 'lib/');
define('WFWAF_VIEW_PATH', WFWAF_PATH . 'views/');
define('WFWAF_API_URL_SEC', 'https://noc4.wordfence.com/v1.11/');
if (!defined('WFWAF_DEBUG')) {
define('WFWAF_DEBUG', false);
}
if (!defined('WFWAF_ENABLED')) {
define('WFWAF_ENABLED', true);
}
define('WFWAF_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
require_once WFWAF_LIB_PATH . 'waf.php';
require_once WFWAF_LIB_PATH . 'utils.php';
require_once WFWAF_LIB_PATH . 'i18n.php';
require_once WFWAF_LIB_PATH . 'xmlrpc.php';
require_once WFWAF_LIB_PATH . 'shutdown.php';
require_once WFWAF_LIB_PATH . 'storage.php';
require_once WFWAF_LIB_PATH . 'storage/file.php';
require_once WFWAF_LIB_PATH . 'storage/mysql.php';
require_once WFWAF_LIB_PATH . 'config.php';
require_once WFWAF_LIB_PATH . 'rules.php';
require_once WFWAF_LIB_PATH . 'parser/lexer.php';
require_once WFWAF_LIB_PATH . 'parser/parser.php';
require_once WFWAF_LIB_PATH . 'parser/sqli.php';
require_once WFWAF_LIB_PATH . 'request.php';
require_once WFWAF_LIB_PATH . 'http.php';
require_once WFWAF_LIB_PATH . 'view.php';

View File

@@ -0,0 +1,69 @@
<?php
class wfWafApiException extends Exception {
}
class wfWafMissingApiKeyException extends wfWafApiException {
}
class wfWafApi {
private $waf;
private $apiKey;
public function __construct($waf) {
$this->waf = $waf;
$this->apiKey = $this->getConfig('apiKey');
if (empty($this->apiKey))
throw new wfWafMissingApiKeyException('No API key is available');
}
private function getConfig($key) {
return $this->waf->getStorageEngine()->getConfig($key, null, 'synced');
}
private function guessSiteUrl() {
return sprintf('%s://%s/', $this->waf->getRequest()->getProtocol(), $this->waf->getRequest()->getHost());
}
private function guessSiteUrlIfNecessary($configKey) {
$url = $this->getConfig($configKey);
if (!$url)
$url = $this->guessSiteUrl();
return $url;
}
private function getSiteUrl() {
return $this->guessSiteUrlIfNecessary('siteURL');
}
private function getHomeUrl() {
return $this->guessSiteUrlIfNecessary('homeURL');
}
private function buildQueryString($additionalParameters = array()) {
$parameters = array(
'k' => $this->apiKey,
's' => $this->getSiteUrl(),
'h' => $this->getHomeUrl(),
't' => microtime(true),
'lang' => $this->getConfig('WPLANG')
);
$parameters = array_merge($parameters, $additionalParameters);
return http_build_query($parameters, '', '&');
}
private function buildUrl($queryParameters, $path = '') {
return WFWAF_API_URL_SEC . $path . '?' . $this->buildQueryString($queryParameters);
}
public function actionGet($action, $parameters = array()) {
$parameters['action'] = $action;
$url = $this->buildUrl($parameters);
$response = wfWAFHTTP::get($url);
if ($response === false)
throw new wfWafApiException('Request failed');
return $response;
}
}

View File

@@ -0,0 +1,88 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
/**
* Class wfWAFConfig provides a convenience interface for accessing the WAF's configuration
* that does not throw exceptions. All exceptions are caught and, if WFWAF_DEBUG is true, logged
* to the server error log.
*/
class wfWAFConfig {
public static function set($key, $val, $waf = null, $category = '') {
if (!($waf instanceof wfWAF)) {
$waf = wfWAF::getInstance();
}
try {
$waf->getStorageEngine()->setConfig($key, $val, $category);
}
catch (Exception $e) {
if (WFWAF_DEBUG) {
error_log("Exception in " . __CLASS__ . "->" . __FUNCTION__ . ": " . $e->getMessage());
}
}
}
public static function get($key, $default = null, $waf = null, $category = '') {
if (!($waf instanceof wfWAF)) {
$waf = wfWAF::getInstance();
}
try {
return $waf->getStorageEngine()->getConfig($key, $default, $category);
}
catch (Exception $e) {
if (WFWAF_DEBUG) {
error_log("Exception in " . __CLASS__ . "->" . __FUNCTION__ . ": " . $e->getMessage());
}
}
return $default;
}
public static function unsetKey($key, $waf = null, $category = '') {
if (!($waf instanceof wfWAF)) {
$waf = wfWAF::getInstance();
}
try {
$waf->getStorageEngine()->unsetConfig($key, $category);
}
catch (Exception $e) {
if (WFWAF_DEBUG) {
error_log("Exception in " . __CLASS__ . "->" . __FUNCTION__ . ": " . $e->getMessage());
}
}
}
public static function isInLearningMode($waf = null) {
if (!($waf instanceof wfWAF)) {
$waf = wfWAF::getInstance();
}
try {
return $waf->getStorageEngine()->isInLearningMode();
}
catch (Exception $e) {
if (WFWAF_DEBUG) {
error_log("Exception in " . __CLASS__ . "->" . __FUNCTION__ . ": " . $e->getMessage());
}
}
return false;
}
public static function isDisabled($waf = null) {
if (!($waf instanceof wfWAF)) {
$waf = wfWAF::getInstance();
}
try {
return $waf->getStorageEngine()->isDisabled();
}
catch (Exception $e) {
if (WFWAF_DEBUG) {
error_log("Exception in " . __CLASS__ . "->" . __FUNCTION__ . ": " . $e->getMessage());
}
}
return true;
}
}
}

View File

@@ -0,0 +1,473 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
class wfWAFHTTP {
private $url;
private $auth;
private $body;
private $cookies;
// private $fileNames;
// private $files;
private $headers;
private $method;
private $queryString;
/**
* @var wfWAFHTTPTransport
*/
private $transport;
/**
* @param string $url
* @param wfWAFHTTP $request
* @return wfWAFHTTPResponse|bool
* @throws wfWAFHTTPTransportException
*/
public static function get($url, $request = null, $timeout = 5, $connectTimeout = null) {
if (!$request) {
$request = new self();
}
$request->setUrl($url);
$request->setMethod('GET');
$transport = wfWAFHTTPTransport::getInstance();
$transport->setConnectTimeout($connectTimeout);
$transport->setTimeout($timeout);
$request->setTransport($transport);
// $request->setCookies("XDEBUG_SESSION=netbeans-xdebug");
return $request->send();
}
/**
* @param string $url
* @param array $post
* @param wfWAFHTTP $request
* @return wfWAFHTTPResponse|bool
* @throws wfWAFHTTPTransportException
*/
public static function post($url, $post = array(), $request = null, $timeout = 5, $connectTimeout = null) {
if (!$request) {
$request = new self();
}
$request->setUrl($url);
$request->setMethod('POST');
$request->setBody($post);
$transport = wfWAFHTTPTransport::getInstance();
$transport->setConnectTimeout($connectTimeout);
$transport->setTimeout($timeout);
$request->setTransport($transport);
return $request->send();
}
/**
* @return wfWAFHTTPResponse|bool
* @throws wfWAFHTTPTransportException
*/
public function send() {
if (!$this->getTransport()) {
throw new wfWAFHTTPTransportException('Need to provide a valid HTTP transport before calling ' . __METHOD__);
}
return $this->getTransport()->send($this);
}
/**
* @return mixed
*/
public function getUrl() {
return $this->url;
}
/**
* @param mixed $url
*/
public function setUrl($url) {
$this->url = $url;
}
/**
* @return mixed
*/
public function getAuth() {
return $this->auth;
}
/**
* @param mixed $auth
*/
public function setAuth($auth) {
$this->auth = $auth;
}
/**
* @return mixed
*/
public function getBody() {
return $this->body;
}
/**
* @param mixed $body
*/
public function setBody($body) {
$this->body = $body;
}
/**
* @return mixed
*/
public function getCookies() {
return $this->cookies;
}
/**
* @param mixed $cookies
*/
public function setCookies($cookies) {
$this->cookies = $cookies;
}
/**
* @return mixed
*/
public function getHeaders() {
return $this->headers;
}
/**
* @param mixed $headers
*/
public function setHeaders($headers) {
$this->headers = $headers;
}
/**
* @return mixed
*/
public function getMethod() {
return $this->method;
}
/**
* @param mixed $method
*/
public function setMethod($method) {
$this->method = $method;
}
/**
* @return mixed
*/
public function getQueryString() {
return $this->queryString;
}
/**
* @param mixed $queryString
*/
public function setQueryString($queryString) {
$this->queryString = $queryString;
}
/**
* @return wfWAFHTTPTransport
*/
public function getTransport() {
return $this->transport;
}
/**
* @param wfWAFHTTPTransport $transport
*/
public function setTransport($transport) {
$this->transport = $transport;
}
}
class wfWAFHTTPResponse {
private $body;
private $headers;
private $statusCode;
/**
* @return mixed
*/
public function getBody() {
return $this->body;
}
/**
* @param mixed $body
*/
public function setBody($body) {
$this->body = $body;
}
/**
* @return mixed
*/
public function getHeaders() {
return $this->headers;
}
/**
* @param mixed $headers
*/
public function setHeaders($headers) {
$this->headers = $headers;
}
/**
* @return mixed
*/
public function getStatusCode() {
return $this->statusCode;
}
/**
* @param mixed $statusCode
*/
public function setStatusCode($statusCode) {
$this->statusCode = $statusCode;
}
}
abstract class wfWAFHTTPTransport {
private static $instance;
private $_connectTimeout = null;
private $_timeout = 5;
/**
* @return wfWAFHTTPTransport
* @throws wfWAFHTTPTransportException
*/
public static function getInstance() {
if (!self::$instance) {
self::$instance = self::getFirstTransport();
}
return self::$instance;
}
/**
* @param mixed $instance
*/
public static function setInstance($instance) {
self::$instance = $instance;
}
/**
* @return wfWAFHTTPTransport
* @throws wfWAFHTTPTransportException
*/
public static function getFirstTransport() {
if (function_exists('curl_init')) {
return new wfWAFHTTPTransportCurl();
} else if (function_exists('file_get_contents')) {
return new wfWAFHTTPTransportStreams();
}
throw new wfWAFHTTPTransportException('No valid HTTP transport found.');
}
/**
* @param array $cookieArray
* @return string
*/
public static function buildCookieString($cookieArray) {
$cookies = '';
foreach ($cookieArray as $cookieName => $value) {
$cookies .= "$cookieName=" . urlencode($value) . '; ';
}
$cookies = rtrim($cookies);
return $cookies;
}
/**
* @param wfWAFHTTP $request
* @return wfWAFHTTPResponse|bool
*/
abstract public function send($request);
public function setConnectTimeout($connectTimeout) {
$this->_connectTimeout = $connectTimeout;
}
public function getConnectTimeout() {
return $this->_connectTimeout;
}
public function setTimeout($timeout) {
$this->_timeout = $timeout;
}
public function getTimeout() {
return $this->_timeout;
}
}
class wfWAFHTTPTransportCurl extends wfWAFHTTPTransport {
/**
* @todo Proxy settings
* @param wfWAFHTTP $request
* @return wfWAFHTTPResponse|bool
*/
public function send($request) {
$url = $request->getUrl();
if ($queryString = $request->getQueryString()) {
if (is_array($queryString)) {
$queryString = http_build_query($queryString, '', '&');
}
$url .= (wfWAFUtils::strpos($url, '?') !== false ? '&' : '?') . $queryString;
}
$ch = curl_init($url);
switch (wfWAFUtils::strtolower($request->getMethod())) {
case 'post':
curl_setopt($ch, CURLOPT_POST, 1);
break;
}
if ($body = $request->getBody()) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
if ($auth = $request->getAuth()) {
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
}
if ($cookies = $request->getCookies()) {
if (is_array($cookies)) {
$cookies = self::buildCookieString($cookies);
}
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
}
if ($headers = $request->getHeaders()) {
if (is_array($headers)) {
$_headers = array();
foreach ($headers as $header => $value) {
$_headers[] = $header . ': ' . $value;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
}
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if ($this->getConnectTimeout() !== null) { curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->getConnectTimeout()); }
curl_setopt($ch, CURLOPT_TIMEOUT, $this->getTimeout());
if (defined('CURLOPT_ACCEPT_ENCODING')) {
curl_setopt($ch, CURLOPT_ACCEPT_ENCODING, ''); //The empty string is a magic value that means "send all supported encodings"
}
else if (defined('CURLOPT_ENCODING')) {
curl_setopt($ch, CURLOPT_ENCODING, '');
}
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CAINFO, WFWAF_PATH . 'cacert.pem'); //On some systems curl uses an outdated root certificate chain file
$curlResponse = curl_exec($ch);
if ($curlResponse !== false) {
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = wfWAFUtils::substr($curlResponse, 0, $headerSize);
$body = wfWAFUtils::substr($curlResponse, $headerSize);
$response = new wfWAFHTTPResponse();
$response->setBody($body);
$response->setHeaders($header);
$response->setStatusCode(curl_getinfo($ch, CURLINFO_HTTP_CODE));
return $response;
}
return false;
}
}
class wfWAFHTTPTransportStreams extends wfWAFHTTPTransport {
/**
* @todo Implement wfWAFHTTPTransportStreams::send.
* @param wfWAFHTTP $request
* @return mixed
* @throws wfWAFHTTPTransportException
*/
public function send($request) {
$timeout = $this->getTimeout();
$url = $request->getUrl();
if ($queryString = $request->getQueryString()) {
if (is_array($queryString)) {
$queryString = http_build_query($queryString, '', '&');
}
$url .= (wfWAFUtils::strpos($url, '?') !== false ? '&' : '?') . $queryString;
}
$urlParsed = parse_url($request->getUrl());
$headers = "Host: $urlParsed[host]\r\n";
if ($auth = $request->getAuth()) {
$headers .= 'Authorization: Basic ' . base64_encode($auth['user'] . ':' . $auth['password']) . "\r\n";
}
if ($cookies = $request->getCookies()) {
if (is_array($cookies)) {
$cookies = self::buildCookieString($cookies);
}
$headers .= "Cookie: $cookies\r\n";
}
$hasUA = false;
if ($_headers = $request->getHeaders()) {
if (is_array($_headers)) {
foreach ($_headers as $header => $value) {
if (trim(wfWAFUtils::strtolower($header)) === 'user-agent') {
$hasUA = true;
}
$headers .= $header . ': ' . $value . "\r\n";
}
}
}
if (!$hasUA) {
$headers .= "User-Agent: Wordfence Streams UA\r\n";
}
$httpOptions = array(
'method' => $request->getMethod(),
'ignore_errors' => true,
'timeout' => $timeout,
'follow_location' => 1,
'max_redirects' => 5,
);
if (wfWAFUtils::strlen($request->getBody()) > 0) {
$httpOptions['content'] = $request->getBody();
$headers .= 'Content-Length: ' . wfWAFUtils::strlen($httpOptions['content']) . "\r\n";
}
$httpOptions['header'] = $headers;
$options = array(
wfWAFUtils::strtolower($urlParsed['scheme']) => $httpOptions,
);
$context = stream_context_create($options);
$stream = fopen($request->getUrl(), 'r', false, $context);
if (!is_resource($stream)) {
return false;
}
$metaData = stream_get_meta_data($stream);
// Get the HTTP response code
$httpResponse = array_shift($metaData['wrapper_data']);
if (preg_match_all('/(\w+\/\d\.\d) (\d{3})/', $httpResponse, $matches) !== false) {
// $protocol = $matches[1][0];
$status = (int) $matches[2][0];
} else {
// $protocol = null;
$status = null;
}
$responseObj = new wfWAFHTTPResponse();
$responseObj->setHeaders(join("\r\n", $metaData['wrapper_data']));
$responseObj->setBody(stream_get_contents($stream));
$responseObj->setStatusCode($status);
// Close the stream after use
fclose($stream);
return $responseObj;
}
}
class wfWAFHTTPTransportException extends wfWAFException {
}
}

View File

@@ -0,0 +1,87 @@
<?php
class wfWAFI18n {
/**
* @var self
*/
protected static $instance;
/**
* @param string $text
* @return string
*/
public static function __($text) {
return self::getInstance()->getI18nEngine()->__($text);
}
public static function esc_html__($text) {
return htmlentities(self::__($text), ENT_QUOTES, 'UTF-8');
}
public static function esc_html_e($text) {
echo self::esc_html__($text);
}
/**
* @return self
*/
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self(new wfWAFI18nEngineDefault());
}
return self::$instance;
}
/**
* @param self $i18nEngine
*/
public static function setInstance($i18nEngine) {
self::$instance = $i18nEngine;
}
/** @var wfWAFI18nEngine */
private $i18nEngine;
/**
* @param wfWAFI18nEngine $i18nEngine
*/
public function __construct($i18nEngine) {
$this->i18nEngine = $i18nEngine;
}
/**
* @return wfWAFI18nEngine
*/
public function getI18nEngine() {
return $this->i18nEngine;
}
/**
* @param wfWAFI18nEngine $i18nEngine
*/
public function setI18nEngine($i18nEngine) {
$this->i18nEngine = $i18nEngine;
}
}
class wfWAFI18nEngineDefault implements wfWAFI18nEngine {
/**
* @param string $text
* @return string
*/
public function __($text) {
return $text;
}
}
interface wfWAFI18nEngine {
/**
* @param string $text
* @return string
*/
public function __($text);
}

View File

@@ -0,0 +1,960 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('WF_SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('WF_SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('WF_SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('WF_SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('WF_SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
*/
define('WF_SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
*/
define('WF_SERVICES_JSON_SUPPRESS_ERRORS', 32);
/**
* Behavior switch for Services_JSON::decode()
*/
define('WF_SERVICES_JSON_USE_TO_JSON', 64);
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class wfServices_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
* - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects
* It serializes the return value from the toJSON call rather
* than the object itself, toJSON can return associative arrays,
* strings or numbers, if you return an object, make sure it does
* not have a toJSON method, otherwise an error will occur.
*/
function __construct( $use = 0 )
{
$this->use = $use;
$this->_mb_strlen = function_exists('mb_strlen');
$this->_mb_convert_encoding = function_exists('mb_convert_encoding');
$this->_mb_substr = function_exists('mb_substr');
}
/**
* PHP4 constructor.
*/
public function wfServices_JSON( $use = 0 ) {
self::__construct( $use );
}
// private - cache the mbstring lookup results..
var $_mb_strlen = false;
var $_mb_substr = false;
var $_mb_convert_encoding = false;
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if($this->_mb_convert_encoding) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if($this->_mb_convert_encoding) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch($this->strlen8($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8[0]) >> 2))
. chr((0xC0 & (ord($utf8[0]) << 6))
| (0x3F & ord($utf8[1])));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8[0]) << 4))
| (0x0F & (ord($utf8[1]) >> 2)))
. chr((0xC0 & (ord($utf8[1]) << 6))
| (0x7F & ord($utf8[2])));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* encodes an arbitrary variable into JSON format (and sends JSON Header)
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
header('Content-type: application/json');
return $this->encodeUnsafe($var);
}
/**
* encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!)
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encodeUnsafe($var)
{
// see bug #16908 - regarding numeric locale printing
$lc = setlocale(LC_NUMERIC, 0);
setlocale(LC_NUMERIC, 'C');
$ret = $this->_encode($var);
setlocale(LC_NUMERIC, $lc);
return $ret;
}
/**
* PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function _encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (float) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = $this->strlen8($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var[$c]);
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var[$c];
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var[$c];
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
if ($c+1 >= $strlen_var) {
$c += 1;
$ascii .= '?';
break;
}
$char = pack('C*', $ord_var_c, ord($var[$c + 1]));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
if ($c+2 >= $strlen_var) {
$c += 2;
$ascii .= '?';
break;
}
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
@ord($var[$c + 1]),
@ord($var[$c + 2]));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
if ($c+3 >= $strlen_var) {
$c += 3;
$ascii .= '?';
break;
}
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
if ($c+4 >= $strlen_var) {
$c += 4;
$ascii .= '?';
break;
}
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
if ($c+5 >= $strlen_var) {
$c += 5;
$ascii .= '?';
break;
}
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]),
ord($var[$c + 5]));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(wfServices_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
// treat it like a regular array
$elements = array_map(array($this, '_encode'), $var);
foreach($elements as $element) {
if(wfServices_JSON::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
// support toJSON methods.
if (($this->use & WF_SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) {
// this may end up allowing unlimited recursion
// so we check the return value to make sure it's not got the same method.
$recode = $var->toJSON();
if (method_exists($recode, 'toJSON')) {
return ($this->use & WF_SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new wfServices_JSON_Error(get_class($var).
" toJSON returned an object with a toJSON method.");
}
return $this->_encode( $recode );
}
$vars = get_object_vars($var);
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(wfServices_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & WF_SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new wfServices_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->_encode($value);
if(wfServices_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->_encode(strval($name)) . ':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = $this->substr8($str, 0, 1);
$chrs = $this->substr8($str, 1, -1);
$utf8 = '';
$strlen_chrs = $this->strlen8($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
$ord_chrs_c = ord($chrs[$c]);
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs[++$c];
}
break;
case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2)))
. chr(hexdec($this->substr8($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs[$c];
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= $this->substr8($chrs, $c, 2);
++$c;
break;
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= $this->substr8($chrs, $c, 3);
$c += 2;
break;
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= $this->substr8($chrs, $c, 4);
$c += 3;
break;
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= $this->substr8($chrs, $c, 5);
$c += 4;
break;
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= $this->substr8($chrs, $c, 6);
$c += 5;
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str[0] == '[') {
$stk = array(WF_SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & WF_SERVICES_JSON_LOOSE_TYPE) {
$stk = array(WF_SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(WF_SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => WF_SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = $this->substr8($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == WF_SERVICES_JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = $this->strlen8($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == WF_SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = $this->substr8($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => WF_SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == WF_SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == WF_SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
if ($this->use & WF_SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
if ($this->use & WF_SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != WF_SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => WF_SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c]));
//print("Found start of string at {$c}\n");
} elseif (($chrs[$c] == $top['delim']) &&
($top['what'] == WF_SERVICES_JSON_IN_STR) &&
(($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs[$c] == '[') &&
in_array($top['what'], array(WF_SERVICES_JSON_SLICE, WF_SERVICES_JSON_IN_ARR, WF_SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => WF_SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs[$c] == ']') && ($top['what'] == WF_SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs[$c] == '{') &&
in_array($top['what'], array(WF_SERVICES_JSON_SLICE, WF_SERVICES_JSON_IN_ARR, WF_SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => WF_SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs[$c] == '}') && ($top['what'] == WF_SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(WF_SERVICES_JSON_SLICE, WF_SERVICES_JSON_IN_ARR, WF_SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => WF_SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == WF_SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == WF_SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == WF_SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'wfservices_json_error' ||
is_subclass_of($data, 'wfServices_JSON_Error'))) {
return true;
}
return false;
}
/**
* Calculates length of string in bytes
* @param string
* @return integer length
*/
function strlen8( $str )
{
if ( $this->_mb_strlen ) {
return mb_strlen( $str, "8bit" );
}
return strlen( $str );
}
/**
* Returns part of a string, interpreting $start and $length as number of bytes.
* @param string
* @param integer start
* @param integer length
* @return integer length
*/
function substr8( $string, $start, $length=false )
{
if ( $length === false ) {
$length = $this->strlen8( $string ) - $start;
}
if ( $this->_mb_substr ) {
return mb_substr( $string, $start, $length, "8bit" );
}
return substr( $string, $start, $length );
}
}
if (class_exists('PEAR_Error')) {
class wfServices_JSON_Error extends PEAR_Error
{
function __construct($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
public function wfServices_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null) {
self::__construct($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null);
}
}
} else {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class wfServices_JSON_Error
{
/**
* PHP5 constructor.
*/
function __construct( $message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null )
{
}
/**
* PHP4 constructor.
*/
public function wfServices_JSON_Error( $message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null ) {
self::__construct( $message, $code, $mode, $options, $userinfo );
}
}
}
}

View File

@@ -0,0 +1,700 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
interface wfWAFLexerInterface {
public function nextToken();
}
class wfWAFRuleLexer implements wfWAFLexerInterface {
const MATCH_IDENTIFIER = '/[a-zA-Z_][\\w_]*/';
const MATCH_SINGLE_STRING_LITERAL = '/\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const MATCH_DOUBLE_STRING_LITERAL = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"/As';
const MATCH_NUMBER_LITERAL = '/-?\d+(\.\d+)?/';
const MATCH_DOT = '/\./';
const MATCH_AND_COMPARISON_OPERATOR = '/&&/';
const MATCH_OR_COMPARISON_OPERATOR = '/\|\|/';
const MATCH_OPEN_PARENTHESIS = '/\(/';
const MATCH_CLOSE_PARENTHESIS = '/\)/';
const MATCH_COMMA = '/,/';
const MATCH_RULE_COMPARISON_END = '/:/';
const MATCH_ASSIGNMENT = '/=/';
const MATCH_SINGLE_LINE_COMMENT = '/(?:#|\/\/)[^\n]*/';
const MATCH_MULTIPLE_LINE_COMMENT = '/\/\*.*?\*\//s';
const MATCH_OPEN_BRACKET = '/\[/';
const MATCH_CLOSE_BRACKET = '/\]/';
const T_RULE_START = 'T_RULE_START';
const T_IDENTIFIER = 'T_IDENTIFIER';
const T_SINGLE_STRING_LITERAL = 'T_SINGLE_STRING_LITERAL';
const T_DOUBLE_STRING_LITERAL = 'T_DOUBLE_STRING_LITERAL';
const T_NUMBER_LITERAL = 'T_NUMBER_LITERAL';
const T_DOT = 'T_DOT';
const T_COMPARISON_OPERATOR = 'T_COMPARISON_OPERATOR';
const T_OPEN_PARENTHESIS = 'T_OPEN_PARENTHESIS';
const T_CLOSE_PARENTHESIS = 'T_CLOSE_PARENTHESIS';
const T_COMMA = 'T_COMMA';
const T_RULE_COMPARISON_END = 'T_RULE_COMPARISON_END';
const T_ASSIGNMENT = 'T_ASSIGNMENT';
const T_SINGLE_LINE_COMMENT = 'T_SINGLE_LINE_COMMENT';
const T_MULTIPLE_LINE_COMMENT = 'T_MULTIPLE_LINE_COMMENT';
const T_OPEN_BRACKET = 'T_OPEN_BRACKET';
const T_CLOSE_BRACKET = 'T_CLOSE_BRACKET';
/**
* @var string
*/
private $rules;
/**
* @var wfWAFStringScanner
*/
private $scanner;
/**
* wfWAFRuleLexer constructor.
* @param $rules
*/
public function __construct($rules) {
$this->setRules($rules);
$this->scanner = new wfWAFStringScanner($rules);
}
/**
* @return array
* @throws wfWAFParserSyntaxError
*/
public function tokenize() {
$tokens = array();
while ($token = $this->nextToken()) {
$tokens[] = $token;
}
return $tokens;
}
/**
* @return bool|wfWAFLexerToken
* @throws wfWAFParserSyntaxError
*/
public function nextToken() {
if (!$this->scanner->eos()) {
$this->scanner->skip('/\s+/s');
if ($this->scanner->eos()) {
return false;
}
if (($match = $this->scanner->scan(self::MATCH_IDENTIFIER)) !== null)
switch (wfWAFUtils::strtolower($match)) {
case 'if':
return $this->createToken(self::T_RULE_START, $match);
case 'and':
case 'or':
case 'xor':
return $this->createToken(self::T_COMPARISON_OPERATOR, $match);
default:
return $this->createToken(self::T_IDENTIFIER, $match);
}
else if (($match = $this->scanner->scan(self::MATCH_SINGLE_STRING_LITERAL)) !== null) return $this->createToken(self::T_SINGLE_STRING_LITERAL, $match);
else if (($match = $this->scanner->scan(self::MATCH_DOUBLE_STRING_LITERAL)) !== null) return $this->createToken(self::T_DOUBLE_STRING_LITERAL, $match);
else if (($match = $this->scanner->scan(self::MATCH_NUMBER_LITERAL)) !== null) return $this->createToken(self::T_NUMBER_LITERAL, $match);
else if (($match = $this->scanner->scan(self::MATCH_DOT)) !== null) return $this->createToken(self::T_DOT, $match);
else if (($match = $this->scanner->scan(self::MATCH_AND_COMPARISON_OPERATOR)) !== null) return $this->createToken(self::T_COMPARISON_OPERATOR, $match);
else if (($match = $this->scanner->scan(self::MATCH_OR_COMPARISON_OPERATOR)) !== null) return $this->createToken(self::T_COMPARISON_OPERATOR, $match);
else if (($match = $this->scanner->scan(self::MATCH_OPEN_PARENTHESIS)) !== null) return $this->createToken(self::T_OPEN_PARENTHESIS, $match);
else if (($match = $this->scanner->scan(self::MATCH_CLOSE_PARENTHESIS)) !== null) return $this->createToken(self::T_CLOSE_PARENTHESIS, $match);
else if (($match = $this->scanner->scan(self::MATCH_COMMA)) !== null) return $this->createToken(self::T_COMMA, $match);
else if (($match = $this->scanner->scan(self::MATCH_RULE_COMPARISON_END)) !== null) return $this->createToken(self::T_RULE_COMPARISON_END, $match);
else if (($match = $this->scanner->scan(self::MATCH_ASSIGNMENT)) !== null) return $this->createToken(self::T_ASSIGNMENT, $match);
else if (($match = $this->scanner->scan(self::MATCH_OPEN_BRACKET)) !== null) return $this->createToken(self::T_OPEN_BRACKET, $match);
else if (($match = $this->scanner->scan(self::MATCH_CLOSE_BRACKET)) !== null) return $this->createToken(self::T_CLOSE_BRACKET, $match);
else if (($match = $this->scanner->scan(self::MATCH_SINGLE_LINE_COMMENT)) !== null) return $this->createToken(self::T_SINGLE_LINE_COMMENT, $match);
else if (($match = $this->scanner->scan(self::MATCH_MULTIPLE_LINE_COMMENT)) !== null) return $this->createToken(self::T_MULTIPLE_LINE_COMMENT, $match);
else {
$e = new wfWAFParserSyntaxError(sprintf('Invalid character "%s" found on line %d, column %d',
$this->scanner->scanChar(), $this->scanner->getLine(), $this->scanner->getColumn()));
$e->setParseLine($this->scanner->getLine());
$e->setParseColumn($this->scanner->getColumn());
throw $e;
}
}
return false;
}
/**
* @param $type
* @param $value
* @return wfWAFLexerToken
*/
protected function createToken($type, $value) {
return new wfWAFLexerToken($type, $value, $this->scanner->getLine(), $this->scanner->getColumn());
}
/**
* @return string
*/
public function getRules() {
return $this->rules;
}
/**
* @param string $rules
*/
public function setRules($rules) {
$this->rules = rtrim($rules);
}
}
/**
*
*/
class wfWAFLexerToken {
private $type;
private $value;
private $line;
private $column;
/**
* wfWAFRuleToken constructor.
*
* @param $type
* @param $value
* @param $line
* @param $column
*/
public function __construct($type, $value, $line, $column) {
$this->setType($type);
$this->setValue($value);
$this->setLine($line);
$this->setColumn($column);
}
/**
* @return string
*/
public function getLowerCaseValue() {
return wfWAFUtils::strtolower($this->getValue());
}
/**
* @return string
*/
public function getUpperCaseValue() {
return wfWAFUtils::strtoupper($this->getValue());
}
/**
* @return mixed
*/
public function getType() {
return $this->type;
}
/**
* @param mixed $type
*/
public function setType($type) {
$this->type = $type;
}
/**
* @return mixed
*/
public function getValue() {
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
* @return mixed
*/
public function getLine() {
return $this->line;
}
/**
* @param mixed $line
*/
public function setLine($line) {
$this->line = $line;
}
/**
* @return mixed
*/
public function getColumn() {
return $this->column;
}
/**
* @param mixed $column
*/
public function setColumn($column) {
$this->column = $column;
}
}
class wfWAFParserSyntaxError extends wfWAFException {
private $parseLine;
private $parseColumn;
private $token;
/**
* @return mixed
*/
public function getToken() {
return $this->token;
}
/**
* @param mixed $token
*/
public function setToken($token) {
$this->token = $token;
}
/**
* @return mixed
*/
public function getParseLine() {
return $this->parseLine;
}
/**
* @param mixed $parseLine
*/
public function setParseLine($parseLine) {
$this->parseLine = $parseLine;
}
/**
* @return mixed
*/
public function getParseColumn() {
return $this->parseColumn;
}
/**
* @param mixed $parseColumn
*/
public function setParseColumn($parseColumn) {
$this->parseColumn = $parseColumn;
}
}
class wfWAFBaseParser {
protected $tokens;
protected $index;
/** @var wfWAFLexerInterface */
protected $lexer;
protected $checkpoint=0;
public function __construct($lexer) {
$this->lexer = $lexer;
}
/**
* @param wfWAFLexerToken $token
* @param mixed $type
* @return bool
*/
protected function isTokenOfType($token, $type) {
if (is_array($type)) {
return $token && in_array($token->getType(), $type);
}
return $token && $token->getType() === $type;
}
/**
* @param wfWAFLexerToken $token
* @param int $type
* @param string $message
* @throws wfWAFParserSyntaxError
*/
protected function expectTokenTypeEquals($token, $type, $message = 'Wordfence WAF Syntax Error: Unexpected %s found on line %d, column %d. Expected %s.') {
if ($token->getType() !== $type) {
$this->triggerSyntaxError($token, sprintf($message, $token->getType(),
$token->getLine(), $token->getColumn(), $type));
}
}
/**
* @param wfWAFLexerToken $token
* @param array $types
* @param string $message
* @throws wfWAFParserSyntaxError
*/
protected function expectTokenTypeInArray($token, $types, $message = 'Wordfence WAF Syntax Error: Unexpected %s found on line %d, column %d') {
if (!in_array($token->getType(), $types)) {
$this->triggerSyntaxError($token, sprintf($message, $token->getType(),
$token->getLine(), $token->getColumn()));
}
}
/**
* @param wfWAFLexerToken $token
* @param string $message
* @throws wfWAFParserSyntaxError
*/
protected function triggerSyntaxError($token, $message = 'Wordfence WAF Syntax Error: Unexpected %s %s found on line %d, column %d') {
$e = new wfWAFParserSyntaxError(sprintf($message, $token->getType(), $token->getValue(),
$token->getLine(), $token->getColumn()));
$e->setToken($token);
$e->setParseLine($token->getLine());
$e->setParseColumn($token->getColumn());
throw $e;
}
/**
* @return wfWAFLexerToken
*/
protected function currentToken() {
return $this->getToken($this->index);
}
/**
* @return bool|wfWAFLexerToken
*/
protected function nextToken() {
$this->index++;
return $this->getToken($this->index);
}
/**
* @param string $message
* @return wfWAFLexerToken
* @throws wfWAFParserSyntaxError
*/
protected function expectNextToken($message = 'Expected statement') {
$this->index++;
if ($token = $this->getToken($this->index)) {
return $token;
}
throw new wfWAFParserSyntaxError($message);
}
/**
* @param int $index
* @return mixed
*/
protected function getToken($index) {
if (is_array($this->tokens) && array_key_exists($index, $this->tokens)) {
return $this->tokens[$index];
}
if ($token = $this->getLexer()->nextToken()) {
$this->tokens[$index] = $token;
return $this->tokens[$index];
}
return false;
}
/**
* @return wfWAFLexerInterface
*/
public function getLexer() {
return $this->lexer;
}
/**
* @param wfWAFLexerInterface $lexer
*/
public function setLexer($lexer) {
$this->lexer = $lexer;
}
/**
* @return mixed
*/
public function getTokens() {
return $this->tokens;
}
/**
* @param mixed $tokens
*/
public function setTokens($tokens) {
$this->tokens = $tokens;
}
protected function setCheckpoint() {
$this->checkpoint=$this->index;
}
protected function reset() {
$this->index=$this->checkpoint;
}
}
/**
*
*/
class wfWAFStringScanner {
private $string;
private $remainingStringCache;
private $length;
private $pointer;
private $remainingStringCachePointer;
private $prevPointer;
private $match;
private $captures;
/**
* wfWAFStringScanner constructor.
* @param $string
*/
public function __construct($string = null) {
if (is_string($string)) {
$this->setString($string);
}
}
/**
* @param $regex
* @return mixed
*/
public function scan($regex) {
$remaining = $this->getRemainingString();
if ($this->regexMatch($regex, $remaining, $matches)) {
$matchLen = wfWAFUtils::strlen($matches[0]);
if ($matchLen > 0 && wfWAFUtils::strpos($remaining, $matches[0]) === 0) {
return $this->setState($matches, $this->getPointer() + $matchLen, $this->getPointer());
}
}
return $this->setState();
}
/**
* @param $regex
* @return int|null
*/
public function skip($regex) {
return $this->scan($regex) ? wfWAFUtils::strlen($this->getMatch()) : null;
}
/**
* @return mixed
*/
public function scanChar() {
return $this->scan('/./s');
}
/**
* @param string $regex
* @return mixed
*/
public function check($regex) {
$remaining = $this->getRemainingString();
if ($this->regexMatch($regex, $remaining, $matches)) {
$matchLen = wfWAFUtils::strlen($matches[0]);
if ($matchLen > 0 && wfWAFUtils::strpos($remaining, $matches[0]) === 0) {
return $this->setState($matches);
}
}
return $this->setState();
}
/**
* @param string $regex
* @param string $remaining
* @param $matches
* @return int
*/
public function regexMatch($regex, $remaining, &$matches) {
// $startTime = microtime(true);
$result = preg_match($regex, $remaining, $matches);
// printf("%s took %f seconds\n", $regex, microtime(true) - $startTime);
return $result;
}
/**
* @return bool
*/
public function eos() {
return $this->getPointer() === $this->getLength();
}
/**
* @return string
*/
public function getRemainingString() {
$pointer = $this->getPointer();
if ($pointer === $this->remainingStringCachePointer && is_string($this->remainingStringCache)) {
return $this->remainingStringCache;
}
$this->remainingStringCache = wfWAFUtils::substr($this->getString(), $pointer);
$this->remainingStringCachePointer = $pointer;
return $this->remainingStringCache;
}
/**
* @return $this
*/
public function reset() {
$this->remainingStringCache = false;
$this->setState(array(), 0, 0);
return $this;
}
/**
* The current line of the scanned string.
*
* @return int
*/
public function getLine() {
if ($this->getPointer() + 1 > $this->getLength()) {
return wfWAFUtils::substr_count($this->getString(), "\n") + 1;
}
return wfWAFUtils::substr_count($this->getString(), "\n", 0, $this->getPointer() + 1) + 1;
}
/**
* The current column of the line of the scanned string.
*
* @return int
*/
public function getColumn() {
return $this->getPointer() - ((int) wfWAFUtils::strrpos(wfWAFUtils::substr($this->getString(), 0, $this->getPointer() + 1), "\n")) + 1;
}
/**
* @param array $matches
* @param int|null $pointer
* @param int|null $prevPointer
* @return mixed
*/
protected function setState($matches = array(), $pointer = null, $prevPointer = null) {
if ($pointer !== null) {
$this->setPointer($pointer);
}
if ($prevPointer !== null) {
$this->setPrevPointer($prevPointer);
}
if (is_array($matches)) {
$this->setCaptures(array_slice($matches, 1));
if (count($matches) > 0) {
$this->setMatch($matches[0]);
} else {
$this->setMatch(null);
}
} else {
$this->setMatch(null);
}
return $this->getMatch();
}
/**
* @return string
*/
public function getString() {
return $this->string;
}
/**
* @param string $string
* @throws InvalidArgumentException
*/
public function setString($string) {
if (!is_string($string)) {
throw new InvalidArgumentException(sprintf('String expected, got [%s]', gettype($string)));
}
$this->setLength(wfWAFUtils::strlen($string));
$this->string = $string;
$this->reset();
}
/**
* @return int
*/
public function getLength() {
return $this->length;
}
/**
* @param int $length
*/
protected function setLength($length) {
$this->length = $length;
}
/**
* @param int $length
*/
public function advancePointer($length) {
$this->setPointer($this->getPointer() + $length);
}
/**
* @return int
*/
public function getPointer() {
return $this->pointer;
}
/**
* @param int $pointer
*/
protected function setPointer($pointer) {
$this->pointer = $pointer;
}
/**
* @return int
*/
public function getPrevPointer() {
return $this->prevPointer;
}
/**
* @param int $prevPointer
*/
protected function setPrevPointer($prevPointer) {
$this->prevPointer = $prevPointer;
}
/**
* @return mixed
*/
public function getMatch() {
return $this->match;
}
/**
* @param mixed $match
*/
protected function setMatch($match) {
$this->match = $match;
}
/**
* @param null $index
* @return mixed
*/
public function getCaptures($index = null) {
if (is_numeric($index)) {
return isset($this->captures[$index]) ? $this->captures[$index] : null;
}
return $this->captures;
}
/**
* @param mixed $captures
*/
protected function setCaptures($captures) {
$this->captures = $captures;
}
}
}

View File

@@ -0,0 +1,923 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
require_once dirname(__FILE__) . '/lexer.php';
class wfWAFRuleParser extends wfWAFBaseParser {
/**
* @var wfWAF
*/
private $waf;
private $parenCount = 0;
/**
* wfWAFRuleParser constructor.
* @param $lexer
* @param wfWAF $waf
*/
public function __construct($lexer, $waf) {
parent::__construct($lexer);
$this->setWAF($waf);
}
/**
* @return array
* @throws wfWAFParserSyntaxError
* @throws wfWAFRuleParserSyntaxError
*/
public function parse() {
$rules = array();
$scores = array();
$blacklistedParams = array();
$whitelistedParams = array();
$variables = array();
$this->index = -1;
while ($token = $this->nextToken()) {
// Rule parsing
if ($token->getType() == wfWAFRuleLexer::T_RULE_START) {
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
$comparisonGroup = $this->parseConditional();
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_CLOSE_PARENTHESIS);
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_RULE_COMPARISON_END);
$action = $this->parseAction();
$rules[] = new wfWAFRule(
$this->getWAF(),
$action->getRuleID(),
$action->getType(),
$action->getCategory(),
$action->getScore(),
$action->getDescription(),
$action->getWhitelist(),
$action->getAction(),
$comparisonGroup
);
}
// Score/config parsing
if ($token->getType() == wfWAFRuleLexer::T_IDENTIFIER) {
switch ($token->getValue()) {
case 'scores':
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_DOT);
$scoreCategoryToken = $this->expectNextToken();
$this->expectTokenTypeEquals($scoreCategoryToken, wfWAFRuleLexer::T_IDENTIFIER);
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_ASSIGNMENT);
$scoreToken = $this->expectNextToken();
$this->expectTokenTypeEquals($scoreToken, wfWAFRuleLexer::T_NUMBER_LITERAL);
$scores[$scoreCategoryToken->getValue()] = $scoreToken->getValue();
break;
case 'blacklistParam':
$blacklistedParams[] = $this->parseURLParams();
break;
case 'whitelistParam':
$whitelistedParams[] = $this->parseURLParams();
break;
default:
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_ASSIGNMENT);
$valueToken = $this->expectNextToken();
$this->expectTokenTypeInArray($valueToken, array(
wfWAFRuleLexer::T_SINGLE_STRING_LITERAL,
wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL,
wfWAFRuleLexer::T_NUMBER_LITERAL,
));
if ($valueToken->getType() === wfWAFRuleLexer::T_SINGLE_STRING_LITERAL) {
$value = wfWAFUtils::substr($valueToken->getValue(), 1, -1);
$value = str_replace("\\'", "'", $value);
} else if ($valueToken->getType() === wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL) {
$value = wfWAFUtils::substr($valueToken->getValue(), 1, -1);
$value = str_replace('\\"', '"', $value);
} else {
$value = $valueToken->getValue();
}
$variables[$token->getValue()] = new wfWAFRuleVariable($this->getWAF(), $token->getValue(), $value);
break;
}
}
}
return array(
'scores' => $scores,
'blacklistedParams' => $blacklistedParams,
'whitelistedParams' => $whitelistedParams,
'variables' => $variables,
'rules' => $rules,
);
}
/**
* @param array $vars
* @return string
*/
public function renderRules($vars) {
$rules = '';
if (array_key_exists('scores', $vars)) {
foreach ($vars['scores'] as $category => $score) {
// scores.sqli = 100
$rules .= sprintf("scores.%s = %d\n", $category, $score);
}
$rules .= "\n";
}
$params = array(
'blacklistParam' => 'blacklistedParams',
'whitelistParam' => 'whitelistedParams',
);
foreach ($params as $action => $key) {
if (array_key_exists($key, $vars)) {
/** @var wfWAFRuleParserURLParam $urlParam */
foreach ($vars[$key] as $urlParam) {
$rules .= $urlParam->renderRule($action) . "\n";
}
$rules .= "\n";
}
}
if (array_key_exists('variables', $vars)) {
/** @var wfWAFRuleVariable $variable */
foreach ($vars['variables'] as $variableName => $variable) {
$rules .= sprintf("%s = %s\n", $variable->renderRule(), $variable->renderValue());
}
$rules .= "\n";
}
if (array_key_exists('rules', $vars)) {
/** @var wfWAFRule $rule */
foreach ($vars['rules'] as $rule) {
$rules .= $rule->renderRule() . "\n";
}
$rules .= "\n";
}
return $rules;
}
/**
* @param int $index
* @return mixed
*/
public function getToken($index) {
if (is_array($this->tokens) && array_key_exists($index, $this->tokens)) {
return $this->tokens[$index];
}
if ($token = $this->getLexer()->nextToken()) {
$this->tokens[$index] = $token;
return $this->tokens[$index];
}
return false;
}
/**
* @return wfWAFRuleComparisonGroup
*/
private function parseConditional() {
$comparisonGroup = new wfWAFRuleComparisonGroup();
while ($token = $this->nextToken()) {
switch ($token->getType()) {
case wfWAFRuleLexer::T_IDENTIFIER:
$comparisonGroup->add($this->parseComparison());
break;
case wfWAFRuleLexer::T_COMPARISON_OPERATOR:
$comparisonGroup->add(new wfWAFRuleLogicalOperator($token->getValue()));
break;
case wfWAFRuleLexer::T_OPEN_PARENTHESIS:
$this->parenCount++;
$comparisonGroup->add($this->parseConditional());
break;
case wfWAFRuleLexer::T_CLOSE_PARENTHESIS:
if ($this->parenCount === 0) {
$this->index--;
return $comparisonGroup;
}
$this->parenCount--;
return $comparisonGroup;
}
}
return $comparisonGroup;
}
private function parseComparison($expectLiteral = true) {
/**
* @var wfWAFLexerToken $actionToken
* @var wfWAFLexerToken $expectedToken
*/
$this->setCheckpoint();
$actionToken = $this->currentToken();
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
$value=null;
if($expectLiteral) {
try {
$value = $this->expectLiteral(array(wfWAFRuleLexer::T_CLOSE_PARENTHESIS));
if ($value === null && $expectLiteral) {
$this->index--;
}
}
catch(wfWAFParserSyntaxError $e) {
if($expectLiteral) {
$this->reset();
return $this->parseComparison(false);
}
throw $e;
}
}
$subjects = array();
$nextToken = $this->nextToken();
if ($value!==null||!$expectLiteral) {
while (true) {
if ($nextToken && $nextToken->getType() === wfWAFRuleLexer::T_CLOSE_PARENTHESIS) {
break;
}
if (!($nextToken && $nextToken->getType() === wfWAFRuleLexer::T_COMMA)) {
if(empty($subjects) && $expectLiteral) {
$this->reset();
return $this->parseComparison(false);
}
$this->index--;
if(!empty($subjects))
break;
}
list($filters, $subject) = $this->parseFilters();
$current = new wfWAFRuleComparisonSubject($this->getWAF(), $subject, $filters);
$nextToken = $this->expectNextToken();
if (in_array($nextToken->getType(), array(wfWAFRuleLexer::T_DOT, wfWAFRuleLexer::T_OPEN_BRACKET))) {
$this->index--;
$childSubject = $this->parseSubject(false);
if (!is_array($childSubject) )
$childSubject = array($childSubject);
array_unshift($childSubject, $current);
$current = new wfWAFRuleComparisonSubject($this->getWAF(), $childSubject, array());
$nextToken = $this->expectNextToken();
}
$subjects[] = $current;
}
$this->expectTokenTypeEquals($nextToken, wfWAFRuleLexer::T_CLOSE_PARENTHESIS);
}
$comparison = new wfWAFRuleComparison($this->getWAF(), $actionToken->getValue(), $value, $subjects);
return $comparison;
}
/**
* @return wfWAFRuleParserAction
*/
private function parseAction() {
$action = new wfWAFRuleParserAction();
$actionToken = $this->expectNextToken();
$this->expectTokenTypeEquals($actionToken, wfWAFRuleLexer::T_IDENTIFIER);
$action->setAction($actionToken->getValue());
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
while (true) {
$token = $this->expectNextToken();
switch ($token->getType()) {
case wfWAFRuleLexer::T_IDENTIFIER:
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_ASSIGNMENT);
$valueToken = $this->expectNextToken();
$this->expectTokenTypeInArray($valueToken, array(
wfWAFRuleLexer::T_SINGLE_STRING_LITERAL,
wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL,
wfWAFRuleLexer::T_NUMBER_LITERAL,
));
$action->set($token->getValue(), $valueToken->getValue());
break;
case wfWAFRuleLexer::T_COMMA:
break;
case wfWAFRuleLexer::T_CLOSE_PARENTHESIS:
break 2;
default:
$this->triggerSyntaxError($token, sprintf('Wordfence WAF Rules Syntax Error: Unexpected %s found on line %d, column %d',
$token->getType(), $token->getLine(), $token->getColumn()));
}
}
return $action;
}
private function parseFilters() {
$filters = array();
$subject = null;
do {
$globalToken = $this->expectNextToken();
$this->expectTokenTypeEquals($globalToken, wfWAFRuleLexer::T_IDENTIFIER);
$parenToken = $this->expectNextToken();
switch ($parenToken->getType()) {
case wfWAFRuleLexer::T_DOT:
$this->index -= 2;
$subject = $this->parseSubject();
break 2;
case wfWAFRuleLexer::T_OPEN_PARENTHESIS:
array_unshift($filters, array($globalToken->getValue()));
break;
default:
$this->triggerSyntaxError($parenToken,
sprintf('Wordfence WAF Rules Syntax Error: Unexpected %s found on line %d, column %d.',
$parenToken->getType(), $parenToken->getLine(), $parenToken->getColumn()));
}
} while (true);
if ($subject === null) {
throw new wfWAFParserSyntaxError('No subject supplied to filter');
}
for ($i = 0; $i < count($filters); $i++) {
do {
$next = $this->expectNextToken();
$this->expectTokenTypeInArray($next, array(wfWAFRuleLexer::T_CLOSE_PARENTHESIS, wfWAFRuleLexer::T_COMMA));
if ($next->getType() === wfWAFRuleLexer::T_COMMA) {
$filters[$i][] = $this->expectLiteral();
}
else {
break;
}
} while(true);
}
return array($filters, $subject);
}
/**
* @throws wfWAFParserSyntaxError
*/
private function parseSubject($global = true) {
if ($global) {
$globalToken = $this->expectNextToken();
$this->expectTokenTypeEquals($globalToken, wfWAFRuleLexer::T_IDENTIFIER);
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_DOT);
$globalToken2 = $this->expectNextToken();
$this->expectTokenTypeEquals($globalToken2, wfWAFRuleLexer::T_IDENTIFIER);
$subject = array(
$globalToken->getValue() . '.' . $globalToken2->getValue(),
);
}
else {
$subject = array();
}
$savePoint = $this->index;
while (($property = $this->parsePropertyAccessor()) !== false) {
$subject[] = $property;
$savePoint = $this->index;
}
$this->index = $savePoint;
if (count($subject) === 1) {
list($subject) = $subject;
}
return $subject;
}
/**
* @return bool|mixed|string
* @throws wfWAFParserSyntaxError
*/
private function parsePropertyAccessor() {
$savePoint = $this->index;
$nextToken = $this->nextToken();
if ($this->isTokenOfType($nextToken, wfWAFRuleLexer::T_DOT)) {
$property = $this->expectNextToken();
$this->expectTokenTypeEquals($property, wfWAFRuleLexer::T_IDENTIFIER);
return $property->getValue();
} else if ($this->isTokenOfType($nextToken, wfWAFRuleLexer::T_OPEN_BRACKET)) {
$property = $this->expectLiteral();
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_CLOSE_BRACKET);
return $property;
}
$this->index = $savePoint;
return false;
}
/**
* @return wfWAFRuleParserURLParam
* @throws wfWAFParserSyntaxError
*/
private function parseURLParams() {
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
$urlParam = new wfWAFRuleParserURLParam();
while (true) {
$token = $this->expectNextToken();
switch ($token->getType()) {
case wfWAFRuleLexer::T_IDENTIFIER:
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_ASSIGNMENT);
if ($token->getValue() === 'url') {
$url = $this->expectLiteral();
$urlParam->setUrl($url);
} else if ($token->getValue() === 'param') {
$subject = $this->parseSubject();
$urlParam->setParam(wfWAFRuleComparison::getSubjectKey($subject));
} else if ($token->getValue() === 'rules') {
$rules = $this->expectLiteral();
$urlParam->setRules($rules);
} else if ($token->getValue() === 'conditional') {
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
$conditional = $this->parseConditional();
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_CLOSE_PARENTHESIS);
$urlParam->setConditional($conditional);
} else if ($token->getValue() === 'minVersion') {
$minVersion = $this->expectLiteral();
$urlParam->setMinVersion($minVersion);
}
break;
case wfWAFRuleLexer::T_COMMA:
break;
case wfWAFRuleLexer::T_CLOSE_PARENTHESIS:
break 2;
default:
$this->triggerSyntaxError($token, sprintf('Wordfence WAF Rules Syntax Error: Unexpected %s found on line %d, column %d',
$token->getType(), $token->getLine(), $token->getColumn()));
}
}
return $urlParam;
}
/**
* @return mixed|string
* @throws wfWAFRuleParserSyntaxError
*/
private function expectLiteral($allowExtra = array()) {
$expectedToken = $this->expectNextToken();
$this->expectTokenTypeInArray($expectedToken, array_merge(array(
wfWAFRuleLexer::T_SINGLE_STRING_LITERAL,
wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL,
wfWAFRuleLexer::T_IDENTIFIER,
wfWAFRuleLexer::T_NUMBER_LITERAL,
wfWAFRuleLexer::T_OPEN_BRACKET,
), $allowExtra));
if ($expectedToken->getType() === wfWAFRuleLexer::T_SINGLE_STRING_LITERAL) {
// Remove quotes, strip slashes
$value = wfWAFUtils::substr($expectedToken->getValue(), 1, -1);
$value = str_replace("\\'", "'", $value);
} else if ($expectedToken->getType() === wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL) {
// Remove quotes, strip slashes
$value = wfWAFUtils::substr($expectedToken->getValue(), 1, -1);
$value = str_replace('\\"', '"', $value);
} else if ($expectedToken->getType() === wfWAFRuleLexer::T_IDENTIFIER) {
// Remove quotes, strip slashes
$value = new wfWAFRuleVariable($this->getWAF(), $expectedToken->getValue());
} else if ($expectedToken->getType() === wfWAFRuleLexer::T_OPEN_BRACKET) {
$value = array();
while (true) {
$nextToken = $this->expectNextToken();
if ($nextToken->getType() === wfWAFRuleLexer::T_CLOSE_BRACKET) {
break;
}
if ($nextToken->getType() === wfWAFRuleLexer::T_COMMA) {
continue;
}
$this->index--;
$value[] = $this->expectLiteral();
}
} else if (in_array($expectedToken->getType(), $allowExtra)) {
return null;
} else {
$value = $expectedToken->getValue();
}
return $value;
}
/**
* @param wfWAFLexerToken $token
* @param string|array $value
* @return bool
*/
private function isIdentifierWithValue($token, $value) {
return $token && $token->getType() === wfWAFRuleLexer::T_IDENTIFIER &&
(is_array($value) ? in_array($token->getLowerCaseValue(), array_map('strtolower', $value)) :
$token->getLowerCaseValue() === strtolower($value));
}
/**
* @param wfWAFLexerToken $token
* @return bool
*/
protected function isCommentToken($token) {
return $token->getType() === wfWAFRuleLexer::T_MULTIPLE_LINE_COMMENT || $token->getType() === wfWAFRuleLexer::T_SINGLE_LINE_COMMENT;
}
/**
* @return wfWAF
*/
public function getWAF() {
return $this->waf;
}
/**
* @param wfWAF $waf
*/
public function setWAF($waf) {
$this->waf = $waf;
}
}
class wfWAFRuleParserAction {
private $ruleID;
private $type;
private $category;
private $score;
private $description;
private $whitelist = 1;
private $action;
/**
* @param string $param
* @param mixed $value
*/
public function set($param, $value) {
$propLinkTable = array(
'id' => 'ruleID',
);
if (array_key_exists($param, $propLinkTable)) {
$param = $propLinkTable[$param];
}
if (property_exists($this, $param)) {
$this->$param = trim($value, '\'"');
}
}
/**
* @return mixed
*/
public function getRuleID() {
return $this->ruleID;
}
/**
* @param mixed $ruleID
*/
public function setRuleID($ruleID) {
$this->ruleID = $ruleID;
}
/**
* @return mixed
*/
public function getType() {
return $this->type;
}
/**
* @param mixed $type
*/
public function setType($type) {
$this->type = $type;
}
/**
* @return mixed
*/
public function getCategory() {
return $this->category;
}
/**
* @param mixed $category
*/
public function setCategory($category) {
$this->category = $category;
}
/**
* @return mixed
*/
public function getScore() {
return $this->score;
}
/**
* @param mixed $score
*/
public function setScore($score) {
$this->score = $score;
}
/**
* @return mixed
*/
public function getDescription() {
return $this->description;
}
/**
* @param mixed $description
*/
public function setDescription($description) {
$this->description = $description;
}
/**
* @return mixed
*/
public function getWhitelist() {
return $this->whitelist;
}
/**
* @param mixed $whitelist
*/
public function setWhitelist($whitelist) {
$this->whitelist = $whitelist;
}
/**
* @return mixed
*/
public function getAction() {
return $this->action;
}
/**
* @param mixed $action
*/
public function setAction($action) {
$this->action = $action;
}
}
class wfWAFRuleParserURLParam {
/**
* @var string
*/
private $url;
/**
* @var string
*/
private $param;
/**
* @var null
*/
private $rules;
/**
* @var null
*/
private $conditional;
/**
* @var float
*/
private $minVersion;
/**
* @param string $param
* @param mixed $value
*/
public function set($param, $value) {
if (property_exists($this, $param)) {
$this->$param = trim($value, '\'"');
}
}
/**
* @param string $url
* @param string $param
* @param null $rules
*/
public function __construct($url = null, $param = null, $rules = null, $conditional = null, $minVersion = null) {
$this->url = $url;
$this->param = $param;
$this->rules = $rules;
$this->conditional = $conditional;
$this->minVersion = $minVersion;
}
/**
* Return format:
* blacklistParam(url='/\/uploadify\.php$/i', param=request.fileNames.Filedata, rules=[3, 14], conditional=(match('1', request.body.field)))
*
* @param string $action
* @return string
*/
public function renderRule($action) {
return sprintf('%s(url=%s, param=%s%s%s)', $action,
wfWAFRule::exportString($this->getUrl()),
$this->renderParam($this->getParam()),
$this->getRules() ? ', rules=[' . join(', ', array_map('intval', $this->getRules())) . ']' : '',
$this->getConditional() ? ', conditional=(' . $this->getConditional()->renderRule() . ')' : '');
//minVersion not included in re-rendering
}
/**
* @param string $param
* @return mixed
*/
private function renderParam($param) {
if (preg_match('/([a-zA-Z_][\\w_]*?\\.[a-zA-Z_][\\w_]*)(.*)/', $param, $matches)) {
list(, $global, $params) = $matches;
if (strlen($params) > 0) {
if (preg_match_all('/\\[([^\\]]*?)\\]/', $params, $matches)) {
$rendered = $global;
foreach ($matches[1] as $prop) {
$single = "'" . str_replace(array("'", '\\'), array("\\'", "\\\\"), $prop) . "'";
$double = '"' . str_replace(array('"', '\\'), array('\\"', "\\\\"), $prop) . '"';
$rendered .= sprintf('[%s]', strlen($single) <= strlen($double) ? $single : $double);
}
return $rendered;
}
}
}
return $param;
}
/**
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* @param string $url
*/
public function setUrl($url) {
$this->url = $url;
}
/**
* @return string
*/
public function getParam() {
return $this->param;
}
/**
* @param string $param
*/
public function setParam($param) {
$this->param = $param;
}
/**
* @return null
*/
public function getRules() {
return $this->rules;
}
/**
* @param null $rules
*/
public function setRules($rules) {
$this->rules = $rules;
}
/**
* @return null
*/
public function getConditional() {
return $this->conditional;
}
/**
* @param null $conditional
*/
public function setConditional($conditional) {
$this->conditional = $conditional;
}
/**
* @return float|null
*/
public function getMinVersion() {
return $this->minVersion;
}
/**
* @param float $minVersion
*/
public function setMinVersion($minVersion) {
$this->minVersion = $minVersion;
}
}
class wfWAFRuleParserSyntaxError extends wfWAFParserSyntaxError {
private $token;
/**
* @return mixed
*/
public function getToken() {
return $this->token;
}
/**
* @param mixed $token
*/
public function setToken($token) {
$this->token = $token;
}
}
class wfWAFRuleVariable {
/**
* @var string
*/
private $name;
/**
* @var mixed|null
*/
private $value;
/**
* @var wfWAF
*/
private $waf;
/**
* wfWAFRuleVariable constructor.
* @param wfWAF $waf
* @param string $name
* @param mixed $value
*/
public function __construct($waf, $name, $value = null) {
$this->waf = $waf;
$this->name = $name;
$this->value = $value;
}
public function __sleep() {
return array(
'name',
'value',
);
}
public function render() {
return sprintf('new %s($this, %s, %s)', get_class($this),
var_export($this->getName(), true), var_export($this->getValue(), true));
}
public function renderRule() {
return sprintf('%s', $this->getName());
}
public function renderValue() {
return wfWAFRule::exportString($this);
}
public function __toString() {
$value = $this->getValue();
if (is_string($value)) {
return $value;
}
return (string) $this->getWAF()->getVariable($this->getName());
}
/**
* @return string
*/
public function getName() {
return $this->name;
}
/**
* @param string $name
*/
public function setName($name) {
$this->name = $name;
}
/**
* @return mixed|null
*/
public function getValue() {
return $this->value;
}
/**
* @param mixed|null $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
* @return wfWAF
*/
public function getWAF() {
return $this->waf;
}
/**
* @param wfWAF $waf
*/
public function setWAF($waf) {
$this->waf = $waf;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
<?php
class wfShutdownFunction {
private $callable;
private $priority;
public function __construct($callable, $priority) {
$this->callable = $callable;
$this->priority = $priority;
}
public function invoke() {
call_user_func($this->callable);
}
public function getPriority() {
return $this->priority;
}
public function __wakeup() {
$this->callable = function() {};
}
}
class wfShutdownRegistry {
private static $instance = null;
const PRIORITY_LAST = 100;
private $functions = array();
private $registered = false;
public function handleShutdown() {
usort($this->functions, function ($a, $b) {
return $a->getPriority() - $b->getPriority();
});
foreach ($this->functions as $function) {
$function->invoke();
}
}
public function register($function, $priority = 50) {
array_push($this->functions, new wfShutdownFunction($function, $priority));
$this->registerSelf();
}
private function registerSelf() {
if (!$this->registered) {
register_shutdown_function(array($this, 'handleShutdown'));
$this->registered = true;
}
}
public function __wakeup() {
$this->functions = array();
$this->registered = false;
}
public static function getDefaultInstance() {
if (self::$instance === null)
self::$instance = new self();
return self::$instance;
}
}

View File

@@ -0,0 +1,81 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
interface wfWAFStorageInterface {
const IP_BLOCKS_ALL = PHP_INT_MAX;
const IP_BLOCKS_SINGLE = 1; //1 << 0
const IP_BLOCKS_BLACKLIST = 2; //1 << 1
public function hasPreviousAttackData($olderThan);
public function hasNewerAttackData($newerThan);
public function getAttackData();
public function getAttackDataArray();
public function getNewestAttackDataArray($newerThan);
public function truncateAttackData();
/**
* @param array $failedRules
* @param string $failedParamKey
* @param string $failedParamValue
* @param wfWAFRequestInterface $request
* @param mixed $_
* @return mixed
*/
public function logAttack($failedRules, $failedParamKey, $failedParamValue, $request, $_ = null);
/**
* @param int $timestamp
* @param string $ip
* @param bool $ssl
* @param array $failedRuleIDs
* @param wfWAFRequestInterface|string $request
* @param mixed $_
* @return mixed
*/
// public function logAttack($timestamp, $ip, $ssl, $failedRuleIDs, $request, $_ = null);
/**
* @param float $timestamp
* @param string $ip
* @return mixed
*/
public function blockIP($timestamp, $ip);
public function isIPBlocked($ip);
public function purgeIPBlocks($types = wfWAFStorageInterface::IP_BLOCKS_ALL);
public function getConfig($key, $default = null, $category = '');
public function setConfig($key, $value, $category = '');
public function unsetConfig($key, $category = '');
public function uninstall();
//optional public function fileList();
public function isInLearningMode();
public function isDisabled();
public function getRulesDSLCacheFile();
public function isAttackDataFull();
public function vacuum();
public function getRules();
public function setRules($rules);
public function needsInitialRules();
public function getDescription();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
class wfWAFView {
/**
* @var string
*/
protected $viewPath;
/**
* @var string
*/
protected $viewFileExtension = '.php';
/**
* @var string
*/
protected $view;
/**
* @var array
*/
protected $data;
/**
* @param string $view
* @param array $data
* @return wfWAFView
*/
public static function create($view, $data = array()) {
return new self($view, $data);
}
/**
* @param string $view
* @param array $data
*/
public function __construct($view, $data = array()) {
$this->viewPath = WFWAF_VIEW_PATH;
$this->view = $view;
$this->data = $data;
}
/**
* @return string
* @throws wfWAFViewNotFoundException
*/
public function render() {
$view = preg_replace('/\.{2,}/', '.', $this->view);
$viewPath = $this->viewPath . '/' . $view . $this->viewFileExtension;
if (!file_exists($viewPath)) {
throw new wfWAFViewNotFoundException('The view ' . $viewPath . ' does not exist or is not readable.');
}
extract($this->data, EXTR_SKIP);
if (!defined('WFWAF_VIEW_RENDERING')) { define('WFWAF_VIEW_RENDERING', true); }
ob_start();
/** @noinspection PhpIncludeInspection */
include $viewPath;
return ob_get_clean();
}
/**
* @return string
*/
public function __toString() {
try {
return $this->render();
} catch (wfWAFViewNotFoundException $e) {
return defined('WFWAF_DEBUG') && WFWAF_DEBUG ? $e->getMessage() : 'The view could not be loaded.';
}
}
/**
* @param $data
* @return $this
*/
public function addData($data) {
$this->data = array_merge($data, $this->data);
return $this;
}
/**
* @return array
*/
public function getData() {
return $this->data;
}
/**
* @param array $data
* @return $this
*/
public function setData($data) {
$this->data = $data;
return $this;
}
/**
* @return string
*/
public function getView() {
return $this->view;
}
/**
* @param string $view
* @return $this
*/
public function setView($view) {
$this->view = $view;
return $this;
}
/**
* Prevent POP
*/
public function __wakeup() {
$this->viewPath = WFWAF_VIEW_PATH;
$this->view = null;
$this->data = array();
$this->viewFileExtension = '.php';
}
}
class wfWAFViewNotFoundException extends Exception {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
<?php
if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) {
/**
* Adaptation of WordPress's XML-RPC message parser so we can use it without loading the full environment
*
*/
class wfXMLRPCBody
{
var $header;
var $doctype;
var $message;
var $messageType; // methodCall / methodResponse / fault
var $faultCode;
var $faultString;
var $methodName;
var $params;
// Current variable stacks
var $_arraystructs = array(); // The stack used to keep track of the current array/struct
var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
var $_currentStructName = array(); // A stack as well
var $_param;
var $_value;
var $_currentTag;
var $_currentTagContents;
// The XML parser
var $_parser;
static function canParse() {
return function_exists('xml_parser_create');
}
/**
* PHP5 constructor.
*/
function __construct( $message )
{
$this->message =& $message;
}
function __toString() {
$output = '';
if (isset($this->header)) {
$output .= $this->header . "\n";
}
if (isset($this->doctype)) {
$output .= $this->doctype . "\n";
}
$output .= '<methodCall><methodName>' . htmlentities($this->methodName, ENT_XML1) . '</methodName><params>' . $this->_paramsToString($this->params) . '</params></methodCall>';
return $output;
}
function _paramsToString($params, $parentType = false) {
$output = '';
if (is_array($params)) {
foreach ($params as $key => $p) {
if (!$parentType) { //Top level
$output .= '<param><value>';
}
else if ($parentType == 'array') {
$output .= '<value>';
}
else if ($parentType == 'struct') {
$output .= '<member><name>' . htmlentities($key, ENT_XML1) . '</name><value>';
}
if ($p['tag'] == 'data') {
$output .= '<array><data>' . $this->_paramsToString($p['value'], 'array') . '</data></array>';
}
else if ($p['tag'] == 'struct') {
$output .= '<struct>' . $this->_paramsToString($p['value'], 'struct') . '</struct>';
}
else if ($p['tag'] == 'base64') {
$output .= '<base64>' . base64_encode($p['value']) . '</base64>';
}
else if ($p['tag'] == 'value') {
$output .= htmlentities($p['value'], ENT_XML1);
}
else if ($p['tag'] == 'dateTime.iso8601') {
$output .= $p['value']->getXml();
}
else {
$output .= '<' . $p['tag'] . '>' . htmlentities($p['value'], ENT_XML1) . '</' . $p['tag'] . '>';
}
if (!$parentType) { //Top level
$output .= '</value></param>';
}
else if ($parentType == 'array') {
$output .= '</value>';
}
else if ($parentType == 'struct') {
$output .= '</value></member>';
}
}
}
return $output;
}
function parse()
{
if (!function_exists( 'xml_parser_create')) {
return false;
}
// first remove the XML declaration
if (preg_match('/<\?xml.*?\?'.'>/s', substr( $this->message, 0, 100 ), $matches)) {
$this->header = $matches[0];
}
$replacement = preg_replace( '/<\?xml.*?\?'.'>/s', '', substr( $this->message, 0, 100 ), 1 );
$this->message = trim( substr_replace( $this->message, $replacement, 0, 100 ) );
if ( '' == $this->message ) {
return false;
}
// Then remove the DOCTYPE
if (preg_match('/^<!DOCTYPE[^>]*+>/i', substr( $this->message, 0, 100 ), $matches)) {
$this->doctype = $matches[0];
}
$replacement = preg_replace( '/^<!DOCTYPE[^>]*+>/i', '', substr( $this->message, 0, 200 ), 1 );
$this->message = trim( substr_replace( $this->message, $replacement, 0, 200 ) );
if ( '' == $this->message ) {
return false;
}
// Check that the root tag is valid
$root_tag = substr( $this->message, 0, strcspn( substr( $this->message, 0, 20 ), "> \t\r\n" ) );
if ( '<!DOCTYPE' === strtoupper( $root_tag ) ) {
return false;
}
if ( ! in_array( $root_tag, array( '<methodCall', '<methodResponse', '<fault' ) ) ) {
return false;
}
// Bail if there are too many elements to parse
$element_limit = 30000;
if ( $element_limit && 2 * $element_limit < substr_count( $this->message, '<' ) ) {
return false;
}
$this->_parser = xml_parser_create();
// Set XML parser to take the case of tags in to account
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
// Set XML parser callback functions
xml_set_object($this->_parser, $this);
xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
xml_set_character_data_handler($this->_parser, 'cdata');
// 256Kb, parse in chunks to avoid the RAM usage on very large messages
$chunk_size = 262144;
$final = false;
do {
if (strlen($this->message) <= $chunk_size) {
$final = true;
}
$part = substr($this->message, 0, $chunk_size);
$this->message = substr($this->message, $chunk_size);
if (!xml_parse($this->_parser, $part, $final)) {
return false;
}
if ($final) {
break;
}
} while (true);
xml_parser_free($this->_parser);
// Grab the error messages, if any
if ($this->messageType == 'fault') {
$this->faultCode = $this->params[0]['faultCode'];
$this->faultString = $this->params[0]['faultString'];
}
return true;
}
function tag_open($parser, $tag, $attr)
{
$this->_currentTagContents = '';
$this->currentTag = $tag;
switch($tag) {
case 'methodCall':
case 'methodResponse':
case 'fault':
$this->messageType = $tag;
break;
/* Deal with stacks of arrays and structs */
case 'data': // data is to all intents and puposes more interesting than array
$this->_arraystructstypes[] = 'array';
$this->_arraystructs[] = array();
break;
case 'struct':
$this->_arraystructstypes[] = 'struct';
$this->_arraystructs[] = array();
break;
}
}
function cdata($parser, $cdata)
{
$this->_currentTagContents .= $cdata;
}
function tag_close($parser, $tag)
{
$valueFlag = false;
switch($tag) {
case 'int':
case 'i4':
$value = (int)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'double':
$value = (double)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'string':
$value = (string)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'dateTime.iso8601':
$value = new wfXMLRPCDate(trim($this->_currentTagContents));
$valueFlag = true;
break;
case 'value':
// "If no type is indicated, the type is string."
if (trim($this->_currentTagContents) != '') {
$value = (string)$this->_currentTagContents;
$valueFlag = true;
}
break;
case 'boolean':
$value = (boolean)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'base64':
$value = base64_decode($this->_currentTagContents);
$valueFlag = true;
break;
/* Deal with stacks of arrays and structs */
case 'data':
case 'struct':
$value = array_pop($this->_arraystructs);
array_pop($this->_arraystructstypes);
$valueFlag = true;
break;
case 'member':
array_pop($this->_currentStructName);
break;
case 'name':
$this->_currentStructName[] = trim($this->_currentTagContents);
break;
case 'methodName':
$this->methodName = trim($this->_currentTagContents);
break;
}
if ($valueFlag) {
if (count($this->_arraystructs) > 0) {
// Add value to struct or array
if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
// Add to struct
$this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = array('tag' => $tag, 'value' => $value);
} else {
// Add to array
$this->_arraystructs[count($this->_arraystructs)-1][] = array('tag' => $tag, 'value' => $value);
}
} else {
// Just add as a parameter
$this->params[] = array('tag' => $tag, 'value' => $value);
}
}
$this->_currentTagContents = '';
}
}
class wfXMLRPCDate {
var $year;
var $month;
var $day;
var $hour;
var $minute;
var $second;
var $timezone;
function __construct( $time )
{
// $time can be a PHP timestamp or an ISO one
if (is_numeric($time)) {
$this->parseTimestamp($time);
} else {
$this->parseIso($time);
}
}
function parseTimestamp($timestamp)
{
$this->year = date('Y', $timestamp);
$this->month = date('m', $timestamp);
$this->day = date('d', $timestamp);
$this->hour = date('H', $timestamp);
$this->minute = date('i', $timestamp);
$this->second = date('s', $timestamp);
$this->timezone = '';
}
function parseIso($iso)
{
$this->year = substr($iso, 0, 4);
$this->month = substr($iso, 4, 2);
$this->day = substr($iso, 6, 2);
$this->hour = substr($iso, 9, 2);
$this->minute = substr($iso, 12, 2);
$this->second = substr($iso, 15, 2);
$this->timezone = substr($iso, 17);
}
function getIso()
{
return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
}
function getXml()
{
return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
}
function getTimestamp()
{
return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
}
}
}

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzovUDp/qu7r6LT5d8dLL
H/87aRrCjUd6XtnG+afAPVfMKNp4u4L+UuYfw1RfpfquP/zLMGdfmJCUp/oJywkW
Rkqo+y7pDuqIFQ59dHvizmYQRvaZgvincBDpey5Ek9AFfB9fqYYnH9+eQw8eLdQi
h6Zsh8RsuxFM2BW6JD9Km7L5Lyxw9jU+lye7I3ICYtUOVxc3n3bJT2SiIwHK57pW
g/asJEUDiYQzsaa90YPOLdf1Ysz2rkgnCduQaEGz/RPhgUrmZfKwq8puEmkh7Yee
auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
1QIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,219 @@
<?php
if (!defined('WFWAF_VIEW_RENDERING')) { exit; }
/** @var wfWAF $waf */
/** @var wfWAFView $this */
/*
* IMPORTANT:
*
* If the form variables below change name or format, admin.ajaxWatcher.js in the main plugin also needs changed. It
* processes these to generate its whitelist button.
*/
$request = $waf->getRequest();
$headerString = '';
if (is_array($request->getHeaders())) {
foreach ($request->getHeaders() as $header => $value) {
switch (wfWAFUtils::strtolower($header)) {
case 'cookie':
$headerString .= 'Cookie: ' . trim($request->getCookieString()) . "\n";
break;
case 'host':
$headerString .= 'Host: ' . $request->getHost() . "\n";
break;
case 'authorization':
$hasAuth = true;
if ($request->getAuth()) {
$headerString .= 'Authorization: Basic <redacted>' . "\n";
}
break;
default:
$headerString .= $header . ': ' . $value . "\n";
break;
}
}
}
$payload = array('ip' => $request->getIP(), 'timestamp' => $request->getTimestamp(), 'headers' => $headerString, 'url' => $request->getProtocol() . '://' . $request->getHost() . $request->getPath(), 'home_url' => $waf->getStorageEngine()->getConfig('homeURL', '', 'synced'));
$payloadJSON = wfWAFUtils::json_encode($payload);
$shouldEncrypt = false;
if (function_exists('openssl_get_publickey') && function_exists('openssl_get_cipher_methods')) {
$ciphers = openssl_get_cipher_methods();
$shouldEncrypt = array_search('aes-256-cbc', $ciphers) !== false;
}
if ($shouldEncrypt) {
$keyData = file_get_contents(dirname(__FILE__) . '/../falsepositive.key');
$key = @openssl_get_publickey($keyData);
if ($key !== false) {
$symmetricKey = wfWAFUtils::random_bytes(32);
$iv = wfWAFUtils::random_bytes(16);
$encrypted = @openssl_encrypt($payloadJSON, 'aes-256-cbc', $symmetricKey, OPENSSL_RAW_DATA, $iv);
if ($encrypted !== false) {
$success = openssl_public_encrypt($symmetricKey, $symmetricKeyEncrypted, $key, OPENSSL_PKCS1_OAEP_PADDING);
if ($success) {
$message = $iv . $symmetricKeyEncrypted . $encrypted;
$signatureRaw = hash('sha256', $message, true);
$success = openssl_public_encrypt($signatureRaw, $signature, $key, OPENSSL_PKCS1_OAEP_PADDING);
if ($success) {
$payload = array('message' => bin2hex($message), 'signature' => bin2hex($signature));
$payloadJSON = wfWAFUtils::json_encode($payload);
}
}
}
}
}
$message = base64_encode($payloadJSON);
$payload = "-----BEGIN REPORT-----\n" . implode("\n", str_split($message, 60)) . "\n-----END REPORT-----";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php wfWAFI18n::esc_html_e('403 Forbidden') ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
background-color: #fff;
}
h1, h2, h3, h4, h45, h6 {
font-weight: 500;
line-height: 1.1;
}
h1 { font-size: 36px; }
h2 { font-size: 30px; }
h3 { font-size: 24px; }
h4 { font-size: 18px; }
h5 { font-size: 14px; }
h6 { font-size: 12px; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.btn {
background-color: #00709e;
border: 1px solid #09486C;
border-radius: 4px;
box-sizing: border-box;
color: #ffffff;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: normal;
letter-spacing: normal;
line-height: 20px;
margin: 5px 0px;
padding: 12px 6px;
text-align: center;
text-decoration: none;
vertical-align: middle;
white-space: nowrap;
word-spacing: 0px;
}
textarea {
display: block;
height: 48px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
font-family: monospace;
}
textarea:focus {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6);
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee
}
.btn.disabled, .btn[disabled] {
background-color: #9f9fa0;
border: 1px solid #7E7E7F;
cursor: not-allowed;
filter: alpha(opacity=65);
-webkit-box-shadow: none;
box-shadow: none;
opacity: .65;
pointer-events: none;
}
</style>
</head>
<body>
<?php
if (!empty($errorNonce)) { echo '<!-- WFWAF NONCE: ' . htmlentities($errorNonce) . ' -->'; }
?>
<h1><?php wfWAFI18n::esc_html_e('403 Forbidden') ?></h1>
<h3><?php wfWAFI18n::esc_html_e('WHAT? Why am I seeing this?') ?></h3>
<p><?php wfWAFI18n::esc_html_e('Your access to this site was blocked by Wordfence, a security provider, who protects sites from malicious activity.') ?></p>
<p><?php wfWAFI18n::esc_html_e('If you believe Wordfence should be allowing you access to this site, please let them know using the steps below so they can investigate why this is happening.') ?></p>
<hr>
<h3><?php wfWAFI18n::esc_html_e('Reporting a Problem') ?></h3>
<h4><?php wfWAFI18n::esc_html_e('1. Please copy this text. You need to paste it into a form later.') ?></h4>
<p><textarea id="payload" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" cols="65"><?php echo htmlspecialchars($payload); ?></textarea></p>
<script type="application/javascript">
(function() {
var textarea = document.getElementById('payload');
var cs = window.getComputedStyle(textarea);
var lines = textarea.value.split('\n');
var height = 1 + lines.length;
var pixelHeight = Math.min(height * parseInt(cs.getPropertyValue('line-height')), 600);
textarea.style.height = pixelHeight + 'px';
textarea.addEventListener('focus', function() {
document.getElementById('reportButton').className = document.getElementById('reportButton').className.replace(new RegExp('(?:^|\\s)'+ 'disabled' + '(?:\\s|$)'), ' ');
document.getElementById('reportButton').href = 'ht' + 'tps:/' + '/user-reports.wordfence' + '.com';
});
})();
</script>
<h4><?php wfWAFI18n::esc_html_e('2. Click this button and you will be prompted to paste the text above.') ?></h4>
<p><a href="#" id="reportButton" class="btn disabled" target="_blank" rel="noopener noreferrer"><?php wfWAFI18n::esc_html_e('Report Problem') ?></a></p>
<p style="color: #999999;margin-top: 2rem;"><em><?php printf(wfWAFI18n::esc_html__('Generated by Wordfence at %s.'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())) ?><br><?php wfWAFI18n::esc_html_e('Your computer\'s time: ') ?><script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</body>
</html>

View File

@@ -0,0 +1,450 @@
<?php
if (!defined('WFWAF_VIEW_RENDERING')) { exit; }
/** @var wfWAF $waf */
/** @var wfWAFView $this */
/*
* IMPORTANT:
*
* If the form variables below change name or format, admin.ajaxWatcher.js in the main plugin also needs changed. It
* processes these to generate its whitelist button.
*/
$method = wfWAFUtils::strtolower($waf->getRequest()->getMethod());
$urlParamsToWhitelist = array();
foreach ($waf->getFailedRules() as $paramKey => $categories) {
foreach ($categories as $category => $failedRules) {
foreach ($failedRules as $failedRule) {
/**
* @var wfWAFRule $rule
* @var wfWAFRuleComparisonFailure $failedComparison
*/
$rule = $failedRule['rule'];
$failedComparison = $failedRule['failedComparison'];
$urlParamsToWhitelist[] = array(
'path' => $waf->getRequest()->getPath(),
'paramKey' => $failedComparison->getParamKey(),
'ruleID' => $rule->getRuleID(),
);
}
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?php wfWAFI18n::esc_html_e('403 Forbidden') ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
</style>
</head>
<body>
<?php if (!empty($errorNonce)) { echo '<!-- WFWAF NONCE: ' . htmlspecialchars($errorNonce) . ' -->'; } ?>
<div class="top-accent"></div>
<div class="container">
<h1><?php wfWAFI18n::esc_html_e('A potentially unsafe operation has been detected in your request to this site') ?></h1>
<p><?php wfWAFI18n::esc_html_e('Your access to this service has been limited. (HTTP response code 403)') ?></p>
<p><?php wfWAFI18n::esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.') ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<?php if ($urlParamsToWhitelist): ?>
<hr>
<p><?php wfWAFI18n::esc_html_e('If you are an administrator and you are certain this is a false positive, you can automatically allowlist this request and repeat the same action.') ?></p>
<form id="whitelist-form" action="<?php echo htmlentities($waf->getRequest()->getPath(), ENT_QUOTES, 'utf-8') ?>" method="post">
<input type="hidden" name="wfwaf-false-positive-params" value="<?php echo htmlentities(wfWAFUtils::json_encode($urlParamsToWhitelist), ENT_QUOTES, 'utf-8') ?>">
<input type="hidden" name="wfwaf-false-positive-nonce" value="<?php echo htmlentities($waf->getAuthCookieValue('nonce', ''), ENT_QUOTES, 'utf-8') ?>">
<div id="whitelist-actions">
<p><label><input id="verified-false-positive-checkbox" type="checkbox" name="wfwaf-false-positive-verified" value="1"> <em><?php wfWAFI18n::esc_html_e('I am certain this is a false positive.') ?></em></label></p>
<p><button id="whitelist-button" type="submit"><?php wfWAFI18n::esc_html_e('Allowlist This Action') ?></button></p>
</div>
<p id="success" style="color: #35b13a; font-weight: bold; display: none"><em><?php wfWAFI18n::esc_html_e('All set! You can refresh the page to try this action again.') ?></em></p>
<p id="error" style="color: #dd422c; font-weight: bold; display: none"><em><?php wfWAFI18n::esc_html_e('Something went wrong allowlisting this request. You can try setting the Firewall Status to Learning Mode under Web Application Firewall in the Wordfence menu, and retry this same action.') ?></em></p>
</form>
<script>
var whitelistButton = document.getElementById('whitelist-button');
var verified = document.getElementById('verified-false-positive-checkbox');
verified.checked = false;
verified.onclick = function() {
whitelistButton.disabled = !this.checked;
};
verified.onclick();
document.getElementById('whitelist-form').onsubmit = function(evt) {
evt.preventDefault();
var request = new XMLHttpRequest();
request.addEventListener("load", function() {
if (this.status === 200 && this.responseText.indexOf('Successfully allowlisted') > -1) {
document.getElementById('whitelist-actions').style.display = 'none';
document.getElementById('success').style.display = 'block';
} else {
document.getElementById('error').style.display = 'block';
}
});
request.open("POST", this.action, true);
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
var inputs = this.querySelectorAll('input[name]');
var data = '';
for (var i = 0; i < inputs.length; i++) {
data += encodeURIComponent(inputs[i].name) + '=' + encodeURIComponent(inputs[i].value) + '&';
}
request.send(data);
return false;
};
</script>
<hr>
<?php endif ?>
<h2 class="h3"><?php wfWAFI18n::esc_html_e('Block Technical Data') ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php wfWAFI18n::esc_html_e('Block Reason:') ?></th>
<td class="reason"><?php wfWAFI18n::esc_html_e('A potentially unsafe operation has been detected in your request to this site') ?></td>
</tr>
<tr>
<th class="time"><?php wfWAFI18n::esc_html_e('Time:') ?></th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(dirname(__FILE__) . '/../../../../../images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php wfWAFI18n::esc_html_e('About Wordfence') ?></h3>
<p><?php wfWAFI18n::esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.') ?></p>
<p><?php wfWAFI18n::esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.') ?></p>
</div>
</div>
<p class="documentation small"><?php wfWAFI18n::esc_html_e('Click here to learn more: '); ?><a href="https://www.wordfence.com/help/?query=locked-out" target="_blank" rel="noopener noreferrer"><?php wfWAFI18n::esc_html_e('Documentation') ?></a></p>
<p class="generated small"><em><?php printf(wfWAFI18n::esc_html__('Generated by Wordfence at %s.'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())) ?><br><?php wfWAFI18n::esc_html_e('Your computer\'s time: ') ?><script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,365 @@
<?php
if (!defined('WFWAF_VIEW_RENDERING')) { exit; }
?>
<!DOCTYPE html>
<html>
<head>
<title><?php wfWAFI18n::esc_html_e('403 Forbidden') ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
</style>
</head>
<body>
<?php if (!empty($errorNonce)) { echo '<!-- WFWAF NONCE: ' . htmlspecialchars($errorNonce) . ' -->'; } ?>
<div class="top-accent"></div>
<div class="container">
<h1><?php wfWAFI18n::esc_html_e('A potentially unsafe operation has been detected in your request to this site') ?></h1>
<p><?php wfWAFI18n::esc_html_e('Your access to this service has been limited. (HTTP response code 403)') ?></p>
<p><?php wfWAFI18n::esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.') ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<h2 class="h3"><?php wfWAFI18n::esc_html_e('Block Technical Data') ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php wfWAFI18n::esc_html_e('Block Reason:') ?></th>
<td class="reason"><?php wfWAFI18n::esc_html_e('A potentially unsafe operation has been detected in your request to this site') ?></td>
</tr>
<tr>
<th class="time"><?php wfWAFI18n::esc_html_e('Time:') ?></th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(dirname(__FILE__) . '/../../../../../images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php wfWAFI18n::esc_html_e('About Wordfence') ?></h3>
<p><?php wfWAFI18n::esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.') ?></p>
<p><?php wfWAFI18n::esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.') ?></p>
</div>
</div>
<p class="documentation small"><?php wfWAFI18n::esc_html_e('Click here to learn more: ') ?><a href="https://www.wordfence.com/help/?query=locked-out" target="_blank" rel="noopener noreferrer"><?php wfWAFI18n::esc_html_e('Documentation'); ?></a></p>
<p class="generated small"><em><?php printf(wfWAFI18n::esc_html__('Generated by Wordfence at %s.'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?><br><?php wfWAFI18n::esc_html_e('Your computer\'s time: ') ?><script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,392 @@
<?php
if (!defined('WFWAF_VIEW_RENDERING')) { exit; }
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php wfWAFI18n::esc_html_e('Your access to this site has been limited by the site owner') ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
</style>
</head>
<body>
<?php if (!empty($errorNonce)) { echo '<!-- WFWAF NONCE: ' . htmlspecialchars($errorNonce) . ' -->'; } ?>
<div class="top-accent"></div>
<div class="container">
<h1><?php wfWAFI18n::esc_html_e('Your access to this site has been temporarily limited by the site owner') ?></h1>
<p><?php wfWAFI18n::esc_html_e('Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)') ?></p>
<p><?php wfWAFI18n::esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.') ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<?php if (!empty($homeURL)): ?>
<hr>
<ul>
<li><a href="<?php echo $homeURL; ?>"><?php wfWAFI18n::esc_html_e('Return to the site home page') ?></a></li>
</ul>
<?php
endif;
$nonce = $waf->createNonce('wf-form');
if (!empty($siteURL) && !empty($nonce)) : ?>
<hr>
<p class="medium"><?php wfWAFI18n::esc_html_e('If you are a WordPress user with administrative privileges on this site, please enter your email address in the box below and click "Send". You will then receive an email that helps you regain access.') ?></p>
<form method="POST" id="unlock-form" action="#">
<input type="hidden" name="nonce" value="<?php echo $nonce; ?>">
<input type="text" size="50" name="email" id="unlock-email" value="" maxlength="255" placeholder="email@example.com">&nbsp;&nbsp;<input type="submit" class="wf-btn wf-btn-default" id="unlock-submit" name="s" value="<?php wfWAFI18n::esc_html_e('Send Unlock Email') ?>" disabled>
</form>
<script type="application/javascript">
(function() {
var textfield = document.getElementById('unlock-email');
textfield.addEventListener('focus', function() {
document.getElementById('unlock-form').action = "<?php echo rtrim($siteURL, '/') . '/'; ?>" + "?_wfsf=unlockEmail";
document.getElementById('unlock-submit').disabled = false;
});
})();
</script>
<?php endif; ?>
<h2 class="h3"><?php wfWAFI18n::esc_html_e('Block Technical Data') ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php wfWAFI18n::esc_html_e('Block Reason:') ?></th>
<td class="reason"><?php wfWAFI18n::esc_html_e('You have been temporarily locked out of this system. This means that you will not be able to log in for a while.') ?></td>
</tr>
<tr>
<th class="time"><?php wfWAFI18n::esc_html_e('Time:') ?></th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(dirname(__FILE__) . '/../../../../../images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php wfWAFI18n::esc_html_e('About Wordfence') ?></h3>
<p><?php wfWAFI18n::esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.') ?></p>
<p><?php wfWAFI18n::esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.') ?></p>
</div>
</div>
<p class="documentation small"><?php wfWAFI18n::esc_html_e('Click here to learn more: '); ?><a href="https://www.wordfence.com/help/?query=locked-out" target="_blank" rel="noopener noreferrer"><?php wfWAFI18n::esc_html_e('Documentation'); ?></a></p>
<p class="generated small"><em><?php printf(wfWAFI18n::esc_html__('Generated by Wordfence at %s.'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())) ?><br><?php wfWAFI18n::esc_html_e('Your computer\'s time: ') ?><script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,386 @@
<?php
if (!defined('WFWAF_VIEW_RENDERING')) { exit; }
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php wfWAFI18n::esc_html_e('Your access to this site has been limited by the site owner') ?></title>
<style>
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.875rem;
line-height: 1.42857143;
color: #333;
background-color: #fff;
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
}
a {
color:#00709e;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 200;
line-height: 1.1;
}
h1, .h1 { font-size: 3rem; }
h2, .h2 { font-size: 2.5rem; }
h3, .h3 { font-size: 1.5rem; }
h4, .h4 { font-size: 1rem; }
h5, .h5 { font-size: 0.875rem; }
h6, .h6 { font-size: 0.75rem; }
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4, h5, h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.wf-btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
text-transform: uppercase;
padding: .4rem 1rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
@media (min-width: 768px) {
.wf-btn {
padding: .5rem 1.25rem;
font-size: .875rem;
line-height: 1.3125rem;
border-radius: 4px
}
}
.wf-btn:focus,
.wf-btn.wf-focus,
.wf-btn:active:focus,
.wf-btn:active.wf-focus,
.wf-btn.wf-active:focus,
.wf-btn.wf-active.wf-focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px
}
.wf-btn:hover,
.wf-btn:focus,
.wf-btn.wf-focus {
color: #00709e;
text-decoration: none
}
.wf-btn:active,
.wf-btn.wf-active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.wf-btn.wf-disabled,
.wf-btn[disabled],
.wf-btn[readonly],
fieldset[disabled] .wf-btn {
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none
}
a.wf-btn {
text-decoration: none
}
a.wf-btn.wf-disabled,
fieldset[disabled] a.wf-btn {
cursor: not-allowed;
pointer-events: none
}
.wf-btn-default {
color: #00709e;
background-color: #fff;
border-color: #00709e
}
.wf-btn-default:focus,
.wf-btn-default.focus {
color: #00709e;
background-color: #e6e6e6;
border-color: #00161f
}
.wf-btn-default:hover {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active,
.wf-btn-default.active {
color: #00709e;
background-color: #e6e6e6;
border-color: #004561
}
.wf-btn-default:active:hover,
.wf-btn-default:active:focus,
.wf-btn-default:active.focus,
.wf-btn-default.active:hover,
.wf-btn-default.active:focus,
.wf-btn-default.active.focus {
color: #00709e;
background-color: #d4d4d4;
border-color: #00161f
}
.wf-btn-default:active,
.wf-btn-default.wf-active {
background-image: none
}
.wf-btn-default.wf-disabled,
.wf-btn-default[disabled],
.wf-btn-default[readonly],
fieldset[disabled] .wf-btn-default {
color: #777;
background-color: #fff;
border-color: #e2e2e2;
cursor: not-allowed
}
.wf-btn-default.wf-disabled:hover,
.wf-btn-default.wf-disabled:focus,
.wf-btn-default.wf-disabled.wf-focus,
.wf-btn-default[disabled]:hover,
.wf-btn-default[disabled]:focus,
.wf-btn-default[disabled].wf-focus,
.wf-btn-default[readonly]:hover,
.wf-btn-default[readonly]:focus,
.wf-btn-default[readonly].wf-focus,
fieldset[disabled] .wf-btn-default:hover,
fieldset[disabled] .wf-btn-default:focus,
fieldset[disabled] .wf-btn-default.wf-focus {
background-color: #fff;
border-color: #00709e
}
input[type="text"], input.wf-input-text {
text-align: left;
max-width: 200px;
height: 30px;
border-radius: 0;
border: 0;
background-color: #ffffff;
box-shadow: 0px 0px 0px 1px rgba(215,215,215,0.65);
padding: 0.25rem;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 4px solid #eee
}
p {
font-size: 1.4rem;
font-weight: 300;
}
p.medium, div.medium p {
font-size: 1.1rem;
}
p.small, div.small p {
font-size: 1rem;
}
.container {
max-width: 900px;
padding: 0 1rem;
margin: 0 auto;
}
.top-accent {
height: 25px;
background-color: #00709e;
}
.block-data {
width: 100%;
border-top: 6px solid #00709e;
}
.block-data tr:nth-child(odd) th, .block-data tr:nth-child(odd) td {
background-color: #eeeeee;
}
.block-data th, .block-data td {
text-align: left;
padding: 1rem;
font-size: 1.1rem;
}
.block-data th.reason, .block-data td.reason {
color: #930000;
}
.block-data th {
font-weight: 300;
}
.block-data td {
font-weight: 500;
}
.about {
margin-top: 2rem;
display: flex;
flex-direction: row;
align-items: stretch;
}
.about .badge {
flex-basis: 116px;
flex-grow: 0;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.about svg {
width: 100px;
height: 100px;
}
.about-text {
background-color: #00709e;
color: #ffffff;
padding: 1rem;
}
.about-text .h4 {
font-weight: 500;
margin-top: 0;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.about-text p {
font-size: 0.875rem;
font-weight: 200;
margin-top: 0.3rem;
margin-bottom: 0.3rem;
}
.about-text p:first-of-type {
margin-top: 0;
}
.about-text p:last-of-type {
margin-bottom: 0;
}
.st0{fill:#00709e;}
.st1{fill:#FFFFFF;}
.generated {
color: #999999;
margin-top: 2rem;
}
</style>
</head>
<body>
<?php if (!empty($errorNonce)) { echo '<!-- WFWAF NONCE: ' . htmlspecialchars($errorNonce) . ' -->'; } ?>
<div class="top-accent"></div>
<div class="container">
<h1><?php wfWAFI18n::esc_html_e('Your access to this site has been limited by the site owner') ?></h1>
<p><?php wfWAFI18n::esc_html_e('Your access to this service has been limited. (HTTP response code 503)') ?></p>
<p><?php wfWAFI18n::esc_html_e('If you think you have been blocked in error, contact the owner of this site for assistance.') ?></p>
<?php if (!empty($customText)): ?>
<hr>
<div class="medium"><?php echo $customText; ?></div>
<?php endif; ?>
<?php
$nonce = $waf->createNonce('wf-form');
if (!empty($siteURL) && !empty($nonce)) : ?>
<hr>
<p class="medium"><?php wfWAFI18n::esc_html_e('If you are a WordPress user with administrative privileges on this site, please enter your email address in the box below and click "Send". You will then receive an email that helps you regain access.') ?></p>
<form method="POST" id="unlock-form" action="#">
<input type="hidden" name="nonce" value="<?php echo $nonce; ?>">
<input type="text" size="50" name="email" id="unlock-email" value="" maxlength="255" placeholder="email@example.com">&nbsp;&nbsp;<input type="submit" class="wf-btn wf-btn-default" id="unlock-submit" name="s" value="<?php echo htmlentities(wfWAFI18n::esc_html__('Send Unlock Email'), ENT_QUOTES, 'utf-8') ?>" disabled>
</form>
<script type="application/javascript">
(function() {
var textfield = document.getElementById('unlock-email');
textfield.addEventListener('focus', function() {
document.getElementById('unlock-form').action = "<?php echo rtrim($siteURL, '/') . '/'; ?>" + "?_wfsf=unlockEmail";
document.getElementById('unlock-submit').disabled = false;
});
})();
</script>
<?php endif; ?>
<h2 class="h3"><?php wfWAFI18n::esc_html_e('Block Technical Data') ?></h2>
<table border="0" cellspacing="0" cellpadding="0" class="block-data">
<tr>
<th class="reason"><?php wfWAFI18n::esc_html_e('Block Reason:') ?></th>
<td class="reason"><?php echo htmlspecialchars($reason); ?></td>
</tr>
<tr>
<th class="time"><?php wfWAFI18n::esc_html_e('Time:') ?></th>
<td class="time"><?php echo htmlspecialchars(gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())); ?></td>
</tr>
</table>
<div class="about">
<div class="badge">
<?php
$contents = file_get_contents(dirname(__FILE__) . '/../../../../../images/wf-error-badge.svg');
$contents = preg_replace('/^<\?xml.+?\?>\s*/i', '', $contents);
$contents = preg_replace('/^<!DOCTYPE.+?>\s*/i', '', $contents);
$contents = preg_replace('/<svg\s+xmlns="[^"]*"/i', '<svg', $contents);
echo $contents;
?>
</div>
<div class="about-text">
<h3 class="h4"><?php wfWAFI18n::esc_html_e('About Wordfence') ?></h3>
<p><?php wfWAFI18n::esc_html_e('Wordfence is a security plugin installed on over 4 million WordPress sites. The owner of this site is using Wordfence to manage access to their site.') ?></p>
<p><?php wfWAFI18n::esc_html_e('You can also read the documentation to learn about Wordfence\'s blocking tools, or visit wordfence.com to learn more about Wordfence.') ?></p>
</div>
</div>
<p class="documentation small"><?php wfWAFI18n::esc_html_e('Click here to learn more: '); ?><a href="https://www.wordfence.com/help/?query=locked-out" target="_blank" rel="noopener noreferrer"><?php wfWAFI18n::esc_html_e('Documentation'); ?></a></p>
<p class="generated small"><em><?php printf(wfWAFI18n::esc_html__('Generated by Wordfence at %s.'), gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime())) ?><br><?php wfWAFI18n::esc_html_e('Your computer\'s time: ') ?><script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
</div>
</body>
</html>