v2 3PID Invites (part of MSC2140) (#5979)

3PID invites require making a request to an identity server to check that the invited 3PID has an Matrix ID linked, and if so, what it is.

These requests are being made on behalf of a user. The user will supply an identity server and an access token for that identity server. The homeserver will then forward this request with the access token (using an `Authorization` header) and, if the given identity server doesn't support v2 endpoints, will fall back to v1 (which doesn't require any access tokens).

Requires: ~~#5976~~
pull/6047/head
Andrew Morgan 2019-09-17 18:05:13 +01:00 committed by GitHub
parent 379d2a8c39
commit 6670bd4072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 23 deletions

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

@ -0,0 +1 @@
Use the v2 Identity Service API for 3PID invites.

View File

@ -684,7 +684,14 @@ class RoomMemberHandler(object):
) )
else: else:
yield self._make_and_store_3pid_invite( yield self._make_and_store_3pid_invite(
requester, id_server, medium, address, room_id, inviter, txn_id=txn_id requester,
id_server,
medium,
address,
room_id,
inviter,
txn_id=txn_id,
id_access_token=id_access_token,
) )
@defer.inlineCallbacks @defer.inlineCallbacks
@ -885,7 +892,15 @@ class RoomMemberHandler(object):
@defer.inlineCallbacks @defer.inlineCallbacks
def _make_and_store_3pid_invite( def _make_and_store_3pid_invite(
self, requester, id_server, medium, address, room_id, user, txn_id self,
requester,
id_server,
medium,
address,
room_id,
user,
txn_id,
id_access_token=None,
): ):
room_state = yield self.state_handler.get_current_state(room_id) room_state = yield self.state_handler.get_current_state(room_id)
@ -934,6 +949,7 @@ class RoomMemberHandler(object):
room_name=room_name, room_name=room_name,
inviter_display_name=inviter_display_name, inviter_display_name=inviter_display_name,
inviter_avatar_url=inviter_avatar_url, inviter_avatar_url=inviter_avatar_url,
id_access_token=id_access_token,
) )
) )
@ -971,6 +987,7 @@ class RoomMemberHandler(object):
room_name, room_name,
inviter_display_name, inviter_display_name,
inviter_avatar_url, inviter_avatar_url,
id_access_token=None,
): ):
""" """
Asks an identity server for a third party invite. Asks an identity server for a third party invite.
@ -990,6 +1007,8 @@ class RoomMemberHandler(object):
inviter_display_name (str): The current display name of the inviter_display_name (str): The current display name of the
inviter. inviter.
inviter_avatar_url (str): The URL of the inviter's avatar. inviter_avatar_url (str): The URL of the inviter's avatar.
id_access_token (str|None): The access token to authenticate to the identity
server with
Returns: Returns:
A deferred tuple containing: A deferred tuple containing:
@ -1000,11 +1019,6 @@ class RoomMemberHandler(object):
display_name (str): A user-friendly name to represent the invited display_name (str): A user-friendly name to represent the invited
user. user.
""" """
is_url = "%s%s/_matrix/identity/api/v1/store-invite" % (
id_server_scheme,
id_server,
)
invite_config = { invite_config = {
"medium": medium, "medium": medium,
"address": address, "address": address,
@ -1017,22 +1031,67 @@ class RoomMemberHandler(object):
"sender_display_name": inviter_display_name, "sender_display_name": inviter_display_name,
"sender_avatar_url": inviter_avatar_url, "sender_avatar_url": inviter_avatar_url,
} }
# Add the identity service access token to the JSON body and use the v2
# Identity Service endpoints if id_access_token is present
data = None
base_url = "%s%s/_matrix/identity" % (id_server_scheme, id_server)
if id_access_token:
key_validity_url = "%s%s/_matrix/identity/v2/pubkey/isvalid" % (
id_server_scheme,
id_server,
)
# Attempt a v2 lookup
url = base_url + "/v2/store-invite"
try: try:
data = yield self.simple_http_client.post_json_get_json( data = yield self.simple_http_client.post_json_get_json(
is_url, invite_config url,
invite_config,
{"Authorization": create_id_access_token_header(id_access_token)},
) )
except HttpResponseException as e: except HttpResponseException as e:
if e.code != 404:
logger.info("Failed to POST %s with JSON: %s", url, e)
raise e
if data is None:
key_validity_url = "%s%s/_matrix/identity/api/v1/pubkey/isvalid" % (
id_server_scheme,
id_server,
)
url = base_url + "/api/v1/store-invite"
try:
data = yield self.simple_http_client.post_json_get_json(
url, invite_config
)
except HttpResponseException as e:
logger.warning(
"Error trying to call /store-invite on %s%s: %s",
id_server_scheme,
id_server,
e,
)
if data is None:
# Some identity servers may only support application/x-www-form-urlencoded # Some identity servers may only support application/x-www-form-urlencoded
# types. This is especially true with old instances of Sydent, see # types. This is especially true with old instances of Sydent, see
# https://github.com/matrix-org/sydent/pull/170 # https://github.com/matrix-org/sydent/pull/170
logger.info( try:
"Failed to POST %s with JSON, falling back to urlencoded form: %s", data = yield self.simple_http_client.post_urlencoded_get_json(
is_url, url, invite_config
)
except HttpResponseException as e:
logger.warning(
"Error calling /store-invite on %s%s with fallback "
"encoding: %s",
id_server_scheme,
id_server,
e, e,
) )
data = yield self.simple_http_client.post_urlencoded_get_json( raise e
is_url, invite_config
)
# TODO: Check for success # TODO: Check for success
token = data["token"] token = data["token"]
@ -1040,8 +1099,7 @@ class RoomMemberHandler(object):
if "public_key" in data: if "public_key" in data:
fallback_public_key = { fallback_public_key = {
"public_key": data["public_key"], "public_key": data["public_key"],
"key_validity_url": "%s%s/_matrix/identity/api/v1/pubkey/isvalid" "key_validity_url": key_validity_url,
% (id_server_scheme, id_server),
} }
else: else:
fallback_public_key = public_keys[0] fallback_public_key = public_keys[0]