mirror of
https://mau.dev/maunium/synapse.git
synced 2024-10-01 01:36:05 -04:00
Fix userconsent on Python 3 (#3938)
This commit is contained in:
parent
8f5c23d0cd
commit
6e05fd032c
1
changelog.d/3938.bugfix
Normal file
1
changelog.d/3938.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Sending server notices regarding user consent now works on Python 3.
|
@ -64,7 +64,7 @@ class ConsentURIBuilder(object):
|
||||
"""
|
||||
mac = hmac.new(
|
||||
key=self._hmac_secret,
|
||||
msg=user_id,
|
||||
msg=user_id.encode('ascii'),
|
||||
digestmod=sha256,
|
||||
).hexdigest()
|
||||
consent_uri = "%s_matrix/consent?%s" % (
|
||||
|
100
tests/server_notices/test_consent.py
Normal file
100
tests/server_notices/test_consent.py
Normal file
@ -0,0 +1,100 @@
|
||||
# -*- 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.
|
||||
|
||||
from synapse.rest.client.v1 import admin, login, room
|
||||
from synapse.rest.client.v2_alpha import sync
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
||||
class ConsentNoticesTests(unittest.HomeserverTestCase):
|
||||
|
||||
servlets = [
|
||||
sync.register_servlets,
|
||||
admin.register_servlets,
|
||||
login.register_servlets,
|
||||
room.register_servlets,
|
||||
]
|
||||
|
||||
def make_homeserver(self, reactor, clock):
|
||||
|
||||
self.consent_notice_message = "consent %(consent_uri)s"
|
||||
config = self.default_config()
|
||||
config.user_consent_version = "1"
|
||||
config.user_consent_server_notice_content = {
|
||||
"msgtype": "m.text",
|
||||
"body": self.consent_notice_message,
|
||||
}
|
||||
config.public_baseurl = "https://example.com/"
|
||||
config.form_secret = "123abc"
|
||||
|
||||
config.server_notices_mxid = "@notices:test"
|
||||
config.server_notices_mxid_display_name = "test display name"
|
||||
config.server_notices_mxid_avatar_url = None
|
||||
config.server_notices_room_name = "Server Notices"
|
||||
|
||||
hs = self.setup_test_homeserver(config=config)
|
||||
|
||||
return hs
|
||||
|
||||
def prepare(self, reactor, clock, hs):
|
||||
self.user_id = self.register_user("bob", "abc123")
|
||||
self.access_token = self.login("bob", "abc123")
|
||||
|
||||
def test_get_sync_message(self):
|
||||
"""
|
||||
When user consent server notices are enabled, a sync will cause a notice
|
||||
to fire (in a room which the user is invited to). The notice contains
|
||||
the notice URL + an authentication code.
|
||||
"""
|
||||
# Initial sync, to get the user consent room invite
|
||||
request, channel = self.make_request(
|
||||
"GET", "/_matrix/client/r0/sync", access_token=self.access_token
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
# Get the Room ID to join
|
||||
room_id = list(channel.json_body["rooms"]["invite"].keys())[0]
|
||||
|
||||
# Join the room
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/" + room_id + "/join",
|
||||
access_token=self.access_token,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
# Sync again, to get the message in the room
|
||||
request, channel = self.make_request(
|
||||
"GET", "/_matrix/client/r0/sync", access_token=self.access_token
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
# Get the message
|
||||
room = channel.json_body["rooms"]["join"][room_id]
|
||||
messages = [
|
||||
x for x in room["timeline"]["events"] if x["type"] == "m.room.message"
|
||||
]
|
||||
|
||||
# One message, with the consent URL
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertTrue(
|
||||
messages[0]["content"]["body"].startswith(
|
||||
"consent https://example.com/_matrix/consent"
|
||||
)
|
||||
)
|
@ -14,10 +14,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
|
||||
from mock import Mock
|
||||
|
||||
from twisted.internet import defer
|
||||
@ -145,34 +141,8 @@ class ClientIpAuthTestCase(unittest.HomeserverTestCase):
|
||||
return hs
|
||||
|
||||
def prepare(self, hs, reactor, clock):
|
||||
self.hs.config.registration_shared_secret = u"shared"
|
||||
self.store = self.hs.get_datastore()
|
||||
|
||||
# Create the user
|
||||
request, channel = self.make_request("GET", "/_matrix/client/r0/admin/register")
|
||||
self.render(request)
|
||||
nonce = channel.json_body["nonce"]
|
||||
|
||||
want_mac = hmac.new(key=b"shared", digestmod=hashlib.sha1)
|
||||
want_mac.update(nonce.encode('ascii') + b"\x00bob\x00abc123\x00admin")
|
||||
want_mac = want_mac.hexdigest()
|
||||
|
||||
body = json.dumps(
|
||||
{
|
||||
"nonce": nonce,
|
||||
"username": "bob",
|
||||
"password": "abc123",
|
||||
"admin": True,
|
||||
"mac": want_mac,
|
||||
}
|
||||
)
|
||||
request, channel = self.make_request(
|
||||
"POST", "/_matrix/client/r0/admin/register", body.encode('utf8')
|
||||
)
|
||||
self.render(request)
|
||||
|
||||
self.assertEqual(channel.code, 200)
|
||||
self.user_id = channel.json_body["user_id"]
|
||||
self.user_id = self.register_user("bob", "abc123", True)
|
||||
|
||||
def test_request_with_xforwarded(self):
|
||||
"""
|
||||
@ -194,20 +164,7 @@ class ClientIpAuthTestCase(unittest.HomeserverTestCase):
|
||||
def _runtest(self, headers, expected_ip, make_request_args):
|
||||
device_id = "bleb"
|
||||
|
||||
body = json.dumps(
|
||||
{
|
||||
"type": "m.login.password",
|
||||
"user": "bob",
|
||||
"password": "abc123",
|
||||
"device_id": device_id,
|
||||
}
|
||||
)
|
||||
request, channel = self.make_request(
|
||||
"POST", "/_matrix/client/r0/login", body.encode('utf8'), **make_request_args
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
access_token = channel.json_body["access_token"].encode('ascii')
|
||||
access_token = self.login("bob", "abc123", device_id=device_id)
|
||||
|
||||
# Advance to a known time
|
||||
self.reactor.advance(123456 - self.reactor.seconds())
|
||||
@ -215,7 +172,6 @@ class ClientIpAuthTestCase(unittest.HomeserverTestCase):
|
||||
request, channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/r0/admin/users/" + self.user_id,
|
||||
body.encode('utf8'),
|
||||
access_token=access_token,
|
||||
**make_request_args
|
||||
)
|
||||
|
@ -14,6 +14,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
|
||||
from mock import Mock
|
||||
@ -32,6 +34,7 @@ from synapse.types import UserID, create_requester
|
||||
from synapse.util.logcontext import LoggingContextFilter
|
||||
|
||||
from tests.server import get_clock, make_request, render, setup_test_homeserver
|
||||
from tests.utils import default_config
|
||||
|
||||
# Set up putting Synapse's logs into Trial's.
|
||||
rootLogger = logging.getLogger()
|
||||
@ -121,7 +124,7 @@ class TestCase(unittest.TestCase):
|
||||
try:
|
||||
self.assertEquals(attrs[key], getattr(obj, key))
|
||||
except AssertionError as e:
|
||||
raise (type(e))(str(e) + " for '.%s'" % key)
|
||||
raise (type(e))(e.message + " for '.%s'" % key)
|
||||
|
||||
def assert_dict(self, required, actual):
|
||||
"""Does a partial assert of a dict.
|
||||
@ -223,6 +226,15 @@ class HomeserverTestCase(TestCase):
|
||||
hs = self.setup_test_homeserver()
|
||||
return hs
|
||||
|
||||
def default_config(self, name="test"):
|
||||
"""
|
||||
Get a default HomeServer config object.
|
||||
|
||||
Args:
|
||||
name (str): The homeserver name/domain.
|
||||
"""
|
||||
return default_config(name)
|
||||
|
||||
def prepare(self, reactor, clock, homeserver):
|
||||
"""
|
||||
Prepare for the test. This involves things like mocking out parts of
|
||||
@ -297,3 +309,69 @@ class HomeserverTestCase(TestCase):
|
||||
return d
|
||||
self.pump()
|
||||
return self.successResultOf(d)
|
||||
|
||||
def register_user(self, username, password, admin=False):
|
||||
"""
|
||||
Register a user. Requires the Admin API be registered.
|
||||
|
||||
Args:
|
||||
username (bytes/unicode): The user part of the new user.
|
||||
password (bytes/unicode): The password of the new user.
|
||||
admin (bool): Whether the user should be created as an admin
|
||||
or not.
|
||||
|
||||
Returns:
|
||||
The MXID of the new user (unicode).
|
||||
"""
|
||||
self.hs.config.registration_shared_secret = u"shared"
|
||||
|
||||
# Create the user
|
||||
request, channel = self.make_request("GET", "/_matrix/client/r0/admin/register")
|
||||
self.render(request)
|
||||
nonce = channel.json_body["nonce"]
|
||||
|
||||
want_mac = hmac.new(key=b"shared", digestmod=hashlib.sha1)
|
||||
nonce_str = b"\x00".join([username.encode('utf8'), password.encode('utf8')])
|
||||
if admin:
|
||||
nonce_str += b"\x00admin"
|
||||
else:
|
||||
nonce_str += b"\x00notadmin"
|
||||
want_mac.update(nonce.encode('ascii') + b"\x00" + nonce_str)
|
||||
want_mac = want_mac.hexdigest()
|
||||
|
||||
body = json.dumps(
|
||||
{
|
||||
"nonce": nonce,
|
||||
"username": username,
|
||||
"password": password,
|
||||
"admin": admin,
|
||||
"mac": want_mac,
|
||||
}
|
||||
)
|
||||
request, channel = self.make_request(
|
||||
"POST", "/_matrix/client/r0/admin/register", body.encode('utf8')
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
user_id = channel.json_body["user_id"]
|
||||
return user_id
|
||||
|
||||
def login(self, username, password, device_id=None):
|
||||
"""
|
||||
Log in a user, and get an access token. Requires the Login API be
|
||||
registered.
|
||||
|
||||
"""
|
||||
body = {"type": "m.login.password", "user": username, "password": password}
|
||||
if device_id:
|
||||
body["device_id"] = device_id
|
||||
|
||||
request, channel = self.make_request(
|
||||
"POST", "/_matrix/client/r0/login", json.dumps(body).encode('utf8')
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
access_token = channel.json_body["access_token"].encode('ascii')
|
||||
return access_token
|
||||
|
105
tests/utils.py
105
tests/utils.py
@ -96,6 +96,62 @@ def setupdb():
|
||||
atexit.register(_cleanup)
|
||||
|
||||
|
||||
def default_config(name):
|
||||
"""
|
||||
Create a reasonable test config.
|
||||
"""
|
||||
config = Mock()
|
||||
config.signing_key = [MockKey()]
|
||||
config.event_cache_size = 1
|
||||
config.enable_registration = True
|
||||
config.macaroon_secret_key = "not even a little secret"
|
||||
config.expire_access_token = False
|
||||
config.server_name = name
|
||||
config.trusted_third_party_id_servers = []
|
||||
config.room_invite_state_types = []
|
||||
config.password_providers = []
|
||||
config.worker_replication_url = ""
|
||||
config.worker_app = None
|
||||
config.email_enable_notifs = False
|
||||
config.block_non_admin_invites = False
|
||||
config.federation_domain_whitelist = None
|
||||
config.federation_rc_reject_limit = 10
|
||||
config.federation_rc_sleep_limit = 10
|
||||
config.federation_rc_sleep_delay = 100
|
||||
config.federation_rc_concurrent = 10
|
||||
config.filter_timeline_limit = 5000
|
||||
config.user_directory_search_all_users = False
|
||||
config.user_consent_server_notice_content = None
|
||||
config.block_events_without_consent_error = None
|
||||
config.media_storage_providers = []
|
||||
config.auto_join_rooms = []
|
||||
config.limit_usage_by_mau = False
|
||||
config.hs_disabled = False
|
||||
config.hs_disabled_message = ""
|
||||
config.hs_disabled_limit_type = ""
|
||||
config.max_mau_value = 50
|
||||
config.mau_trial_days = 0
|
||||
config.mau_limits_reserved_threepids = []
|
||||
config.admin_contact = None
|
||||
config.rc_messages_per_second = 10000
|
||||
config.rc_message_burst_count = 10000
|
||||
|
||||
# we need a sane default_room_version, otherwise attempts to create rooms will
|
||||
# fail.
|
||||
config.default_room_version = "1"
|
||||
|
||||
# disable user directory updates, because they get done in the
|
||||
# background, which upsets the test runner.
|
||||
config.update_user_directory = False
|
||||
|
||||
def is_threepid_reserved(threepid):
|
||||
return ServerConfig.is_threepid_reserved(config, threepid)
|
||||
|
||||
config.is_threepid_reserved.side_effect = is_threepid_reserved
|
||||
|
||||
return config
|
||||
|
||||
|
||||
class TestHomeServer(HomeServer):
|
||||
DATASTORE_CLASS = DataStore
|
||||
|
||||
@ -124,54 +180,7 @@ def setup_test_homeserver(
|
||||
from twisted.internet import reactor
|
||||
|
||||
if config is None:
|
||||
config = Mock()
|
||||
config.signing_key = [MockKey()]
|
||||
config.event_cache_size = 1
|
||||
config.enable_registration = True
|
||||
config.macaroon_secret_key = "not even a little secret"
|
||||
config.expire_access_token = False
|
||||
config.server_name = name
|
||||
config.trusted_third_party_id_servers = []
|
||||
config.room_invite_state_types = []
|
||||
config.password_providers = []
|
||||
config.worker_replication_url = ""
|
||||
config.worker_app = None
|
||||
config.email_enable_notifs = False
|
||||
config.block_non_admin_invites = False
|
||||
config.federation_domain_whitelist = None
|
||||
config.federation_rc_reject_limit = 10
|
||||
config.federation_rc_sleep_limit = 10
|
||||
config.federation_rc_sleep_delay = 100
|
||||
config.federation_rc_concurrent = 10
|
||||
config.filter_timeline_limit = 5000
|
||||
config.user_directory_search_all_users = False
|
||||
config.user_consent_server_notice_content = None
|
||||
config.block_events_without_consent_error = None
|
||||
config.media_storage_providers = []
|
||||
config.auto_join_rooms = []
|
||||
config.limit_usage_by_mau = False
|
||||
config.hs_disabled = False
|
||||
config.hs_disabled_message = ""
|
||||
config.hs_disabled_limit_type = ""
|
||||
config.max_mau_value = 50
|
||||
config.mau_trial_days = 0
|
||||
config.mau_limits_reserved_threepids = []
|
||||
config.admin_contact = None
|
||||
config.rc_messages_per_second = 10000
|
||||
config.rc_message_burst_count = 10000
|
||||
|
||||
# we need a sane default_room_version, otherwise attempts to create rooms will
|
||||
# fail.
|
||||
config.default_room_version = "1"
|
||||
|
||||
# disable user directory updates, because they get done in the
|
||||
# background, which upsets the test runner.
|
||||
config.update_user_directory = False
|
||||
|
||||
def is_threepid_reserved(threepid):
|
||||
return ServerConfig.is_threepid_reserved(config, threepid)
|
||||
|
||||
config.is_threepid_reserved.side_effect = is_threepid_reserved
|
||||
config = default_config(name)
|
||||
|
||||
config.use_frozen_dicts = True
|
||||
config.ldap_enabled = False
|
||||
|
Loading…
Reference in New Issue
Block a user