Merge branch 'develop' of git+ssh://github.com/matrix-org/synapse into matrix-org-hotfixes
This commit is contained in:
commit
36bbac05bd
60
CHANGES.rst
60
CHANGES.rst
|
@ -1,3 +1,63 @@
|
||||||
|
Synapse 0.32.1 (2018-07-06)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add explicit dependency on netaddr (`#3488 <https://github.com/matrix-org/synapse/issues/3488>`_)
|
||||||
|
|
||||||
|
|
||||||
|
Changes in synapse v0.32.0 (2018-07-06)
|
||||||
|
===========================================
|
||||||
|
No changes since 0.32.0rc1
|
||||||
|
|
||||||
|
Synapse 0.32.0rc1 (2018-07-05)
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add blacklist & whitelist of servers allowed to send events to a room via ``m.room.server_acl`` event.
|
||||||
|
- Cache factor override system for specific caches (`#3334 <https://github.com/matrix-org/synapse/issues/3334>`_)
|
||||||
|
- Add metrics to track appservice transactions (`#3344 <https://github.com/matrix-org/synapse/issues/3344>`_)
|
||||||
|
- Try to log more helpful info when a sig verification fails (`#3372 <https://github.com/matrix-org/synapse/issues/3372>`_)
|
||||||
|
- Synapse now uses the best performing JSON encoder/decoder according to your runtime (simplejson on CPython, stdlib json on PyPy). (`#3462 <https://github.com/matrix-org/synapse/issues/3462>`_)
|
||||||
|
- Add optional ip_range_whitelist param to AS registration files to lock AS IP access (`#3465 <https://github.com/matrix-org/synapse/issues/3465>`_)
|
||||||
|
- Reject invalid server names in federation requests (`#3480 <https://github.com/matrix-org/synapse/issues/3480>`_)
|
||||||
|
- Reject invalid server names in homeserver.yaml (`#3483 <https://github.com/matrix-org/synapse/issues/3483>`_)
|
||||||
|
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Strip access_token from outgoing requests (`#3327 <https://github.com/matrix-org/synapse/issues/3327>`_)
|
||||||
|
- Redact AS tokens in logs (`#3349 <https://github.com/matrix-org/synapse/issues/3349>`_)
|
||||||
|
- Fix federation backfill from SQLite servers (`#3355 <https://github.com/matrix-org/synapse/issues/3355>`_)
|
||||||
|
- Fix event-purge-by-ts admin API (`#3363 <https://github.com/matrix-org/synapse/issues/3363>`_)
|
||||||
|
- Fix event filtering in get_missing_events handler (`#3371 <https://github.com/matrix-org/synapse/issues/3371>`_)
|
||||||
|
- Synapse is now stricter regarding accepting events which it cannot retrieve the prev_events for. (`#3456 <https://github.com/matrix-org/synapse/issues/3456>`_)
|
||||||
|
- Fix bug where synapse would explode when receiving unicode in HTTP User-Agent header (`#3470 <https://github.com/matrix-org/synapse/issues/3470>`_)
|
||||||
|
- Invalidate cache on correct thread to avoid race (`#3473 <https://github.com/matrix-org/synapse/issues/3473>`_)
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- ``doc/postgres.rst``: fix display of the last command block. Thanks to @ArchangeGabriel! (`#3340 <https://github.com/matrix-org/synapse/issues/3340>`_)
|
||||||
|
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Remove was_forgotten_at (`#3324 <https://github.com/matrix-org/synapse/issues/3324>`_)
|
||||||
|
|
||||||
|
|
||||||
|
Misc
|
||||||
|
----
|
||||||
|
|
||||||
|
- `#3332 <https://github.com/matrix-org/synapse/issues/3332>`_, `#3341 <https://github.com/matrix-org/synapse/issues/3341>`_, `#3347 <https://github.com/matrix-org/synapse/issues/3347>`_, `#3348 <https://github.com/matrix-org/synapse/issues/3348>`_, `#3356 <https://github.com/matrix-org/synapse/issues/3356>`_, `#3385 <https://github.com/matrix-org/synapse/issues/3385>`_, `#3446 <https://github.com/matrix-org/synapse/issues/3446>`_, `#3447 <https://github.com/matrix-org/synapse/issues/3447>`_, `#3467 <https://github.com/matrix-org/synapse/issues/3467>`_, `#3474 <https://github.com/matrix-org/synapse/issues/3474>`_
|
||||||
|
|
||||||
|
|
||||||
Changes in synapse v0.31.2 (2018-06-14)
|
Changes in synapse v0.31.2 (2018-06-14)
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Remove was_forgotten_at
|
|
|
@ -1 +0,0 @@
|
||||||
Strip access_token from outgoing requests
|
|
|
@ -1 +0,0 @@
|
||||||
Cache factor override system for specific caches
|
|
|
@ -1 +0,0 @@
|
||||||
``doc/postgres.rst``: fix display of the last command block. Thanks to @ArchangeGabriel!
|
|
|
@ -1 +0,0 @@
|
||||||
Add metrics to track appservice transactions
|
|
|
@ -1 +0,0 @@
|
||||||
Redact AS tokens in logs
|
|
|
@ -1 +0,0 @@
|
||||||
Fix federation backfill from SQLite servers
|
|
|
@ -1 +0,0 @@
|
||||||
Fix event-purge-by-ts admin API
|
|
|
@ -1 +0,0 @@
|
||||||
Fix event filtering in get_missing_events handler
|
|
|
@ -1 +0,0 @@
|
||||||
Try to log more helpful info when a sig verification fails
|
|
|
@ -1 +0,0 @@
|
||||||
Reinstate lost run_on_reactor in unit tests
|
|
|
@ -1 +0,0 @@
|
||||||
Synapse is now stricter regarding accepting events which it cannot retrieve the prev_events for.
|
|
|
@ -1 +0,0 @@
|
||||||
Synapse now uses the best performing JSON encoder/decoder according to your runtime (simplejson on CPython, stdlib json on PyPy).
|
|
|
@ -1 +0,0 @@
|
||||||
Add optional ip_range_whitelist param to AS registration files to lock AS IP access
|
|
|
@ -1 +0,0 @@
|
||||||
Fix bug where synapse would explode when receiving unicode in HTTP User-Agent header
|
|
|
@ -1 +0,0 @@
|
||||||
Invalidate cache on correct thread to avoid race
|
|
|
@ -1 +0,0 @@
|
||||||
Reject invalid server names in federation requests
|
|
|
@ -1 +0,0 @@
|
||||||
Reject invalid server names in homeserver.yaml
|
|
|
@ -17,4 +17,4 @@
|
||||||
""" This is a reference implementation of a Matrix home server.
|
""" This is a reference implementation of a Matrix home server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.31.2"
|
__version__ = "0.32.1"
|
||||||
|
|
|
@ -76,6 +76,8 @@ class EventTypes(object):
|
||||||
Topic = "m.room.topic"
|
Topic = "m.room.topic"
|
||||||
Name = "m.room.name"
|
Name = "m.room.name"
|
||||||
|
|
||||||
|
ServerACL = "m.room.server_acl"
|
||||||
|
|
||||||
|
|
||||||
class RejectedReason(object):
|
class RejectedReason(object):
|
||||||
AUTH_ERROR = "auth_error"
|
AUTH_ERROR = "auth_error"
|
||||||
|
|
|
@ -14,10 +14,14 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
from canonicaljson import json
|
from canonicaljson import json
|
||||||
|
import six
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
from twisted.internet.abstract import isIPAddress
|
||||||
|
|
||||||
|
from synapse.api.constants import EventTypes
|
||||||
from synapse.api.errors import AuthError, FederationError, SynapseError, NotFoundError
|
from synapse.api.errors import AuthError, FederationError, SynapseError, NotFoundError
|
||||||
from synapse.crypto.event_signing import compute_event_signature
|
from synapse.crypto.event_signing import compute_event_signature
|
||||||
from synapse.federation.federation_base import (
|
from synapse.federation.federation_base import (
|
||||||
|
@ -27,6 +31,7 @@ from synapse.federation.federation_base import (
|
||||||
|
|
||||||
from synapse.federation.persistence import TransactionActions
|
from synapse.federation.persistence import TransactionActions
|
||||||
from synapse.federation.units import Edu, Transaction
|
from synapse.federation.units import Edu, Transaction
|
||||||
|
from synapse.http.endpoint import parse_server_name
|
||||||
from synapse.types import get_domain_from_id
|
from synapse.types import get_domain_from_id
|
||||||
from synapse.util import async
|
from synapse.util import async
|
||||||
from synapse.util.caches.response_cache import ResponseCache
|
from synapse.util.caches.response_cache import ResponseCache
|
||||||
|
@ -74,6 +79,9 @@ class FederationServer(FederationBase):
|
||||||
@log_function
|
@log_function
|
||||||
def on_backfill_request(self, origin, room_id, versions, limit):
|
def on_backfill_request(self, origin, room_id, versions, limit):
|
||||||
with (yield self._server_linearizer.queue((origin, room_id))):
|
with (yield self._server_linearizer.queue((origin, room_id))):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
pdus = yield self.handler.on_backfill_request(
|
pdus = yield self.handler.on_backfill_request(
|
||||||
origin, room_id, versions, limit
|
origin, room_id, versions, limit
|
||||||
)
|
)
|
||||||
|
@ -134,6 +142,8 @@ class FederationServer(FederationBase):
|
||||||
|
|
||||||
received_pdus_counter.inc(len(transaction.pdus))
|
received_pdus_counter.inc(len(transaction.pdus))
|
||||||
|
|
||||||
|
origin_host, _ = parse_server_name(transaction.origin)
|
||||||
|
|
||||||
pdus_by_room = {}
|
pdus_by_room = {}
|
||||||
|
|
||||||
for p in transaction.pdus:
|
for p in transaction.pdus:
|
||||||
|
@ -154,9 +164,21 @@ class FederationServer(FederationBase):
|
||||||
# we can process different rooms in parallel (which is useful if they
|
# we can process different rooms in parallel (which is useful if they
|
||||||
# require callouts to other servers to fetch missing events), but
|
# require callouts to other servers to fetch missing events), but
|
||||||
# impose a limit to avoid going too crazy with ram/cpu.
|
# impose a limit to avoid going too crazy with ram/cpu.
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def process_pdus_for_room(room_id):
|
def process_pdus_for_room(room_id):
|
||||||
logger.debug("Processing PDUs for %s", room_id)
|
logger.debug("Processing PDUs for %s", room_id)
|
||||||
|
try:
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
except AuthError as e:
|
||||||
|
logger.warn(
|
||||||
|
"Ignoring PDUs for room %s from banned server", room_id,
|
||||||
|
)
|
||||||
|
for pdu in pdus_by_room[room_id]:
|
||||||
|
event_id = pdu.event_id
|
||||||
|
pdu_results[event_id] = e.error_dict()
|
||||||
|
return
|
||||||
|
|
||||||
for pdu in pdus_by_room[room_id]:
|
for pdu in pdus_by_room[room_id]:
|
||||||
event_id = pdu.event_id
|
event_id = pdu.event_id
|
||||||
try:
|
try:
|
||||||
|
@ -211,6 +233,9 @@ class FederationServer(FederationBase):
|
||||||
if not event_id:
|
if not event_id:
|
||||||
raise NotImplementedError("Specify an event")
|
raise NotImplementedError("Specify an event")
|
||||||
|
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
in_room = yield self.auth.check_host_in_room(room_id, origin)
|
in_room = yield self.auth.check_host_in_room(room_id, origin)
|
||||||
if not in_room:
|
if not in_room:
|
||||||
raise AuthError(403, "Host not in room.")
|
raise AuthError(403, "Host not in room.")
|
||||||
|
@ -234,6 +259,9 @@ class FederationServer(FederationBase):
|
||||||
if not event_id:
|
if not event_id:
|
||||||
raise NotImplementedError("Specify an event")
|
raise NotImplementedError("Specify an event")
|
||||||
|
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
in_room = yield self.auth.check_host_in_room(room_id, origin)
|
in_room = yield self.auth.check_host_in_room(room_id, origin)
|
||||||
if not in_room:
|
if not in_room:
|
||||||
raise AuthError(403, "Host not in room.")
|
raise AuthError(403, "Host not in room.")
|
||||||
|
@ -298,7 +326,9 @@ class FederationServer(FederationBase):
|
||||||
defer.returnValue((200, resp))
|
defer.returnValue((200, resp))
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_make_join_request(self, room_id, user_id):
|
def on_make_join_request(self, origin, room_id, user_id):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
pdu = yield self.handler.on_make_join_request(room_id, user_id)
|
pdu = yield self.handler.on_make_join_request(room_id, user_id)
|
||||||
time_now = self._clock.time_msec()
|
time_now = self._clock.time_msec()
|
||||||
defer.returnValue({"event": pdu.get_pdu_json(time_now)})
|
defer.returnValue({"event": pdu.get_pdu_json(time_now)})
|
||||||
|
@ -306,6 +336,8 @@ class FederationServer(FederationBase):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_invite_request(self, origin, content):
|
def on_invite_request(self, origin, content):
|
||||||
pdu = event_from_pdu_json(content)
|
pdu = event_from_pdu_json(content)
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, pdu.room_id)
|
||||||
ret_pdu = yield self.handler.on_invite_request(origin, pdu)
|
ret_pdu = yield self.handler.on_invite_request(origin, pdu)
|
||||||
time_now = self._clock.time_msec()
|
time_now = self._clock.time_msec()
|
||||||
defer.returnValue((200, {"event": ret_pdu.get_pdu_json(time_now)}))
|
defer.returnValue((200, {"event": ret_pdu.get_pdu_json(time_now)}))
|
||||||
|
@ -314,6 +346,10 @@ class FederationServer(FederationBase):
|
||||||
def on_send_join_request(self, origin, content):
|
def on_send_join_request(self, origin, content):
|
||||||
logger.debug("on_send_join_request: content: %s", content)
|
logger.debug("on_send_join_request: content: %s", content)
|
||||||
pdu = event_from_pdu_json(content)
|
pdu = event_from_pdu_json(content)
|
||||||
|
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, pdu.room_id)
|
||||||
|
|
||||||
logger.debug("on_send_join_request: pdu sigs: %s", pdu.signatures)
|
logger.debug("on_send_join_request: pdu sigs: %s", pdu.signatures)
|
||||||
res_pdus = yield self.handler.on_send_join_request(origin, pdu)
|
res_pdus = yield self.handler.on_send_join_request(origin, pdu)
|
||||||
time_now = self._clock.time_msec()
|
time_now = self._clock.time_msec()
|
||||||
|
@ -325,7 +361,9 @@ class FederationServer(FederationBase):
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_make_leave_request(self, room_id, user_id):
|
def on_make_leave_request(self, origin, room_id, user_id):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
pdu = yield self.handler.on_make_leave_request(room_id, user_id)
|
pdu = yield self.handler.on_make_leave_request(room_id, user_id)
|
||||||
time_now = self._clock.time_msec()
|
time_now = self._clock.time_msec()
|
||||||
defer.returnValue({"event": pdu.get_pdu_json(time_now)})
|
defer.returnValue({"event": pdu.get_pdu_json(time_now)})
|
||||||
|
@ -334,6 +372,10 @@ class FederationServer(FederationBase):
|
||||||
def on_send_leave_request(self, origin, content):
|
def on_send_leave_request(self, origin, content):
|
||||||
logger.debug("on_send_leave_request: content: %s", content)
|
logger.debug("on_send_leave_request: content: %s", content)
|
||||||
pdu = event_from_pdu_json(content)
|
pdu = event_from_pdu_json(content)
|
||||||
|
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, pdu.room_id)
|
||||||
|
|
||||||
logger.debug("on_send_leave_request: pdu sigs: %s", pdu.signatures)
|
logger.debug("on_send_leave_request: pdu sigs: %s", pdu.signatures)
|
||||||
yield self.handler.on_send_leave_request(origin, pdu)
|
yield self.handler.on_send_leave_request(origin, pdu)
|
||||||
defer.returnValue((200, {}))
|
defer.returnValue((200, {}))
|
||||||
|
@ -341,6 +383,9 @@ class FederationServer(FederationBase):
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_event_auth(self, origin, room_id, event_id):
|
def on_event_auth(self, origin, room_id, event_id):
|
||||||
with (yield self._server_linearizer.queue((origin, room_id))):
|
with (yield self._server_linearizer.queue((origin, room_id))):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
time_now = self._clock.time_msec()
|
time_now = self._clock.time_msec()
|
||||||
auth_pdus = yield self.handler.on_event_auth(event_id)
|
auth_pdus = yield self.handler.on_event_auth(event_id)
|
||||||
res = {
|
res = {
|
||||||
|
@ -369,6 +414,9 @@ class FederationServer(FederationBase):
|
||||||
Deferred: Results in `dict` with the same format as `content`
|
Deferred: Results in `dict` with the same format as `content`
|
||||||
"""
|
"""
|
||||||
with (yield self._server_linearizer.queue((origin, room_id))):
|
with (yield self._server_linearizer.queue((origin, room_id))):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
auth_chain = [
|
auth_chain = [
|
||||||
event_from_pdu_json(e)
|
event_from_pdu_json(e)
|
||||||
for e in content["auth_chain"]
|
for e in content["auth_chain"]
|
||||||
|
@ -442,6 +490,9 @@ class FederationServer(FederationBase):
|
||||||
def on_get_missing_events(self, origin, room_id, earliest_events,
|
def on_get_missing_events(self, origin, room_id, earliest_events,
|
||||||
latest_events, limit, min_depth):
|
latest_events, limit, min_depth):
|
||||||
with (yield self._server_linearizer.queue((origin, room_id))):
|
with (yield self._server_linearizer.queue((origin, room_id))):
|
||||||
|
origin_host, _ = parse_server_name(origin)
|
||||||
|
yield self.check_server_matches_acl(origin_host, room_id)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"on_get_missing_events: earliest_events: %r, latest_events: %r,"
|
"on_get_missing_events: earliest_events: %r, latest_events: %r,"
|
||||||
" limit: %d, min_depth: %d",
|
" limit: %d, min_depth: %d",
|
||||||
|
@ -579,6 +630,101 @@ class FederationServer(FederationBase):
|
||||||
)
|
)
|
||||||
defer.returnValue(ret)
|
defer.returnValue(ret)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def check_server_matches_acl(self, server_name, room_id):
|
||||||
|
"""Check if the given server is allowed by the server ACLs in the room
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_name (str): name of server, *without any port part*
|
||||||
|
room_id (str): ID of the room to check
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
AuthError if the server does not match the ACL
|
||||||
|
"""
|
||||||
|
state_ids = yield self.store.get_current_state_ids(room_id)
|
||||||
|
acl_event_id = state_ids.get((EventTypes.ServerACL, ""))
|
||||||
|
|
||||||
|
if not acl_event_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
acl_event = yield self.store.get_event(acl_event_id)
|
||||||
|
if server_matches_acl_event(server_name, acl_event):
|
||||||
|
return
|
||||||
|
|
||||||
|
raise AuthError(code=403, msg="Server is banned from room")
|
||||||
|
|
||||||
|
|
||||||
|
def server_matches_acl_event(server_name, acl_event):
|
||||||
|
"""Check if the given server is allowed by the ACL event
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_name (str): name of server, without any port part
|
||||||
|
acl_event (EventBase): m.room.server_acl event
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if this server is allowed by the ACLs
|
||||||
|
"""
|
||||||
|
logger.debug("Checking %s against acl %s", server_name, acl_event.content)
|
||||||
|
|
||||||
|
# first of all, check if literal IPs are blocked, and if so, whether the
|
||||||
|
# server name is a literal IP
|
||||||
|
allow_ip_literals = acl_event.content.get("allow_ip_literals", True)
|
||||||
|
if not isinstance(allow_ip_literals, bool):
|
||||||
|
logger.warn("Ignorning non-bool allow_ip_literals flag")
|
||||||
|
allow_ip_literals = True
|
||||||
|
if not allow_ip_literals:
|
||||||
|
# check for ipv6 literals. These start with '['.
|
||||||
|
if server_name[0] == '[':
|
||||||
|
return False
|
||||||
|
|
||||||
|
# check for ipv4 literals. We can just lift the routine from twisted.
|
||||||
|
if isIPAddress(server_name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# next, check the deny list
|
||||||
|
deny = acl_event.content.get("deny", [])
|
||||||
|
if not isinstance(deny, (list, tuple)):
|
||||||
|
logger.warn("Ignorning non-list deny ACL %s", deny)
|
||||||
|
deny = []
|
||||||
|
for e in deny:
|
||||||
|
if _acl_entry_matches(server_name, e):
|
||||||
|
# logger.info("%s matched deny rule %s", server_name, e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# then the allow list.
|
||||||
|
allow = acl_event.content.get("allow", [])
|
||||||
|
if not isinstance(allow, (list, tuple)):
|
||||||
|
logger.warn("Ignorning non-list allow ACL %s", allow)
|
||||||
|
allow = []
|
||||||
|
for e in allow:
|
||||||
|
if _acl_entry_matches(server_name, e):
|
||||||
|
# logger.info("%s matched allow rule %s", server_name, e)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# everything else should be rejected.
|
||||||
|
# logger.info("%s fell through", server_name)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _acl_entry_matches(server_name, acl_entry):
|
||||||
|
if not isinstance(acl_entry, six.string_types):
|
||||||
|
logger.warn("Ignoring non-str ACL entry '%s' (is %s)", acl_entry, type(acl_entry))
|
||||||
|
return False
|
||||||
|
regex = _glob_to_regex(acl_entry)
|
||||||
|
return regex.match(server_name)
|
||||||
|
|
||||||
|
|
||||||
|
def _glob_to_regex(glob):
|
||||||
|
res = ''
|
||||||
|
for c in glob:
|
||||||
|
if c == '*':
|
||||||
|
res = res + '.*'
|
||||||
|
elif c == '?':
|
||||||
|
res = res + '.'
|
||||||
|
else:
|
||||||
|
res = res + re.escape(c)
|
||||||
|
return re.compile(res + "\\Z", re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
class FederationHandlerRegistry(object):
|
class FederationHandlerRegistry(object):
|
||||||
"""Allows classes to register themselves as handlers for a given EDU or
|
"""Allows classes to register themselves as handlers for a given EDU or
|
||||||
|
|
|
@ -385,7 +385,9 @@ class FederationMakeJoinServlet(BaseFederationServlet):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, context, user_id):
|
def on_GET(self, origin, content, query, context, user_id):
|
||||||
content = yield self.handler.on_make_join_request(context, user_id)
|
content = yield self.handler.on_make_join_request(
|
||||||
|
origin, context, user_id,
|
||||||
|
)
|
||||||
defer.returnValue((200, content))
|
defer.returnValue((200, content))
|
||||||
|
|
||||||
|
|
||||||
|
@ -394,7 +396,9 @@ class FederationMakeLeaveServlet(BaseFederationServlet):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def on_GET(self, origin, content, query, context, user_id):
|
def on_GET(self, origin, content, query, context, user_id):
|
||||||
content = yield self.handler.on_make_leave_request(context, user_id)
|
content = yield self.handler.on_make_leave_request(
|
||||||
|
origin, context, user_id,
|
||||||
|
)
|
||||||
defer.returnValue((200, content))
|
defer.returnValue((200, content))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,15 +58,13 @@ REQUIREMENTS = {
|
||||||
"six": ["six"],
|
"six": ["six"],
|
||||||
"prometheus_client": ["prometheus_client"],
|
"prometheus_client": ["prometheus_client"],
|
||||||
"attr": ["attr"],
|
"attr": ["attr"],
|
||||||
|
"netaddr>=0.7.18": ["netaddr"],
|
||||||
}
|
}
|
||||||
|
|
||||||
CONDITIONAL_REQUIREMENTS = {
|
CONDITIONAL_REQUIREMENTS = {
|
||||||
"web_client": {
|
"web_client": {
|
||||||
"matrix_angular_sdk>=0.6.8": ["syweb>=0.6.8"],
|
"matrix_angular_sdk>=0.6.8": ["syweb>=0.6.8"],
|
||||||
},
|
},
|
||||||
"preview_url": {
|
|
||||||
"netaddr>=0.7.18": ["netaddr"],
|
|
||||||
},
|
|
||||||
"email.enable_notifs": {
|
"email.enable_notifs": {
|
||||||
"Jinja2>=2.8": ["Jinja2>=2.8"],
|
"Jinja2>=2.8": ["Jinja2>=2.8"],
|
||||||
"bleach>=1.4.2": ["bleach>=1.4.2"],
|
"bleach>=1.4.2": ["bleach>=1.4.2"],
|
||||||
|
|
57
tests/federation/test_federation_server.py
Normal file
57
tests/federation/test_federation_server.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2018 New Vector Ltd
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from synapse.events import FrozenEvent
|
||||||
|
from synapse.federation.federation_server import server_matches_acl_event
|
||||||
|
from tests import unittest
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.DEBUG
|
||||||
|
class ServerACLsTestCase(unittest.TestCase):
|
||||||
|
def test_blacklisted_server(self):
|
||||||
|
e = _create_acl_event({
|
||||||
|
"allow": ["*"],
|
||||||
|
"deny": ["evil.com"],
|
||||||
|
})
|
||||||
|
logging.info("ACL event: %s", e.content)
|
||||||
|
|
||||||
|
self.assertFalse(server_matches_acl_event("evil.com", e))
|
||||||
|
self.assertFalse(server_matches_acl_event("EVIL.COM", e))
|
||||||
|
|
||||||
|
self.assertTrue(server_matches_acl_event("evil.com.au", e))
|
||||||
|
self.assertTrue(server_matches_acl_event("honestly.not.evil.com", e))
|
||||||
|
|
||||||
|
def test_block_ip_literals(self):
|
||||||
|
e = _create_acl_event({
|
||||||
|
"allow_ip_literals": False,
|
||||||
|
"allow": ["*"],
|
||||||
|
})
|
||||||
|
logging.info("ACL event: %s", e.content)
|
||||||
|
|
||||||
|
self.assertFalse(server_matches_acl_event("1.2.3.4", e))
|
||||||
|
self.assertTrue(server_matches_acl_event("1a.2.3.4", e))
|
||||||
|
self.assertFalse(server_matches_acl_event("[1:2::]", e))
|
||||||
|
self.assertTrue(server_matches_acl_event("1:2:3:4", e))
|
||||||
|
|
||||||
|
|
||||||
|
def _create_acl_event(content):
|
||||||
|
return FrozenEvent({
|
||||||
|
"room_id": "!a:b",
|
||||||
|
"event_id": "$a:b",
|
||||||
|
"type": "m.room.server_acls",
|
||||||
|
"sender": "@a:b",
|
||||||
|
"content": content
|
||||||
|
})
|
Loading…
Reference in a new issue