From 29319ccfd515102659fa20136e09b30562057f71 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 8 Feb 2025 16:17:54 +0200 Subject: [PATCH] pushrules: fix word boundary matching and case sensitivity --- go.mod | 2 +- go.sum | 4 ++-- pushrules/rule.go | 20 +++++++++++++++----- pushrules/rule_test.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index e34ef036..e8e71d54 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 github.com/yuin/goldmark v1.7.8 - go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 + go.mau.fi/util v0.8.5-0.20250208141401-fde0c0c733f1 go.mau.fi/zeroconfig v0.1.3 golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c diff --git a/go.sum b/go.sum index e04685a8..3f58ff96 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 h1:ye5l+QpYW5CpGVMedb3EHlmflGMQsMtw8mC4K/U8hIw= -go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= +go.mau.fi/util v0.8.5-0.20250208141401-fde0c0c733f1 h1:XQ47o9cbYOCtohOkxXIzIM3xnSsR/8lggdgLEZm8PHU= +go.mau.fi/util v0.8.5-0.20250208141401-fde0c0c733f1/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= diff --git a/pushrules/rule.go b/pushrules/rule.go index ee6d33c4..cf659695 100644 --- a/pushrules/rule.go +++ b/pushrules/rule.go @@ -8,7 +8,10 @@ package pushrules import ( "encoding/gob" + "regexp" + "strings" + "go.mau.fi/util/exerrors" "go.mau.fi/util/glob" "maunium.net/go/mautrix/event" @@ -165,13 +168,20 @@ func (rule *PushRule) matchConditions(room Room, evt *event.Event) bool { } func (rule *PushRule) matchPattern(room Room, evt *event.Event) bool { - pattern := glob.CompileWithImplicitContains(rule.Pattern) - if pattern == nil { - return false - } msg, ok := evt.Content.Raw["body"].(string) if !ok { return false } - return pattern.Match(msg) + var buf strings.Builder + // As per https://spec.matrix.org/unstable/client-server-api/#push-rules, content rules are case-insensitive + // and must match whole words, so wrap the converted glob in (?i) and \b. + buf.WriteString(`(?i)\b`) + // strings.Builder will never return errors + exerrors.PanicIfNotNil(glob.ToRegexPattern(rule.Pattern, &buf)) + buf.WriteString(`\b`) + pattern, err := regexp.Compile(buf.String()) + if err != nil { + return false + } + return pattern.MatchString(msg) } diff --git a/pushrules/rule_test.go b/pushrules/rule_test.go index 803c721e..7ff839a7 100644 --- a/pushrules/rule_test.go +++ b/pushrules/rule_test.go @@ -186,6 +186,34 @@ func TestPushRule_Match_Content(t *testing.T) { assert.True(t, rule.Match(blankTestRoom, evt)) } +func TestPushRule_Match_WordBoundary(t *testing.T) { + rule := &pushrules.PushRule{ + Type: pushrules.ContentRule, + Enabled: true, + Pattern: "test", + } + + evt := newFakeEvent(event.EventMessage, &event.MessageEventContent{ + MsgType: event.MsgEmote, + Body: "is testing pushrules", + }) + assert.False(t, rule.Match(blankTestRoom, evt)) +} + +func TestPushRule_Match_CaseInsensitive(t *testing.T) { + rule := &pushrules.PushRule{ + Type: pushrules.ContentRule, + Enabled: true, + Pattern: "test", + } + + evt := newFakeEvent(event.EventMessage, &event.MessageEventContent{ + MsgType: event.MsgEmote, + Body: "is TeSt-InG pushrules", + }) + assert.True(t, rule.Match(blankTestRoom, evt)) +} + func TestPushRule_Match_Content_Fail(t *testing.T) { rule := &pushrules.PushRule{ Type: pushrules.ContentRule,