169 lines
6.6 KiB
Go
169 lines
6.6 KiB
Go
// Package checker implements the email autoconfiguration checker for
|
|
// happyDomain.
|
|
//
|
|
// It verifies that a domain publishes discoverable email client
|
|
// configuration, as described in Bucksch' autoconfig draft
|
|
// (draft-bucksch-autoconfig-00), Microsoft's Autodiscover (POX) and RFC
|
|
// 6186 SRV records. The checker probes every standard endpoint, parses
|
|
// the returned documents, cross-checks the servers they advertise and
|
|
// rates the result with user-actionable hints.
|
|
package checker
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// ObservationKeyAutoconfig is the observation key for autoconfig data.
|
|
const ObservationKeyAutoconfig = "email_autoconfig"
|
|
|
|
// Data is the full collected payload.
|
|
type Data struct {
|
|
Domain string `json:"domain"`
|
|
Email string `json:"email"`
|
|
CollectedAt time.Time `json:"collected_at"`
|
|
|
|
// MX records found on the domain.
|
|
MX []MXRecord `json:"mx,omitempty"`
|
|
MXError string `json:"mx_error,omitempty"`
|
|
|
|
// RFC 6186 style SRV records.
|
|
SRV []SRVRecord `json:"srv,omitempty"`
|
|
|
|
// Thunderbird autoconfig probes.
|
|
Autoconfig []AutoconfigProbe `json:"autoconfig,omitempty"`
|
|
|
|
// Microsoft Autodiscover probes.
|
|
Autodiscover []AutodiscoverProbe `json:"autodiscover,omitempty"`
|
|
|
|
// The "best" (first successful) autoconfig document we received,
|
|
// fully parsed. Present only when at least one probe succeeded.
|
|
ClientConfig *ClientConfig `json:"client_config,omitempty"`
|
|
|
|
// Source of the ClientConfig above ("autoconfig", "ispdb", "mx").
|
|
ClientConfigSource string `json:"client_config_source,omitempty"`
|
|
|
|
// The Autodiscover response we parsed, if any.
|
|
AutodiscoverResult *AutodiscoverResponse `json:"autodiscover_result,omitempty"`
|
|
}
|
|
|
|
// MXRecord is a single MX record.
|
|
type MXRecord struct {
|
|
Host string `json:"host"`
|
|
Preference uint16 `json:"preference"`
|
|
}
|
|
|
|
// SRVRecord is a single RFC 6186 SRV record observation.
|
|
type SRVRecord struct {
|
|
// Service is the RFC 6186 service tag, e.g. "_imaps._tcp".
|
|
Service string `json:"service"`
|
|
Target string `json:"target"`
|
|
Port uint16 `json:"port"`
|
|
Priority uint16 `json:"priority"`
|
|
Weight uint16 `json:"weight"`
|
|
// Skip is true when RFC 6186 indicates the service is explicitly
|
|
// unsupported (target ".").
|
|
Skip bool `json:"skip,omitempty"`
|
|
}
|
|
|
|
// ProbeResult captures the outcome of a single HTTP probe.
|
|
type ProbeResult struct {
|
|
URL string `json:"url"`
|
|
Method string `json:"method,omitempty"`
|
|
StatusCode int `json:"status_code,omitempty"`
|
|
DurationMs int64 `json:"duration_ms,omitempty"`
|
|
ContentType string `json:"content_type,omitempty"`
|
|
BodyBytes int `json:"body_bytes,omitempty"`
|
|
Redirected bool `json:"redirected,omitempty"`
|
|
FinalURL string `json:"final_url,omitempty"`
|
|
TLSServerName string `json:"tls_server_name,omitempty"`
|
|
TLSIssuer string `json:"tls_issuer,omitempty"`
|
|
TLSSubject string `json:"tls_subject,omitempty"`
|
|
TLSNotAfter string `json:"tls_not_after,omitempty"`
|
|
TLSValid bool `json:"tls_valid,omitempty"`
|
|
TLSError string `json:"tls_error,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
ParseError string `json:"parse_error,omitempty"`
|
|
}
|
|
|
|
// AutoconfigProbe is one probe attempt for Thunderbird-style autoconfig.
|
|
type AutoconfigProbe struct {
|
|
Source string `json:"source"` // "autoconfig", "wellknown", "http-autoconfig", "ispdb", "mx-autoconfig", "mx-ispdb"
|
|
Result ProbeResult `json:"result"`
|
|
Parsed *ClientConfig `json:"parsed,omitempty"`
|
|
}
|
|
|
|
// AutodiscoverProbe is one probe attempt for MS Autodiscover (POX).
|
|
type AutodiscoverProbe struct {
|
|
Source string `json:"source"` // "root", "subdomain", "srv", "redirect"
|
|
Result ProbeResult `json:"result"`
|
|
Parsed *AutodiscoverResponse `json:"parsed,omitempty"`
|
|
}
|
|
|
|
// ClientConfig is the parsed Thunderbird-style clientConfig document.
|
|
type ClientConfig struct {
|
|
Version string `json:"version,omitempty"`
|
|
EmailProviderID string `json:"email_provider_id,omitempty"`
|
|
DisplayName string `json:"display_name,omitempty"`
|
|
ShortName string `json:"short_name,omitempty"`
|
|
Domains []string `json:"domains,omitempty"`
|
|
Incoming []ServerConfig `json:"incoming,omitempty"`
|
|
Outgoing []ServerConfig `json:"outgoing,omitempty"`
|
|
AddressBook []DavServer `json:"address_book,omitempty"`
|
|
Calendar []DavServer `json:"calendar,omitempty"`
|
|
WebMail *WebMail `json:"webmail,omitempty"`
|
|
Documentation []Documentation `json:"documentation,omitempty"`
|
|
}
|
|
|
|
// ServerConfig is one incoming/outgoing server definition.
|
|
type ServerConfig struct {
|
|
Type string `json:"type"` // imap, pop3, smtp
|
|
Hostname string `json:"hostname"`
|
|
Port int `json:"port"`
|
|
SocketType string `json:"socket_type"` // plain, SSL, STARTTLS
|
|
Username string `json:"username"` // may contain %EMAIL% placeholders
|
|
Authentication string `json:"authentication"` // password-cleartext, password-encrypted, OAuth2, ...
|
|
}
|
|
|
|
// DavServer is a CardDAV or CalDAV server reference.
|
|
type DavServer struct {
|
|
Type string `json:"type"`
|
|
Username string `json:"username,omitempty"`
|
|
Authentication string `json:"authentication,omitempty"`
|
|
ServerURL string `json:"server_url,omitempty"`
|
|
}
|
|
|
|
// WebMail holds webmail configuration (if any).
|
|
type WebMail struct {
|
|
LoginPage string `json:"login_page,omitempty"`
|
|
}
|
|
|
|
// Documentation is a clientConfig <documentation> entry.
|
|
type Documentation struct {
|
|
URL string `json:"url,omitempty"`
|
|
Descr string `json:"descr,omitempty"`
|
|
}
|
|
|
|
// AutodiscoverResponse is the parsed POX response.
|
|
type AutodiscoverResponse struct {
|
|
// User.DisplayName
|
|
DisplayName string `json:"display_name,omitempty"`
|
|
// Redirect destinations (when Action=redirectAddr/redirectUrl).
|
|
RedirectAddr string `json:"redirect_addr,omitempty"`
|
|
RedirectURL string `json:"redirect_url,omitempty"`
|
|
// Protocols configured by the server.
|
|
Protocols []AutodiscoverProtocol `json:"protocols,omitempty"`
|
|
}
|
|
|
|
// AutodiscoverProtocol mirrors the subset of <Protocol> elements relevant
|
|
// to IMAP/POP/SMTP configuration. Exchange-specific protocols are captured
|
|
// but not deeply analysed.
|
|
type AutodiscoverProtocol struct {
|
|
Type string `json:"type"` // IMAP, POP3, SMTP, EXCH, EXPR, WEB, MobileSync
|
|
Server string `json:"server,omitempty"`
|
|
Port int `json:"port,omitempty"`
|
|
Encryption string `json:"encryption,omitempty"` // SSL, TLS, None
|
|
SSL string `json:"ssl,omitempty"` // on/off
|
|
LoginName string `json:"login_name,omitempty"`
|
|
DomainRequired string `json:"domain_required,omitempty"`
|
|
AuthRequired string `json:"auth_required,omitempty"`
|
|
}
|