register.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014 - 2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Contains functions for registering clients."""
  16. import logging
  17. from synapse import types
  18. from synapse.api.constants import MAX_USERID_LENGTH, EventTypes, JoinRules, LoginType
  19. from synapse.api.errors import AuthError, Codes, ConsentNotGivenError, SynapseError
  20. from synapse.config.server import is_threepid_reserved
  21. from synapse.http.servlet import assert_params_in_dict
  22. from synapse.replication.http.login import RegisterDeviceReplicationServlet
  23. from synapse.replication.http.register import (
  24. ReplicationPostRegisterActionsServlet,
  25. ReplicationRegisterServlet,
  26. )
  27. from synapse.spam_checker_api import RegistrationBehaviour
  28. from synapse.storage.state import StateFilter
  29. from synapse.types import RoomAlias, UserID, create_requester
  30. from ._base import BaseHandler
  31. logger = logging.getLogger(__name__)
  32. class RegistrationHandler(BaseHandler):
  33. def __init__(self, hs):
  34. """
  35. Args:
  36. hs (synapse.server.HomeServer):
  37. """
  38. super().__init__(hs)
  39. self.hs = hs
  40. self.auth = hs.get_auth()
  41. self._auth_handler = hs.get_auth_handler()
  42. self.profile_handler = hs.get_profile_handler()
  43. self.user_directory_handler = hs.get_user_directory_handler()
  44. self.identity_handler = self.hs.get_identity_handler()
  45. self.ratelimiter = hs.get_registration_ratelimiter()
  46. self.macaroon_gen = hs.get_macaroon_generator()
  47. self._server_notices_mxid = hs.config.server_notices_mxid
  48. self.spam_checker = hs.get_spam_checker()
  49. if hs.config.worker_app:
  50. self._register_client = ReplicationRegisterServlet.make_client(hs)
  51. self._register_device_client = RegisterDeviceReplicationServlet.make_client(
  52. hs
  53. )
  54. self._post_registration_client = ReplicationPostRegisterActionsServlet.make_client(
  55. hs
  56. )
  57. else:
  58. self.device_handler = hs.get_device_handler()
  59. self.pusher_pool = hs.get_pusherpool()
  60. self.session_lifetime = hs.config.session_lifetime
  61. async def check_username(
  62. self, localpart, guest_access_token=None, assigned_user_id=None
  63. ):
  64. if types.contains_invalid_mxid_characters(localpart):
  65. raise SynapseError(
  66. 400,
  67. "User ID can only contain characters a-z, 0-9, or '=_-./'",
  68. Codes.INVALID_USERNAME,
  69. )
  70. if not localpart:
  71. raise SynapseError(400, "User ID cannot be empty", Codes.INVALID_USERNAME)
  72. if localpart[0] == "_":
  73. raise SynapseError(
  74. 400, "User ID may not begin with _", Codes.INVALID_USERNAME
  75. )
  76. user = UserID(localpart, self.hs.hostname)
  77. user_id = user.to_string()
  78. if assigned_user_id:
  79. if user_id == assigned_user_id:
  80. return
  81. else:
  82. raise SynapseError(
  83. 400,
  84. "A different user ID has already been registered for this session",
  85. )
  86. self.check_user_id_not_appservice_exclusive(user_id)
  87. if len(user_id) > MAX_USERID_LENGTH:
  88. raise SynapseError(
  89. 400,
  90. "User ID may not be longer than %s characters" % (MAX_USERID_LENGTH,),
  91. Codes.INVALID_USERNAME,
  92. )
  93. users = await self.store.get_users_by_id_case_insensitive(user_id)
  94. if users:
  95. if not guest_access_token:
  96. raise SynapseError(
  97. 400, "User ID already taken.", errcode=Codes.USER_IN_USE
  98. )
  99. user_data = await self.auth.get_user_by_access_token(guest_access_token)
  100. if (
  101. not user_data.is_guest
  102. or UserID.from_string(user_data.user_id).localpart != localpart
  103. ):
  104. raise AuthError(
  105. 403,
  106. "Cannot register taken user ID without valid guest "
  107. "credentials for that user.",
  108. errcode=Codes.FORBIDDEN,
  109. )
  110. if guest_access_token is None:
  111. try:
  112. int(localpart)
  113. raise SynapseError(
  114. 400,
  115. "Numeric user IDs are reserved for guest users.",
  116. errcode=Codes.INVALID_USERNAME,
  117. )
  118. except ValueError:
  119. pass
  120. async def register_user(
  121. self,
  122. localpart=None,
  123. password_hash=None,
  124. guest_access_token=None,
  125. make_guest=False,
  126. admin=False,
  127. threepid=None,
  128. user_type=None,
  129. default_display_name=None,
  130. address=None,
  131. bind_emails=[],
  132. by_admin=False,
  133. user_agent_ips=None,
  134. ):
  135. """Registers a new client on the server.
  136. Args:
  137. localpart: The local part of the user ID to register. If None,
  138. one will be generated.
  139. password_hash (str|None): The hashed password to assign to this user so they can
  140. login again. This can be None which means they cannot login again
  141. via a password (e.g. the user is an application service user).
  142. user_type (str|None): type of user. One of the values from
  143. api.constants.UserTypes, or None for a normal user.
  144. default_display_name (unicode|None): if set, the new user's displayname
  145. will be set to this. Defaults to 'localpart'.
  146. address (str|None): the IP address used to perform the registration.
  147. bind_emails (List[str]): list of emails to bind to this account.
  148. by_admin (bool): True if this registration is being made via the
  149. admin api, otherwise False.
  150. user_agent_ips (List[(str, str)]): Tuples of IP addresses and user-agents used
  151. during the registration process.
  152. Returns:
  153. str: user_id
  154. Raises:
  155. SynapseError if there was a problem registering.
  156. """
  157. self.check_registration_ratelimit(address)
  158. result = self.spam_checker.check_registration_for_spam(
  159. threepid, localpart, user_agent_ips or [],
  160. )
  161. if result == RegistrationBehaviour.DENY:
  162. logger.info(
  163. "Blocked registration of %r", localpart,
  164. )
  165. # We return a 429 to make it not obvious that they've been
  166. # denied.
  167. raise SynapseError(429, "Rate limited")
  168. shadow_banned = result == RegistrationBehaviour.SHADOW_BAN
  169. if shadow_banned:
  170. logger.info(
  171. "Shadow banning registration of %r", localpart,
  172. )
  173. # do not check_auth_blocking if the call is coming through the Admin API
  174. if not by_admin:
  175. await self.auth.check_auth_blocking(threepid=threepid)
  176. if localpart is not None:
  177. await self.check_username(localpart, guest_access_token=guest_access_token)
  178. was_guest = guest_access_token is not None
  179. user = UserID(localpart, self.hs.hostname)
  180. user_id = user.to_string()
  181. if was_guest:
  182. # If the user was a guest then they already have a profile
  183. default_display_name = None
  184. elif default_display_name is None:
  185. default_display_name = localpart
  186. await self.register_with_store(
  187. user_id=user_id,
  188. password_hash=password_hash,
  189. was_guest=was_guest,
  190. make_guest=make_guest,
  191. create_profile_with_displayname=default_display_name,
  192. admin=admin,
  193. user_type=user_type,
  194. address=address,
  195. shadow_banned=shadow_banned,
  196. )
  197. if self.hs.config.user_directory_search_all_users:
  198. profile = await self.store.get_profileinfo(localpart)
  199. await self.user_directory_handler.handle_local_profile_change(
  200. user_id, profile
  201. )
  202. else:
  203. # autogen a sequential user ID
  204. fail_count = 0
  205. user = None
  206. while not user:
  207. # Fail after being unable to find a suitable ID a few times
  208. if fail_count > 10:
  209. raise SynapseError(500, "Unable to find a suitable guest user ID")
  210. localpart = await self.store.generate_user_id()
  211. user = UserID(localpart, self.hs.hostname)
  212. user_id = user.to_string()
  213. self.check_user_id_not_appservice_exclusive(user_id)
  214. if default_display_name is None:
  215. default_display_name = localpart
  216. try:
  217. await self.register_with_store(
  218. user_id=user_id,
  219. password_hash=password_hash,
  220. make_guest=make_guest,
  221. create_profile_with_displayname=default_display_name,
  222. address=address,
  223. shadow_banned=shadow_banned,
  224. )
  225. # Successfully registered
  226. break
  227. except SynapseError:
  228. # if user id is taken, just generate another
  229. user = None
  230. user_id = None
  231. fail_count += 1
  232. if not self.hs.config.user_consent_at_registration:
  233. if not self.hs.config.auto_join_rooms_for_guests and make_guest:
  234. logger.info(
  235. "Skipping auto-join for %s because auto-join for guests is disabled",
  236. user_id,
  237. )
  238. else:
  239. await self._auto_join_rooms(user_id)
  240. else:
  241. logger.info(
  242. "Skipping auto-join for %s because consent is required at registration",
  243. user_id,
  244. )
  245. # Bind any specified emails to this account
  246. current_time = self.hs.get_clock().time_msec()
  247. for email in bind_emails:
  248. # generate threepid dict
  249. threepid_dict = {
  250. "medium": "email",
  251. "address": email,
  252. "validated_at": current_time,
  253. }
  254. # Bind email to new account
  255. await self._register_email_threepid(user_id, threepid_dict, None)
  256. return user_id
  257. async def _create_and_join_rooms(self, user_id: str):
  258. """
  259. Create the auto-join rooms and join or invite the user to them.
  260. This should only be called when the first "real" user registers.
  261. Args:
  262. user_id: The user to join
  263. """
  264. # Getting the handlers during init gives a dependency loop.
  265. room_creation_handler = self.hs.get_room_creation_handler()
  266. room_member_handler = self.hs.get_room_member_handler()
  267. # Generate a stub for how the rooms will be configured.
  268. stub_config = {
  269. "preset": self.hs.config.registration.autocreate_auto_join_room_preset,
  270. }
  271. # If the configuration providers a user ID to create rooms with, use
  272. # that instead of the first user registered.
  273. requires_join = False
  274. if self.hs.config.registration.auto_join_user_id:
  275. fake_requester = create_requester(
  276. self.hs.config.registration.auto_join_user_id
  277. )
  278. # If the room requires an invite, add the user to the list of invites.
  279. if self.hs.config.registration.auto_join_room_requires_invite:
  280. stub_config["invite"] = [user_id]
  281. # If the room is being created by a different user, the first user
  282. # registered needs to join it. Note that in the case of an invitation
  283. # being necessary this will occur after the invite was sent.
  284. requires_join = True
  285. else:
  286. fake_requester = create_requester(user_id)
  287. # Choose whether to federate the new room.
  288. if not self.hs.config.registration.autocreate_auto_join_rooms_federated:
  289. stub_config["creation_content"] = {"m.federate": False}
  290. for r in self.hs.config.registration.auto_join_rooms:
  291. logger.info("Auto-joining %s to %s", user_id, r)
  292. try:
  293. room_alias = RoomAlias.from_string(r)
  294. if self.hs.hostname != room_alias.domain:
  295. logger.warning(
  296. "Cannot create room alias %s, "
  297. "it does not match server domain",
  298. r,
  299. )
  300. else:
  301. # A shallow copy is OK here since the only key that is
  302. # modified is room_alias_name.
  303. config = stub_config.copy()
  304. # create room expects the localpart of the room alias
  305. config["room_alias_name"] = room_alias.localpart
  306. info, _ = await room_creation_handler.create_room(
  307. fake_requester, config=config, ratelimit=False,
  308. )
  309. # If the room does not require an invite, but another user
  310. # created it, then ensure the first user joins it.
  311. if requires_join:
  312. await room_member_handler.update_membership(
  313. requester=create_requester(user_id),
  314. target=UserID.from_string(user_id),
  315. room_id=info["room_id"],
  316. # Since it was just created, there are no remote hosts.
  317. remote_room_hosts=[],
  318. action="join",
  319. ratelimit=False,
  320. )
  321. except ConsentNotGivenError as e:
  322. # Technically not necessary to pull out this error though
  323. # moving away from bare excepts is a good thing to do.
  324. logger.error("Failed to join new user to %r: %r", r, e)
  325. except Exception as e:
  326. logger.error("Failed to join new user to %r: %r", r, e)
  327. async def _join_rooms(self, user_id: str):
  328. """
  329. Join or invite the user to the auto-join rooms.
  330. Args:
  331. user_id: The user to join
  332. """
  333. room_member_handler = self.hs.get_room_member_handler()
  334. for r in self.hs.config.registration.auto_join_rooms:
  335. logger.info("Auto-joining %s to %s", user_id, r)
  336. try:
  337. room_alias = RoomAlias.from_string(r)
  338. if RoomAlias.is_valid(r):
  339. (
  340. room_id,
  341. remote_room_hosts,
  342. ) = await room_member_handler.lookup_room_alias(room_alias)
  343. room_id = room_id.to_string()
  344. else:
  345. raise SynapseError(
  346. 400, "%s was not legal room ID or room alias" % (r,)
  347. )
  348. # Calculate whether the room requires an invite or can be
  349. # joined directly. Note that unless a join rule of public exists,
  350. # it is treated as requiring an invite.
  351. requires_invite = True
  352. state = await self.store.get_filtered_current_state_ids(
  353. room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
  354. )
  355. event_id = state.get((EventTypes.JoinRules, ""))
  356. if event_id:
  357. join_rules_event = await self.store.get_event(
  358. event_id, allow_none=True
  359. )
  360. if join_rules_event:
  361. join_rule = join_rules_event.content.get("join_rule", None)
  362. requires_invite = join_rule and join_rule != JoinRules.PUBLIC
  363. # Send the invite, if necessary.
  364. if requires_invite:
  365. await room_member_handler.update_membership(
  366. requester=create_requester(
  367. self.hs.config.registration.auto_join_user_id
  368. ),
  369. target=UserID.from_string(user_id),
  370. room_id=room_id,
  371. remote_room_hosts=remote_room_hosts,
  372. action="invite",
  373. ratelimit=False,
  374. )
  375. # Send the join.
  376. await room_member_handler.update_membership(
  377. requester=create_requester(user_id),
  378. target=UserID.from_string(user_id),
  379. room_id=room_id,
  380. remote_room_hosts=remote_room_hosts,
  381. action="join",
  382. ratelimit=False,
  383. )
  384. except ConsentNotGivenError as e:
  385. # Technically not necessary to pull out this error though
  386. # moving away from bare excepts is a good thing to do.
  387. logger.error("Failed to join new user to %r: %r", r, e)
  388. except Exception as e:
  389. logger.error("Failed to join new user to %r: %r", r, e)
  390. async def _auto_join_rooms(self, user_id: str):
  391. """Automatically joins users to auto join rooms - creating the room in the first place
  392. if the user is the first to be created.
  393. Args:
  394. user_id: The user to join
  395. """
  396. # auto-join the user to any rooms we're supposed to dump them into
  397. # try to create the room if we're the first real user on the server. Note
  398. # that an auto-generated support or bot user is not a real user and will never be
  399. # the user to create the room
  400. should_auto_create_rooms = False
  401. is_real_user = await self.store.is_real_user(user_id)
  402. if self.hs.config.registration.autocreate_auto_join_rooms and is_real_user:
  403. count = await self.store.count_real_users()
  404. should_auto_create_rooms = count == 1
  405. if should_auto_create_rooms:
  406. await self._create_and_join_rooms(user_id)
  407. else:
  408. await self._join_rooms(user_id)
  409. async def post_consent_actions(self, user_id):
  410. """A series of registration actions that can only be carried out once consent
  411. has been granted
  412. Args:
  413. user_id (str): The user to join
  414. """
  415. await self._auto_join_rooms(user_id)
  416. async def appservice_register(self, user_localpart, as_token):
  417. user = UserID(user_localpart, self.hs.hostname)
  418. user_id = user.to_string()
  419. service = self.store.get_app_service_by_token(as_token)
  420. if not service:
  421. raise AuthError(403, "Invalid application service token.")
  422. if not service.is_interested_in_user(user_id):
  423. raise SynapseError(
  424. 400,
  425. "Invalid user localpart for this application service.",
  426. errcode=Codes.EXCLUSIVE,
  427. )
  428. service_id = service.id if service.is_exclusive_user(user_id) else None
  429. self.check_user_id_not_appservice_exclusive(user_id, allowed_appservice=service)
  430. await self.register_with_store(
  431. user_id=user_id,
  432. password_hash="",
  433. appservice_id=service_id,
  434. create_profile_with_displayname=user.localpart,
  435. )
  436. return user_id
  437. def check_user_id_not_appservice_exclusive(self, user_id, allowed_appservice=None):
  438. # don't allow people to register the server notices mxid
  439. if self._server_notices_mxid is not None:
  440. if user_id == self._server_notices_mxid:
  441. raise SynapseError(
  442. 400, "This user ID is reserved.", errcode=Codes.EXCLUSIVE
  443. )
  444. # valid user IDs must not clash with any user ID namespaces claimed by
  445. # application services.
  446. services = self.store.get_app_services()
  447. interested_services = [
  448. s
  449. for s in services
  450. if s.is_interested_in_user(user_id) and s != allowed_appservice
  451. ]
  452. for service in interested_services:
  453. if service.is_exclusive_user(user_id):
  454. raise SynapseError(
  455. 400,
  456. "This user ID is reserved by an application service.",
  457. errcode=Codes.EXCLUSIVE,
  458. )
  459. def check_registration_ratelimit(self, address):
  460. """A simple helper method to check whether the registration rate limit has been hit
  461. for a given IP address
  462. Args:
  463. address (str|None): the IP address used to perform the registration. If this is
  464. None, no ratelimiting will be performed.
  465. Raises:
  466. LimitExceededError: If the rate limit has been exceeded.
  467. """
  468. if not address:
  469. return
  470. self.ratelimiter.ratelimit(address)
  471. def register_with_store(
  472. self,
  473. user_id,
  474. password_hash=None,
  475. was_guest=False,
  476. make_guest=False,
  477. appservice_id=None,
  478. create_profile_with_displayname=None,
  479. admin=False,
  480. user_type=None,
  481. address=None,
  482. shadow_banned=False,
  483. ):
  484. """Register user in the datastore.
  485. Args:
  486. user_id (str): The desired user ID to register.
  487. password_hash (str|None): Optional. The password hash for this user.
  488. was_guest (bool): Optional. Whether this is a guest account being
  489. upgraded to a non-guest account.
  490. make_guest (boolean): True if the the new user should be guest,
  491. false to add a regular user account.
  492. appservice_id (str|None): The ID of the appservice registering the user.
  493. create_profile_with_displayname (unicode|None): Optionally create a
  494. profile for the user, setting their displayname to the given value
  495. admin (boolean): is an admin user?
  496. user_type (str|None): type of user. One of the values from
  497. api.constants.UserTypes, or None for a normal user.
  498. address (str|None): the IP address used to perform the registration.
  499. shadow_banned (bool): Whether to shadow-ban the user
  500. Returns:
  501. Awaitable
  502. """
  503. if self.hs.config.worker_app:
  504. return self._register_client(
  505. user_id=user_id,
  506. password_hash=password_hash,
  507. was_guest=was_guest,
  508. make_guest=make_guest,
  509. appservice_id=appservice_id,
  510. create_profile_with_displayname=create_profile_with_displayname,
  511. admin=admin,
  512. user_type=user_type,
  513. address=address,
  514. shadow_banned=shadow_banned,
  515. )
  516. else:
  517. return self.store.register_user(
  518. user_id=user_id,
  519. password_hash=password_hash,
  520. was_guest=was_guest,
  521. make_guest=make_guest,
  522. appservice_id=appservice_id,
  523. create_profile_with_displayname=create_profile_with_displayname,
  524. admin=admin,
  525. user_type=user_type,
  526. shadow_banned=shadow_banned,
  527. )
  528. async def register_device(
  529. self, user_id, device_id, initial_display_name, is_guest=False
  530. ):
  531. """Register a device for a user and generate an access token.
  532. The access token will be limited by the homeserver's session_lifetime config.
  533. Args:
  534. user_id (str): full canonical @user:id
  535. device_id (str|None): The device ID to check, or None to generate
  536. a new one.
  537. initial_display_name (str|None): An optional display name for the
  538. device.
  539. is_guest (bool): Whether this is a guest account
  540. Returns:
  541. tuple[str, str]: Tuple of device ID and access token
  542. """
  543. if self.hs.config.worker_app:
  544. r = await self._register_device_client(
  545. user_id=user_id,
  546. device_id=device_id,
  547. initial_display_name=initial_display_name,
  548. is_guest=is_guest,
  549. )
  550. return r["device_id"], r["access_token"]
  551. valid_until_ms = None
  552. if self.session_lifetime is not None:
  553. if is_guest:
  554. raise Exception(
  555. "session_lifetime is not currently implemented for guest access"
  556. )
  557. valid_until_ms = self.clock.time_msec() + self.session_lifetime
  558. device_id = await self.device_handler.check_device_registered(
  559. user_id, device_id, initial_display_name
  560. )
  561. if is_guest:
  562. assert valid_until_ms is None
  563. access_token = self.macaroon_gen.generate_access_token(
  564. user_id, ["guest = true"]
  565. )
  566. else:
  567. access_token = await self._auth_handler.get_access_token_for_user_id(
  568. user_id, device_id=device_id, valid_until_ms=valid_until_ms
  569. )
  570. return (device_id, access_token)
  571. async def post_registration_actions(self, user_id, auth_result, access_token):
  572. """A user has completed registration
  573. Args:
  574. user_id (str): The user ID that consented
  575. auth_result (dict): The authenticated credentials of the newly
  576. registered user.
  577. access_token (str|None): The access token of the newly logged in
  578. device, or None if `inhibit_login` enabled.
  579. """
  580. if self.hs.config.worker_app:
  581. await self._post_registration_client(
  582. user_id=user_id, auth_result=auth_result, access_token=access_token
  583. )
  584. return
  585. if auth_result and LoginType.EMAIL_IDENTITY in auth_result:
  586. threepid = auth_result[LoginType.EMAIL_IDENTITY]
  587. # Necessary due to auth checks prior to the threepid being
  588. # written to the db
  589. if is_threepid_reserved(
  590. self.hs.config.mau_limits_reserved_threepids, threepid
  591. ):
  592. await self.store.upsert_monthly_active_user(user_id)
  593. await self._register_email_threepid(user_id, threepid, access_token)
  594. if auth_result and LoginType.MSISDN in auth_result:
  595. threepid = auth_result[LoginType.MSISDN]
  596. await self._register_msisdn_threepid(user_id, threepid)
  597. if auth_result and LoginType.TERMS in auth_result:
  598. await self._on_user_consented(user_id, self.hs.config.user_consent_version)
  599. async def _on_user_consented(self, user_id, consent_version):
  600. """A user consented to the terms on registration
  601. Args:
  602. user_id (str): The user ID that consented.
  603. consent_version (str): version of the policy the user has
  604. consented to.
  605. """
  606. logger.info("%s has consented to the privacy policy", user_id)
  607. await self.store.user_set_consent_version(user_id, consent_version)
  608. await self.post_consent_actions(user_id)
  609. async def _register_email_threepid(self, user_id, threepid, token):
  610. """Add an email address as a 3pid identifier
  611. Also adds an email pusher for the email address, if configured in the
  612. HS config
  613. Must be called on master.
  614. Args:
  615. user_id (str): id of user
  616. threepid (object): m.login.email.identity auth response
  617. token (str|None): access_token for the user, or None if not logged
  618. in.
  619. """
  620. reqd = ("medium", "address", "validated_at")
  621. if any(x not in threepid for x in reqd):
  622. # This will only happen if the ID server returns a malformed response
  623. logger.info("Can't add incomplete 3pid")
  624. return
  625. await self._auth_handler.add_threepid(
  626. user_id, threepid["medium"], threepid["address"], threepid["validated_at"],
  627. )
  628. # And we add an email pusher for them by default, but only
  629. # if email notifications are enabled (so people don't start
  630. # getting mail spam where they weren't before if email
  631. # notifs are set up on a homeserver)
  632. if (
  633. self.hs.config.email_enable_notifs
  634. and self.hs.config.email_notif_for_new_users
  635. and token
  636. ):
  637. # Pull the ID of the access token back out of the db
  638. # It would really make more sense for this to be passed
  639. # up when the access token is saved, but that's quite an
  640. # invasive change I'd rather do separately.
  641. user_tuple = await self.store.get_user_by_access_token(token)
  642. token_id = user_tuple.token_id
  643. await self.pusher_pool.add_pusher(
  644. user_id=user_id,
  645. access_token=token_id,
  646. kind="email",
  647. app_id="m.email",
  648. app_display_name="Email Notifications",
  649. device_display_name=threepid["address"],
  650. pushkey=threepid["address"],
  651. lang=None, # We don't know a user's language here
  652. data={},
  653. )
  654. async def _register_msisdn_threepid(self, user_id, threepid):
  655. """Add a phone number as a 3pid identifier
  656. Must be called on master.
  657. Args:
  658. user_id (str): id of user
  659. threepid (object): m.login.msisdn auth response
  660. """
  661. try:
  662. assert_params_in_dict(threepid, ["medium", "address", "validated_at"])
  663. except SynapseError as ex:
  664. if ex.errcode == Codes.MISSING_PARAM:
  665. # This will only happen if the ID server returns a malformed response
  666. logger.info("Can't add incomplete 3pid")
  667. return None
  668. raise
  669. await self._auth_handler.add_threepid(
  670. user_id, threepid["medium"], threepid["address"], threepid["validated_at"],
  671. )