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

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into clokep/bundle-redu…
Browse files Browse the repository at this point in the history
…ce-queries
  • Loading branch information
clokep committed Jan 26, 2022
2 parents 8400c20 + 2897fb6 commit e2f905b
Show file tree
Hide file tree
Showing 35 changed files with 792 additions and 208 deletions.
28 changes: 18 additions & 10 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -323,17 +323,22 @@ jobs:
if: ${{ !failure() && !cancelled() }}
needs: linting-done
runs-on: ubuntu-latest
container:
# https://github.com/matrix-org/complement/blob/master/dockerfiles/ComplementCIBuildkite.Dockerfile
image: matrixdotorg/complement:latest
env:
CI: true
ports:
- 8448:8448
volumes:
- /var/run/docker.sock:/var/run/docker.sock

steps:
# The path is set via a file given by $GITHUB_PATH. We need both Go 1.17 and GOPATH on the path to run Complement.
# See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
- name: "Set Go Version"
run: |
# Add Go 1.17 to the PATH: see https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#environment-variables-2
echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH
# Add the Go path to the PATH: We need this so we can call gotestfmt
echo "~/go/bin" >> $GITHUB_PATH
- name: "Install Complement Dependencies"
run: |
sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev
go get -v github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest
- name: Run actions/checkout@v2 for synapse
uses: actions/checkout@v2
with:
Expand Down Expand Up @@ -376,8 +381,11 @@ jobs:
working-directory: complement/dockerfiles

# Run Complement
- run: set -o pipefail && go test -v -json -tags synapse_blacklist,msc2403 ./tests/... 2>&1 | gotestfmt
- run: |
set -o pipefail
go test -v -json -tags synapse_blacklist,msc2403 ./tests/... 2>&1 | gotestfmt
shell: bash
name: Run Complement Tests
env:
COMPLEMENT_BASE_IMAGE: complement-synapse:latest
working-directory: complement
Expand Down
1 change: 1 addition & 0 deletions changelog.d/11658.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an admin API to get a list of rooms that federate with a given remote homeserver.
1 change: 1 addition & 0 deletions changelog.d/11743.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a config flag to inhibit M_USER_IN_USE during registration.
1 change: 1 addition & 0 deletions changelog.d/11811.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Run Complement on the Github Actions VM and not inside a Docker container.
1 change: 1 addition & 0 deletions changelog.d/11815.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve type safety of bundled aggregations code.
1 change: 1 addition & 0 deletions changelog.d/11816.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Drop support for Python 3.6, which is EOL.
2 changes: 1 addition & 1 deletion changelog.d/11817.misc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Compatibility with updated type hints for jsonschema 4.4.0.
Correct a type annotation in the event validation logic.
1 change: 1 addition & 0 deletions changelog.d/11827.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a bug introduced in Synapse 0.33.3 causing requests to sometimes log strings such as `HTTPStatus.OK` instead of integer status codes.
1 change: 1 addition & 0 deletions changelog.d/11830.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correct a type annotation in the event validation logic.
1 change: 1 addition & 0 deletions changelog.d/11834.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Workaround a type annotation problem in `prometheus_client` 0.13.0.
10 changes: 10 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,16 @@ account_threepid_delegates:
#
#auto_join_rooms_for_guests: false

# Whether to inhibit errors raised when registering a new account if the user ID
# already exists. If turned on, that requests to /register/available will always
# show a user ID as available, and Synapse won't raise an error when starting
# a registration with a user ID that already exists. However, Synapse will still
# raise an error if the registration completes and the username conflicts.
#
# Defaults to false.
#
#inhibit_user_in_use_error: true


## Metrics ###

Expand Down
60 changes: 60 additions & 0 deletions docs/usage/administration/admin_api/federation.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,66 @@ The following parameters should be set in the URL:
The response fields are the same like in the `destinations` array in
[List of destinations](#list-of-destinations) response.

## Destination rooms

This API gets the rooms that federate with a specific remote server.

The API is:

```
GET /_synapse/admin/v1/federation/destinations/<destination>/rooms
```

A response body like the following is returned:

```json
{
"rooms":[
{
"room_id": "!OGEhHVWSdvArJzumhm:matrix.org",
"stream_ordering": 8326
},
{
"room_id": "!xYvNcQPhnkrdUmYczI:matrix.org",
"stream_ordering": 93534
}
],
"total": 2
}
```

To paginate, check for `next_token` and if present, call the endpoint again
with `from` set to the value of `next_token`. This will return a new page.

If the endpoint does not return a `next_token` then there are no more destinations
to paginate through.

**Parameters**

The following parameters should be set in the URL:

- `destination` - Name of the remote server.

The following query parameters are available:

- `from` - Offset in the returned list. Defaults to `0`.
- `limit` - Maximum amount of destinations to return. Defaults to `100`.
- `dir` - Direction of room order by `room_id`. Either `f` for forwards or `b` for
backwards. Defaults to `f`.

**Response**

The following fields are returned in the JSON response body:

- `rooms` - An array of objects, each containing information about a room.
Room objects contain the following fields:
- `room_id` - string - The ID of the room.
- `stream_ordering` - integer - The stream ordering of the most recent
successfully-sent [PDU](understanding_synapse_through_grafana_graphs.md#federation)
to this destination in this room.
- `next_token`: string representing a positive integer - Indication for pagination. See above.
- `total` - integer - Total number of destinations.

## Reset connection timeout

Synapse makes federation requests to other homeservers. If a federation request fails,
Expand Down
14 changes: 8 additions & 6 deletions synapse/app/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,14 @@ def run_sighup(*args: Any, **kwargs: Any) -> None:
# everything currently allocated are things that will be used for the
# rest of time. Doing so means less work each GC (hopefully).
#
gc.collect()
gc.freeze()

# Speed up shutdowns by freezing all allocated objects. This moves everything
# into the permanent generation and excludes them from the final GC.
atexit.register(gc.freeze)
# PyPy does not (yet?) implement gc.freeze()
if hasattr(gc, "freeze"):
gc.collect()
gc.freeze()

# Speed up shutdowns by freezing all allocated objects. This moves everything
# into the permanent generation and excludes them from the final GC.
atexit.register(gc.freeze)


def setup_sentry(hs: "HomeServer") -> None:
Expand Down
12 changes: 12 additions & 0 deletions synapse/config/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ def read_config(self, config, **kwargs):
# The success template used during fallback auth.
self.fallback_success_template = self.read_template("auth_success.html")

self.inhibit_user_in_use_error = config.get("inhibit_user_in_use_error", False)

def generate_config_section(self, generate_secrets=False, **kwargs):
if generate_secrets:
registration_shared_secret = 'registration_shared_secret: "%s"' % (
Expand Down Expand Up @@ -446,6 +448,16 @@ def generate_config_section(self, generate_secrets=False, **kwargs):
# Defaults to true.
#
#auto_join_rooms_for_guests: false
# Whether to inhibit errors raised when registering a new account if the user ID
# already exists. If turned on, that requests to /register/available will always
# show a user ID as available, and Synapse won't raise an error when starting
# a registration with a user ID that already exists. However, Synapse will still
# raise an error if the registration completes and the username conflicts.
#
# Defaults to false.
#
#inhibit_user_in_use_error: true
"""
% locals()
)
Expand Down
57 changes: 40 additions & 17 deletions synapse/events/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@
# limitations under the License.
import collections.abc
import re
from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Union
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
Iterable,
List,
Mapping,
Optional,
Union,
)

from frozendict import frozendict

Expand All @@ -26,6 +36,10 @@

from . import EventBase

if TYPE_CHECKING:
from synapse.storage.databases.main.relations import BundledAggregations


# Split strings on "." but not "\." This uses a negative lookbehind assertion for '\'
# (?<!stuff) matches if the current position in the string is not preceded
# by a match for 'stuff'.
Expand Down Expand Up @@ -376,7 +390,7 @@ def serialize_event(
event: Union[JsonDict, EventBase],
time_now: int,
*,
bundle_aggregations: Optional[Dict[str, JsonDict]] = None,
bundle_aggregations: Optional[Dict[str, "BundledAggregations"]] = None,
**kwargs: Any,
) -> JsonDict:
"""Serializes a single event.
Expand Down Expand Up @@ -415,7 +429,7 @@ def _inject_bundled_aggregations(
self,
event: EventBase,
time_now: int,
aggregations: JsonDict,
aggregations: "BundledAggregations",
serialized_event: JsonDict,
) -> None:
"""Potentially injects bundled aggregations into the unsigned portion of the serialized event.
Expand All @@ -427,13 +441,18 @@ def _inject_bundled_aggregations(
serialized_event: The serialized event which may be modified.
"""
# Make a copy in-case the object is cached.
aggregations = aggregations.copy()
serialized_aggregations = {}

if aggregations.annotations:
serialized_aggregations[RelationTypes.ANNOTATION] = aggregations.annotations

if aggregations.references:
serialized_aggregations[RelationTypes.REFERENCE] = aggregations.references

if RelationTypes.REPLACE in aggregations:
if aggregations.replace:
# If there is an edit replace the content, preserving existing
# relations.
edit = aggregations[RelationTypes.REPLACE]
edit = aggregations.replace

# Ensure we take copies of the edit content, otherwise we risk modifying
# the original event.
Expand All @@ -451,24 +470,28 @@ def _inject_bundled_aggregations(
else:
serialized_event["content"].pop("m.relates_to", None)

aggregations[RelationTypes.REPLACE] = {
serialized_aggregations[RelationTypes.REPLACE] = {
"event_id": edit.event_id,
"origin_server_ts": edit.origin_server_ts,
"sender": edit.sender,
}

# If this event is the start of a thread, include a summary of the replies.
if RelationTypes.THREAD in aggregations:
# Serialize the latest thread event.
latest_thread_event = aggregations[RelationTypes.THREAD]["latest_event"]

# Don't bundle aggregations as this could recurse forever.
aggregations[RelationTypes.THREAD]["latest_event"] = self.serialize_event(
latest_thread_event, time_now, bundle_aggregations=None
)
if aggregations.thread:
serialized_aggregations[RelationTypes.THREAD] = {
# Don't bundle aggregations as this could recurse forever.
"latest_event": self.serialize_event(
aggregations.thread.latest_event, time_now, bundle_aggregations=None
),
"count": aggregations.thread.count,
"current_user_participated": aggregations.thread.current_user_participated,
}

# Include the bundled aggregations in the event.
serialized_event["unsigned"].setdefault("m.relations", {}).update(aggregations)
if serialized_aggregations:
serialized_event["unsigned"].setdefault("m.relations", {}).update(
serialized_aggregations
)

def serialize_events(
self, events: Iterable[Union[JsonDict, EventBase]], time_now: int, **kwargs: Any
Expand Down
6 changes: 2 additions & 4 deletions synapse/events/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import collections.abc
from typing import Iterable, Union
from typing import Iterable, Type, Union

import jsonschema

Expand Down Expand Up @@ -246,9 +246,7 @@ def _ensure_state_event(self, event: Union[EventBase, EventBuilder]) -> None:

# This could return something newer than Draft 7, but that's the current "latest"
# validator.
#
# See https://github.com/python/typeshed/issues/7028 for the ignored return type.
def _create_power_level_validator() -> jsonschema.Draft7Validator: # type: ignore[valid-type]
def _create_power_level_validator() -> Type[jsonschema.Draft7Validator]:
validator = jsonschema.validators.validator_for(POWER_LEVELS_SCHEMA)

# by default jsonschema does not consider a frozendict to be an object so
Expand Down
26 changes: 14 additions & 12 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ async def check_username(
localpart: str,
guest_access_token: Optional[str] = None,
assigned_user_id: Optional[str] = None,
inhibit_user_in_use_error: bool = False,
) -> None:
if types.contains_invalid_mxid_characters(localpart):
raise SynapseError(
Expand Down Expand Up @@ -171,21 +172,22 @@ async def check_username(

users = await self.store.get_users_by_id_case_insensitive(user_id)
if users:
if not guest_access_token:
if not inhibit_user_in_use_error and not guest_access_token:
raise SynapseError(
400, "User ID already taken.", errcode=Codes.USER_IN_USE
)
user_data = await self.auth.get_user_by_access_token(guest_access_token)
if (
not user_data.is_guest
or UserID.from_string(user_data.user_id).localpart != localpart
):
raise AuthError(
403,
"Cannot register taken user ID without valid guest "
"credentials for that user.",
errcode=Codes.FORBIDDEN,
)
if guest_access_token:
user_data = await self.auth.get_user_by_access_token(guest_access_token)
if (
not user_data.is_guest
or UserID.from_string(user_data.user_id).localpart != localpart
):
raise AuthError(
403,
"Cannot register taken user ID without valid guest "
"credentials for that user.",
errcode=Codes.FORBIDDEN,
)

if guest_access_token is None:
try:
Expand Down
Loading

0 comments on commit e2f905b

Please sign in to comment.