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

Do not assume that m.ignored_user_list data is of the correct form. #8454

Merged
merged 4 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/8454.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a longstanding bug where invalid ignored users in account data could break clients.
5 changes: 5 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,8 @@ class EventContentFields:
class RoomEncryptionAlgorithms:
MEGOLM_V1_AES_SHA2 = "m.megolm.v1.aes-sha2"
DEFAULT = MEGOLM_V1_AES_SHA2


class AccountDataTypes:
DIRECT = "m.direct"
IGNORED_USER_LIST = "m.ignored_user_list"
6 changes: 3 additions & 3 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from unpaddedbase64 import encode_base64

from synapse import types
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
from synapse.api.constants import MAX_DEPTH, AccountDataTypes, EventTypes, Membership
from synapse.api.errors import (
AuthError,
Codes,
Expand Down Expand Up @@ -247,7 +247,7 @@ async def copy_room_tags_and_direct_to_room(
user_account_data, _ = await self.store.get_account_data_for_user(user_id)

# Copy direct message state if applicable
direct_rooms = user_account_data.get("m.direct", {})
direct_rooms = user_account_data.get(AccountDataTypes.DIRECT, {})

# Check which key this room is under
if isinstance(direct_rooms, dict):
Expand All @@ -258,7 +258,7 @@ async def copy_room_tags_and_direct_to_room(

# Save back to user's m.direct account data
await self.store.add_account_data_for_user(
user_id, "m.direct", direct_rooms
user_id, AccountDataTypes.DIRECT, direct_rooms
)
break

Expand Down
19 changes: 11 additions & 8 deletions synapse/handlers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import attr
from prometheus_client import Counter

from synapse.api.constants import EventTypes, Membership
from synapse.api.constants import AccountDataTypes, EventTypes, Membership
from synapse.api.filtering import FilterCollection
from synapse.events import EventBase
from synapse.logging.context import current_context
Expand Down Expand Up @@ -1378,13 +1378,16 @@ async def _generate_sync_entry_for_rooms(
return set(), set(), set(), set()

ignored_account_data = await self.store.get_global_account_data_by_type_for_user(
"m.ignored_user_list", user_id=user_id
AccountDataTypes.IGNORED_USER_LIST, user_id=user_id
)

# If there is ignored users account data and it matches the proper type,
# then use it.
ignored_users = frozenset() # type: FrozenSet[str]
if ignored_account_data:
ignored_users = ignored_account_data.get("ignored_users", {}).keys()
else:
ignored_users = frozenset()
ignored_users_data = ignored_account_data.get("ignored_users", {})
if isinstance(ignored_users_data, dict):
ignored_users = frozenset(ignored_users_data.keys())

if since_token:
room_changes = await self._get_rooms_changed(
Expand Down Expand Up @@ -1478,7 +1481,7 @@ async def _have_rooms_changed(
return False

async def _get_rooms_changed(
self, sync_result_builder: "SyncResultBuilder", ignored_users: Set[str]
self, sync_result_builder: "SyncResultBuilder", ignored_users: FrozenSet[str]
) -> _RoomChanges:
"""Gets the the changes that have happened since the last sync.
"""
Expand Down Expand Up @@ -1690,7 +1693,7 @@ async def _get_rooms_changed(
return _RoomChanges(room_entries, invited, newly_joined_rooms, newly_left_rooms)

async def _get_all_rooms(
self, sync_result_builder: "SyncResultBuilder", ignored_users: Set[str]
self, sync_result_builder: "SyncResultBuilder", ignored_users: FrozenSet[str]
) -> _RoomChanges:
"""Returns entries for all rooms for the user.

Expand Down Expand Up @@ -1764,7 +1767,7 @@ async def _get_all_rooms(
async def _generate_room_entry(
self,
sync_result_builder: "SyncResultBuilder",
ignored_users: Set[str],
ignored_users: FrozenSet[str],
room_builder: "RoomSyncResultBuilder",
ephemeral: List[JsonDict],
tags: Optional[Dict[str, Dict[str, Any]]],
Expand Down
9 changes: 7 additions & 2 deletions synapse/storage/databases/main/account_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import logging
from typing import Dict, List, Optional, Tuple

from synapse.api.constants import AccountDataTypes
from synapse.storage._base import SQLBaseStore, db_to_json
from synapse.storage.database import DatabasePool
from synapse.storage.util.id_generators import StreamIdGenerator
Expand Down Expand Up @@ -291,14 +292,18 @@ async def is_ignored_by(
self, ignored_user_id: str, ignorer_user_id: str, cache_context: _CacheContext
) -> bool:
ignored_account_data = await self.get_global_account_data_by_type_for_user(
"m.ignored_user_list",
AccountDataTypes.IGNORED_USER_LIST,
ignorer_user_id,
on_invalidate=cache_context.invalidate,
)
if not ignored_account_data:
return False

return ignored_user_id in ignored_account_data.get("ignored_users", {})
try:
return ignored_user_id in ignored_account_data.get("ignored_users", {})
except TypeError:
# The type of the ignored_users field is invalid.
return False


class AccountDataStore(AccountDataWorkerStore):
Expand Down
15 changes: 7 additions & 8 deletions synapse/visibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import logging
import operator

from synapse.api.constants import EventTypes, Membership
from synapse.api.constants import AccountDataTypes, EventTypes, Membership
from synapse.events.utils import prune_event
from synapse.storage import Storage
from synapse.storage.state import StateFilter
Expand Down Expand Up @@ -77,15 +77,14 @@ async def filter_events_for_client(
)

ignore_dict_content = await storage.main.get_global_account_data_by_type_for_user(
"m.ignored_user_list", user_id
AccountDataTypes.IGNORED_USER_LIST, user_id
)

# FIXME: This will explode if people upload something incorrect.
ignore_list = frozenset(
ignore_dict_content.get("ignored_users", {}).keys()
if ignore_dict_content
else []
)
ignore_list = frozenset()
if ignore_dict_content:
ignored_users_dict = ignore_dict_content.get("ignored_users", {})
if isinstance(ignored_users_dict, dict):
ignore_list = frozenset(ignored_users_dict.keys())

erased_senders = await storage.main.are_users_erased((e.sender for e in events))

Expand Down