1
0

Use the v2 lookup API for 3PID invites (#5897)

This commit is contained in:
Andrew Morgan
2020-02-24 17:15:16 +00:00
10 changed files with 326 additions and 189 deletions

1
changelog.d/5897.feature Normal file
View File

@@ -0,0 +1 @@
Switch to the v2 lookup API for 3PID invites.

View File

@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
class SpamChecker(object):
def __init__(self, hs):
self.spam_checker = None

View File

@@ -20,18 +20,13 @@
import logging
from canonicaljson import json
from signedjson.key import decode_verify_key_bytes
from signedjson.sign import verify_signed_json
from unpaddedbase64 import decode_base64
from twisted.internet import defer
from synapse.api.errors import (
AuthError,
CodeMessageException,
Codes,
HttpResponseException,
ProxiedRequestError,
SynapseError,
)
@@ -48,26 +43,9 @@ class IdentityHandler(BaseHandler):
self.federation_http_client = hs.get_http_client()
self.trusted_id_servers = set(hs.config.trusted_third_party_id_servers)
self.trust_any_id_server_just_for_testing_do_not_use = (
hs.config.use_insecure_ssl_client_just_for_testing_do_not_use
)
self.rewrite_identity_server_urls = hs.config.rewrite_identity_server_urls
self._enable_lookup = hs.config.enable_3pid_lookup
def _should_trust_id_server(self, id_server):
if id_server not in self.trusted_id_servers:
if self.trust_any_id_server_just_for_testing_do_not_use:
logger.warn(
"Trusting untrustworthy ID server %r even though it isn't"
" in the trusted id list for testing because"
" 'use_insecure_ssl_client_just_for_testing_do_not_use'"
" is set in the config",
id_server,
)
else:
return False
return True
@defer.inlineCallbacks
def threepid_from_creds(self, creds):
if "id_server" in creds:
@@ -84,16 +62,17 @@ class IdentityHandler(BaseHandler):
else:
raise SynapseError(400, "No client_secret in creds")
if not self._should_trust_id_server(id_server):
if not should_trust_id_server(self.hs, id_server):
logger.warn(
"%s is not a trusted ID server: rejecting 3pid " + "credentials",
id_server,
)
return None
# if we have a rewrite rule set for the identity server,
# apply it now.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.http_client.get_json(
"https://%s%s"
@@ -130,10 +109,7 @@ class IdentityHandler(BaseHandler):
# if we have a rewrite rule set for the identity server,
# apply it now, but only for sending the request (not
# storing in the database).
if id_server in self.rewrite_identity_server_urls:
id_server_host = self.rewrite_identity_server_urls[id_server]
else:
id_server_host = id_server
id_server_host = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.http_client.post_json_get_json(
@@ -205,7 +181,6 @@ class IdentityHandler(BaseHandler):
Deferred[bool]: True on success, otherwise False if the identity
server doesn't support unbinding
"""
url = "https://%s/_matrix/identity/api/v1/3pid/unbind" % (id_server,)
content = {
"mxid": mxid,
"threepid": {"medium": threepid["medium"], "address": threepid["address"]},
@@ -228,8 +203,7 @@ class IdentityHandler(BaseHandler):
#
# Note that destination_is has to be the real id_server, not
# the server we connect to.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
url = "https://%s/_matrix/identity/api/v1/3pid/unbind" % (id_server,)
@@ -258,7 +232,7 @@ class IdentityHandler(BaseHandler):
def requestEmailToken(
self, id_server, email, client_secret, send_attempt, next_link=None
):
if not self._should_trust_id_server(id_server):
if not should_trust_id_server(self.hs, id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
)
@@ -269,10 +243,8 @@ class IdentityHandler(BaseHandler):
"send_attempt": send_attempt,
}
# if we have a rewrite rule set for the identity server,
# apply it now.
if id_server in self.rewrite_identity_server_urls:
id_server = self.rewrite_identity_server_urls[id_server]
# Rewrite id_server URL if necessary
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
if next_link:
params.update({"next_link": next_link})
@@ -292,11 +264,14 @@ class IdentityHandler(BaseHandler):
def requestMsisdnToken(
self, id_server, country, phone_number, client_secret, send_attempt, **kwargs
):
if not self._should_trust_id_server(id_server):
if not should_trust_id_server(self.hs, id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
)
# Rewrite id_server URL if necessary
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
params = {
"country": country,
"phone_number": phone_number,
@@ -319,119 +294,30 @@ class IdentityHandler(BaseHandler):
logger.info("Proxied requestToken failed: %r", e)
raise e.to_synapse_error()
@defer.inlineCallbacks
def lookup_3pid(self, id_server, medium, address):
"""Looks up a 3pid in the passed identity server.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
medium (str): The type of the third party identifier (e.g. "email").
address (str): The third party identifier (e.g. "foo@example.com").
Returns:
Deferred[dict]: The result of the lookup. See
https://matrix.org/docs/spec/identity_service/r0.1.0.html#association-lookup
for details
"""
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
def should_trust_id_server(hs, id_server):
if id_server not in hs.config.trusted_third_party_id_servers:
if hs.trust_any_id_server_just_for_testing_do_not_use:
logger.warn(
"Trusting untrustworthy ID server %r even though it isn't"
" in the trusted id list for testing because"
" 'use_insecure_ssl_client_just_for_testing_do_not_use'"
" is set in the config",
id_server,
)
else:
return False
return True
if not self._enable_lookup:
raise AuthError(
403, "Looking up third-party identifiers is denied from this server"
)
target = self.rewrite_identity_server_urls.get(id_server, id_server)
class LookupAlgorithm:
"""
Supported hashing algorithms when performing a 3PID lookup.
try:
data = yield self.http_client.get_json(
"https://%s/_matrix/identity/api/v1/lookup" % (target,),
{"medium": medium, "address": address},
)
SHA256 - Hashing an (address, medium, pepper) combo with sha256, then url-safe base64
encoding
NONE - Not performing any hashing. Simply sending an (address, medium) combo in plaintext
"""
if "mxid" in data:
if "signatures" not in data:
raise AuthError(401, "No signatures on 3pid binding")
yield self._verify_any_signature(data, id_server)
except HttpResponseException as e:
logger.info("Proxied lookup failed: %r", e)
raise e.to_synapse_error()
except IOError as e:
logger.info("Failed to contact %r: %s", id_server, e)
raise ProxiedRequestError(503, "Failed to contact identity server")
defer.returnValue(data)
@defer.inlineCallbacks
def bulk_lookup_3pid(self, id_server, threepids):
"""Looks up given 3pids in the passed identity server.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
threepids ([[str, str]]): The third party identifiers to lookup, as
a list of 2-string sized lists ([medium, address]).
Returns:
Deferred[dict]: The result of the lookup. See
https://matrix.org/docs/spec/identity_service/r0.1.0.html#association-lookup
for details
"""
if not self._should_trust_id_server(id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server, Codes.SERVER_NOT_TRUSTED
)
if not self._enable_lookup:
raise AuthError(
403, "Looking up third-party identifiers is denied from this server"
)
target = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.http_client.post_json_get_json(
"https://%s/_matrix/identity/api/v1/bulk_lookup" % (target,),
{"threepids": threepids},
)
except HttpResponseException as e:
logger.info("Proxied lookup failed: %r", e)
raise e.to_synapse_error()
except IOError as e:
logger.info("Failed to contact %r: %s", id_server, e)
raise ProxiedRequestError(503, "Failed to contact identity server")
defer.returnValue(data)
@defer.inlineCallbacks
def _verify_any_signature(self, data, server_hostname):
if server_hostname not in data["signatures"]:
raise AuthError(401, "No signature from server %s" % (server_hostname,))
for key_name, signature in data["signatures"][server_hostname].items():
target = self.rewrite_identity_server_urls.get(
server_hostname, server_hostname
)
key_data = yield self.http_client.get_json(
"https://%s/_matrix/identity/api/v1/pubkey/%s" % (target, key_name)
)
if "public_key" not in key_data:
raise AuthError(
401, "No public key named %s from %s" % (key_name, server_hostname)
)
verify_signed_json(
data,
server_hostname,
decode_verify_key_bytes(
key_name, decode_base64(key_data["public_key"])
),
)
return
raise AuthError(401, "No signature from server %s" % (server_hostname,))
SHA256 = "sha256"
NONE = "none"

View File

@@ -20,11 +20,14 @@ import logging
from six.moves import http_client
from signedjson.key import decode_verify_key_bytes
from signedjson.sign import verify_signed_json
from unpaddedbase64 import decode_base64
from twisted.internet import defer
from synapse import types
from synapse.api.constants import EventTypes, Membership
from synapse.api.ratelimiting import Ratelimiter
from synapse.api.errors import (
AuthError,
Codes,
@@ -32,9 +35,13 @@ from synapse.api.errors import (
HttpResponseException,
SynapseError,
)
from synapse.handlers.identity import LookupAlgorithm, should_trust_id_server
from synapse.types import RoomID, UserID
from synapse.util.async_helpers import Linearizer
from synapse.util.distributor import user_joined_room, user_left_room
from synapse.util.hash import sha256_and_url_safe_base64
from ._base import BaseHandler
logger = logging.getLogger(__name__)
@@ -78,7 +85,11 @@ class RoomMemberHandler(object):
self.rewrite_identity_server_urls = self.config.rewrite_identity_server_urls
self._enable_lookup = hs.config.enable_3pid_lookup
self.allow_per_room_profiles = self.config.allow_per_room_profiles
self.ratelimiter = Ratelimiter()
# This is only used to get at ratelimit function, and
# maybe_kick_guest_users. It's fine there are multiple of these as
# it doesn't store state.
self.base_handler = BaseHandler(hs)
@abc.abstractmethod
def _remote_join(self, requester, remote_room_hosts, room_id, user, content):
@@ -572,7 +583,7 @@ class RoomMemberHandler(object):
event (SynapseEvent): The membership event.
context: The context of the event.
is_guest (bool): Whether the sender is a guest.
room_hosts ([str]): Homeservers which are likely to already be in
remote_room_hosts (list[str]|None): Homeservers which are likely to already be in
the room, and could be danced with in order to join this
homeserver for the first time.
ratelimit (bool): Whether to rate limit this request.
@@ -683,7 +694,7 @@ class RoomMemberHandler(object):
servers.remove(room_alias.domain)
servers.insert(0, room_alias.domain)
return (RoomID.from_string(room_id), servers)
return RoomID.from_string(room_id), servers
@defer.inlineCallbacks
def _get_inviter(self, user_id, room_id):
@@ -714,7 +725,7 @@ class RoomMemberHandler(object):
# We need to rate limit *before* we send out any 3PID invites, so we
# can't just rely on the standard ratelimiting of events.
self.ratelimiter.ratelimit(
self.base_handler.ratelimiter.ratelimit(
requester.user.to_string(),
time_now_s=self.hs.clock.time(),
rate_hz=self.hs.config.rc_third_party_invite.per_second,
@@ -742,7 +753,7 @@ class RoomMemberHandler(object):
Codes.FORBIDDEN,
)
invitee = yield self._lookup_3pid(id_server, medium, address)
invitee = yield self.lookup_3pid(id_server, medium, address)
is_published = yield self.store.is_room_published(room_id)
@@ -766,22 +777,8 @@ class RoomMemberHandler(object):
requester, id_server, medium, address, room_id, inviter, txn_id=txn_id
)
def _get_id_server_target(self, id_server):
"""Looks up an id_server's actual http endpoint
Args:
id_server (str): the server name to lookup.
Returns:
the http endpoint to connect to.
"""
if id_server in self.rewrite_identity_server_urls:
return self.rewrite_identity_server_urls[id_server]
return id_server
@defer.inlineCallbacks
def _lookup_3pid(self, id_server, medium, address):
def lookup_3pid(self, id_server, medium, address):
"""Looks up a 3pid in the passed identity server.
Args:
@@ -793,13 +790,216 @@ class RoomMemberHandler(object):
Returns:
str: the matrix ID of the 3pid, or None if it is not recognized.
"""
if not should_trust_id_server(self.hs, id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server,
Codes.SERVER_NOT_TRUSTED
)
if not self._enable_lookup:
raise SynapseError(
403, "Looking up third-party identifiers is denied from this server"
)
# Rewrite id_server URL if necessary
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
# Check what hashing details are supported by this identity server
use_v1 = False
hash_details = None
try:
data = yield self.identity_handler.lookup_3pid(id_server, medium, address)
return data.get("mxid")
hash_details = yield self.simple_http_client.get_json(
"%s%s/_matrix/identity/v2/hash_details" % (id_server_scheme, id_server)
)
except (HttpResponseException, ValueError) as e:
# Catch HttpResponseExcept for a non-200 response code
# Catch ValueError for non-JSON response body
# Check if this identity server does not know about v2 lookups
if e.code == 404:
# This is an old identity server that does not yet support v2 lookups
use_v1 = True
else:
logger.warn("Error when looking up hashing details: %s" % (e,))
return None
if use_v1:
return (yield self._lookup_3pid_v1(id_server, medium, address))
return (yield self._lookup_3pid_v2(id_server, medium, address, hash_details))
@defer.inlineCallbacks
def _lookup_3pid_v1(self, id_server, medium, address):
"""Looks up a 3pid in the passed identity server using v1 lookup.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
medium (str): The type of the third party identifier (e.g. "email").
address (str): The third party identifier (e.g. "foo@example.com").
Returns:
str: the matrix ID of the 3pid, or None if it is not recognized.
"""
try:
data = yield self.simple_http_client.get_json(
"%s%s/_matrix/identity/api/v1/lookup" % (id_server_scheme, id_server),
{"medium": medium, "address": address},
)
if "mxid" in data:
if "signatures" not in data:
raise AuthError(401, "No signatures on 3pid binding")
yield self._verify_any_signature(data, id_server)
return data["mxid"]
except ProxiedRequestError as e:
logger.warn("Error from identity server lookup: %s" % (e,))
except IOError as e:
logger.warn("Error from identity server lookup: %s" % (e,))
return None
@defer.inlineCallbacks
def _lookup_3pid_v2(self, id_server, medium, address, hash_details):
"""Looks up a 3pid in the passed identity server using v2 lookup.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
medium (str): The type of the third party identifier (e.g. "email").
address (str): The third party identifier (e.g. "foo@example.com").
hash_details (dict[str, str|list]): A dictionary containing hashing information
provided by an identity server.
Returns:
Deferred[str|None]: the matrix ID of the 3pid, or None if it is not recognised.
"""
# Extract information from hash_details
supported_lookup_algorithms = hash_details["algorithms"]
lookup_pepper = hash_details["lookup_pepper"]
# Check if any of the supported lookup algorithms are present
if LookupAlgorithm.SHA256 in supported_lookup_algorithms:
# Perform a hashed lookup
lookup_algorithm = LookupAlgorithm.SHA256
# Hash address, medium and the pepper with sha256
to_hash = "%s %s %s" % (address, medium, lookup_pepper)
lookup_value = sha256_and_url_safe_base64(to_hash)
elif LookupAlgorithm.NONE in supported_lookup_algorithms:
# Perform a non-hashed lookup
lookup_algorithm = LookupAlgorithm.NONE
# Combine together plaintext address and medium
lookup_value = "%s %s" % (address, medium)
else:
logger.warn(
"None of the provided lookup algorithms of %s%s are supported: %s",
id_server_scheme,
id_server,
hash_details["algorithms"],
)
raise SynapseError(
400,
"Provided identity server does not support any v2 lookup "
"algorithms that this homeserver supports.",
)
try:
lookup_results = yield self.simple_http_client.post_json_get_json(
"%s%s/_matrix/identity/v2/lookup" % (id_server_scheme, id_server),
{
"addresses": [lookup_value],
"algorithm": lookup_algorithm,
"pepper": lookup_pepper,
},
)
except (HttpResponseException, ValueError) as e:
# Catch HttpResponseExcept for a non-200 response code
# Catch ValueError for non-JSON response body
logger.warn("Error when performing a 3pid lookup: %s" % (e,))
return None
# Check for a mapping from what we looked up to an MXID
if "mappings" not in lookup_results or not isinstance(
lookup_results["mappings"], dict
):
logger.debug("No results from 3pid lookup")
return None
# Return the MXID if it's available, or None otherwise
mxid = lookup_results["mappings"].get(lookup_value)
return mxid
@defer.inlineCallbacks
def bulk_lookup_3pid(self, id_server, threepids):
"""Looks up given 3pids in the passed identity server.
Args:
id_server (str): The server name (including port, if required)
of the identity server to use.
threepids ([[str, str]]): The third party identifiers to lookup, as
a list of 2-string sized lists ([medium, address]).
Returns:
Deferred[dict]: The result of the lookup. See
https://matrix.org/docs/spec/identity_service/r0.1.0.html#association-lookup
for details
"""
if not should_trust_id_server(self.hs, id_server):
raise SynapseError(
400, "Untrusted ID server '%s'" % id_server,
Codes.SERVER_NOT_TRUSTED
)
if not self._enable_lookup:
raise AuthError(
403, "Looking up third-party identifiers is denied from this server",
)
target = self.rewrite_identity_server_urls.get(id_server, id_server)
try:
data = yield self.simple_http_client.post_json_get_json(
"https://%s/_matrix/identity/api/v1/bulk_lookup" % (target,),
{
"threepids": threepids,
}
)
except HttpResponseException as e:
logger.info("Proxied lookup failed: %r", e)
raise e.to_synapse_error()
except IOError as e:
logger.info("Failed to contact %r: %s", id_server, e)
raise ProxiedRequestError(503, "Failed to contact identity server")
defer.returnValue(data)
@defer.inlineCallbacks
def _verify_any_signature(self, data, server_hostname):
if server_hostname not in data["signatures"]:
raise AuthError(401, "No signature from server %s" % (server_hostname,))
for key_name, signature in data["signatures"][server_hostname].items():
key_data = yield self.simple_http_client.get_json(
"%s%s/_matrix/identity/api/v1/pubkey/%s"
% (id_server_scheme, server_hostname, key_name)
)
if "public_key" not in key_data:
raise AuthError(
401, "No public key named %s from %s" % (key_name, server_hostname)
)
verify_signed_json(
data,
server_hostname,
decode_verify_key_bytes(
key_name, decode_base64(key_data["public_key"])
),
)
return
@defer.inlineCallbacks
def _make_and_store_3pid_invite(
self, requester, id_server, medium, address, room_id, user, txn_id
@@ -917,11 +1117,10 @@ class RoomMemberHandler(object):
display_name (str): A user-friendly name to represent the invited
user.
"""
target = self._get_id_server_target(id_server)
id_server = self.rewrite_identity_server_urls.get(id_server, id_server)
is_url = "%s%s/_matrix/identity/api/v1/store-invite" % (
id_server_scheme,
target,
id_server,
)
invite_config = {
@@ -961,7 +1160,7 @@ class RoomMemberHandler(object):
fallback_public_key = {
"public_key": data["public_key"],
"key_validity_url": "%s%s/_matrix/identity/api/v1/pubkey/isvalid"
% (id_server_scheme, target),
% (id_server_scheme, id_server),
}
else:
fallback_public_key = public_keys[0]
@@ -1028,9 +1227,7 @@ class RoomMemberMasterHandler(RoomMemberHandler):
)
if complexity:
if complexity["v1"] > max_complexity:
return True
return False
return complexity["v1"] > max_complexity
return None
@defer.inlineCallbacks
@@ -1046,10 +1243,7 @@ class RoomMemberMasterHandler(RoomMemberHandler):
max_complexity = self.hs.config.limit_remote_rooms.complexity
complexity = yield self.store.get_room_complexity(room_id)
if complexity["v1"] > max_complexity:
return True
return False
return complexity["v1"] > max_complexity
@defer.inlineCallbacks
def _remote_join(self, requester, remote_room_hosts, room_id, user, content):

View File

@@ -706,6 +706,7 @@ class ThreepidLookupRestServlet(RestServlet):
super(ThreepidLookupRestServlet, self).__init__()
self.auth = hs.get_auth()
self.identity_handler = hs.get_handlers().identity_handler
self.room_member_handler = hs.get_room_member_handler()
@defer.inlineCallbacks
def on_GET(self, request):
@@ -725,7 +726,7 @@ class ThreepidLookupRestServlet(RestServlet):
# Proxy the request to the identity server. lookup_3pid handles checking
# if the lookup is allowed so we don't need to do it here.
ret = yield self.identity_handler.lookup_3pid(id_server, medium, address)
ret = yield self.room_member_handler.lookup_3pid(id_server, medium, address)
defer.returnValue((200, ret))
@@ -737,6 +738,7 @@ class ThreepidBulkLookupRestServlet(RestServlet):
super(ThreepidBulkLookupRestServlet, self).__init__()
self.auth = hs.get_auth()
self.identity_handler = hs.get_handlers().identity_handler
self.room_member_handler = hs.get_room_member_handler()
@defer.inlineCallbacks
def on_POST(self, request):
@@ -751,7 +753,7 @@ class ThreepidBulkLookupRestServlet(RestServlet):
# Proxy the request to the identity server. lookup_3pid handles checking
# if the lookup is allowed so we don't need to do it here.
ret = yield self.identity_handler.bulk_lookup_3pid(
ret = yield self.room_member_handler.bulk_lookup_3pid(
body["id_server"], body["threepids"]
)

33
synapse/util/hash.py Normal file
View File

@@ -0,0 +1,33 @@
# -*- 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.
import hashlib
import unpaddedbase64
def sha256_and_url_safe_base64(input_text):
"""SHA256 hash an input string, encode the digest as url-safe base64, and
return
:param input_text: string to hash
:type input_text: str
:returns a sha256 hashed and url-safe base64 encoded digest
:rtype: str
"""
digest = hashlib.sha256(input_text.encode()).digest()
return unpaddedbase64.encode_base64(digest, urlsafe=True)

View File

@@ -20,6 +20,7 @@ from mock import Mock
from twisted.internet import defer
import synapse.rest.admin
from synapse.api.errors import HttpResponseException
from synapse.rest.client.v1 import login, room
from synapse.rest.client.v2_alpha import account
@@ -109,8 +110,15 @@ class IdentityEnabledTestCase(unittest.HomeserverTestCase):
config["enable_3pid_lookup"] = True
config["trusted_third_party_id_servers"] = ["testis"]
def get_json(uri, args={}, headers=None):
# TODO: Mock v2 hash_details endpoints and don't just run the v1 code
if "/hash_details" in uri:
raise HttpResponseException(404, "I am a happy v1 server", b"{}")
return defer.succeed((200, "{}"))
mock_http_client = Mock(spec=["get_json", "post_json_get_json"])
mock_http_client.get_json.return_value = defer.succeed((200, "{}"))
mock_http_client.get_json.side_effect = get_json
mock_http_client.post_json_get_json.return_value = defer.succeed((200, "{}"))
self.hs = self.setup_test_homeserver(
@@ -143,8 +151,10 @@ class IdentityEnabledTestCase(unittest.HomeserverTestCase):
)
self.render(request)
# There will be a call to hash_details, which will 404
# then /lookup. Thus we don't use `assert_called_with_once` here
get_json = self.hs.get_simple_http_client().get_json
get_json.assert_called_once_with(
get_json.assert_called_with(
"https://testis/_matrix/identity/api/v1/lookup",
{"address": "test@example.com", "medium": "email"},
)
@@ -157,8 +167,10 @@ class IdentityEnabledTestCase(unittest.HomeserverTestCase):
request, channel = self.make_request("GET", url, access_token=self.tok)
self.render(request)
# There will be a call to hash_details, which will 404
# then /lookup. Thus we don't use `assert_called_with_once` here
get_json = self.hs.get_simple_http_client().get_json
get_json.assert_called_once_with(
get_json.assert_called_with(
"https://testis/_matrix/identity/api/v1/lookup",
{"address": "foo@bar.baz", "medium": "email"},
)

View File

@@ -22,6 +22,7 @@ from mock import Mock
from twisted.internet import defer
from synapse.api.constants import EventTypes, JoinRules, RoomCreationPreset
from synapse.api.errors import HttpResponseException
from synapse.rest import admin
from synapse.rest.client.v1 import login, room
from synapse.third_party_rules.access_rules import (
@@ -58,6 +59,10 @@ class RoomAccessTestCase(unittest.HomeserverTestCase):
return defer.succeed(pdu)
def get_json(uri, args={}, headers=None):
# TODO: Mock v2 hash_details endpoints and don't just run the v1 code
if "/hash_details" in uri:
raise HttpResponseException(404, "I am a happy v1 server", b"{}")
address_domain = args["address"].split("@")[1]
return defer.succeed({"hs": address_domain})
@@ -332,6 +337,7 @@ class RoomAccessTestCase(unittest.HomeserverTestCase):
self.hs.config.rc_third_party_invite.burst_count = 10
self.hs.config.rc_third_party_invite.per_second = 0.1
# Note: These calls trigger the mocked get_json method above
# We can't send a 3PID invite to a room that already has two members.
self.send_threepid_invite(
address="test@allowed_domain",

View File

@@ -52,7 +52,6 @@ class RegisterRestServletTestCase(unittest.HomeserverTestCase):
return self.hs
@unittest.DEBUG
def test_POST_appservice_registration_valid(self):
user_id = "@as_user_kermit:test"
as_token = "i_am_an_app_service"

View File

@@ -15,6 +15,8 @@
import json
from mock import Mock
from twisted.internet import defer
import synapse.rest.admin
from synapse.config._base import ConfigError
@@ -287,6 +289,9 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase):
def test_cannot_3pid_invite(self):
"""Test that unbound 3pid invites get rejected.
"""
self.hs.get_room_member_handler().lookup_3pid = Mock()
self.hs.get_room_member_handler().lookup_3pid.return_value = defer.succeed(None)
channel = self._create_room(self.admin_access_token)
assert channel.result["code"] == b"200", channel.result