119 lines
3.7 KiB
Python
119 lines
3.7 KiB
Python
# magic.py — handle magic token login confirmation
|
|
|
|
from fastapi import APIRouter, Form, HTTPException, Depends, Request, Response
|
|
from fastapi.responses import RedirectResponse, JSONResponse
|
|
from sqlmodel import Session, select
|
|
from database import get_db
|
|
from models import User, DBSession
|
|
from datetime import datetime, timedelta
|
|
import secrets
|
|
import json
|
|
|
|
router = APIRouter()
|
|
|
|
@router.post("/magic-login")
|
|
async def magic_login(request: Request, response: Response, token: str = Form(...)):
|
|
# Debug messages disabled
|
|
|
|
# Use the database session context manager
|
|
with get_db() as db:
|
|
try:
|
|
# Look up user by token
|
|
user = db.query(User).filter(User.token == token).first()
|
|
# Debug messages disabled
|
|
|
|
if not user:
|
|
# Debug messages disabled
|
|
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
|
|
|
if datetime.utcnow() - user.token_created > timedelta(minutes=30):
|
|
# Debug messages disabled
|
|
raise HTTPException(status_code=401, detail="Token expired")
|
|
|
|
# Mark user as confirmed if not already
|
|
if not user.confirmed:
|
|
user.confirmed = True
|
|
user.ip = request.client.host
|
|
db.add(user)
|
|
# Debug messages disabled
|
|
|
|
# Create a new session for the user (valid for 24 hours)
|
|
session_token = secrets.token_urlsafe(32)
|
|
expires_at = datetime.utcnow() + timedelta(hours=24)
|
|
|
|
# Create new session
|
|
session = DBSession(
|
|
token=session_token,
|
|
uid=user.email or user.username, # Use email as UID
|
|
ip_address=request.client.host or "",
|
|
user_agent=request.headers.get("user-agent", ""),
|
|
expires_at=expires_at,
|
|
is_active=True
|
|
)
|
|
db.add(session)
|
|
db.commit()
|
|
|
|
# Store user data for use after the session is committed
|
|
user_email = user.email or user.username
|
|
username = user.username
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
# Debug messages disabled
|
|
# Debug messages disabled
|
|
raise HTTPException(status_code=500, detail="Database error during login")
|
|
|
|
# Determine if we're running in development (localhost) or production
|
|
is_localhost = request.url.hostname == "localhost"
|
|
|
|
# Prepare response data
|
|
response_data = {
|
|
"success": True,
|
|
"message": "Login successful",
|
|
"user": {
|
|
"email": user_email,
|
|
"username": username
|
|
},
|
|
"token": session_token # Include the token in the JSON response
|
|
}
|
|
|
|
# Create the response
|
|
response = JSONResponse(
|
|
content=response_data,
|
|
status_code=200
|
|
)
|
|
|
|
# Set cookies
|
|
response.set_cookie(
|
|
key="sessionid",
|
|
value=session_token,
|
|
httponly=True,
|
|
secure=not is_localhost,
|
|
samesite="lax" if is_localhost else "none",
|
|
max_age=86400, # 24 hours
|
|
path="/"
|
|
)
|
|
|
|
response.set_cookie(
|
|
key="uid",
|
|
value=user_email,
|
|
samesite="lax" if is_localhost else "none",
|
|
secure=not is_localhost,
|
|
max_age=86400, # 24 hours
|
|
path="/"
|
|
)
|
|
|
|
response.set_cookie(
|
|
key="authToken",
|
|
value=session_token,
|
|
samesite="lax" if is_localhost else "none",
|
|
secure=not is_localhost,
|
|
max_age=86400, # 24 hours
|
|
path="/"
|
|
)
|
|
|
|
# Debug messages disabled
|
|
# Debug messages disabled
|
|
# Debug messages disabled
|
|
return response
|