mirror of
https://github.com/LibreTranslate/LibreTranslate.git
synced 2024-11-22 07:51:00 +00:00
Merge pull request #88 from pierotofy/flood
Flood Protection (IP based)
This commit is contained in:
commit
f7d7731fb4
4 changed files with 74 additions and 3 deletions
35
app/app.py
35
app/app.py
|
@ -5,8 +5,7 @@ from flask_swagger_ui import get_swaggerui_blueprint
|
||||||
from pkg_resources import resource_filename
|
from pkg_resources import resource_filename
|
||||||
from .api_keys import Database
|
from .api_keys import Database
|
||||||
from app.language import detect_languages, transliterate
|
from app.language import detect_languages, transliterate
|
||||||
|
from app import flood
|
||||||
api_keys_db = None
|
|
||||||
|
|
||||||
def get_json_dict(request):
|
def get_json_dict(request):
|
||||||
d = request.get_json()
|
d = request.get_json()
|
||||||
|
@ -89,6 +88,9 @@ def create_app(args):
|
||||||
from .no_limiter import Limiter
|
from .no_limiter import Limiter
|
||||||
limiter = Limiter()
|
limiter = Limiter()
|
||||||
|
|
||||||
|
if args.req_flood_threshold > 0:
|
||||||
|
flood.setup(args.req_flood_threshold)
|
||||||
|
|
||||||
@app.errorhandler(400)
|
@app.errorhandler(400)
|
||||||
def invalid_api(e):
|
def invalid_api(e):
|
||||||
return jsonify({"error": str(e.description)}), 400
|
return jsonify({"error": str(e.description)}), 400
|
||||||
|
@ -99,8 +101,14 @@ def create_app(args):
|
||||||
|
|
||||||
@app.errorhandler(429)
|
@app.errorhandler(429)
|
||||||
def slow_down_error(e):
|
def slow_down_error(e):
|
||||||
|
flood.report(get_remote_address())
|
||||||
return jsonify({"error": "Slowdown: " + str(e.description)}), 429
|
return jsonify({"error": "Slowdown: " + str(e.description)}), 429
|
||||||
|
|
||||||
|
@app.errorhandler(403)
|
||||||
|
def denied(e):
|
||||||
|
return jsonify({"error": str(e.description)}), 403
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
def index():
|
def index():
|
||||||
|
@ -236,7 +244,18 @@ def create_app(args):
|
||||||
error:
|
error:
|
||||||
type: string
|
type: string
|
||||||
description: Reason for slow down
|
description: Reason for slow down
|
||||||
|
403:
|
||||||
|
description: Banned
|
||||||
|
schema:
|
||||||
|
id: error-response
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
description: Error message
|
||||||
"""
|
"""
|
||||||
|
if flood.is_banned(get_remote_address()):
|
||||||
|
abort(403, description="Too many request limits violations")
|
||||||
|
|
||||||
if request.is_json:
|
if request.is_json:
|
||||||
json = get_json_dict(request)
|
json = get_json_dict(request)
|
||||||
|
@ -369,7 +388,19 @@ def create_app(args):
|
||||||
error:
|
error:
|
||||||
type: string
|
type: string
|
||||||
description: Reason for slow down
|
description: Reason for slow down
|
||||||
|
403:
|
||||||
|
description: Banned
|
||||||
|
schema:
|
||||||
|
id: error-response
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
description: Error message
|
||||||
"""
|
"""
|
||||||
|
if flood.is_banned(get_remote_address()):
|
||||||
|
abort(403, description="Too many request limits violations")
|
||||||
|
|
||||||
if request.is_json:
|
if request.is_json:
|
||||||
json = get_json_dict(request)
|
json = get_json_dict(request)
|
||||||
q = json.get('q')
|
q = json.get('q')
|
||||||
|
|
37
app/flood.py
Normal file
37
app/flood.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import time
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
|
||||||
|
banned = {}
|
||||||
|
active = False
|
||||||
|
threshold = -1
|
||||||
|
|
||||||
|
def clear_banned():
|
||||||
|
global banned
|
||||||
|
print(banned)
|
||||||
|
banned = {}
|
||||||
|
|
||||||
|
def setup(violations_threshold = 100):
|
||||||
|
global active
|
||||||
|
global threshold
|
||||||
|
|
||||||
|
active = True
|
||||||
|
threshold = violations_threshold
|
||||||
|
|
||||||
|
scheduler = BackgroundScheduler()
|
||||||
|
scheduler.add_job(func=clear_banned, trigger="interval", weeks=4)
|
||||||
|
scheduler.start()
|
||||||
|
|
||||||
|
# Shut down the scheduler when exiting the app
|
||||||
|
atexit.register(lambda: scheduler.shutdown())
|
||||||
|
|
||||||
|
|
||||||
|
def report(request_ip):
|
||||||
|
if active:
|
||||||
|
banned[request_ip] = banned.get(request_ip, 0)
|
||||||
|
banned[request_ip] += 1
|
||||||
|
|
||||||
|
def is_banned(request_ip):
|
||||||
|
# More than X offences?
|
||||||
|
return active and banned.get(request_ip, 0) >= threshold
|
|
@ -14,6 +14,8 @@ def main():
|
||||||
help='Set the default maximum number of requests per minute per client (%(default)s)')
|
help='Set the default maximum number of requests per minute per client (%(default)s)')
|
||||||
parser.add_argument('--daily-req-limit', default=-1, type=int, metavar="<number>",
|
parser.add_argument('--daily-req-limit', default=-1, type=int, metavar="<number>",
|
||||||
help='Set the default maximum number of requests per day per client, in addition to req-limit. (%(default)s)')
|
help='Set the default maximum number of requests per day per client, in addition to req-limit. (%(default)s)')
|
||||||
|
parser.add_argument('--req-flood-threshold', default=-1, type=int, metavar="<number>",
|
||||||
|
help='Set the maximum number of request limit offences per 4 weeks that a client can exceed before being banned. (%(default)s)')
|
||||||
parser.add_argument('--batch-limit', default=-1, type=int, metavar="<number of texts>",
|
parser.add_argument('--batch-limit', default=-1, type=int, metavar="<number of texts>",
|
||||||
help='Set maximum number of texts to translate in a batch request (%(default)s)')
|
help='Set maximum number of texts to translate in a batch request (%(default)s)')
|
||||||
parser.add_argument('--ga-id', type=str, default=None, metavar="<GA ID>",
|
parser.add_argument('--ga-id', type=str, default=None, metavar="<GA ID>",
|
||||||
|
|
|
@ -10,3 +10,4 @@ pycld2==0.41
|
||||||
morfessor==2.0.6
|
morfessor==2.0.6
|
||||||
polyglot==16.7.4
|
polyglot==16.7.4
|
||||||
appdirs==1.4.4
|
appdirs==1.4.4
|
||||||
|
APScheduler==3.7.0
|
||||||
|
|
Loading…
Reference in a new issue