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

Add admin API to remove a local user from a space #11358

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/11356.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `Final` annotation to string constants in `synapse.api.constants` so that they get typed as `Literal`s.
1 change: 1 addition & 0 deletions changelog.d/11358.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an admin API endpoint to force a local user to leave all non-public rooms in a space.
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
- [Registration Tokens](usage/administration/admin_api/registration_tokens.md)
- [Manipulate Room Membership](admin_api/room_membership.md)
- [Rooms](admin_api/rooms.md)
- [Spaces](usage/administration/admin_api/spaces.md)
- [Server Notices](admin_api/server_notices.md)
- [Statistics](admin_api/statistics.md)
- [Users](admin_api/user_admin_api.md)
Expand Down
46 changes: 46 additions & 0 deletions docs/usage/administration/admin_api/spaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Spaces API

This API allows a server administrator to manage spaces.

## Remove local user

This API forces a local user to leave all non-public rooms in a space.

The space itself is always left, regardless of whether it is public.

May succeed partially if the user fails to leave some rooms.

The API is:

```
DELETE /_synapse/admin/v1/rooms/<room_id>/hierarchy/members/<user_id>
```

Returning:

```json
{
"left": ["!room1:example.net", "!room2:example.net", ...],
"failed": {
"!room3:example.net": [
"Could not explore space or room fully."
],
"!room4:example.net": [
"Failed to leave room."
],
...
}
}
```

`left`: A list of rooms that the user has been made to leave.

`failed`: A dictionary with entries for rooms that could not be fully
processed. The values of the dictionary are lists of failure reasons.
Rooms may appear here if:
* The user failed to leave them for any reason.
* The room is a space that the local homeserver is not in, and so
its full list of child rooms could not be determined.
* The room is inaccessible to the local homeserver, and it is not
known whether the room is a subspace containing further rooms.
* Some combination of the above.
198 changes: 100 additions & 98 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

"""Contains constants from the specification."""

from typing_extensions import Final

# the max size of a (canonical-json-encoded) event
MAX_PDU_SIZE = 65536

Expand All @@ -39,217 +41,217 @@ class Membership:

"""Represents the membership states of a user in a room."""

INVITE = "invite"
JOIN = "join"
KNOCK = "knock"
LEAVE = "leave"
BAN = "ban"
LIST = (INVITE, JOIN, KNOCK, LEAVE, BAN)
INVITE: Final = "invite"
JOIN: Final = "join"
KNOCK: Final = "knock"
LEAVE: Final = "leave"
BAN: Final = "ban"
LIST: Final = (INVITE, JOIN, KNOCK, LEAVE, BAN)


class PresenceState:
"""Represents the presence state of a user."""

OFFLINE = "offline"
UNAVAILABLE = "unavailable"
ONLINE = "online"
BUSY = "org.matrix.msc3026.busy"
OFFLINE: Final = "offline"
UNAVAILABLE: Final = "unavailable"
ONLINE: Final = "online"
BUSY: Final = "org.matrix.msc3026.busy"


class JoinRules:
PUBLIC = "public"
KNOCK = "knock"
INVITE = "invite"
PRIVATE = "private"
PUBLIC: Final = "public"
KNOCK: Final = "knock"
INVITE: Final = "invite"
PRIVATE: Final = "private"
# As defined for MSC3083.
RESTRICTED = "restricted"
RESTRICTED: Final = "restricted"


class RestrictedJoinRuleTypes:
"""Understood types for the allow rules in restricted join rules."""

ROOM_MEMBERSHIP = "m.room_membership"
ROOM_MEMBERSHIP: Final = "m.room_membership"


class LoginType:
PASSWORD = "m.login.password"
EMAIL_IDENTITY = "m.login.email.identity"
MSISDN = "m.login.msisdn"
RECAPTCHA = "m.login.recaptcha"
TERMS = "m.login.terms"
SSO = "m.login.sso"
DUMMY = "m.login.dummy"
REGISTRATION_TOKEN = "org.matrix.msc3231.login.registration_token"
PASSWORD: Final = "m.login.password"
EMAIL_IDENTITY: Final = "m.login.email.identity"
MSISDN: Final = "m.login.msisdn"
RECAPTCHA: Final = "m.login.recaptcha"
TERMS: Final = "m.login.terms"
SSO: Final = "m.login.sso"
DUMMY: Final = "m.login.dummy"
REGISTRATION_TOKEN: Final = "org.matrix.msc3231.login.registration_token"


# This is used in the `type` parameter for /register when called by
# an appservice to register a new user.
APP_SERVICE_REGISTRATION_TYPE = "m.login.application_service"
APP_SERVICE_REGISTRATION_TYPE: Final = "m.login.application_service"


class EventTypes:
Member = "m.room.member"
Create = "m.room.create"
Tombstone = "m.room.tombstone"
JoinRules = "m.room.join_rules"
PowerLevels = "m.room.power_levels"
Aliases = "m.room.aliases"
Redaction = "m.room.redaction"
ThirdPartyInvite = "m.room.third_party_invite"
RelatedGroups = "m.room.related_groups"

RoomHistoryVisibility = "m.room.history_visibility"
CanonicalAlias = "m.room.canonical_alias"
Encrypted = "m.room.encrypted"
RoomAvatar = "m.room.avatar"
RoomEncryption = "m.room.encryption"
GuestAccess = "m.room.guest_access"
Member: Final = "m.room.member"
Create: Final = "m.room.create"
Tombstone: Final = "m.room.tombstone"
JoinRules: Final = "m.room.join_rules"
PowerLevels: Final = "m.room.power_levels"
Aliases: Final = "m.room.aliases"
Redaction: Final = "m.room.redaction"
ThirdPartyInvite: Final = "m.room.third_party_invite"
RelatedGroups: Final = "m.room.related_groups"

RoomHistoryVisibility: Final = "m.room.history_visibility"
CanonicalAlias: Final = "m.room.canonical_alias"
Encrypted: Final = "m.room.encrypted"
RoomAvatar: Final = "m.room.avatar"
RoomEncryption: Final = "m.room.encryption"
GuestAccess: Final = "m.room.guest_access"

# These are used for validation
Message = "m.room.message"
Topic = "m.room.topic"
Name = "m.room.name"
Message: Final = "m.room.message"
Topic: Final = "m.room.topic"
Name: Final = "m.room.name"

ServerACL = "m.room.server_acl"
Pinned = "m.room.pinned_events"
ServerACL: Final = "m.room.server_acl"
Pinned: Final = "m.room.pinned_events"

Retention = "m.room.retention"
Retention: Final = "m.room.retention"

Dummy = "org.matrix.dummy_event"
Dummy: Final = "org.matrix.dummy_event"

SpaceChild = "m.space.child"
SpaceParent = "m.space.parent"
SpaceChild: Final = "m.space.child"
SpaceParent: Final = "m.space.parent"

MSC2716_INSERTION = "org.matrix.msc2716.insertion"
MSC2716_BATCH = "org.matrix.msc2716.batch"
MSC2716_MARKER = "org.matrix.msc2716.marker"
MSC2716_INSERTION: Final = "org.matrix.msc2716.insertion"
MSC2716_BATCH: Final = "org.matrix.msc2716.batch"
MSC2716_MARKER: Final = "org.matrix.msc2716.marker"


class ToDeviceEventTypes:
RoomKeyRequest = "m.room_key_request"
RoomKeyRequest: Final = "m.room_key_request"


class DeviceKeyAlgorithms:
"""Spec'd algorithms for the generation of per-device keys"""

ED25519 = "ed25519"
CURVE25519 = "curve25519"
SIGNED_CURVE25519 = "signed_curve25519"
ED25519: Final = "ed25519"
CURVE25519: Final = "curve25519"
SIGNED_CURVE25519: Final = "signed_curve25519"


class EduTypes:
Presence = "m.presence"
Presence: Final = "m.presence"


class RejectedReason:
AUTH_ERROR = "auth_error"
AUTH_ERROR: Final = "auth_error"


class RoomCreationPreset:
PRIVATE_CHAT = "private_chat"
PUBLIC_CHAT = "public_chat"
TRUSTED_PRIVATE_CHAT = "trusted_private_chat"
PRIVATE_CHAT: Final = "private_chat"
PUBLIC_CHAT: Final = "public_chat"
TRUSTED_PRIVATE_CHAT: Final = "trusted_private_chat"


class ThirdPartyEntityKind:
USER = "user"
LOCATION = "location"
USER: Final = "user"
LOCATION: Final = "location"


ServerNoticeMsgType = "m.server_notice"
ServerNoticeLimitReached = "m.server_notice.usage_limit_reached"
ServerNoticeMsgType: Final = "m.server_notice"
ServerNoticeLimitReached: Final = "m.server_notice.usage_limit_reached"


class UserTypes:
"""Allows for user type specific behaviour. With the benefit of hindsight
'admin' and 'guest' users should also be UserTypes. Normal users are type None
"""

SUPPORT = "support"
BOT = "bot"
ALL_USER_TYPES = (SUPPORT, BOT)
SUPPORT: Final = "support"
BOT: Final = "bot"
ALL_USER_TYPES: Final = (SUPPORT, BOT)


class RelationTypes:
"""The types of relations known to this server."""

ANNOTATION = "m.annotation"
REPLACE = "m.replace"
REFERENCE = "m.reference"
THREAD = "io.element.thread"
ANNOTATION: Final = "m.annotation"
REPLACE: Final = "m.replace"
REFERENCE: Final = "m.reference"
THREAD: Final = "io.element.thread"


class LimitBlockingTypes:
"""Reasons that a server may be blocked"""

MONTHLY_ACTIVE_USER = "monthly_active_user"
HS_DISABLED = "hs_disabled"
MONTHLY_ACTIVE_USER: Final = "monthly_active_user"
HS_DISABLED: Final = "hs_disabled"


class EventContentFields:
"""Fields found in events' content, regardless of type."""

# Labels for the event, cf https://github.com/matrix-org/matrix-doc/pull/2326
LABELS = "org.matrix.labels"
LABELS: Final = "org.matrix.labels"

# Timestamp to delete the event after
# cf https://github.com/matrix-org/matrix-doc/pull/2228
SELF_DESTRUCT_AFTER = "org.matrix.self_destruct_after"
SELF_DESTRUCT_AFTER: Final = "org.matrix.self_destruct_after"

# cf https://github.com/matrix-org/matrix-doc/pull/1772
ROOM_TYPE = "type"
ROOM_TYPE: Final = "type"

# Whether a room can federate.
FEDERATE = "m.federate"
FEDERATE: Final = "m.federate"

# The creator of the room, as used in `m.room.create` events.
ROOM_CREATOR = "creator"
ROOM_CREATOR: Final = "creator"

# Used in m.room.guest_access events.
GUEST_ACCESS = "guest_access"
GUEST_ACCESS: Final = "guest_access"

# Used on normal messages to indicate they were historically imported after the fact
MSC2716_HISTORICAL = "org.matrix.msc2716.historical"
MSC2716_HISTORICAL: Final = "org.matrix.msc2716.historical"
# For "insertion" events to indicate what the next batch ID should be in
# order to connect to it
MSC2716_NEXT_BATCH_ID = "org.matrix.msc2716.next_batch_id"
MSC2716_NEXT_BATCH_ID: Final = "org.matrix.msc2716.next_batch_id"
# Used on "batch" events to indicate which insertion event it connects to
MSC2716_BATCH_ID = "org.matrix.msc2716.batch_id"
MSC2716_BATCH_ID: Final = "org.matrix.msc2716.batch_id"
# For "marker" events
MSC2716_MARKER_INSERTION = "org.matrix.msc2716.marker.insertion"
MSC2716_MARKER_INSERTION: Final = "org.matrix.msc2716.marker.insertion"

# The authorising user for joining a restricted room.
AUTHORISING_USER = "join_authorised_via_users_server"
AUTHORISING_USER: Final = "join_authorised_via_users_server"


class RoomTypes:
"""Understood values of the room_type field of m.room.create events."""

SPACE = "m.space"
SPACE: Final = "m.space"


class RoomEncryptionAlgorithms:
MEGOLM_V1_AES_SHA2 = "m.megolm.v1.aes-sha2"
DEFAULT = MEGOLM_V1_AES_SHA2
MEGOLM_V1_AES_SHA2: Final = "m.megolm.v1.aes-sha2"
DEFAULT: Final = MEGOLM_V1_AES_SHA2


class AccountDataTypes:
DIRECT = "m.direct"
IGNORED_USER_LIST = "m.ignored_user_list"
DIRECT: Final = "m.direct"
IGNORED_USER_LIST: Final = "m.ignored_user_list"


class HistoryVisibility:
INVITED = "invited"
JOINED = "joined"
SHARED = "shared"
WORLD_READABLE = "world_readable"
INVITED: Final = "invited"
JOINED: Final = "joined"
SHARED: Final = "shared"
WORLD_READABLE: Final = "world_readable"


class GuestAccess:
CAN_JOIN = "can_join"
CAN_JOIN: Final = "can_join"
# anything that is not "can_join" is considered "forbidden", but for completeness:
FORBIDDEN = "forbidden"
FORBIDDEN: Final = "forbidden"


class ReadReceiptEventFields:
MSC2285_HIDDEN = "org.matrix.msc2285.hidden"
MSC2285_HIDDEN: Final = "org.matrix.msc2285.hidden"
Loading