Skip to content

Commit

Permalink
Merge branch 'main' into use-pattern-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
richvdh committed May 8, 2024
2 parents 4c19498 + df1e799 commit 9dbe436
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 19 deletions.
1 change: 1 addition & 0 deletions changelogs/client_server/newsfragments/1812.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Specify terms of services at registration, as per [MSC1692](https://github.com/matrix-org/matrix-spec-proposals/pull/1692).
1 change: 1 addition & 0 deletions changelogs/internal/newsfragments/1814.clarification
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for rendering string formats.
1 change: 1 addition & 0 deletions changelogs/server_server/newsfragments/1818.clarification
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Clarify that whitespace around commas is allowed in the `X-Matrix` `Authorization` header value params list.
153 changes: 143 additions & 10 deletions content/client-server-api/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,10 @@ request 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:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```

```json
{
Expand Down Expand Up @@ -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
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
{
Expand All @@ -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
client has completed successfully:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```

```json
{
Expand Down Expand Up @@ -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
`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
{
Expand All @@ -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
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
{
Expand Down Expand Up @@ -970,6 +980,129 @@ in the registration process that their token has expired.

{{% 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

Clients cannot be expected to be able to know how to process every
Expand Down
12 changes: 7 additions & 5 deletions content/server-server-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,10 @@ def authorization_headers(origin_name, origin_signing_key,

The format of the Authorization header is given 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
one 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
summary, the header begins with authorization scheme `X-Matrix`, followed by one
or more spaces, followed by a comma-separated list of parameters written as
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
allowed in `token`s, as defined in
[RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6); if a
Expand All @@ -363,8 +364,9 @@ replaced by the character that follows the backslash.

For compatibility with older servers, the sender should
- only include one space after `X-Matrix`,
- only use lower-case names, and
- avoid using backslashes in parameter values.
- only use lower-case names,
- 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
included in values without requiring the value to be enclosed in quotes.
Expand Down
82 changes: 82 additions & 0 deletions data/api/client-server/definitions/m.login.terms_params.yaml
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
}
7 changes: 6 additions & 1 deletion data/custom-formats.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ mx-event-id:
mx-room-id:
title: Room ID
url: /appendices#room-ids
# regex: "^!"
# regex: "^!"

uri:
title: URI
url: http://tools.ietf.org/html/rfc3986
# no regex
32 changes: 29 additions & 3 deletions layouts/partials/openapi/render-object-table.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@

* `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" }}
{{ $type := "" }}
Expand All @@ -143,6 +145,15 @@
{{ $items := .items }}
{{ $inner_type := partial "property-type" $items }}
{{ $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 }}
{{/*
It's legal to specify an array of types.
Expand All @@ -167,7 +178,7 @@

{{ $type = delimit $types "|" }}
{{ else }}
{{/* A simple type like string or boolean */}}
{{/* A simple type like integer or boolean */}}
{{ $type = (htmlEscape .type) }}
{{ end }}

Expand Down Expand Up @@ -241,8 +252,8 @@
{{ range $formatId, $formatType := $formatMap.Values }}
{{ $formatKey := "string" }}
{{ if ne $formatId "string" }}
{{ with index site.Data "custom-formats" $formatId }}
{{ $formatKey = printf "<a href=\"%s\">%s</a>" (htmlEscape .url) (htmlEscape .title) }}
{{ with partial "custom-format" $formatId }}
{{ $formatKey = . }}
{{ else }}
{{ errorf "Unsupported value for `x-pattern-format`: %s" $formatId }}
{{ end }}
Expand Down Expand Up @@ -290,3 +301,18 @@
{{ 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 -}}
{{ 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 }}

0 comments on commit 9dbe436

Please sign in to comment.