From eabedd9520ec56e3b52153ab823124bee9e7148a Mon Sep 17 00:00:00 2001 From: FadhlanR Date: Tue, 2 Jan 2024 23:25:26 +0700 Subject: [PATCH] Fix email verification redirection (#16761) Previously, the response status of `HTMLResource` was hardcoded as `200`. However, for proper redirection after the user verifies their email, we require the status to be `302`. This PR addresses that issue by using `code` as response status. --- changelog.d/16761.bugfix | 1 + synapse/http/server.py | 2 +- synapse/rest/synapse/client/password_reset.py | 2 +- tests/rest/client/test_account.py | 43 +++++++++++++++++-- 4 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 changelog.d/16761.bugfix diff --git a/changelog.d/16761.bugfix b/changelog.d/16761.bugfix new file mode 100644 index 00000000000..86c6545eda9 --- /dev/null +++ b/changelog.d/16761.bugfix @@ -0,0 +1 @@ +Fix email verification redirection. Contributed by Fadhlan Ridhwanallah. \ No newline at end of file diff --git a/synapse/http/server.py b/synapse/http/server.py index d570bf5e62a..31311aeb2a2 100644 --- a/synapse/http/server.py +++ b/synapse/http/server.py @@ -574,7 +574,7 @@ def _send_response( assert isinstance(response_object, bytes) html_bytes = response_object - respond_with_html_bytes(request, 200, html_bytes) + respond_with_html_bytes(request, code, html_bytes) def _send_error_response( self, diff --git a/synapse/rest/synapse/client/password_reset.py b/synapse/rest/synapse/client/password_reset.py index f6bdccad30c..671eae7c075 100644 --- a/synapse/rest/synapse/client/password_reset.py +++ b/synapse/rest/synapse/client/password_reset.py @@ -106,7 +106,7 @@ async def _async_render_POST(self, request: Request) -> Tuple[int, bytes]: return ( 302, ( - b'You are being redirected to %s.' + b'You are being redirected to %s.' % (next_link_bytes, next_link_bytes) ), ) diff --git a/tests/rest/client/test_account.py b/tests/rest/client/test_account.py index 5cef9c5c17f..f1e4bdea76e 100644 --- a/tests/rest/client/test_account.py +++ b/tests/rest/client/test_account.py @@ -328,16 +328,49 @@ def test_password_reset_bad_email_inhibit_error(self) -> None: self.assertIsNotNone(session_id) + def test_password_reset_redirection(self) -> None: + """Test basic password reset flow""" + old_password = "monkey" + + user_id = self.register_user("kermit", old_password) + self.login("kermit", old_password) + + email = "test@example.com" + + # Add a threepid + self.get_success( + self.store.user_add_threepid( + user_id=user_id, + medium="email", + address=email, + validated_at=0, + added_at=0, + ) + ) + + client_secret = "foobar" + next_link = "http://example.com" + self._request_token(email, client_secret, "127.0.0.1", next_link) + + self.assertEqual(len(self.email_attempts), 1) + link = self._get_link_from_email() + + self._validate_token(link, next_link) + def _request_token( self, email: str, client_secret: str, ip: str = "127.0.0.1", + next_link: Optional[str] = None, ) -> str: + body = {"client_secret": client_secret, "email": email, "send_attempt": 1} + if next_link is not None: + body["next_link"] = next_link channel = self.make_request( "POST", b"account/password/email/requestToken", - {"client_secret": client_secret, "email": email, "send_attempt": 1}, + body, client_ip=ip, ) @@ -350,7 +383,7 @@ def _request_token( return channel.json_body["sid"] - def _validate_token(self, link: str) -> None: + def _validate_token(self, link: str, next_link: Optional[str] = None) -> None: # Remove the host path = link.replace("https://example.com", "") @@ -378,7 +411,11 @@ def _validate_token(self, link: str) -> None: shorthand=False, content_is_form=True, ) - self.assertEqual(HTTPStatus.OK, channel.code, channel.result) + self.assertEqual( + HTTPStatus.OK if next_link is None else HTTPStatus.FOUND, + channel.code, + channel.result, + ) def _get_link_from_email(self) -> str: assert self.email_attempts, "No emails have been sent"