Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4139328
Throttle.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
Throttle.php
View Options
<?php
namespace
MediaWiki\Extension\AbuseFilter\Consequences\Consequence
;
use
InvalidArgumentException
;
use
MediaWiki\Extension\AbuseFilter\Consequences\ConsequenceNotPrecheckedException
;
use
MediaWiki\Extension\AbuseFilter\Consequences\Parameters
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\UserEditTracker
;
use
MediaWiki\User\UserFactory
;
use
Psr\Log\LoggerInterface
;
use
Wikimedia\IPUtils
;
use
Wikimedia\ObjectCache\BagOStuff
;
/**
* Consequence that delays executing other actions until certain conditions are met
*/
class
Throttle
extends
Consequence
implements
ConsequencesDisablerConsequence
{
/** @var array */
private
$throttleParams
;
/** @var BagOStuff */
private
$mainStash
;
/** @var UserEditTracker */
private
$userEditTracker
;
/** @var UserFactory */
private
$userFactory
;
/** @var LoggerInterface */
private
$logger
;
/** @var bool */
private
$filterIsCentral
;
/** @var string|null */
private
$centralDB
;
/** @var bool|null */
private
$hitThrottle
;
private
const
IPV4_RANGE
=
'16'
;
private
const
IPV6_RANGE
=
'64'
;
/**
* @param Parameters $parameters
* @param array $throttleParams
* @phan-param array{groups:string[],id:int|string,count:int,period:int} $throttleParams
* @param BagOStuff $mainStash
* @param UserEditTracker $userEditTracker
* @param UserFactory $userFactory
* @param LoggerInterface $logger
* @param bool $filterIsCentral
* @param string|null $centralDB
*/
public
function
__construct
(
Parameters
$parameters
,
array
$throttleParams
,
BagOStuff
$mainStash
,
UserEditTracker
$userEditTracker
,
UserFactory
$userFactory
,
LoggerInterface
$logger
,
bool
$filterIsCentral
,
?
string
$centralDB
)
{
parent
::
__construct
(
$parameters
);
$this
->
throttleParams
=
$throttleParams
;
$this
->
mainStash
=
$mainStash
;
$this
->
userEditTracker
=
$userEditTracker
;
$this
->
userFactory
=
$userFactory
;
$this
->
logger
=
$logger
;
$this
->
filterIsCentral
=
$filterIsCentral
;
$this
->
centralDB
=
$centralDB
;
}
/**
* @return bool Whether the throttling took place (i.e. the limit was NOT hit)
* @throws ConsequenceNotPrecheckedException
*/
public
function
execute
():
bool
{
if
(
$this
->
hitThrottle
===
null
)
{
throw
new
ConsequenceNotPrecheckedException
();
}
foreach
(
$this
->
throttleParams
[
'groups'
]
as
$throttleType
)
{
$this
->
setThrottled
(
$throttleType
);
}
return
!
$this
->
hitThrottle
;
}
/**
* @inheritDoc
*/
public
function
shouldDisableOtherConsequences
():
bool
{
$this
->
hitThrottle
=
false
;
foreach
(
$this
->
throttleParams
[
'groups'
]
as
$throttleType
)
{
$this
->
hitThrottle
=
$this
->
isThrottled
(
$throttleType
)
||
$this
->
hitThrottle
;
}
return
!
$this
->
hitThrottle
;
}
/**
* @inheritDoc
*/
public
function
getSort
():
int
{
return
0
;
}
/**
* Determines whether the throttle has been hit with the given parameters
* @note If caching is disabled, get() will return false, so the throttle count will never be reached (if >0).
* This means that filters with 'throttle' enabled won't ever trigger any consequence.
*
* @param string $types
* @return bool
*/
private
function
isThrottled
(
string
$types
):
bool
{
$key
=
$this
->
throttleKey
(
$types
);
$newCount
=
(
int
)
$this
->
mainStash
->
get
(
$key
)
+
1
;
$this
->
logger
->
debug
(
'New value is {newCount} for throttle key {key}. Maximum is {rateCount}.'
,
[
'newCount'
=>
$newCount
,
'key'
=>
$key
,
'rateCount'
=>
$this
->
throttleParams
[
'count'
],
]
);
return
$newCount
>
$this
->
throttleParams
[
'count'
];
}
/**
* Updates the throttle status with the given parameters
*
* @param string $types
*/
private
function
setThrottled
(
string
$types
):
void
{
$key
=
$this
->
throttleKey
(
$types
);
$this
->
logger
->
debug
(
'Increasing throttle key {key}'
,
[
'key'
=>
$key
]
);
$this
->
mainStash
->
incrWithInit
(
$key
,
$this
->
throttleParams
[
'period'
]
);
}
/**
* @param string $type
* @return string
*/
private
function
throttleKey
(
string
$type
):
string
{
$types
=
explode
(
','
,
$type
);
$identifiers
=
[];
foreach
(
$types
as
$subtype
)
{
$identifiers
[]
=
$this
->
throttleIdentifier
(
$subtype
);
}
$identifier
=
sha1
(
implode
(
':'
,
$identifiers
)
);
if
(
$this
->
parameters
->
getIsGlobalFilter
()
&&
!
$this
->
filterIsCentral
)
{
return
$this
->
mainStash
->
makeGlobalKey
(
'abusefilter'
,
'throttle'
,
$this
->
centralDB
,
$this
->
throttleParams
[
'id'
],
$identifier
);
}
return
$this
->
mainStash
->
makeKey
(
'abusefilter'
,
'throttle'
,
$this
->
throttleParams
[
'id'
],
$identifier
);
}
/**
* @param string $type
* @return string
*/
private
function
throttleIdentifier
(
string
$type
):
string
{
$user
=
$this
->
parameters
->
getUser
();
switch
(
$type
)
{
case
'ip'
:
$identifier
=
$this
->
parameters
->
getActionSpecifier
()->
getIP
();
break
;
case
'user'
:
// NOTE: This is always 0 for anons. Is this good/wanted?
$identifier
=
$user
->
getId
();
break
;
case
'range'
:
$requestIP
=
$this
->
parameters
->
getActionSpecifier
()->
getIP
();
$range
=
IPUtils
::
isIPv6
(
$requestIP
)
?
self
::
IPV6_RANGE
:
self
::
IPV4_RANGE
;
$identifier
=
IPUtils
::
sanitizeRange
(
"{$requestIP}/$range"
);
break
;
case
'creationdate'
:
// TODO Inject a proper service, not UserFactory, once getRegistration is moved away from User
$reg
=
(
int
)
$this
->
userFactory
->
newFromUserIdentity
(
$user
)->
getRegistration
();
$identifier
=
$reg
-
(
$reg
%
86400
);
break
;
case
'editcount'
:
// Hack for detecting different single-purpose accounts.
$identifier
=
$this
->
userEditTracker
->
getUserEditCount
(
$user
)
?:
0
;
break
;
case
'site'
:
$identifier
=
1
;
break
;
case
'page'
:
$title
=
Title
::
castFromLinkTarget
(
$this
->
parameters
->
getTarget
()
);
// TODO Replace with something from LinkTarget, e.g. namespace + text
$identifier
=
$title
->
getPrefixedText
();
break
;
default
:
// Should never happen
throw
new
InvalidArgumentException
(
"Invalid throttle type $type."
);
}
return
"$type-$identifier"
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Wed, Aug 19, 15:01 (3 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2c/ac/a22bb6f33bd7254d2fa3349c53eb
Default Alt Text
Throttle.php (5 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment