diff options
author | Andrew Morgan <andrew@amorgan.xyz> | 2019-08-21 16:25:00 +0200 |
---|---|---|
committer | Andrew Morgan <andrew@amorgan.xyz> | 2019-08-21 16:25:00 +0200 |
commit | 1954438610691f7dcfd6f5478265f6f5d7df9daa (patch) | |
tree | a49dc48f34e468af0506d423e2487c0c9ba51827 | |
parent | Merge pull request #5860 from matrix-org/erikj/update_5704_comments (diff) | |
download | synapse-1954438610691f7dcfd6f5478265f6f5d7df9daa.tar.xz |
Use the v2 lookup API
-rw-r--r-- | synapse/handlers/identity.py | 12 | ||||
-rw-r--r-- | synapse/handlers/room_member.py | 68 | ||||
-rw-r--r-- | synapse/util/hash.py | 33 |
3 files changed, 102 insertions, 11 deletions
diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py index d199521b58..beb7cadd46 100644 --- a/synapse/handlers/identity.py +++ b/synapse/handlers/identity.py @@ -31,6 +31,7 @@ from synapse.api.errors import ( ) from ._base import BaseHandler +from enum import Enum logger = logging.getLogger(__name__) @@ -282,3 +283,14 @@ class IdentityHandler(BaseHandler): except HttpResponseException as e: logger.info("Proxied requestToken failed: %r", e) raise e.to_synapse_error() + +class LookupAlgorithm(Enum): + """ + Supported hashing algorithms when performing a 3PID lookup. + + 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 + """ + SHA256 = "sha256" + NONE = "none" diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py index 249a6d9c5d..68b280924d 100644 --- a/synapse/handlers/room_member.py +++ b/synapse/handlers/room_member.py @@ -32,14 +32,16 @@ from synapse.api.errors import AuthError, Codes, HttpResponseException, SynapseE 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 +from synapse.handlers.identity import LookupAlgorithm + logger = logging.getLogger(__name__) id_server_scheme = "https://" - class RoomMemberHandler(object): # TODO(paul): This handler currently contains a messy conflation of # low-level API that works on UserID objects and so on, and REST-level @@ -697,22 +699,66 @@ class RoomMemberHandler(object): raise SynapseError( 403, "Looking up third-party identifiers is denied from this server" ) + + # Check what hashing details are supported by this identity server 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}, + hash_details = yield self.simple_http_client.get_json( + "%s%s/_matrix/identity/v2/hash_details" % (id_server_scheme, id_server) ) + supported_lookup_algorithms = hash_details["algorithms"] + lookup_pepper = hash_details["lookup_pepper"] + except (HttpResponseException, ValueError) as e: + logger.warn("Error when looking up hashing details: %s" % (e,)) + return None - 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"] + # Check if none of the supported lookup algorithms are present + if not any(i in supported_lookup_algorithms for i in [LookupAlgorithm.SHA256, + LookupAlgorithm.NONE]): + logger.warn("No supported lookup algorithms found for %s%s" % + (id_server_scheme, id_server)) - except IOError as e: - logger.warn("Error from identity server lookup: %s" % (e,)) return None + 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) + + 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: + 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 + return lookup_results["mappings"].get(lookup_value) + + @defer.inlineCallbacks def _verify_any_signature(self, data, server_hostname): if server_hostname not in data["signatures"]: diff --git a/synapse/util/hash.py b/synapse/util/hash.py new file mode 100644 index 0000000000..aa5d5ae31c --- /dev/null +++ b/synapse/util/hash.py @@ -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) + |