Adds support for Brand Indicators for Message Identification (BIMI),
the emerging standard that lets receiving mail clients display verified
brand logos next to authenticated messages.
Replace sha256.Sum224 (SHA-224 algorithm) with SHA-256 truncated to 28
bytes, matching what RFCs 7929 and 8162 actually specify and what the
frontend was already computing correctly. Also wrap GetRecords errors
with the service type name for easier diagnosis.
Several service analyzers were silently discarding errors returned by
a.UseRR(), unlike txt.go and others that properly checked them. This
could mask issues like double-claimed records during zone analysis.
Analogous to internal/provider, extract the service registry (Svc,
RegisterService, FindService, ListServices, OrderedServices, FindSubService,
RegisterSubServices) and the zone analyzer (ServiceAnalyzer, Analyzer,
AnalyzeZone) from services/ into a new internal/service package.
After AnalyzeZone rebuilds services from raw DNS records, metadata that
cannot be derived from DNS (Id, UserComment, OwnerId, Aliases, TTL, and
service-specific fields like OpenPGP/SMimeCert Username) was lost.
Add a post-processing function ReassociateMetadata that matches new
services to old ones by type and subdomain (using RDATA hashing for
disambiguation) and transfers metadata. Services opt in to body-level
transfer via the new MetadataEnricher interface.
Restructure the service analyzer architecture to improve maintainability:
- Extract recordPool (zone records + mark-delete claiming) and
serviceAccumulator (service registry + domain normalization) as
embedded structs in Analyzer
- Replace swap-delete with mark-delete to eliminate mutation-during-iteration
- Centralize domain normalization using helpers.DomainRelative
- Make Comment/NbResources lazy via Service.MarshalJSON instead of
eager assignment at three separate call sites
- Extract SPF merging from usecase layer into services.CollectAndMergeSPF
- Add GetDefaultTTL accessor and comprehensive Analyzer doc comments
- Add round-trip test infrastructure covering MX, CNAME, CAA, TXT, SPF,
DMARC, GSuite, Origin, Server and more
When a record matched more than one AnalyzerRecordFilter, it was
appended to the result slice multiple times. Break after the first
matching filter to include each record at most once.
The swap-and-shrink deletion inside a range loop skipped the element
swapped into position k. Since there should only be one matching
record (pointer equality), breaking immediately is both correct and
clearer.
RFC 7208 requires exactly one SPF record per domain. Previously, the
standalone SPF service and provider services like GSuite each emitted
their own SPF TXT record, producing invalid DNS when both existed.
Introduce SPFContributor interface so services can declare SPF
directives independently. At zone generation time, all contributions
for the same domain are merged into a single SPF record with the
strictest "all" policy winning. During zone import, GSuite claims its
directive via ClaimSPFDirective so the SPF analyzer excludes it from
the standalone SPF service.
- Moved usecases into internal/usecase
- Renamed internal/utils to internal/helpers for better naming semantics
- Clarified separation between domain model, usecases, adapters, and web/API