from fastapi import FastAPI, File, UploadFile, Depends, HTTPException, Security from fastapi.responses import FileResponse, PlainTextResponse, StreamingResponse from fastapi.security import APIKeyHeader from sqlalchemy import exists import hashlib from ftplib import FTP from io import BytesIO from . import db from dotenv import load_dotenv import os import hmac load_dotenv() FILES_DIR = os.getenv("FILES_DIR") API_KEY_HASH = os.getenv("API_KEY_HASH") api_key_header = APIKeyHeader(name="X-API-Key") FTP_URL = os.getenv("FTP_URL") FTP_LOGIN = os.getenv("FTP_LOGIN") FTP_PASSWORD = os.getenv("FTP_PASSWORD") CACHE_DIR = "cache" def verify_api_key(api_key: str = Security(api_key_header)): api_key_hashed = hashlib.sha256(api_key.encode()).hexdigest() if not hmac.compare_digest(api_key_hashed, API_KEY_HASH): raise HTTPException(status_code=403, detail="Forbidden. (╥﹏╥)") return api_key def compute_hash(data: bytes, algorithm="sha256") -> str: h = hashlib.new(algorithm) h.update(data) return h.hexdigest() app = FastAPI() @app.get("/") async def root(): return {"message": "hiii from sfs"} @app.post("/file") async def save_file(file: UploadFile = File(...), api_key: str = Depends(verify_api_key)): contents = await file.read() hash = compute_hash(contents) existed_url = db.file_exists(file.size, hash) if not existed_url: file_url = db.add_file(file.filename, file.content_type, file.size, hash) try: ftp = FTP(FTP_URL) ftp.login(FTP_LOGIN, FTP_PASSWORD) buffer = BytesIO(contents) try: ftp.mkd(FILES_DIR) except: pass ftp.storbinary(f"STOR {FILES_DIR}/{file_url}", buffer) ftp.quit() cached = os.path.join(CACHE_DIR, file_url) if os.path.exists(cached): os.remove(cached) return {"status": "saved", "filename": file_url} except Exception as e: db.remove_file(file_url) return {"status": "error", "message": f"Could not save file {file_url}: {e}"} else: return {"status": "file_exists", "filename": existed_url} @app.get("/file/{filename}") async def get_file(filename: str, raw: bool = False, api_key: str = Depends(verify_api_key)): local_path = os.path.join(CACHE_DIR, filename) if not os.path.exists(local_path): try: ftp = FTP(FTP_URL) ftp.login(FTP_LOGIN, FTP_PASSWORD) with open(local_path, "wb") as f: ftp.retrbinary(f"RETR {FILES_DIR}/{filename}", f.write) ftp.quit() except Exception as e: raise HTTPException(status_code=404, detail=f"File not found: {e}") if raw: with open(local_path, "r", encoding="utf-8", errors="ignore") as f: return PlainTextResponse(f.read()) return FileResponse(local_path, filename=filename) from ftplib import FTP @app.delete("/file/{filename}") async def delete_file(filename: str, api_key: str = Depends(verify_api_key)): if not db.remove_file(filename): return {"status": "error", "message": "no file like that"} try: ftp = FTP(FTP_URL) ftp.login(FTP_LOGIN, FTP_PASSWORD) ftp.delete(f"{FILES_DIR}/{filename}") ftp.quit() return {"status": "deleted"} except Exception as e: return {"status": "error", "message": f"Could not delete file {filename}: {e}"} @app.get("/files/") async def get_list_of_files(api_key: str = Depends(verify_api_key)): return db.get_all_files() @app.get("/healthchecker") async def healthchecker(): return {"message": "Howdy, all is fine :3"}