-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
API Rate Limiting for Bad Actor; Small Code Refactor (#8)
* Cleanup Log.py * Remove Unused Import * Correct Typo * Update Requirements to have rate-limiter package * Update routes to use rate limiting * rollback Rate Limit Changes * Rollback Rate Limit; Implement Metrics * Split Middleware to own files * update requirements.txt * remove unneeded requirement * remove unused imports * Adjust Middleware files to be better importable. * remove unneeded API Singleton * Update Authentication Import Path * Properly implement new file layout. * remove manual auth checking, 'prebuilt' middleware * implement authentication middleware as middleware * add authentication middleware to FastAPI App * readd eof new line --------- Co-authored-by: Chats <[email protected]>
- Loading branch information
1 parent
599b9d4
commit bb47b60
Showing
10 changed files
with
174 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ gitpython~=3.1.43 | |
gunicorn~=21.2.0 | ||
uvicorn~=0.29.0 | ||
brotli-asgi~=1.4.0 | ||
prometheus-fastapi-instrumentator~=7.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import bcrypt | ||
|
||
from fastapi import status | ||
from fastapi.requests import Request | ||
from fastapi.responses import JSONResponse | ||
|
||
from src.cfg.settings import security | ||
|
||
TOKEN = security["token"] | ||
hashed = bcrypt.hashpw(bytes(TOKEN, "utf-8"), bcrypt.gensalt()) | ||
|
||
|
||
async def authenticate(request: Request, call_next): | ||
authenticated_prefixes = "admin" | ||
response = None | ||
headers = dict(request.scope["headers"]) | ||
if ( | ||
authenticated_prefixes in request.url.path | ||
and "authorization" in request.headers | ||
): | ||
if verify_password(request.headers["Authorization"]): | ||
response = await call_next(request) | ||
else: | ||
response = JSONResponse( | ||
status_code=status.HTTP_401_UNAUTHORIZED, | ||
content={"error": "Unauthorized"}, | ||
) | ||
else: | ||
response = await call_next(request) | ||
return response | ||
|
||
|
||
def verify_length(token): | ||
length = len(token) | ||
if length <= 7 or length >= 25: | ||
return False | ||
return True | ||
|
||
|
||
def verify_password(plaintext_token): | ||
if verify_length(plaintext_token): | ||
if bcrypt.checkpw(str.encode(plaintext_token), hashed): | ||
return True | ||
else: | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from fastapi.requests import Request | ||
|
||
|
||
async def case_sens_middleware(request: Request, call_next): | ||
decode_format = "utf-8" | ||
raw_query_str = request.scope["query_string"].decode(decode_format).lower() | ||
request.scope["query_string"] = raw_query_str.encode(decode_format) | ||
|
||
path = request.scope["path"].lower() | ||
request.scope["path"] = path | ||
|
||
response = await call_next(request) | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from prometheus_fastapi_instrumentator import Instrumentator, metrics | ||
|
||
# from prometheus_fastapi_instrumentator.metrics import Info | ||
# from prometheus_client import Counter | ||
|
||
instrumentator = Instrumentator( | ||
should_group_status_codes=True, | ||
should_ignore_untemplated=False, | ||
should_group_untemplated=False, | ||
should_round_latency_decimals=True, | ||
should_instrument_requests_inprogress=True, | ||
excluded_handlers=[".*admin.*", "/metrics.py"], | ||
inprogress_name="inprogress", | ||
inprogress_labels=True, | ||
) | ||
|
||
instrumentator.add( | ||
metrics.request_size( | ||
should_include_method=True, | ||
should_include_status=True, | ||
should_include_handler=True, | ||
metric_namespace="request", | ||
metric_subsystem="size", | ||
) | ||
).add( | ||
metrics.response_size( | ||
should_include_handler=True, | ||
should_include_status=True, | ||
should_include_method=False, | ||
metric_namespace="response", | ||
metric_subsystem="size", | ||
) | ||
).add( | ||
metrics.latency( | ||
should_include_handler=True, | ||
should_include_status=True, | ||
should_include_method=False, | ||
metric_namespace="latency", | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import src.utils.log as log | ||
from fastapi.requests import Request | ||
from fastapi.responses import JSONResponse | ||
|
||
|
||
async def cutoff(request: Request, call_next): | ||
block_list = "Helldivers%20Companion/238 CFNetwork/1494.0.7 Darwin/23.4.0" | ||
decode_format = "utf-8" | ||
raw_query_str = request.headers.get("User-Agent", "") | ||
if block_list == raw_query_str: | ||
log.info(request, 429, block_list) | ||
response = JSONResponse( | ||
status_code=429, | ||
content={ | ||
"limited": "Contact @chatterchats on Discord.", | ||
}, | ||
) | ||
return response | ||
else: | ||
response = await call_next(request) | ||
return response |