2024-08-10 22:49:00 -04:00
|
|
|
#!/usr/bin/env python3.12
|
|
|
|
|
|
|
|
import logging
|
2025-02-15 21:09:33 -05:00
|
|
|
from typing import Optional
|
2025-01-11 20:59:10 -05:00
|
|
|
from fastapi import FastAPI, Response, HTTPException
|
2025-01-21 19:16:23 -05:00
|
|
|
from fastapi.responses import RedirectResponse
|
2024-08-14 22:43:20 -04:00
|
|
|
|
2024-08-10 22:49:00 -04:00
|
|
|
|
|
|
|
class Utilities:
|
2025-02-15 21:09:33 -05:00
|
|
|
"""
|
|
|
|
API Utilities
|
|
|
|
"""
|
2025-04-17 07:28:05 -04:00
|
|
|
|
|
|
|
def __init__(self, app: FastAPI, constants):
|
2024-08-14 22:43:20 -04:00
|
|
|
self.constants = constants
|
2025-01-21 19:16:23 -05:00
|
|
|
self.blocked_redirect_uri = "https://codey.lol"
|
2025-01-11 20:59:10 -05:00
|
|
|
self.app = app
|
2024-08-10 22:49:00 -04:00
|
|
|
|
2025-02-15 21:09:33 -05:00
|
|
|
def get_blocked_response(self, path: Optional[str] = None):
|
|
|
|
"""
|
2025-09-23 13:17:34 -04:00
|
|
|
Return a redirect response for blocked requests.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
path (Optional[str]): The requested path (currently unused).
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
RedirectResponse: A redirect to the blocked URI.
|
2025-02-15 21:09:33 -05:00
|
|
|
"""
|
2024-08-10 22:49:00 -04:00
|
|
|
logging.error("Rejected request: Blocked")
|
2025-01-21 19:16:23 -05:00
|
|
|
return RedirectResponse(url=self.blocked_redirect_uri)
|
2024-08-10 22:49:00 -04:00
|
|
|
|
2025-04-17 07:28:05 -04:00
|
|
|
def get_no_endpoint_found(self, path: Optional[str] = None):
|
2025-02-15 21:09:33 -05:00
|
|
|
"""
|
2025-09-23 13:17:34 -04:00
|
|
|
Raise an HTTP 404 exception for unknown endpoints.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
path (Optional[str]): The requested path (currently unused).
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
HTTPException: With status code 404 and detail "Unknown endpoint".
|
2025-02-15 21:09:33 -05:00
|
|
|
"""
|
2024-08-10 22:49:00 -04:00
|
|
|
logging.error("Rejected request: No such endpoint")
|
|
|
|
raise HTTPException(detail="Unknown endpoint", status_code=404)
|
|
|
|
|
2025-04-17 07:28:05 -04:00
|
|
|
def check_key(self, path: str, key: str, req_type: int = 0) -> bool:
|
2024-08-14 22:43:20 -04:00
|
|
|
"""
|
2025-09-23 13:17:34 -04:00
|
|
|
Check if the provided API key is valid and meets the requirements.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
path (str): The request path (reserved for future fine-tuning).
|
|
|
|
key (str): The authorization header value, expected to start with "Bearer ".
|
|
|
|
req_type (int): The type of access required.
|
|
|
|
0: Basic access.
|
|
|
|
2: Private access (key must start with "PRV-").
|
|
|
|
4: Radio access (key must start with "RAD-").
|
2024-08-14 22:43:20 -04:00
|
|
|
|
2025-09-23 13:17:34 -04:00
|
|
|
Returns:
|
|
|
|
bool: True if the key is valid and meets the requirements, False otherwise.
|
|
|
|
"""
|
2024-08-14 22:43:20 -04:00
|
|
|
if not key or not key.startswith("Bearer "):
|
|
|
|
return False
|
2025-04-17 07:28:05 -04:00
|
|
|
|
2025-02-15 21:09:33 -05:00
|
|
|
_key: str = key.split("Bearer ", maxsplit=1)[1].strip()
|
2024-08-14 22:43:20 -04:00
|
|
|
|
2025-09-22 11:08:48 -04:00
|
|
|
if _key not in self.constants.API_KEYS:
|
2024-08-19 11:42:23 -04:00
|
|
|
return False
|
2025-04-17 07:28:05 -04:00
|
|
|
|
2024-08-27 20:47:29 -04:00
|
|
|
if req_type == 2:
|
2025-02-15 21:09:33 -05:00
|
|
|
return _key.startswith("PRV-")
|
2025-02-09 20:34:11 -05:00
|
|
|
elif req_type == 4:
|
2025-02-15 21:09:33 -05:00
|
|
|
return _key.startswith("RAD-")
|
2025-04-17 07:28:05 -04:00
|
|
|
|
|
|
|
if path.lower().startswith("/xc/") and not key.startswith("XC-"):
|
|
|
|
return False
|
2025-02-10 20:29:57 -05:00
|
|
|
return True
|