checker-dav/internal/dav/client.go
Pierre-Olivier Mercier de7e99d5a9 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.
2026-04-26 02:46:17 +07:00

55 lines
1.6 KiB
Go

package dav
import (
"net/http"
"net/url"
"strings"
"time"
)
// NewHTTPClient returns an http.Client with a sane default transport for
// probing DAV servers. TLS certificate validation uses Go's default rules;
// dedicated TLS correctness belongs in a separate checker.
func NewHTTPClient(timeout time.Duration) *http.Client {
return &http.Client{
Timeout: timeout,
}
}
// basicAuthRoundTripper injects HTTP Basic credentials on every request so
// callers can pass the same client through go-webdav's own API without losing
// auth on internal redirects.
//
// Credentials are scoped to a single host: a redirect to a different host
// silently drops the Authorization header rather than forwarding the
// credentials to a third party. This matches the behavior of curl --location
// without --location-trusted.
type basicAuthRoundTripper struct {
user, pass string
host string
next http.RoundTripper
}
func (b *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if strings.EqualFold(req.URL.Host, b.host) {
req.SetBasicAuth(b.user, b.pass)
}
return b.next.RoundTrip(req)
}
// WithBasicAuth clones c and attaches Basic credentials to the transport,
// scoped to the host of contextURL. Requests to any other host (e.g. via a
// redirect) will not carry the credentials.
func WithBasicAuth(c *http.Client, contextURL, user, pass string) *http.Client {
nc := *c
base := c.Transport
if base == nil {
base = http.DefaultTransport
}
host := ""
if u, err := url.Parse(contextURL); err == nil {
host = u.Host
}
nc.Transport = &basicAuthRoundTripper{user: user, pass: pass, host: host, next: base}
return &nc
}