From 6a7491b15bbe3a710f4e01a22bb4ed067a88d3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= Date: Tue, 30 Dec 2025 13:50:13 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20model=20rework=20for=20"Credenti?= =?UTF-8?q?als"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit affects: - environment vars/api.conf: "WEBDAV__USERNAME" -> "WEBDAV__AUTH__USERNAME" and "WEBDAV__PASSWORD" -> "WEBDAV__AUTH__PASSWORD" - remote config.toml: "[admin] name" -> "[admin] username" --- api/advent22_api/core/config.py | 9 ++----- api/advent22_api/core/dav/webdav.py | 4 +-- api/advent22_api/core/settings.py | 11 ++++++-- api/advent22_api/routers/_security.py | 2 +- api/advent22_api/routers/admin.py | 36 ++++++++++++-------------- ui/src/components/admin/ConfigView.vue | 34 ++++++++++++++---------- ui/src/lib/api.ts | 14 ++++++---- ui/src/lib/model.ts | 5 +++- ui/src/lib/store.ts | 4 +-- 9 files changed, 66 insertions(+), 53 deletions(-) diff --git a/api/advent22_api/core/config.py b/api/advent22_api/core/config.py index 8811661..03c1730 100644 --- a/api/advent22_api/core/config.py +++ b/api/advent22_api/core/config.py @@ -4,15 +4,10 @@ from markdown import markdown from pydantic import BaseModel, ConfigDict, field_validator from .dav.webdav import WebDAV -from .settings import SETTINGS +from .settings import SETTINGS, Credentials from .transformed_string import TransformedString -class User(BaseModel): - name: str - password: str - - class Site(BaseModel): model_config = ConfigDict(validate_default=True) @@ -60,7 +55,7 @@ class Image(BaseModel): class Config(BaseModel): # Login-Daten für Admin-Modus - admin: User + admin: Credentials # Lösungswort solution: TransformedString diff --git a/api/advent22_api/core/dav/webdav.py b/api/advent22_api/core/dav/webdav.py index 2e60a16..a5d8b67 100644 --- a/api/advent22_api/core/dav/webdav.py +++ b/api/advent22_api/core/dav/webdav.py @@ -16,8 +16,8 @@ class WebDAV: _webdav_client = WebDAVclient( { "webdav_hostname": SETTINGS.webdav.url, - "webdav_login": SETTINGS.webdav.username, - "webdav_password": SETTINGS.webdav.password, + "webdav_login": SETTINGS.webdav.auth.username, + "webdav_password": SETTINGS.webdav.auth.password, } ) diff --git a/api/advent22_api/core/settings.py b/api/advent22_api/core/settings.py index 2a4ffc9..d0d2408 100644 --- a/api/advent22_api/core/settings.py +++ b/api/advent22_api/core/settings.py @@ -6,6 +6,11 @@ from pydantic_settings import BaseSettings, SettingsConfigDict T = TypeVar("T") +class Credentials(BaseModel): + username: str = "" + password: str = "" + + class DavSettings(BaseModel): """ Connection to a DAV server. @@ -16,8 +21,10 @@ class DavSettings(BaseModel): path: str = "/remote.php/webdav" prefix: str = "/advent22" - username: str = "advent22_user" - password: str = "password" + auth: Credentials = Credentials( + username="advent22_user", + password="password", + ) cache_ttl: int = 60 * 10 config_filename: str = "config.toml" diff --git a/api/advent22_api/routers/_security.py b/api/advent22_api/routers/_security.py index 6a6eb81..47e14c1 100644 --- a/api/advent22_api/routers/_security.py +++ b/api/advent22_api/routers/_security.py @@ -21,7 +21,7 @@ async def user_is_admin( username_correct = secrets.compare_digest( credentials.username.lower(), - cfg.admin.name.lower(), + cfg.admin.username.lower(), ) password_correct = secrets.compare_digest( credentials.password, diff --git a/api/advent22_api/routers/admin.py b/api/advent22_api/routers/admin.py index ee5bb4b..cc7fd8a 100644 --- a/api/advent22_api/routers/admin.py +++ b/api/advent22_api/routers/admin.py @@ -5,7 +5,11 @@ from pydantic import BaseModel from advent22_api.core.helpers import EventDates -from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config +from ..core.calendar_config import ( + CalendarConfig, + DoorsSaved, + get_calendar_config, +) from ..core.config import Config, Image, get_config from ..core.depends import ( TTFont, @@ -14,7 +18,7 @@ from ..core.depends import ( get_all_parts, get_all_ttfonts, ) -from ..core.settings import SETTINGS, RedisSettings +from ..core.settings import SETTINGS, Credentials, RedisSettings from ._security import require_admin, user_is_admin router = APIRouter(prefix="/admin", tags=["admin"]) @@ -170,24 +174,16 @@ async def put_doors( await cal_cfg.change(cfg) -@router.get("/dav_credentials") -async def get_dav_credentials( - _: None = Depends(require_admin), -) -> tuple[str, str]: - """ - Zugangsdaten für WebDAV - """ - - return SETTINGS.webdav.username, SETTINGS.webdav.password - - -@router.get("/ui_credentials") -async def get_ui_credentials( +@router.get("/credentials/{name}") +async def get_credentials( + name: str, _: None = Depends(require_admin), cfg: Config = Depends(get_config), -) -> tuple[str, str]: - """ - Zugangsdaten für Admin-UI - """ +) -> Credentials: - return cfg.admin.name, cfg.admin.password + if name == "dav": + return SETTINGS.webdav.auth + elif name == "ui": + return cfg.admin + else: + return Credentials() diff --git a/ui/src/components/admin/ConfigView.vue b/ui/src/components/admin/ConfigView.vue index 2e214a7..e0eb483 100644 --- a/ui/src/components/admin/ConfigView.vue +++ b/ui/src/components/admin/ConfigView.vue @@ -140,14 +140,14 @@
Zugangsdaten
user - {{ creds.dav[0] }} + {{ creds.dav.username }}
pass - {{ creds.dav[1] }} + {{ creds.dav.password }}
@@ -171,14 +171,14 @@
UI-Admin
user - {{ creds.ui[0] }} + {{ creds.ui.username }}
pass - {{ creds.ui[1] }} + {{ creds.ui.password }}
@@ -244,8 +244,14 @@ const admin_config_model = ref({ const doors = ref([]); const creds = ref>({ - dav: ["", ""], - ui: ["", ""], + dav: { + username: "", + password: "", + }, + ui: { + username: "", + password: "", + }, }); function fmt_puzzle_date(name: keyof AdminConfigModel["puzzle"]): string { @@ -265,7 +271,9 @@ async function on_open(): Promise { void store_update; // discard value admin_config_model.value = new_admin_config_model; doors.value = new_doors; - creds.value = { dav: ["", ""], ui: ["", ""] }; + + clear_credentials(creds.value.dav); + clear_credentials(creds.value.ui); } async function load_credentials( @@ -275,14 +283,14 @@ async function load_credentials( try { const new_creds = await API.request(endpoint); - creds[0] = new_creds[0]; - creds[1] = new_creds[1]; + creds.username = new_creds.username; + creds.password = new_creds.password; } catch {} } function clear_credentials(creds: Credentials): void { - creds[0] = ""; - creds[1] = ""; + creds.username = ""; + creds.password = ""; } diff --git a/ui/src/lib/api.ts b/ui/src/lib/api.ts index 3ab2270..ea9c7ce 100644 --- a/ui/src/lib/api.ts +++ b/ui/src/lib/api.ts @@ -44,12 +44,16 @@ export class API { } public static get creds(): AxiosBasicCredentials { - const auth_json = localStorage.getItem(this.creds_key); - if (auth_json !== null) { - return JSON.parse(auth_json); - } else { - return { username: "", password: "" }; + const stored_auth = JSON.parse(localStorage.getItem(this.creds_key) ?? ""); + if ( + stored_auth !== null && + Object.hasOwn(stored_auth, "username") && + Object.hasOwn(stored_auth, "password") + ) { + return stored_auth; } + + return { username: "", password: "" }; } private static get_axios_config({ diff --git a/ui/src/lib/model.ts b/ui/src/lib/model.ts index 6f24170..44b684e 100644 --- a/ui/src/lib/model.ts +++ b/ui/src/lib/model.ts @@ -64,4 +64,7 @@ export interface ImageData { data_url: string; } -export type Credentials = [username: string, password: string]; +export interface Credentials { + username: string; + password: string; +} diff --git a/ui/src/lib/store.ts b/ui/src/lib/store.ts index c1150d1..6c9de5f 100644 --- a/ui/src/lib/store.ts +++ b/ui/src/lib/store.ts @@ -111,12 +111,12 @@ export const advent22Store = defineStore({ }, async login(creds: Credentials): Promise { - API.creds = { username: creds[0], password: creds[1] }; + API.creds = creds; return await this.update_is_admin(); }, logout() { - API.creds = { username: "", password: "" }; + API.creds = null; this.is_admin = false; },