@ -21,12 +21,7 @@ from six.moves import http_client
from twisted . internet import defer
from synapse . api . constants import LoginType
from synapse . api . errors import (
Codes ,
HttpResponseException ,
SynapseError ,
ThreepidValidationError ,
)
from synapse . api . errors import Codes , SynapseError , ThreepidValidationError
from synapse . config . emailconfig import ThreepidBehaviour
from synapse . http . server import finish_request
from synapse . http . servlet import (
@ -485,10 +480,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
def on_POST ( self , request ) :
body = parse_json_object_from_request ( request )
assert_params_in_dict (
body ,
[ " id_server " , " client_secret " , " country " , " phone_number " , " send_attempt " ] ,
body , [ " client_secret " , " country " , " phone_number " , " send_attempt " ]
)
id_server = " https:// " + body [ " id_server " ] # Assume https
client_secret = body [ " client_secret " ]
country = body [ " country " ]
phone_number = body [ " phone_number " ]
@ -509,8 +502,23 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
if existing_user_id is not None :
raise SynapseError ( 400 , " MSISDN is already in use " , Codes . THREEPID_IN_USE )
if not self . hs . config . account_threepid_delegate_msisdn :
logger . warn (
" No upstream msisdn account_threepid_delegate configured on the server to "
" handle this request "
)
raise SynapseError (
400 ,
" Adding phone numbers to user account is not supported by this homeserver " ,
)
ret = yield self . identity_handler . requestMsisdnToken (
id_server , country , phone_number , client_secret , send_attempt , next_link
self . hs . config . account_threepid_delegate_msisdn ,
country ,
phone_number ,
client_secret ,
send_attempt ,
next_link ,
)
return 200 , ret
@ -627,81 +635,88 @@ class ThreepidRestServlet(RestServlet):
client_secret = threepid_creds [ " client_secret " ]
sid = threepid_creds [ " sid " ]
# We don't actually know which medium this 3PID is. Thus we first assume it's email,
# and if validation fails we try msisdn
validation_session = None
# Try to validate as email
if self . hs . config . threepid_behaviour_email == ThreepidBehaviour . REMOTE :
# Ask our delegated email identity server
try :
validation_session = yield self . identity_handler . threepid_from_creds (
self . hs . config . account_threepid_delegate_email , threepid_creds
)
except HttpResponseException :
logger . debug (
" %s reported non-validated threepid: %s " ,
self . hs . config . account_threepid_delegate_email ,
threepid_creds ,
)
elif self . hs . config . threepid_behaviour_email == ThreepidBehaviour . LOCAL :
# Get a validated session matching these details
validation_session = yield self . datastore . get_threepid_validation_session (
" email " , client_secret , sid = sid , validated = True
)
# Old versions of Sydent return a 200 http code even on a failed validation check.
# Thus, in addition to the HttpResponseException check above (which checks for
# non-200 errors), we need to make sure validation_session isn't actually an error,
# identified by containing an "error" key
# See https://github.com/matrix-org/sydent/issues/215 for details
if validation_session and " error " not in validation_session :
yield self . _add_threepid_to_account ( user_id , validation_session )
validation_session = yield self . identity_handler . validate_threepid_session (
client_secret , sid
)
if validation_session :
yield self . auth_handler . add_threepid (
user_id ,
validation_session [ " medium " ] ,
validation_session [ " address " ] ,
validation_session [ " validated_at " ] ,
)
return 200 , { }
# Try to validate as msisdn
if self . hs . config . account_threepid_delegate_msisdn :
# Ask our delegated msisdn identity server
try :
validation_session = yield self . identity_handler . threepid_from_creds (
self . hs . config . account_threepid_delegate_msisdn , threepid_creds
)
except HttpResponseException :
logger . debug (
" %s reported non-validated threepid: %s " ,
self . hs . config . account_threepid_delegate_email ,
threepid_creds ,
)
raise SynapseError (
400 , " No validated 3pid session found " , Codes . THREEPID_AUTH_FAILED
)
# Check that validation_session isn't actually an error due to old Sydent instances
# See explanatory comment above
if validation_session and " error " not in validation_session :
yield self . _add_threepid_to_account ( user_id , validation_session )
return 200 , { }
class ThreepidAddRestServlet ( RestServlet ) :
PATTERNS = client_patterns ( " /account/3pid/add$ " , releases = ( ) , unstable = True )
def __init__ ( self , hs ) :
super ( ThreepidAddRestServlet , self ) . __init__ ( )
self . hs = hs
self . identity_handler = hs . get_handlers ( ) . identity_handler
self . auth = hs . get_auth ( )
self . auth_handler = hs . get_auth_handler ( )
@defer . inlineCallbacks
def on_POST ( self , request ) :
requester = yield self . auth . get_user_by_req ( request )
user_id = requester . user . to_string ( )
body = parse_json_object_from_request ( request )
assert_params_in_dict ( body , [ " client_secret " , " sid " ] )
client_secret = body [ " client_secret " ]
sid = body [ " sid " ]
validation_session = yield self . identity_handler . validate_threepid_session (
client_secret , sid
)
if validation_session :
yield self . auth_handler . add_threepid (
user_id ,
validation_session [ " medium " ] ,
validation_session [ " address " ] ,
validation_session [ " validated_at " ] ,
)
return 200 , { }
raise SynapseError (
400 , " No validated 3pid session found " , Codes . THREEPID_AUTH_FAILED
)
class ThreepidBindRestServlet ( RestServlet ) :
PATTERNS = client_patterns ( " /account/3pid/bind$ " , releases = ( ) , unstable = True )
def __init__ ( self , hs ) :
super ( ThreepidBindRestServlet , self ) . __init__ ( )
self . hs = hs
self . identity_handler = hs . get_handlers ( ) . identity_handler
self . auth = hs . get_auth ( )
@defer . inlineCallbacks
def _add_threepid_to_account ( self , user_id , validation_session ) :
""" Add a threepid wrapped in a validation_session dict to an account
def on_POST ( self , req ues t) :
body = parse_json_object_from_request ( request )
Args :
user_id ( str ) : The mxid of the user to add this 3 PID to
assert_params_in_dict ( body , [ " id_server " , " sid " , " client_secret " ] )
id_server = body [ " id_server " ]
sid = body [ " sid " ]
client_secret = body [ " client_secret " ]
id_access_token = body . get ( " id_access_token " ) # optional
validation_session ( dict ) : A dict containing the following :
* medium - medium of the threepid
* address - address of the threepid
* validated_at - timestamp of when the validation occurred
"""
yield self . auth_handler . add_threepid (
user_id ,
validation_session [ " medium " ] ,
validation_session [ " address " ] ,
validation_session [ " validated_at " ] ,
requester = yield self . auth . get_user_by_req ( request )
user_id = requester . user . to_string ( )
yield self . identity_handler . bind_threepid (
client_secret , sid , user_id , id_server , id_access_token
)
return 200 , { }
class ThreepidUnbindRestServlet ( RestServlet ) :
PATTERNS = client_patterns ( " /account/3pid/unbind$ " , releases = ( ) , unstable = True )
@ -794,6 +809,8 @@ def register_servlets(hs, http_server):
MsisdnThreepidRequestTokenRestServlet ( hs ) . register ( http_server )
AddThreepidSubmitTokenServlet ( hs ) . register ( http_server )
ThreepidRestServlet ( hs ) . register ( http_server )
ThreepidAddRestServlet ( hs ) . register ( http_server )
ThreepidBindRestServlet ( hs ) . register ( http_server )
ThreepidUnbindRestServlet ( hs ) . register ( http_server )
ThreepidDeleteRestServlet ( hs ) . register ( http_server )
WhoamiRestServlet ( hs ) . register ( http_server )