This repository was archived by the owner on Feb 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
139 lines (100 loc) · 4.84 KB
/
main.py
File metadata and controls
139 lines (100 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from fastapi import Depends, FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security.api_key import APIKeyCookie, APIKeyHeader
from fastapi.responses import RedirectResponse
from sqlalchemy.orm import Session
from starlette.middleware.sessions import SessionMiddleware
from starlette.requests import Request
from starlette.responses import Response
from typing import List, Optional
from urllib.parse import urljoin
from uuid import UUID
from auth import oauth
from database import engine, SessionLocal
from models import Base
from schemas import Project, ProjectIn, User, UserInternal, UserOut
from settings import SESSION_SECRET, TOKEN_NAME, FRONTEND_URL
import crud
Base.metadata.create_all(bind=engine)
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=FRONTEND_URL, allow_credentials="*", allow_methods=["*"], allow_headers=["*"])
app.add_middleware(SessionMiddleware, secret_key=SESSION_SECRET)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
api_key_cookie = APIKeyCookie(name=TOKEN_NAME, auto_error=False)
api_key_header = APIKeyHeader(name=TOKEN_NAME, auto_error=False)
def auth(cookie: str = Depends(api_key_cookie), header: str = Depends(api_key_header), db: str = Depends(get_db)):
token = header or cookie
user = crud.get_user_by_token(db, token)
if user is None:
raise HTTPException(status_code=401, detail="Not authenticated")
return user
response_401 = {401: {"description": "Not authenticated"}}
response_403 = {403: {"description": "Forbidden"}}
response_404 = {404: {"description": "Project not found"}}
# Handle Google token redirect
@app.get("/login/google")
async def login_via_google(request: Request, redirect: str = ""):
request.session["redirect"] = redirect
redirect_uri = request.url_for(auth_via_google.__name__)
return await oauth.google.authorize_redirect(request, redirect_uri)
@app.get("/auth/google")
async def auth_via_google(request: Request, db: Session = Depends(get_db)):
token = await oauth.google.authorize_access_token(request)
id_token = await oauth.google.parse_id_token(request, token)
sub = id_token["sub"]
user = crud.get_user_by_subject(db, sub)
if user is None:
user = UserInternal(google_subject=sub, email=id_token["email"])
user = crud.create_user(db, user)
hackbca_token = crud.create_token(db, user.id)
response = RedirectResponse(url=urljoin(FRONTEND_URL, request.session["redirect"]))
del request.session["redirect"]
response.set_cookie(key=TOKEN_NAME, value=hackbca_token, expires=None)
return response
@app.get("/me", response_model=dict, responses=response_401)
async def me(user: User = Depends(auth)):
return {"id": user.id, "email": user.email}
@app.get("/logout")
async def logout(cookie: str = Depends(api_key_cookie), header: str = Depends(api_key_header), db: str = Depends(get_db)):
crud.delete_token(db, header)
crud.delete_token(db, cookie)
response = RedirectResponse(url=FRONTEND_URL)
if cookie:
response.set_cookie(key=TOKEN_NAME, value="", expires=0)
return response
@app.get("/projects", response_model=List[Project])
async def list_projects(db: Session = Depends(get_db)):
return crud.list_all_projects(db)
@app.get("/projects/{uuid}", response_model=Project, responses=response_404)
async def get_project(uuid: UUID, db: Session = Depends(get_db)):
if res := crud.get_project(db, uuid):
return res
else:
raise HTTPException(status_code=404, detail="Project not found")
@app.post("/projects", response_model=Project, responses=response_403)
async def create_project(project: ProjectIn, db: Session = Depends(get_db), user: User = Depends(auth)):
return crud.create_project(db, project, user)
@app.put("/projects/{uuid}", response_model=Project, responses=response_403|response_404)
async def update_project(uuid: UUID, project: ProjectIn, db: Session = Depends(get_db), user: User = Depends(auth)):
res = crud.get_project(db, uuid)
if res is None:
raise HTTPException(status_code=404, detail="Project not found")
if user.id not in [u.id for u in res.users]:
raise HTTPException(status_code=403, detail="Forbidden")
return crud.update_project(db, uuid, project)
@app.delete("/projects/{uuid}", responses=response_403|response_404)
async def update_project(uuid: UUID, db: Session = Depends(get_db), user: User = Depends(auth)):
res = crud.get_project(db, uuid)
if res is None:
raise HTTPException(status_code=404, detail="Project not found")
if user.id not in [u.id for u in res.users]:
raise HTTPException(status_code=403, detail="Forbidden")
return crud.delete_project(db, uuid)
@app.get("/users", response_model=List[UserOut])
async def list_users(db: Session = Depends(get_db)):
return crud.list_all_users(db)