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

Add type hints to groups code #9393

Merged
merged 11 commits into from
Feb 17, 2021
Merged
2 changes: 1 addition & 1 deletion changelog.d/9321.bugfix
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Assert a maximum length for the `client_secret` parameter for spec compliance.
Assert a maximum length for some parameters for spec compliance.
1 change: 1 addition & 0 deletions changelog.d/9393.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Assert a maximum length for some parameters for spec compliance.
1 change: 1 addition & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ files =
synapse/events/validator.py,
synapse/events/spamcheck.py,
synapse/federation,
synapse/groups,
synapse/handlers,
synapse/http/client.py,
synapse/http/federation/matrix_federation_agent.py,
Expand Down
5 changes: 5 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
# the maximum length for a user id is 255 characters
MAX_USERID_LENGTH = 255

# The maximum length for a group id is 255 characters
MAX_GROUPID_LENGTH = 255
MAX_GROUP_CATEGORYID_LENGTH = 255
MAX_GROUP_ROLEID_LENGTH = 255


class Membership:

Expand Down
41 changes: 39 additions & 2 deletions synapse/federation/transport/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from typing import Optional, Tuple, Type

import synapse
from synapse.api.constants import MAX_GROUP_CATEGORYID_LENGTH, MAX_GROUP_ROLEID_LENGTH
from synapse.api.errors import Codes, FederationDeniedError, SynapseError
from synapse.api.room_versions import RoomVersions
from synapse.api.urls import (
Expand Down Expand Up @@ -1118,7 +1119,17 @@ async def on_POST(self, origin, content, query, group_id, category_id, room_id):
raise SynapseError(403, "requester_user_id doesn't match origin")

if category_id == "":
raise SynapseError(400, "category_id cannot be empty string")
raise SynapseError(
400, "category_id cannot be empty string", Codes.INVALID_PARAM
)

if len(category_id) > MAX_GROUP_CATEGORYID_LENGTH:
raise SynapseError(
400,
"category_id may not be longer than %s characters"
% (MAX_GROUP_CATEGORYID_LENGTH,),
Codes.INVALID_PARAM,
)

resp = await self.handler.update_group_summary_room(
group_id,
Expand Down Expand Up @@ -1184,6 +1195,14 @@ async def on_POST(self, origin, content, query, group_id, category_id):
if category_id == "":
raise SynapseError(400, "category_id cannot be empty string")

if len(category_id) > MAX_GROUP_CATEGORYID_LENGTH:
raise SynapseError(
400,
"category_id may not be longer than %s characters"
% (MAX_GROUP_CATEGORYID_LENGTH,),
Codes.INVALID_PARAM,
)

resp = await self.handler.upsert_group_category(
group_id, requester_user_id, category_id, content
)
Expand Down Expand Up @@ -1240,7 +1259,17 @@ async def on_POST(self, origin, content, query, group_id, role_id):
raise SynapseError(403, "requester_user_id doesn't match origin")

if role_id == "":
raise SynapseError(400, "role_id cannot be empty string")
raise SynapseError(
400, "role_id cannot be empty string", Codes.INVALID_PARAM
)

if len(role_id) > MAX_GROUP_ROLEID_LENGTH:
raise SynapseError(
400,
"role_id may not be longer than %s characters"
% (MAX_GROUP_ROLEID_LENGTH,),
Codes.INVALID_PARAM,
)

resp = await self.handler.update_group_role(
group_id, requester_user_id, role_id, content
Expand Down Expand Up @@ -1285,6 +1314,14 @@ async def on_POST(self, origin, content, query, group_id, role_id, user_id):
if role_id == "":
raise SynapseError(400, "role_id cannot be empty string")

if len(role_id) > MAX_GROUP_ROLEID_LENGTH:
raise SynapseError(
400,
"role_id may not be longer than %s characters"
% (MAX_GROUP_ROLEID_LENGTH,),
Codes.INVALID_PARAM,
)

resp = await self.handler.update_group_summary_user(
group_id,
requester_user_id,
Expand Down
37 changes: 24 additions & 13 deletions synapse/groups/attestations.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@

import logging
import random
from typing import Tuple
from typing import TYPE_CHECKING, Optional, Tuple

from signedjson.sign import sign_json

from synapse.api.errors import HttpResponseException, RequestSendFailed, SynapseError
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.types import get_domain_from_id
from synapse.types import JsonDict, get_domain_from_id

if TYPE_CHECKING:
from synapse.app.homeserver import HomeServer

logger = logging.getLogger(__name__)

Expand All @@ -63,15 +66,19 @@
class GroupAttestationSigning:
"""Creates and verifies group attestations."""

def __init__(self, hs):
def __init__(self, hs: "HomeServer"):
self.keyring = hs.get_keyring()
self.clock = hs.get_clock()
self.server_name = hs.hostname
self.signing_key = hs.signing_key

async def verify_attestation(
self, attestation, group_id, user_id, server_name=None
):
self,
attestation: JsonDict,
group_id: str,
user_id: str,
server_name: Optional[str] = None,
) -> None:
"""Verifies that the given attestation matches the given parameters.

An optional server_name can be supplied to explicitly set which server's
Expand Down Expand Up @@ -100,16 +107,18 @@ async def verify_attestation(
if valid_until_ms < now:
raise SynapseError(400, "Attestation expired")

assert server_name is not None
await self.keyring.verify_json_for_server(
server_name, attestation, now, "Group attestation"
)

def create_attestation(self, group_id, user_id):
def create_attestation(self, group_id: str, user_id: str) -> JsonDict:
"""Create an attestation for the group_id and user_id with default
validity length.
"""
validity_period = DEFAULT_ATTESTATION_LENGTH_MS
validity_period *= random.uniform(*DEFAULT_ATTESTATION_JITTER)
validity_period = DEFAULT_ATTESTATION_LENGTH_MS * random.uniform(
*DEFAULT_ATTESTATION_JITTER
)
valid_until_ms = int(self.clock.time_msec() + validity_period)

return sign_json(
Expand All @@ -126,7 +135,7 @@ def create_attestation(self, group_id, user_id):
class GroupAttestionRenewer:
"""Responsible for sending and receiving attestation updates."""

def __init__(self, hs):
def __init__(self, hs: "HomeServer"):
self.clock = hs.get_clock()
self.store = hs.get_datastore()
self.assestations = hs.get_groups_attestation_signing()
Expand All @@ -139,7 +148,9 @@ def __init__(self, hs):
self._start_renew_attestations, 30 * 60 * 1000
)

async def on_renew_attestation(self, group_id, user_id, content):
async def on_renew_attestation(
self, group_id: str, user_id: str, content: JsonDict
) -> JsonDict:
"""When a remote updates an attestation"""
attestation = content["attestation"]

Expand All @@ -154,10 +165,10 @@ async def on_renew_attestation(self, group_id, user_id, content):

return {}

def _start_renew_attestations(self):
def _start_renew_attestations(self) -> None:
return run_as_background_process("renew_attestations", self._renew_attestations)

async def _renew_attestations(self):
async def _renew_attestations(self) -> None:
"""Called periodically to check if we need to update any of our attestations"""

now = self.clock.time_msec()
Expand All @@ -166,7 +177,7 @@ async def _renew_attestations(self):
now + UPDATE_ATTESTATION_TIME_MS
)

async def _renew_attestation(group_user: Tuple[str, str]):
async def _renew_attestation(group_user: Tuple[str, str]) -> None:
group_id, user_id = group_user
try:
if not self.is_mine_id(group_id):
Expand Down
Loading