fix: close all bincio-auth migration holes
Pages (register, reset-password, invites) now redirect to bincio.org like login already did. Admin user-state ops (reset-password-code, suspend, unsuspend, delete account) are proxied to bincio-auth via httpx so they write to the correct DB. Adds BINCIO_AUTH_API env var.
This commit is contained in:
@@ -9,10 +9,22 @@ import threading
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, Cookie, HTTPException, Request
|
||||
from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
|
||||
|
||||
from bincio.serve import deps, tasks
|
||||
|
||||
|
||||
async def _auth_proxy(method: str, path: str, cookie: str | None) -> JSONResponse:
|
||||
"""Forward a user-state admin request to bincio-auth and relay the response."""
|
||||
if not deps.auth_api:
|
||||
raise HTTPException(503, "User management is handled by bincio-auth but BINCIO_AUTH_API is not configured.")
|
||||
url = f"{deps.auth_api}{path}"
|
||||
cookies = {"bincio_session": cookie} if cookie else {}
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.request(method, url, cookies=cookies)
|
||||
return JSONResponse(r.json(), status_code=r.status_code)
|
||||
from bincio.serve.models import ResetPasswordCodeResponse
|
||||
from bincio.serve.db import (
|
||||
User,
|
||||
@@ -152,14 +164,8 @@ async def admin_reset_password_code(
|
||||
handle: str,
|
||||
bincio_session: str | None = Cookie(default=None),
|
||||
) -> JSONResponse:
|
||||
"""Generate a one-time password reset code for a user. Admin only."""
|
||||
from bincio.serve.db import create_reset_code
|
||||
admin = deps._require_admin(bincio_session)
|
||||
db = deps._get_db()
|
||||
if not get_user(db, handle):
|
||||
raise HTTPException(404, f"User '{handle}' not found")
|
||||
code = create_reset_code(db, handle, admin.handle)
|
||||
return JSONResponse({"ok": True, "code": code, "expires_in_hours": 24})
|
||||
"""Generate a one-time password reset code for a user. Proxied to bincio-auth."""
|
||||
return await _auth_proxy("POST", f"/api/admin/users/{handle}/reset-password-code", bincio_session)
|
||||
|
||||
|
||||
@router.post("/api/admin/users/{handle}/suspend")
|
||||
@@ -167,18 +173,8 @@ async def admin_suspend(
|
||||
handle: str,
|
||||
bincio_session: str | None = Cookie(default=None),
|
||||
) -> JSONResponse:
|
||||
"""Suspend a user account. Blocks login and invalidates existing sessions. Admin only."""
|
||||
from bincio.serve.db import set_suspended, purge_expired_sessions
|
||||
admin = deps._require_admin(bincio_session)
|
||||
if handle == admin.handle:
|
||||
raise HTTPException(400, "Cannot suspend yourself")
|
||||
db = deps._get_db()
|
||||
if not get_user(db, handle):
|
||||
raise HTTPException(404, "User not found")
|
||||
set_suspended(db, handle, True)
|
||||
db.execute("DELETE FROM sessions WHERE handle = ?", (handle,))
|
||||
db.commit()
|
||||
return JSONResponse({"status": "suspended", "handle": handle})
|
||||
"""Suspend a user account. Proxied to bincio-auth."""
|
||||
return await _auth_proxy("POST", f"/api/admin/users/{handle}/suspend", bincio_session)
|
||||
|
||||
|
||||
@router.post("/api/admin/users/{handle}/unsuspend")
|
||||
@@ -186,14 +182,8 @@ async def admin_unsuspend(
|
||||
handle: str,
|
||||
bincio_session: str | None = Cookie(default=None),
|
||||
) -> JSONResponse:
|
||||
"""Re-enable a suspended user account. Admin only."""
|
||||
from bincio.serve.db import set_suspended
|
||||
deps._require_admin(bincio_session)
|
||||
db = deps._get_db()
|
||||
if not get_user(db, handle):
|
||||
raise HTTPException(404, "User not found")
|
||||
set_suspended(db, handle, False)
|
||||
return JSONResponse({"status": "unsuspended", "handle": handle})
|
||||
"""Re-enable a suspended user account. Proxied to bincio-auth."""
|
||||
return await _auth_proxy("POST", f"/api/admin/users/{handle}/unsuspend", bincio_session)
|
||||
|
||||
|
||||
@router.delete("/api/admin/users/{handle}/account")
|
||||
@@ -201,16 +191,8 @@ async def admin_delete_account(
|
||||
handle: str,
|
||||
bincio_session: str | None = Cookie(default=None),
|
||||
) -> JSONResponse:
|
||||
"""Delete a user account from the database. Data directory is NOT removed. Admin only."""
|
||||
from bincio.serve.db import delete_user as _delete_user
|
||||
admin = deps._require_admin(bincio_session)
|
||||
if handle == admin.handle:
|
||||
raise HTTPException(400, "Cannot delete your own account")
|
||||
db = deps._get_db()
|
||||
if not get_user(db, handle):
|
||||
raise HTTPException(404, "User not found")
|
||||
_delete_user(db, handle)
|
||||
return JSONResponse({"status": "deleted", "handle": handle})
|
||||
"""Delete a user account. Proxied to bincio-auth."""
|
||||
return await _auth_proxy("DELETE", f"/api/admin/users/{handle}/account", bincio_session)
|
||||
|
||||
|
||||
@router.post("/api/admin/users/{handle}/rebuild")
|
||||
|
||||
Reference in New Issue
Block a user