92 $this->logger = LoggerFactory::getInstance(
'ratelimit' );
95 $this->options = $options;
96 $this->wrstatsFactory = $wrstatsFactory;
97 $this->centralIdLookup = $centralIdLookup;
98 $this->userFactory = $userFactory;
99 $this->userGroupManager = $userGroupManager;
100 $this->hookRunner =
new HookRunner( $hookContainer );
142 $ip = $subject->
getIP();
146 $legacyUser = $this->userFactory->newFromUserIdentity( $user );
147 if ( !$this->hookRunner->onPingLimiter( $legacyUser, $action, $result, $incrBy ) ) {
151 if ( !isset( $this->rateLimits[$action] ) ) {
156 if ( $this->canBypass( $action ) && $this->
isExempt( $subject ) ) {
160 $conds = $this->getConditions( $action );
161 $limiter = $this->wrstatsFactory->createRateLimiter( $conds, [
'limiter', $action ] );
162 $peekMode = $incrBy === 0;
163 $limitBatch = $limiter->createBatch( $incrBy ?: 1 );
164 $this->logger->debug( __METHOD__ .
": limiting $action rate for {$user->getName()}" );
166 $id = $user->getId();
167 $isNewbie = $subject->
is( RateLimitSubject::NEWBIE );
171 if ( isset( $conds[
'anon'] ) ) {
172 $limitBatch->localOp(
'anon', [] );
176 if ( isset( $conds[
'user-global'] ) ) {
178 $centralId = $this->centralIdLookup
184 $realm = $this->centralIdLookup->getProviderId();
185 $limitBatch->globalOp(
'user-global', [ $realm, $centralId ] );
188 $limitBatch->localOp(
'user-global', [
'local', $id ] );
193 if ( $isNewbie && $ip ) {
195 if ( isset( $conds[
'ip'] ) ) {
196 $limitBatch->globalOp(
'ip', $ip );
199 if ( isset( $conds[
'subnet'] ) ) {
200 $subnet = IPUtils::getSubnet( $ip );
201 if ( $subnet !==
false ) {
202 $limitBatch->globalOp(
'subnet', $subnet );
208 $userEntityType =
false;
209 if ( $id !== 0 && isset( $conds[
'user'] ) ) {
211 $userEntityType =
'user';
214 if ( $id !== 0 && $isNewbie && isset( $conds[
'newbie'] ) ) {
215 $userEntityType =
'newbie';
219 $userGroups = $this->userGroupManager->getUserGroups( $user );
220 foreach ( $userGroups as $group ) {
221 if ( isset( $conds[$group] ) ) {
222 if ( $userEntityType ===
false
223 || $conds[$group]->perSecond() > $conds[$userEntityType]->perSecond()
225 $userEntityType = $group;
232 if ( $userEntityType !==
false ) {
233 $limitBatch->localOp( $userEntityType, $id );
237 if ( isset( $conds[
'ip-all'] ) && $ip ) {
239 if ( $isNewbie || $userEntityType ===
false
240 || $conds[
'ip-all']->perSecond() > $conds[$userEntityType]->perSecond()
242 $limitBatch->globalOp(
'ip-all', $ip );
247 if ( isset( $conds[
'subnet-all'] ) && $ip ) {
248 $subnet = IPUtils::getSubnet( $ip );
249 if ( $subnet !==
false ) {
251 if ( $isNewbie || $userEntityType ===
false
252 || $conds[
'ip-all']->perSecond() > $conds[$userEntityType]->perSecond()
254 $limitBatch->globalOp(
'subnet-all', $subnet );
260 'name' => $user->getName(),
264 $batchResult = $peekMode ? $limitBatch->peek() : $limitBatch->tryIncr();
265 foreach ( $batchResult->getFailedResults() as
$type => $result ) {
267 'User::pingLimiter: User tripped rate limit',
270 'limit' => $result->condition->limit,
271 'period' => $result->condition->window,
272 'count' => $result->prevTotal,
278 return !$batchResult->isAllowed();