1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 17:47:03 +00:00

Handle IP address domains (#285)

* Add basic TestRecipientAddress tests

* Handle forward-path route spec

* Validate IP addr "domains"

* Forward-path test cases

* Add integration test

* Add IPv4 recip swaks test

* Special case domain mailbox extraction

* add IPv6 swaks test

* Formatting

Signed-off-by: James Hillyerd <james@hillyerd.com>

* Update changelog
This commit is contained in:
James Hillyerd
2022-08-07 20:13:58 -07:00
committed by GitHub
parent 344c3ffb21
commit 1f1a8b4192
10 changed files with 269 additions and 24 deletions

View File

@@ -259,6 +259,30 @@ func TestExtractMailboxValid(t *testing.T) {
full: "chars|}~@example.co.uk",
domain: "example.co.uk",
},
{
input: "@host:user+label@domain.com",
local: "user",
full: "user@domain.com",
domain: "domain.com",
},
{
input: "@a.com,@b.com:user+label@domain.com",
local: "user",
full: "user@domain.com",
domain: "domain.com",
},
{
input: "u@[127.0.0.1]",
local: "u",
full: "u@[127.0.0.1]",
domain: "[127.0.0.1]",
},
{
input: "u@[IPv6:2001:db8:aaaa:1::100]",
local: "u",
full: "u@[IPv6:2001:db8:aaaa:1::100]",
domain: "[IPv6:2001:db8:aaaa:1::100]",
},
}
for _, tc := range testTable {
if result, err := localPolicy.ExtractMailbox(tc.input); err != nil {
@@ -285,10 +309,42 @@ func TestExtractMailboxValid(t *testing.T) {
}
}
// Test special cases with domain addressing mode.
func TestExtractDomainMailboxValid(t *testing.T) {
domainPolicy := policy.Addressing{Config: &config.Root{MailboxNaming: config.DomainNaming}}
tests := map[string]struct {
input string // Input to test
domain string // Expected output when mailbox naming = domain
}{
"ipv4": {
input: "[127.0.0.1]",
domain: "[127.0.0.1]",
},
"medium ipv6": {
input: "[IPv6:2001:db8:aaaa:1::100]",
domain: "[IPv6:2001:db8:aaaa:1::100]",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
if result, err := domainPolicy.ExtractMailbox(tc.input); tc.domain != "" && err != nil {
t.Errorf("Error while parsing with domain naming %q: %v", tc.input, err)
} else {
if result != tc.domain {
t.Errorf("Parsing %q, expected %q, got %q", tc.input, tc.domain, result)
}
}
})
}
}
func TestExtractMailboxInvalid(t *testing.T) {
localPolicy := policy.Addressing{Config: &config.Root{MailboxNaming: config.LocalNaming}}
fullPolicy := policy.Addressing{Config: &config.Root{MailboxNaming: config.FullNaming}}
domainPolicy := policy.Addressing{Config: &config.Root{MailboxNaming: config.DomainNaming}}
// Test local mailbox naming policy.
localInvalidTable := []struct {
input, msg string
@@ -303,6 +359,7 @@ func TestExtractMailboxInvalid(t *testing.T) {
t.Errorf("Didn't get an error while parsing in local mode %q: %v", tt.input, tt.msg)
}
}
// Test full mailbox naming policy.
fullInvalidTable := []struct {
input, msg string
@@ -318,6 +375,7 @@ func TestExtractMailboxInvalid(t *testing.T) {
t.Errorf("Didn't get an error while parsing in full mode %q: %v", tt.input, tt.msg)
}
}
// Test domain mailbox naming policy.
domainInvalidTable := []struct {
input, msg string
@@ -365,6 +423,10 @@ func TestValidateDomain(t *testing.T) {
{strings.Repeat("a", 256), false, "Max domain length is 255"},
{strings.Repeat("a", 63) + ".com", true, "Should allow 63 char domain label"},
{strings.Repeat("a", 64) + ".com", false, "Max domain label length is 63"},
{"[0.0.0.0]", true, "Single digit octet IP addr is valid"},
{"[123.123.123.123]", true, "Multiple digit octet IP addr is valid"},
{"[IPv6:2001:0db8:aaaa:0001:0000:0000:0000:0200]", true, "Full IPv6 addr is valid"},
{"[IPv6:::1]", true, "Abbr IPv6 addr is valid"},
}
for _, tt := range testTable {
if policy.ValidateDomainPart(tt.input) != tt.expect {
@@ -419,6 +481,9 @@ func TestValidateLocal(t *testing.T) {
{"$A12345", true, "RFC3696 test case should be valid"},
{"!def!xyz%abc", true, "RFC3696 test case should be valid"},
{"_somename", true, "RFC3696 test case should be valid"},
{"@host:mailbox", true, "Forward-path routes are valid"},
{"@a.com,@b.com:mailbox", true, "Multi-hop forward-path routes are valid"},
{"@a.com,mailbox", false, "Unterminated forward-path routes are invalid"},
}
for _, tt := range testTable {
_, _, err := policy.ParseEmailAddress(tt.input + "@domain.com")
@@ -430,3 +495,33 @@ func TestValidateLocal(t *testing.T) {
}
}
}
// TestRecipientAddress verifies the Recipient.Address values returned by Addressing.NewRecipient.
// This function parses a RCPT TO path, not a To header. See rfc5321#section-4.1.2
func TestRecipientAddress(t *testing.T) {
localPolicy := policy.Addressing{Config: &config.Root{MailboxNaming: config.LocalNaming}}
tests := map[string]string{
"common": "user@example.com",
"with label": "user+mailbox@example.com",
"special chars": "a!#$%&'*+-/=?^_`{|}~@example.com",
"ipv4": "user@[127.0.0.1]",
"ipv6": "user@[IPv6:::1]",
"route host": "@host:user@example.com",
"route domain": "@route.com:user@example.com",
"multi-hop route": "@first.com,@second.com:user@example.com",
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
r, err := localPolicy.NewRecipient(tc)
if err != nil {
t.Fatalf("Parse of %q failed: %v", tc, err)
}
if got, want := r.Address.Address, tc; got != want {
t.Errorf("Got Address: %q, want: %q", got, want)
}
})
}
}