Merge branch 'api-ip-exempt' of https://github.com/rodehoed/PrivateBin into rodehoed-api-ip-exempt

This commit is contained in:
El RIDO 2021-05-22 08:39:53 +02:00
commit 194b27e685
No known key found for this signature in database
GPG key ID: 0F5C940A6BD81F92
5 changed files with 143 additions and 6 deletions

View file

@ -135,6 +135,10 @@ markdown = "Markdown"
; Set this to 0 to disable rate limiting. ; Set this to 0 to disable rate limiting.
limit = 10 limit = 10
; Set ips (v4|v6) which should be exempted for the rate-limit. CIDR also supported. Needed to be comma separated.
; Unset for enabling and invalid values will be ignored
; eg: exemptedIp = '1.2.3.4,10.10.10/24'
; (optional) if your website runs behind a reverse proxy or load balancer, ; (optional) if your website runs behind a reverse proxy or load balancer,
; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR ; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
; header = "X_FORWARDED_FOR" ; header = "X_FORWARDED_FOR"

View file

@ -26,7 +26,8 @@
"require" : { "require" : {
"php" : "^5.6.0 || ^7.0 || ^8.0", "php" : "^5.6.0 || ^7.0 || ^8.0",
"paragonie/random_compat" : "2.0.19", "paragonie/random_compat" : "2.0.19",
"yzalis/identicon" : "2.0.0" "yzalis/identicon" : "2.0.0",
"mlocati/ip-lib": "^1.14"
}, },
"require-dev" : { "require-dev" : {
"phpunit/phpunit" : "^4.6 || ^5.0" "phpunit/phpunit" : "^4.6 || ^5.0"

70
composer.lock generated
View file

@ -4,8 +4,76 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9d110873bf15a6abd66734e8a818134c", "content-hash": "8138b0e4bb3fcaab9ca4c02bbe35d891",
"packages": [ "packages": [
{
"name": "mlocati/ip-lib",
"version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/mlocati/ip-lib.git",
"reference": "882bc0e115970a536b13bcfa59f312783fce08c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/882bc0e115970a536b13bcfa59f312783fce08c8",
"reference": "882bc0e115970a536b13bcfa59f312783fce08c8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"phpunit/dbunit": "^1.4 || ^2 || ^3 || ^4",
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5"
},
"type": "library",
"autoload": {
"psr-4": {
"IPLib\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michele Locati",
"email": "mlocati@gmail.com",
"homepage": "https://github.com/mlocati",
"role": "Author"
}
],
"description": "Handle IPv4, IPv6 addresses and ranges",
"homepage": "https://github.com/mlocati/ip-lib",
"keywords": [
"IP",
"address",
"addresses",
"ipv4",
"ipv6",
"manage",
"managing",
"matching",
"network",
"networking",
"range",
"subnet"
],
"funding": [
{
"url": "https://github.com/sponsors/mlocati",
"type": "github"
},
{
"url": "https://paypal.me/mlocati",
"type": "other"
}
],
"time": "2020-12-31T11:30:02+00:00"
},
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v2.0.19", "version": "v2.0.19",

View file

@ -79,9 +79,10 @@ class Configuration
'markdown' => 'Markdown', 'markdown' => 'Markdown',
), ),
'traffic' => array( 'traffic' => array(
'limit' => 10, 'limit' => 10,
'header' => null, 'header' => null,
'dir' => 'data', 'dir' => 'data',
'exemptedIp' => null,
), ),
'purge' => array( 'purge' => array(
'limit' => 300, 'limit' => 300,

View file

@ -1,4 +1,5 @@
<?php <?php
/** /**
* PrivateBin * PrivateBin
* *
@ -30,6 +31,15 @@ class TrafficLimiter extends AbstractPersistence
*/ */
private static $_limit = 10; private static $_limit = 10;
/**
* listed ips are exempted from limits, defaults to null
*
* @access private
* @static
* @var array
*/
private static $_exemptedIp = null;
/** /**
* key to fetch IP address * key to fetch IP address
* *
@ -51,6 +61,18 @@ class TrafficLimiter extends AbstractPersistence
self::$_limit = $limit; self::$_limit = $limit;
} }
/**
* set a list of ip(ranges) as string
*
* @access public
* @static
* @param string $exemptedIps
*/
public static function setExemptedIp($exemptedIp)
{
self::$_exemptedIp = $exemptedIp;
}
/** /**
* set configuration options of the traffic limiter * set configuration options of the traffic limiter
* *
@ -62,6 +84,8 @@ class TrafficLimiter extends AbstractPersistence
{ {
self::setLimit($conf->getKey('limit', 'traffic')); self::setLimit($conf->getKey('limit', 'traffic'));
self::setPath($conf->getKey('dir', 'traffic')); self::setPath($conf->getKey('dir', 'traffic'));
self::setExemptedIp($conf->getKey('exemptedIp', 'traffic'));
if (($option = $conf->getKey('header', 'traffic')) !== null) { if (($option = $conf->getKey('header', 'traffic')) !== null) {
$httpHeader = 'HTTP_' . $option; $httpHeader = 'HTTP_' . $option;
if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) { if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) {
@ -83,6 +107,35 @@ class TrafficLimiter extends AbstractPersistence
return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get()); return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get());
} }
/**
* Validate $_ipKey against configured ipranges. If matched ratelimiter will ignore ip
*
* @access private
* @static
* @param string $ipRange
* @return bool
*/
private static function matchIp($ipRange = null)
{
// Match $_ipKey to $ipRange and if it matches it will return with a true
$address = \IPLib\Factory::addressFromString($_SERVER[self::$_ipKey]);
$range = \IPLib\Factory::rangeFromString(trim($ipRange));
// If $range is null something went wrong (possible invalid ip given in config). It's here becaue matches($range) does not accepts null vallue
if ($range == null) {
return false;
}
// Ip-lib does throws and exception when something goes wrong, if so we want to catch it and set contained to false
try {
return $address->matches($range);
} catch (\Exception $e) {
// If something is wrong with matching the ip, we do nothing
}
return false;
}
/** /**
* traffic limiter * traffic limiter
* *
@ -100,6 +153,16 @@ class TrafficLimiter extends AbstractPersistence
return true; return true;
} }
// Check if $_ipKey is exempted from ratelimiting
if (!is_null(self::$_exemptedIp)) {
$exIp_array = explode(',', self::$_exemptedIp);
foreach ($exIp_array as $ipRange) {
if (self::matchIp($ipRange) === true) {
return true;
}
}
}
$file = 'traffic_limiter.php'; $file = 'traffic_limiter.php';
if (self::_exists($file)) { if (self::_exists($file)) {
require self::getPath($file); require self::getPath($file);