Add browser Python editor with Pyodide, user auth, and workspace API
- FastAPI serves static UI, file CRUD under code/ and read-only lib/ - Pyodide worker runs Python and Jedi completions in the browser - SQLite accounts: login/register, session cookies, superuser user management - Optional EDITOR_API_KEY, AUTH_* env vars, .env.example - Pipenv, pytest, Selenium smoke test, README Made-with: Cursor
This commit is contained in:
63
src/editor_app/deps.py
Normal file
63
src/editor_app/deps.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from fastapi import Cookie, Depends, Header, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from editor_app.db.session import get_db
|
||||
from editor_app.db.models import User
|
||||
from editor_app.services import accounts
|
||||
|
||||
|
||||
def api_key_valid(authorization: str | None) -> bool:
|
||||
expected = (os.environ.get("EDITOR_API_KEY") or "").strip()
|
||||
if not expected:
|
||||
return False
|
||||
return (authorization or "").strip() == f"Bearer {expected}"
|
||||
|
||||
|
||||
async def require_api_access(
|
||||
db: Session = Depends(get_db),
|
||||
authorization: str | None = Header(None),
|
||||
editor_session: str | None = Cookie(None),
|
||||
) -> None:
|
||||
"""API key, or (when auth off) open access, or (when auth on) valid session — see README."""
|
||||
if api_key_valid(authorization):
|
||||
return
|
||||
key_configured = bool((os.environ.get("EDITOR_API_KEY") or "").strip())
|
||||
if key_configured:
|
||||
if accounts.auth_enabled():
|
||||
user = accounts.get_session_user(db, editor_session)
|
||||
if user:
|
||||
return
|
||||
raise HTTPException(status_code=401, detail="Invalid or missing API key")
|
||||
if not accounts.auth_enabled():
|
||||
return
|
||||
user = accounts.get_session_user(db, editor_session)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||
|
||||
|
||||
async def get_current_user_optional(
|
||||
db: Session = Depends(get_db),
|
||||
authorization: str | None = Header(None),
|
||||
editor_session: str | None = Cookie(None),
|
||||
) -> User | None:
|
||||
if api_key_valid(authorization):
|
||||
return None
|
||||
if not accounts.auth_enabled():
|
||||
return None
|
||||
return accounts.get_session_user(db, editor_session)
|
||||
|
||||
|
||||
async def require_superuser(
|
||||
user: User | None = Depends(get_current_user_optional),
|
||||
) -> User:
|
||||
if not accounts.auth_enabled():
|
||||
raise HTTPException(status_code=400, detail="User management requires AUTH_ENABLED=true")
|
||||
if user is None:
|
||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||
if not user.is_superuser:
|
||||
raise HTTPException(status_code=403, detail="Superuser required")
|
||||
return user
|
||||
Reference in New Issue
Block a user