Implement knock feature (#6739)

This PR aims to implement the knock feature as proposed in https://github.com/matrix-org/matrix-doc/pull/2403

Signed-off-by: Sorunome mail@sorunome.de
Signed-off-by: Andrew Morgan andrewm@element.io
This commit is contained in:
Sorunome 2021-06-09 20:39:51 +02:00 committed by GitHub
parent 11846dff8c
commit d936371b69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1614 additions and 119 deletions

View file

@ -1,5 +1,5 @@
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
# Copyright 2014-2021 The Matrix.org Foundation C.I.C.
# Copyright 2020 Sorunome
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -47,6 +47,7 @@ class TransportLayerClient:
def __init__(self, hs):
self.server_name = hs.hostname
self.client = hs.get_federation_http_client()
self._msc2403_enabled = hs.config.experimental.msc2403_enabled
@log_function
def get_room_state_ids(self, destination, room_id, event_id):
@ -221,12 +222,28 @@ class TransportLayerClient:
is not in our federation whitelist
"""
valid_memberships = {Membership.JOIN, Membership.LEAVE}
# Allow knocking if the feature is enabled
if self._msc2403_enabled:
valid_memberships.add(Membership.KNOCK)
if membership not in valid_memberships:
raise RuntimeError(
"make_membership_event called with membership='%s', must be one of %s"
% (membership, ",".join(valid_memberships))
)
path = _create_v1_path("/make_%s/%s/%s", membership, room_id, user_id)
# Knock currently uses an unstable prefix
if membership == Membership.KNOCK:
# Create a path in the form of /unstable/xyz.amorgan.knock/make_knock/...
path = _create_path(
FEDERATION_UNSTABLE_PREFIX + "/xyz.amorgan.knock",
"/make_knock/%s/%s",
room_id,
user_id,
)
else:
path = _create_v1_path("/make_%s/%s/%s", membership, room_id, user_id)
ignore_backoff = False
retry_on_dns_fail = False
@ -321,6 +338,45 @@ class TransportLayerClient:
return response
@log_function
async def send_knock_v1(
self,
destination: str,
room_id: str,
event_id: str,
content: JsonDict,
) -> JsonDict:
"""
Sends a signed knock membership event to a remote server. This is the second
step for knocking after make_knock.
Args:
destination: The remote homeserver.
room_id: The ID of the room to knock on.
event_id: The ID of the knock membership event that we're sending.
content: The knock membership event that we're sending. Note that this is not the
`content` field of the membership event, but the entire signed membership event
itself represented as a JSON dict.
Returns:
The remote homeserver can optionally return some state from the room. The response
dictionary is in the form:
{"knock_state_events": [<state event dict>, ...]}
The list of state events may be empty.
"""
path = _create_path(
FEDERATION_UNSTABLE_PREFIX + "/xyz.amorgan.knock",
"/send_knock/%s/%s",
room_id,
event_id,
)
return await self.client.put_json(
destination=destination, path=path, data=content
)
@log_function
async def send_invite_v1(self, destination, room_id, event_id, content):
path = _create_v1_path("/invite/%s/%s", room_id, event_id)