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:
Davide Scaini
2026-06-03 09:36:20 +02:00
parent 75f7fa8810
commit 0e5044eb06
6 changed files with 37 additions and 365 deletions
+20 -38
View File
@@ -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")