feat(policy): inbound whitelist + subject-regex filter
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
// InboundRule captures one account's read-side filtering.
|
||||||
|
type InboundRule struct {
|
||||||
|
WhitelistInEnabled bool
|
||||||
|
WhitelistIn []string
|
||||||
|
SubjectRegex *regexp.Regexp // nil = no subject filter
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompileSubject compiles a subject filter; empty pattern => (nil, nil).
|
||||||
|
func CompileSubject(pattern string) (*regexp.Regexp, error) {
|
||||||
|
if pattern == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return regexp.Compile(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows reports whether a message with the given sender and subject is visible.
|
||||||
|
func (r InboundRule) Allows(from, subject string) bool {
|
||||||
|
if r.WhitelistInEnabled && !MatchAddress(r.WhitelistIn, from) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.SubjectRegex != nil && !r.SubjectRegex.MatchString(subject) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestInboundAllows(t *testing.T) {
|
||||||
|
re, err := CompileSubject("(?i)invoice")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("compile: %v", err)
|
||||||
|
}
|
||||||
|
rule := InboundRule{
|
||||||
|
WhitelistInEnabled: true,
|
||||||
|
WhitelistIn: []string{"@trusted.com"},
|
||||||
|
SubjectRegex: re,
|
||||||
|
}
|
||||||
|
cases := []struct {
|
||||||
|
from, subject string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"bob@trusted.com", "Your Invoice #5", true},
|
||||||
|
{"bob@trusted.com", "lunch?", false}, // subject fails
|
||||||
|
{"eve@evil.com", "Invoice", false}, // sender fails
|
||||||
|
{"eve@evil.com", "lunch?", false}, // both fail
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if got := rule.Allows(c.from, c.subject); got != c.want {
|
||||||
|
t.Fatalf("Allows(%q,%q)=%v want %v", c.from, c.subject, got, c.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInboundNoFiltersAllowsAll(t *testing.T) {
|
||||||
|
rule := InboundRule{} // whitelist disabled, no regex
|
||||||
|
if !rule.Allows("anyone@anywhere.com", "anything") {
|
||||||
|
t.Fatal("empty rule must allow everything")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompileSubjectEmpty(t *testing.T) {
|
||||||
|
re, err := CompileSubject("")
|
||||||
|
if err != nil || re != nil {
|
||||||
|
t.Fatalf("empty pattern: re=%v err=%v", re, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user