feat(bimi): logotipo do dominio validado, alojado e publicado no DNS
A foto de perfil nao viaja: nem o Gmail nem o Outlook leem uma imagem por utilizador do servidor de quem envia, e nao existe protocolo que o permita. O avatar que esses mostram vem dos contactos de quem recebe ou da conta Google ou Microsoft do remetente. O que eles leem e BIMI, que e por dominio. Fica implementado: validacao, alojamento e o registo. O validador reporta todas as violacoes de uma vez, e nao a primeira. Um receptor que recusa a marca nao explica nada -- simplesmente nao desenha -- por isso descobrir as regras uma viagem de cada vez seria a pior maneira possivel de aprender este formato. Sao verificados o baseProfile e a versao que os receptores procuram, o viewBox quadrado (uma marca nao quadrada e cortada de forma diferente por cada cliente), exactamente um title, e a ausencia de tudo o que seja activo ou externo: script, handlers de evento, links, imagens rasterizadas, animacoes e referencias para fora do documento. O registo so e publicado quando ha mesmo uma marca guardada. Um registo que aponta para um logotipo inexistente e pior do que nenhum, porque o receptor para de procurar assim que encontra um. O logotipo e servido aberto, porque quem o vai buscar sao os fornecedores de correio a avaliar uma mensagem e esses nunca terao sessao aqui. Fica escrito no README que o Gmail e o Outlook so desenham a marca com um VMC, e o painel avisa quando nao ha nenhum configurado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fcfee6a3f9
commit
6a602ab88f
16 files changed
+955
-5
No files matched your search
@@ -230,11 +230,15 @@ func run(cfg config) {
|
||||
// list stops disagreeing with the page next to it.
|
||||
router.SetDnsStatusWriter(postgres.NewDomainRepository(pool))
|
||||
router.SetAdminDnsAPI(
|
||||
&dnsSpecSource{cfg: cfg, dkim: dkimRepo},
|
||||
&dnsSpecSource{cfg: cfg, dkim: dkimRepo, bimi: postgres.NewBimiRepository(pool)},
|
||||
netdns.NewPublicVerifier(),
|
||||
cfg.JwtSecret,
|
||||
)
|
||||
}
|
||||
// The BIMI mark: served to receivers over the well-known URL, managed from
|
||||
// the domains panel.
|
||||
router.SetBimiAPI(bimiStore{postgres.NewBimiRepository(pool)}, cfg.JwtSecret, cfg.domain())
|
||||
|
||||
// The TLS panel reads the live watcher instead of the constants the admin
|
||||
// service used to return, which reported a healthy certificate whatever
|
||||
// the process actually held.
|
||||
@@ -698,6 +702,7 @@ func runHealthcheck() {
|
||||
type dnsSpecSource struct {
|
||||
cfg config
|
||||
dkim *postgres.DkimRepository
|
||||
bimi *postgres.BimiRepository
|
||||
}
|
||||
|
||||
func (s *dnsSpecSource) ExpectedRecords(ctx context.Context, domain string) ([]entity.DnsRecord, error) {
|
||||
@@ -710,6 +715,15 @@ func (s *dnsSpecSource) ExpectedRecords(ctx context.Context, domain string) ([]e
|
||||
RelaySpfInclude: relayConfig(s.cfg).SpfInclude(),
|
||||
}
|
||||
|
||||
// The BIMI record is published only when a mark is actually stored, so
|
||||
// the panel never advertises a logo that would 404.
|
||||
if s.bimi != nil {
|
||||
if logo, err := s.bimi.Load(ctx, domain); err == nil && logo != nil {
|
||||
spec.BimiLogoURL = httppresentation.BimiLogoURL(s.cfg.PrimaryMailHost)
|
||||
spec.BimiVmcURL = logo.VmcURL
|
||||
}
|
||||
}
|
||||
|
||||
// Read rather than provisioned: verifying must not create keys as a side
|
||||
// effect of somebody opening a screen.
|
||||
if s.dkim != nil {
|
||||
|
||||
Reference in new issue
Block a user