Archived
Build KarlDNS self-hosted DynDNS service
This commit is contained in:
1 parent
45bc38d950
commit
ca92dc211a
65 files changed
+9200
-3570
No files matched your search
@@ -0,0 +1,123 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import HTTPException, Request, Response
|
||||
from fastapi.responses import HTMLResponse
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
|
||||
from ..ddns_models import DdnsSettings
|
||||
from ..ddns_security import (
|
||||
DASHBOARD_UNLOCK_COOKIE,
|
||||
dashboard_csrf_token,
|
||||
sign_dashboard_unlock_cookie,
|
||||
verify_dashboard_unlock_cookie,
|
||||
)
|
||||
from ..ddns_service import DdnsService
|
||||
from ..ddns_store import DdnsStore
|
||||
from ..store.types import AccountRow
|
||||
from ..web.templates_management import _render_management_page, _render_management_unlock_page
|
||||
|
||||
ManagementAccount = AccountRow
|
||||
|
||||
|
||||
def get_active_management_account(store: DdnsStore, management_slug: str) -> ManagementAccount:
|
||||
account = store.get_account_by_management_slug(management_slug)
|
||||
if not account or account["disabled"]:
|
||||
raise HTTPException(status_code=404, detail="not found")
|
||||
return account
|
||||
|
||||
|
||||
async def get_active_management_account_async(store: DdnsStore, management_slug: str) -> ManagementAccount:
|
||||
return await run_in_threadpool(get_active_management_account, store, management_slug)
|
||||
|
||||
|
||||
def has_management_access(request: Request, management_slug: str, account: ManagementAccount) -> bool:
|
||||
password_hash = account.get("dashboard_password_hash")
|
||||
if not password_hash:
|
||||
return True
|
||||
return verify_dashboard_unlock_cookie(
|
||||
str(account["hostname"]),
|
||||
management_slug,
|
||||
str(password_hash),
|
||||
request.cookies.get(DASHBOARD_UNLOCK_COOKIE),
|
||||
)
|
||||
|
||||
|
||||
def locked_management_response(management_slug: str, account: ManagementAccount) -> HTMLResponse:
|
||||
return HTMLResponse(_render_management_unlock_page(management_slug, account, dashboard_csrf_token(management_slug, account)), status_code=401)
|
||||
|
||||
|
||||
def management_error_response(
|
||||
service: DdnsService,
|
||||
settings: DdnsSettings,
|
||||
management_slug: str,
|
||||
account: ManagementAccount,
|
||||
message: str,
|
||||
) -> HTMLResponse:
|
||||
return HTMLResponse(
|
||||
_render_management_page(service, settings, management_slug, account, dashboard_csrf_token(management_slug, account), message=message),
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
|
||||
async def management_error_response_async(
|
||||
service: DdnsService,
|
||||
settings: DdnsSettings,
|
||||
management_slug: str,
|
||||
account: ManagementAccount,
|
||||
message: str,
|
||||
) -> HTMLResponse:
|
||||
return await run_in_threadpool(management_error_response, service, settings, management_slug, account, message)
|
||||
|
||||
|
||||
async def render_management_page_async(
|
||||
service: DdnsService,
|
||||
settings: DdnsSettings,
|
||||
management_slug: str,
|
||||
account: ManagementAccount,
|
||||
csrf_token: str,
|
||||
message: str | None = None,
|
||||
challenge: dict[str, str | None] | None = None,
|
||||
created_account: dict[str, str] | None = None,
|
||||
) -> str:
|
||||
return await run_in_threadpool(
|
||||
_render_management_page,
|
||||
service,
|
||||
settings,
|
||||
management_slug,
|
||||
account,
|
||||
csrf_token,
|
||||
message,
|
||||
challenge,
|
||||
created_account,
|
||||
)
|
||||
|
||||
|
||||
def set_unlock_cookie(
|
||||
response: Response,
|
||||
settings: DdnsSettings,
|
||||
management_slug: str,
|
||||
account: ManagementAccount,
|
||||
max_age_seconds: int,
|
||||
) -> None:
|
||||
password_hash = account.get("dashboard_password_hash")
|
||||
if not password_hash:
|
||||
return
|
||||
response.set_cookie(
|
||||
DASHBOARD_UNLOCK_COOKIE,
|
||||
sign_dashboard_unlock_cookie(str(account["hostname"]), management_slug, str(password_hash), max_age_seconds),
|
||||
max_age=max_age_seconds,
|
||||
path=f"/m/{management_slug}",
|
||||
httponly=True,
|
||||
samesite="lax",
|
||||
secure=settings.public_base_url.startswith("https://"),
|
||||
)
|
||||
|
||||
|
||||
def delete_unlock_cookie(response: Response, management_slug: str) -> None:
|
||||
response.delete_cookie(DASHBOARD_UNLOCK_COOKIE, path=f"/m/{management_slug}", httponly=True, samesite="lax")
|
||||
|
||||
|
||||
def unlock_cookie_seconds(settings: DdnsSettings, stay_unlocked: str) -> int:
|
||||
if stay_unlocked:
|
||||
return settings.dashboard_stay_unlocked_seconds
|
||||
return settings.dashboard_unlock_seconds
|
||||
Reference in new issue
Block a user