diff --git a/backend/src/api/protein.py b/backend/src/api/protein.py index 84cf640e..6576dd45 100644 --- a/backend/src/api/protein.py +++ b/backend/src/api/protein.py @@ -7,9 +7,11 @@ from ..db import Database, bytea_to_str, str_to_bytea from ..api_types import ProteinEntry, UploadBody, UploadError, EditBody, CamelModel +from ..auth import requiresAuthentication from io import BytesIO from fastapi import APIRouter from fastapi.responses import FileResponse, StreamingResponse +from fastapi.requests import Request router = APIRouter() @@ -179,7 +181,9 @@ def get_protein_entry(protein_name: str): # TODO: add permissions so only the creator can delete not just anyone @router.delete("/protein/entry/{protein_name:str}", response_model=None) -def delete_protein_entry(protein_name: str): +def delete_protein_entry(protein_name: str, req: Request): + print("DELETING") + requiresAuthentication(req) # Todo, have a meaningful error if the delete fails with Database() as db: # remove protein @@ -207,7 +211,8 @@ def upload_protein_png(body: UploadPNGBody): # None return means success @router.post("/protein/upload", response_model=UploadError | None) -def upload_protein_entry(body: UploadBody): +def upload_protein_entry(body: UploadBody, req: Request): + requiresAuthentication(req) # check that the name is not already taken in the DB if protein_name_found(body.name): return UploadError.NAME_NOT_UNIQUE @@ -262,10 +267,10 @@ def upload_protein_entry(body: UploadBody): # TODO: add more edits, now only does name and content edits @router.put("/protein/edit", response_model=UploadError | None) -def edit_protein_entry(body: EditBody): +def edit_protein_entry(body: EditBody, req: Request): # check that the name is not already taken in the DB # TODO: check if permission so we don't have people overriding other people's names - + requiresAuthentication(req) try: if body.new_name != body.old_name: os.rename(pdb_file_name(body.old_name), pdb_file_name(body.new_name)) diff --git a/backend/src/auth.py b/backend/src/auth.py index 2a1437cd..84d27851 100644 --- a/backend/src/auth.py +++ b/backend/src/auth.py @@ -1,5 +1,7 @@ import jwt from datetime import datetime, timezone, timedelta +from fastapi.requests import Request +from fastapi import HTTPException # TODO: This method of secret key generation is, obviously, extremely unsafe. # This needs to be changed. @@ -15,13 +17,31 @@ def generateAuthToken(userId, admin): return jwt.encode(payload, secret_key, algorithm="HS256") -# TODO: Find out how FastAPI handles middleware functions, and turn this into one. def authenticateToken(token): # Return the decoded token if it's valid. try: - decoded = jwt.decode(token, secret_key, algorithms="HS256") + # Valid token is always is in the form "Bearer [token]", so we need to slice off the "Bearer" portion. + sliced_token = token[7:] + print(sliced_token) + decoded = jwt.decode(sliced_token, secret_key, algorithms="HS256") + print("Valid token") + print(decoded) return decoded # If the token is invalid, return None. - except Exception: + except Exception as err: + print("Invalid token:", err) return None + + +# Use this function with a request if you want. +def requiresAuthentication(req: Request): + userInfo = authenticateToken(req.headers["authorization"]) + if (not userInfo or not userInfo.get("admin")): + print("Unauthorized User") + raise HTTPException( + status_code=403, + detail="Unauthorized" + ) + else: + print("User authorized.") \ No newline at end of file