import os from fastapi import FastAPI, Request, Form, Depends, HTTPException, status from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from pydantic import BaseModel from typing import Optional from datetime import datetime, timedelta from jose import JWTError, jwt app = FastAPI() # Configuration for dummy Auth SECRET_KEY = "dummy_secret_key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 # Dummy user database: username -> {password, role} USER_DB = { "auditor1": {"password": "password123", "role": "auditor"}, "reviewer1": {"password": "admin123", "role": "reviewer"} } templates = Jinja2Templates(directory=".") def create_access_token(data: dict): to_encode = data.copy() expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) to_encode.update({"exp": expire}) return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) def get_current_user(request: Request): token = request.cookies.get("access_token") if not token: return None try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: return None return {"username": username, "role": payload.get("role")} except JWTError: return None @app.get("/", response_class=HTMLResponse) async def index(request: Request): user = get_current_user(request) if not user: return templates.TemplateResponse("index.html", {"request": request, "user": None}) return templates.TemplateResponse("index.html", {"request": request, "user": user}) @app.post("/login") async def login(username: str = Form(...), password: str = Form(...)): user = USER_DB.get(username) if user and user["password"] == password: token = create_access_token({"sub": username, "role": user["role"]}) response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND) response.set_cookie(key="access_token", value=token, httponly=True) return response return HTMLResponse("Invalid credentials", status_code=401) @app.get("/logout") async def logout(): response = RedirectResponse(url="/") response.delete_cookie("access_token") return response @app.post("/submit-finding") async def submit_finding(request: Request, finding: str = Form(...)): user = get_current_user(request) if not user or user["role"] != "auditor": raise HTTPException(status_code=403, detail="Only auditors can submit findings") # Logic to save finding would go here return {"status": "success", "message": "Finding submitted for review"} @app.post("/review-finding") async def review_finding(request: Request, decision: str = Form(...)): user = get_current_user(request) if not user or user["role"] != "reviewer": raise HTTPException(status_code=403, detail="Only reviewers can approve findings") return {"status": "success", "message": f"Finding {decision}"}