diff options
author | reivilibre <38398653+reivilibre@users.noreply.github.com> | 2021-08-17 12:57:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-17 11:57:58 +0000 |
commit | 642a42eddece60afbbd5e5a6659fa9b939238b4a (patch) | |
tree | fde46b103f636a302d6a47aadf368e19e4fc43da /synapse/rest/client/v2_alpha/account.py | |
parent | Always list fallback key types in /sync (#10623) (diff) | |
download | synapse-642a42eddece60afbbd5e5a6659fa9b939238b4a.tar.xz |
Flatten the synapse.rest.client package (#10600)
Diffstat (limited to 'synapse/rest/client/v2_alpha/account.py')
-rw-r--r-- | synapse/rest/client/v2_alpha/account.py | 910 |
1 files changed, 0 insertions, 910 deletions
diff --git a/synapse/rest/client/v2_alpha/account.py b/synapse/rest/client/v2_alpha/account.py deleted file mode 100644 index fb5ad2906e..0000000000 --- a/synapse/rest/client/v2_alpha/account.py +++ /dev/null @@ -1,910 +0,0 @@ -# Copyright 2015, 2016 OpenMarket Ltd -# Copyright 2017 Vector Creations Ltd -# Copyright 2018 New Vector Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import logging -import random -from http import HTTPStatus -from typing import TYPE_CHECKING -from urllib.parse import urlparse - -from synapse.api.constants import LoginType -from synapse.api.errors import ( - Codes, - InteractiveAuthIncompleteError, - SynapseError, - ThreepidValidationError, -) -from synapse.config.emailconfig import ThreepidBehaviour -from synapse.handlers.ui_auth import UIAuthSessionDataConstants -from synapse.http.server import finish_request, respond_with_html -from synapse.http.servlet import ( - RestServlet, - assert_params_in_dict, - parse_json_object_from_request, - parse_string, -) -from synapse.metrics import threepid_send_requests -from synapse.push.mailer import Mailer -from synapse.util.msisdn import phone_number_to_msisdn -from synapse.util.stringutils import assert_valid_client_secret, random_string -from synapse.util.threepids import check_3pid_allowed, validate_email - -from ._base import client_patterns, interactive_auth_handler - -if TYPE_CHECKING: - from synapse.server import HomeServer - - -logger = logging.getLogger(__name__) - - -class EmailPasswordRequestTokenRestServlet(RestServlet): - PATTERNS = client_patterns("/account/password/email/requestToken$") - - def __init__(self, hs: "HomeServer"): - super().__init__() - self.hs = hs - self.datastore = hs.get_datastore() - self.config = hs.config - self.identity_handler = hs.get_identity_handler() - - if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL: - self.mailer = Mailer( - hs=self.hs, - app_name=self.config.email_app_name, - template_html=self.config.email_password_reset_template_html, - template_text=self.config.email_password_reset_template_text, - ) - - async def on_POST(self, request): - if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF: - if self.config.local_threepid_handling_disabled_due_to_email_config: - logger.warning( - "User password resets have been disabled due to lack of email config" - ) - raise SynapseError( - 400, "Email-based password resets have been disabled on this server" - ) - - body = parse_json_object_from_request(request) - - assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) - - # Extract params from body - client_secret = body["client_secret"] - assert_valid_client_secret(client_secret) - - # Canonicalise the email address. The addresses are all stored canonicalised - # in the database. This allows the user to reset his password without having to - # know the exact spelling (eg. upper and lower case) of address in the database. - # Stored in the database "foo@bar.com" - # User requests with "FOO@bar.com" would raise a Not Found error - try: - email = validate_email(body["email"]) - except ValueError as e: - raise SynapseError(400, str(e)) - send_attempt = body["send_attempt"] - next_link = body.get("next_link") # Optional param - - if next_link: - # Raise if the provided next_link value isn't valid - assert_valid_next_link(self.hs, next_link) - - await self.identity_handler.ratelimit_request_token_requests( - request, "email", email - ) - - # The email will be sent to the stored address. - # This avoids a potential account hijack by requesting a password reset to - # an email address which is controlled by the attacker but which, after - # canonicalisation, matches the one in our database. - existing_user_id = await self.hs.get_datastore().get_user_id_by_threepid( - "email", email - ) - - if existing_user_id is None: - if self.config.request_token_inhibit_3pid_errors: - # Make the client think the operation succeeded. See the rationale in the - # comments for request_token_inhibit_3pid_errors. - # Also wait for some random amount of time between 100ms and 1s to make it - # look like we did something. - await self.hs.get_clock().sleep(random.randint(1, 10) / 10) - return 200, {"sid": random_string(16)} - - raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND) - - if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: - assert self.hs.config.account_threepid_delegate_email - - # Have the configured identity server handle the request - ret = await self.identity_handler.requestEmailToken( - self.hs.config.account_threepid_delegate_email, - email, - client_secret, - send_attempt, - next_link, - ) - else: - # Send password reset emails from Synapse - sid = await self.identity_handler.send_threepid_validation( - email, - client_secret, - send_attempt, - self.mailer.send_password_reset_mail, - next_link, - ) - - # Wrap the session id in a JSON object - ret = {"sid": sid} - - threepid_send_requests.labels(type="email", reason="password_reset").observe( - send_attempt - ) - - return 200, ret - - -class PasswordRestServlet(RestServlet): - PATTERNS = client_patterns("/account/password$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - self.datastore = self.hs.get_datastore() - self.password_policy_handler = hs.get_password_policy_handler() - self._set_password_handler = hs.get_set_password_handler() - - @interactive_auth_handler - async def on_POST(self, request): - body = parse_json_object_from_request(request) - - # we do basic sanity checks here because the auth layer will store these - # in sessions. Pull out the new password provided to us. - new_password = body.pop("new_password", None) - if new_password is not None: - if not isinstance(new_password, str) or len(new_password) > 512: - raise SynapseError(400, "Invalid password") - self.password_policy_handler.validate_password(new_password) - - # there are two possibilities here. Either the user does not have an - # access token, and needs to do a password reset; or they have one and - # need to validate their identity. - # - # In the first case, we offer a couple of means of identifying - # themselves (email and msisdn, though it's unclear if msisdn actually - # works). - # - # In the second case, we require a password to confirm their identity. - - if self.auth.has_access_token(request): - requester = await self.auth.get_user_by_req(request) - try: - params, session_id = await self.auth_handler.validate_user_via_ui_auth( - requester, - request, - body, - "modify your account password", - ) - except InteractiveAuthIncompleteError as e: - # The user needs to provide more steps to complete auth, but - # they're not required to provide the password again. - # - # If a password is available now, hash the provided password and - # store it for later. - if new_password: - password_hash = await self.auth_handler.hash(new_password) - await self.auth_handler.set_session_data( - e.session_id, - UIAuthSessionDataConstants.PASSWORD_HASH, - password_hash, - ) - raise - user_id = requester.user.to_string() - else: - requester = None - try: - result, params, session_id = await self.auth_handler.check_ui_auth( - [[LoginType.EMAIL_IDENTITY]], - request, - body, - "modify your account password", - ) - except InteractiveAuthIncompleteError as e: - # The user needs to provide more steps to complete auth, but - # they're not required to provide the password again. - # - # If a password is available now, hash the provided password and - # store it for later. - if new_password: - password_hash = await self.auth_handler.hash(new_password) - await self.auth_handler.set_session_data( - e.session_id, - UIAuthSessionDataConstants.PASSWORD_HASH, - password_hash, - ) - raise - - if LoginType.EMAIL_IDENTITY in result: - threepid = result[LoginType.EMAIL_IDENTITY] - if "medium" not in threepid or "address" not in threepid: - raise SynapseError(500, "Malformed threepid") - if threepid["medium"] == "email": - # For emails, canonicalise the address. - # We store all email addresses canonicalised in the DB. - # (See add_threepid in synapse/handlers/auth.py) - try: - threepid["address"] = validate_email(threepid["address"]) - except ValueError as e: - raise SynapseError(400, str(e)) - # if using email, we must know about the email they're authing with! - threepid_user_id = await self.datastore.get_user_id_by_threepid( - threepid["medium"], threepid["address"] - ) - if not threepid_user_id: - raise SynapseError(404, "Email address not found", Codes.NOT_FOUND) - user_id = threepid_user_id - else: - logger.error("Auth succeeded but no known type! %r", result.keys()) - raise SynapseError(500, "", Codes.UNKNOWN) - - # If we have a password in this request, prefer it. Otherwise, use the - # password hash from an earlier request. - if new_password: - password_hash = await self.auth_handler.hash(new_password) - elif session_id is not None: - password_hash = await self.auth_handler.get_session_data( - session_id, UIAuthSessionDataConstants.PASSWORD_HASH, None - ) - else: - # UI validation was skipped, but the request did not include a new - # password. - password_hash = None - if not password_hash: - raise SynapseError(400, "Missing params: password", Codes.MISSING_PARAM) - - logout_devices = params.get("logout_devices", True) - - await self._set_password_handler.set_password( - user_id, password_hash, logout_devices, requester - ) - - return 200, {} - - -class DeactivateAccountRestServlet(RestServlet): - PATTERNS = client_patterns("/account/deactivate$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - self._deactivate_account_handler = hs.get_deactivate_account_handler() - - @interactive_auth_handler - async def on_POST(self, request): - body = parse_json_object_from_request(request) - erase = body.get("erase", False) - if not isinstance(erase, bool): - raise SynapseError( - HTTPStatus.BAD_REQUEST, - "Param 'erase' must be a boolean, if given", - Codes.BAD_JSON, - ) - - requester = await self.auth.get_user_by_req(request) - - # allow ASes to deactivate their own users - if requester.app_service: - await self._deactivate_account_handler.deactivate_account( - requester.user.to_string(), erase, requester - ) - return 200, {} - - await self.auth_handler.validate_user_via_ui_auth( - requester, - request, - body, - "deactivate your account", - ) - result = await self._deactivate_account_handler.deactivate_account( - requester.user.to_string(), - erase, - requester, - id_server=body.get("id_server"), - ) - if result: - id_server_unbind_result = "success" - else: - id_server_unbind_result = "no-support" - - return 200, {"id_server_unbind_result": id_server_unbind_result} - - -class EmailThreepidRequestTokenRestServlet(RestServlet): - PATTERNS = client_patterns("/account/3pid/email/requestToken$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.config = hs.config - self.identity_handler = hs.get_identity_handler() - self.store = self.hs.get_datastore() - - if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL: - self.mailer = Mailer( - hs=self.hs, - app_name=self.config.email_app_name, - template_html=self.config.email_add_threepid_template_html, - template_text=self.config.email_add_threepid_template_text, - ) - - async def on_POST(self, request): - if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF: - if self.config.local_threepid_handling_disabled_due_to_email_config: - logger.warning( - "Adding emails have been disabled due to lack of an email config" - ) - raise SynapseError( - 400, "Adding an email to your account is disabled on this server" - ) - - body = parse_json_object_from_request(request) - assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) - client_secret = body["client_secret"] - assert_valid_client_secret(client_secret) - - # Canonicalise the email address. The addresses are all stored canonicalised - # in the database. - # This ensures that the validation email is sent to the canonicalised address - # as it will later be entered into the database. - # Otherwise the email will be sent to "FOO@bar.com" and stored as - # "foo@bar.com" in database. - try: - email = validate_email(body["email"]) - except ValueError as e: - raise SynapseError(400, str(e)) - send_attempt = body["send_attempt"] - next_link = body.get("next_link") # Optional param - - if not check_3pid_allowed(self.hs, "email", email): - raise SynapseError( - 403, - "Your email domain is not authorized on this server", - Codes.THREEPID_DENIED, - ) - - await self.identity_handler.ratelimit_request_token_requests( - request, "email", email - ) - - if next_link: - # Raise if the provided next_link value isn't valid - assert_valid_next_link(self.hs, next_link) - - existing_user_id = await self.store.get_user_id_by_threepid("email", email) - - if existing_user_id is not None: - if self.config.request_token_inhibit_3pid_errors: - # Make the client think the operation succeeded. See the rationale in the - # comments for request_token_inhibit_3pid_errors. - # Also wait for some random amount of time between 100ms and 1s to make it - # look like we did something. - await self.hs.get_clock().sleep(random.randint(1, 10) / 10) - return 200, {"sid": random_string(16)} - - raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE) - - if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: - assert self.hs.config.account_threepid_delegate_email - - # Have the configured identity server handle the request - ret = await self.identity_handler.requestEmailToken( - self.hs.config.account_threepid_delegate_email, - email, - client_secret, - send_attempt, - next_link, - ) - else: - # Send threepid validation emails from Synapse - sid = await self.identity_handler.send_threepid_validation( - email, - client_secret, - send_attempt, - self.mailer.send_add_threepid_mail, - next_link, - ) - - # Wrap the session id in a JSON object - ret = {"sid": sid} - - threepid_send_requests.labels(type="email", reason="add_threepid").observe( - send_attempt - ) - - return 200, ret - - -class MsisdnThreepidRequestTokenRestServlet(RestServlet): - PATTERNS = client_patterns("/account/3pid/msisdn/requestToken$") - - def __init__(self, hs: "HomeServer"): - self.hs = hs - super().__init__() - self.store = self.hs.get_datastore() - self.identity_handler = hs.get_identity_handler() - - async def on_POST(self, request): - body = parse_json_object_from_request(request) - assert_params_in_dict( - body, ["client_secret", "country", "phone_number", "send_attempt"] - ) - client_secret = body["client_secret"] - assert_valid_client_secret(client_secret) - - country = body["country"] - phone_number = body["phone_number"] - send_attempt = body["send_attempt"] - next_link = body.get("next_link") # Optional param - - msisdn = phone_number_to_msisdn(country, phone_number) - - if not check_3pid_allowed(self.hs, "msisdn", msisdn): - raise SynapseError( - 403, - "Account phone numbers are not authorized on this server", - Codes.THREEPID_DENIED, - ) - - await self.identity_handler.ratelimit_request_token_requests( - request, "msisdn", msisdn - ) - - if next_link: - # Raise if the provided next_link value isn't valid - assert_valid_next_link(self.hs, next_link) - - existing_user_id = await self.store.get_user_id_by_threepid("msisdn", msisdn) - - if existing_user_id is not None: - if self.hs.config.request_token_inhibit_3pid_errors: - # Make the client think the operation succeeded. See the rationale in the - # comments for request_token_inhibit_3pid_errors. - # Also wait for some random amount of time between 100ms and 1s to make it - # look like we did something. - await self.hs.get_clock().sleep(random.randint(1, 10) / 10) - return 200, {"sid": random_string(16)} - - raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE) - - if not self.hs.config.account_threepid_delegate_msisdn: - logger.warning( - "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 = await self.identity_handler.requestMsisdnToken( - self.hs.config.account_threepid_delegate_msisdn, - country, - phone_number, - client_secret, - send_attempt, - next_link, - ) - - threepid_send_requests.labels(type="msisdn", reason="add_threepid").observe( - send_attempt - ) - - return 200, ret - - -class AddThreepidEmailSubmitTokenServlet(RestServlet): - """Handles 3PID validation token submission for adding an email to a user's account""" - - PATTERNS = client_patterns( - "/add_threepid/email/submit_token$", releases=(), unstable=True - ) - - def __init__(self, hs): - """ - Args: - hs (synapse.server.HomeServer): server - """ - super().__init__() - self.config = hs.config - self.clock = hs.get_clock() - self.store = hs.get_datastore() - if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL: - self._failure_email_template = ( - self.config.email_add_threepid_template_failure_html - ) - - async def on_GET(self, request): - if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF: - if self.config.local_threepid_handling_disabled_due_to_email_config: - logger.warning( - "Adding emails have been disabled due to lack of an email config" - ) - raise SynapseError( - 400, "Adding an email to your account is disabled on this server" - ) - elif self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: - raise SynapseError( - 400, - "This homeserver is not validating threepids. Use an identity server " - "instead.", - ) - - sid = parse_string(request, "sid", required=True) - token = parse_string(request, "token", required=True) - client_secret = parse_string(request, "client_secret", required=True) - assert_valid_client_secret(client_secret) - - # Attempt to validate a 3PID session - try: - # Mark the session as valid - next_link = await self.store.validate_threepid_session( - sid, client_secret, token, self.clock.time_msec() - ) - - # Perform a 302 redirect if next_link is set - if next_link: - request.setResponseCode(302) - request.setHeader("Location", next_link) - finish_request(request) - return None - - # Otherwise show the success template - html = self.config.email_add_threepid_template_success_html_content - status_code = 200 - except ThreepidValidationError as e: - status_code = e.code - - # Show a failure page with a reason - template_vars = {"failure_reason": e.msg} - html = self._failure_email_template.render(**template_vars) - - respond_with_html(request, status_code, html) - - -class AddThreepidMsisdnSubmitTokenServlet(RestServlet): - """Handles 3PID validation token submission for adding a phone number to a user's - account - """ - - PATTERNS = client_patterns( - "/add_threepid/msisdn/submit_token$", releases=(), unstable=True - ) - - def __init__(self, hs): - """ - Args: - hs (synapse.server.HomeServer): server - """ - super().__init__() - self.config = hs.config - self.clock = hs.get_clock() - self.store = hs.get_datastore() - self.identity_handler = hs.get_identity_handler() - - async def on_POST(self, request): - if not self.config.account_threepid_delegate_msisdn: - raise SynapseError( - 400, - "This homeserver is not validating phone numbers. Use an identity server " - "instead.", - ) - - body = parse_json_object_from_request(request) - assert_params_in_dict(body, ["client_secret", "sid", "token"]) - assert_valid_client_secret(body["client_secret"]) - - # Proxy submit_token request to msisdn threepid delegate - response = await self.identity_handler.proxy_msisdn_submit_token( - self.config.account_threepid_delegate_msisdn, - body["client_secret"], - body["sid"], - body["token"], - ) - return 200, response - - -class ThreepidRestServlet(RestServlet): - PATTERNS = client_patterns("/account/3pid$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.identity_handler = hs.get_identity_handler() - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - self.datastore = self.hs.get_datastore() - - async def on_GET(self, request): - requester = await self.auth.get_user_by_req(request) - - threepids = await self.datastore.user_get_threepids(requester.user.to_string()) - - return 200, {"threepids": threepids} - - async def on_POST(self, request): - if not self.hs.config.enable_3pid_changes: - raise SynapseError( - 400, "3PID changes are disabled on this server", Codes.FORBIDDEN - ) - - requester = await self.auth.get_user_by_req(request) - user_id = requester.user.to_string() - body = parse_json_object_from_request(request) - - threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds") - if threepid_creds is None: - raise SynapseError( - 400, "Missing param three_pid_creds", Codes.MISSING_PARAM - ) - assert_params_in_dict(threepid_creds, ["client_secret", "sid"]) - - sid = threepid_creds["sid"] - client_secret = threepid_creds["client_secret"] - assert_valid_client_secret(client_secret) - - validation_session = await self.identity_handler.validate_threepid_session( - client_secret, sid - ) - if validation_session: - await 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 ThreepidAddRestServlet(RestServlet): - PATTERNS = client_patterns("/account/3pid/add$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.identity_handler = hs.get_identity_handler() - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - - @interactive_auth_handler - async def on_POST(self, request): - if not self.hs.config.enable_3pid_changes: - raise SynapseError( - 400, "3PID changes are disabled on this server", Codes.FORBIDDEN - ) - - requester = await 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"]) - sid = body["sid"] - client_secret = body["client_secret"] - assert_valid_client_secret(client_secret) - - await self.auth_handler.validate_user_via_ui_auth( - requester, - request, - body, - "add a third-party identifier to your account", - ) - - validation_session = await self.identity_handler.validate_threepid_session( - client_secret, sid - ) - if validation_session: - await 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$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.identity_handler = hs.get_identity_handler() - self.auth = hs.get_auth() - - async def on_POST(self, request): - body = parse_json_object_from_request(request) - - assert_params_in_dict(body, ["id_server", "sid", "client_secret"]) - id_server = body["id_server"] - sid = body["sid"] - id_access_token = body.get("id_access_token") # optional - client_secret = body["client_secret"] - assert_valid_client_secret(client_secret) - - requester = await self.auth.get_user_by_req(request) - user_id = requester.user.to_string() - - await 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$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.identity_handler = hs.get_identity_handler() - self.auth = hs.get_auth() - self.datastore = self.hs.get_datastore() - - async def on_POST(self, request): - """Unbind the given 3pid from a specific identity server, or identity servers that are - known to have this 3pid bound - """ - requester = await self.auth.get_user_by_req(request) - body = parse_json_object_from_request(request) - assert_params_in_dict(body, ["medium", "address"]) - - medium = body.get("medium") - address = body.get("address") - id_server = body.get("id_server") - - # Attempt to unbind the threepid from an identity server. If id_server is None, try to - # unbind from all identity servers this threepid has been added to in the past - result = await self.identity_handler.try_unbind_threepid( - requester.user.to_string(), - {"address": address, "medium": medium, "id_server": id_server}, - ) - return 200, {"id_server_unbind_result": "success" if result else "no-support"} - - -class ThreepidDeleteRestServlet(RestServlet): - PATTERNS = client_patterns("/account/3pid/delete$") - - def __init__(self, hs): - super().__init__() - self.hs = hs - self.auth = hs.get_auth() - self.auth_handler = hs.get_auth_handler() - - async def on_POST(self, request): - if not self.hs.config.enable_3pid_changes: - raise SynapseError( - 400, "3PID changes are disabled on this server", Codes.FORBIDDEN - ) - - body = parse_json_object_from_request(request) - assert_params_in_dict(body, ["medium", "address"]) - - requester = await self.auth.get_user_by_req(request) - user_id = requester.user.to_string() - - try: - ret = await self.auth_handler.delete_threepid( - user_id, body["medium"], body["address"], body.get("id_server") - ) - except Exception: - # NB. This endpoint should succeed if there is nothing to - # delete, so it should only throw if something is wrong - # that we ought to care about. - logger.exception("Failed to remove threepid") - raise SynapseError(500, "Failed to remove threepid") - - if ret: - id_server_unbind_result = "success" - else: - id_server_unbind_result = "no-support" - - return 200, {"id_server_unbind_result": id_server_unbind_result} - - -def assert_valid_next_link(hs: "HomeServer", next_link: str): - """ - Raises a SynapseError if a given next_link value is invalid - - next_link is valid if the scheme is http(s) and the next_link.domain_whitelist config - option is either empty or contains a domain that matches the one in the given next_link - - Args: - hs: The homeserver object - next_link: The next_link value given by the client - - Raises: - SynapseError: If the next_link is invalid - """ - valid = True - - # Parse the contents of the URL - next_link_parsed = urlparse(next_link) - - # Scheme must not point to the local drive - if next_link_parsed.scheme == "file": - valid = False - - # If the domain whitelist is set, the domain must be in it - if ( - valid - and hs.config.next_link_domain_whitelist is not None - and next_link_parsed.hostname not in hs.config.next_link_domain_whitelist - ): - valid = False - - if not valid: - raise SynapseError( - 400, - "'next_link' domain not included in whitelist, or not http(s)", - errcode=Codes.INVALID_PARAM, - ) - - -class WhoamiRestServlet(RestServlet): - PATTERNS = client_patterns("/account/whoami$") - - def __init__(self, hs): - super().__init__() - self.auth = hs.get_auth() - - async def on_GET(self, request): - requester = await self.auth.get_user_by_req(request) - - response = {"user_id": requester.user.to_string()} - - # Appservices and similar accounts do not have device IDs - # that we can report on, so exclude them for compliance. - if requester.device_id is not None: - response["device_id"] = requester.device_id - - return 200, response - - -def register_servlets(hs, http_server): - EmailPasswordRequestTokenRestServlet(hs).register(http_server) - PasswordRestServlet(hs).register(http_server) - DeactivateAccountRestServlet(hs).register(http_server) - EmailThreepidRequestTokenRestServlet(hs).register(http_server) - MsisdnThreepidRequestTokenRestServlet(hs).register(http_server) - AddThreepidEmailSubmitTokenServlet(hs).register(http_server) - AddThreepidMsisdnSubmitTokenServlet(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) |