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

Commit

Permalink
Merge commit 'abeab964d' into anoa/dinsic_release_1_21_x
Browse files Browse the repository at this point in the history
* commit 'abeab964d':
  Make _get_e2e_device_keys_and_signatures_txn return an attrs (#8224)
  Fix errors when updating the user directory with invalid data (#8223)
  Explain better what GDPR-erased means (#8189)
  Convert additional databases to async/await part 3 (#8201)
  Convert appservice code to async/await. (#8207)
  Rename `_get_e2e_device_keys_txn` (#8222)
  • Loading branch information
anoadragon453 committed Oct 20, 2020
2 parents e85c635 + abeab96 commit 2bd022e
Show file tree
Hide file tree
Showing 17 changed files with 207 additions and 124 deletions.
1 change: 1 addition & 0 deletions changelog.d/8189.doc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Explain better what GDPR-erased means when deactivating a user.
1 change: 1 addition & 0 deletions changelog.d/8201.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Convert various parts of the codebase to async/await.
1 change: 1 addition & 0 deletions changelog.d/8207.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Convert various parts of the codebase to async/await.
1 change: 1 addition & 0 deletions changelog.d/8222.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor queries for device keys and cross-signatures.
1 change: 1 addition & 0 deletions changelog.d/8223.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes a longstanding bug where user directory updates could break when unexpected profile data was included in events.
1 change: 1 addition & 0 deletions changelog.d/8224.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor queries for device keys and cross-signatures.
8 changes: 5 additions & 3 deletions docs/admin_api/user_admin_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ Deactivate Account

This API deactivates an account. It removes active access tokens, resets the
password, and deletes third-party IDs (to prevent the user requesting a
password reset). It can also mark the user as GDPR-erased (stopping their data
from distributed further, and deleting it entirely if there are no other
references to it).
password reset).

It can also mark the user as GDPR-erased. This means messages sent by the
user will still be visible by anyone that was in the room when these messages
were sent, but hidden from users joining the room afterwards.

The api is::

Expand Down
19 changes: 11 additions & 8 deletions synapse/appservice/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@
# limitations under the License.
import logging
import urllib
from typing import TYPE_CHECKING, Optional

from prometheus_client import Counter

from twisted.internet import defer

from synapse.api.constants import EventTypes, ThirdPartyEntityKind
from synapse.api.errors import CodeMessageException
from synapse.events.utils import serialize_event
from synapse.http.client import SimpleHttpClient
from synapse.types import ThirdPartyInstanceID
from synapse.types import JsonDict, ThirdPartyInstanceID
from synapse.util.caches.response_cache import ResponseCache

if TYPE_CHECKING:
from synapse.appservice import ApplicationService

logger = logging.getLogger(__name__)

sent_transactions_counter = Counter(
Expand Down Expand Up @@ -163,19 +165,20 @@ async def query_3pe(self, service, kind, protocol, fields):
logger.warning("query_3pe to %s threw exception %s", uri, ex)
return []

def get_3pe_protocol(self, service, protocol):
async def get_3pe_protocol(
self, service: "ApplicationService", protocol: str
) -> Optional[JsonDict]:
if service.url is None:
return {}

@defer.inlineCallbacks
def _get():
async def _get() -> Optional[JsonDict]:
uri = "%s%s/thirdparty/protocol/%s" % (
service.url,
APP_SERVICE_PREFIX,
urllib.parse.quote(protocol),
)
try:
info = yield defer.ensureDeferred(self.get_json(uri, {}))
info = await self.get_json(uri, {})

if not _is_valid_3pe_metadata(info):
logger.warning(
Expand All @@ -196,7 +199,7 @@ def _get():
return None

key = (service.id, protocol)
return self.protocol_meta_cache.wrap(key, _get)
return await self.protocol_meta_cache.wrap(key, _get)

async def push_bulk(self, service, events, txn_id=None):
if service.url is None:
Expand Down
6 changes: 6 additions & 0 deletions synapse/handlers/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ async def set_displayname(
Codes.FORBIDDEN,
)

if not isinstance(new_displayname, str):
raise SynapseError(400, "Invalid displayname")

if len(new_displayname) > MAX_DISPLAYNAME_LEN:
raise SynapseError(
400, "Displayname is too long (max %i)" % (MAX_DISPLAYNAME_LEN,)
Expand Down Expand Up @@ -386,6 +389,9 @@ async def set_avatar_url(
400, "Changing avatar is disabled on this server", Codes.FORBIDDEN
)

if not isinstance(new_avatar_url, str):
raise SynapseError(400, "Invalid displayname")

if len(new_avatar_url) > MAX_AVATAR_URL_LEN:
raise SynapseError(
400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN,)
Expand Down
8 changes: 7 additions & 1 deletion synapse/handlers/user_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ async def _handle_deltas(self, deltas):
async def _handle_room_publicity_change(
self, room_id, prev_event_id, event_id, typ
):
"""Handle a room having potentially changed from/to world_readable/publically
"""Handle a room having potentially changed from/to world_readable/publicly
joinable.
Args:
Expand Down Expand Up @@ -388,9 +388,15 @@ async def _handle_profile_change(self, user_id, room_id, prev_event_id, event_id

prev_name = prev_event.content.get("displayname")
new_name = event.content.get("displayname")
# If the new name is an unexpected form, do not update the directory.
if not isinstance(new_name, str):
new_name = prev_name

prev_avatar = prev_event.content.get("avatar_url")
new_avatar = event.content.get("avatar_url")
# If the new avatar is an unexpected form, do not update the directory.
if not isinstance(new_avatar, str):
new_avatar = prev_avatar

if prev_name != new_name or prev_avatar != new_avatar:
await self.store.update_profile_in_user_dir(user_id, new_name, new_avatar)
4 changes: 2 additions & 2 deletions synapse/storage/background_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,15 +433,15 @@ async def _end_background_update(self, update_name: str) -> None:
"background_updates", keyvalues={"update_name": update_name}
)

def _background_update_progress(self, update_name: str, progress: dict):
async def _background_update_progress(self, update_name: str, progress: dict):
"""Update the progress of a background update
Args:
update_name: The name of the background update task
progress: The progress of the update.
"""

return self.db_pool.runInteraction(
return await self.db_pool.runInteraction(
"background_update_progress",
self._background_update_progress_txn,
update_name,
Expand Down
59 changes: 32 additions & 27 deletions synapse/storage/databases/main/account_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@

import abc
import logging
from typing import List, Optional, Tuple

from twisted.internet import defer
from typing import Dict, List, Optional, Tuple

from synapse.storage._base import SQLBaseStore, db_to_json
from synapse.storage.database import DatabasePool
Expand Down Expand Up @@ -58,14 +56,16 @@ def get_max_account_data_stream_id(self):
raise NotImplementedError()

@cached()
def get_account_data_for_user(self, user_id):
async def get_account_data_for_user(
self, user_id: str
) -> Tuple[Dict[str, JsonDict], Dict[str, Dict[str, JsonDict]]]:
"""Get all the client account_data for a user.
Args:
user_id(str): The user to get the account_data for.
user_id: The user to get the account_data for.
Returns:
A deferred pair of a dict of global account_data and a dict
mapping from room_id string to per room account_data dicts.
A 2-tuple of a dict of global account_data and a dict mapping from
room_id string to per room account_data dicts.
"""

def get_account_data_for_user_txn(txn):
Expand Down Expand Up @@ -94,7 +94,7 @@ def get_account_data_for_user_txn(txn):

return global_account_data, by_room

return self.db_pool.runInteraction(
return await self.db_pool.runInteraction(
"get_account_data_for_user", get_account_data_for_user_txn
)

Expand All @@ -120,14 +120,16 @@ async def get_global_account_data_by_type_for_user(
return None

@cached(num_args=2)
def get_account_data_for_room(self, user_id, room_id):
async def get_account_data_for_room(
self, user_id: str, room_id: str
) -> Dict[str, JsonDict]:
"""Get all the client account_data for a user for a room.
Args:
user_id(str): The user to get the account_data for.
room_id(str): The room to get the account_data for.
user_id: The user to get the account_data for.
room_id: The room to get the account_data for.
Returns:
A deferred dict of the room account_data
A dict of the room account_data
"""

def get_account_data_for_room_txn(txn):
Expand All @@ -142,21 +144,22 @@ def get_account_data_for_room_txn(txn):
row["account_data_type"]: db_to_json(row["content"]) for row in rows
}

return self.db_pool.runInteraction(
return await self.db_pool.runInteraction(
"get_account_data_for_room", get_account_data_for_room_txn
)

@cached(num_args=3, max_entries=5000)
def get_account_data_for_room_and_type(self, user_id, room_id, account_data_type):
async def get_account_data_for_room_and_type(
self, user_id: str, room_id: str, account_data_type: str
) -> Optional[JsonDict]:
"""Get the client account_data of given type for a user for a room.
Args:
user_id(str): The user to get the account_data for.
room_id(str): The room to get the account_data for.
account_data_type (str): The account data type to get.
user_id: The user to get the account_data for.
room_id: The room to get the account_data for.
account_data_type: The account data type to get.
Returns:
A deferred of the room account_data for that type, or None if
there isn't any set.
The room account_data for that type, or None if there isn't any set.
"""

def get_account_data_for_room_and_type_txn(txn):
Expand All @@ -174,7 +177,7 @@ def get_account_data_for_room_and_type_txn(txn):

return db_to_json(content_json) if content_json else None

return self.db_pool.runInteraction(
return await self.db_pool.runInteraction(
"get_account_data_for_room_and_type", get_account_data_for_room_and_type_txn
)

Expand Down Expand Up @@ -238,12 +241,14 @@ def get_updated_room_account_data_txn(txn):
"get_updated_room_account_data", get_updated_room_account_data_txn
)

def get_updated_account_data_for_user(self, user_id, stream_id):
async def get_updated_account_data_for_user(
self, user_id: str, stream_id: int
) -> Tuple[Dict[str, JsonDict], Dict[str, Dict[str, JsonDict]]]:
"""Get all the client account_data for a that's changed for a user
Args:
user_id(str): The user to get the account_data for.
stream_id(int): The point in the stream since which to get updates
user_id: The user to get the account_data for.
stream_id: The point in the stream since which to get updates
Returns:
A deferred pair of a dict of global account_data and a dict
mapping from room_id string to per room account_data dicts.
Expand Down Expand Up @@ -277,9 +282,9 @@ def get_updated_account_data_for_user_txn(txn):
user_id, int(stream_id)
)
if not changed:
return defer.succeed(({}, {}))
return ({}, {})

return self.db_pool.runInteraction(
return await self.db_pool.runInteraction(
"get_updated_account_data_for_user", get_updated_account_data_for_user_txn
)

Expand Down Expand Up @@ -416,7 +421,7 @@ async def add_account_data_for_user(

return self._account_data_id_gen.get_current_token()

def _update_max_stream_id(self, next_id: int):
async def _update_max_stream_id(self, next_id: int) -> None:
"""Update the max stream_id
Args:
Expand All @@ -435,4 +440,4 @@ def _update(txn):
)
txn.execute(update_max_id_sql, (next_id, next_id))

return self.db_pool.runInteraction("update_account_data_max_stream_id", _update)
await self.db_pool.runInteraction("update_account_data_max_stream_id", _update)
12 changes: 6 additions & 6 deletions synapse/storage/databases/main/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ async def _get_device_update_edus_by_remote(
"""
devices = (
await self.db_pool.runInteraction(
"_get_e2e_device_keys_txn",
self._get_e2e_device_keys_txn,
"get_e2e_device_keys_and_signatures_txn",
self._get_e2e_device_keys_and_signatures_txn,
query_map.keys(),
include_all_devices=True,
include_deleted_devices=True,
Expand Down Expand Up @@ -293,17 +293,17 @@ async def _get_device_update_edus_by_remote(
prev_id = stream_id

if device is not None:
key_json = device.get("key_json", None)
key_json = device.key_json
if key_json:
result["keys"] = db_to_json(key_json)

if "signatures" in device:
for sig_user_id, sigs in device["signatures"].items():
if device.signatures:
for sig_user_id, sigs in device.signatures.items():
result["keys"].setdefault("signatures", {}).setdefault(
sig_user_id, {}
).update(sigs)

device_display_name = device.get("device_display_name", None)
device_display_name = device.display_name
if device_display_name:
result["device_display_name"] = device_display_name
else:
Expand Down
Loading

0 comments on commit 2bd022e

Please sign in to comment.