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

Commit

Permalink
Do not assume that account data is of the correct form. (#8454)
Browse files Browse the repository at this point in the history
This fixes a bug where `m.ignored_user_list` was assumed to be a dict,
leading to odd behavior for users who set it to something else.
  • Loading branch information
clokep authored Oct 5, 2020
1 parent e3debf9 commit c5251c6
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 21 deletions.
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

0 comments on commit c5251c6

Please sign in to comment.