mirror of https://github.com/watcha-fr/synapse
parent
6bac9ca6d7
commit
f874b16b2e
@ -0,0 +1 @@ |
||||
Allow server admins to define implementations of extra rules for allowing or denying incoming events. |
@ -0,0 +1,42 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Copyright 2019 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. |
||||
|
||||
from synapse.util.module_loader import load_module |
||||
|
||||
from ._base import Config |
||||
|
||||
|
||||
class ThirdPartyRulesConfig(Config): |
||||
def read_config(self, config): |
||||
self.third_party_event_rules = None |
||||
|
||||
provider = config.get("third_party_event_rules", None) |
||||
if provider is not None: |
||||
self.third_party_event_rules = load_module(provider) |
||||
|
||||
def default_config(self, **kwargs): |
||||
return """\ |
||||
# Server admins can define a Python module that implements extra rules for |
||||
# allowing or denying incoming events. In order to work, this module needs to |
||||
# override the methods defined in synapse/events/third_party_rules.py. |
||||
# |
||||
# This feature is designed to be used in closed federations only, where each |
||||
# participating server enforces the same rules. |
||||
# |
||||
#third_party_event_rules: |
||||
# module: "my_custom_project.SuperRulesSet" |
||||
# config: |
||||
# example_option: 'things' |
||||
""" |
@ -0,0 +1,62 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Copyright 2019 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. |
||||
|
||||
from twisted.internet import defer |
||||
|
||||
|
||||
class ThirdPartyEventRules(object): |
||||
"""Allows server admins to provide a Python module implementing an extra set of rules |
||||
to apply when processing events. |
||||
|
||||
This is designed to help admins of closed federations with enforcing custom |
||||
behaviours. |
||||
""" |
||||
|
||||
def __init__(self, hs): |
||||
self.third_party_rules = None |
||||
|
||||
self.store = hs.get_datastore() |
||||
|
||||
module = None |
||||
config = None |
||||
if hs.config.third_party_event_rules: |
||||
module, config = hs.config.third_party_event_rules |
||||
|
||||
if module is not None: |
||||
self.third_party_rules = module(config=config) |
||||
|
||||
@defer.inlineCallbacks |
||||
def check_event_allowed(self, event, context): |
||||
"""Check if a provided event should be allowed in the given context. |
||||
|
||||
Args: |
||||
event (synapse.events.EventBase): The event to be checked. |
||||
context (synapse.events.snapshot.EventContext): The context of the event. |
||||
|
||||
Returns: |
||||
defer.Deferred(bool), True if the event should be allowed, False if not. |
||||
""" |
||||
if self.third_party_rules is None: |
||||
defer.returnValue(True) |
||||
|
||||
prev_state_ids = yield context.get_prev_state_ids(self.store) |
||||
|
||||
# Retrieve the state events from the database. |
||||
state_events = {} |
||||
for key, event_id in prev_state_ids.items(): |
||||
state_events[key] = yield self.store.get_event(event_id, allow_none=True) |
||||
|
||||
ret = yield self.third_party_rules.check_event_allowed(event, state_events) |
||||
defer.returnValue(ret) |
@ -0,0 +1,79 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Copyright 2019 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. |
||||
|
||||
from synapse.rest import admin |
||||
from synapse.rest.client.v1 import login, room |
||||
|
||||
from tests import unittest |
||||
|
||||
|
||||
class ThirdPartyRulesTestModule(object): |
||||
def __init__(self, config): |
||||
pass |
||||
|
||||
def check_event_allowed(self, event, context): |
||||
if event.type == "foo.bar.forbidden": |
||||
return False |
||||
else: |
||||
return True |
||||
|
||||
@staticmethod |
||||
def parse_config(config): |
||||
return config |
||||
|
||||
|
||||
class ThirdPartyRulesTestCase(unittest.HomeserverTestCase): |
||||
servlets = [ |
||||
admin.register_servlets, |
||||
login.register_servlets, |
||||
room.register_servlets, |
||||
] |
||||
|
||||
def make_homeserver(self, reactor, clock): |
||||
config = self.default_config() |
||||
config["third_party_event_rules"] = { |
||||
"module": "tests.rest.client.third_party_rules.ThirdPartyRulesTestModule", |
||||
"config": {}, |
||||
} |
||||
|
||||
self.hs = self.setup_test_homeserver(config=config) |
||||
return self.hs |
||||
|
||||
def test_third_party_rules(self): |
||||
"""Tests that a forbidden event is forbidden from being sent, but an allowed one |
||||
can be sent. |
||||
""" |
||||
user_id = self.register_user("kermit", "monkey") |
||||
tok = self.login("kermit", "monkey") |
||||
|
||||
room_id = self.helper.create_room_as(user_id, tok=tok) |
||||
|
||||
request, channel = self.make_request( |
||||
"PUT", |
||||
"/_matrix/client/r0/rooms/%s/send/foo.bar.allowed/1" % room_id, |
||||
{}, |
||||
access_token=tok, |
||||
) |
||||
self.render(request) |
||||
self.assertEquals(channel.result["code"], b"200", channel.result) |
||||
|
||||
request, channel = self.make_request( |
||||
"PUT", |
||||
"/_matrix/client/r0/rooms/%s/send/foo.bar.forbidden/1" % room_id, |
||||
{}, |
||||
access_token=tok, |
||||
) |
||||
self.render(request) |
||||
self.assertEquals(channel.result["code"], b"403", channel.result) |
Loading…
Reference in new issue