Add group_id, rate_limit and protocol AS config options (#478)
* Add group_id, rate_limit and protocol AS config options * We currently just record and error check these options. There are not currently implemented. Signed-off-by: Andrew Morgan <andrewm@matrix.org> * Clean things up and fix yaml declaration * Warn loudly when app service requests unimplemented options * Fix comments * Remove high cyclomatic complexity of appservice checkErrors * Set default rate limited to truemain
parent
78440083df
commit
93b7b18646
|
@ -182,6 +182,12 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(ctx context.Context, ev
|
||||||
// appserviceIsInterestedInEvent returns a boolean depending on whether a given
|
// appserviceIsInterestedInEvent returns a boolean depending on whether a given
|
||||||
// event falls within one of a given application service's namespaces.
|
// event falls within one of a given application service's namespaces.
|
||||||
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event gomatrixserverlib.Event, appservice config.ApplicationService) bool {
|
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event gomatrixserverlib.Event, appservice config.ApplicationService) bool {
|
||||||
|
// No reason to queue events if they'll never be sent to the application
|
||||||
|
// service
|
||||||
|
if appservice.URL == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Check sender of the event
|
// Check sender of the event
|
||||||
for _, userNamespace := range appservice.NamespaceMap["users"] {
|
for _, userNamespace := range appservice.NamespaceMap["users"] {
|
||||||
if userNamespace.RegexpObject.MatchString(event.Sender()) {
|
if userNamespace.RegexpObject.MatchString(event.Sender()) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,6 +32,14 @@ type ApplicationServiceNamespace struct {
|
||||||
Exclusive bool `yaml:"exclusive"`
|
Exclusive bool `yaml:"exclusive"`
|
||||||
// A regex pattern that represents the namespace
|
// A regex pattern that represents the namespace
|
||||||
Regex string `yaml:"regex"`
|
Regex string `yaml:"regex"`
|
||||||
|
// The ID of an existing group that all users of this application service will
|
||||||
|
// be added to. This field is only relevant to the `users` namespace.
|
||||||
|
// Note that users who are joined to this group through an application service
|
||||||
|
// are not to be listed when querying for the group's members, however the
|
||||||
|
// group should be listed when querying an application service user's groups.
|
||||||
|
// This is to prevent making spamming all users of an application service
|
||||||
|
// trivial.
|
||||||
|
GroupID string `yaml:"group_id"`
|
||||||
// Regex object representing our pattern. Saves having to recompile every time
|
// Regex object representing our pattern. Saves having to recompile every time
|
||||||
RegexpObject *regexp.Regexp
|
RegexpObject *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
@ -51,14 +60,20 @@ type ApplicationService struct {
|
||||||
// Information about an application service's namespaces. Key is either
|
// Information about an application service's namespaces. Key is either
|
||||||
// "users", "aliases" or "rooms"
|
// "users", "aliases" or "rooms"
|
||||||
NamespaceMap map[string][]ApplicationServiceNamespace `yaml:"namespaces"`
|
NamespaceMap map[string][]ApplicationServiceNamespace `yaml:"namespaces"`
|
||||||
|
// Whether rate limiting is applied to each application service user
|
||||||
|
RateLimited bool `yaml:"rate_limited"`
|
||||||
|
// Any custom protocols that this application service provides (e.g. IRC)
|
||||||
|
Protocols []string `yaml:"protocols"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadAppservices iterates through all application service config files
|
// loadAppservices iterates through all application service config files
|
||||||
// and loads their data into the config object for later access.
|
// and loads their data into the config object for later access.
|
||||||
func loadAppservices(config *Dendrite) error {
|
func loadAppservices(config *Dendrite) error {
|
||||||
for _, configPath := range config.ApplicationServices.ConfigFiles {
|
for _, configPath := range config.ApplicationServices.ConfigFiles {
|
||||||
// Create a new application service
|
// Create a new application service with default options
|
||||||
var appservice ApplicationService
|
appservice := ApplicationService{
|
||||||
|
RateLimited: true,
|
||||||
|
}
|
||||||
|
|
||||||
// Create an absolute path from a potentially relative path
|
// Create an absolute path from a potentially relative path
|
||||||
absPath, err := filepath.Abs(configPath)
|
absPath, err := filepath.Abs(configPath)
|
||||||
|
@ -161,8 +176,20 @@ func checkErrors(config *Dendrite) (err error) {
|
||||||
var idMap = make(map[string]bool)
|
var idMap = make(map[string]bool)
|
||||||
var tokenMap = make(map[string]bool)
|
var tokenMap = make(map[string]bool)
|
||||||
|
|
||||||
|
// Compile regexp object for checking groupIDs
|
||||||
|
groupIDRegexp := regexp.MustCompile(`\+.*:.*`)
|
||||||
|
|
||||||
// Check each application service for any config errors
|
// Check each application service for any config errors
|
||||||
for _, appservice := range config.Derived.ApplicationServices {
|
for _, appservice := range config.Derived.ApplicationServices {
|
||||||
|
// Namespace-related checks
|
||||||
|
for key, namespaceSlice := range appservice.NamespaceMap {
|
||||||
|
for _, namespace := range namespaceSlice {
|
||||||
|
if err := validateNamespace(&appservice, key, &namespace, groupIDRegexp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we've already seen this ID. No two application services
|
// Check if we've already seen this ID. No two application services
|
||||||
// can have the same ID or token.
|
// can have the same ID or token.
|
||||||
if idMap[appservice.ID] {
|
if idMap[appservice.ID] {
|
||||||
|
@ -193,24 +220,53 @@ func checkErrors(config *Dendrite) (err error) {
|
||||||
)})
|
)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check that namespace(s) are valid regex
|
// TODO: Remove once rate_limited is implemented
|
||||||
for _, appservice := range config.Derived.ApplicationServices {
|
if appservice.RateLimited {
|
||||||
for _, namespaceSlice := range appservice.NamespaceMap {
|
log.Warn("WARNING: Application service option rate_limited is currently unimplemented")
|
||||||
for _, namespace := range namespaceSlice {
|
}
|
||||||
if !IsValidRegex(namespace.Regex) {
|
// TODO: Remove once protocols is implemented
|
||||||
return configErrors([]string{fmt.Sprintf(
|
if len(appservice.Protocols) > 0 {
|
||||||
"Invalid regex string for Application Service %s", appservice.ID,
|
log.Warn("WARNING: Application service option protocols is currently unimplemented")
|
||||||
)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupRegexps(config)
|
return setupRegexps(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateNamespace returns nil or an error based on whether a given
|
||||||
|
// application service namespace is valid. A namespace is valid if it has the
|
||||||
|
// required fields, and its regex is correct.
|
||||||
|
func validateNamespace(
|
||||||
|
appservice *ApplicationService,
|
||||||
|
key string,
|
||||||
|
namespace *ApplicationServiceNamespace,
|
||||||
|
groupIDRegexp *regexp.Regexp,
|
||||||
|
) error {
|
||||||
|
// Check that namespace(s) are valid regex
|
||||||
|
if !IsValidRegex(namespace.Regex) {
|
||||||
|
return configErrors([]string{fmt.Sprintf(
|
||||||
|
"Invalid regex string for Application Service %s", appservice.ID,
|
||||||
|
)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if GroupID for the users namespace is in the correct format
|
||||||
|
if key == "users" && namespace.GroupID != "" {
|
||||||
|
// TODO: Remove once group_id is implemented
|
||||||
|
log.Warn("WARNING: Application service option group_id is currently unimplemented")
|
||||||
|
|
||||||
|
correctFormat := groupIDRegexp.MatchString(namespace.GroupID)
|
||||||
|
if !correctFormat {
|
||||||
|
return configErrors([]string{fmt.Sprintf(
|
||||||
|
"Invalid user group_id field for application service %s.",
|
||||||
|
appservice.ID,
|
||||||
|
)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsValidRegex returns true or false based on whether the
|
// IsValidRegex returns true or false based on whether the
|
||||||
// given string is valid regex or not
|
// given string is valid regex or not
|
||||||
func IsValidRegex(regexString string) bool {
|
func IsValidRegex(regexString string) bool {
|
||||||
|
|
Loading…
Reference in New Issue