mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-04-04 18:24:10 +02:00
Merge branch 'main' into use-pattern-properties
This commit is contained in:
commit
9dbe436851
1
changelogs/client_server/newsfragments/1812.feature
Normal file
1
changelogs/client_server/newsfragments/1812.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Specify terms of services at registration, as per [MSC1692](https://github.com/matrix-org/matrix-spec-proposals/pull/1692).
|
||||||
1
changelogs/internal/newsfragments/1814.clarification
Normal file
1
changelogs/internal/newsfragments/1814.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add support for rendering string formats.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that whitespace around commas is allowed in the `X-Matrix` `Authorization` header value params list.
|
||||||
|
|
@ -546,8 +546,10 @@ request parameter.
|
||||||
A client should first make a request with no `auth` parameter.
|
A client should first make a request with no `auth` parameter.
|
||||||
The homeserver returns an HTTP 401 response, with a JSON body, as follows:
|
The homeserver returns an HTTP 401 response, with a JSON body, as follows:
|
||||||
|
|
||||||
HTTP/1.1 401 Unauthorized
|
```
|
||||||
Content-Type: application/json
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -590,8 +592,10 @@ given. It also contains other keys dependent on the auth type being
|
||||||
attempted. For example, if the client is attempting to complete auth
|
attempted. For example, if the client is attempting to complete auth
|
||||||
type `example.type.foo`, it might submit something like this:
|
type `example.type.foo`, it might submit something like this:
|
||||||
|
|
||||||
POST /_matrix/client/v3/endpoint HTTP/1.1
|
```
|
||||||
Content-Type: application/json
|
POST /_matrix/client/v3/endpoint HTTP/1.1
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -611,8 +615,10 @@ along with the same object as when no authentication was attempted, with
|
||||||
the addition of the `completed` key which is an array of auth types the
|
the addition of the `completed` key which is an array of auth types the
|
||||||
client has completed successfully:
|
client has completed successfully:
|
||||||
|
|
||||||
HTTP/1.1 401 Unauthorized
|
```
|
||||||
Content-Type: application/json
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -643,8 +649,10 @@ but the client may make a second attempt, it returns the same HTTP
|
||||||
status 401 response as above, with the addition of the standard
|
status 401 response as above, with the addition of the standard
|
||||||
`errcode` and `error` fields describing the error. For example:
|
`errcode` and `error` fields describing the error. For example:
|
||||||
|
|
||||||
HTTP/1.1 401 Unauthorized
|
```
|
||||||
Content-Type: application/json
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -671,8 +679,10 @@ status 401 response as above, with the addition of the standard
|
||||||
If the request fails for a reason other than authentication, the server
|
If the request fails for a reason other than authentication, the server
|
||||||
returns an error message in the standard format. For example:
|
returns an error message in the standard format. For example:
|
||||||
|
|
||||||
HTTP/1.1 400 Bad request
|
```
|
||||||
Content-Type: application/json
|
HTTP/1.1 400 Bad request
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -970,6 +980,129 @@ in the registration process that their token has expired.
|
||||||
|
|
||||||
{{% http-api spec="client-server" api="registration_tokens" %}}
|
{{% http-api spec="client-server" api="registration_tokens" %}}
|
||||||
|
|
||||||
|
##### Terms of service at registration
|
||||||
|
|
||||||
|
{{% added-in v="1.11" %}}
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|--------------------------|--------------------------------------------------------------------------|
|
||||||
|
| `m.login.terms` | Authentication requires the user to accept a set of policy documents. |
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
The `m.login.terms` authentication type is only valid on the
|
||||||
|
[`/register`](#post_matrixclientv3register) endpoint.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
This authentication type is used when the homeserver requires new users to
|
||||||
|
accept a given set of policy documents, such as a terms of service and a privacy
|
||||||
|
policy. There may be many different types of documents, all of which are
|
||||||
|
versioned and presented in (potentially) multiple languages.
|
||||||
|
|
||||||
|
When the server requires the user to accept some terms, it does so by returning
|
||||||
|
a 401 response to the `/register` request, where the response body includes
|
||||||
|
`m.login.terms` in the `flows` list, and the `m.login.terms` property in the
|
||||||
|
`params` object has the structure [shown below](#definition-mloginterms-params).
|
||||||
|
|
||||||
|
If a client encounters an invalid parameter, registration should stop with an
|
||||||
|
error presented to the user.
|
||||||
|
|
||||||
|
The client should present the user with a checkbox to accept each policy,
|
||||||
|
including a link to the provided URL. Once the user has done so, the client
|
||||||
|
submits an `auth` dict with just the `type` and `session`, as follows, to
|
||||||
|
indicate that all of the policies have been accepted:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "m.login.terms",
|
||||||
|
"session": "<session ID>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The server is expected to track which document versions it presented to the
|
||||||
|
user during registration, if applicable.
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
1. A client might submit a registration request as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /_matrix/client/v3/register
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "cheeky_monkey",
|
||||||
|
"password": "ilovebananas"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. The server requires the user to accept some terms of service before
|
||||||
|
registration, so returns the following response:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"flows": [
|
||||||
|
{ "stages": [ "m.login.terms" ] }
|
||||||
|
],
|
||||||
|
"params": {
|
||||||
|
"m.login.terms": {
|
||||||
|
"policies": {
|
||||||
|
"terms_of_service": {
|
||||||
|
"version": "1.2",
|
||||||
|
"en": {
|
||||||
|
"name": "Terms of Service",
|
||||||
|
"url": "https://example.org/somewhere/terms-1.2-en.html"
|
||||||
|
},
|
||||||
|
"fr": {
|
||||||
|
"name": "Conditions d'utilisation",
|
||||||
|
"url": "https://example.org/somewhere/terms-1.2-fr.html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"session": "kasgjaelkgj"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. The client presents the list of documents to the user, inviting them to
|
||||||
|
accept the polices.
|
||||||
|
|
||||||
|
4. The client repeats the registration request, confirming that the user has
|
||||||
|
accepted the documents:
|
||||||
|
```
|
||||||
|
POST /_matrix/client/v3/register
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "cheeky_monkey",
|
||||||
|
"password": "ilovebananas",
|
||||||
|
"auth": {
|
||||||
|
"type": "m.login.terms",
|
||||||
|
"session": "kasgjaelkgj"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5. All authentication steps have now completed, so the request is successful:
|
||||||
|
```
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"access_token": "abc123",
|
||||||
|
"device_id": "GHTYAJCE",
|
||||||
|
"user_id": "@cheeky_monkey:matrix.org"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% definition path="api/client-server/definitions/m.login.terms_params" %}}
|
||||||
|
|
||||||
#### Fallback
|
#### Fallback
|
||||||
|
|
||||||
Clients cannot be expected to be able to know how to process every
|
Clients cannot be expected to be able to know how to process every
|
||||||
|
|
|
||||||
|
|
@ -350,9 +350,10 @@ def authorization_headers(origin_name, origin_signing_key,
|
||||||
|
|
||||||
The format of the Authorization header is given in
|
The format of the Authorization header is given in
|
||||||
[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1). In
|
[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1). In
|
||||||
summary, the header begins with authorization scheme `X-Matrix`, followed by
|
summary, the header begins with authorization scheme `X-Matrix`, followed by one
|
||||||
one or more spaces, followed by a comma-separated list of parameters written as
|
or more spaces, followed by a comma-separated list of parameters written as
|
||||||
name=value pairs. The names are case insensitive and order does not matter. The
|
name=value pairs. Zero or more spaces and tabs around each comma are allowed.
|
||||||
|
The names are case insensitive and order does not matter. The
|
||||||
values must be enclosed in quotes if they contain characters that are not
|
values must be enclosed in quotes if they contain characters that are not
|
||||||
allowed in `token`s, as defined in
|
allowed in `token`s, as defined in
|
||||||
[RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6); if a
|
[RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6); if a
|
||||||
|
|
@ -363,8 +364,9 @@ replaced by the character that follows the backslash.
|
||||||
|
|
||||||
For compatibility with older servers, the sender should
|
For compatibility with older servers, the sender should
|
||||||
- only include one space after `X-Matrix`,
|
- only include one space after `X-Matrix`,
|
||||||
- only use lower-case names, and
|
- only use lower-case names,
|
||||||
- avoid using backslashes in parameter values.
|
- avoid using backslashes in parameter values, and
|
||||||
|
- avoid including whitespace around the commas between name=value pairs.
|
||||||
|
|
||||||
For compatibility with older servers, the recipient should allow colons to be
|
For compatibility with older servers, the recipient should allow colons to be
|
||||||
included in values without requiring the value to be enclosed in quotes.
|
included in values without requiring the value to be enclosed in quotes.
|
||||||
|
|
|
||||||
82
data/api/client-server/definitions/m.login.terms_params.yaml
Normal file
82
data/api/client-server/definitions/m.login.terms_params.yaml
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Copyright 2024 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.
|
||||||
|
|
||||||
|
type: object
|
||||||
|
title: m.login.terms params
|
||||||
|
description: Schema for `m.login.terms` entry in the `params` object in a User-Interactive Authentication response.
|
||||||
|
required: ['policies']
|
||||||
|
properties:
|
||||||
|
policies:
|
||||||
|
type: object
|
||||||
|
description: |
|
||||||
|
A map from "Policy ID" to the current definition of this policy document. The Policy ID is a unique
|
||||||
|
identifier for a given policy document, using the [Opaque Identifier Grammar](/appendices/#opaque-identifiers).
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
title: Policy Definition
|
||||||
|
required: [version]
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
The version of this policy document. This is provided as a convenience for the client,
|
||||||
|
and uses the [Opaque Identifier Grammar](/appendices/#opaque-identifiers).
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
title: Policy Translation
|
||||||
|
required: [name, url]
|
||||||
|
description: |
|
||||||
|
Map from language codes to details of the document in that language.
|
||||||
|
Language codes SHOULD be formatted as per [Section 2.2 of RFC
|
||||||
|
5646](https://datatracker.ietf.org/doc/html/rfc5646#section-2.2),
|
||||||
|
though some implementations may use an underscore instead of dash
|
||||||
|
(for example, `en_US` instead of `en-US`).
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
The name of this document, in the appropriate language. An
|
||||||
|
arbitrary string with no specified maximum length.
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
A link to the text of this document, in the appropriate
|
||||||
|
language. MUST be a valid URI with scheme `https://` or
|
||||||
|
`http://`. Insecure HTTP is discouraged.
|
||||||
|
example: {
|
||||||
|
"policies": {
|
||||||
|
"terms_of_service": {
|
||||||
|
"version": "1.2",
|
||||||
|
"en": {
|
||||||
|
"name": "Terms of Service",
|
||||||
|
"url": "https://example.org/somewhere/terms-1.2-en.html"
|
||||||
|
},
|
||||||
|
"fr": {
|
||||||
|
"name": "Conditions d'utilisation",
|
||||||
|
"url": "https://example.org/somewhere/terms-1.2-fr.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacy_policy": {
|
||||||
|
"version": "1.2",
|
||||||
|
"en": {
|
||||||
|
"name": "Privacy Policy",
|
||||||
|
"url": "https://example.org/somewhere/privacy-1.2-en.html"
|
||||||
|
},
|
||||||
|
"fr": {
|
||||||
|
"name": "Politique de confidentialité",
|
||||||
|
"url": "https://example.org/somewhere/privacy-1.2-fr.html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,4 +35,9 @@ mx-event-id:
|
||||||
mx-room-id:
|
mx-room-id:
|
||||||
title: Room ID
|
title: Room ID
|
||||||
url: /appendices#room-ids
|
url: /appendices#room-ids
|
||||||
# regex: "^!"
|
# regex: "^!"
|
||||||
|
|
||||||
|
uri:
|
||||||
|
title: URI
|
||||||
|
url: http://tools.ietf.org/html/rfc3986
|
||||||
|
# no regex
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ resolve-additional-types.)
|
||||||
|
|
||||||
* `anchor`: optional HTML element id for the target type, which will be used to link to it.
|
* `anchor`: optional HTML element id for the target type, which will be used to link to it.
|
||||||
|
|
||||||
|
* `format`: optional string for the format of the type, used for strings.
|
||||||
|
|
||||||
*/}}
|
*/}}
|
||||||
{{ define "partials/property-type" }}
|
{{ define "partials/property-type" }}
|
||||||
{{ $type := "" }}
|
{{ $type := "" }}
|
||||||
|
|
@ -143,6 +145,15 @@ resolve-additional-types.)
|
||||||
{{ $items := .items }}
|
{{ $items := .items }}
|
||||||
{{ $inner_type := partial "property-type" $items }}
|
{{ $inner_type := partial "property-type" $items }}
|
||||||
{{ $type = delimit (slice "[" $inner_type "]") "" }}
|
{{ $type = delimit (slice "[" $inner_type "]") "" }}
|
||||||
|
{{ else if eq .type "string" }}
|
||||||
|
{{ $type = "string" }}
|
||||||
|
|
||||||
|
{{/* If the string uses a known format, use it. */}}
|
||||||
|
{{ with .format }}
|
||||||
|
{{ with partial "custom-format" . }}
|
||||||
|
{{ $type = . }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
{{ else if or (reflect.IsSlice .type) .oneOf }}
|
{{ else if or (reflect.IsSlice .type) .oneOf }}
|
||||||
{{/*
|
{{/*
|
||||||
It's legal to specify an array of types.
|
It's legal to specify an array of types.
|
||||||
|
|
@ -167,7 +178,7 @@ resolve-additional-types.)
|
||||||
|
|
||||||
{{ $type = delimit $types "|" }}
|
{{ $type = delimit $types "|" }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{/* A simple type like string or boolean */}}
|
{{/* A simple type like integer or boolean */}}
|
||||||
{{ $type = (htmlEscape .type) }}
|
{{ $type = (htmlEscape .type) }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
@ -241,8 +252,8 @@ resolve-additional-types.)
|
||||||
{{ range $formatId, $formatType := $formatMap.Values }}
|
{{ range $formatId, $formatType := $formatMap.Values }}
|
||||||
{{ $formatKey := "string" }}
|
{{ $formatKey := "string" }}
|
||||||
{{ if ne $formatId "string" }}
|
{{ if ne $formatId "string" }}
|
||||||
{{ with index site.Data "custom-formats" $formatId }}
|
{{ with partial "custom-format" $formatId }}
|
||||||
{{ $formatKey = printf "<a href=\"%s\">%s</a>" (htmlEscape .url) (htmlEscape .title) }}
|
{{ $formatKey = . }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{ errorf "Unsupported value for `x-pattern-format`: %s" $formatId }}
|
{{ errorf "Unsupported value for `x-pattern-format`: %s" $formatId }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
@ -290,3 +301,18 @@ resolve-additional-types.)
|
||||||
{{ if (index .property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index .property "x-addedInMatrixVersion")) }}{{ end -}}
|
{{ if (index .property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index .property "x-addedInMatrixVersion")) }}{{ end -}}
|
||||||
{{ if (index .property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index .property "x-changedInMatrixVersion")) }}{{ end -}}
|
{{ if (index .property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index .property "x-changedInMatrixVersion")) }}{{ end -}}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Computes the type to display for a string format, given the identifier of
|
||||||
|
the format as a string.
|
||||||
|
*/}}
|
||||||
|
{{ define "partials/custom-format" }}
|
||||||
|
{{ $customFormat := "" }}
|
||||||
|
|
||||||
|
{{ with index site.Data "custom-formats" . }}
|
||||||
|
{{ $customFormat = printf "<a href=\"%s\">%s</a>" (htmlEscape .url) (htmlEscape .title) }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ return $customFormat }}
|
||||||
|
{{ end }}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue