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
149
internal/dav/types.go
Normal file
149
internal/dav/types.go
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// Package dav holds code shared by the CalDAV and CardDAV checkers:
|
||||
// discovery, OPTIONS probing, PROPFIND helpers, and report rendering.
|
||||
package dav
|
||||
|
||||
import "time"
|
||||
|
||||
// Kind is carried end-to-end through a run so shared helpers branch on it
|
||||
// rather than duplicating per-protocol code.
|
||||
type Kind string
|
||||
|
||||
const (
|
||||
KindCalDAV Kind = "caldav"
|
||||
KindCardDAV Kind = "carddav"
|
||||
)
|
||||
|
||||
// ServiceName returns the RFC 6764 SRV label, with the leading "_" but
|
||||
// without the "_tcp" suffix.
|
||||
func (k Kind) ServiceName(secure bool) string {
|
||||
switch k {
|
||||
case KindCalDAV:
|
||||
if secure {
|
||||
return "_caldavs"
|
||||
}
|
||||
return "_caldav"
|
||||
case KindCardDAV:
|
||||
if secure {
|
||||
return "_carddavs"
|
||||
}
|
||||
return "_carddav"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (k Kind) WellKnownPath() string {
|
||||
return "/.well-known/" + string(k)
|
||||
}
|
||||
|
||||
// RequiredCapability is the DAV: header token a compliant server must
|
||||
// advertise.
|
||||
func (k Kind) RequiredCapability() string {
|
||||
switch k {
|
||||
case KindCalDAV:
|
||||
return "calendar-access"
|
||||
case KindCardDAV:
|
||||
return "addressbook"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Observation is what each checker persists. Scheduling is CalDAV-only and
|
||||
// left nil for CardDAV.
|
||||
type Observation struct {
|
||||
Kind Kind `json:"kind"`
|
||||
Domain string `json:"domain"`
|
||||
HasCredentials bool `json:"has_credentials"`
|
||||
Discovery DiscoveryResult `json:"discovery"`
|
||||
Transport TransportResult `json:"transport"`
|
||||
Options OptionsResult `json:"options"`
|
||||
Principal PrincipalResult `json:"principal"`
|
||||
HomeSet HomeSetResult `json:"home_set"`
|
||||
Collections CollectionsResult `json:"collections"`
|
||||
Report ReportResult `json:"report"`
|
||||
Scheduling *SchedulingResult `json:"scheduling,omitempty"`
|
||||
CollectedAt time.Time `json:"collected_at"`
|
||||
}
|
||||
|
||||
type SRVRecord struct {
|
||||
Target string `json:"target"`
|
||||
Port uint16 `json:"port"`
|
||||
Priority uint16 `json:"priority"`
|
||||
Weight uint16 `json:"weight"`
|
||||
}
|
||||
|
||||
// DiscoveryResult records every signal seen during lookup, even on failure,
|
||||
// so the report can pinpoint which leg of discovery broke.
|
||||
type DiscoveryResult struct {
|
||||
SecureSRV []SRVRecord `json:"secure_srv,omitempty"`
|
||||
PlaintextSRV []SRVRecord `json:"plaintext_srv,omitempty"`
|
||||
SRVError string `json:"srv_error,omitempty"`
|
||||
TXTPath string `json:"txt_path,omitempty"`
|
||||
TXTError string `json:"txt_error,omitempty"`
|
||||
WellKnownURL string `json:"well_known_url,omitempty"`
|
||||
WellKnownCode int `json:"well_known_code,omitempty"`
|
||||
WellKnownChain []string `json:"well_known_chain,omitempty"`
|
||||
WellKnownError string `json:"well_known_error,omitempty"`
|
||||
ContextURL string `json:"context_url,omitempty"`
|
||||
Source string `json:"source,omitempty"` // "explicit", "well-known", "srv-txt"
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// TransportResult is intentionally minimal: cert validation is out of scope
|
||||
// here, a dedicated TLS checker owns it.
|
||||
type TransportResult struct {
|
||||
Reached bool `json:"reached"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type OptionsResult struct {
|
||||
StatusCode int `json:"status_code"`
|
||||
DAVClasses []string `json:"dav_classes,omitempty"`
|
||||
AllowMethods []string `json:"allow_methods,omitempty"`
|
||||
AuthSchemes []string `json:"auth_schemes,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// PrincipalResult.Skipped is set when no credentials were supplied; the
|
||||
// rule turns that into StatusUnknown rather than a failure.
|
||||
type PrincipalResult struct {
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type HomeSetResult struct {
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type CollectionInfo struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MaxResourceSize int64 `json:"max_resource_size,omitempty"`
|
||||
SupportedComponentSet []string `json:"supported_component_set,omitempty"` // CalDAV only
|
||||
SupportedAddressData []string `json:"supported_address_data,omitempty"` // CardDAV only
|
||||
}
|
||||
|
||||
type CollectionsResult struct {
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
Items []CollectionInfo `json:"items,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type ReportResult struct {
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
QueryOK bool `json:"query_ok,omitempty"`
|
||||
ProbePath string `json:"probe_path,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulingResult is CalDAV-only.
|
||||
type SchedulingResult struct {
|
||||
Advertised bool `json:"advertised"`
|
||||
InboxURL string `json:"inbox_url,omitempty"`
|
||||
OutboxURL string `json:"outbox_url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue