Compare commits

...

8 Commits

Author SHA1 Message Date
Richard van der Hoff 9de6e9e249 move #8444 to 'feature' 2020-10-02 12:56:40 +01:00
Richard van der Hoff 8672642225 linkify changelog 2020-10-02 12:54:53 +01:00
Richard van der Hoff 6a8fd03acb 1.21.0rc2 2020-10-02 12:48:33 +01:00
Richard van der Hoff f6c526ce67 1.21.0rc2 2020-10-02 12:46:58 +01:00
Richard van der Hoff 73d93039ff
Fix bug in remote thumbnail search (#8438)
#7124 changed the behaviour of remote thumbnails so that the thumbnailing method was included in the filename of the thumbnail. To support existing files, it included a fallback so that we would check the old filename if the new filename didn't exist.

Unfortunately, it didn't apply this logic to storage providers, so any thumbnails stored on such a storage provider was broken.
2020-10-02 12:29:29 +01:00
Erik Johnston 695240d34a
Fix DB query on startup for negative streams. (#8447)
For negative streams we have to negate the internal stream ID before
querying the DB.

The effect of this bug was to query far too many rows, slowing start up
time, but we would correctly filter the results afterwards so there was
no ill effect.
2020-10-02 12:22:19 +01:00
Patrick Cloke 34ff8da83b
Convert additional templates to Jinja (#8444)
This converts a few more of our inline HTML templates to Jinja. This is somewhat part of #7280 and should make it a bit easier to customize these in the future.
2020-10-02 11:15:53 +01:00
Richard van der Hoff 3bd3707cb9
Fix malformed log line in new federation "catch up" logic (#8442) 2020-10-02 11:05:29 +01:00
14 changed files with 163 additions and 140 deletions

View File

@ -1,3 +1,20 @@
Synapse 1.21.0rc2 (2020-10-02)
==============================
Features
--------
- Convert additional templates from inline HTML to Jinja2 templates. ([\#8444](https://github.com/matrix-org/synapse/issues/8444))
Bugfixes
--------
- Fix a regression in v1.21.0rc1 which broke thumbnails of remote media. ([\#8438](https://github.com/matrix-org/synapse/issues/8438))
- Do not expose the experimental `uk.half-shot.msc2778.login.application_service` flow in the login API, which caused a compatibility problem with Element iOS. ([\#8440](https://github.com/matrix-org/synapse/issues/8440))
- Fix malformed log line in new federation "catch up" logic. ([\#8442](https://github.com/matrix-org/synapse/issues/8442))
- Fix DB query on startup for negative streams which caused long start up times. Introduced in [\#8374](https://github.com/matrix-org/synapse/issues/8374). ([\#8447](https://github.com/matrix-org/synapse/issues/8447))
Synapse 1.21.0rc1 (2020-10-01)
==============================

View File

@ -1 +0,0 @@
Do not expose the experimental `uk.half-shot.msc2778.login.application_service` flow in the login API.

View File

@ -48,7 +48,7 @@ try:
except ImportError:
pass
__version__ = "1.21.0rc1"
__version__ = "1.21.0rc2"
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

View File

@ -242,12 +242,11 @@ class Config:
env = jinja2.Environment(loader=loader, autoescape=autoescape)
# Update the environment with our custom filters
env.filters.update(
{
"format_ts": _format_ts_filter,
"mxc_to_http": _create_mxc_to_http_filter(self.public_baseurl),
}
)
env.filters.update({"format_ts": _format_ts_filter})
if self.public_baseurl:
env.filters.update(
{"mxc_to_http": _create_mxc_to_http_filter(self.public_baseurl)}
)
for filename in filenames:
# Load the template

View File

@ -28,6 +28,9 @@ class CaptchaConfig(Config):
"recaptcha_siteverify_api",
"https://www.recaptcha.net/recaptcha/api/siteverify",
)
self.recaptcha_template = self.read_templates(
["recaptcha.html"], autoescape=True
)[0]
def generate_config_section(self, **kwargs):
return """\

View File

@ -89,6 +89,8 @@ class ConsentConfig(Config):
def read_config(self, config, **kwargs):
consent_config = config.get("user_consent")
self.terms_template = self.read_templates(["terms.html"], autoescape=True)[0]
if consent_config is None:
return
self.user_consent_version = str(consent_config["version"])

View File

@ -187,6 +187,11 @@ class RegistrationConfig(Config):
session_lifetime = self.parse_duration(session_lifetime)
self.session_lifetime = session_lifetime
# The success template used during fallback auth.
self.fallback_success_template = self.read_templates(
["auth_success.html"], autoescape=True
)[0]
def generate_config_section(self, generate_secrets=False, **kwargs):
if generate_secrets:
registration_shared_secret = 'registration_shared_secret: "%s"' % (

View File

@ -490,7 +490,7 @@ class PerDestinationQueue:
)
if logger.isEnabledFor(logging.INFO):
rooms = (p.room_id for p in catchup_pdus)
rooms = [p.room_id for p in catchup_pdus]
logger.info("Catching up rooms to %s: %r", self._destination, rooms)
success = await self._transaction_manager.send_new_transaction(

View File

@ -0,0 +1,21 @@
<html>
<head>
<title>Success!</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
<script>
if (window.onAuthDone) {
window.onAuthDone();
} else if (window.opener && window.opener.postMessage) {
window.opener.postMessage("authDone", "*");
}
</script>
</head>
<body>
<div>
<p>Thank you</p>
<p>You may now close this window and return to the application</p>
</div>
</body>
</html>

View File

@ -0,0 +1,38 @@
<html>
<head>
<title>Authentication</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<script src="https://www.recaptcha.net/recaptcha/api.js"
async defer></script>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
<script>
function captchaDone() {
$('#registrationForm').submit();
}
</script>
</head>
<body>
<form id="registrationForm" method="post" action="{{ myurl }}">
<div>
<p>
Hello! We need to prevent computer programs and other automated
things from creating accounts on this server.
</p>
<p>
Please verify that you're not a robot.
</p>
<input type="hidden" name="session" value="{{ session }}" />
<div class="g-recaptcha"
data-sitekey="{{ sitekey }}"
data-callback="captchaDone">
</div>
<noscript>
<input type="submit" value="All Done" />
</noscript>
</div>
</div>
</form>
</body>
</html>

View File

@ -0,0 +1,20 @@
<html>
<head>
<title>Authentication</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
</head>
<body>
<form id="registrationForm" method="post" action="{{ myurl }}">
<div>
<p>
Please click the button below if you agree to the
<a href="{{ terms_url }}">privacy policy of this homeserver.</a>
</p>
<input type="hidden" name="session" value="{{ session }}" />
<input type="submit" value="Agree" />
</div>
</form>
</body>
</html>

View File

@ -25,94 +25,6 @@ from ._base import client_patterns
logger = logging.getLogger(__name__)
RECAPTCHA_TEMPLATE = """
<html>
<head>
<title>Authentication</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<script src="https://www.recaptcha.net/recaptcha/api.js"
async defer></script>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
<script>
function captchaDone() {
$('#registrationForm').submit();
}
</script>
</head>
<body>
<form id="registrationForm" method="post" action="%(myurl)s">
<div>
<p>
Hello! We need to prevent computer programs and other automated
things from creating accounts on this server.
</p>
<p>
Please verify that you're not a robot.
</p>
<input type="hidden" name="session" value="%(session)s" />
<div class="g-recaptcha"
data-sitekey="%(sitekey)s"
data-callback="captchaDone">
</div>
<noscript>
<input type="submit" value="All Done" />
</noscript>
</div>
</div>
</form>
</body>
</html>
"""
TERMS_TEMPLATE = """
<html>
<head>
<title>Authentication</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
</head>
<body>
<form id="registrationForm" method="post" action="%(myurl)s">
<div>
<p>
Please click the button below if you agree to the
<a href="%(terms_url)s">privacy policy of this homeserver.</a>
</p>
<input type="hidden" name="session" value="%(session)s" />
<input type="submit" value="Agree" />
</div>
</form>
</body>
</html>
"""
SUCCESS_TEMPLATE = """
<html>
<head>
<title>Success!</title>
<meta name='viewport' content='width=device-width, initial-scale=1,
user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'>
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
<script>
if (window.onAuthDone) {
window.onAuthDone();
} else if (window.opener && window.opener.postMessage) {
window.opener.postMessage("authDone", "*");
}
</script>
</head>
<body>
<div>
<p>Thank you</p>
<p>You may now close this window and return to the application</p>
</div>
</body>
</html>
"""
class AuthRestServlet(RestServlet):
"""
@ -145,26 +57,30 @@ class AuthRestServlet(RestServlet):
self._cas_server_url = hs.config.cas_server_url
self._cas_service_url = hs.config.cas_service_url
self.recaptcha_template = hs.config.recaptcha_template
self.terms_template = hs.config.terms_template
self.success_template = hs.config.fallback_success_template
async def on_GET(self, request, stagetype):
session = parse_string(request, "session")
if not session:
raise SynapseError(400, "No session supplied")
if stagetype == LoginType.RECAPTCHA:
html = RECAPTCHA_TEMPLATE % {
"session": session,
"myurl": "%s/r0/auth/%s/fallback/web"
html = self.recaptcha_template.render(
session=session,
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.RECAPTCHA),
"sitekey": self.hs.config.recaptcha_public_key,
}
sitekey=self.hs.config.recaptcha_public_key,
)
elif stagetype == LoginType.TERMS:
html = TERMS_TEMPLATE % {
"session": session,
"terms_url": "%s_matrix/consent?v=%s"
html = self.terms_template.render(
session=session,
terms_url="%s_matrix/consent?v=%s"
% (self.hs.config.public_baseurl, self.hs.config.user_consent_version),
"myurl": "%s/r0/auth/%s/fallback/web"
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.TERMS),
}
)
elif stagetype == LoginType.SSO:
# Display a confirmation page which prompts the user to
@ -222,14 +138,14 @@ class AuthRestServlet(RestServlet):
)
if success:
html = SUCCESS_TEMPLATE
html = self.success_template.render()
else:
html = RECAPTCHA_TEMPLATE % {
"session": session,
"myurl": "%s/r0/auth/%s/fallback/web"
html = self.recaptcha_template.render(
session=session,
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.RECAPTCHA),
"sitekey": self.hs.config.recaptcha_public_key,
}
sitekey=self.hs.config.recaptcha_public_key,
)
elif stagetype == LoginType.TERMS:
authdict = {"session": session}
@ -238,18 +154,18 @@ class AuthRestServlet(RestServlet):
)
if success:
html = SUCCESS_TEMPLATE
html = self.success_template.render()
else:
html = TERMS_TEMPLATE % {
"session": session,
"terms_url": "%s_matrix/consent?v=%s"
html = self.terms_template.render(
session=session,
terms_url="%s_matrix/consent?v=%s"
% (
self.hs.config.public_baseurl,
self.hs.config.user_consent_version,
),
"myurl": "%s/r0/auth/%s/fallback/web"
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.TERMS),
}
)
elif stagetype == LoginType.SSO:
# The SSO fallback workflow should not post here,
raise SynapseError(404, "Fallback SSO auth does not support POST requests.")

View File

@ -141,31 +141,34 @@ class MediaStorage:
Returns:
Returns a Responder if the file was found, otherwise None.
"""
paths = [self._file_info_to_path(file_info)]
path = self._file_info_to_path(file_info)
local_path = os.path.join(self.local_media_directory, path)
if os.path.exists(local_path):
return FileResponder(open(local_path, "rb"))
# Fallback for paths without method names
# Should be removed in the future
# fallback for remote thumbnails with no method in the filename
if file_info.thumbnail and file_info.server_name:
legacy_path = self.filepaths.remote_media_thumbnail_rel_legacy(
server_name=file_info.server_name,
file_id=file_info.file_id,
width=file_info.thumbnail_width,
height=file_info.thumbnail_height,
content_type=file_info.thumbnail_type,
paths.append(
self.filepaths.remote_media_thumbnail_rel_legacy(
server_name=file_info.server_name,
file_id=file_info.file_id,
width=file_info.thumbnail_width,
height=file_info.thumbnail_height,
content_type=file_info.thumbnail_type,
)
)
legacy_local_path = os.path.join(self.local_media_directory, legacy_path)
if os.path.exists(legacy_local_path):
return FileResponder(open(legacy_local_path, "rb"))
for path in paths:
local_path = os.path.join(self.local_media_directory, path)
if os.path.exists(local_path):
logger.debug("responding with local file %s", local_path)
return FileResponder(open(local_path, "rb"))
logger.debug("local file %s did not exist", local_path)
for provider in self.storage_providers:
res = await provider.fetch(path, file_info) # type: Any
if res:
logger.debug("Streaming %s from %s", path, provider)
return res
for path in paths:
res = await provider.fetch(path, file_info) # type: Any
if res:
logger.debug("Streaming %s from %s", path, provider)
return res
logger.debug("%s not found on %s", path, provider)
return None

View File

@ -341,7 +341,7 @@ class MultiWriterIdGenerator:
"cmp": "<=" if self._positive else ">=",
}
sql = self._db.engine.convert_param_style(sql)
cur.execute(sql, (min_stream_id,))
cur.execute(sql, (min_stream_id * self._return_factor,))
self._persisted_upto_position = min_stream_id