feat(policy): case-insensitive address and domain matching
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestMatchAddress(t *testing.T) {
|
||||||
|
wl := []string{"bob@example.com", "@trusted.com"}
|
||||||
|
cases := []struct {
|
||||||
|
addr string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"bob@example.com", true},
|
||||||
|
{"BOB@Example.com", true},
|
||||||
|
{`"Bob" <bob@example.com>`, true},
|
||||||
|
{"alice@trusted.com", true},
|
||||||
|
{"alice@untrusted.com", false},
|
||||||
|
{"eve@example.com", false},
|
||||||
|
{"", false},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if got := MatchAddress(wl, c.addr); got != c.want {
|
||||||
|
t.Fatalf("MatchAddress(%q)=%v want %v", c.addr, got, c.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNormalizeAddr(t *testing.T) {
|
||||||
|
if got := NormalizeAddr(`"Bob Smith" <Bob@Example.COM>`); got != "bob@example.com" {
|
||||||
|
t.Fatalf("got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Package policy holds pure enforcement functions: address matching,
|
||||||
|
// inbound filtering, and (in a later phase) outbound checks.
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/mail"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NormalizeAddr lower-cases an address and strips any display name/brackets.
|
||||||
|
func NormalizeAddr(addr string) string {
|
||||||
|
addr = strings.TrimSpace(addr)
|
||||||
|
if a, err := mail.ParseAddress(addr); err == nil {
|
||||||
|
return strings.ToLower(a.Address)
|
||||||
|
}
|
||||||
|
return strings.ToLower(strings.Trim(addr, "<> "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchAddress reports whether addr matches any whitelist entry.
|
||||||
|
// Entries beginning with '@' match a whole domain; others match exactly.
|
||||||
|
func MatchAddress(entries []string, addr string) bool {
|
||||||
|
norm := NormalizeAddr(addr)
|
||||||
|
if norm == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
at := strings.LastIndex(norm, "@")
|
||||||
|
domain := ""
|
||||||
|
if at >= 0 {
|
||||||
|
domain = norm[at:] // includes '@'
|
||||||
|
}
|
||||||
|
for _, e := range entries {
|
||||||
|
e = strings.ToLower(strings.TrimSpace(e))
|
||||||
|
if strings.HasPrefix(e, "@") {
|
||||||
|
if e == domain {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if e == norm {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user