Synapse 1.15.2 (2020-07-02)
=========================== Due to the two security issues highlighted below, server administrators are encouraged to update Synapse. We are not aware of these vulnerabilities being exploited in the wild. Security advisory ----------------- * A malicious homeserver could force Synapse to reset the state in a room to a small subset of the correct state. This affects all Synapse deployments which federate with untrusted servers. ([pull/7780/head96e9afe6
](96e9afe625
)) * HTML pages served via Synapse were vulnerable to clickjacking attacks. This predominantly affects homeservers with single-sign-on enabled, but all server administrators are encouraged to upgrade. ([ea26e9a9
](ea26e9a98b
)) This was reported by [Quentin Gliech](https://sandhose.fr/). -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEF3tZXk38tRDFVnUIM/xY9qcRMEgFAl799QkACgkQM/xY9qcR MEhKzQ/+JJCbIuaymKQuyZRRt4b2ylXmMjfM8LpYgwk1vEUN2z+NNt4pmbFQtvdJ Q1unHToDIK8b080DMagAc55MEF8GRtl8D411iGgSDeI/AqgVnsBTOW1cd7gDc0LC eEs3jwnL5TYDeZYZUGqu+OfoPbdGnUX8ywQYTXk8y0njELwnoJdMuHSMq8kgsMur eQ1cryevidpJiDQZlZFJQzlGoMrr4Aq94BZHooXfAdJnwCoIR/EVW4iie8GKSaNa OT5tVYg8l4KzBOWZBrtXeeIKVNh7HHie8aJRJVXAGq/3vAEDT8HTAxPNJ6Ru4DA9 2VrflzmuRl9phxybfq2m1G1AvNkOlKu67e21YTSKK9EG/52VJoSXzKEeP9hdMfj5 v/Xfm7v1WqolukZZMc9zyleCoAK2Znu32/0/PYGsgw/vX7wGoCORdP22/vVfuCni ZpUkZPlCA5XyD4QAyegzTVlp94IRI5oCErl6v1mESAaSkKyaGZ5jejTFWzOsKMuo TpyCLLz6ZKLCtxsU6e7nGwDV7dX2iztq8fGf9+8lFsdXCbdI0YsyzAE8reehK9lL rYxzl7fV+m6kzYg+pu3bfjH/YYgkPTvnV4juCOT/LQV7P3sEJAQrYBceIpAzyuS7 t0kCWTfX4UDrt1XbouuWJnvIHAFOG5/o/BEyhkQmW1c3GvDe8Jo= =QQ4B -----END PGP SIGNATURE----- Merge tag 'v1.15.2' Synapse 1.15.2 (2020-07-02) =========================== Due to the two security issues highlighted below, server administrators are encouraged to update Synapse. We are not aware of these vulnerabilities being exploited in the wild. Security advisory ----------------- * A malicious homeserver could force Synapse to reset the state in a room to a small subset of the correct state. This affects all Synapse deployments which federate with untrusted servers. ([96e9afe6
](96e9afe625
)) * HTML pages served via Synapse were vulnerable to clickjacking attacks. This predominantly affects homeservers with single-sign-on enabled, but all server administrators are encouraged to upgrade. ([ea26e9a9
](ea26e9a98b
)) This was reported by [Quentin Gliech](https://sandhose.fr/).
commit
fedb632d0a
20
CHANGES.md
20
CHANGES.md
|
@ -1,3 +1,23 @@
|
||||||
|
Synapse 1.15.2 (2020-07-02)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Due to the two security issues highlighted below, server administrators are
|
||||||
|
encouraged to update Synapse. We are not aware of these vulnerabilities being
|
||||||
|
exploited in the wild.
|
||||||
|
|
||||||
|
Security advisory
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* A malicious homeserver could force Synapse to reset the state in a room to a
|
||||||
|
small subset of the correct state. This affects all Synapse deployments which
|
||||||
|
federate with untrusted servers. ([96e9afe6](https://github.com/matrix-org/synapse/commit/96e9afe62500310977dc3cbc99a8d16d3d2fa15c))
|
||||||
|
* HTML pages served via Synapse were vulnerable to clickjacking attacks. This
|
||||||
|
predominantly affects homeservers with single-sign-on enabled, but all server
|
||||||
|
administrators are encouraged to upgrade. ([ea26e9a9](https://github.com/matrix-org/synapse/commit/ea26e9a98b0541fc886a1cb826a38352b7599dbe))
|
||||||
|
|
||||||
|
This was reported by [Quentin Gliech](https://sandhose.fr/).
|
||||||
|
|
||||||
|
|
||||||
Synapse 1.15.1 (2020-06-16)
|
Synapse 1.15.1 (2020-06-16)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
matrix-synapse-py3 (1.15.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* New synapse release 1.15.2.
|
||||||
|
|
||||||
|
-- Synapse Packaging team <packages@matrix.org> Thu, 02 Jul 2020 10:34:00 -0400
|
||||||
|
|
||||||
matrix-synapse-py3 (1.15.1) stable; urgency=medium
|
matrix-synapse-py3 (1.15.1) stable; urgency=medium
|
||||||
|
|
||||||
* New synapse release 1.15.1.
|
* New synapse release 1.15.1.
|
||||||
|
|
|
@ -36,7 +36,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
__version__ = "1.15.1"
|
__version__ = "1.15.2"
|
||||||
|
|
||||||
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
|
||||||
# We import here so that we don't have to install a bunch of deps when
|
# We import here so that we don't have to install a bunch of deps when
|
||||||
|
|
|
@ -56,6 +56,7 @@ from synapse.http.server import (
|
||||||
OptionsResource,
|
OptionsResource,
|
||||||
RootOptionsRedirectResource,
|
RootOptionsRedirectResource,
|
||||||
RootRedirect,
|
RootRedirect,
|
||||||
|
StaticResource,
|
||||||
)
|
)
|
||||||
from synapse.http.site import SynapseSite
|
from synapse.http.site import SynapseSite
|
||||||
from synapse.logging.context import LoggingContext
|
from synapse.logging.context import LoggingContext
|
||||||
|
@ -228,7 +229,7 @@ class SynapseHomeServer(HomeServer):
|
||||||
if name in ["static", "client"]:
|
if name in ["static", "client"]:
|
||||||
resources.update(
|
resources.update(
|
||||||
{
|
{
|
||||||
STATIC_PREFIX: File(
|
STATIC_PREFIX: StaticResource(
|
||||||
os.path.join(os.path.dirname(synapse.__file__), "static")
|
os.path.join(os.path.dirname(synapse.__file__), "static")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ from synapse.api.errors import (
|
||||||
from synapse.api.ratelimiting import Ratelimiter
|
from synapse.api.ratelimiting import Ratelimiter
|
||||||
from synapse.handlers.ui_auth import INTERACTIVE_AUTH_CHECKERS
|
from synapse.handlers.ui_auth import INTERACTIVE_AUTH_CHECKERS
|
||||||
from synapse.handlers.ui_auth.checkers import UserInteractiveAuthChecker
|
from synapse.handlers.ui_auth.checkers import UserInteractiveAuthChecker
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import finish_request, respond_with_html
|
||||||
from synapse.http.site import SynapseRequest
|
from synapse.http.site import SynapseRequest
|
||||||
from synapse.logging.context import defer_to_thread
|
from synapse.logging.context import defer_to_thread
|
||||||
from synapse.metrics.background_process_metrics import run_as_background_process
|
from synapse.metrics.background_process_metrics import run_as_background_process
|
||||||
|
@ -1055,13 +1055,8 @@ class AuthHandler(BaseHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Render the HTML and return.
|
# Render the HTML and return.
|
||||||
html_bytes = self._sso_auth_success_template.encode("utf-8")
|
html = self._sso_auth_success_template
|
||||||
request.setResponseCode(200)
|
respond_with_html(request, 200, html)
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
|
||||||
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
async def complete_sso_login(
|
async def complete_sso_login(
|
||||||
self,
|
self,
|
||||||
|
@ -1081,13 +1076,7 @@ class AuthHandler(BaseHandler):
|
||||||
# flow.
|
# flow.
|
||||||
deactivated = await self.store.get_user_deactivated_status(registered_user_id)
|
deactivated = await self.store.get_user_deactivated_status(registered_user_id)
|
||||||
if deactivated:
|
if deactivated:
|
||||||
html_bytes = self._sso_account_deactivated_template.encode("utf-8")
|
respond_with_html(request, 403, self._sso_account_deactivated_template)
|
||||||
|
|
||||||
request.setResponseCode(403)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self._complete_sso_login(registered_user_id, request, client_redirect_url)
|
self._complete_sso_login(registered_user_id, request, client_redirect_url)
|
||||||
|
@ -1128,17 +1117,12 @@ class AuthHandler(BaseHandler):
|
||||||
# URL we redirect users to.
|
# URL we redirect users to.
|
||||||
redirect_url_no_params = client_redirect_url.split("?")[0]
|
redirect_url_no_params = client_redirect_url.split("?")[0]
|
||||||
|
|
||||||
html_bytes = self._sso_redirect_confirm_template.render(
|
html = self._sso_redirect_confirm_template.render(
|
||||||
display_url=redirect_url_no_params,
|
display_url=redirect_url_no_params,
|
||||||
redirect_url=redirect_url,
|
redirect_url=redirect_url,
|
||||||
server_name=self._server_name,
|
server_name=self._server_name,
|
||||||
).encode("utf-8")
|
)
|
||||||
|
respond_with_html(request, 200, html)
|
||||||
request.setResponseCode(200)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_query_param_to_url(url: str, param_name: str, param: Any):
|
def add_query_param_to_url(url: str, param_name: str, param: Any):
|
||||||
|
|
|
@ -238,7 +238,7 @@ class FederationHandler(BaseHandler):
|
||||||
logger.debug("[%s %s] min_depth: %d", room_id, event_id, min_depth)
|
logger.debug("[%s %s] min_depth: %d", room_id, event_id, min_depth)
|
||||||
|
|
||||||
prevs = set(pdu.prev_event_ids())
|
prevs = set(pdu.prev_event_ids())
|
||||||
seen = await self.store.have_seen_events(prevs)
|
seen = await self.store.have_events_in_timeline(prevs)
|
||||||
|
|
||||||
if min_depth is not None and pdu.depth < min_depth:
|
if min_depth is not None and pdu.depth < min_depth:
|
||||||
# This is so that we don't notify the user about this
|
# This is so that we don't notify the user about this
|
||||||
|
@ -278,7 +278,7 @@ class FederationHandler(BaseHandler):
|
||||||
|
|
||||||
# Update the set of things we've seen after trying to
|
# Update the set of things we've seen after trying to
|
||||||
# fetch the missing stuff
|
# fetch the missing stuff
|
||||||
seen = await self.store.have_seen_events(prevs)
|
seen = await self.store.have_events_in_timeline(prevs)
|
||||||
|
|
||||||
if not prevs - seen:
|
if not prevs - seen:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -423,7 +423,7 @@ class FederationHandler(BaseHandler):
|
||||||
room_id = pdu.room_id
|
room_id = pdu.room_id
|
||||||
event_id = pdu.event_id
|
event_id = pdu.event_id
|
||||||
|
|
||||||
seen = await self.store.have_seen_events(prevs)
|
seen = await self.store.have_events_in_timeline(prevs)
|
||||||
|
|
||||||
if not prevs - seen:
|
if not prevs - seen:
|
||||||
return
|
return
|
||||||
|
|
|
@ -35,7 +35,7 @@ from typing_extensions import TypedDict
|
||||||
from twisted.web.client import readBody
|
from twisted.web.client import readBody
|
||||||
|
|
||||||
from synapse.config import ConfigError
|
from synapse.config import ConfigError
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import respond_with_html
|
||||||
from synapse.http.site import SynapseRequest
|
from synapse.http.site import SynapseRequest
|
||||||
from synapse.logging.context import make_deferred_yieldable
|
from synapse.logging.context import make_deferred_yieldable
|
||||||
from synapse.push.mailer import load_jinja2_templates
|
from synapse.push.mailer import load_jinja2_templates
|
||||||
|
@ -144,15 +144,10 @@ class OidcHandler:
|
||||||
access_denied.
|
access_denied.
|
||||||
error_description: A human-readable description of the error.
|
error_description: A human-readable description of the error.
|
||||||
"""
|
"""
|
||||||
html_bytes = self._error_template.render(
|
html = self._error_template.render(
|
||||||
error=error, error_description=error_description
|
error=error, error_description=error_description
|
||||||
).encode("utf-8")
|
)
|
||||||
|
respond_with_html(request, 400, html)
|
||||||
request.setResponseCode(400)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%i" % len(html_bytes))
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
def _validate_metadata(self):
|
def _validate_metadata(self):
|
||||||
"""Verifies the provider metadata.
|
"""Verifies the provider metadata.
|
||||||
|
|
|
@ -30,7 +30,7 @@ from twisted.internet import defer
|
||||||
from twisted.python import failure
|
from twisted.python import failure
|
||||||
from twisted.web import resource
|
from twisted.web import resource
|
||||||
from twisted.web.server import NOT_DONE_YET, Request
|
from twisted.web.server import NOT_DONE_YET, Request
|
||||||
from twisted.web.static import NoRangeStaticProducer
|
from twisted.web.static import File, NoRangeStaticProducer
|
||||||
from twisted.web.util import redirectTo
|
from twisted.web.util import redirectTo
|
||||||
|
|
||||||
import synapse.events
|
import synapse.events
|
||||||
|
@ -202,12 +202,7 @@ def return_html_error(
|
||||||
else:
|
else:
|
||||||
body = error_template.render(code=code, msg=msg)
|
body = error_template.render(code=code, msg=msg)
|
||||||
|
|
||||||
body_bytes = body.encode("utf-8")
|
respond_with_html(request, code, body)
|
||||||
request.setResponseCode(code)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%i" % (len(body_bytes),))
|
|
||||||
request.write(body_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_async_request_handler(h):
|
def wrap_async_request_handler(h):
|
||||||
|
@ -420,6 +415,18 @@ class DirectServeResource(resource.Resource):
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
|
|
||||||
|
class StaticResource(File):
|
||||||
|
"""
|
||||||
|
A resource that represents a plain non-interpreted file or directory.
|
||||||
|
|
||||||
|
Differs from the File resource by adding clickjacking protection.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def render_GET(self, request: Request):
|
||||||
|
set_clickjacking_protection_headers(request)
|
||||||
|
return super().render_GET(request)
|
||||||
|
|
||||||
|
|
||||||
def _options_handler(request):
|
def _options_handler(request):
|
||||||
"""Request handler for OPTIONS requests
|
"""Request handler for OPTIONS requests
|
||||||
|
|
||||||
|
@ -530,7 +537,7 @@ def respond_with_json_bytes(
|
||||||
code (int): The HTTP response code.
|
code (int): The HTTP response code.
|
||||||
json_bytes (bytes): The json bytes to use as the response body.
|
json_bytes (bytes): The json bytes to use as the response body.
|
||||||
send_cors (bool): Whether to send Cross-Origin Resource Sharing headers
|
send_cors (bool): Whether to send Cross-Origin Resource Sharing headers
|
||||||
http://www.w3.org/TR/cors/
|
https://fetch.spec.whatwg.org/#http-cors-protocol
|
||||||
Returns:
|
Returns:
|
||||||
twisted.web.server.NOT_DONE_YET"""
|
twisted.web.server.NOT_DONE_YET"""
|
||||||
|
|
||||||
|
@ -568,6 +575,59 @@ def set_cors_headers(request):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def respond_with_html(request: Request, code: int, html: str):
|
||||||
|
"""
|
||||||
|
Wraps `respond_with_html_bytes` by first encoding HTML from a str to UTF-8 bytes.
|
||||||
|
"""
|
||||||
|
respond_with_html_bytes(request, code, html.encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def respond_with_html_bytes(request: Request, code: int, html_bytes: bytes):
|
||||||
|
"""
|
||||||
|
Sends HTML (encoded as UTF-8 bytes) as the response to the given request.
|
||||||
|
|
||||||
|
Note that this adds clickjacking protection headers and finishes the request.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The http request to respond to.
|
||||||
|
code: The HTTP response code.
|
||||||
|
html_bytes: The HTML bytes to use as the response body.
|
||||||
|
"""
|
||||||
|
# could alternatively use request.notifyFinish() and flip a flag when
|
||||||
|
# the Deferred fires, but since the flag is RIGHT THERE it seems like
|
||||||
|
# a waste.
|
||||||
|
if request._disconnected:
|
||||||
|
logger.warning(
|
||||||
|
"Not sending response to request %s, already disconnected.", request
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
request.setResponseCode(code)
|
||||||
|
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
||||||
|
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
||||||
|
|
||||||
|
# Ensure this content cannot be embedded.
|
||||||
|
set_clickjacking_protection_headers(request)
|
||||||
|
|
||||||
|
request.write(html_bytes)
|
||||||
|
finish_request(request)
|
||||||
|
|
||||||
|
|
||||||
|
def set_clickjacking_protection_headers(request: Request):
|
||||||
|
"""
|
||||||
|
Set headers to guard against clickjacking of embedded content.
|
||||||
|
|
||||||
|
This sets the X-Frame-Options and Content-Security-Policy headers which instructs
|
||||||
|
browsers to not allow the HTML of the response to be embedded onto another
|
||||||
|
page.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The http request to add the headers to.
|
||||||
|
"""
|
||||||
|
request.setHeader(b"X-Frame-Options", b"DENY")
|
||||||
|
request.setHeader(b"Content-Security-Policy", b"frame-ancestors 'none';")
|
||||||
|
|
||||||
|
|
||||||
def finish_request(request):
|
def finish_request(request):
|
||||||
""" Finish writing the response to the request.
|
""" Finish writing the response to the request.
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from synapse.api.errors import Codes, StoreError, SynapseError
|
from synapse.api.errors import Codes, StoreError, SynapseError
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import respond_with_html_bytes
|
||||||
from synapse.http.servlet import (
|
from synapse.http.servlet import (
|
||||||
RestServlet,
|
RestServlet,
|
||||||
assert_params_in_dict,
|
assert_params_in_dict,
|
||||||
|
@ -177,13 +177,9 @@ class PushersRemoveRestServlet(RestServlet):
|
||||||
|
|
||||||
self.notifier.on_new_replication_data()
|
self.notifier.on_new_replication_data()
|
||||||
|
|
||||||
request.setResponseCode(200)
|
respond_with_html_bytes(
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
request, 200, PushersRemoveRestServlet.SUCCESS_HTML,
|
||||||
request.setHeader(
|
|
||||||
b"Content-Length", b"%d" % (len(PushersRemoveRestServlet.SUCCESS_HTML),)
|
|
||||||
)
|
)
|
||||||
request.write(PushersRemoveRestServlet.SUCCESS_HTML)
|
|
||||||
finish_request(request)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def on_OPTIONS(self, _):
|
def on_OPTIONS(self, _):
|
||||||
|
|
|
@ -21,7 +21,7 @@ from six.moves import http_client
|
||||||
from synapse.api.constants import LoginType
|
from synapse.api.constants import LoginType
|
||||||
from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
|
from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
|
||||||
from synapse.config.emailconfig import ThreepidBehaviour
|
from synapse.config.emailconfig import ThreepidBehaviour
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import finish_request, respond_with_html
|
||||||
from synapse.http.servlet import (
|
from synapse.http.servlet import (
|
||||||
RestServlet,
|
RestServlet,
|
||||||
assert_params_in_dict,
|
assert_params_in_dict,
|
||||||
|
@ -199,16 +199,15 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
||||||
|
|
||||||
# Otherwise show the success template
|
# Otherwise show the success template
|
||||||
html = self.config.email_password_reset_template_success_html
|
html = self.config.email_password_reset_template_success_html
|
||||||
request.setResponseCode(200)
|
status_code = 200
|
||||||
except ThreepidValidationError as e:
|
except ThreepidValidationError as e:
|
||||||
request.setResponseCode(e.code)
|
status_code = e.code
|
||||||
|
|
||||||
# Show a failure page with a reason
|
# Show a failure page with a reason
|
||||||
template_vars = {"failure_reason": e.msg}
|
template_vars = {"failure_reason": e.msg}
|
||||||
html = self.failure_email_template.render(**template_vars)
|
html = self.failure_email_template.render(**template_vars)
|
||||||
|
|
||||||
request.write(html.encode("utf-8"))
|
respond_with_html(request, status_code, html)
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordRestServlet(RestServlet):
|
class PasswordRestServlet(RestServlet):
|
||||||
|
@ -571,16 +570,15 @@ class AddThreepidEmailSubmitTokenServlet(RestServlet):
|
||||||
|
|
||||||
# Otherwise show the success template
|
# Otherwise show the success template
|
||||||
html = self.config.email_add_threepid_template_success_html_content
|
html = self.config.email_add_threepid_template_success_html_content
|
||||||
request.setResponseCode(200)
|
status_code = 200
|
||||||
except ThreepidValidationError as e:
|
except ThreepidValidationError as e:
|
||||||
request.setResponseCode(e.code)
|
status_code = e.code
|
||||||
|
|
||||||
# Show a failure page with a reason
|
# Show a failure page with a reason
|
||||||
template_vars = {"failure_reason": e.msg}
|
template_vars = {"failure_reason": e.msg}
|
||||||
html = self.failure_email_template.render(**template_vars)
|
html = self.failure_email_template.render(**template_vars)
|
||||||
|
|
||||||
request.write(html.encode("utf-8"))
|
respond_with_html(request, status_code, html)
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
class AddThreepidMsisdnSubmitTokenServlet(RestServlet):
|
class AddThreepidMsisdnSubmitTokenServlet(RestServlet):
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from synapse.api.errors import AuthError, SynapseError
|
from synapse.api.errors import AuthError, SynapseError
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import respond_with_html
|
||||||
from synapse.http.servlet import RestServlet
|
from synapse.http.servlet import RestServlet
|
||||||
|
|
||||||
from ._base import client_patterns
|
from ._base import client_patterns
|
||||||
|
@ -26,9 +26,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class AccountValidityRenewServlet(RestServlet):
|
class AccountValidityRenewServlet(RestServlet):
|
||||||
PATTERNS = client_patterns("/account_validity/renew$")
|
PATTERNS = client_patterns("/account_validity/renew$")
|
||||||
SUCCESS_HTML = (
|
|
||||||
b"<html><body>Your account has been successfully renewed.</body><html>"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
"""
|
"""
|
||||||
|
@ -59,11 +56,7 @@ class AccountValidityRenewServlet(RestServlet):
|
||||||
status_code = 404
|
status_code = 404
|
||||||
response = self.failure_html
|
response = self.failure_html
|
||||||
|
|
||||||
request.setResponseCode(status_code)
|
respond_with_html(request, status_code, response)
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(response),))
|
|
||||||
request.write(response.encode("utf8"))
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
class AccountValiditySendMailServlet(RestServlet):
|
class AccountValiditySendMailServlet(RestServlet):
|
||||||
|
|
|
@ -18,7 +18,7 @@ import logging
|
||||||
from synapse.api.constants import LoginType
|
from synapse.api.constants import LoginType
|
||||||
from synapse.api.errors import SynapseError
|
from synapse.api.errors import SynapseError
|
||||||
from synapse.api.urls import CLIENT_API_PREFIX
|
from synapse.api.urls import CLIENT_API_PREFIX
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import respond_with_html
|
||||||
from synapse.http.servlet import RestServlet, parse_string
|
from synapse.http.servlet import RestServlet, parse_string
|
||||||
|
|
||||||
from ._base import client_patterns
|
from ._base import client_patterns
|
||||||
|
@ -200,13 +200,7 @@ class AuthRestServlet(RestServlet):
|
||||||
raise SynapseError(404, "Unknown auth stage type")
|
raise SynapseError(404, "Unknown auth stage type")
|
||||||
|
|
||||||
# Render the HTML and return.
|
# Render the HTML and return.
|
||||||
html_bytes = html.encode("utf8")
|
respond_with_html(request, 200, html)
|
||||||
request.setResponseCode(200)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
|
||||||
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def on_POST(self, request, stagetype):
|
async def on_POST(self, request, stagetype):
|
||||||
|
@ -263,13 +257,7 @@ class AuthRestServlet(RestServlet):
|
||||||
raise SynapseError(404, "Unknown auth stage type")
|
raise SynapseError(404, "Unknown auth stage type")
|
||||||
|
|
||||||
# Render the HTML and return.
|
# Render the HTML and return.
|
||||||
html_bytes = html.encode("utf8")
|
respond_with_html(request, 200, html)
|
||||||
request.setResponseCode(200)
|
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
|
|
||||||
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def on_OPTIONS(self, _):
|
def on_OPTIONS(self, _):
|
||||||
|
|
|
@ -38,7 +38,7 @@ from synapse.config.ratelimiting import FederationRateLimitConfig
|
||||||
from synapse.config.registration import RegistrationConfig
|
from synapse.config.registration import RegistrationConfig
|
||||||
from synapse.config.server import is_threepid_reserved
|
from synapse.config.server import is_threepid_reserved
|
||||||
from synapse.handlers.auth import AuthHandler
|
from synapse.handlers.auth import AuthHandler
|
||||||
from synapse.http.server import finish_request
|
from synapse.http.server import finish_request, respond_with_html
|
||||||
from synapse.http.servlet import (
|
from synapse.http.servlet import (
|
||||||
RestServlet,
|
RestServlet,
|
||||||
assert_params_in_dict,
|
assert_params_in_dict,
|
||||||
|
@ -306,17 +306,15 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
||||||
|
|
||||||
# Otherwise show the success template
|
# Otherwise show the success template
|
||||||
html = self.config.email_registration_template_success_html_content
|
html = self.config.email_registration_template_success_html_content
|
||||||
|
status_code = 200
|
||||||
request.setResponseCode(200)
|
|
||||||
except ThreepidValidationError as e:
|
except ThreepidValidationError as e:
|
||||||
request.setResponseCode(e.code)
|
status_code = e.code
|
||||||
|
|
||||||
# Show a failure page with a reason
|
# Show a failure page with a reason
|
||||||
template_vars = {"failure_reason": e.msg}
|
template_vars = {"failure_reason": e.msg}
|
||||||
html = self.failure_email_template.render(**template_vars)
|
html = self.failure_email_template.render(**template_vars)
|
||||||
|
|
||||||
request.write(html.encode("utf-8"))
|
respond_with_html(request, status_code, html)
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
class UsernameAvailabilityRestServlet(RestServlet):
|
class UsernameAvailabilityRestServlet(RestServlet):
|
||||||
|
|
|
@ -29,7 +29,7 @@ from synapse.api.errors import NotFoundError, StoreError, SynapseError
|
||||||
from synapse.config import ConfigError
|
from synapse.config import ConfigError
|
||||||
from synapse.http.server import (
|
from synapse.http.server import (
|
||||||
DirectServeResource,
|
DirectServeResource,
|
||||||
finish_request,
|
respond_with_html,
|
||||||
wrap_html_request_handler,
|
wrap_html_request_handler,
|
||||||
)
|
)
|
||||||
from synapse.http.servlet import parse_string
|
from synapse.http.servlet import parse_string
|
||||||
|
@ -197,12 +197,8 @@ class ConsentResource(DirectServeResource):
|
||||||
template_html = self._jinja_env.get_template(
|
template_html = self._jinja_env.get_template(
|
||||||
path.join(TEMPLATE_LANGUAGE, template_name)
|
path.join(TEMPLATE_LANGUAGE, template_name)
|
||||||
)
|
)
|
||||||
html_bytes = template_html.render(**template_args).encode("utf8")
|
html = template_html.render(**template_args)
|
||||||
|
respond_with_html(request, 200, html)
|
||||||
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
|
|
||||||
request.setHeader(b"Content-Length", b"%i" % len(html_bytes))
|
|
||||||
request.write(html_bytes)
|
|
||||||
finish_request(request)
|
|
||||||
|
|
||||||
def _check_hash(self, userid, userhmac):
|
def _check_hash(self, userid, userhmac):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue