Merge #1359
1359: Refactor the rate limiting code r=mergify[bot] a=kaiyou ## What type of PR? Enhancement ## What does this PR do? Rate limiting was already redesigned to use Python limits. This introduced some unexpected behavior, including the fact that only one criteria is supported per limiter. Docs and setup utility are updated with this in mind. Also, the code was made more generic, so limiters can be delivered for something else than authentication. Authentication-specific code was moved directly to the authentication routine. ### Related issue(s) No specific issue. ## Prerequistes Before we can consider review and merge, please make sure the following list is done and checked. If an entry in not applicable, you can check it or remove it from the list. - [x] In case of feature or enhancement: documentation updated accordingly - [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/guide.html#changelog) entry file. Co-authored-by: kaiyou <pierre@jaury.eu>master
commit
b8b1699f9e
@ -1,23 +1,7 @@
|
||||
from mailu.limiter import RateLimitExceeded
|
||||
|
||||
from mailu import utils
|
||||
from flask import current_app as app
|
||||
|
||||
import socket
|
||||
import flask
|
||||
|
||||
|
||||
internal = flask.Blueprint('internal', __name__, template_folder='templates')
|
||||
|
||||
|
||||
@internal.app_errorhandler(RateLimitExceeded)
|
||||
def rate_limit_handler(e):
|
||||
response = flask.Response()
|
||||
response.headers['Auth-Status'] = 'Authentication rate limit from one source exceeded'
|
||||
response.headers['Auth-Error-Code'] = '451 4.3.2'
|
||||
if int(flask.request.headers['Auth-Login-Attempt']) < 10:
|
||||
response.headers['Auth-Wait'] = '3'
|
||||
return response
|
||||
|
||||
|
||||
from mailu.internal.views import *
|
||||
|
@ -1,36 +1,34 @@
|
||||
import limits
|
||||
import limits.storage
|
||||
import limits.strategies
|
||||
import ipaddress
|
||||
|
||||
class RateLimitExceeded(Exception):
|
||||
pass
|
||||
|
||||
class Limiter:
|
||||
class LimitWrapper(object):
|
||||
""" Wraps a limit by providing the storage, item and identifiers
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.storage = None
|
||||
self.limiter = None
|
||||
self.rate = None
|
||||
self.subnet = None
|
||||
self.rate_limit_subnet = True
|
||||
def __init__(self, limiter, limit, *identifiers):
|
||||
self.limiter = limiter
|
||||
self.limit = limit
|
||||
self.base_identifiers = identifiers
|
||||
|
||||
def test(self, *args):
|
||||
return self.limiter.test(self.limit, *(self.base_identifiers + args))
|
||||
|
||||
def hit(self, *args):
|
||||
return self.limiter.hit(self.limit, *(self.base_identifiers + args))
|
||||
|
||||
def get_window_stats(self, *args):
|
||||
return self.limiter.get_window_stats(self.limit, *(self.base_identifiers + args))
|
||||
|
||||
|
||||
class LimitWraperFactory(object):
|
||||
""" Global limiter, to be used as a factory
|
||||
"""
|
||||
|
||||
def init_app(self, app):
|
||||
self.storage = limits.storage.storage_from_string(app.config["RATELIMIT_STORAGE_URL"])
|
||||
self.limiter = limits.strategies.MovingWindowRateLimiter(self.storage)
|
||||
self.rate = limits.parse(app.config["AUTH_RATELIMIT"])
|
||||
self.rate_limit_subnet = str(app.config["AUTH_RATELIMIT_SUBNET"])!='False'
|
||||
self.subnet = ipaddress.ip_network(app.config["SUBNET"])
|
||||
|
||||
def check(self,clientip):
|
||||
# disable limits for internal requests (e.g. from webmail)?
|
||||
if self.rate_limit_subnet==False and ipaddress.ip_address(clientip) in self.subnet:
|
||||
return
|
||||
if not self.limiter.test(self.rate,"client-ip",clientip):
|
||||
raise RateLimitExceeded()
|
||||
|
||||
def hit(self,clientip):
|
||||
# disable limits for internal requests (e.g. from webmail)?
|
||||
if self.rate_limit_subnet==False and ipaddress.ip_address(clientip) in self.subnet:
|
||||
return
|
||||
self.limiter.hit(self.rate,"client-ip",clientip)
|
||||
def get_limiter(self, limit, *args):
|
||||
return LimitWrapper(self.limiter, limits.parse(limit), *args)
|
Loading…
Reference in New Issue