|
|
|
@ -12,9 +12,9 @@ |
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
|
|
# See the License for the specific language governing permissions and |
|
|
|
|
# limitations under the License. |
|
|
|
|
|
|
|
|
|
import logging |
|
|
|
|
import random |
|
|
|
|
from typing import TYPE_CHECKING, Optional |
|
|
|
|
|
|
|
|
|
from synapse.api.errors import ( |
|
|
|
|
AuthError, |
|
|
|
@ -25,10 +25,19 @@ from synapse.api.errors import ( |
|
|
|
|
SynapseError, |
|
|
|
|
) |
|
|
|
|
from synapse.metrics.background_process_metrics import wrap_as_background_process |
|
|
|
|
from synapse.types import UserID, create_requester, get_domain_from_id |
|
|
|
|
from synapse.types import ( |
|
|
|
|
JsonDict, |
|
|
|
|
Requester, |
|
|
|
|
UserID, |
|
|
|
|
create_requester, |
|
|
|
|
get_domain_from_id, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
from ._base import BaseHandler |
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING: |
|
|
|
|
from synapse.app.homeserver import HomeServer |
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
MAX_DISPLAYNAME_LEN = 256 |
|
|
|
@ -45,7 +54,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
PROFILE_UPDATE_MS = 60 * 1000 |
|
|
|
|
PROFILE_UPDATE_EVERY_MS = 24 * 60 * 60 * 1000 |
|
|
|
|
|
|
|
|
|
def __init__(self, hs): |
|
|
|
|
def __init__(self, hs: "HomeServer"): |
|
|
|
|
super().__init__(hs) |
|
|
|
|
|
|
|
|
|
self.federation = hs.get_federation_client() |
|
|
|
@ -60,7 +69,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
self._update_remote_profile_cache, self.PROFILE_UPDATE_MS |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
async def get_profile(self, user_id): |
|
|
|
|
async def get_profile(self, user_id: str) -> JsonDict: |
|
|
|
|
target_user = UserID.from_string(user_id) |
|
|
|
|
|
|
|
|
|
if self.hs.is_mine(target_user): |
|
|
|
@ -91,7 +100,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
except HttpResponseException as e: |
|
|
|
|
raise e.to_synapse_error() |
|
|
|
|
|
|
|
|
|
async def get_profile_from_cache(self, user_id): |
|
|
|
|
async def get_profile_from_cache(self, user_id: str) -> JsonDict: |
|
|
|
|
"""Get the profile information from our local cache. If the user is |
|
|
|
|
ours then the profile information will always be corect. Otherwise, |
|
|
|
|
it may be out of date/missing. |
|
|
|
@ -115,7 +124,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
profile = await self.store.get_from_remote_profile_cache(user_id) |
|
|
|
|
return profile or {} |
|
|
|
|
|
|
|
|
|
async def get_displayname(self, target_user): |
|
|
|
|
async def get_displayname(self, target_user: UserID) -> str: |
|
|
|
|
if self.hs.is_mine(target_user): |
|
|
|
|
try: |
|
|
|
|
displayname = await self.store.get_profile_displayname( |
|
|
|
@ -143,15 +152,19 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
return result["displayname"] |
|
|
|
|
|
|
|
|
|
async def set_displayname( |
|
|
|
|
self, target_user, requester, new_displayname, by_admin=False |
|
|
|
|
): |
|
|
|
|
self, |
|
|
|
|
target_user: UserID, |
|
|
|
|
requester: Requester, |
|
|
|
|
new_displayname: str, |
|
|
|
|
by_admin: bool = False, |
|
|
|
|
) -> None: |
|
|
|
|
"""Set the displayname of a user |
|
|
|
|
|
|
|
|
|
Args: |
|
|
|
|
target_user (UserID): the user whose displayname is to be changed. |
|
|
|
|
requester (Requester): The user attempting to make this change. |
|
|
|
|
new_displayname (str): The displayname to give this user. |
|
|
|
|
by_admin (bool): Whether this change was made by an administrator. |
|
|
|
|
target_user: the user whose displayname is to be changed. |
|
|
|
|
requester: The user attempting to make this change. |
|
|
|
|
new_displayname: The displayname to give this user. |
|
|
|
|
by_admin: Whether this change was made by an administrator. |
|
|
|
|
""" |
|
|
|
|
if not self.hs.is_mine(target_user): |
|
|
|
|
raise SynapseError(400, "User is not hosted on this homeserver") |
|
|
|
@ -176,8 +189,9 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
400, "Displayname is too long (max %i)" % (MAX_DISPLAYNAME_LEN,) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
displayname_to_set = new_displayname # type: Optional[str] |
|
|
|
|
if new_displayname == "": |
|
|
|
|
new_displayname = None |
|
|
|
|
displayname_to_set = None |
|
|
|
|
|
|
|
|
|
# If the admin changes the display name of a user, the requesting user cannot send |
|
|
|
|
# the join event to update the displayname in the rooms. |
|
|
|
@ -185,7 +199,9 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
if by_admin: |
|
|
|
|
requester = create_requester(target_user) |
|
|
|
|
|
|
|
|
|
await self.store.set_profile_displayname(target_user.localpart, new_displayname) |
|
|
|
|
await self.store.set_profile_displayname( |
|
|
|
|
target_user.localpart, displayname_to_set |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if self.hs.config.user_directory_search_all_users: |
|
|
|
|
profile = await self.store.get_profileinfo(target_user.localpart) |
|
|
|
@ -195,7 +211,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
|
|
|
|
|
await self._update_join_states(requester, target_user) |
|
|
|
|
|
|
|
|
|
async def get_avatar_url(self, target_user): |
|
|
|
|
async def get_avatar_url(self, target_user: UserID) -> str: |
|
|
|
|
if self.hs.is_mine(target_user): |
|
|
|
|
try: |
|
|
|
|
avatar_url = await self.store.get_profile_avatar_url( |
|
|
|
@ -222,15 +238,19 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
return result["avatar_url"] |
|
|
|
|
|
|
|
|
|
async def set_avatar_url( |
|
|
|
|
self, target_user, requester, new_avatar_url, by_admin=False |
|
|
|
|
self, |
|
|
|
|
target_user: UserID, |
|
|
|
|
requester: Requester, |
|
|
|
|
new_avatar_url: str, |
|
|
|
|
by_admin: bool = False, |
|
|
|
|
): |
|
|
|
|
"""Set a new avatar URL for a user. |
|
|
|
|
|
|
|
|
|
Args: |
|
|
|
|
target_user (UserID): the user whose avatar URL is to be changed. |
|
|
|
|
requester (Requester): The user attempting to make this change. |
|
|
|
|
new_avatar_url (str): The avatar URL to give this user. |
|
|
|
|
by_admin (bool): Whether this change was made by an administrator. |
|
|
|
|
target_user: the user whose avatar URL is to be changed. |
|
|
|
|
requester: The user attempting to make this change. |
|
|
|
|
new_avatar_url: The avatar URL to give this user. |
|
|
|
|
by_admin: Whether this change was made by an administrator. |
|
|
|
|
""" |
|
|
|
|
if not self.hs.is_mine(target_user): |
|
|
|
|
raise SynapseError(400, "User is not hosted on this homeserver") |
|
|
|
@ -267,7 +287,7 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
|
|
|
|
|
await self._update_join_states(requester, target_user) |
|
|
|
|
|
|
|
|
|
async def on_profile_query(self, args): |
|
|
|
|
async def on_profile_query(self, args: JsonDict) -> JsonDict: |
|
|
|
|
user = UserID.from_string(args["user_id"]) |
|
|
|
|
if not self.hs.is_mine(user): |
|
|
|
|
raise SynapseError(400, "User is not hosted on this homeserver") |
|
|
|
@ -292,7 +312,9 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
|
|
|
|
|
return response |
|
|
|
|
|
|
|
|
|
async def _update_join_states(self, requester, target_user): |
|
|
|
|
async def _update_join_states( |
|
|
|
|
self, requester: Requester, target_user: UserID |
|
|
|
|
) -> None: |
|
|
|
|
if not self.hs.is_mine(target_user): |
|
|
|
|
return |
|
|
|
|
|
|
|
|
@ -323,15 +345,17 @@ class ProfileHandler(BaseHandler): |
|
|
|
|
"Failed to update join event for room %s - %s", room_id, str(e) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
async def check_profile_query_allowed(self, target_user, requester=None): |
|
|
|
|
async def check_profile_query_allowed( |
|
|
|
|
self, target_user: UserID, requester: Optional[UserID] = None |
|
|
|
|
) -> None: |
|
|
|
|
"""Checks whether a profile query is allowed. If the |
|
|
|
|
'require_auth_for_profile_requests' config flag is set to True and a |
|
|
|
|
'requester' is provided, the query is only allowed if the two users |
|
|
|
|
share a room. |
|
|
|
|
|
|
|
|
|
Args: |
|
|
|
|
target_user (UserID): The owner of the queried profile. |
|
|
|
|
requester (None|UserID): The user querying for the profile. |
|
|
|
|
target_user: The owner of the queried profile. |
|
|
|
|
requester: The user querying for the profile. |
|
|
|
|
|
|
|
|
|
Raises: |
|
|
|
|
SynapseError(403): The two users share no room, or ne user couldn't |
|
|
|
|