Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Allow users to rebind 3pids they own (MSC2229) #5996

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/5996.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow users to rebind 3pids they own (MSC2229).
61 changes: 54 additions & 7 deletions synapse/rest/client/v2_alpha/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
from twisted.internet import defer

from synapse.api.constants import LoginType
from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
from synapse.api.errors import (
AuthError,
Codes,
InvalidClientCredentialsError,
SynapseError,
ThreepidValidationError,
)
from synapse.config.emailconfig import ThreepidBehaviour
from synapse.http.server import finish_request
from synapse.http.servlet import (
Expand Down Expand Up @@ -412,6 +418,7 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
def __init__(self, hs):
super(EmailThreepidRequestTokenRestServlet, self).__init__()
self.hs = hs
self.auth = hs.get_auth()
self.config = hs.config
self.identity_handler = hs.get_handlers().identity_handler
self.store = self.hs.get_datastore()
Expand All @@ -435,12 +442,26 @@ def on_POST(self, request):
Codes.THREEPID_DENIED,
)

requester = None
try:
requester = yield self.auth.get_user_by_req(request)
except (AuthError, InvalidClientCredentialsError):
# No authentication provided, ignore
pass

existing_user_id = yield self.store.get_user_id_by_threepid(
"email", body["email"]
)

if existing_user_id is not None:
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
# If the request is authenticated, allow this MSISDN to be rebound if the requester
# owns it.
# Otherwise, deny the request if the 3PID exists
if existing_user_id:
if (
requester is None or
(requester and existing_user_id != requester.user.to_string)
):
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)

ret = yield self.identity_handler.requestEmailToken(
id_server, email, client_secret, send_attempt, next_link
Expand All @@ -452,8 +473,9 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
PATTERNS = client_patterns("/account/3pid/msisdn/requestToken$")

def __init__(self, hs):
self.hs = hs
super(MsisdnThreepidRequestTokenRestServlet, self).__init__()
self.hs = hs
self.auth = hs.get_auth()
self.store = self.hs.get_datastore()
self.identity_handler = hs.get_handlers().identity_handler

Expand All @@ -480,10 +502,24 @@ def on_POST(self, request):
Codes.THREEPID_DENIED,
)

requester = None
try:
requester = yield self.auth.get_user_by_req(request)
except (AuthError, InvalidClientCredentialsError):
# No authentication provided, ignore
pass

existing_user_id = yield self.store.get_user_id_by_threepid("msisdn", msisdn)

if existing_user_id is not None:
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
# If the request is authenticated, allow this MSISDN to be rebound if the requester
# owns it.
# Otherwise, deny the request if the 3PID exists
if existing_user_id:
if (
requester is None or
(requester and existing_user_id != requester.user.to_string)
):
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)

ret = yield self.identity_handler.requestMsisdnToken(
id_server, country, phone_number, client_secret, send_attempt, next_link
Expand Down Expand Up @@ -522,7 +558,6 @@ def on_POST(self, request):

requester = yield self.auth.get_user_by_req(request)
user_id = requester.user.to_string()

threepid = yield self.identity_handler.threepid_from_creds(threepid_creds)

if not threepid:
Expand All @@ -533,6 +568,18 @@ def on_POST(self, request):
logger.warn("Couldn't add 3pid: invalid response from ID server")
raise SynapseError(500, "Invalid response from ID Server")

existing_user_id = yield self.datastore.get_user_id_by_threepid(
threepid["medium"], threepid["address"]
)

# Check that the user is not trying to add an email that's already bound to another
# user
if existing_user_id and existing_user_id != requester.user.to_string():
raise SynapseError(
400, "This 3PID is already in use by %s" % (existing_user_id,),
Codes.THREEPID_IN_USE,
)

yield self.auth_handler.add_threepid(
user_id, threepid["medium"], threepid["address"], threepid["validated_at"]
)
Expand Down