75 lines
2.8 KiB
Python
75 lines
2.8 KiB
Python
import logging
|
|
|
|
from fastapi import Cookie, HTTPException, Request
|
|
from fastapi.responses import RedirectResponse
|
|
|
|
from ..db import sql
|
|
from ..util import passphrase, tokens
|
|
from . import session
|
|
|
|
|
|
def register_reset_routes(app):
|
|
"""Register all device addition/reset routes on the FastAPI app."""
|
|
|
|
@app.post("/auth/create-link")
|
|
async def api_create_link(request: Request, auth=Cookie(None)):
|
|
"""Create a device addition link for the authenticated user."""
|
|
try:
|
|
# Require authentication
|
|
s = await session.get_session(auth)
|
|
|
|
# Generate a human-readable token
|
|
token = passphrase.generate() # e.g., "cross.rotate.yin.note.evoke"
|
|
await sql.create_session(
|
|
user_uuid=s.user_uuid,
|
|
key=tokens.reset_key(token),
|
|
expires=session.expires(),
|
|
info=session.infodict(request, "device addition"),
|
|
)
|
|
|
|
# Generate the device addition link with pretty URL
|
|
path = request.url.path.removesuffix("create-link") + token
|
|
url = f"{request.headers['origin']}{path}"
|
|
|
|
return {
|
|
"status": "success",
|
|
"message": "Registration link generated successfully",
|
|
"url": url,
|
|
"expires": session.expires().isoformat(),
|
|
}
|
|
|
|
except ValueError:
|
|
return {"error": "Authentication required"}
|
|
except Exception as e:
|
|
return {"error": f"Failed to create registration link: {str(e)}"}
|
|
|
|
@app.get("/auth/{reset_token}")
|
|
async def reset_authentication(
|
|
request: Request,
|
|
reset_token: str,
|
|
):
|
|
"""Verifies the token and redirects to auth app for credential registration."""
|
|
# This route should only match to exact passphrases
|
|
print(f"Reset handler called with url: {request.url.path}")
|
|
if not passphrase.is_well_formed(reset_token):
|
|
raise HTTPException(status_code=404)
|
|
try:
|
|
# Get session token to validate it exists and get user_id
|
|
key = tokens.reset_key(reset_token)
|
|
sess = await sql.get_session(key)
|
|
if not sess:
|
|
raise ValueError("Invalid or expired registration token")
|
|
|
|
response = RedirectResponse(url="/auth/", status_code=303)
|
|
session.set_session_cookie(response, reset_token)
|
|
return response
|
|
|
|
except Exception as e:
|
|
# On any error, redirect to auth app
|
|
if isinstance(e, ValueError):
|
|
msg = str(e)
|
|
else:
|
|
logging.exception("Internal Server Error in reset_authentication")
|
|
msg = "Internal Server Error"
|
|
return RedirectResponse(url=f"/auth/#{msg}", status_code=303)
|