Add tests, tweaks to behaviour

This commit is contained in:
Neil Alexander 2020-08-11 17:44:02 +01:00
parent 2c729c7628
commit 1c071d4e5b
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
7 changed files with 149 additions and 15 deletions

View file

@ -1,3 +1,17 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package acls package acls
import ( import (
@ -57,6 +71,13 @@ type serverACL struct {
deniedRegexes []*regexp.Regexp deniedRegexes []*regexp.Regexp
} }
func compileACLRegex(orig string) (*regexp.Regexp, error) {
escaped := regexp.QuoteMeta(orig)
escaped = strings.Replace(escaped, "\\?", ".", -1)
escaped = strings.Replace(escaped, "\\*", ".*", -1)
return regexp.Compile(escaped)
}
func (s *ServerACLs) OnServerACLUpdate(state *gomatrixserverlib.Event) { func (s *ServerACLs) OnServerACLUpdate(state *gomatrixserverlib.Event) {
acls := &serverACL{} acls := &serverACL{}
if err := json.Unmarshal(state.Content(), &acls.ServerACL); err != nil { if err := json.Unmarshal(state.Content(), &acls.ServerACL); err != nil {
@ -68,20 +89,14 @@ func (s *ServerACLs) OnServerACLUpdate(state *gomatrixserverlib.Event) {
// special characters and then replace * and ? with their regex counterparts. // special characters and then replace * and ? with their regex counterparts.
// https://matrix.org/docs/spec/client_server/r0.6.1#m-room-server-acl // https://matrix.org/docs/spec/client_server/r0.6.1#m-room-server-acl
for _, orig := range acls.Allowed { for _, orig := range acls.Allowed {
escaped := regexp.QuoteMeta(orig) if expr, err := compileACLRegex(orig); err != nil {
escaped = strings.Replace(escaped, "\\?", "(.)", -1)
escaped = strings.Replace(escaped, "\\*", "(.*)", -1)
if expr, err := regexp.Compile(escaped); err != nil {
logrus.WithError(err).Errorf("Failed to compile allowed regex") logrus.WithError(err).Errorf("Failed to compile allowed regex")
} else { } else {
acls.allowedRegexes = append(acls.allowedRegexes, expr) acls.allowedRegexes = append(acls.allowedRegexes, expr)
} }
} }
for _, orig := range acls.Denied { for _, orig := range acls.Denied {
escaped := regexp.QuoteMeta(orig) if expr, err := compileACLRegex(orig); err != nil {
escaped = strings.Replace(escaped, "\\?", "(.)", -1)
escaped = strings.Replace(escaped, "\\*", "(.*)", -1)
if expr, err := regexp.Compile(escaped); err != nil {
logrus.WithError(err).Errorf("Failed to compile denied regex") logrus.WithError(err).Errorf("Failed to compile denied regex")
} else { } else {
acls.deniedRegexes = append(acls.deniedRegexes, expr) acls.deniedRegexes = append(acls.deniedRegexes, expr)
@ -97,7 +112,7 @@ func (s *ServerACLs) OnServerACLUpdate(state *gomatrixserverlib.Event) {
s.acls[state.RoomID()] = acls s.acls[state.RoomID()] = acls
} }
func (s *ServerACLs) IsServerBannedFromRoom(serverNameAndPort gomatrixserverlib.ServerName, roomID string) bool { func (s *ServerACLs) IsServerBannedFromRoom(serverName gomatrixserverlib.ServerName, roomID string) bool {
s.aclsMutex.RLock() s.aclsMutex.RLock()
// First of all check if we have an ACL for this room. If we don't then // First of all check if we have an ACL for this room. If we don't then
// no servers are banned from the room. // no servers are banned from the room.
@ -109,9 +124,8 @@ func (s *ServerACLs) IsServerBannedFromRoom(serverNameAndPort gomatrixserverlib.
s.aclsMutex.RUnlock() s.aclsMutex.RUnlock()
// Split the host and port apart. This is because the spec calls on us to // Split the host and port apart. This is because the spec calls on us to
// validate the hostname only in cases where the port is also present. // validate the hostname only in cases where the port is also present.
serverName, _, err := net.SplitHostPort(string(serverNameAndPort)) if serverNameOnly, _, err := net.SplitHostPort(string(serverName)); err == nil {
if err != nil { serverName = gomatrixserverlib.ServerName(serverNameOnly)
return true
} }
// Check if the hostname is an IPv4 or IPv6 literal. We cheat here by adding // Check if the hostname is an IPv4 or IPv6 literal. We cheat here by adding
// a /0 prefix length just to trick ParseCIDR into working. If we find that // a /0 prefix length just to trick ParseCIDR into working. If we find that

View file

@ -0,0 +1,105 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package acls
import (
"regexp"
"testing"
)
func TestOpenACLsWithBlacklist(t *testing.T) {
roomID := "!test:test.com"
allowRegex, err := compileACLRegex("*")
if err != nil {
t.Fatalf(err.Error())
}
denyRegex, err := compileACLRegex("foo.com")
if err != nil {
t.Fatalf(err.Error())
}
acls := ServerACLs{
acls: make(map[string]*serverACL),
}
acls.acls[roomID] = &serverACL{
ServerACL: ServerACL{
AllowIPLiterals: true,
},
allowedRegexes: []*regexp.Regexp{allowRegex},
deniedRegexes: []*regexp.Regexp{denyRegex},
}
if acls.IsServerBannedFromRoom("1.2.3.4", roomID) {
t.Fatal("Expected 1.2.3.4 to be allowed but wasn't")
}
if acls.IsServerBannedFromRoom("1.2.3.4:2345", roomID) {
t.Fatal("Expected 1.2.3.4 to be allowed but wasn't")
}
if !acls.IsServerBannedFromRoom("foo.com", roomID) {
t.Fatal("Expected foo.com to be banned but wasn't")
}
if !acls.IsServerBannedFromRoom("foo.com:3456", roomID) {
t.Fatal("Expected foo.com:3456 to be banned but wasn't")
}
if acls.IsServerBannedFromRoom("bar.com", roomID) {
t.Fatal("Expected bar.com to be allowed but wasn't")
}
if acls.IsServerBannedFromRoom("bar.com:4567", roomID) {
t.Fatal("Expected bar.com to be allowed but wasn't")
}
}
func TestDefaultACLsWithWhitelist(t *testing.T) {
roomID := "!test:test.com"
allowRegex, err := compileACLRegex("foo.com")
if err != nil {
t.Fatalf(err.Error())
}
acls := ServerACLs{
acls: make(map[string]*serverACL),
}
acls.acls[roomID] = &serverACL{
ServerACL: ServerACL{
AllowIPLiterals: false,
},
allowedRegexes: []*regexp.Regexp{allowRegex},
deniedRegexes: []*regexp.Regexp{},
}
if !acls.IsServerBannedFromRoom("1.2.3.4", roomID) {
t.Fatal("Expected 1.2.3.4 to be banned but wasn't")
}
if !acls.IsServerBannedFromRoom("1.2.3.4:2345", roomID) {
t.Fatal("Expected 1.2.3.4 to be banned but wasn't")
}
if acls.IsServerBannedFromRoom("foo.com", roomID) {
t.Fatal("Expected foo.com to be allowed but wasn't")
}
if acls.IsServerBannedFromRoom("foo.com:3456", roomID) {
t.Fatal("Expected foo.com:3456 to be allowed but wasn't")
}
if !acls.IsServerBannedFromRoom("bar.com", roomID) {
t.Fatal("Expected bar.com to be allowed but wasn't")
}
if !acls.IsServerBannedFromRoom("baz.com", roomID) {
t.Fatal("Expected baz.com to be allowed but wasn't")
}
if !acls.IsServerBannedFromRoom("qux.com:4567", roomID) {
t.Fatal("Expected baz.com to be allowed but wasn't")
}
}

View file

@ -1,3 +1,17 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api package api
import ( import (

View file

@ -79,7 +79,7 @@ func (c *OutputRoomEventConsumer) onNewRoomEvent(
) error { ) error {
ev := msg.Event ev := msg.Event
if ev.Type() == "m.room.server_acl" { if ev.Type() == "m.room.server_acl" && ev.StateKeyEquals("") {
defer c.acls.OnServerACLUpdate(&ev.Event) defer c.acls.OnServerACLUpdate(&ev.Event)
} }

View file

@ -113,7 +113,7 @@ func (h *httpCurrentStateInternalAPI) QueryKnownUsers(
func (h *httpCurrentStateInternalAPI) QueryServerBannedFromRoom( func (h *httpCurrentStateInternalAPI) QueryServerBannedFromRoom(
ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse, ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse,
) error { ) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKnownUsers") span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerBannedFromRoom")
defer span.Finish() defer span.Finish()
apiURL := h.apiURL + QueryServerBannedFromRoomPath apiURL := h.apiURL + QueryServerBannedFromRoomPath

View file

@ -90,7 +90,7 @@ func AddRoutes(internalAPIMux *mux.Router, intAPI api.CurrentStateInternalAPI) {
return util.JSONResponse{Code: http.StatusOK, JSON: &response} return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}), }),
) )
internalAPIMux.Handle(QuerySharedUsersPath, internalAPIMux.Handle(QueryServerBannedFromRoomPath,
httputil.MakeInternalAPI("queryServerBannedFromRoom", func(req *http.Request) util.JSONResponse { httputil.MakeInternalAPI("queryServerBannedFromRoom", func(req *http.Request) util.JSONResponse {
request := api.QueryServerBannedFromRoomRequest{} request := api.QueryServerBannedFromRoomRequest{}
response := api.QueryServerBannedFromRoomResponse{} response := api.QueryServerBannedFromRoomResponse{}

View file

@ -447,3 +447,4 @@ Banned servers cannot /event_auth
Banned servers cannot get missing events Banned servers cannot get missing events
Banned servers cannot get room state ids Banned servers cannot get room state ids
Banned servers cannot backfill Banned servers cannot backfill
Inbound /v1/send_leave rejects leaves from other servers