Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 053ca5f

Browse files
author
Sean Quah
committed
Merge tag 'v1.60.0rc2' into develop
Synapse 1.60.0rc2 (2022-05-27) ============================== This release of Synapse adds a unique index to the `state_group_edges` table, in order to prevent accidentally introducing duplicate information (for example, because a database backup was restored multiple times). If your Synapse database already has duplicate rows in this table, this could fail with an error and require manual remediation. Additionally, the signature of the `check_event_for_spam` module callback has changed. The previous signature has been deprecated and remains working for now. Module authors should update their modules to use the new signature where possible. See [the upgrade notes](https://github.com/matrix-org/synapse/blob/develop/docs/upgrade.md#upgrading-to-v1600) for more details. Features -------- - Add an option allowing users to use their password to reauthenticate for privileged actions even though password login is disabled. ([\#12883](#12883)) Bugfixes -------- - Explicitly close `ijson` coroutines once we are done with them, instead of leaving the garbage collector to close them. ([\#12875](#12875)) Internal Changes ---------------- - Improve URL previews by not including the content of media tags in the generated description. ([\#12887](#12887))
2 parents a7da00d + e409ab8 commit 053ca5f

File tree

11 files changed

+138
-17
lines changed

11 files changed

+138
-17
lines changed

CHANGES.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Synapse 1.60.0rc1 (2022-05-24)
1+
Synapse 1.60.0rc2 (2022-05-27)
22
==============================
33

44
This release of Synapse adds a unique index to the `state_group_edges` table, in
@@ -17,6 +17,27 @@ for more details.
1717
Features
1818
--------
1919

20+
- Add an option allowing users to use their password to reauthenticate for privileged actions even though password login is disabled. ([\#12883](https://github.com/matrix-org/synapse/issues/12883))
21+
22+
23+
Bugfixes
24+
--------
25+
26+
- Explicitly close `ijson` coroutines once we are done with them, instead of leaving the garbage collector to close them. ([\#12875](https://github.com/matrix-org/synapse/issues/12875))
27+
28+
29+
Internal Changes
30+
----------------
31+
32+
- Improve URL previews by not including the content of media tags in the generated description. ([\#12887](https://github.com/matrix-org/synapse/issues/12887))
33+
34+
35+
Synapse 1.60.0rc1 (2022-05-24)
36+
==============================
37+
38+
Features
39+
--------
40+
2041
- Measure the time taken in spam-checking callbacks and expose those measurements as metrics. ([\#12513](https://github.com/matrix-org/synapse/issues/12513))
2142
- Add a `default_power_level_content_override` config option to set default room power levels per room preset. ([\#12618](https://github.com/matrix-org/synapse/issues/12618))
2243
- Add support for [MSC3787: Allowing knocks to restricted rooms](https://github.com/matrix-org/matrix-spec-proposals/pull/3787). ([\#12623](https://github.com/matrix-org/synapse/issues/12623))

debian/changelog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
matrix-synapse-py3 (1.60.0~rc2) stable; urgency=medium
2+
3+
* New Synapse release 1.60.0rc2.
4+
5+
-- Synapse Packaging team <[email protected]> Fri, 27 May 2022 11:04:55 +0100
6+
17
matrix-synapse-py3 (1.60.0~rc1) stable; urgency=medium
28

39
* New Synapse release 1.60.0rc1.

docs/sample_config.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2216,7 +2216,9 @@ sso:
22162216

22172217

22182218
password_config:
2219-
# Uncomment to disable password login
2219+
# Uncomment to disable password login.
2220+
# Set to `only_for_reauth` to permit reauthentication for users that
2221+
# have passwords and are already logged in.
22202222
#
22212223
#enabled: false
22222224

docs/usage/configuration/config_documentation.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,6 +2930,9 @@ Use this setting to enable password-based logins.
29302930

29312931
This setting has the following sub-options:
29322932
* `enabled`: Defaults to true.
2933+
Set to false to disable password authentication.
2934+
Set to `only_for_reauth` to allow users with existing passwords to use them
2935+
to log in and reauthenticate, whilst preventing new users from setting passwords.
29332936
* `localdb_enabled`: Set to false to disable authentication against the local password
29342937
database. This is ignored if `enabled` is false, and is only useful
29352938
if you have other `password_providers`. Defaults to true.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ skip_gitignore = true
5454

5555
[tool.poetry]
5656
name = "matrix-synapse"
57-
version = "1.60.0rc1"
57+
version = "1.60.0rc2"
5858
description = "Homeserver for the Matrix decentralised comms protocol"
5959
authors = ["Matrix.org Team and Contributors <[email protected]>"]
6060
license = "Apache-2.0"

synapse/config/auth.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,18 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
2929
if password_config is None:
3030
password_config = {}
3131

32-
self.password_enabled = password_config.get("enabled", True)
32+
passwords_enabled = password_config.get("enabled", True)
33+
# 'only_for_reauth' allows users who have previously set a password to use it,
34+
# even though passwords would otherwise be disabled.
35+
passwords_for_reauth_only = passwords_enabled == "only_for_reauth"
36+
37+
self.password_enabled_for_login = (
38+
passwords_enabled and not passwords_for_reauth_only
39+
)
40+
self.password_enabled_for_reauth = (
41+
passwords_for_reauth_only or passwords_enabled
42+
)
43+
3344
self.password_localdb_enabled = password_config.get("localdb_enabled", True)
3445
self.password_pepper = password_config.get("pepper", "")
3546

@@ -46,7 +57,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
4657
def generate_config_section(self, **kwargs: Any) -> str:
4758
return """\
4859
password_config:
49-
# Uncomment to disable password login
60+
# Uncomment to disable password login.
61+
# Set to `only_for_reauth` to permit reauthentication for users that
62+
# have passwords and are already logged in.
5063
#
5164
#enabled: false
5265

synapse/federation/transport/client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ class SendJoinParser(ByteParser[SendJoinResponse]):
13611361
def __init__(self, room_version: RoomVersion, v1_api: bool):
13621362
self._response = SendJoinResponse([], [], event_dict={})
13631363
self._room_version = room_version
1364-
self._coros = []
1364+
self._coros: List[Generator[None, bytes, None]] = []
13651365

13661366
# The V1 API has the shape of `[200, {...}]`, which we handle by
13671367
# prefixing with `item.*`.
@@ -1409,6 +1409,9 @@ def write(self, data: bytes) -> int:
14091409
return len(data)
14101410

14111411
def finish(self) -> SendJoinResponse:
1412+
for c in self._coros:
1413+
c.close()
1414+
14121415
if self._response.event_dict:
14131416
self._response.event = make_event_from_dict(
14141417
self._response.event_dict, self._room_version
@@ -1431,7 +1434,7 @@ class _StateParser(ByteParser[StateRequestResponse]):
14311434
def __init__(self, room_version: RoomVersion):
14321435
self._response = StateRequestResponse([], [])
14331436
self._room_version = room_version
1434-
self._coros = [
1437+
self._coros: List[Generator[None, bytes, None]] = [
14351438
ijson.items_coro(
14361439
_event_list_parser(room_version, self._response.state),
14371440
"pdus.item",
@@ -1450,4 +1453,6 @@ def write(self, data: bytes) -> int:
14501453
return len(data)
14511454

14521455
def finish(self) -> StateRequestResponse:
1456+
for c in self._coros:
1457+
c.close()
14531458
return self._response

synapse/handlers/auth.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ def __init__(self, hs: "HomeServer"):
210210

211211
self.hs = hs # FIXME better possibility to access registrationHandler later?
212212
self.macaroon_gen = hs.get_macaroon_generator()
213-
self._password_enabled = hs.config.auth.password_enabled
213+
self._password_enabled_for_login = hs.config.auth.password_enabled_for_login
214+
self._password_enabled_for_reauth = hs.config.auth.password_enabled_for_reauth
214215
self._password_localdb_enabled = hs.config.auth.password_localdb_enabled
215216
self._third_party_rules = hs.get_third_party_event_rules()
216217

@@ -387,13 +388,13 @@ def get_new_session_data() -> JsonDict:
387388
return params, session_id
388389

389390
async def _get_available_ui_auth_types(self, user: UserID) -> Iterable[str]:
390-
"""Get a list of the authentication types this user can use"""
391+
"""Get a list of the user-interactive authentication types this user can use."""
391392

392393
ui_auth_types = set()
393394

394395
# if the HS supports password auth, and the user has a non-null password, we
395396
# support password auth
396-
if self._password_localdb_enabled and self._password_enabled:
397+
if self._password_localdb_enabled and self._password_enabled_for_reauth:
397398
lookupres = await self._find_user_id_and_pwd_hash(user.to_string())
398399
if lookupres:
399400
_, password_hash = lookupres
@@ -402,7 +403,7 @@ async def _get_available_ui_auth_types(self, user: UserID) -> Iterable[str]:
402403

403404
# also allow auth from password providers
404405
for t in self.password_auth_provider.get_supported_login_types().keys():
405-
if t == LoginType.PASSWORD and not self._password_enabled:
406+
if t == LoginType.PASSWORD and not self._password_enabled_for_reauth:
406407
continue
407408
ui_auth_types.add(t)
408409

@@ -710,7 +711,7 @@ async def _check_auth_dict(
710711
return res
711712

712713
# fall back to the v1 login flow
713-
canonical_id, _ = await self.validate_login(authdict)
714+
canonical_id, _ = await self.validate_login(authdict, is_reauth=True)
714715
return canonical_id
715716

716717
def _get_params_recaptcha(self) -> dict:
@@ -1064,7 +1065,7 @@ def can_change_password(self) -> bool:
10641065
Returns:
10651066
Whether users on this server are allowed to change or set a password
10661067
"""
1067-
return self._password_enabled and self._password_localdb_enabled
1068+
return self._password_enabled_for_login and self._password_localdb_enabled
10681069

10691070
def get_supported_login_types(self) -> Iterable[str]:
10701071
"""Get a the login types supported for the /login API
@@ -1089,9 +1090,9 @@ def get_supported_login_types(self) -> Iterable[str]:
10891090
# that comes first, where it's present.
10901091
if LoginType.PASSWORD in types:
10911092
types.remove(LoginType.PASSWORD)
1092-
if self._password_enabled:
1093+
if self._password_enabled_for_login:
10931094
types.insert(0, LoginType.PASSWORD)
1094-
elif self._password_localdb_enabled and self._password_enabled:
1095+
elif self._password_localdb_enabled and self._password_enabled_for_login:
10951096
types.insert(0, LoginType.PASSWORD)
10961097

10971098
return types
@@ -1100,6 +1101,7 @@ async def validate_login(
11001101
self,
11011102
login_submission: Dict[str, Any],
11021103
ratelimit: bool = False,
1104+
is_reauth: bool = False,
11031105
) -> Tuple[str, Optional[Callable[["LoginResponse"], Awaitable[None]]]]:
11041106
"""Authenticates the user for the /login API
11051107
@@ -1110,6 +1112,9 @@ async def validate_login(
11101112
login_submission: the whole of the login submission
11111113
(including 'type' and other relevant fields)
11121114
ratelimit: whether to apply the failed_login_attempt ratelimiter
1115+
is_reauth: whether this is part of a User-Interactive Authorisation
1116+
flow to reauthenticate for a privileged action (rather than a
1117+
new login)
11131118
Returns:
11141119
A tuple of the canonical user id, and optional callback
11151120
to be called once the access token and device id are issued
@@ -1132,8 +1137,14 @@ async def validate_login(
11321137
# special case to check for "password" for the check_password interface
11331138
# for the auth providers
11341139
password = login_submission.get("password")
1140+
11351141
if login_type == LoginType.PASSWORD:
1136-
if not self._password_enabled:
1142+
if is_reauth:
1143+
passwords_allowed_here = self._password_enabled_for_reauth
1144+
else:
1145+
passwords_allowed_here = self._password_enabled_for_login
1146+
1147+
if not passwords_allowed_here:
11371148
raise SynapseError(400, "Password login has been disabled.")
11381149
if not isinstance(password, str):
11391150
raise SynapseError(400, "Bad parameter: password", Codes.INVALID_PARAM)

synapse/http/matrixfederationclient.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ async def _handle_response(
223223

224224
max_response_size = parser.MAX_RESPONSE_SIZE
225225

226+
finished = False
226227
try:
227228
check_content_type_is(response.headers, parser.CONTENT_TYPE)
228229

@@ -231,6 +232,7 @@ async def _handle_response(
231232

232233
length = await make_deferred_yieldable(d)
233234

235+
finished = True
234236
value = parser.finish()
235237
except BodyExceededMaxSize as e:
236238
# The response was too big.
@@ -281,6 +283,15 @@ async def _handle_response(
281283
e,
282284
)
283285
raise
286+
finally:
287+
if not finished:
288+
# There was an exception and we didn't `finish()` the parse.
289+
# Let the parser know that it can free up any resources.
290+
try:
291+
parser.finish()
292+
except Exception:
293+
# Ignore any additional exceptions.
294+
pass
284295

285296
time_taken_secs = reactor.seconds() - start_ms / 1000
286297

synapse/rest/media/v1/preview_html.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@ def parse_html_description(tree: "etree.Element") -> Optional[str]:
246246
247247
Grabs any text nodes which are inside the <body/> tag, unless they are within
248248
an HTML5 semantic markup tag (<header/>, <nav/>, <aside/>, <footer/>), or
249-
if they are within a <script/> or <style/> tag.
249+
if they are within a <script/>, <svg/> or <style/> tag, or if they are within
250+
a tag whose content is usually only shown to old browsers
251+
(<iframe/>, <video/>, <canvas/>, <picture/>).
250252
251253
This is a very very very coarse approximation to a plain text render of the page.
252254
@@ -268,6 +270,12 @@ def parse_html_description(tree: "etree.Element") -> Optional[str]:
268270
"script",
269271
"noscript",
270272
"style",
273+
"svg",
274+
"iframe",
275+
"video",
276+
"canvas",
277+
"img",
278+
"picture",
271279
etree.Comment,
272280
)
273281

0 commit comments

Comments
 (0)