Skip to content
Snippets Groups Projects
Commit 532acdc9 authored by Simon Künzel's avatar Simon Künzel
Browse files

Add separate rate limiter for resources

parent b96ca28e
Branches
Tags
No related merge requests found
......@@ -111,6 +111,21 @@ API_AUTH_RATE_LIMIT = [
}
]
# Works the same as global but used for resource requests (should be higher than default, since loading a course page can
# send dozens of requests at once; jumping in the video, etc.)
API_RESOURCES_RATE_LIMIT = [
{
"id": "short",
"window_size_seconds": 60,
"max_request_count": 500
},
{
"id": "long",
"window_size_seconds": 60 * 60,
"max_request_count": 4000
}
]
# Absolute limit. If there are already 32 chapters (visible or not visible), no more suggestions are accepted
API_CHAPTER_SUGGESTIONS_LIMIT_PER_LECTURE = 32
# This is NOT host based but globally. It uses a sliding window. For example for a window size of 24 hours, no more than
......
......@@ -18,6 +18,8 @@ _FILE_URI_PREFIX_PATH = url_parse.urlparse(_FILE_URI_PREFIX).path
if _FILE_URI_PREFIX_PATH is None:
raise ValueError("Cannot get path from FILE_URI_PREFIX")
_API_RESOURCE_RATE_LIMITERS = create_configured_host_rate_limiters("resources", api.config["API_RESOURCES_RATE_LIMIT"])
def _check_access_medium_file(course_handle: str, medium_file_id: int) -> MediumFile:
is_mod = is_moderator()
......@@ -54,16 +56,23 @@ def _decode_str_from_url(url_val: str) -> str:
return base64.urlsafe_b64decode(url_val.encode(encoding="utf-8")).decode(encoding="utf-8")
@api_route("/course/<string:course_handle>/resources/medium_file/<int:medium_file_id>", "GET", allow_while_readonly=True,
no_documentation=True)
@api_add_route("/course/<string:course_handle>/resources/medium_file/<int:medium_file_id>", "GET")
@api_function(
rate_limiters=_API_RESOURCE_RATE_LIMITERS,
allow_while_readonly=True,
no_documentation=True,
)
def api_route_access_target_medium(course_handle: str, medium_file_id: int):
download = request.args.get("download", "true").lower() == "true"
download = request.args.get("download", "false").lower() == "true"
medium_file = _check_access_medium_file(course_handle, medium_file_id)
# TODO download stats
return redirect(f"{_FILE_URI_PREFIX}/{medium_file.file_path}?co_ha={_encode_str_for_url(course_handle)}&mf_id={medium_file.id}&download={"true" if download else "false"}")
@api_route("/resources/internal_auth_check", "GET", allow_while_readonly=True,
@api_add_route("/resources/internal_auth_check", "GET")
@api_function(
rate_limiters=(), # Don't limit internal auth check. Always from same IP
allow_while_readonly=True,
no_documentation=True)
def api_route_resource_internal_auth_check():
if "X-Original-URI" not in request.headers:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment