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
parent
379d2a8c39
commit
6670bd4072
|
@ -0,0 +1 @@
|
||||||
|
Use the v2 Identity Service API for 3PID invites.
|
|
@ -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]
|
||||||
|
|
Loading…
Reference in New Issue