Stop using deprecated `keyIds` param on /key/v2/server (#14525)
Fixes #14523.
This commit is contained in:
parent
13aa29db1d
commit
ecb6fe9d9c
|
@ -0,0 +1 @@
|
||||||
|
Stop using deprecated `keyIds` parameter when calling `/_matrix/key/v2/server`.
|
|
@ -1 +0,0 @@
|
||||||
Fix a bug introduced in Synapse 0.9 where it would fail to fetch server keys whose IDs contain a forward slash.
|
|
|
@ -0,0 +1 @@
|
||||||
|
Stop using deprecated `keyIds` parameter when calling `/_matrix/key/v2/server`.
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
import logging
|
import logging
|
||||||
import urllib
|
|
||||||
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Optional, Tuple
|
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
@ -813,31 +812,27 @@ class ServerKeyFetcher(BaseV2KeyFetcher):
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
async def get_key(key_to_fetch_item: _FetchKeyRequest) -> None:
|
async def get_keys(key_to_fetch_item: _FetchKeyRequest) -> None:
|
||||||
server_name = key_to_fetch_item.server_name
|
server_name = key_to_fetch_item.server_name
|
||||||
key_ids = key_to_fetch_item.key_ids
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
keys = await self.get_server_verify_key_v2_direct(server_name, key_ids)
|
keys = await self.get_server_verify_keys_v2_direct(server_name)
|
||||||
results[server_name] = keys
|
results[server_name] = keys
|
||||||
except KeyLookupError as e:
|
except KeyLookupError as e:
|
||||||
logger.warning(
|
logger.warning("Error looking up keys from %s: %s", server_name, e)
|
||||||
"Error looking up keys %s from %s: %s", key_ids, server_name, e
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Error getting keys %s from %s", key_ids, server_name)
|
logger.exception("Error getting keys from %s", server_name)
|
||||||
|
|
||||||
await yieldable_gather_results(get_key, keys_to_fetch)
|
await yieldable_gather_results(get_keys, keys_to_fetch)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
async def get_server_verify_key_v2_direct(
|
async def get_server_verify_keys_v2_direct(
|
||||||
self, server_name: str, key_ids: Iterable[str]
|
self, server_name: str
|
||||||
) -> Dict[str, FetchKeyResult]:
|
) -> Dict[str, FetchKeyResult]:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
server_name:
|
server_name: Server to request keys from
|
||||||
key_ids:
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Map from key ID to lookup result
|
Map from key ID to lookup result
|
||||||
|
@ -845,57 +840,41 @@ class ServerKeyFetcher(BaseV2KeyFetcher):
|
||||||
Raises:
|
Raises:
|
||||||
KeyLookupError if there was a problem making the lookup
|
KeyLookupError if there was a problem making the lookup
|
||||||
"""
|
"""
|
||||||
keys: Dict[str, FetchKeyResult] = {}
|
time_now_ms = self.clock.time_msec()
|
||||||
|
try:
|
||||||
for requested_key_id in key_ids:
|
response = await self.client.get_json(
|
||||||
# we may have found this key as a side-effect of asking for another.
|
destination=server_name,
|
||||||
if requested_key_id in keys:
|
path="/_matrix/key/v2/server",
|
||||||
continue
|
ignore_backoff=True,
|
||||||
|
# we only give the remote server 10s to respond. It should be an
|
||||||
time_now_ms = self.clock.time_msec()
|
# easy request to handle, so if it doesn't reply within 10s, it's
|
||||||
try:
|
# probably not going to.
|
||||||
response = await self.client.get_json(
|
#
|
||||||
destination=server_name,
|
# Furthermore, when we are acting as a notary server, we cannot
|
||||||
path="/_matrix/key/v2/server/"
|
# wait all day for all of the origin servers, as the requesting
|
||||||
+ urllib.parse.quote(requested_key_id, safe=""),
|
# server will otherwise time out before we can respond.
|
||||||
ignore_backoff=True,
|
#
|
||||||
# we only give the remote server 10s to respond. It should be an
|
# (Note that get_json may make 4 attempts, so this can still take
|
||||||
# easy request to handle, so if it doesn't reply within 10s, it's
|
# almost 45 seconds to fetch the headers, plus up to another 60s to
|
||||||
# probably not going to.
|
# read the response).
|
||||||
#
|
timeout=10000,
|
||||||
# Furthermore, when we are acting as a notary server, we cannot
|
|
||||||
# wait all day for all of the origin servers, as the requesting
|
|
||||||
# server will otherwise time out before we can respond.
|
|
||||||
#
|
|
||||||
# (Note that get_json may make 4 attempts, so this can still take
|
|
||||||
# almost 45 seconds to fetch the headers, plus up to another 60s to
|
|
||||||
# read the response).
|
|
||||||
timeout=10000,
|
|
||||||
)
|
|
||||||
except (NotRetryingDestination, RequestSendFailed) as e:
|
|
||||||
# these both have str() representations which we can't really improve
|
|
||||||
# upon
|
|
||||||
raise KeyLookupError(str(e))
|
|
||||||
except HttpResponseException as e:
|
|
||||||
raise KeyLookupError("Remote server returned an error: %s" % (e,))
|
|
||||||
|
|
||||||
assert isinstance(response, dict)
|
|
||||||
if response["server_name"] != server_name:
|
|
||||||
raise KeyLookupError(
|
|
||||||
"Expected a response for server %r not %r"
|
|
||||||
% (server_name, response["server_name"])
|
|
||||||
)
|
|
||||||
|
|
||||||
response_keys = await self.process_v2_response(
|
|
||||||
from_server=server_name,
|
|
||||||
response_json=response,
|
|
||||||
time_added_ms=time_now_ms,
|
|
||||||
)
|
)
|
||||||
await self.store.store_server_verify_keys(
|
except (NotRetryingDestination, RequestSendFailed) as e:
|
||||||
server_name,
|
# these both have str() representations which we can't really improve
|
||||||
time_now_ms,
|
# upon
|
||||||
((server_name, key_id, key) for key_id, key in response_keys.items()),
|
raise KeyLookupError(str(e))
|
||||||
)
|
except HttpResponseException as e:
|
||||||
keys.update(response_keys)
|
raise KeyLookupError("Remote server returned an error: %s" % (e,))
|
||||||
|
|
||||||
return keys
|
assert isinstance(response, dict)
|
||||||
|
if response["server_name"] != server_name:
|
||||||
|
raise KeyLookupError(
|
||||||
|
"Expected a response for server %r not %r"
|
||||||
|
% (server_name, response["server_name"])
|
||||||
|
)
|
||||||
|
|
||||||
|
return await self.process_v2_response(
|
||||||
|
from_server=server_name,
|
||||||
|
response_json=response,
|
||||||
|
time_added_ms=time_now_ms,
|
||||||
|
)
|
||||||
|
|
|
@ -433,7 +433,7 @@ class ServerKeyFetcherTestCase(unittest.HomeserverTestCase):
|
||||||
|
|
||||||
async def get_json(destination, path, **kwargs):
|
async def get_json(destination, path, **kwargs):
|
||||||
self.assertEqual(destination, SERVER_NAME)
|
self.assertEqual(destination, SERVER_NAME)
|
||||||
self.assertEqual(path, "/_matrix/key/v2/server/key1")
|
self.assertEqual(path, "/_matrix/key/v2/server")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
self.http_client.get_json.side_effect = get_json
|
self.http_client.get_json.side_effect = get_json
|
||||||
|
@ -469,18 +469,6 @@ class ServerKeyFetcherTestCase(unittest.HomeserverTestCase):
|
||||||
keys = self.get_success(fetcher.get_keys(SERVER_NAME, ["key1"], 0))
|
keys = self.get_success(fetcher.get_keys(SERVER_NAME, ["key1"], 0))
|
||||||
self.assertEqual(keys, {})
|
self.assertEqual(keys, {})
|
||||||
|
|
||||||
def test_keyid_containing_forward_slash(self) -> None:
|
|
||||||
"""We should url-encode any url unsafe chars in key ids.
|
|
||||||
|
|
||||||
Detects https://github.com/matrix-org/synapse/issues/14488.
|
|
||||||
"""
|
|
||||||
fetcher = ServerKeyFetcher(self.hs)
|
|
||||||
self.get_success(fetcher.get_keys("example.com", ["key/potato"], 0))
|
|
||||||
|
|
||||||
self.http_client.get_json.assert_called_once()
|
|
||||||
args, kwargs = self.http_client.get_json.call_args
|
|
||||||
self.assertEqual(kwargs["path"], "/_matrix/key/v2/server/key%2Fpotato")
|
|
||||||
|
|
||||||
|
|
||||||
class PerspectivesKeyFetcherTestCase(unittest.HomeserverTestCase):
|
class PerspectivesKeyFetcherTestCase(unittest.HomeserverTestCase):
|
||||||
def make_homeserver(self, reactor, clock):
|
def make_homeserver(self, reactor, clock):
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# 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 urllib.parse
|
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from typing import Any, Dict, Optional, Union
|
from typing import Any, Dict, Optional, Union
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
@ -65,9 +64,7 @@ class BaseRemoteKeyResourceTestCase(unittest.HomeserverTestCase):
|
||||||
self.assertTrue(ignore_backoff)
|
self.assertTrue(ignore_backoff)
|
||||||
self.assertEqual(destination, server_name)
|
self.assertEqual(destination, server_name)
|
||||||
key_id = "%s:%s" % (signing_key.alg, signing_key.version)
|
key_id = "%s:%s" % (signing_key.alg, signing_key.version)
|
||||||
self.assertEqual(
|
self.assertEqual(path, "/_matrix/key/v2/server")
|
||||||
path, "/_matrix/key/v2/server/%s" % (urllib.parse.quote(key_id),)
|
|
||||||
)
|
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"server_name": server_name,
|
"server_name": server_name,
|
||||||
|
|
Loading…
Reference in New Issue