Rebrand app to KarlDNS
No files matched your search
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 477 KiB |
@@ -1,35 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-labelledby="title">
|
||||
<title id="title">router-dyndns logo</title>
|
||||
<defs>
|
||||
<linearGradient id="navy" x1="48" x2="208" y1="52" y2="220" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#17395d"/>
|
||||
<stop offset="1" stop-color="#071727"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="blue" x1="44" x2="218" y1="72" y2="180" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#14b8ff"/>
|
||||
<stop offset="1" stop-color="#0066cc"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="30" d="M60 155a78 78 0 0 1 112-70"/>
|
||||
<path fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="30" d="M184 88a78 78 0 0 1 12 81"/>
|
||||
<path fill="#fff" d="m198 64 33 20-32 22-5-22z"/>
|
||||
<path fill="none" stroke="url(#blue)" stroke-linecap="round" stroke-linejoin="round" stroke-width="18" d="M60 155a78 78 0 0 1 112-70"/>
|
||||
<path fill="none" stroke="url(#blue)" stroke-linecap="round" stroke-linejoin="round" stroke-width="18" d="M184 88a78 78 0 0 1 12 81"/>
|
||||
<path fill="url(#blue)" d="m198 74 21 12-20 14-3-14z"/>
|
||||
<rect x="46" y="172" width="164" height="44" rx="18" fill="#fff"/>
|
||||
<rect x="56" y="181" width="144" height="26" rx="11" fill="url(#navy)"/>
|
||||
<path fill="#fff" d="M80 202h18v19a9 9 0 0 1-18 0zm78 0h18v19a9 9 0 0 1-18 0z"/>
|
||||
<circle cx="86" cy="194" r="4" fill="#fff"/>
|
||||
<circle cx="104" cy="194" r="4" fill="#fff"/>
|
||||
<circle cx="122" cy="194" r="4" fill="#fff"/>
|
||||
<circle cx="128" cy="119" r="47" fill="#fff"/>
|
||||
<circle cx="128" cy="119" r="37" fill="url(#navy)"/>
|
||||
<path fill="none" stroke="#fff" stroke-linecap="round" stroke-width="8" d="M102 94c19 6 38 18 53 35M98 132c22 8 46 6 64-12M122 83c-10 22-10 49 0 72M149 88c8 20 8 44-2 63"/>
|
||||
<circle cx="108" cy="105" r="10" fill="url(#navy)" stroke="#fff" stroke-width="7"/>
|
||||
<circle cx="148" cy="128" r="10" fill="url(#navy)" stroke="#fff" stroke-width="7"/>
|
||||
<circle cx="120" cy="148" r="9" fill="url(#navy)" stroke="#fff" stroke-width="7"/>
|
||||
<path fill="none" stroke="#fff" stroke-linecap="round" stroke-width="24" d="M91 65a53 53 0 0 1 74 0"/>
|
||||
<path fill="none" stroke="#fff" stroke-linecap="round" stroke-width="24" d="M109 86a28 28 0 0 1 38 0"/>
|
||||
<path fill="none" stroke="url(#navy)" stroke-linecap="round" stroke-width="12" d="M91 65a53 53 0 0 1 74 0"/>
|
||||
<path fill="none" stroke="url(#navy)" stroke-linecap="round" stroke-width="12" d="M109 86a28 28 0 0 1 38 0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -6,7 +6,7 @@ from .ddns import DdnsSettings, make_app
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(prog="router-dyndns")
|
||||
parser = argparse.ArgumentParser(prog="karldns")
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
render_url = subparsers.add_parser("render-fritz-url", help="Render a FRITZ!Box custom DynDNS update URL.")
|
||||
|
||||
@@ -229,7 +229,7 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI:
|
||||
await cleanup_task
|
||||
|
||||
app = FastAPI(
|
||||
title="router_dyndns DDNS",
|
||||
title="KarlDNS",
|
||||
summary="A small self-hosted DynDNS provider for FRITZ!Box routers.",
|
||||
description=(
|
||||
"Generate cryptographically random DynDNS endpoints, verify custom domains with DNS TXT "
|
||||
@@ -301,7 +301,7 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail="admin authentication required",
|
||||
headers={"WWW-Authenticate": 'Basic realm="router_dyndns-ddns"'},
|
||||
headers={"WWW-Authenticate": 'Basic realm="karldns"'},
|
||||
)
|
||||
|
||||
def apply_update(
|
||||
@@ -521,10 +521,6 @@ def make_app(settings: DdnsSettings | None = None) -> FastAPI:
|
||||
def favicon() -> FileResponse:
|
||||
return FileResponse(ASSET_DIR / "favicon.ico", media_type="image/x-icon")
|
||||
|
||||
@app.get("/logo.svg", include_in_schema=False)
|
||||
def logo_svg() -> FileResponse:
|
||||
return FileResponse(ASSET_DIR / "logo.svg", media_type="image/svg+xml")
|
||||
|
||||
@app.get("/logo.png", include_in_schema=False)
|
||||
def logo_png() -> FileResponse:
|
||||
return FileResponse(ASSET_DIR / "logo.png", media_type="image/png")
|
||||
@@ -647,13 +643,13 @@ def _render_public_home(
|
||||
message_html = _message_band(message) if message and not challenge else ""
|
||||
challenge_html = _custom_domain_flow(service, challenge, message)
|
||||
return _page(
|
||||
"router-dyndns",
|
||||
"KarlDNS",
|
||||
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.svg" alt="" width="92" height="92">
|
||||
<img class="hero-logo" src="/logo.png" alt="" width="92" height="92">
|
||||
<p class="eyebrow">Dynamic DNS for FRITZ!Box and any router</p>
|
||||
<h1>The simplest way to keep a home IP updated.</h1>
|
||||
<div class="install-pill mx-auto">
|
||||
@@ -677,7 +673,7 @@ def _render_public_home(
|
||||
<p class="section-copy">The generated URL is the secret. FRITZ!Box replaces <code><ipaddr></code> and calls it when your public IP changes.</p>
|
||||
<div class="terminal-card mt-4" aria-hidden="true">
|
||||
<div class="terminal-dots"><span></span><span></span><span></span></div>
|
||||
<code>$ curl -sS 'https://ddns.example.net/u/<secret>?myip=203.0.113.10'</code>
|
||||
<code>$ curl -sS 'https://karldns.de/u/<secret>?myip=203.0.113.10'</code>
|
||||
<code>good 203.0.113.10</code>
|
||||
</div>
|
||||
</div>
|
||||
@@ -698,9 +694,9 @@ def _render_public_home(
|
||||
<div class="terminal-card text-start mt-4">
|
||||
<div class="terminal-dots"><span></span><span></span><span></span></div>
|
||||
<code># explicit IPv4</code>
|
||||
<code>curl -sS 'https://ddns.example.net/u/<secret>?myip=203.0.113.10'</code>
|
||||
<code>curl -sS 'https://karldns.de/u/<secret>?myip=203.0.113.10'</code>
|
||||
<code># source IP fallback</code>
|
||||
<code>curl -sS 'https://ddns.example.net/u/<secret>'</code>
|
||||
<code>curl -sS 'https://karldns.de/u/<secret>'</code>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -727,7 +723,7 @@ def _top_nav(label: str | None = None, links: str = "") -> str:
|
||||
<a class="skip-link" href="#main">Skip to content</a>
|
||||
<nav class="navbar navbar-expand-sm sticky-top navbar-blur border-bottom" aria-label="Main navigation">
|
||||
<div class="container">
|
||||
<a class="navbar-brand brand" href="/"><img src="/logo.svg" alt="" width="28" height="28">router-dyndns</a>
|
||||
<a class="navbar-brand brand" href="/"><img src="/logo.png" alt="" width="28" height="28">KarlDNS</a>
|
||||
<div class="navbar-nav ms-auto flex-row align-items-center gap-2 gap-sm-3">
|
||||
{links}
|
||||
{account_html}
|
||||
@@ -806,7 +802,7 @@ def _custom_domain_flow(service: DdnsService, challenge: dict[str, str | None] |
|
||||
<div>
|
||||
<p class="eyebrow">Direct custom-domain publishing</p>
|
||||
<h2>Verify DNS ownership</h2>
|
||||
<p class="section-copy">Use this only when RouterPulse should publish A/AAAA records directly inside your domain. If you just want your own subdomain, generate a hostname above and create a CNAME to it.</p>
|
||||
<p class="section-copy">Use this only when KarlDNS should publish A/AAAA records directly inside your domain. If you just want your own subdomain, generate a hostname above and create a CNAME to it.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3 mt-4">
|
||||
@@ -924,7 +920,7 @@ def _manual_update_panel(commands: str) -> str:
|
||||
<div class="card card-body gap-3 mt-4">
|
||||
<div>
|
||||
<h3>Manual updates</h3>
|
||||
<p class="section-copy">FRITZ!Box replaces <code><ipaddr></code> and <code><ip6addr></code>, then sends a GET request to the Update-URL. Scripts and other routers can do the same with curl. If no IP parameter is sent, RouterPulse uses the request source IP.</p>
|
||||
<p class="section-copy">FRITZ!Box replaces <code><ipaddr></code> and <code><ip6addr></code>, then sends a GET request to the Update-URL. Scripts and other routers can do the same with curl. If no IP parameter is sent, KarlDNS uses the request source IP.</p>
|
||||
</div>
|
||||
<pre class="manual-code mb-0"><code>{safe_commands}</code></pre>
|
||||
{_copy_button("Copy curl examples", commands)}
|
||||
@@ -1316,7 +1312,6 @@ def _page(title: str, body: str) -> str:
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{html.escape(title)}</title>
|
||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||
<link rel="icon" href="/logo.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/logo.png">
|
||||
<script src="/app.js" defer></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
|
||||
@@ -16,7 +16,7 @@ class DdnsSettings(BaseModel):
|
||||
public_base_url: str = Field(default="http://localhost:8080")
|
||||
trusted_hosts: set[str] = Field(default_factory=set)
|
||||
hostname_suffix: str = Field(default="")
|
||||
verification_prefix: str = Field(default="_router_dyndns-ddns")
|
||||
verification_prefix: str = Field(default="_karldns")
|
||||
rate_limit_per_minute: int = Field(default=60, ge=1, le=10_000)
|
||||
admin_rate_limit_per_minute: int = Field(default=20, ge=1, le=10_000)
|
||||
max_request_body_bytes: int = Field(default=16_384, ge=1024, le=1_048_576)
|
||||
@@ -85,7 +85,7 @@ class DdnsSettings(BaseModel):
|
||||
public_base_url=os.getenv("DDNS_PUBLIC_BASE_URL", "http://localhost:8080"),
|
||||
trusted_hosts=trusted_hosts,
|
||||
hostname_suffix=os.getenv("DDNS_HOSTNAME_SUFFIX", ""),
|
||||
verification_prefix=os.getenv("DDNS_VERIFICATION_PREFIX", "_router_dyndns-ddns"),
|
||||
verification_prefix=os.getenv("DDNS_VERIFICATION_PREFIX", "_karldns"),
|
||||
rate_limit_per_minute=_env_int("DDNS_RATE_LIMIT_PER_MINUTE", 60),
|
||||
admin_rate_limit_per_minute=_env_int("DDNS_ADMIN_RATE_LIMIT_PER_MINUTE", 20),
|
||||
max_request_body_bytes=_env_int("DDNS_MAX_REQUEST_BODY_BYTES", 16_384),
|
||||
|
||||
@@ -160,7 +160,7 @@ class DdnsService:
|
||||
return None
|
||||
|
||||
def verification_name(self, domain: str) -> str:
|
||||
prefix = self.settings.verification_prefix.strip().strip(".") or "_router_dyndns-ddns"
|
||||
prefix = self.settings.verification_prefix.strip().strip(".") or "_karldns"
|
||||
return f"{prefix}.{domain}"
|
||||
|
||||
def hostname_is_publishable(self, hostname: str) -> bool:
|
||||
|
||||