From 20ef8af0478953d107cc1a8889dcb39a26739661 Mon Sep 17 00:00:00 2001 From: Cyd <34154246+cyd01@users.noreply.github.com> Date: Sun, 12 Nov 2023 18:42:20 +0100 Subject: [PATCH] Reject invalidomain with wildcards (#412) Co-authored-by: Cyril DUPONT --- pkg/policy/address.go | 9 ++++++- pkg/server/smtp/handler_test.go | 4 ++- pkg/stringutil/utils.go | 37 ++++++++++++++++++++++++++ pkg/stringutil/utils_test.go | 46 +++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/pkg/policy/address.go b/pkg/policy/address.go index f1dc157..6770815 100644 --- a/pkg/policy/address.go +++ b/pkg/policy/address.go @@ -117,7 +117,14 @@ func (a *Addressing) ShouldStoreDomain(domain string) bool { // ShouldAcceptOriginDomain indicates if Inbucket accept mail from the specified domain. func (a *Addressing) ShouldAcceptOriginDomain(domain string) bool { domain = strings.ToLower(domain) - return !stringutil.SliceContains(a.Config.SMTP.RejectOriginDomains, domain) + if len(a.Config.SMTP.RejectOriginDomains) > 0 { + for _, d := range a.Config.SMTP.RejectOriginDomains { + if stringutil.MatchWithWildcards(d, domain) { + return false + } + } + } + return true } // ParseEmailAddress unescapes an email address, and splits the local part from the domain part. diff --git a/pkg/server/smtp/handler_test.go b/pkg/server/smtp/handler_test.go index b5e9305..c6395c5 100644 --- a/pkg/server/smtp/handler_test.go +++ b/pkg/server/smtp/handler_test.go @@ -206,6 +206,8 @@ func TestReadyStateRejectedDomains(t *testing.T) { tests := []scriptStep{ {"MAIL FROM: ", 250}, {"MAIL FROM: ", 501}, + {"MAIL FROM: ", 501}, + {"MAIL FROM: ", 501}, } for _, tc := range tests { @@ -582,7 +584,7 @@ func setupSMTPServer(ds storage.Store, extHost *extension.Host) *Server { MaxMessageBytes: 5000, DefaultAccept: true, RejectDomains: []string{"deny.com"}, - RejectOriginDomains: []string{"invalidomain.com"}, + RejectOriginDomains: []string{"invalidomain.com", "*.otherinvaliddomain.com"}, Timeout: 5, }, } diff --git a/pkg/stringutil/utils.go b/pkg/stringutil/utils.go index 67647f6..faeb30e 100644 --- a/pkg/stringutil/utils.go +++ b/pkg/stringutil/utils.go @@ -74,3 +74,40 @@ func MakePathPrefixer(prefix string) func(string) string { return prefix + path } } + +// Test if a "s" string match a "p" pattern with wildcards (*, ?) +func MatchWithWildcards(p string, s string) bool { + runeInput := []rune(s) + runePattern := []rune(p) + lenInput := len(runeInput) + lenPattern := len(runePattern) + isMatchingMatrix := make([][]bool, lenInput+1) + for i := range isMatchingMatrix { + isMatchingMatrix[i] = make([]bool, lenPattern+1) + } + isMatchingMatrix[0][0] = true + if lenPattern > 0 { + if runePattern[0] == '*' { + isMatchingMatrix[0][1] = true + } + } + for j := 2; j <= lenPattern; j++ { + if runePattern[j-1] == '*' { + isMatchingMatrix[0][j] = isMatchingMatrix[0][j-1] + } + + } + for i := 1; i <= lenInput; i++ { + for j := 1; j <= lenPattern; j++ { + + if runePattern[j-1] == '*' { + isMatchingMatrix[i][j] = isMatchingMatrix[i-1][j] || isMatchingMatrix[i][j-1] + } + + if runePattern[j-1] == '?' || runeInput[i-1] == runePattern[j-1] { + isMatchingMatrix[i][j] = isMatchingMatrix[i-1][j-1] + } + } + } + return isMatchingMatrix[lenInput][lenPattern] +} diff --git a/pkg/stringutil/utils_test.go b/pkg/stringutil/utils_test.go index f245f92..1bfa638 100644 --- a/pkg/stringutil/utils_test.go +++ b/pkg/stringutil/utils_test.go @@ -76,3 +76,49 @@ func TestMakePathPrefixer(t *testing.T) { }) } } + +func TestMatchWithWildcards(t *testing.T) { + testCases := []struct { + pattern, input string + want bool + }{ + {pattern: "", input: "", want: true}, + {pattern: "", input: "qwerty", want: false}, + {pattern: "qw*ty", input: "qwerty", want: true}, + {pattern: "qw?ty", input: "qwerty", want: false}, + {pattern: "qwe*ty", input: "qwerty", want: true}, + {pattern: "*erty", input: "qwerty", want: true}, + {pattern: "?erty", input: "qwerty", want: false}, + {pattern: "?werty", input: "qwerty", want: true}, + {pattern: "qwer*", input: "qwerty", want: true}, + {pattern: "qwer?", input: "qwerty", want: false}, + {pattern: "qwert?", input: "qwerty", want: true}, + {pattern: "qw**ty", input: "qwerty", want: true}, + {pattern: "qw??ty", input: "qwerty", want: true}, + {pattern: "qwe??ty", input: "qwerty", want: false}, + {pattern: "**erty", input: "qwerty", want: true}, + {pattern: "??erty", input: "qwerty", want: true}, + {pattern: "??werty", input: "qwerty", want: false}, + {pattern: "qwer**", input: "qwerty", want: true}, + {pattern: "qwer??", input: "qwerty", want: true}, + {pattern: "qwert??", input: "qwerty", want: false}, + {pattern: "q?er?y", input: "qwerty", want: true}, + {pattern: "q?r?y", input: "qwerty", want: false}, + {pattern: "q*er*y", input: "qwerty", want: true}, + {pattern: "q*r*y", input: "qwerty", want: true}, + {pattern: "q*?werty", input: "qwerty", want: false}, + {pattern: "q*?erty", input: "qwerty", want: true}, + {pattern: "q?*werty", input: "qwerty", want: false}, + {pattern: "q?*erty", input: "qwerty", want: true}, + {pattern: "?*rty", input: "qwerty", want: true}, + {pattern: "*?rty", input: "qwerty", want: true}, + {pattern: "qwe?*", input: "qwerty", want: true}, + {pattern: "qwe*?", input: "qwerty", want: true}, + } + for _, tc := range testCases { + got := stringutil.MatchWithWildcards(tc.pattern, tc.input) + if got != tc.want { + t.Errorf("Test %s with pattern %s, Got: %v, want: %v", tc.input, tc.pattern, got, tc.want) + } + } +}