fix(matrix): improve group mention detection
This commit is contained in:
parent
a66eac42c4
commit
64b99b34bb
2 changed files with 87 additions and 1 deletions
|
|
@ -3,7 +3,9 @@ package matrix
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"mime"
|
"mime"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
@ -29,6 +31,8 @@ const (
|
||||||
roomKindCacheTTL = 5 * time.Minute
|
roomKindCacheTTL = 5 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var matrixMentionHrefRegexp = regexp.MustCompile(`(?i)<a[^>]+href=["']([^"']+)["']`)
|
||||||
|
|
||||||
type roomKindCacheEntry struct {
|
type roomKindCacheEntry struct {
|
||||||
isGroup bool
|
isGroup bool
|
||||||
expiresAt time.Time
|
expiresAt time.Time
|
||||||
|
|
@ -469,6 +473,12 @@ func (c *MatrixChannel) handleMessageEvent(ctx context.Context, evt *event.Event
|
||||||
}
|
}
|
||||||
respond, cleaned := c.ShouldRespondInGroup(isMentioned, content)
|
respond, cleaned := c.ShouldRespondInGroup(isMentioned, content)
|
||||||
if !respond {
|
if !respond {
|
||||||
|
logger.DebugCF("matrix", "Ignoring group message by trigger rules", map[string]any{
|
||||||
|
"room_id": roomID,
|
||||||
|
"is_mentioned": isMentioned,
|
||||||
|
"mention_only": c.config.GroupTrigger.MentionOnly,
|
||||||
|
"prefixes": c.config.GroupTrigger.Prefixes,
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content = cleaned
|
content = cleaned
|
||||||
|
|
@ -807,7 +817,10 @@ func (c *MatrixChannel) isBotMentioned(msgEvt *event.MessageEventContent) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := c.client.UserID.String()
|
userID := c.client.UserID.String()
|
||||||
if userID != "" && (strings.Contains(msgEvt.Body, userID) || strings.Contains(msgEvt.FormattedBody, userID)) {
|
if userID != "" && strings.Contains(msgEvt.Body, userID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if mentionsUserInFormattedBody(msgEvt.FormattedBody, c.client.UserID) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -820,6 +833,63 @@ func (c *MatrixChannel) isBotMentioned(msgEvt *event.MessageEventContent) bool {
|
||||||
return re.MatchString(msgEvt.Body) || re.MatchString(msgEvt.FormattedBody)
|
return re.MatchString(msgEvt.Body) || re.MatchString(msgEvt.FormattedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mentionsUserInFormattedBody(formattedBody string, userID id.UserID) bool {
|
||||||
|
target := strings.ToLower(strings.TrimSpace(userID.String()))
|
||||||
|
if target == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedBody = strings.TrimSpace(formattedBody)
|
||||||
|
if formattedBody == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(strings.ToLower(formattedBody), target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := matrixMentionHrefRegexp.FindAllStringSubmatch(formattedBody, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
if len(match) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
decoded := decodeMatrixMentionHref(match[1])
|
||||||
|
if strings.Contains(strings.ToLower(decoded), target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(decoded)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(strings.ToLower(u.Path), target) || strings.Contains(strings.ToLower(u.Fragment), target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.ToLower(decodeMatrixMentionHref(u.Fragment)), target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeMatrixMentionHref(v string) string {
|
||||||
|
decoded := html.UnescapeString(strings.TrimSpace(v))
|
||||||
|
if decoded == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
next, err := url.QueryUnescape(decoded)
|
||||||
|
if err != nil || next == decoded {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
decoded = next
|
||||||
|
}
|
||||||
|
return decoded
|
||||||
|
}
|
||||||
|
|
||||||
func (c *MatrixChannel) typingLoop(ctx context.Context, roomID id.RoomID, session *typingSession) {
|
func (c *MatrixChannel) typingLoop(ctx context.Context, roomID id.RoomID, session *typingSession) {
|
||||||
sendTyping := func() {
|
sendTyping := func() {
|
||||||
_, err := c.client.UserTyping(ctx, roomID, true, typingServerTTL)
|
_, err := c.client.UserTyping(ctx, roomID, true, typingServerTTL)
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,22 @@ func TestIsBotMentioned(t *testing.T) {
|
||||||
},
|
},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "formatted mention href matrix.to plain",
|
||||||
|
msg: event.MessageEventContent{
|
||||||
|
Body: "hello bot",
|
||||||
|
FormattedBody: `<a href="https://matrix.to/#/@picoclaw:matrix.org">PicoClaw</a> hello`,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "formatted mention href matrix.to encoded",
|
||||||
|
msg: event.MessageEventContent{
|
||||||
|
Body: "hello bot",
|
||||||
|
FormattedBody: `<a href="https://matrix.to/#/%40picoclaw%3Amatrix.org">PicoClaw</a> hello`,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue