From 3c9ba4a06d86e62f5664bdab45dccce1bab59495 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 18 Mar 2026 09:51:49 -0600 Subject: [PATCH] Specify Policy Servers (MSC4284) (#2332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Specify Policy Servers (MSC4284) * changelogs * Fix placement of `required` * Fix broken links * Apply suggestions from code review Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com> Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> * Clarify "incomplete" * Mark ed25519 keys as required * Add cross references throughout the spec --------- Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com> Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- .../client_server/newsfragments/2332.feature | 1 + .../server_server/newsfragments/2332.feature | 1 + content/client-server-api/_index.md | 6 +- .../modules/policy_servers.md | 98 ++++++++++ content/server-server-api.md | 185 ++++++++++++++++++ data/api/client-server/policy_server.yaml | 82 ++++++++ data/api/server-server/room_policy.yaml | 172 ++++++++++++++++ .../event-schemas/examples/m.room.policy.yaml | 11 ++ data/event-schemas/schema/m.room.policy.yaml | 41 ++++ 9 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 changelogs/client_server/newsfragments/2332.feature create mode 100644 changelogs/server_server/newsfragments/2332.feature create mode 100644 content/client-server-api/modules/policy_servers.md create mode 100644 data/api/client-server/policy_server.yaml create mode 100644 data/api/server-server/room_policy.yaml create mode 100644 data/event-schemas/examples/m.room.policy.yaml create mode 100644 data/event-schemas/schema/m.room.policy.yaml diff --git a/changelogs/client_server/newsfragments/2332.feature b/changelogs/client_server/newsfragments/2332.feature new file mode 100644 index 00000000..86f270ec --- /dev/null +++ b/changelogs/client_server/newsfragments/2332.feature @@ -0,0 +1 @@ +Add a "Policy Servers" module, as per [MSC4284](https://github.com/matrix-org/matrix-spec-proposals/pull/4284). \ No newline at end of file diff --git a/changelogs/server_server/newsfragments/2332.feature b/changelogs/server_server/newsfragments/2332.feature new file mode 100644 index 00000000..c0631d36 --- /dev/null +++ b/changelogs/server_server/newsfragments/2332.feature @@ -0,0 +1 @@ +Add a concept of "Policy Servers", as per [MSC4284](https://github.com/matrix-org/matrix-spec-proposals/pull/4284). \ No newline at end of file diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 2c70c580..410a1f25 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -469,6 +469,8 @@ The flow for auto-discovery is as follows: {{% http-api spec="client-server" api="support" %}} +{{% http-api spec="client-server" api="policy_server" %}} + ### API Versions Upon connecting, the Matrix client and server need to negotiate which version of the specification @@ -1685,7 +1687,7 @@ For a client to be considered fully OAuth 2.0 aware it MUST: then the client MUST redirect users to manage their account at the [account management URL](#oauth-20-account-management), if available, instead of providing a native UI using the legacy API endpoints. - + * If the user wishes to deactivate their account then the client MUST refer them to the account management URL. * If the user wishes to sign out a device other than its own then the client @@ -4275,6 +4277,7 @@ that profile. | [Read and Unread Markers](#read-and-unread-markers) | Optional | Optional | Optional | Optional | Optional | | [Guest Access](#guest-access) | Optional | Optional | Optional | Optional | Optional | | [Moderation Policy Lists](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional | +| [Policy Servers](#policy-servers) | Optional | Optional | Optional | Optional | Optional | | [OpenID](#openid) | Optional | Optional | Optional | Optional | Optional | | [Recently used emoji](#recently-used-emoji) | Optional | Optional | Optional | Optional | Optional | | [Reference Relations](#reference-relations) | Optional | Optional | Optional | Optional | Optional | @@ -4377,6 +4380,7 @@ systems. {{% cs-module name="Room Upgrades" filename="room_upgrades" %}} {{% cs-module name="Server Notices" filename="server_notices" %}} {{% cs-module name="Moderation policy lists" filename="moderation_policies" %}} +{{% cs-module name="Policy Servers" filename="policy_servers" %}} {{% cs-module name="Spaces" filename="spaces" %}} {{% cs-module name="Event replacements" filename="event_replacements" %}} {{% cs-module name="Event annotations and reactions" filename="event_annotations" %}} diff --git a/content/client-server-api/modules/policy_servers.md b/content/client-server-api/modules/policy_servers.md new file mode 100644 index 00000000..d35faa02 --- /dev/null +++ b/content/client-server-api/modules/policy_servers.md @@ -0,0 +1,98 @@ +### Policy Servers + +{{% added-in v="1.18" %}} + +A Policy Server is a homeserver in the room designated to proactively check events +before they are sent to the room/users. Rooms are not required to use a Policy +Server (PS). Rooms which do use a Policy Server can prevent unwanted events from +reaching users. + +{{% boxes/note %}} +Room operators might prefer to use a "moderation bot" instead of a Policy Server. +Moderation bots are reactive because they typically [redact](#redactions) events +after they've already been sent. + +Room operators might also prefer to layer a moderation bot with a Policy Server +for added protection. +{{% /boxes/note %}} + +A room's Policy Server is designated by the [`m.room.policy`](#mroompolicy) state +event described below. If the state event is not set in the room or is missing +required fields, the room does *not* use a Policy Server. Similarly, if the server name in the state +event has zero joined users in the room, the room also does *not* use a Policy +Server. + +When the room is using a Policy Server, *all* events except for the `m.room.policy` +state event itself are checked by that Policy Server. This includes membership +events, power level changes, events from before the Policy Server was enabled, +and non-state or non-empty `state_key` `m.room.policy` events. + +What a Policy Server checks for on an event is left as an implementation detail. + +{{% boxes/note %}} +More information about how a Policy Server operates precisely is available in +the [Server-Server API](/server-server-api/#policy-servers). Most notably, not +every homeserver is a Policy Server, and not every Policy Server is a full +homeserver. +{{% /boxes/note %}} + +{{% event event="m.room.policy" %}} + +#### Client behaviour + +Clients do not interact with the Policy Server directly, but may need enough +information to be able to set the `m.room.policy` state event. For this, a client +can attempt to call [`/.well-known/matrix/policy_server`](#getwell-knownmatrixpolicy_server) +on a user-provided server name. The returned information can then be used to +populate the `m.room.policy` state event. + +{{% boxes/note %}} +Clients are *not* required to use `/.well-known/matrix/policy_server` to populate the +`m.room.policy` state event. If they have the required information from elsewhere, +they can simply send the state event. +{{% /boxes/note %}} + +#### Server behaviour + +See the [Policy Servers section of the Server-Server API](/server-server-api/#policy-servers). + +{{% boxes/note %}} +If implementing your own Policy Server, see [MSC4284: Policy Servers](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/4284-policy-servers.md) +for additional security, implementation, and safety considerations. +{{% /boxes/note %}} + +#### Security considerations + +{{% boxes/note %}} +Portions of this section rely on context from the [Policy Servers section of the Server-Server API](/server-server-api/#policy-servers). +{{% /boxes/note %}} + +By nature of being a proactive tool for a room, Policy Server can expect to be +Denial of Service (DoS) targets. Policy Servers MUST be tolerant to DoS attacks. +The scale of attack they need to tolerate is left as an implementation/deployment +detail. A Policy Server dedicated to a small community might not have the same +requirements as a Policy Server available for many communities to use. + +To help ensure that rooms can be used when their chosen Policy Server is inaccessible, +the `m.room.policy` state event can be set *without* consulting the Policy Server. +This in effect allows users with appropriate power levels to wipe the content of +`m.room.policy`, disabling the Policy Server immediately. + +Policy Servers MUST have a joined user in the room to prevent rooms overloading +or forcing a given server to act as a Policy Server. The Policy Server can evict +itself from the room to also disable usage immediately. + +Events sent "before" the Policy Server was enabled can end up being recommended +for exclusion by the Policy Server. This is expected behaviour to ensure new policies +apply to events which took a while to send. + +Homeservers might not ask a Policy Server for a signature on an event before sending +it to the room. Other compliant homeservers will request that signature instead, +and layered tooling (like "moderation bots") can help remove events which bypass +the room's Policy Server, if desirable. + +Homeservers might request and receive a valid signature for an event, but delay +or never send the event. "Moderation bots" can monitor for clock drift on signed +events, if desirable. A Policy Server implementation might also monitor for clock +drift, though does need to consider that events can be backdated in ways beyond +`origin_server_ts`. diff --git a/content/server-server-api.md b/content/server-server-api.md index 50104ed5..8bc0d28b 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -473,6 +473,9 @@ server must ensure that the event: otherwise it is rejected. 6. Passes authorization rules based on the current state of the room, otherwise it is "soft failed". +7. {{% added-in v="1.18" %}} Is [validated](#validating-policy-server-signatures) + by the Policy Server, if the room is [using a Policy Server](#determining-if-a-policy-server-is-enabled-in-a-room), + otherwise it is "soft failed". Further details of these checks, and how to handle failures, are described below. @@ -689,6 +692,11 @@ then any new event `D'` will not reference `C`: | D' +{{% boxes/note %}} +{{% added-in v="1.18" %}} +Events can also be soft failed if they fail [Policy Server checks](#validating-policy-server-signatures). +{{% /boxes/note %}} + #### Retrieving event authorization information The homeserver may be missing event authorization information, or wish @@ -1277,6 +1285,171 @@ endpoint MUST be protected as follows: room ID MUST be ignored if the sending server is denied access to the room identified by that ID. +The following endpoints MAY be protected: + +- [`/_matrix/policy/v1/sign`](#post_matrixpolicyv1sign) - {{< added-in v="1.18" >}} + Protected if the server is tracking the DAG and chooses to enforce the ACL. + + +## Policy Servers + +{{% added-in v="1.18" %}} + +Policy Servers are an available tool for rooms to add proactive protections. Rooms +which use a Policy Server (PS) can prevent unwanted events from reaching users. Rooms +are not required to use a Policy Server, and can disable it any time after enabling +it. + +For a homeserver to be a Policy Server, it MUST implement the following functionality +of the Server-Server API: + +* [Normal server name resolution](#resolving-server-names). +* [Publishing a signing key](#publishing-keys). +* [Request authentication](#authentication). +* Being able to [make and send join requests](#joining-rooms). +* Receiving and processing [`POST /_matrix/policy/v1/sign`](#post_matrixpolicyv1sign) + requests. + +All other functionality and endpoints are optional for a Policy Server. + +{{% boxes/note %}} +Though a Policy Server is not required to implement the full Server-Server API +surface, some functionality may be desirable to implement anyway: + +* Receiving [invites](#inviting-to-a-room) can make it easier to add the Policy + Server to a room. +* Receiving [transactions](#transactions) is recommended to avoid remote servers + flagging the Policy Server as "offline", even if the contents are discarded. +* Receiving [device lookups](#get_matrixfederationv1userdevicesuserid) can also + help reduce remote servers flagging the Policy Server as "offline". +{{% /boxes/note %}} + +{{% boxes/note %}} +Policy Servers are *not* required to track the DAG for a room. Policy Servers +might be optimized for content moderation and therefore do not need knowledge of +the DAG. +{{% /boxes/note %}} + +### Determining if a Policy Server is enabled in a room + +For a room to be considered as "using" a Policy Server, *all* of the following +conditions MUST be true: + +* The *current state* for the room has a valid [`m.room.policy`](/client-server-api/#mroompolicy) + state event with empty state key. Valid means `content` contains at least: + * A string value for `via`. + * An object value for `public_keys` containing at least a string value for + `ed25519`. +* The server name denoted by the `m.room.policy` state event's `via` has at least + one joined user in the room in *current state*. The user does not need any + special permissions or power levels in the room. + +If a room has enabled a Policy Server, *all* servers in that room MUST [ask that +Policy Server](#asking-for-a-policy-server-signature-on-an-event) for a signature +before sending an event. If the Policy Server refuses to sign the event being +sent, servers SHOULD fail to send that event as per the [validation rules](#validating-policy-server-signatures). + +{{% boxes/note %}} +"Current state" shares the same definition as [soft failure](#soft-failure). +{{% /boxes/note %}} + +{{% boxes/note %}} +Policy Servers MUST have at least one joined user in the room to give the Policy +Server agency in whether it serves that role for the room. Otherwise, a room +would be able to force a Policy Server to participate and then overwhelm it. +{{% /boxes/note %}} + +### Validating Policy Server signatures + +Policy Servers use signatures to indicate whether an event was checked and is +recommended for inclusion in a room. The Policy Server's recommendation does *not* +affect the authorization rules for an event, but does affect whether homeservers +[soft fail](#soft-failure) or refuse to actually go forward with sending an event. + +If a room has disabled (or never enabled) a Policy Server, events are recommended +for inclusion and subject to normal authorization rules. + +{{% boxes/note %}} +Because the Policy Server is not asked to sign [`m.room.policy`](/client-server-api/#mroompolicy) +state events with empty string `state_key`s, those events will not have a Policy +Server signature. Those events are by default recommended for inclusion and still +subject to normal authorization rules. + +All other events SHOULD have a valid Policy Server signature when a Policy Server +is enabled in the room, including non-state `m.room.policy` events and `m.room.policy` +state events with non-empty `state_key`s. This also includes state events like +membership and power level changes. +{{% /boxes/note %}} + +If a room has enabled a Policy Server, the Policy Server's signature appears +alongside the normal [event signatures](#signing-events), though uses a public +key from the room's `m.room.policy` state event. + +{{% boxes/note %}} +Currently, only Ed25519 keys are supported by homeservers. The Key ID for the +`ed25519` key in `m.room.policy` is *always* `ed25519:policy_server`. +{{% /boxes/note %}} + +{{% boxes/note %}} +By embedding the Policy Server's public key into room state, the Policy Server +does not need to be online or have its keys cached by a notary in order to validate +an event. +{{% /boxes/note %}} + +{{% boxes/warning %}} +The Policy Server's [published signing key](#publishing-keys) SHOULD NOT be the +same key contained in the `m.room.policy` state event. This is to keep "can send +federation traffic" and "can recommend events for inclusion" separate, and to +allow rooms to revoke the Policy Server's key without cooperation of the Policy +Server. + +If the Policy Server is acting as a normal homeserver and attempting to send an +event, that event will require a signature from the server's published signing +key alongside the Policy Server signature described in this section. +{{% /boxes/warning %}} + +If the Policy Server's signature is valid, the event is recommended for inclusion +in the room, and is still subject to normal authorization rules. + +If the Policy Server's signature is invalid or missing, the homeserver SHOULD +[ask for a new signature](#asking-for-a-policy-server-signature-on-an-event). If +the event still does not have a valid Policy Server signature, the event is *not* +recommended for inclusion and the homeserver SHOULD: + +* If applicable, reject the Client-Server API request which was generating the + event. If the Policy Server returned an error, that error SHOULD be provided + to the client verbatim. The event the client was attempting to send SHOULD be + discarded and not processed/sent any further. +* If the event was received over federation or the homeserver sends a local client's + event anyway, [soft fail](#soft-failure) the event. + +{{% boxes/note %}} +For clarity, an event which lacks a valid Policy Server signature is still subject +to normal authorization rules. +{{% /boxes/note %}} + +{{% boxes/note %}} +When a Policy Server's signature is invalid, a new one is requested because the +Policy Server's key may have rotated between the event being signed and the event +being checked. + +Because the key is contained in the `m.room.policy` state event, if the Policy +Server rotates its key without the room also updating the state event, events +will be flagged as not recommended for inclusion. This is expected behaviour. +{{% /boxes/note %}} + +### Asking for a Policy Server signature on an event + +Per [above](#determining-if-a-policy-server-is-enabled-in-a-room), if a room has +a Policy Server enabled, *all* servers in the room MUST ask the Policy Server to +sign their events before sending them to clients and servers. + +After asking for a signature, homeservers SHOULD [validate](#validating-policy-server-signatures) +the returned signature before continuing to send events. If the Policy Server +returns an error, the event SHOULD NOT be sent to clients and servers. + +{{% http-api spec="server-server" api="room_policy" %}} + ## Signing Events Signing events is complicated by the fact that servers can choose to @@ -1300,6 +1473,12 @@ The signature is then copied back to the original event object. For an example of a signed event, see the [room version specification](/rooms). +{{% boxes/note %}} +{{% added-in v="1.18" %}} +Events sent in rooms with [Policy Servers](#policy-servers) MUST [ask](#asking-for-a-policy-server-signature-on-an-event) +the Policy Server for a signature too. +{{% /boxes/note %}} + ### Validating hashes and signatures on received events When a server receives an event over federation from another server, the @@ -1334,6 +1513,12 @@ only been given a redacted version of the event. To enforce this, the receiving server should use the redacted copy it calculated rather than the full copy it received. +{{% boxes/note %}} +{{% added-in v="1.18" %}} +Events sent in rooms with [Policy Servers](#policy-servers) have [additional](#validating-policy-server-signatures) +signature validation requirements. +{{% /boxes/note %}} + ### Calculating the reference hash for an event The *reference hash* of an event covers the essential fields of an diff --git a/data/api/client-server/policy_server.yaml b/data/api/client-server/policy_server.yaml new file mode 100644 index 00000000..2febe0f0 --- /dev/null +++ b/data/api/client-server/policy_server.yaml @@ -0,0 +1,82 @@ +# Copyright 2026 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +openapi: 3.1.0 +info: + title: Matrix Client-Server Policy Server Discovery API + version: 1.0.0 +paths: + /matrix/policy_server: + get: + summary: Gets information about a Policy Server's configuration, if available. + description: |- + Gets public key information for a [Policy Server](/client-server-api/#policy-servers). + + {{% boxes/note %}} + Like the [well-known discovery URI](/client-server-api/#well-known-uris), + this endpoint should be accessed with the hostname of the Policy Server's + [server name](/appendices/#server-name) by making a + GET request to `https://hostname/.well-known/matrix/policy_server`. + {{% /boxes/note %}} + + Note that this endpoint is not necessarily handled by the homeserver or + Policy Server. It may be served by another webserver. + operationId: getWellknownPolicy + x-addedInMatrixVersion: "1.18" + responses: + "200": + description: |- + Public keys for the Policy Server. Can be supplied to the [`m.room.policy`](/client-server-api/#mroompolicy) + state event. + content: + application/json: + schema: + type: object + properties: + public_keys: + type: object + description: |- + The unpadded base64-encoded public keys for the Policy Server. MUST contain + at least `ed25519`. + properties: + ed25519: + type: string + description: The unpadded base64-encoded ed25519 public key for the Policy Server. + required: ['ed25519'] + additionalProperties: + type: string + description: The unpadded base64-encoded public key for the key algorithm. + required: ["public_keys"] + examples: + response: + value: + { + "public_keys": { + "ed25519": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" + } + } + "404": + description: No policy server information available. + tags: + - Server administration +servers: + - url: "{protocol}://{hostname}{basePath}" + variables: + protocol: + enum: + - https + default: https + hostname: + default: localhost:8008 + basePath: + default: /.well-known diff --git a/data/api/server-server/room_policy.yaml b/data/api/server-server/room_policy.yaml new file mode 100644 index 00000000..4f9634cf --- /dev/null +++ b/data/api/server-server/room_policy.yaml @@ -0,0 +1,172 @@ +# Copyright 2026 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +openapi: 3.1.0 +info: + title: Matrix Federation Room Policy API + version: 1.0.0 +paths: + "/sign": + post: + summary: Asks the Policy Server to sign an event. + description: |- + A server is a Policy Server if it implements this endpoint, among + [other requirements](/server-server-api/#policy-servers). This endpoint + is otherwise optional. See [Unsupported Endpoints](/server-server-api/#unsupported-endpoints) + for details on how to exclude implementation of this endpoint. + + This endpoint MUST NOT be called for events which have a type of `m.room.policy` + and an empty string `state_key`. All other events, including state events, + non-state `m.room.policy` events, and `m.room.policy` state events with + non-empty string `state_key`s are processed by this endpoint. + + Whether a signature is required by a Policy Server further depends on whether + the room has [enabled a Policy Server](#determining-if-a-policy-server-is-enabled-in-a-room). + + {{% boxes/note %}} + The Policy Server MAY respond with *any* of the defined errors to indicate + failure. For example, if it wishes to hide whether it knows about a room, + it MAY return `400 M_FORBIDDEN` instead (or, it MAY sign the event anyway). + {{% /boxes/note %}} + + What the Policy Server checks for when calling this endpoint is left as an + implementation detail. + operationId: askPolicyServerToSign + security: + - signedRequest: [] + parameters: [] + requestBody: + content: + application/json: + schema: + type: object + title: PDU + description: |- + The [PDU](/server-server-api/#pdus) to request a signature for. The event format + varies depending on the room version - check the [room version specification](/rooms) + for precise event formats. + properties: {} + example: + $ref: examples/minimal_pdu.json + required: true + responses: + "200": + description: |- + The Policy Server has signed the event, indicating that it recommends the event for + inclusion in the room. Only the Policy Server's signature is returned. This signature + is to be added to the event before sending or processing the event further. + + `ed25519:policy_server` is *always* used for Ed25519 signatures. + content: + application/json: + schema: + type: object + properties: {} + required: [] + example: { + "policy.example.org": { + "ed25519:policy_server": "zLFxllD0pbBuBpfHh8NuHNaICpReF/PAOpUQTsw+bFGKiGfDNAsnhcP7pbrmhhpfbOAxIdLraQLeeiXBryLmBw" + } + } + "429": + $ref: '#/components/responses/rateLimited' + "400": + description: |- + The request is invalid or the Policy Server refuses to sign the event. + + Error codes include: + * `M_BAD_JSON` - The supplied PDU-formatted event was improperly formatted. For example, + missing keys required for the room version. + * `M_NOT_JSON` - The body wasn't JSON. + * `M_FORBIDDEN` - The Policy Server refuses to sign the event. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "The message appears to contain possible spam" + } + "403": + description: |- + The calling server is [ACL'd](/server-server-api/#server-access-control-lists-acls). + + {{% boxes/note %}} + This endpoint is optionally affected by server ACLs. The Policy Server + MAY NOT apply an ACL to the request, especially if the Policy Server + is not tracking the room DAG. + {{% /boxes/note %}} + content: + application/json: + schema: + allOf: + # XXX: We should move error definitions into a more generic place. + - $ref: ../client-server/definitions/errors/error.yaml + - type: object + properties: + errcode: + description: "The `M_FORBIDDEN` error code." + required: [errcode] + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "Your server is not allowed to request a signature." + } + "404": + description: |- + The server is not a Policy Server, or the room is unknown/not protected by the Policy Server. + + Error codes include: + * `M_NOT_FOUND` - The room is not known or is not protected by the Policy Server. + * `M_UNRECOGNIZED` - The server is not a Policy Server. See [Unsupported Endpoints](/server-server-api/#unsupported-endpoints) + for more detail. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "Unknown room" + } +servers: + - url: "{protocol}://{hostname}{basePath}" + variables: + protocol: + enum: + - http + - https + default: https + hostname: + default: localhost:8448 + basePath: + default: /_matrix/policy/v1 +components: + securitySchemes: + signedRequest: + $ref: definitions/security.yaml#/signedRequest + responses: + rateLimited: + description: This request was rate-limited. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/rate_limited.yaml + diff --git a/data/event-schemas/examples/m.room.policy.yaml b/data/event-schemas/examples/m.room.policy.yaml new file mode 100644 index 00000000..249c2e43 --- /dev/null +++ b/data/event-schemas/examples/m.room.policy.yaml @@ -0,0 +1,11 @@ +{ + "$ref": "core/state_event.json", + "type": "m.room.policy", + "state_key": "", + "content": { + "via": "policy.example.org", + "public_keys": { + "ed25519": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" + } + } +} diff --git a/data/event-schemas/schema/m.room.policy.yaml b/data/event-schemas/schema/m.room.policy.yaml new file mode 100644 index 00000000..a7ff26f3 --- /dev/null +++ b/data/event-schemas/schema/m.room.policy.yaml @@ -0,0 +1,41 @@ +--- +$schema: https://json-schema.org/draft/2020-12/schema + +allOf: + - $ref: core-event-schema/state_event.yaml +description: |- + A [Policy Server](/client-server-api/#policy-servers) configuration. If invalid + or not set, the room does not use a Policy Server. +properties: + content: + properties: + via: + description: |- + The server name to use as a Policy Server. MUST have a joined user in + the room. + type: string + public_keys: + description: |- + The unpadded base64-encoded public keys for the Policy Server. MUST contain at + least `ed25519`. + type: object + properties: + ed25519: + type: string + description: The unpadded base64-encoded ed25519 public key for the Policy Server. + required: ['ed25519'] + additionalProperties: + description: The unpadded base64-encoded public key for the key algorithm. + type: string + type: object + required: + - via + - public_keys + state_key: + description: An empty string. + type: string + type: + enum: + - m.room.policy + type: string +type: object