File size: 12,071 Bytes
763951b 1deefa3 325f578 5ed4a12 325f578 f24c2bb 325f578 f5ffa3e fc80837 9731a64 afd16c0 616d5ed 10b597c afd16c0 10b597c 46a06f8 325f578 10b597c c856d60 625461f c856d60 10b597c 625461f 10511db 325f578 44372ef c5c4c92 8268a41 7c0b4d6 8268a41 c5c4c92 fab519b 7c0b4d6 c5c4c92 8268a41 09274a9 0e0e35e bda9eb4 7c0b4d6 bda9eb4 cb6494b b7bbd14 8d61206 17abc14 b7bbd14 8d61206 b7bbd14 8d61206 09274a9 8268a41 09274a9 e3afd2e cb6494b a3ea3d6 4da28a8 dcdcf2f 35db52b 4da28a8 c856d60 78e68c7 2559567 c856d60 35db52b c856d60 35db52b c856d60 3d61992 653d617 c856d60 653d617 c856d60 2a3fa0d dcdcf2f 4da28a8 377e020 473df3a 377e020 473df3a 44372ef 5ed4a12 dc39372 e007f86 dc39372 8338c06 e007f86 dc39372 e007f86 5ed4a12 e007f86 5ed4a12 c209774 1deefa3 fecefe5 1deefa3 493f2fc 1deefa3 493f2fc ca1fdb8 493f2fc ca1fdb8 1deefa3 3dc66e5 ca1fdb8 1deefa3 ca1fdb8 fecefe5 ca1fdb8 |
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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
#main.py
from fastapi import FastAPI, Form, Depends, HTTPException, status
from fastapi.requests import Request
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from auth import verify_token, oauth2_scheme, auth_views, register, UserCreate, authenticate_user, get_user_by_verification_token
from database import get_db, get_user_by_email
from datetime import timedelta
from typing import Optional
#import auth
#import tts
import os
import asyncio
my_secret_key = os.environ['my_secret_key']
app = FastAPI()
#router = APIRouter()
templates = Jinja2Templates(directory="templates")
from google.cloud import recaptchaenterprise_v1
from google.cloud.recaptchaenterprise_v1 import Assessment
def create_assessment(
project_id: str, recaptcha_key: str, token: str, recaptcha_action: str
) -> Assessment:
"""Create an assessment to analyse the risk of a UI action.
Args:
project_id: Your Google Cloud project ID.
recaptcha_key: The reCAPTCHA key associated with the site/app
token: The generated token obtained from the client.
recaptcha_action: Action name corresponding to the token.
"""
client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()
# Set the properties of the event to be tracked.
event = recaptchaenterprise_v1.Event()
event.site_key = recaptcha_key
event.token = token
assessment = recaptchaenterprise_v1.Assessment()
assessment.event = event
project_name = f"projects/{project_id}"
# Build the assessment request.
request = recaptchaenterprise_v1.CreateAssessmentRequest()
request.assessment = assessment
request.parent = project_name
response = client.create_assessment(request)
# Check if the token is valid.
if not response.token_properties.valid:
print(
"The CreateAssessment call failed because the token was "
+ "invalid for the following reasons: "
+ str(response.token_properties.invalid_reason)
)
return
# Check if the expected action was executed.
if response.token_properties.action != recaptcha_action:
print(
"The action attribute in your reCAPTCHA tag does"
+ "not match the action you are expecting to score"
)
return
else:
# Get the risk score and the reason(s).
# For more information on interpreting the assessment, see:
# https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment
for reason in response.risk_analysis.reasons:
print(reason)
print(
"The reCAPTCHA score for this token is: "
+ str(response.risk_analysis.score)
)
# Get the assessment name (ID). Use this to annotate the assessment.
assessment_name = client.parse_assessment_path(response.name).get("assessment")
print(f"Assessment name: {assessment_name}")
return response
# Dependency for verifying the user's token
def get_current_user(token: str = Depends(verify_token)):
if not token:
raise HTTPException(status_code=401, detail="Token not valid")
return token
# Route for the landing page
@app.get("/", response_class=HTMLResponse)
async def landing(request: Request):
return templates.TemplateResponse("landing.html", {"request": request})
# Your other routes and app configuration go here
@app.get("/login", response_class=HTMLResponse)
async def login(request: Request):
return templates.TemplateResponse("login.html", {"request": request})
@app.post("/login")
async def login_post(
request: Request,
email: str = Form(...),
password: str = Form(...),
db: Session = Depends(get_db)
):
if not email or not password:
raise HTTPException(status_code=400, detail="Invalid email or password")
user = authenticate_user(db, email, password)
if user and user.is_verified: # Check if user is verified
access_token = auth_views.create_access_token(
data={"sub": user.email},
expires_delta=timedelta(minutes=auth_views.ACCESS_TOKEN_EXPIRE_MINUTES)
)
# Redirect the user to the protected route with the token in the URL
url = app.url_path_for("get_protected") # Ensure you have a name="get_protected" in your app.get("/protected") decorator
#return RedirectResponse(url=f"/protected?token={access_token}", status_code=status.HTTP_303_SEE_OTHER)
#return RedirectResponse(f"{url}?token={access_token}")
response = RedirectResponse(f"{url}?token={access_token}", status_code=status.HTTP_303_SEE_OTHER)
response.set_cookie(key="access_token", value=f"Bearer {access_token}", httponly=True)
# response.set_cookie(key="access_token", value=access_token, httponly=True)
return response
elif user and not user.is_verified: # User is not verified
raise HTTPException(
status_code=400,
detail="You must verify your email before accessing this resource."
)
else:
# If authentication fails, return to the login page with an error message
return templates.TemplateResponse(
"login.html",
{"request": request, "error_message": "Invalid email or password"}
)
@app.get("/register", response_class=HTMLResponse)
async def register_get(request: Request):
return templates.TemplateResponse("register.html", {"request": request})
@app.post("/register", response_class=HTMLResponse)
async def register_post(
request: Request,
username: str = Form(...),
email: str = Form(...),
password: str = Form(...),
confirm_password: str = Form(...),
recaptcha_token: str = Form(...), # Add this line to accept the reCAPTCHA token
db: Session = Depends(get_db)
):
# Perform reCAPTCHA verification first
project_id = 'login-auth-1699381988574' # Replace with your project ID
recaptcha_key = '6LdMjQcpAAAAAGtbNZkL17ry1scsQjp1HSEhkLNl' # Replace with your site key
recaptcha_action = 'submit' # The action you're expecting
recaptcha_secret = '6LdMjQcpAAAAAGtbNZkL17ry1scsQjp1HSEhkLNl' # Replace with your reCAPTCHA secret key
recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify'
recaptcha_data = {
'secret': recaptcha_secret,
'response': recaptcha_token
}
recaptcha_response = requests.post(recaptcha_url, data=recaptcha_data)
recaptcha_result = recaptcha_response.json()
if not recaptcha_result.get('success', False):
raise HTTPException(status_code=400, detail="reCAPTCHA validation failed.")
# Call the create_assessment function to validate the token
# assessment = await create_assessment( project_id, recaptcha_key, token, recaptcha_action )
# loop = asyncio.get_running_loop()
# assessment = await loop.run_in_executor(
# None, create_assessment, project_id, recaptcha_key, token, recaptcha_action
# )
# Check the assessment result
# if not assessment or assessment.risk_analysis.score < 0.5: # Use an appropriate risk score threshold
# return templates.TemplateResponse("register.html", {
# "request": request,
# "error_message": "Captcha validation failed."
# })
if password != confirm_password:
# Return to the registration page with an error
return templates.TemplateResponse("register.html", {
"request": request,
"error_message": "Passwords do not match."
})
try:
user = UserCreate(username=username, email=email, password=password, confirm_password=confirm_password)
register(user, db) # If this function raises an HTTPException, it should be handled
except HTTPException as e:
# Return to the registration page with the error detail
return templates.TemplateResponse("register.html", {
"request": request,
"error_message": e.detail
})
# Redirect to the successful registration page
response = RedirectResponse("/registration_successful", status_code=status.HTTP_302_FOUND)
return response
@app.get("/registration_successful", response_class=HTMLResponse)
async def registration_successful(request: Request):
# Render the successful registration page
return templates.TemplateResponse("registration_successful.html", {"request": request})
@app.get("/verify/{verification_token}", response_class=HTMLResponse)
async def verify_email(verification_token: str, db: Session = Depends(get_db)):
user = get_user_by_verification_token(db, verification_token)
if not user:
raise HTTPException(status_code=400, detail="Invalid verification token")
if user.is_verified:
raise HTTPException(status_code=400, detail="Email already verified")
user.is_verified = True
user.email_verification_token = None # Clear the verification token
db.commit()
# Create access token for the user after successful verification
access_token = auth_views.create_access_token(data={"sub": user.email}, expires_delta=timedelta(minutes=auth_views.ACCESS_TOKEN_EXPIRE_MINUTES))
# Redirect to the protected route with the token as a query parameter (or as required by your front-end/client)
return RedirectResponse(url=f"/protected?token={access_token}")
#from jwt import decode, PyJWTError # make sure jwt is imported
@app.get("/protected", response_class=HTMLResponse)
async def get_protected(
request: Request,
db: Session = Depends(get_db),
token: Optional[str] = None # token is Optional because it may come from the cookie
):
# Try to get the token from the query parameter first, then fall back to the cookie
token = token or request.cookies.get("access_token")
if not token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
# Here verify_token is used directly in the endpoint
# If the token is invalid, verify_token will raise an HTTPException and the following lines will not be executed
user_email = verify_token(token) # Assuming that verify_token returns the user's email if the token is valid
# Get the user from the database
db_user = get_user_by_email(db, user_email)
if db_user is None or not db_user.is_verified:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found or not verified in the database")
# Render a template response
return templates.TemplateResponse("protected.html", {"request": request, "user": db_user.username})
#@app.get("/protected", response_class=HTMLResponse)
#async def get_protected(request: Request, token: Optional[str] = None, db: Session = Depends(get_db)):
# Try to get the token from the query parameter first, then fall back to the cookie
# token = token or request.cookies.get("access_token")
# if not token:
# raise HTTPException(status_code=401, detail="Not authenticated")
# try:
# payload = decode(token, auth_views.SECRET_KEY, algorithms=[auth_views.ALGORITHM])
# user_email = payload.get("sub")
# if user_email is None:
# raise HTTPException(status_code=401, detail="Not authenticated")
# except PyJWTError:
# raise HTTPException(status_code=401, detail="Could not validate credentials")
# db_user = get_user_by_email(db, user_email)
# if db_user is None or not db_user.is_verified:
# raise HTTPException(status_code=401, detail="User not found or not verified in the database")
# return templates.TemplateResponse("protected.html", {"request": request, "user": db_user.username})
#async def get_protected(
# request: Request,
# token: str = Query(None), # Accept token from query parameters
# db: Session = Depends(get_db)
#):
# Now pass both the request and token to the protected_route function
# return await protected_route(request, token, db) |