Files
mailgoserver/internal/dkim/global_key_test.go
T

125 lines
4.6 KiB
Go

package dkim
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"mailgoserver/internal/dnspublish"
)
// TestGenerateGlobalDKIMKeyWithoutHostnameSkipsPublish confirms regenerating with no
// hostname/creds configured just rotates the key, no publish attempt.
func TestGenerateGlobalDKIMKeyWithoutHostnameSkipsPublish(t *testing.T) {
database := openTestDKIMDB(t)
mgr := New(database, 1024)
publishErr, err := mgr.GenerateGlobalDKIMKey("", nil)
if err != nil {
t.Fatal(err)
}
if publishErr != nil {
t.Fatalf("expected no publish attempt with no hostname/creds, got %v", publishErr)
}
key, err := mgr.GetActiveGlobalDKIMKey()
if err != nil || key == nil {
t.Fatalf("expected a global key to exist, got %v %v", key, err)
}
}
// TestGenerateGlobalDKIMKeyPublishesAndRotates confirms a real publish happens against
// the configured hostname, and a second regenerate deactivates the first key.
func TestGenerateGlobalDKIMKeyPublishesAndRotates(t *testing.T) {
var bodies []string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/zones":
w.Write([]byte(`{"success":true,"errors":[],"result":[{"id":"zone1"}]}`))
case r.URL.Path == "/zones/zone1/dns_records" && r.Method == http.MethodGet:
w.Write([]byte(`{"success":true,"errors":[],"result":[]}`))
case r.URL.Path == "/zones/zone1/dns_records" && r.Method == http.MethodPost:
body, _ := io.ReadAll(r.Body)
bodies = append(bodies, string(body))
w.Write([]byte(`{"success":true,"errors":[],"result":{"id":"rec1"}}`))
default:
w.WriteHeader(http.StatusNotFound)
}
}))
defer srv.Close()
orig := dnspublish.CloudflareAPIBase
dnspublish.CloudflareAPIBase = srv.URL
defer func() { dnspublish.CloudflareAPIBase = orig }()
database := openTestDKIMDB(t)
mgr := New(database, 1024)
creds := &dnspublish.Credentials{Provider: "cloudflare", ZoneName: "example.com", CloudflareAPIToken: "tok"}
publishErr, err := mgr.GenerateGlobalDKIMKey("dkim.example.com", creds)
if err != nil || publishErr != nil {
t.Fatalf("first generate: err=%v publishErr=%v", err, publishErr)
}
first, _ := mgr.GetActiveGlobalDKIMKey()
if first == nil {
t.Fatal("expected an active global key after first generate")
}
if len(bodies) != 1 || !strings.Contains(bodies[0], "_domainkey.dkim.example.com") {
t.Fatalf("expected a publish call naming the configured hostname, got %v", bodies)
}
publishErr, err = mgr.GenerateGlobalDKIMKey("dkim.example.com", creds)
if err != nil || publishErr != nil {
t.Fatalf("second generate: err=%v publishErr=%v", err, publishErr)
}
second, _ := mgr.GetActiveGlobalDKIMKey()
if second == nil || second.ID == first.ID {
t.Fatalf("expected a distinct, newly active key after rotation: first=%+v second=%+v", first, second)
}
}
// TestGetActiveDKIMKeySwapsToGlobalKeyMaterial confirms a domain with UseGlobalDKIM
// signs with the global key's material while keeping its own selector, and falls back
// to its own key when no global key exists yet.
func TestGetActiveDKIMKeySwapsToGlobalKeyMaterial(t *testing.T) {
database := openTestDKIMDB(t)
domainID, err := database.CreateDomain("useglobal.example")
if err != nil {
t.Fatal(err)
}
mgr := New(database, 1024)
if ok, err := mgr.GenerateDKIMKeypair("useglobal.example", "own-sel", true); err != nil || !ok {
t.Fatalf("seed domain key: ok=%v err=%v", ok, err)
}
ownKey, _ := mgr.GetActiveDKIMKey("useglobal.example")
if err := database.SetDomainUseGlobalDKIM(domainID, true); err != nil {
t.Fatal(err)
}
// No global key generated yet — falls back to the domain's own material.
fallback, err := mgr.GetActiveDKIMKey("useglobal.example")
if err != nil || fallback == nil || fallback.PrivateKey != ownKey.PrivateKey || fallback.Selector != "own-sel" {
t.Fatalf("expected fallback to the domain's own key material, got %+v", fallback)
}
if _, err := mgr.GenerateGlobalDKIMKey("", nil); err != nil {
t.Fatal(err)
}
globalKey, _ := mgr.GetActiveGlobalDKIMKey()
swapped, err := mgr.GetActiveDKIMKey("useglobal.example")
if err != nil || swapped == nil {
t.Fatalf("GetActiveDKIMKey: %v %v", swapped, err)
}
if swapped.Selector != "own-sel" {
t.Fatalf("expected the domain's own selector preserved, got %q", swapped.Selector)
}
if swapped.PrivateKey != globalKey.PrivateKey || swapped.PublicKey != globalKey.PublicKey {
t.Fatalf("expected the global key's material substituted in, got %+v want private=%q public=%q", swapped, globalKey.PrivateKey, globalKey.PublicKey)
}
if swapped.PrivateKey == ownKey.PrivateKey {
t.Fatal("expected the domain's own private key to no longer be used once global mode is on")
}
}