Complete admin package restructuring

This commit is contained in:
2025-05-10 08:28:15 +02:00
parent 4f970a3f71
commit 0a427b6a91
80 changed files with 1282 additions and 843 deletions

View File

@ -0,0 +1,181 @@
#!/usr/bin/env python3
# pyright: reportUnusedFunction=false
import logging
import secrets as pysecrets
from typing import Annotated, Any
from fastapi import APIRouter, Depends, Form, Request
from pydantic import BaseModel, BeforeValidator, Field
from sshecret_admin.auth import User
from sshecret_admin.services import AdminBackend
from ..dependencies import FrontendDependencies
LOG = logging.getLogger(__name__)
def split_clients(clients: Any) -> Any: # pyright: ignore[reportAny]
"""Split clients."""
if isinstance(clients, list):
return clients # pyright: ignore[reportUnknownVariableType]
if not isinstance(clients, str):
raise ValueError("Invalid type for clients.")
if not clients:
return []
return [client.rstrip() for client in clients.split(",")]
def handle_select_bool(value: Any) -> Any: # pyright: ignore[reportAny]
"""Handle boolean from select."""
if isinstance(value, bool):
return value
if value == "on":
return True
if value == "off":
return False
class CreateSecret(BaseModel):
"""Create secret model."""
name: str
value: str | None = None
auto_generate: Annotated[bool, BeforeValidator(handle_select_bool)] = False
clients: Annotated[list[str], BeforeValidator(split_clients)] = Field(
default_factory=list
)
def create_router(dependencies: FrontendDependencies) -> APIRouter:
"""Create secrets router."""
app = APIRouter()
templates = dependencies.templates
@app.get("/secrets/")
async def get_secrets(
request: Request,
current_user: Annotated[User, Depends(dependencies.get_user_from_access_token)],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
):
"""Get secrets index page."""
secrets = await admin.get_detailed_secrets()
clients = await admin.get_clients()
return templates.TemplateResponse(
request,
"secrets/index.html.j2",
{
"page_title": "Secrets",
"secrets": secrets,
"user": current_user.username,
"clients": clients,
},
)
@app.post("/secrets/")
async def add_secret(
request: Request,
_current_user: Annotated[
User, Depends(dependencies.get_user_from_access_token)
],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
secret: Annotated[CreateSecret, Form()],
):
"""Add secret."""
LOG.info("secret: %s", secret.model_dump_json(indent=2))
clients = await admin.get_clients()
if secret.value:
value = secret.value
else:
value = pysecrets.token_urlsafe(32)
await admin.add_secret(secret.name, value, secret.clients)
secrets = await admin.get_detailed_secrets()
return templates.TemplateResponse(
request,
"secrets/inner.html.j2",
{
"secrets": secrets,
"clients": clients,
},
)
@app.delete("/secrets/{name}/clients/{id}")
async def remove_client_secret_access(
request: Request,
name: str,
id: str,
_current_user: Annotated[
User, Depends(dependencies.get_user_from_access_token)
],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
):
"""Remove a client's access to a secret."""
await admin.delete_client_secret(id, name)
clients = await admin.get_clients()
secrets = await admin.get_detailed_secrets()
headers = {"Hx-Refresh": "true"}
return templates.TemplateResponse(
request,
"secrets/inner.html.j2",
{"clients": clients, "secret": secrets},
headers=headers,
)
@app.post("/secrets/{name}/clients/")
async def add_secret_to_client(
request: Request,
name: str,
client: Annotated[str, Form()],
_current_user: Annotated[
User, Depends(dependencies.get_user_from_access_token)
],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
):
"""Add a secret to a client."""
await admin.create_client_secret(client, name)
clients = await admin.get_clients()
secrets = await admin.get_detailed_secrets()
headers = {"Hx-Refresh": "true"}
return templates.TemplateResponse(
request,
"secrets/inner.html.j2",
{
"clients": clients,
"secrets": secrets,
},
headers=headers,
)
@app.delete("/secrets/{name}")
async def delete_secret(
request: Request,
name: str,
_current_user: Annotated[
User, Depends(dependencies.get_user_from_access_token)
],
admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)],
):
"""Delete a secret."""
await admin.delete_secret(name)
clients = await admin.get_clients()
secrets = await admin.get_detailed_secrets()
headers = {"Hx-Refresh": "true"}
return templates.TemplateResponse(
request,
"secrets/inner.html.j2",
{
"clients": clients,
"secrets": secrets,
},
headers=headers,
)
return app