fix: skip canonical ID parsing for @-prefixed allow_from entries (#2815)

Matrix user IDs (MXIDs) contain colons (e.g. @alice:matrix.org) which
caused MatchAllowed to misinterpret them as canonical platform:id pairs.
The @ prefix in the allow_from entry is an explicit signal of a username
or MXID, not a platform:id separator.

Changes:
- Move isAtUsername check before the canonical parsing block
- Gate canonical parsing with !isAtUsername to skip it for @ entries
- Add direct match of full @-prefixed entry against PlatformID/Username
- Add test cases covering all Matrix allow_from formats from the issue

Fixes #2815
This commit is contained in:
Ashid332 2026-05-08 21:42:54 +05:30
parent 8508f80608
commit cfa640780a
2 changed files with 78 additions and 15 deletions

View file

@ -44,27 +44,31 @@ func MatchAllowed(sender bus.SenderInfo, allowed string) bool {
return false
}
// Try canonical match first: "platform:id" format
if platform, id, ok := ParseCanonicalID(allowed); ok {
// Only treat as canonical if the platform portion looks like a known platform name
// (not a pure-numeric string, which could be a compound ID)
if !isNumeric(platform) {
candidate := BuildCanonicalID(platform, id)
if candidate != "" && sender.CanonicalID != "" {
return strings.EqualFold(sender.CanonicalID, candidate)
}
// If sender has no canonical ID, try matching platform + platformID
return strings.EqualFold(platform, sender.Platform) &&
sender.PlatformID == id
}
}
// Keep track of explicit username format
isAtUsername := strings.HasPrefix(allowed, "@")
// Strip leading "@" for username matching
trimmed := strings.TrimPrefix(allowed, "@")
// Try canonical match first: "platform:id" format.
// Skip when the entry starts with "@" — the "@" prefix signals a
// username or Matrix MXID (e.g. "@alice:matrix.org"), not a platform:id pair.
if !isAtUsername {
if platform, id, ok := ParseCanonicalID(allowed); ok {
// Only treat as canonical if the platform portion looks like a known platform name
// (not a pure-numeric string, which could be a compound ID)
if !isNumeric(platform) {
candidate := BuildCanonicalID(platform, id)
if candidate != "" && sender.CanonicalID != "" {
return strings.EqualFold(sender.CanonicalID, candidate)
}
// If sender has no canonical ID, try matching platform + platformID
return strings.EqualFold(platform, sender.Platform) &&
sender.PlatformID == id
}
}
}
// Split compound "id|username" format
allowedID := trimmed
allowedUser := ""
@ -83,6 +87,18 @@ func MatchAllowed(sender bus.SenderInfo, allowed string) bool {
return true
}
// Match the full "@"-prefixed entry against PlatformID or Username.
// Needed for Matrix MXIDs where both the config entry and the
// sender identifiers include the "@" prefix (e.g. "@alice:matrix.org").
if isAtUsername {
if sender.PlatformID != "" && sender.PlatformID == allowed {
return true
}
if sender.Username != "" && sender.Username == allowed {
return true
}
}
// Match compound sender format against allowed parts
if allowedUser != "" && sender.PlatformID != "" && sender.PlatformID == allowedID {
return true

View file

@ -223,6 +223,53 @@ func TestMatchAllowed(t *testing.T) {
allowed: " 123456 ",
want: true,
},
// Matrix MXID matching (issue #2815)
// Matrix user IDs look like "@alice:matrix.org" — the colon must
// not be misinterpreted as a canonical "platform:id" separator.
{
name: "matrix MXID with @ prefix matches PlatformID",
sender: bus.SenderInfo{
Platform: "matrix",
PlatformID: "@alice:matrix.org",
CanonicalID: BuildCanonicalID("matrix", "@alice:matrix.org"),
Username: "@alice:matrix.org",
},
allowed: "@alice:matrix.org",
want: true,
},
{
name: "matrix MXID without @ prefix matches PlatformID",
sender: bus.SenderInfo{
Platform: "matrix",
PlatformID: "@alice:matrix.org",
CanonicalID: BuildCanonicalID("matrix", "@alice:matrix.org"),
Username: "@alice:matrix.org",
},
allowed: "alice:matrix.org",
want: false, // ambiguous — could be a canonical "platform:id" entry
},
{
name: "matrix canonical format matches",
sender: bus.SenderInfo{
Platform: "matrix",
PlatformID: "@alice:matrix.org",
CanonicalID: BuildCanonicalID("matrix", "@alice:matrix.org"),
Username: "@alice:matrix.org",
},
allowed: "matrix:@alice:matrix.org",
want: true,
},
{
name: "matrix MXID rejects unlisted sender",
sender: bus.SenderInfo{
Platform: "matrix",
PlatformID: "@eve:evil.org",
CanonicalID: BuildCanonicalID("matrix", "@eve:evil.org"),
Username: "@eve:evil.org",
},
allowed: "@alice:matrix.org",
want: false,
},
}
for _, tt := range tests {