mirror of
https://github.com/mjl-/mox.git
synced 2025-07-14 08:54:35 +03:00
expose fewer internals in packages, for easier software reuse
- prometheus is now behind an interface, they aren't dependencies for the reusable components anymore. - some dependencies have been inverted: instead of packages importing a main package to get configuration, the main package now sets configuration in these packages. that means fewer internals are pulled in. - some functions now have new parameters for values that were retrieved from package "mox-".
This commit is contained in:
38
dsn/dsn.go
38
dsn/dsn.go
@ -5,7 +5,6 @@ package dsn
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -16,13 +15,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/slog"
|
||||
|
||||
"github.com/mjl-/mox/dkim"
|
||||
"github.com/mjl-/mox/dns"
|
||||
"github.com/mjl-/mox/message"
|
||||
"github.com/mjl-/mox/mlog"
|
||||
"github.com/mjl-/mox/mox-"
|
||||
"github.com/mjl-/mox/smtp"
|
||||
)
|
||||
|
||||
@ -48,7 +42,6 @@ type Message struct {
|
||||
// Message subject header, e.g. describing mail delivery failure.
|
||||
Subject string
|
||||
|
||||
// Set when message is composed.
|
||||
MessageID string
|
||||
|
||||
// References header, with Message-ID of original message this DSN is about. So
|
||||
@ -136,7 +129,7 @@ type Recipient struct {
|
||||
// supports smtputf8. This influences the message media (sub)types used for the
|
||||
// DSN.
|
||||
//
|
||||
// DKIM signatures are added if DKIM signing is configured for the "from" domain.
|
||||
// Called may want to add DKIM-Signature headers.
|
||||
func (m *Message) Compose(log mlog.Log, smtputf8 bool) ([]byte, error) {
|
||||
// ../rfc/3462:119
|
||||
// ../rfc/3464:377
|
||||
@ -168,7 +161,9 @@ func (m *Message) Compose(log mlog.Log, smtputf8 bool) ([]byte, error) {
|
||||
header("From", fmt.Sprintf("<%s>", m.From.XString(smtputf8))) // todo: would be good to have a local ascii-only name for this address.
|
||||
header("To", fmt.Sprintf("<%s>", m.To.XString(smtputf8))) // todo: we could just leave this out if it has utf-8 and remote does not support utf-8.
|
||||
header("Subject", m.Subject)
|
||||
m.MessageID = mox.MessageIDGen(smtputf8)
|
||||
if m.MessageID == "" {
|
||||
return nil, fmt.Errorf("missing message-id")
|
||||
}
|
||||
header("Message-Id", fmt.Sprintf("<%s>", m.MessageID))
|
||||
if m.References != "" {
|
||||
header("References", m.References)
|
||||
@ -367,31 +362,6 @@ func (m *Message) Compose(log mlog.Log, smtputf8 bool) ([]byte, error) {
|
||||
}
|
||||
|
||||
data := msgw.w.Bytes()
|
||||
|
||||
// Add DKIM signature for domain, even if higher up than the full mail hostname.
|
||||
// This helps with an assumed (because default) relaxed DKIM policy. If the DMARC
|
||||
// policy happens to be strict, the signature won't help, but won't hurt either.
|
||||
fd := m.From.IPDomain.Domain
|
||||
var zerodom dns.Domain
|
||||
for fd != zerodom {
|
||||
confDom, ok := mox.Conf.Domain(fd)
|
||||
if !ok {
|
||||
var nfd dns.Domain
|
||||
_, nfd.ASCII, _ = strings.Cut(fd.ASCII, ".")
|
||||
_, nfd.Unicode, _ = strings.Cut(fd.Unicode, ".")
|
||||
fd = nfd
|
||||
continue
|
||||
}
|
||||
|
||||
dkimHeaders, err := dkim.Sign(context.Background(), log.Logger, m.From.Localpart, fd, confDom.DKIM, smtputf8, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
log.Errorx("dsn: dkim sign for domain, returning unsigned dsn", err, slog.Any("domain", fd))
|
||||
} else {
|
||||
data = append([]byte(dkimHeaders), data...)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
@ -2,21 +2,17 @@ package dsn
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mjl-/mox/dkim"
|
||||
"github.com/mjl-/mox/dns"
|
||||
"github.com/mjl-/mox/message"
|
||||
"github.com/mjl-/mox/mlog"
|
||||
"github.com/mjl-/mox/mox-"
|
||||
"github.com/mjl-/mox/smtp"
|
||||
)
|
||||
|
||||
@ -83,10 +79,11 @@ func TestDSN(t *testing.T) {
|
||||
m := Message{
|
||||
SMTPUTF8: false,
|
||||
|
||||
From: smtp.Path{Localpart: "postmaster", IPDomain: xparseIPDomain("mox.example")},
|
||||
To: smtp.Path{Localpart: "mjl", IPDomain: xparseIPDomain("remote.example")},
|
||||
Subject: "dsn",
|
||||
TextBody: "delivery failure\n",
|
||||
From: smtp.Path{Localpart: "postmaster", IPDomain: xparseIPDomain("mox.example")},
|
||||
To: smtp.Path{Localpart: "mjl", IPDomain: xparseIPDomain("remote.example")},
|
||||
Subject: "dsn",
|
||||
MessageID: "test@localhost",
|
||||
TextBody: "delivery failure\n",
|
||||
|
||||
ReportingMTA: "mox.example",
|
||||
ReceivedFromMTA: smtp.Ehlo{Name: xparseIPDomain("relay.example"), ConnIP: net.ParseIP("10.10.10.10")},
|
||||
@ -107,6 +104,7 @@ func TestDSN(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("composing dsn: %v", err)
|
||||
}
|
||||
|
||||
pmsg, part := tparseMessage(t, msgbuf, 3)
|
||||
tcheckType(t, part, "multipart", "report", "")
|
||||
tcheckType(t, &part.Parts[0], "text", "plain", "7bit")
|
||||
@ -130,35 +128,15 @@ func TestDSN(t *testing.T) {
|
||||
tcompareReader(t, part.Parts[2].Reader(), m.Original)
|
||||
tcompare(t, pmsg.Recipients[0].FinalRecipient, m.Recipients[0].FinalRecipient)
|
||||
|
||||
// Test for valid DKIM signature.
|
||||
mox.Context = context.Background()
|
||||
mox.ConfigStaticPath = filepath.FromSlash("../testdata/dsn/mox.conf")
|
||||
mox.MustLoadConfig(true, false)
|
||||
msgbuf, err = m.Compose(log, false)
|
||||
if err != nil {
|
||||
t.Fatalf("composing utf-8 dsn with utf-8 support: %v", err)
|
||||
}
|
||||
resolver := &dns.MockResolver{
|
||||
TXT: map[string][]string{
|
||||
"testsel._domainkey.mox.example.": {"v=DKIM1;h=sha256;t=s;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3ZId3ys70VFspp/VMFaxMOrNjHNPg04NOE1iShih16b3Ex7hHBOgC1UvTGSmrMlbCB1OxTXkvf6jW6S4oYRnZYVNygH6zKUwYYhaSaGIg1xA/fDn+IgcTRyLoXizMUgUgpTGyxhNrwIIWv+i7jjbs3TKpP3NU4owQ/rxowmSNqg+fHIF1likSvXvljYS" + "jaFXXnWfYibW7TdDCFFpN4sB5o13+as0u4vLw6MvOi59B1tLype1LcHpi1b9PfxNtznTTdet3kL0paxIcWtKHT0LDPUos8YYmiPa5nGbUqlC7d+4YT2jQPvwGxCws1oo2Tw6nj1UaihneYGAyvEky49FBwIDAQAB"},
|
||||
},
|
||||
}
|
||||
results, err := dkim.Verify(context.Background(), log.Logger, resolver, false, func(*dkim.Sig) error { return nil }, bytes.NewReader(msgbuf), false)
|
||||
if err != nil {
|
||||
t.Fatalf("dkim verify: %v", err)
|
||||
}
|
||||
if len(results) != 1 || results[0].Status != dkim.StatusPass {
|
||||
t.Fatalf("dkim result not pass, %#v", results)
|
||||
}
|
||||
|
||||
// An utf-8 message.
|
||||
m = Message{
|
||||
SMTPUTF8: true,
|
||||
|
||||
From: smtp.Path{Localpart: "postmæster", IPDomain: xparseIPDomain("møx.example")},
|
||||
To: smtp.Path{Localpart: "møx", IPDomain: xparseIPDomain("remøte.example")},
|
||||
Subject: "dsn¡",
|
||||
TextBody: "delivery failure¿\n",
|
||||
From: smtp.Path{Localpart: "postmæster", IPDomain: xparseIPDomain("møx.example")},
|
||||
To: smtp.Path{Localpart: "møx", IPDomain: xparseIPDomain("remøte.example")},
|
||||
Subject: "dsn¡",
|
||||
MessageID: "test@localhost",
|
||||
TextBody: "delivery failure¿\n",
|
||||
|
||||
ReportingMTA: "mox.example",
|
||||
ReceivedFromMTA: smtp.Ehlo{Name: xparseIPDomain("reläy.example"), ConnIP: net.ParseIP("10.10.10.10")},
|
||||
|
Reference in New Issue
Block a user