dendrite/currentstateserver/acls/acls.go
2020-08-11 15:39:41 +01:00

103 lines
2.6 KiB
Go

package acls
import (
"context"
"encoding/json"
"fmt"
"net"
"regexp"
"strings"
"sync"
"github.com/matrix-org/dendrite/currentstateserver/storage"
"github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus"
)
type ServerACLs struct {
acls map[string]*serverACL // room ID -> ACL
aclsMutex sync.RWMutex // protects the above
}
func NewServerACLs(db storage.Database) *ServerACLs {
ctx := context.TODO()
acls := &ServerACLs{
acls: make(map[string]*serverACL),
}
rooms, err := db.GetKnownRooms(ctx)
if err != nil {
logrus.WithError(err).Errorf("Failed to get known rooms")
}
for _, room := range rooms {
state, err := db.GetStateEvent(ctx, room, "m.room.server_acls", "")
if err != nil {
logrus.WithError(err).Errorf("Failed to get server ACLs for room %q", room)
continue
}
acls.OnServerACLUpdate(&state.Event)
}
return acls
}
type ServerACL struct {
Allowed []string `json:"allow"`
Denied []string `json:"deny"`
AllowIPLiterals bool `json:"allow_ip_literals"`
}
type serverACL struct {
ServerACL
allowedRegexes []*regexp.Regexp
deniedRegexes []*regexp.Regexp
}
func (s *ServerACLs) OnServerACLUpdate(state *gomatrixserverlib.Event) {
acls := &serverACL{}
if err := json.Unmarshal(state.Content(), &acls.ServerACL); err != nil {
return
}
for _, orig := range acls.Allowed {
escaped := regexp.QuoteMeta(orig)
escaped = strings.Replace(escaped, "\\?", "(.)", -1)
escaped = strings.Replace(escaped, "\\*", "(.*)", -1)
if expr, err := regexp.Compile(escaped); err == nil {
acls.allowedRegexes = append(acls.allowedRegexes, expr)
}
}
for _, orig := range acls.Denied {
escaped := regexp.QuoteMeta(orig)
escaped = strings.Replace(escaped, "\\?", "(.)", -1)
escaped = strings.Replace(escaped, "\\*", "(.*)", -1)
if expr, err := regexp.Compile(escaped); err == nil {
acls.deniedRegexes = append(acls.deniedRegexes, expr)
}
}
logrus.Infof("Update server ACLs for %q", state.RoomID())
s.aclsMutex.Lock()
defer s.aclsMutex.RUnlock()
s.acls[state.RoomID()] = acls
}
func (s *ServerACLs) IsServerBannedFromRoom(serverName gomatrixserverlib.ServerName, roomID string) bool {
acls, ok := s.acls[roomID]
if !ok {
return false
}
if _, _, err := net.ParseCIDR(fmt.Sprintf("%s/0", serverName)); err == nil {
if !acls.AllowIPLiterals {
return true
}
}
for _, expr := range acls.deniedRegexes {
if expr.MatchString(string(serverName)) {
return true
}
}
for _, expr := range acls.allowedRegexes {
if expr.MatchString(string(serverName)) {
return false
}
}
return true
}