Archived
134 lines
7.2 KiB
Python
134 lines
7.2 KiB
Python
from __future__ import annotations
|
|||
|
|
|
||
|
|
from ..ddns_models import DdnsSettings
|
||
|
|
from ..ddns_service import DdnsService
|
||
|
|
from .html_utils import escape, trusted
|
||
|
|
from .templates import _message_band, _page, _top_nav
|
||
|
|
from .templates_public_sections import _credentials_panel, _custom_domain_flow, _linux_installer_section
|
||
|
|
|
||
|
|
|
||
|
|
def _render_public_home(
|
||
|
|
service: DdnsService,
|
||
|
|
settings: DdnsSettings,
|
||
|
|
created_account: dict[str, str] | None,
|
||
|
|
message: str | None,
|
||
|
|
challenge: dict[str, str | None] | None = None,
|
||
|
|
) -> str:
|
||
|
|
suffix = escape(settings.hostname_suffix or "your DynDNS domain")
|
||
|
|
demo_update_url = escape(f"{settings.public_base_url.rstrip('/')}/u/<secret>?myip=<ipaddr>")
|
||
|
|
created_html = _credentials_panel(service, created_account)
|
||
|
|
message_html = _message_band(message) if message and not challenge else ""
|
||
|
|
challenge_html = _custom_domain_flow(service, challenge, message)
|
||
|
|
return _page(
|
||
|
|
"KarlDNS",
|
||
|
|
trusted(f"""
|
||
|
|
<main id="main">
|
||
|
|
{_top_nav()}
|
||
|
|
<section class="hero-band">
|
||
|
|
<div class="container text-center d-grid justify-items-center gap-3">
|
||
|
|
<img class="hero-logo" src="/logo.png" alt="" width="80" height="80">
|
||
|
|
<h1>KarlDNS for home routers.</h1>
|
||
|
|
<div class="install-pill mx-auto">
|
||
|
|
<code>{demo_update_url}</code>
|
||
|
|
</div>
|
||
|
|
<p class="lead">Generate one secret update URL under {suffix}. Paste it into your router, script it with curl, or point your own subdomain at it with a CNAME.</p>
|
||
|
|
<div class="d-flex gap-2 flex-wrap justify-content-center mt-2">
|
||
|
|
<a class="btn btn-primary rounded-pill" href="#create">Generate hostname</a>
|
||
|
|
<a class="btn btn-outline-primary rounded-pill" href="#manual-updates">See curl flow</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
{message_html}
|
||
|
|
{created_html}
|
||
|
|
<section class="section" id="create">
|
||
|
|
<div class="container narrow">
|
||
|
|
<div class="text-center mb-4">
|
||
|
|
<p class="eyebrow">Choose your hostname</p>
|
||
|
|
<h2>No account. No login.</h2>
|
||
|
|
<p class="section-copy mx-auto">Use a generated KarlDNS hostname immediately, or verify your own domain with a DNS TXT record.</p>
|
||
|
|
</div>
|
||
|
|
<div class="row g-4 align-items-stretch">
|
||
|
|
<div class="col-lg-6">
|
||
|
|
<div class="card card-body h-100 gap-3">
|
||
|
|
<p class="eyebrow">Use our domain</p>
|
||
|
|
<h3>Generate a KarlDNS hostname</h3>
|
||
|
|
<p class="section-copy mb-0">KarlDNS generates the hostname, secret update URL, and optional router compatibility credentials automatically.</p>
|
||
|
|
<form method="post" action="/magic" class="d-grid gap-3" aria-label="Create a generated DynDNS hostname">
|
||
|
|
<button type="submit" class="btn btn-primary rounded-pill">Generate hostname</button>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="col-lg-6">
|
||
|
|
<div class="card card-body h-100 gap-3">
|
||
|
|
<p class="eyebrow">Use your own domain</p>
|
||
|
|
<h3>Verify DNS ownership</h3>
|
||
|
|
<p class="section-copy mb-0">Add one TXT record so KarlDNS can confirm you control the domain before it publishes A/AAAA records there.</p>
|
||
|
|
<form method="post" action="/request-domain" class="d-grid gap-3" aria-label="Request a custom domain TXT challenge">
|
||
|
|
<label>Domain
|
||
|
|
<input class="form-control" name="domain" placeholder="example.com" autocomplete="off" autocapitalize="none" spellcheck="false" required>
|
||
|
|
</label>
|
||
|
|
<button type="submit" class="btn btn-primary rounded-pill">Create TXT challenge</button>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="terminal-card mt-4" aria-hidden="true">
|
||
|
|
<code>$ curl -sS 'https://karldns.de/u/<secret>?myip=203.0.113.10'</code>
|
||
|
|
<code>good 203.0.113.10</code>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
<section class="section" id="manual-updates">
|
||
|
|
<div class="container narrow text-center">
|
||
|
|
<h2>Update from anything that can send GET.</h2>
|
||
|
|
<p class="lead mx-auto mt-3">Use FRITZ!Box placeholders, curl, cron, Home Assistant, OpenWrt, pfSense, OPNsense, UniFi, MikroTik, or your own automation.</p>
|
||
|
|
<div class="terminal-card text-start mt-4">
|
||
|
|
<code># explicit IPv4</code>
|
||
|
|
<code>curl -sS 'https://karldns.de/u/<secret>?myip=203.0.113.10'</code>
|
||
|
|
<code># source IP fallback</code>
|
||
|
|
<code>curl -sS 'https://karldns.de/u/<secret>'</code>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
{_linux_installer_section()}
|
||
|
|
{challenge_html}
|
||
|
|
</main>
|
||
|
|
"""),
|
||
|
|
)
|
||
|
|
|
||
|
|
def _render_privacy_page() -> str:
|
||
|
|
return _page(
|
||
|
|
"Legal and Privacy",
|
||
|
|
trusted(f"""
|
||
|
|
<main id="main">
|
||
|
|
{_top_nav()}
|
||
|
|
<section class="hero-band compact">
|
||
|
|
<div class="container text-center d-grid justify-items-center gap-3">
|
||
|
|
<p class="eyebrow">Legal and privacy</p>
|
||
|
|
<h1>KarlDNS keeps accountless DynDNS simple.</h1>
|
||
|
|
<p class="lead">This page explains the basic data handled by this self-hosted service. Configure your own imprint, controller details, and jurisdiction-specific terms before offering it publicly.</p>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
<section class="section">
|
||
|
|
<div class="container narrow d-grid gap-4">
|
||
|
|
<div>
|
||
|
|
<h2>Data processed</h2>
|
||
|
|
<p class="section-copy">KarlDNS stores generated hostnames, public DNS target names, update slugs, hashed management tokens, hashed router passwords, DNS TXT verification challenges, IP update history, timestamps, and operational events needed to run Dynamic DNS.</p>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<h2>Secrets</h2>
|
||
|
|
<p class="section-copy">Private management links, update URLs, router passwords, and one-box update URLs are bearer secrets. Anyone with them can update or manage the related hostname. Passwords and management lookup values are not stored in recoverable plaintext.</p>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<h2>Logs and retention</h2>
|
||
|
|
<p class="section-copy">The service keeps recent update events for troubleshooting and runs cleanup jobs for abandoned setup flows and unused hostnames. Server and reverse-proxy logs may also contain IP addresses and request metadata depending on your deployment.</p>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<h2>Contact</h2>
|
||
|
|
<p class="section-copy">For the public KarlDNS instance, contact Karl through <a href="https://karl.fail" rel="noopener">karl.fail</a> or <a href="https://karlcom.de" rel="noopener">karlcom.de</a>.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
</main>
|
||
|
|
"""),
|
||
|
|
)
|