Archived
153 lines
5.7 KiB
Python
153 lines
5.7 KiB
Python
from __future__ import annotations
|
|||
|
|
|
||
|
|
import sqlite3
|
||
|
|
|
||
|
|
from fastapi import APIRouter, HTTPException, Request
|
||
|
|
from fastapi.responses import HTMLResponse
|
||
|
|
from starlette.concurrency import run_in_threadpool
|
||
|
|
|
||
|
|
from ..ddns_security import client_ip, dashboard_csrf_token, require_dashboard_csrf
|
||
|
|
from ..ddns_service import normalize_domain
|
||
|
|
from ..dependencies import ServiceDep, SettingsDep, StoreDep
|
||
|
|
from ..event_statuses import (
|
||
|
|
DASHBOARD_CUSTOM_HOSTNAME_CREATED,
|
||
|
|
DASHBOARD_DOMAIN_CLAIM_CREATED,
|
||
|
|
DASHBOARD_DOMAIN_CLAIM_PENDING,
|
||
|
|
DASHBOARD_DOMAIN_CLAIM_VERIFIED,
|
||
|
|
)
|
||
|
|
from ..web.forms import first_form_value, request_form
|
||
|
|
from ..web.templates_public import _render_public_home
|
||
|
|
from .management_shared import (
|
||
|
|
get_active_management_account_async,
|
||
|
|
has_management_access,
|
||
|
|
locked_management_response,
|
||
|
|
render_management_page_async,
|
||
|
|
)
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/d/{claim_secret}", response_class=HTMLResponse, include_in_schema=False)
|
||
|
|
async def manage_domain_claim(claim_secret: str, settings: SettingsDep, store: StoreDep, service: ServiceDep) -> str:
|
||
|
|
challenge = await run_in_threadpool(store.get_domain_challenge_by_secret, claim_secret)
|
||
|
|
if not challenge:
|
||
|
|
raise HTTPException(status_code=404, detail="not found")
|
||
|
|
return await run_in_threadpool(_render_public_home, service, settings, None, None, challenge)
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/m/{management_slug}/domains/request", response_class=HTMLResponse, include_in_schema=False)
|
||
|
|
async def request_dashboard_domain(
|
||
|
|
management_slug: str,
|
||
|
|
request: Request,
|
||
|
|
settings: SettingsDep,
|
||
|
|
store: StoreDep,
|
||
|
|
service: ServiceDep,
|
||
|
|
) -> str:
|
||
|
|
account = await get_active_management_account_async(store, management_slug)
|
||
|
|
if not has_management_access(request, management_slug, account):
|
||
|
|
return locked_management_response(management_slug, account)
|
||
|
|
form = await request_form(request, settings)
|
||
|
|
require_dashboard_csrf(management_slug, account, first_form_value(form, "csrf"))
|
||
|
|
try:
|
||
|
|
challenge = await run_in_threadpool(
|
||
|
|
service.create_domain_challenge,
|
||
|
|
first_form_value(form, "domain"),
|
||
|
|
str(account["hostname"]),
|
||
|
|
)
|
||
|
|
except sqlite3.IntegrityError as exc:
|
||
|
|
raise HTTPException(status_code=409, detail="domain is already verified") from exc
|
||
|
|
await run_in_threadpool(
|
||
|
|
store.log_update_event,
|
||
|
|
str(account["hostname"]),
|
||
|
|
None,
|
||
|
|
None,
|
||
|
|
DASHBOARD_DOMAIN_CLAIM_CREATED,
|
||
|
|
"domain claim created",
|
||
|
|
client_ip(request, settings),
|
||
|
|
)
|
||
|
|
return await render_management_page_async(
|
||
|
|
service,
|
||
|
|
settings,
|
||
|
|
management_slug,
|
||
|
|
account,
|
||
|
|
dashboard_csrf_token(management_slug, account),
|
||
|
|
message="Domain claim created. Add the TXT record, then verify it.",
|
||
|
|
challenge=challenge,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/m/{management_slug}/domains/verify", response_class=HTMLResponse, include_in_schema=False)
|
||
|
|
async def verify_dashboard_domain(
|
||
|
|
management_slug: str,
|
||
|
|
request: Request,
|
||
|
|
settings: SettingsDep,
|
||
|
|
store: StoreDep,
|
||
|
|
service: ServiceDep,
|
||
|
|
) -> str:
|
||
|
|
account = await get_active_management_account_async(store, management_slug)
|
||
|
|
if not has_management_access(request, management_slug, account):
|
||
|
|
return locked_management_response(management_slug, account)
|
||
|
|
form = await request_form(request, settings)
|
||
|
|
require_dashboard_csrf(management_slug, account, first_form_value(form, "csrf"))
|
||
|
|
domain = normalize_domain(first_form_value(form, "domain"))
|
||
|
|
claim_secret = first_form_value(form, "claim_secret")
|
||
|
|
found, challenge = await run_in_threadpool(service.verify_domain, domain, claim_secret, str(account["hostname"]))
|
||
|
|
message = "Domain verified. You can now create a custom hostname." if found else "TXT record not found yet. DNS propagation can take a few minutes."
|
||
|
|
await run_in_threadpool(
|
||
|
|
store.log_update_event,
|
||
|
|
str(account["hostname"]),
|
||
|
|
None,
|
||
|
|
None,
|
||
|
|
DASHBOARD_DOMAIN_CLAIM_VERIFIED if found else DASHBOARD_DOMAIN_CLAIM_PENDING,
|
||
|
|
"domain claim verified" if found else "domain claim TXT not found",
|
||
|
|
client_ip(request, settings),
|
||
|
|
)
|
||
|
|
return await render_management_page_async(
|
||
|
|
service,
|
||
|
|
settings,
|
||
|
|
management_slug,
|
||
|
|
account,
|
||
|
|
dashboard_csrf_token(management_slug, account),
|
||
|
|
message=message,
|
||
|
|
challenge=challenge,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/m/{management_slug}/domains/hostnames", response_class=HTMLResponse, include_in_schema=False)
|
||
|
|
async def create_dashboard_custom_hostname(
|
||
|
|
management_slug: str,
|
||
|
|
request: Request,
|
||
|
|
settings: SettingsDep,
|
||
|
|
store: StoreDep,
|
||
|
|
service: ServiceDep,
|
||
|
|
) -> str:
|
||
|
|
account = await get_active_management_account_async(store, management_slug)
|
||
|
|
if not has_management_access(request, management_slug, account):
|
||
|
|
return locked_management_response(management_slug, account)
|
||
|
|
form = await request_form(request, settings)
|
||
|
|
require_dashboard_csrf(management_slug, account, first_form_value(form, "csrf"))
|
||
|
|
created = await run_in_threadpool(
|
||
|
|
service.create_custom_account,
|
||
|
|
first_form_value(form, "hostname"),
|
||
|
|
first_form_value(form, "claim_secret"),
|
||
|
|
None,
|
||
|
|
str(account["hostname"]),
|
||
|
|
)
|
||
|
|
await run_in_threadpool(
|
||
|
|
store.log_update_event,
|
||
|
|
str(account["hostname"]),
|
||
|
|
None,
|
||
|
|
None,
|
||
|
|
DASHBOARD_CUSTOM_HOSTNAME_CREATED,
|
||
|
|
"custom hostname created",
|
||
|
|
client_ip(request, settings),
|
||
|
|
)
|
||
|
|
return await render_management_page_async(
|
||
|
|
service,
|
||
|
|
settings,
|
||
|
|
management_slug,
|
||
|
|
account,
|
||
|
|
dashboard_csrf_token(management_slug, account),
|
||
|
|
message="Custom hostname created. Copy these router settings now.",
|
||
|
|
created_account=created,
|
||
|
|
)
|