diff --git a/internal/pihole/client.go b/internal/pihole/client.go index df0a4ac..72cb517 100644 --- a/internal/pihole/client.go +++ b/internal/pihole/client.go @@ -71,7 +71,11 @@ func New(rawURL string, insecureTLS bool) (*Client, error) { } func normalizeBaseURL(raw string) (string, error) { - parsed, err := url.Parse(strings.TrimSpace(raw)) + raw = strings.TrimSpace(raw) + if address := net.ParseIP(raw); address != nil && address.To4() != nil { + raw = "http://" + raw + } + parsed, err := url.Parse(raw) if err != nil || parsed.Host == "" || (parsed.Scheme != "http" && parsed.Scheme != "https") { return "", errors.New("Pi-hole-Adresse muss eine vollständige HTTP- oder HTTPS-URL sein") } diff --git a/internal/pihole/client_test.go b/internal/pihole/client_test.go index 479b02f..62a3daf 100644 --- a/internal/pihole/client_test.go +++ b/internal/pihole/client_test.go @@ -101,6 +101,10 @@ func TestNewValidatesAndNormalizesPiHoleURL(t *testing.T) { if err != nil || client.BaseURL() != "http://pihole.local/custom/api" { t.Fatalf("custom path not normalized: %q err=%v", client.BaseURL(), err) } + client, err = New("10.0.20.100", false) + if err != nil || client.BaseURL() != "http://10.0.20.100/api" { + t.Fatalf("bare IPv4 address not normalized: %q err=%v", client.BaseURL(), err) + } for _, invalid := range []string{"pi.hole", "ftp://pi.hole", "https://user:pass@pi.hole", "https://pi.hole?sid=secret"} { if _, err := New(invalid, false); err == nil { t.Errorf("invalid URL accepted: %s", invalid) diff --git a/internal/web/server_test.go b/internal/web/server_test.go index 0f917d9..0aca317 100644 --- a/internal/web/server_test.go +++ b/internal/web/server_test.go @@ -317,7 +317,7 @@ func TestPiHolePageRendersConnectionAndLocalDNSControls(t *testing.T) { t.Fatalf("render Pi-hole page: %v", err) } body := rendered.String() - for _, expected := range []string{`href="/pihole"`, `aria-current="page"`, `action="/pihole/7/records"`, `action="/pihole/7/records/update"`, `action="/pihole/7/records/archive"`, `action="/pihole/7/records/restore"`, `action="/pihole/7/records/delete"`, `action="/pihole/7/remove"`, `action="/pihole/7/delete"`, `action="/pihole/7/save"`, `action="/pihole/7/password"`, `name="active"`, `name="link_id" value="11"`, `name="insecure_tls"`, `data-dirty-form`, `data-dirty-submit disabled aria-disabled="true"`, `data-scroll-page-end`, `Anwendungspasswort anzeigen`, `Passwort entschlüsseln`, `Nur aus der WebUI entfernen`, `Anwendungspasswort`, `nas.lan`, `old.lan`, `192.168.1.20`} { + for _, expected := range []string{`href="/pihole"`, `aria-current="page"`, `action="/pihole/7/records"`, `action="/pihole/7/records/update"`, `action="/pihole/7/records/archive"`, `action="/pihole/7/records/restore"`, `action="/pihole/7/records/delete"`, `action="/pihole/7/remove"`, `action="/pihole/7/delete"`, `action="/pihole/7/save"`, `action="/pihole/7/password"`, `name="active"`, `name="link_id" value="11"`, `name="insecure_tls"`, `name="base_url" type="text"`, `data-dirty-form`, `data-dirty-submit disabled aria-disabled="true"`, `data-scroll-page-end`, `Anwendungspasswort anzeigen`, `Passwort entschlüsseln`, `Nur aus der WebUI entfernen`, `Anwendungspasswort`, `nas.lan`, `old.lan`, `192.168.1.20`} { if !strings.Contains(body, expected) { t.Errorf("Pi-hole page is missing %q", expected) } @@ -359,7 +359,7 @@ func TestPiHoleDisconnectedPageCentersConnectFormWithoutEmptyState(t *testing.T) t.Fatalf("render disconnected Pi-hole page: %v", err) } body := rendered.String() - for _, expected := range []string{`class="pihole-connect-stage"`, `class="form-panel pihole-connect-panel"`, `action="/pihole/connect"`} { + for _, expected := range []string{`class="pihole-connect-stage"`, `class="form-panel pihole-connect-panel"`, `action="/pihole/connect"`, `name="base_url" type="text"`, `10.0.20.100 oder https://pi.hole`} { if !strings.Contains(body, expected) { t.Errorf("disconnected Pi-hole page is missing %q", expected) } diff --git a/internal/web/templates/layout.html b/internal/web/templates/layout.html index 4769f31..d792729 100644 --- a/internal/web/templates/layout.html +++ b/internal/web/templates/layout.html @@ -6,8 +6,8 @@ {{.Title}} · DNS Control - - + + diff --git a/internal/web/templates/pihole.html b/internal/web/templates/pihole.html index 640d350..655d384 100644 --- a/internal/web/templates/pihole.html +++ b/internal/web/templates/pihole.html @@ -69,7 +69,7 @@

Verbindung verwalten

{{if $view.FetchError}}Nicht erreichbar{{else}}Verbunden{{end}}

Das Anwendungspasswort bleibt verschlüsselt und standardmäßig verborgen. Eine Anzeige erfordert erneut dein Admin-Passwort.

-
+
Anwendungspasswort anzeigen
@@ -82,7 +82,7 @@

Pi-hole verbinden

API v6

Verwende ein eigenes Pi-hole-Anwendungspasswort. Es wird mit dem Master-Key dieser Anwendung verschlüsselt.

-
Nur für ein selbstsigniertes Zertifikat in einem vertrauenswürdigen internen Netz verwenden. Bei HTTP wird das Passwort auf dem Netzwerkweg unverschlüsselt übertragen.
+
Nur für ein selbstsigniertes Zertifikat in einem vertrauenswürdigen internen Netz verwenden. Bei HTTP wird das Passwort auf dem Netzwerkweg unverschlüsselt übertragen.
{{end}}