Initial commit
CalDAV and CardDAV checkers sharing a single Go module. Discovery follows RFC 6764 (/.well-known + SRV/TXT), authenticated probes cover principal, home-set, collections and a minimal REPORT query on top of go-webdav. Common shape in internal/dav/; CalDAV adds a scheduling rule. Surfaces its context URL (and each secure-SRV target) as TLS endpoints via the EndpointDiscoverer interface, so the dedicated TLS checker can pick them up without re-parsing observations. HTML report foregrounds common misconfigs (well-known returning 200, missing SRV, plaintext-only SRV, missing DAV capability, skipped auth phase) as action-item callouts before the full phase breakdown.
This commit is contained in:
commit
7d5535fddf
39 changed files with 3179 additions and 0 deletions
112
internal/dav/discover_test.go
Normal file
112
internal/dav/discover_test.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package dav
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestDiscover_wellKnownRedirect walks the happy path: /.well-known/caldav
|
||||
// returns a 301 to the real context URL.
|
||||
func TestDiscover_wellKnownRedirect(t *testing.T) {
|
||||
var hits []string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
hits = append(hits, r.URL.Path)
|
||||
if r.URL.Path == "/.well-known/caldav" {
|
||||
http.Redirect(w, r, "/dav/", http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
// Route "example.test/.well-known/caldav" through the test server.
|
||||
c := srv.Client()
|
||||
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
||||
|
||||
res := Discover(context.Background(), c, KindCalDAV, "example.test", "")
|
||||
if res.Source != "well-known" {
|
||||
t.Errorf("source = %q, want well-known", res.Source)
|
||||
}
|
||||
if !strings.HasSuffix(res.ContextURL, "/dav/") {
|
||||
t.Errorf("context URL = %q", res.ContextURL)
|
||||
}
|
||||
if res.WellKnownCode != 301 {
|
||||
t.Errorf("expected 301 captured, got %d", res.WellKnownCode)
|
||||
}
|
||||
if len(res.WellKnownChain) < 1 {
|
||||
t.Error("expected redirect chain to be recorded")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDiscover_wellKnownReturns200 reproduces the most common misconfig: the
|
||||
// server returns 200 on /.well-known/caldav instead of redirecting. Discover
|
||||
// must still set ContextURL (to the well-known URL) but WellKnownCode=200 so
|
||||
// the rule can emit the warning callout.
|
||||
func TestDiscover_wellKnownReturns200(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
c := srv.Client()
|
||||
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
||||
|
||||
res := Discover(context.Background(), c, KindCardDAV, "example.test", "")
|
||||
if res.WellKnownCode != 200 {
|
||||
t.Errorf("well-known code = %d, want 200", res.WellKnownCode)
|
||||
}
|
||||
if res.ContextURL == "" {
|
||||
t.Error("expected ContextURL to fall back to the well-known URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscover_explicitOverride(t *testing.T) {
|
||||
res := Discover(context.Background(), http.DefaultClient, KindCalDAV, "example.test", "https://custom.example/dav/")
|
||||
if res.Source != "explicit" {
|
||||
t.Errorf("source: %q", res.Source)
|
||||
}
|
||||
if res.ContextURL != "https://custom.example/dav/" {
|
||||
t.Errorf("ctx: %q", res.ContextURL)
|
||||
}
|
||||
if res.WellKnownURL != "" {
|
||||
t.Errorf("should not have probed well-known, got %q", res.WellKnownURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscover_redirectLoop(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Always redirect to itself → triggers "too many redirects".
|
||||
http.Redirect(w, r, r.URL.Path, http.StatusFound)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
c := srv.Client()
|
||||
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
||||
|
||||
res := Discover(context.Background(), c, KindCalDAV, "example.test", "")
|
||||
if res.WellKnownError == "" {
|
||||
t.Error("expected well-known error, got none")
|
||||
}
|
||||
}
|
||||
|
||||
// rewriteTransport rewrites any request URL's host to point at base so we can
|
||||
// exercise Discover() without setting up DNS. It preserves the original path.
|
||||
type rewriteTransport struct {
|
||||
base string
|
||||
next http.RoundTripper
|
||||
}
|
||||
|
||||
func (r rewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
baseURL, _ := url.Parse(r.base)
|
||||
req.URL.Scheme = baseURL.Scheme
|
||||
req.URL.Host = baseURL.Host
|
||||
next := r.next
|
||||
if next == nil {
|
||||
next = http.DefaultTransport
|
||||
}
|
||||
return next.RoundTrip(req)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue