mirror of
https://github.com/matrix-org/matrix-spec
synced 2025-12-20 16:38:37 +01:00
Compare commits
69 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f6867348f | ||
|
|
6b5ff04d00 | ||
|
|
ce5ae4d371 | ||
|
|
27315feb17 | ||
|
|
a1c930d0d1 | ||
|
|
9e959f3922 | ||
|
|
7c39427d8b | ||
|
|
54944e2866 | ||
|
|
13aa6e83ae | ||
|
|
705240da72 | ||
|
|
4dbe080570 | ||
|
|
7a1eb81c9c | ||
|
|
22c0952003 | ||
|
|
a5afe542c0 | ||
|
|
d28e05af87 | ||
|
|
b1fd2af72c | ||
|
|
f7a0d8d135 | ||
|
|
a2027a3985 | ||
|
|
ff1a39e36a | ||
|
|
add0f2232c | ||
|
|
8ebf4a4789 | ||
|
|
935c23485b | ||
|
|
fe3f43a905 | ||
|
|
4783619964 | ||
|
|
4cafe7d9f4 | ||
|
|
e2b2e56bd2 | ||
|
|
967b54195c | ||
|
|
9d063c8d2d | ||
|
|
74a0d5f289 | ||
|
|
974b0b721e | ||
|
|
fda3be5ee3 | ||
|
|
7f4072d993 | ||
|
|
58744f4734 | ||
|
|
dfdb1d09b8 | ||
|
|
f82d8ab15b | ||
|
|
b6a127b5cb | ||
|
|
0a649cb0db | ||
|
|
d8be2ad942 | ||
|
|
21109b4d5b | ||
|
|
d4d31a8894 | ||
|
|
d968774fb7 | ||
|
|
2aacc1feda | ||
|
|
2a8c0bc7b8 | ||
|
|
81a864545f | ||
|
|
671bc674cd | ||
|
|
72a2ebc7ad | ||
|
|
7bc016bda6 | ||
|
|
fea0b925a0 | ||
|
|
bfbeb5e257 | ||
|
|
d1a51f7b8c | ||
|
|
6e16a19ac9 | ||
|
|
4d4069166d | ||
|
|
b5ee6adc0f | ||
|
|
f97d2944ae | ||
|
|
c4bfd2feb8 | ||
|
|
04f42ac208 | ||
|
|
f6d5009959 | ||
|
|
9c313b099f | ||
|
|
67a2aa4761 | ||
|
|
7d2de48cb4 | ||
|
|
fb4a0d8f66 | ||
|
|
4c87e0e745 | ||
|
|
3e1e9fa8df | ||
|
|
c8380d9552 | ||
|
|
3877598b1e | ||
|
|
0e280ed014 | ||
|
|
625ed5c599 | ||
|
|
484a777572 | ||
|
|
6edb6ba1cd |
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
name: "Spec"
|
name: "Spec"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
HUGO_VERSION: 0.139.0
|
HUGO_VERSION: 0.148.1
|
||||||
PYTHON_VERSION: 3.13
|
PYTHON_VERSION: 3.13
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
|
@ -155,6 +155,11 @@ jobs:
|
||||||
--api server-server \
|
--api server-server \
|
||||||
-r "$RELEASE" \
|
-r "$RELEASE" \
|
||||||
-o spec/server-server-api/api.json
|
-o spec/server-server-api/api.json
|
||||||
|
scripts/dump-openapi.py \
|
||||||
|
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
||||||
|
--api identity \
|
||||||
|
-r "$RELEASE" \
|
||||||
|
-o spec/identity-service-api/api.json
|
||||||
tar -czf openapi.tar.gz spec
|
tar -czf openapi.tar.gz spec
|
||||||
- name: "📤 Artifact upload"
|
- name: "📤 Artifact upload"
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|
|
||||||
15
.github/workflows/release.yaml
vendored
15
.github/workflows/release.yaml
vendored
|
|
@ -12,6 +12,9 @@ jobs:
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: packages/npm
|
working-directory: packages/npm
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: 🧮 Checkout code
|
- name: 🧮 Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -23,6 +26,10 @@ jobs:
|
||||||
cache-dependency-path: packages/npm/yarn.lock
|
cache-dependency-path: packages/npm/yarn.lock
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
|
# Ensure npm 11.5.1 or later is installed
|
||||||
|
- name: Update npm
|
||||||
|
run: npm install -g npm@latest
|
||||||
|
|
||||||
- name: 🔨 Install dependencies
|
- name: 🔨 Install dependencies
|
||||||
run: "yarn install --frozen-lockfile"
|
run: "yarn install --frozen-lockfile"
|
||||||
|
|
||||||
|
|
@ -33,10 +40,4 @@ jobs:
|
||||||
VERSION: ${{ github.event.release.tag_name }}.0
|
VERSION: ${{ github.event.release.tag_name }}.0
|
||||||
|
|
||||||
- name: 🚀 Publish to npm
|
- name: 🚀 Publish to npm
|
||||||
id: npm-publish
|
run: npm publish --provenance --access public --tag latest
|
||||||
uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
|
||||||
package: packages/npm
|
|
||||||
access: public
|
|
||||||
ignore-scripts: false
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ place after an MSC has been accepted, not as part of a proposal itself.
|
||||||
|
|
||||||
1. Install the extended version (often the OS default) of Hugo:
|
1. Install the extended version (often the OS default) of Hugo:
|
||||||
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
|
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
|
||||||
v0.123.1 is required.
|
v0.146.0 is required.
|
||||||
|
|
||||||
Alternatively, use the Docker image at
|
Alternatively, use the Docker image at
|
||||||
https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required
|
https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required
|
||||||
|
|
|
||||||
114
assets/js/versions.template.js
Normal file
114
assets/js/versions.template.js
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the current version as defined in hugo.toml. This will either be
|
||||||
|
// "unstable" or "vX.X" and doesn't depend on the current URL.
|
||||||
|
//
|
||||||
|
// The oddity below is an attempt at producing a readable Hugo template while
|
||||||
|
// avoiding JS syntax errors in your IDE.
|
||||||
|
const currentVersion = `{{ if eq .Site.Params.version.status "unstable" }}
|
||||||
|
{{- /**/ -}}
|
||||||
|
unstable
|
||||||
|
{{- /**/ -}}
|
||||||
|
{{ else }}
|
||||||
|
{{- /**/ -}}
|
||||||
|
{{ printf "v%s.%s" .Site.Params.version.major .Site.Params.version.minor }}
|
||||||
|
{{- /**/ -}}
|
||||||
|
{{ end }}`;
|
||||||
|
|
||||||
|
// Determine the current version segment by regex matching the URL. This will either
|
||||||
|
// be "unstable", "latest", "vX.X" (production) or undefined (local & netlify).
|
||||||
|
const href = window.location.href;
|
||||||
|
const segmentMatches = href.match(/(?<=\/)unstable|latest|v\d+.\d+(?=\/)/);
|
||||||
|
const currentSegment = segmentMatches ? segmentMatches[0] : undefined;
|
||||||
|
|
||||||
|
// Determine the selected menu element. If we were able to obtain the version
|
||||||
|
// segment from the URL (production), use that. Otherwise (local & netlify),
|
||||||
|
// fall back to the version as defined in Hugo.
|
||||||
|
const selected = currentSegment ?? currentVersion;
|
||||||
|
|
||||||
|
function appendVersion(parent, name, segment, url) {
|
||||||
|
// The list item
|
||||||
|
const li = document.createElement("li");
|
||||||
|
if (segment === selected) {
|
||||||
|
li.classList.add("version-picker-selected");
|
||||||
|
}
|
||||||
|
if (segment === "latest") {
|
||||||
|
li.classList.add("version-picker-latest");
|
||||||
|
}
|
||||||
|
parent.appendChild(li);
|
||||||
|
|
||||||
|
// The link
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.classList.add("dropdown-item");
|
||||||
|
a.setAttribute("href", url);
|
||||||
|
li.appendChild(a);
|
||||||
|
|
||||||
|
// Handle clicks manually to preserve the current path / fragment
|
||||||
|
a.addEventListener("click", (ev) => {
|
||||||
|
// If the URL is a relative link (i.e. the historical versions changelog), just
|
||||||
|
// let the browser load it
|
||||||
|
if (url.startsWith("/")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we couldn't determine the current segment, we cannot safely replace
|
||||||
|
// it and have to let the browser load the (root) URL instead
|
||||||
|
if (!currentSegment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, stop further event handling and replace the segment
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
window.location.href = href.replace(`/${currentSegment}/`, `/${segment}/`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// The link text
|
||||||
|
const text = document.createTextNode(name);
|
||||||
|
a.appendChild(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're in the unstable version, we're the latest thing and can just load
|
||||||
|
// versions.json from our own resources. Otherwise, we fall back to loading it
|
||||||
|
// from /unstable/versions.json, assuming we are on the spec.matrix.org deployment.
|
||||||
|
const url = currentVersion === "unstable"
|
||||||
|
? '{{ .Site.Home.Permalink }}versions.json'
|
||||||
|
: "/unstable/versions.json";
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(versions => {
|
||||||
|
// Find the surrounding list element
|
||||||
|
const ul = document.querySelector("ul#version-selector");
|
||||||
|
if (!ul) {
|
||||||
|
console.error("Cannot populate version selector: ul element not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a entries for the unstable version and the "latest" shortcut
|
||||||
|
appendVersion(ul, "unstable", "unstable", "https://spec.matrix.org/unstable");
|
||||||
|
const latestName = versions?.length ? `latest (${versions[0].name})` : "latest";
|
||||||
|
appendVersion(ul, latestName, "latest", "https://spec.matrix.org/latest");
|
||||||
|
|
||||||
|
// Add an entry for each proper version
|
||||||
|
for (const version of versions) {
|
||||||
|
appendVersion(ul, version.name, version.name, `https://spec.matrix.org/${version.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For historical versions, simply link to the changelog
|
||||||
|
appendVersion(ul, "historical", "historical", '{{ (site.GetPage "changelog/historical").RelPermalink }}');
|
||||||
|
});
|
||||||
|
|
@ -50,6 +50,20 @@ Custom SCSS for the Matrix spec
|
||||||
a {
|
a {
|
||||||
color: $black;
|
color: $black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make the version dropdown scroll if it's too large */
|
||||||
|
ul#version-selector {
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#version-selector li.version-picker-selected a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#version-selector li.version-picker-latest a {
|
||||||
|
color: $secondary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styles for the sidebar nav */
|
/* Styles for the sidebar nav */
|
||||||
|
|
@ -243,6 +257,69 @@ Custom SCSS for the Matrix spec
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.endpoints-toc {
|
||||||
|
summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-list {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-list li {
|
||||||
|
margin: 0.2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-list a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0.05rem 0.25rem;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $secondary-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-list .http-api-method {
|
||||||
|
margin-right: 0.35rem;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-path {
|
||||||
|
font-family: $font-family-monospace;
|
||||||
|
color: $secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-deprecated {
|
||||||
|
color: $danger;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
margin-left: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-module {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-module-title {
|
||||||
|
// font-weight: $font-weight-bold;
|
||||||
|
font-size: 1.20rem;
|
||||||
|
margin-bottom: 0.35rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-description {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
/* Styles for alert boxes */
|
/* Styles for alert boxes */
|
||||||
.alert {
|
.alert {
|
||||||
&.note {
|
&.note {
|
||||||
|
|
@ -502,6 +579,13 @@ Make padding symmetrical (this selector is used in the default styles to apply p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adjust the width of math to match normal paragraphs */
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
.katex-display {
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Adjust default styles for info banner */
|
/* Adjust default styles for info banner */
|
||||||
.pageinfo-primary {
|
.pageinfo-primary {
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
|
|
|
||||||
1
changelogs/internal/newsfragments/2282.clarification
Normal file
1
changelogs/internal/newsfragments/2282.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Replace the Twitter link in the footer with our BlueSky and Mastodon socials.
|
||||||
|
|
@ -8,7 +8,7 @@ enableRobotsTXT = true
|
||||||
# We disable RSS, because (a) it's useless, (b) Hugo seems to generate broken
|
# We disable RSS, because (a) it's useless, (b) Hugo seems to generate broken
|
||||||
# links to it when used with a --baseURL (for example, https://spec.matrix.org/v1.4/
|
# links to it when used with a --baseURL (for example, https://spec.matrix.org/v1.4/
|
||||||
# contains `<link rel="alternate" type="application/rss+xml" href="/v1.4/v1.4/index.xml">`).
|
# contains `<link rel="alternate" type="application/rss+xml" href="/v1.4/v1.4/index.xml">`).
|
||||||
disableKinds = ["taxonomy", "RSS"]
|
disableKinds = ["taxonomy", "rss"]
|
||||||
|
|
||||||
[languages]
|
[languages]
|
||||||
[languages.en]
|
[languages.en]
|
||||||
|
|
@ -43,6 +43,15 @@ description = "Home of the Matrix specification for decentralised communication"
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
# Enables us to render raw HTML
|
# Enables us to render raw HTML
|
||||||
unsafe = true
|
unsafe = true
|
||||||
|
[markup.goldmark.extensions]
|
||||||
|
# Tell Goldmark to pass delimited blocks through the `render-passthrough` render hook.
|
||||||
|
# This is used to render the maths in the Olm spec.
|
||||||
|
# See: https://gohugo.io/functions/transform/tomath/#step-1.
|
||||||
|
[markup.goldmark.extensions.passthrough]
|
||||||
|
enable = true
|
||||||
|
[markup.goldmark.extensions.passthrough.delimiters]
|
||||||
|
block = [['\[', '\]']]
|
||||||
|
inline = [['\(', '\)']]
|
||||||
[markup.highlight]
|
[markup.highlight]
|
||||||
# See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html
|
# See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html
|
||||||
# If the style is changed, remember to regenerate the CSS with:
|
# If the style is changed, remember to regenerate the CSS with:
|
||||||
|
|
@ -61,13 +70,17 @@ copyright = "The Matrix.org Foundation CIC"
|
||||||
[params.version]
|
[params.version]
|
||||||
# must be one of "unstable", "current", "historical"
|
# must be one of "unstable", "current", "historical"
|
||||||
# this is used to decide whether to show a banner pointing to the current release
|
# this is used to decide whether to show a banner pointing to the current release
|
||||||
status = "stable"
|
status = "unstable"
|
||||||
# A URL pointing to the latest, stable release of the spec. To be shown in the unstable version warning banner.
|
# A URL pointing to the latest, stable release of the spec. To be shown in the unstable version warning banner.
|
||||||
current_version_url = "https://spec.matrix.org/latest"
|
current_version_url = "https://spec.matrix.org/latest"
|
||||||
# The following is used when status = "stable", and is displayed in various UI elements on a released version
|
# The following is used when status = "stable", and is displayed in various UI elements on a released version
|
||||||
# of the spec.
|
# of the spec.
|
||||||
major = "1"
|
#major = "1"
|
||||||
minor = "15"
|
#minor = "17"
|
||||||
|
|
||||||
|
[[params.versions]]
|
||||||
|
# We must include this parameter to enable docsy's version picker in the navbar. The picker
|
||||||
|
# is populated automatically in navbar-version-selector.html.
|
||||||
|
|
||||||
# User interface configuration
|
# User interface configuration
|
||||||
[params.ui]
|
[params.ui]
|
||||||
|
|
@ -108,10 +121,15 @@ sidebar_menu_compact = true
|
||||||
icon = "fab fa-youtube"
|
icon = "fab fa-youtube"
|
||||||
desc = "Matrix YouTube channel"
|
desc = "Matrix YouTube channel"
|
||||||
[[params.links.bottom]]
|
[[params.links.bottom]]
|
||||||
name = "Twitter"
|
name = "Mastodon"
|
||||||
url = "https://twitter.com/matrixdotorg"
|
url = "https://mastodon.matrix.org/@matrix"
|
||||||
icon = "fab fa-twitter"
|
icon = "fab fa-mastodon"
|
||||||
desc = "Matrix on Twitter"
|
desc = "Matrix on Mastodon"
|
||||||
|
[[params.links.bottom]]
|
||||||
|
name = "Bluesky"
|
||||||
|
url = "https://bsky.app/profile/matrix.org"
|
||||||
|
icon = "fab fa-bluesky"
|
||||||
|
desc = "Matrix on Bluesky"
|
||||||
|
|
||||||
|
|
||||||
# configuration for the hugo development server
|
# configuration for the hugo development server
|
||||||
|
|
@ -121,7 +139,9 @@ sidebar_menu_compact = true
|
||||||
[[server.headers]]
|
[[server.headers]]
|
||||||
for = '/**'
|
for = '/**'
|
||||||
[server.headers.values]
|
[server.headers.values]
|
||||||
Content-Security-Policy = "default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; media-src 'self'; child-src 'self'; form-action 'self'; object-src 'self'"
|
# `style-src 'unsafe-inline'` is needed to correctly render the maths in the Olm spec:
|
||||||
|
# https://github.com/KaTeX/KaTeX/issues/4096
|
||||||
|
Content-Security-Policy = "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; media-src 'self'; child-src 'self'; form-action 'self'; object-src 'self'"
|
||||||
X-XSS-Protection = "1; mode=block"
|
X-XSS-Protection = "1; mode=block"
|
||||||
X-Content-Type-Options = "nosniff"
|
X-Content-Type-Options = "nosniff"
|
||||||
# Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
|
# Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
|
||||||
|
|
@ -134,7 +154,7 @@ sidebar_menu_compact = true
|
||||||
[module]
|
[module]
|
||||||
[module.hugoVersion]
|
[module.hugoVersion]
|
||||||
extended = true
|
extended = true
|
||||||
min = "0.123.1"
|
min = "0.146.0"
|
||||||
[[module.imports]]
|
[[module.imports]]
|
||||||
path = "github.com/matrix-org/docsy"
|
path = "github.com/matrix-org/docsy"
|
||||||
disable = false
|
disable = false
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ The specification consists of the following parts:
|
||||||
* [Identity Service API](/identity-service-api)
|
* [Identity Service API](/identity-service-api)
|
||||||
* [Push Gateway API](/push-gateway-api)
|
* [Push Gateway API](/push-gateway-api)
|
||||||
* [Room Versions](/rooms)
|
* [Room Versions](/rooms)
|
||||||
|
* [Olm & Megolm](/olm-megolm)
|
||||||
* [Appendices](/appendices)
|
* [Appendices](/appendices)
|
||||||
|
|
||||||
Additionally, this introduction page contains the key baseline
|
Additionally, this introduction page contains the key baseline
|
||||||
|
|
@ -151,7 +152,7 @@ request.
|
||||||
|
|
||||||
How data flows between clients:
|
How data flows between clients:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{ Matrix client A } { Matrix client B }
|
{ Matrix client A } { Matrix client B }
|
||||||
^ | ^ |
|
^ | ^ |
|
||||||
| events | Client-Server API | events |
|
| events | Client-Server API | events |
|
||||||
|
|
|
||||||
|
|
@ -657,27 +657,48 @@ provides no way to encode ASCII punctuation).
|
||||||
|
|
||||||
#### Room IDs
|
#### Room IDs
|
||||||
|
|
||||||
A room has exactly one room ID. A room ID has the format:
|
{{% changed-in v="1.16" %}} Room IDs can now appear without a domain depending on
|
||||||
|
the room version.
|
||||||
|
|
||||||
|
A room has exactly one room ID. Room IDs take the form:
|
||||||
|
|
||||||
|
!opaque_id
|
||||||
|
|
||||||
|
However, the precise format depends upon the [room version specification](/rooms):
|
||||||
|
some room versions included a `domain` component, whereas more recent room versions
|
||||||
|
omit the domain and use a base64-encoded hash instead.
|
||||||
|
|
||||||
|
Room IDs are case-sensitive and not meant to be human-readable. They are intended
|
||||||
|
to be used as fully opaque strings by clients, even when a `domain` component is
|
||||||
|
present.
|
||||||
|
|
||||||
|
If the room version requires a `domain` component, room IDs take the following
|
||||||
|
form:
|
||||||
|
|
||||||
!opaque_id:domain
|
!opaque_id:domain
|
||||||
|
|
||||||
The `domain` of a room ID is the [server name](#server-name) of the
|
In such a form, the `opaque_id` is a localpart. The localpart MUST only contain
|
||||||
homeserver which created the room. The domain is used only for
|
valid non-surrogate Unicode code points, including control characters, except `:`
|
||||||
namespacing to avoid the risk of clashes of identifiers between
|
and `NUL` (U+0000). The localpart SHOULD only consist of alphanumeric characters
|
||||||
different homeservers. There is no implication that the room in
|
(`A-Z`, `a-z`, `0-9`) when generating them. The `domain` is the [server name](#server-name)
|
||||||
question is still available at the corresponding homeserver.
|
of the homeserver which created the room - it is only used to reduce namespace
|
||||||
|
collisions. There is no implication that the room in question is still available
|
||||||
|
at the corresponding homeserver. Combined, the localpart, domain, and `!` sigil
|
||||||
|
MUST NOT exceed 255 bytes.
|
||||||
|
|
||||||
Room IDs are case-sensitive. They are not meant to be
|
When a room version requires the `domain`-less format, room IDs are simply the
|
||||||
human-readable. They are intended to be treated as fully opaque strings
|
[event ID](#event-ids) of the `m.room.create` event using `!` as the sigil instead
|
||||||
by clients.
|
of `$`. The grammar is otherwise inherited verbatim.
|
||||||
|
|
||||||
The localpart of a room ID (`opaque_id` above) may contain any valid
|
{{% boxes/note %}}
|
||||||
non-surrogate Unicode code points, including control characters, except `:` and `NUL`
|
Applications which previously relied upon the `domain` in a room ID can instead
|
||||||
(U+0000), but it is recommended to only include ASCII letters and
|
parse the [user IDs](#user-identifiers) found in the `m.room.create` event's `sender`.
|
||||||
digits (`A-Z`, `a-z`, `0-9`) when generating them.
|
|
||||||
|
|
||||||
The length of a room ID, including the `!` sigil and the domain, MUST
|
Though the `m.room.create` event's `additional_creators` (in `content`) may be
|
||||||
NOT exceed 255 bytes.
|
used when present, applications should take care when parsing or interpreting the
|
||||||
|
list. The user IDs in `additional_creators` will have correct grammar, but may
|
||||||
|
not be real users or may not belong to actual Matrix homeservers.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
#### Room Aliases
|
#### Room Aliases
|
||||||
|
|
||||||
|
|
@ -728,13 +749,13 @@ history (a permalink).
|
||||||
|
|
||||||
The Matrix URI scheme is defined as follows (`[]` enclose optional parts, `{}`
|
The Matrix URI scheme is defined as follows (`[]` enclose optional parts, `{}`
|
||||||
enclose variables):
|
enclose variables):
|
||||||
```
|
```nohighlight
|
||||||
matrix:[//{authority}/]{type}/{id without sigil}[/{type}/{id without sigil}...][?{query}][#{fragment}]
|
matrix:[//{authority}/]{type}/{id without sigil}[/{type}/{id without sigil}...][?{query}][#{fragment}]
|
||||||
```
|
```
|
||||||
|
|
||||||
As a schema, this can be represented as:
|
As a schema, this can be represented as:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
MatrixURI = "matrix:" hier-part [ "?" query ] [ "#" fragment ]
|
MatrixURI = "matrix:" hier-part [ "?" query ] [ "#" fragment ]
|
||||||
hier-part = [ "//" authority "/" ] path
|
hier-part = [ "//" authority "/" ] path
|
||||||
path = entity-descriptor ["/" entity-descriptor]
|
path = entity-descriptor ["/" entity-descriptor]
|
||||||
|
|
@ -844,7 +865,7 @@ below for more details.
|
||||||
A matrix.to URI has the following format, based upon the specification
|
A matrix.to URI has the following format, based upon the specification
|
||||||
defined in [RFC 3986](https://tools.ietf.org/html/rfc3986):
|
defined in [RFC 3986](https://tools.ietf.org/html/rfc3986):
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
https://matrix.to/#/<identifier>/<extra parameter>?<additional arguments>
|
https://matrix.to/#/<identifier>/<extra parameter>?<additional arguments>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@
|
||||||
title: "Application Service API"
|
title: "Application Service API"
|
||||||
weight: 30
|
weight: 30
|
||||||
type: docs
|
type: docs
|
||||||
|
description: |
|
||||||
|
The Matrix client-server API and server-server APIs provide a consistent,
|
||||||
|
self-contained federated messaging fabric but leave little room for custom
|
||||||
|
server-side behaviour such as gateways, filters, or extensible hooks. The
|
||||||
|
Application Service API defines a standard way to add this extensible
|
||||||
|
functionality, independent of the underlying homeserver implementation.
|
||||||
---
|
---
|
||||||
|
|
||||||
The Matrix client-server API and server-server APIs provide the means to
|
|
||||||
implement a consistent self-contained federated messaging fabric.
|
|
||||||
However, they provide limited means of implementing custom server-side
|
|
||||||
behaviour in Matrix (e.g. gateways, filters, extensible hooks etc). The
|
|
||||||
Application Service API (AS API) defines a standard API to allow such
|
|
||||||
extensible functionality to be implemented irrespective of the
|
|
||||||
underlying homeserver implementation.
|
|
||||||
|
|
||||||
## Application Services
|
## Application Services
|
||||||
|
|
||||||
Application services are passive and can only observe events from the
|
Application services are passive and can only observe events from the
|
||||||
|
|
@ -178,13 +176,13 @@ The application service API provides a transaction API for sending a
|
||||||
list of events. Each list of events includes a transaction ID, which
|
list of events. Each list of events includes a transaction ID, which
|
||||||
works as follows:
|
works as follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
Typical
|
Typical
|
||||||
HS ---> AS : Homeserver sends events with transaction ID T.
|
HS ---> AS : Homeserver sends events with transaction ID T.
|
||||||
<--- : Application Service sends back 200 OK.
|
<--- : Application Service sends back 200 OK.
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
AS ACK Lost
|
AS ACK Lost
|
||||||
HS ---> AS : Homeserver sends events with transaction ID T.
|
HS ---> AS : Homeserver sends events with transaction ID T.
|
||||||
<-/- : AS 200 OK is lost.
|
<-/- : AS 200 OK is lost.
|
||||||
|
|
@ -258,7 +256,7 @@ have been omitted for brevity):
|
||||||
|
|
||||||
**Typical**
|
**Typical**
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
||||||
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
||||||
HS <--- AS : 200 OK {}
|
HS <--- AS : 200 OK {}
|
||||||
|
|
@ -267,7 +265,7 @@ AS <--- HS : 200 OK {"duration_ms": 123}
|
||||||
|
|
||||||
**Incorrect `hs_token`**
|
**Incorrect `hs_token`**
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
||||||
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
||||||
HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"}
|
HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"}
|
||||||
|
|
@ -276,7 +274,7 @@ AS <--- HS : 502 Bad Gateway {"errcode": "M_BAD_STATUS", "status": 403, "body":
|
||||||
|
|
||||||
**Can't connect to appservice**
|
**Can't connect to appservice**
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
|
||||||
HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
|
||||||
AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"}
|
AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"}
|
||||||
|
|
@ -356,6 +354,7 @@ service would like to masquerade as.
|
||||||
Inputs:
|
Inputs:
|
||||||
- Application service token (`as_token`)
|
- Application service token (`as_token`)
|
||||||
- User ID in the AS namespace to act as.
|
- User ID in the AS namespace to act as.
|
||||||
|
- Device ID belonging to the User ID to act with.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- This applies to all aspects of the Client-Server API, except for
|
- This applies to all aspects of the Client-Server API, except for
|
||||||
|
|
@ -375,9 +374,19 @@ service's `user` namespaces. If the parameter is missing, the homeserver
|
||||||
is to assume the application service intends to act as the user implied
|
is to assume the application service intends to act as the user implied
|
||||||
by the `sender_localpart` property of the registration.
|
by the `sender_localpart` property of the registration.
|
||||||
|
|
||||||
|
{{% added-in v="1.17" %}} Application services MAY similarly masquerade
|
||||||
|
as a specific device ID belonging the user ID through use of the `device_id`
|
||||||
|
query string parameter on the request. If the given device ID is not known
|
||||||
|
to belong to the user, the server will return a 400 `M_UNKNOWN_DEVICE` error.
|
||||||
|
If no `user_id` is supplied, the `device_id` MUST belong to the user implied
|
||||||
|
by the `sender_localpart` property of the application service's registration.
|
||||||
|
If no `device_id` is supplied, the homeserver is to assume the request is
|
||||||
|
being made without a device ID and will fail to complete operations which
|
||||||
|
require a device ID (such as uploading one-time keys).
|
||||||
|
|
||||||
An example request would be:
|
An example request would be:
|
||||||
|
|
||||||
GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org
|
GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org&device_id=ABC123
|
||||||
Authorization: Bearer YourApplicationServiceTokenHere
|
Authorization: Bearer YourApplicationServiceTokenHere
|
||||||
|
|
||||||
#### Timestamp massaging
|
#### Timestamp massaging
|
||||||
|
|
@ -417,6 +426,8 @@ imports and similar behaviour).
|
||||||
|
|
||||||
#### Server admin style permissions
|
#### Server admin style permissions
|
||||||
|
|
||||||
|
{{% changed-in v="1.17" %}}
|
||||||
|
|
||||||
The homeserver needs to give the application service *full control* over
|
The homeserver needs to give the application service *full control* over
|
||||||
its namespace, both for users and for room aliases. This means that the
|
its namespace, both for users and for room aliases. This means that the
|
||||||
AS should be able to manage any users and room alias in its namespace. No additional API
|
AS should be able to manage any users and room alias in its namespace. No additional API
|
||||||
|
|
@ -433,33 +444,59 @@ achieved by including the `as_token` on a `/register` request, along
|
||||||
with a login type of `m.login.application_service` to set the desired
|
with a login type of `m.login.application_service` to set the desired
|
||||||
user ID without a password.
|
user ID without a password.
|
||||||
|
|
||||||
POST /_matrix/client/v3/register
|
```http
|
||||||
Authorization: Bearer YourApplicationServiceTokenHere
|
POST /_matrix/client/v3/register
|
||||||
|
Authorization: Bearer YourApplicationServiceTokenHere
|
||||||
|
```
|
||||||
|
|
||||||
Content:
|
```json
|
||||||
{
|
{
|
||||||
type: "m.login.application_service",
|
"type": "m.login.application_service",
|
||||||
username: "_irc_example"
|
"username": "_irc_example"
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Similarly, logging in as users needs API changes in order to allow the AS to
|
{{% boxes/note %}}
|
||||||
log in without needing the user's password. This is achieved by including the
|
{{% added-in v="1.17" %}}
|
||||||
`as_token` on a `/login` request, along with a login type of
|
Servers MUST still allow application services to use the `/register` endpoint
|
||||||
`m.login.application_service`:
|
with a login type of `m.login.application_service` even if they don't support
|
||||||
|
the [Legacy Authentication API](/client-server-api/#legacy-api).
|
||||||
|
|
||||||
|
In that case application services MUST set the `"inhibit_login": true` parameter
|
||||||
|
as they cannot use it to log in as users. If the `inhibit_login` parameter is
|
||||||
|
not set to `true`, the server MUST return a 400 HTTP status code with an
|
||||||
|
`M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
Similarly, logging in as users using the [Legacy authentication API](/client-server-api/#legacy-api)
|
||||||
|
needs API changes in order to allow the AS to log in without needing the user's
|
||||||
|
password. This is achieved by including the `as_token` on a `/login` request,
|
||||||
|
along with a login type of `m.login.application_service`:
|
||||||
|
|
||||||
{{% added-in v="1.2" %}}
|
{{% added-in v="1.2" %}}
|
||||||
|
|
||||||
POST /_matrix/client/v3/login
|
```http
|
||||||
Authorization: Bearer YourApplicationServiceTokenHere
|
POST /_matrix/client/v3/login
|
||||||
|
Authorization: Bearer YourApplicationServiceTokenHere
|
||||||
|
```
|
||||||
|
|
||||||
Content:
|
```json
|
||||||
{
|
{
|
||||||
type: "m.login.application_service",
|
"type": "m.login.application_service",
|
||||||
"identifier": {
|
"identifier": {
|
||||||
"type": "m.id.user",
|
"type": "m.id.user",
|
||||||
"user": "_irc_example"
|
"user": "_irc_example"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
Application services MUST NOT use the `/login` endpoint if the server doesn't
|
||||||
|
support the Legacy authentication API. If `/login` is called with the
|
||||||
|
`m.login.application_service` login type the server MUST return a 400 HTTP
|
||||||
|
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
Application services which attempt to create users or aliases *outside*
|
Application services which attempt to create users or aliases *outside*
|
||||||
of their defined namespaces, or log in as users outside of their defined
|
of their defined namespaces, or log in as users outside of their defined
|
||||||
|
|
@ -501,6 +538,38 @@ client-server endpoint.
|
||||||
|
|
||||||
{{% http-api spec="client-server" api="appservice_room_directory" %}}
|
{{% http-api spec="client-server" api="appservice_room_directory" %}}
|
||||||
|
|
||||||
|
#### Device management
|
||||||
|
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
|
||||||
|
Application services need to be able to create and delete devices to manage the
|
||||||
|
encryption for their users without having to rely on `/login`, which also
|
||||||
|
generates an access token for the user, and which might not be available for
|
||||||
|
homeservers that only support the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
||||||
|
|
||||||
|
##### Creating devices
|
||||||
|
|
||||||
|
Application services can use the [`PUT /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#put_matrixclientv3devicesdeviceid)
|
||||||
|
endpoint to create new devices.
|
||||||
|
|
||||||
|
##### Deleting devices
|
||||||
|
|
||||||
|
The following endpoints used to delete devices MUST NOT require [User-Interactive
|
||||||
|
Authentication](/client-server-api/#user-interactive-authentication-api) when
|
||||||
|
used by an application service:
|
||||||
|
|
||||||
|
* [`DELETE /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#delete_matrixclientv3devicesdeviceid)
|
||||||
|
* [`POST /_matrix/client/v3/delete_devices`](/client-server-api/#post_matrixclientv3delete_devices)
|
||||||
|
|
||||||
|
#### Cross-signing
|
||||||
|
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
|
||||||
|
Appservices need to be able to verify themselves and replace their cross-signing
|
||||||
|
keys, so the [`POST /_matrix/client/v3/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload)
|
||||||
|
endpoint MUST NOT require [User-Interactive Authentication](/client-server-api/#user-interactive-authentication-api)
|
||||||
|
when used by an application service, even if cross-signing keys already exist.
|
||||||
|
|
||||||
### Referencing messages from a third-party network
|
### Referencing messages from a third-party network
|
||||||
|
|
||||||
Application services should include an `external_url` in the `content`
|
Application services should include an `external_url` in the `content`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Changelog
|
title: Changelog
|
||||||
type: docs
|
type: docs
|
||||||
|
layout: changelog-index
|
||||||
weight: 1000
|
weight: 1000
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
103
content/changelog/v1.16.md
Normal file
103
content/changelog/v1.16.md
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
---
|
||||||
|
title: v1.16 Changelog
|
||||||
|
linkTitle: v1.16
|
||||||
|
type: docs
|
||||||
|
layout: changelog
|
||||||
|
outputs:
|
||||||
|
- html
|
||||||
|
- checklist
|
||||||
|
date: 2025-09-17
|
||||||
|
---
|
||||||
|
|
||||||
|
## Client-Server API
|
||||||
|
|
||||||
|
**Deprecations**
|
||||||
|
|
||||||
|
- Deprecate `m.set_avatar_url` and `m.set_displayname` capabilities, as per [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133). ([#2071](https://github.com/matrix-org/matrix-spec/issues/2071))
|
||||||
|
|
||||||
|
**Removed Endpoints**
|
||||||
|
|
||||||
|
- Remove unintentional intentional mentions in replies, as per [MSC4142](https://github.com/matrix-org/matrix-spec-proposals/pull/4142). ([#2210](https://github.com/matrix-org/matrix-spec/issues/2210))
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Update user profile endpoints to handle custom fields, and add a new `m.profile_fields` capability, as per [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133). ([#2071](https://github.com/matrix-org/matrix-spec/issues/2071))
|
||||||
|
- Add `format` query parameter to `GET /state/{eventType}/{stateKey}` to allow fetching metadata of a specific state event. ([#2175](https://github.com/matrix-org/matrix-spec/issues/2175))
|
||||||
|
- Add the `use_state_after` query parameter and `state_after` response property to `GET /sync`, as per [MSC4222](https://github.com/matrix-org/matrix-spec-proposals/issues/4222). ([#2187](https://github.com/matrix-org/matrix-spec/issues/2187))
|
||||||
|
- When upgrading rooms to [room version 12](/rooms/v12), `additional_creators` may be specified on the [`POST /_matrix/client/v3/rooms/{roomId}/upgrade`](/client-server-api/#post_matrixclientv3roomsroomidupgrade) endpoint, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- When creating rooms with [room version 12](/rooms/v12), the `trusted_private_chat` preset should merge the invitees into the supplied `content.additional_creators` in the resulting room, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- In [room version 12](/rooms/v12), the power level of room creators is now infinitely high as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- In [room version 12](/rooms/v12), room IDs no longer have a domain component as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- When creating rooms with [room version 12](/rooms/v12), the initial power levels will restrict the ability to upgrade rooms by default, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- Add a profile field for a user's time zone, as per [MSC4175](https://github.com/matrix-org/matrix-spec-proposals/pull/4175). ([#2206](https://github.com/matrix-org/matrix-spec/issues/2206))
|
||||||
|
- Invites and knocks are now expected to contain the `m.room.create` event in their stripped state entries, as per [MSC4311](https://github.com/matrix-org/matrix-spec-proposals/pull/4311). ([#2207](https://github.com/matrix-org/matrix-spec/issues/2207))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Clarify that `format` is required if `formatted_body` is specified. ([#2167](https://github.com/matrix-org/matrix-spec/issues/2167))
|
||||||
|
- The `latest_event` in an aggregated set of thread events uses the same format as the event itself. ([#2169](https://github.com/matrix-org/matrix-spec/issues/2169))
|
||||||
|
- Fix various typos throughout the specification. ([#2171](https://github.com/matrix-org/matrix-spec/issues/2171), [#2177](https://github.com/matrix-org/matrix-spec/issues/2177), [#2179](https://github.com/matrix-org/matrix-spec/issues/2179))
|
||||||
|
- Clarify that clients should replace events with the most recent replacement by `origin_server_ts`. ([#2190](https://github.com/matrix-org/matrix-spec/issues/2190))
|
||||||
|
- Fix `/sync` flow referencing incorrect parameter to use with `/messages`. ([#2195](https://github.com/matrix-org/matrix-spec/issues/2195))
|
||||||
|
- Clarify wording around the `world_readable` history visibility setting. Contributed by @HarHarLinks. ([#2204](https://github.com/matrix-org/matrix-spec/issues/2204))
|
||||||
|
|
||||||
|
|
||||||
|
## Server-Server API
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- `invite_room_state` and `knock_room_state` now have additional requirements and validation depending on the room version, as per [MSC4311](https://github.com/matrix-org/matrix-spec-proposals/pull/4311). ([#2207](https://github.com/matrix-org/matrix-spec/issues/2207))
|
||||||
|
|
||||||
|
|
||||||
|
## Application Service API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Identity Service API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Push Gateway API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Room Versions
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Room IDs in room version 12 are now the event ID of the create event with the normal room ID sigil (`!`), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- Room creators are formalized in room version 12 and have infinitely high power level, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- State Resolution is updated in room version 12 to reduce the opportunity for "state resets", as per [MSC4297](https://github.com/matrix-org/matrix-spec-proposals/pull/4297). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- The default room version is now room version 12, though servers SHOULD keep using room version 11 for a little while, as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
- Add [room version 12](/rooms/v12) as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193), [#2199](https://github.com/matrix-org/matrix-spec/issues/2199))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- In room versions 1 through 12, an event's `auth_events` have always needed to belong to the same room as per [MSC4307](https://github.com/matrix-org/matrix-spec-proposals/pull/4307). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
|
||||||
|
|
||||||
|
## Appendices
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Room IDs can now appear without a domain component in [room version 12](/rooms/v12), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291). ([#2193](https://github.com/matrix-org/matrix-spec/issues/2193))
|
||||||
|
|
||||||
|
|
||||||
|
## Internal Changes/Tooling
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Add "placeholder MSC" process definition. ([#2157](https://github.com/matrix-org/matrix-spec/issues/2157))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Declare the Application Service Registration schema to follow JSON Schema spec 2020-12. ([#2132](https://github.com/matrix-org/matrix-spec/issues/2132))
|
||||||
|
- Declare the event schemas to follow JSON Schema spec 2020-12. ([#2132](https://github.com/matrix-org/matrix-spec/issues/2132))
|
||||||
|
- Upgrade the docsy theme to version 0.12.0. ([#2160](https://github.com/matrix-org/matrix-spec/issues/2160))
|
||||||
|
- GitHub actions are now building the OpenAPI `spec/identity-service-api/api.json` file. ([#2172](https://github.com/matrix-org/matrix-spec/issues/2172))
|
||||||
|
- Minor fixes to JSON schemas. ([#2182](https://github.com/matrix-org/matrix-spec/issues/2182))
|
||||||
|
- Specify a correct spelling for "display name". ([#2189](https://github.com/matrix-org/matrix-spec/issues/2189))
|
||||||
|
- Fix a grammatical typo on the Matrix Spec Process documentation page. ([#2205](https://github.com/matrix-org/matrix-spec/issues/2205))
|
||||||
91
content/changelog/v1.17.md
Normal file
91
content/changelog/v1.17.md
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
---
|
||||||
|
title: v1.17 Changelog
|
||||||
|
linkTitle: v1.17
|
||||||
|
type: docs
|
||||||
|
layout: changelog
|
||||||
|
outputs:
|
||||||
|
- html
|
||||||
|
- checklist
|
||||||
|
date: 2025-12-18
|
||||||
|
---
|
||||||
|
|
||||||
|
## Client-Server API
|
||||||
|
|
||||||
|
**Removed Endpoints**
|
||||||
|
|
||||||
|
- Remove legacy mentions, as per [MSC4210](https://github.com/matrix-org/matrix-spec-proposals/issues/4210). ([#2186](https://github.com/matrix-org/matrix-spec/issues/2186))
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
|
||||||
|
- Add the `m.oauth` authentication type for User-Interactive Authentication, as per [MSC4312](https://github.com/matrix-org/matrix-spec-proposals/pull/4312). ([#2234](https://github.com/matrix-org/matrix-spec/issues/2234))
|
||||||
|
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Push rule IDs are globally unique within their kind. ([#2214](https://github.com/matrix-org/matrix-spec/issues/2214))
|
||||||
|
- Don't advertise `creator` field in description of room creation. ([#2215](https://github.com/matrix-org/matrix-spec/issues/2215))
|
||||||
|
- `room_id` is required for peeking via `/_matrix/client/v3/events`. ([#2216](https://github.com/matrix-org/matrix-spec/issues/2216))
|
||||||
|
- The `server-name` segment of MXC URIs is sanitised differently from the `media-id` segment. ([#2217](https://github.com/matrix-org/matrix-spec/issues/2217))
|
||||||
|
- Add note to each endpoint that uses capability negotiation. ([#2223](https://github.com/matrix-org/matrix-spec/issues/2223))
|
||||||
|
- Additional OpenGraph properties can be present in URL previews. ([#2225](https://github.com/matrix-org/matrix-spec/issues/2225))
|
||||||
|
- Clarify the special casing of membership events and redactions in power levels. ([#2231](https://github.com/matrix-org/matrix-spec/issues/2231))
|
||||||
|
- `M_RESOURCE_LIMIT_EXCEEDED` is now listed as a common error code. ([#2232](https://github.com/matrix-org/matrix-spec/issues/2232))
|
||||||
|
- Add `m.login.terms` to enumeration of authentication types. ([#2233](https://github.com/matrix-org/matrix-spec/issues/2233))
|
||||||
|
- Clarify how to use `state_after` ahead of declaring full support for its spec version. ([#2240](https://github.com/matrix-org/matrix-spec/issues/2240))
|
||||||
|
- `device_one_time_keys_count` is only optional if no unclaimed one-time keys exist. ([#2245](https://github.com/matrix-org/matrix-spec/issues/2245))
|
||||||
|
- Clarify that servers may choose not to use `M_USER_DEACTIVATED` at login time, for example for privacy reasons when they can't authenticate deactivated users. ([#2246](https://github.com/matrix-org/matrix-spec/issues/2246))
|
||||||
|
- Usage of the `event_id_only` format for push notifications is not mandatory. ([#2255](https://github.com/matrix-org/matrix-spec/issues/2255))
|
||||||
|
- Fix various typos throughout the specification. ([#2224](https://github.com/matrix-org/matrix-spec/issues/2224), [#2227](https://github.com/matrix-org/matrix-spec/issues/2227), [#2250](https://github.com/matrix-org/matrix-spec/issues/2250))
|
||||||
|
|
||||||
|
|
||||||
|
## Server-Server API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Application Service API
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
|
||||||
|
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Fix JSON formatting in the "Server admin style permissions" examples. ([#2213](https://github.com/matrix-org/matrix-spec/issues/2213))
|
||||||
|
|
||||||
|
|
||||||
|
## Identity Service API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Push Gateway API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Room Versions
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- In room versions 8 through 12, clarify that "sufficient permission to invite users" on restricted joins also includes being a joined member of the room. ([#2220](https://github.com/matrix-org/matrix-spec/issues/2220))
|
||||||
|
- In room versions 3 through 12, clarify that when you have the power to redact, it is possible to redact events that you don't have the power to send. ([#2249](https://github.com/matrix-org/matrix-spec/issues/2249))
|
||||||
|
|
||||||
|
|
||||||
|
## Appendices
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Internal Changes/Tooling
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Swapped icon for X (fka. twitter) to updated logo in footer. ([#2219](https://github.com/matrix-org/matrix-spec/issues/2219))
|
||||||
|
- Inline Olm & Megolm specifications. ([#2226](https://github.com/matrix-org/matrix-spec/issues/2226), [#2241](https://github.com/matrix-org/matrix-spec/issues/2241), [#2242](https://github.com/matrix-org/matrix-spec/issues/2242))
|
||||||
|
- Silence failing redocly-cli rule. ([#2238](https://github.com/matrix-org/matrix-spec/issues/2238))
|
||||||
|
- Use NPM Trusted Publishers for publishing `@matrix-org/spec` to npm. ([#2239](https://github.com/matrix-org/matrix-spec/issues/2239))
|
||||||
|
- Add version picker in the navbar. ([#2256](https://github.com/matrix-org/matrix-spec/issues/2256), [#2258](https://github.com/matrix-org/matrix-spec/issues/2258), [#2259](https://github.com/matrix-org/matrix-spec/issues/2259), [#2260](https://github.com/matrix-org/matrix-spec/issues/2260), [#2261](https://github.com/matrix-org/matrix-spec/issues/2261), [#2264](https://github.com/matrix-org/matrix-spec/issues/2264), [#2268](https://github.com/matrix-org/matrix-spec/issues/2268))
|
||||||
|
- Add a list of endpoints to the top of each spec page. ([#2262](https://github.com/matrix-org/matrix-spec/issues/2262))
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
title: "Client-Server API"
|
title: "Client-Server API"
|
||||||
weight: 10
|
weight: 10
|
||||||
type: docs
|
type: docs
|
||||||
|
description: |
|
||||||
|
The client-server API allows clients to send messages, control rooms and
|
||||||
|
synchronise conversation history. It is designed to support both lightweight
|
||||||
|
clients which store no state and lazy-load data from the server as required,
|
||||||
|
as well as heavyweight clients which maintain a full local persistent copy of
|
||||||
|
server state.
|
||||||
---
|
---
|
||||||
|
|
||||||
The client-server API allows clients to
|
|
||||||
send messages, control rooms and synchronise conversation history. It is
|
|
||||||
designed to support both lightweight clients which store no state and
|
|
||||||
lazy-load data from the server as required - as well as heavyweight
|
|
||||||
clients which maintain a full local persistent copy of server state.
|
|
||||||
|
|
||||||
## API Standards
|
## API Standards
|
||||||
|
|
||||||
{{% boxes/note %}}
|
{{% boxes/note %}}
|
||||||
|
|
@ -132,6 +132,21 @@ The server did not understand the request. This is expected to be returned with
|
||||||
a 404 HTTP status code if the endpoint is not implemented or a 405 HTTP status
|
a 404 HTTP status code if the endpoint is not implemented or a 405 HTTP status
|
||||||
code if the endpoint is implemented, but the incorrect HTTP method is used.
|
code if the endpoint is implemented, but the incorrect HTTP method is used.
|
||||||
|
|
||||||
|
`M_UNKNOWN_DEVICE`
|
||||||
|
{{% added-in v="1.17" %}} The device ID supplied by the application service does
|
||||||
|
not belong to the user ID during [identity assertion](/application-service-api/#identity-assertion).
|
||||||
|
|
||||||
|
`M_RESOURCE_LIMIT_EXCEEDED`
|
||||||
|
The request cannot be completed because the homeserver has reached a
|
||||||
|
resource limit imposed on it. For example, a homeserver held in a shared
|
||||||
|
hosting environment may reach a resource limit if it starts using too
|
||||||
|
much memory or disk space. The error MUST have an `admin_contact` field
|
||||||
|
to provide the user receiving the error a place to reach out to.
|
||||||
|
Typically, this error will appear on routes which attempt to modify
|
||||||
|
state (e.g.: sending messages, account data, etc) and not routes which
|
||||||
|
only read state (e.g.: [`/sync`](#get_matrixclientv3sync),
|
||||||
|
[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype), etc).
|
||||||
|
|
||||||
`M_UNKNOWN`
|
`M_UNKNOWN`
|
||||||
An unknown error has occurred.
|
An unknown error has occurred.
|
||||||
|
|
||||||
|
|
@ -217,17 +232,6 @@ The request or entity was too large.
|
||||||
The resource being requested is reserved by an application service, or
|
The resource being requested is reserved by an application service, or
|
||||||
the application service making the request has not created the resource.
|
the application service making the request has not created the resource.
|
||||||
|
|
||||||
`M_RESOURCE_LIMIT_EXCEEDED`
|
|
||||||
The request cannot be completed because the homeserver has reached a
|
|
||||||
resource limit imposed on it. For example, a homeserver held in a shared
|
|
||||||
hosting environment may reach a resource limit if it starts using too
|
|
||||||
much memory or disk space. The error MUST have an `admin_contact` field
|
|
||||||
to provide the user receiving the error a place to reach out to.
|
|
||||||
Typically, this error will appear on routes which attempt to modify
|
|
||||||
state (e.g.: sending messages, account data, etc) and not routes which
|
|
||||||
only read state (e.g.: [`/sync`](#get_matrixclientv3sync),
|
|
||||||
[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype), etc).
|
|
||||||
|
|
||||||
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
|
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
|
||||||
The user is unable to reject an invite to join the server notices room.
|
The user is unable to reject an invite to join the server notices room.
|
||||||
See the [Server Notices](#server-notices) module for more information.
|
See the [Server Notices](#server-notices) module for more information.
|
||||||
|
|
@ -473,8 +477,7 @@ the API that was used to obtain their current access token.
|
||||||
|
|
||||||
{{% boxes/note %}}
|
{{% boxes/note %}}
|
||||||
Currently the OAuth 2.0 API doesn't cover all the use cases of the legacy API,
|
Currently the OAuth 2.0 API doesn't cover all the use cases of the legacy API,
|
||||||
such as automated applications that cannot use a web browser, or
|
such as automated applications that cannot use a web browser.
|
||||||
user management by [application services](application-service-api/#server-admin-style-permissions).
|
|
||||||
{{% /boxes/note %}}
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
### Authentication API discovery
|
### Authentication API discovery
|
||||||
|
|
@ -498,6 +501,12 @@ user must do that directly in the homeserver's web UI. However, the client can
|
||||||
signal to the homeserver that the user wishes to create a new account with the
|
signal to the homeserver that the user wishes to create a new account with the
|
||||||
[`prompt=create`](#user-registration) parameter during authorization.
|
[`prompt=create`](#user-registration) parameter during authorization.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
Application services can use the `/register` endpoint to create users regardless
|
||||||
|
of the authentication API supported by the homeserver.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
### Login
|
### Login
|
||||||
|
|
||||||
With the legacy API, a client can obtain an access token by using one of the
|
With the legacy API, a client can obtain an access token by using one of the
|
||||||
|
|
@ -683,7 +692,7 @@ 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:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -729,7 +738,7 @@ 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:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
POST /_matrix/client/v3/endpoint HTTP/1.1
|
POST /_matrix/client/v3/endpoint HTTP/1.1
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -752,7 +761,7 @@ 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:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -786,7 +795,7 @@ 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:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -816,7 +825,7 @@ Content-Type: application/json
|
||||||
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:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 400 Bad request
|
HTTP/1.1 400 Bad request
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -855,7 +864,7 @@ must still give a 401 response to requests with no auth data.
|
||||||
At a high level, the requests made for an API call completing an auth
|
At a high level, the requests made for an API call completing an auth
|
||||||
flow with three stages will resemble the following diagram:
|
flow with three stages will resemble the following diagram:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
_______________________
|
_______________________
|
||||||
| Stage 0 |
|
| Stage 0 |
|
||||||
| No auth |
|
| No auth |
|
||||||
|
|
@ -902,6 +911,8 @@ This specification defines the following auth types:
|
||||||
- `m.login.msisdn`
|
- `m.login.msisdn`
|
||||||
- `m.login.dummy`
|
- `m.login.dummy`
|
||||||
- `m.login.registration_token`
|
- `m.login.registration_token`
|
||||||
|
- {{% added-in v="1.11" %}} `m.login.terms`
|
||||||
|
- {{% added-in v="1.17" %}} `m.oauth`
|
||||||
|
|
||||||
###### Password-based
|
###### Password-based
|
||||||
|
|
||||||
|
|
@ -913,7 +924,7 @@ This specification defines the following auth types:
|
||||||
To use this authentication type, clients should submit an auth dict as
|
To use this authentication type, clients should submit an auth dict as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"type": "m.login.password",
|
"type": "m.login.password",
|
||||||
"identifier": {
|
"identifier": {
|
||||||
|
|
@ -1163,7 +1174,7 @@ user during registration, if applicable.
|
||||||
|
|
||||||
1. A client might submit a registration request as follows:
|
1. A client might submit a registration request as follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
POST /_matrix/client/v3/register
|
POST /_matrix/client/v3/register
|
||||||
```
|
```
|
||||||
```json
|
```json
|
||||||
|
|
@ -1176,7 +1187,7 @@ user during registration, if applicable.
|
||||||
2. The server requires the user to accept some terms of service before
|
2. The server requires the user to accept some terms of service before
|
||||||
registration, so returns the following response:
|
registration, so returns the following response:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -1211,7 +1222,7 @@ user during registration, if applicable.
|
||||||
|
|
||||||
4. The client repeats the registration request, confirming that the user has
|
4. The client repeats the registration request, confirming that the user has
|
||||||
accepted the documents:
|
accepted the documents:
|
||||||
```
|
```nohighlight
|
||||||
POST /_matrix/client/v3/register
|
POST /_matrix/client/v3/register
|
||||||
```
|
```
|
||||||
```json
|
```json
|
||||||
|
|
@ -1226,7 +1237,7 @@ user during registration, if applicable.
|
||||||
```
|
```
|
||||||
|
|
||||||
5. All authentication steps have now completed, so the request is successful:
|
5. All authentication steps have now completed, so the request is successful:
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -1240,6 +1251,40 @@ user during registration, if applicable.
|
||||||
|
|
||||||
{{% definition path="api/client-server/definitions/m.login.terms_params" %}}
|
{{% definition path="api/client-server/definitions/m.login.terms_params" %}}
|
||||||
|
|
||||||
|
###### OAuth authentication
|
||||||
|
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|-------------------------------|-------------------------------------------------------------------|
|
||||||
|
| `m.oauth` | Authentication is supported by authorising via the homeserver's OAuth account management web UI. |
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
The `m.oauth` authentication type is currently only valid on the
|
||||||
|
[`/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload) endpoint.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
This authentication type provides homeservers the ability to guard access to
|
||||||
|
sensitive actions when the client has authenticated via the
|
||||||
|
[OAuth 2.0 API](/client-server-api/#oauth-20-api), which is otherwise not
|
||||||
|
compatible with User-Interactive Authentication (UIA). To do so, the server
|
||||||
|
returns a 401 response on the respective request, where the response body
|
||||||
|
includes `m.oauth` in the `flows` list, and the `m.oauth` property in the
|
||||||
|
`params` object has the structure [shown below](#definition-moauth-params).
|
||||||
|
|
||||||
|
The client is expected to open the contained URL to let the user confirm the
|
||||||
|
action in the homeserver's account management web UI. Once the user has done
|
||||||
|
so, the client submits an `auth` dict with just the `session`, as follows,
|
||||||
|
to complete the stage:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"session": "<session ID>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% definition path="api/client-server/definitions/m.oauth_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
|
||||||
|
|
@ -1522,6 +1567,10 @@ If the access token does correspond to an appservice, but the user id does
|
||||||
not lie within its namespace then the homeserver will respond with an
|
not lie within its namespace then the homeserver will respond with an
|
||||||
errcode of `M_EXCLUSIVE`.
|
errcode of `M_EXCLUSIVE`.
|
||||||
|
|
||||||
|
{{% added-in v="1.17" %}} If this login type is used and the server doesn't
|
||||||
|
support logging in via the Legacy authentication API, it MUST return a 400 HTTP
|
||||||
|
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
|
||||||
|
|
||||||
##### Login Fallback
|
##### Login Fallback
|
||||||
|
|
||||||
If a client does not recognize any or all login flows it can use the
|
If a client does not recognize any or all login flows it can use the
|
||||||
|
|
@ -1586,6 +1635,11 @@ because they don't have access to the user's credentials anymore.
|
||||||
The [User-Interactive Authentication API](#user-interactive-authentication-api)
|
The [User-Interactive Authentication API](#user-interactive-authentication-api)
|
||||||
is not compatible with the OAuth 2.0 API, so the endpoints that depend on it for
|
is not compatible with the OAuth 2.0 API, so the endpoints that depend on it for
|
||||||
authentication can't be used when an access token is obtained with this API.
|
authentication can't be used when an access token is obtained with this API.
|
||||||
|
|
||||||
|
The only exception to this is the
|
||||||
|
[`/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload)
|
||||||
|
endpoint which uses the [`m.oauth`](/client-server-api/#oauth-authentication)
|
||||||
|
authentication type.
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
**Sample flow**
|
**Sample flow**
|
||||||
|
|
@ -1647,7 +1701,7 @@ This authorization request URL must be opened in the user's browser:
|
||||||
|
|
||||||
Sample authorization request, with extra whitespaces for readability:
|
Sample authorization request, with extra whitespaces for readability:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
https://account.example.com/oauth2/auth?
|
https://account.example.com/oauth2/auth?
|
||||||
client_id = s6BhdRkqt3 &
|
client_id = s6BhdRkqt3 &
|
||||||
response_type = code &
|
response_type = code &
|
||||||
|
|
@ -1680,7 +1734,7 @@ used in the authorization request.
|
||||||
|
|
||||||
A successful authorization will have a `code` value, for example:
|
A successful authorization will have a `code` value, for example:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
|
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1692,7 +1746,7 @@ A failed authorization will have the following values:
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.&error_uri=https%3A%2F%2Ferrors.example.com%2F
|
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.&error_uri=https%3A%2F%2Ferrors.example.com%2F
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1717,7 +1771,7 @@ type, the expiration time, and the refresh token.
|
||||||
|
|
||||||
Sample token request:
|
Sample token request:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
POST /oauth2/token HTTP/1.1
|
POST /oauth2/token HTTP/1.1
|
||||||
Host: account.example.com
|
Host: account.example.com
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
@ -2040,7 +2094,7 @@ When generating a new `device_id`, the client SHOULD generate a random string
|
||||||
with enough entropy. It SHOULD only use characters from the unreserved character
|
with enough entropy. It SHOULD only use characters from the unreserved character
|
||||||
list defined by [RFC 3986 section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3):
|
list defined by [RFC 3986 section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3):
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~"
|
unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -2053,7 +2107,7 @@ In any case it MUST only use characters allowed by the OAuth 2.0 scope
|
||||||
definition in [RFC 6749 section 3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3),
|
definition in [RFC 6749 section 3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3),
|
||||||
which is defined as the following ASCII ranges:
|
which is defined as the following ASCII ranges:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
%x21 / %x23-5B / %x5D-7E
|
%x21 / %x23-5B / %x5D-7E
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -2195,7 +2249,7 @@ The body of the request includes the following parameters, encoded as
|
||||||
|
|
||||||
For example, revoking using the access token:
|
For example, revoking using the access token:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
POST /oauth2/revoke HTTP/1.1
|
POST /oauth2/revoke HTTP/1.1
|
||||||
Host: auth.example.com
|
Host: auth.example.com
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
@ -2240,7 +2294,7 @@ set to `true` on all but the following Client-Server APIs:
|
||||||
Servers MAY additionally include details of why the lock was applied in
|
Servers MAY additionally include details of why the lock was applied in
|
||||||
the `error` field.
|
the `error` field.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 401 Unauthorized
|
HTTP/1.1 401 Unauthorized
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -2320,7 +2374,7 @@ When a client attempts to perform an action while suspended, the server MUST
|
||||||
respond with a `403 Forbidden` error response with `M_USER_SUSPENDED` as the
|
respond with a `403 Forbidden` error response with `M_USER_SUSPENDED` as the
|
||||||
error code, as shown below:
|
error code, as shown below:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
HTTP/1.1 403 Forbidden
|
HTTP/1.1 403 Forbidden
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
@ -2491,8 +2545,66 @@ using an `unstable` version.
|
||||||
When this capability is not listed, clients should use `"1"` as the
|
When this capability is not listed, clients should use `"1"` as the
|
||||||
default and only stable `available` room version.
|
default and only stable `available` room version.
|
||||||
|
|
||||||
|
### `m.profile_fields` capability
|
||||||
|
|
||||||
|
{{% added-in v="1.16" %}}
|
||||||
|
|
||||||
|
This capability defines which [profile](#profiles) fields the user is
|
||||||
|
able to change.
|
||||||
|
|
||||||
|
The capability value has a required flag, `enabled`, and two optional lists, `allowed` and
|
||||||
|
`disallowed`.
|
||||||
|
|
||||||
|
When `enabled` is `false`, all profile fields are managed by the server
|
||||||
|
and the client is not permitted to make any changes.
|
||||||
|
|
||||||
|
When `enabled` is `true`, clients are permitted to modify profile fields,
|
||||||
|
subject to the restrictions implied by the OPTIONAL lists `allowed` and
|
||||||
|
`disallowed`.
|
||||||
|
|
||||||
|
If `allowed` is present, clients can modify only the fields
|
||||||
|
listed. They SHOULD assume all other fields to be managed by
|
||||||
|
the server. In this case, `disallowed` has no meaning and should be ignored.
|
||||||
|
|
||||||
|
If `disallowed` is present (and `allowed` is not), clients SHOULD assume
|
||||||
|
that the listed fields are managed by the server. Clients may modify any
|
||||||
|
fields that are *not* listed, provided `enabled` is `true`.
|
||||||
|
|
||||||
|
If neither `allowed` nor `disallowed` is present, clients can modify all fields
|
||||||
|
without restrictions, provided `enabled` is `true`.
|
||||||
|
|
||||||
|
When this capability is not listed, clients SHOULD assume the user is able to change
|
||||||
|
profile fields without any restrictions, provided the homeserver
|
||||||
|
advertises a specification version that includes the `m.profile_fields`
|
||||||
|
capability in the [`/versions`](/client-server-api/#get_matrixclientversions)
|
||||||
|
response.
|
||||||
|
|
||||||
|
An example of the capability API's response for this capability is:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"capabilities": {
|
||||||
|
"m.profile_fields": {
|
||||||
|
"enabled": true,
|
||||||
|
"disallowed": ["displayname"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `m.set_displayname` capability
|
### `m.set_displayname` capability
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% changed-in v="1.16" %}}
|
||||||
|
This capability is now deprecated. Clients SHOULD use the
|
||||||
|
[`m.profile_fields`](/client-server-api/#mprofile_fields-capability)
|
||||||
|
capability instead.
|
||||||
|
|
||||||
|
For backwards compatibility, servers that forbid setting the
|
||||||
|
`displayname` profile field in the `m.profile_fields` capability
|
||||||
|
MUST still present this capability with `"enabled": false`.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
This capability has a single flag, `enabled`, to denote whether the user
|
This capability has a single flag, `enabled`, to denote whether the user
|
||||||
is able to change their own display name via profile endpoints. Cases for
|
is able to change their own display name via profile endpoints. Cases for
|
||||||
disabling might include users mapped from external identity/directory
|
disabling might include users mapped from external identity/directory
|
||||||
|
|
@ -2517,6 +2629,17 @@ An example of the capability API's response for this capability is:
|
||||||
|
|
||||||
### `m.set_avatar_url` capability
|
### `m.set_avatar_url` capability
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% changed-in v="1.16" %}}
|
||||||
|
This capability is now deprecated. Clients SHOULD use the
|
||||||
|
[`m.profile_fields`](/client-server-api/#mprofile_fields-capability)
|
||||||
|
capability instead.
|
||||||
|
|
||||||
|
For backwards compatibility, servers that forbid setting the
|
||||||
|
`avatar_url` profile field in the `m.profile_fields` capability
|
||||||
|
MUST still present this capability with `"enabled": false`.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
This capability has a single flag, `enabled`, to denote whether the user
|
This capability has a single flag, `enabled`, to denote whether the user
|
||||||
is able to change their own avatar via profile endpoints. Cases for
|
is able to change their own avatar via profile endpoints. Cases for
|
||||||
disabling might include users mapped from external identity/directory
|
disabling might include users mapped from external identity/directory
|
||||||
|
|
@ -2749,6 +2872,14 @@ should be represented as stripped state events when possible:
|
||||||
* [`m.room.canonical_alias`](#mroomcanonical_alias)
|
* [`m.room.canonical_alias`](#mroomcanonical_alias)
|
||||||
* [`m.room.encryption`](#mroomencryption)
|
* [`m.room.encryption`](#mroomencryption)
|
||||||
|
|
||||||
|
{{% changed-in v="1.16" %}} The `m.room.create` event is now **required** in
|
||||||
|
the following places:
|
||||||
|
* [`invite_state`](#get_matrixclientv3sync_response-200_invited-room) and
|
||||||
|
[`knock_state`](#get_matrixclientv3sync_response-200_knocked-room) on
|
||||||
|
[`/sync`](#get_matrixclientv3sync) responses.
|
||||||
|
* On [`m.room.member`](#mroommember) events, the `invite_room_state`
|
||||||
|
and `knock_room_state` under `unsigned` on the event.
|
||||||
|
|
||||||
{{% boxes/note %}}
|
{{% boxes/note %}}
|
||||||
Clients should inspect the list of stripped state events and not assume any
|
Clients should inspect the list of stripped state events and not assume any
|
||||||
particular event is present. The server might include events not described
|
particular event is present. The server might include events not described
|
||||||
|
|
@ -2779,6 +2910,12 @@ events are not signed and could theoretically be modified, or outdated due to
|
||||||
updates not being sent.
|
updates not being sent.
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
{{% added-in v="1.16" %}} Servers cannot pass through what they receive over
|
||||||
|
federation to clients as stripped state. Servers are expected to prune the events
|
||||||
|
into the stripped state schema below before passing the details onto clients.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
{{% event-fields event_type="stripped_state" %}}
|
{{% event-fields event_type="stripped_state" %}}
|
||||||
|
|
||||||
### Size limits
|
### Size limits
|
||||||
|
|
@ -2837,7 +2974,7 @@ most recent message events for each room, as well as the state of the
|
||||||
room at the start of the returned timeline. The response also includes a
|
room at the start of the returned timeline. The response also includes a
|
||||||
`next_batch` field, which should be used as the value of the `since`
|
`next_batch` field, which should be used as the value of the `since`
|
||||||
parameter in the next call to `/sync`. Finally, the response includes,
|
parameter in the next call to `/sync`. Finally, the response includes,
|
||||||
for each room, a `prev_batch` field, which can be passed as a `start`
|
for each room, a `prev_batch` field, which can be passed as a `from`/`to`
|
||||||
parameter to the [`/rooms/<room_id>/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) API to retrieve earlier
|
parameter to the [`/rooms/<room_id>/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) API to retrieve earlier
|
||||||
messages.
|
messages.
|
||||||
|
|
||||||
|
|
@ -2845,7 +2982,7 @@ For example, a `/sync` request might return a range of four events
|
||||||
`E2`, `E3`, `E4` and `E5` within a given room, omitting two prior events
|
`E2`, `E3`, `E4` and `E5` within a given room, omitting two prior events
|
||||||
`E0` and `E1`. This can be visualised as follows:
|
`E0` and `E1`. This can be visualised as follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
|
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
|
||||||
^ ^
|
^ ^
|
||||||
| |
|
| |
|
||||||
|
|
@ -2863,7 +3000,7 @@ deprecated `/events` API) support long-polling in this way.
|
||||||
Continuing the example above, an incremental sync might report
|
Continuing the example above, an incremental sync might report
|
||||||
a single new event `E6`. The response can be visualised as:
|
a single new event `E6`. The response can be visualised as:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]
|
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]
|
||||||
^ ^
|
^ ^
|
||||||
| |
|
| |
|
||||||
|
|
@ -2887,7 +3024,7 @@ the `since` parameter. The server knows about four new events, `E7`, `E8`,
|
||||||
the server sends a `limited` response containing `E8`, `E9` and `E10`but
|
the server sends a `limited` response containing `E8`, `E9` and `E10`but
|
||||||
omitting `E7`. This forms a gap, which we can see in the visualisation:
|
omitting `E7`. This forms a gap, which we can see in the visualisation:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
| gap |
|
| gap |
|
||||||
| <-> |
|
| <-> |
|
||||||
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
|
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
|
||||||
|
|
@ -2982,29 +3119,29 @@ to another.
|
||||||
|
|
||||||
Valid requests look like:
|
Valid requests look like:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.example.event
|
PUT /rooms/!roomid:domain/state/m.example.event
|
||||||
{ "key" : "without a state key" }
|
{ "key" : "without a state key" }
|
||||||
```
|
```
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
|
||||||
{ "key" : "with 'foo' as the state key" }
|
{ "key" : "with 'foo' as the state key" }
|
||||||
```
|
```
|
||||||
|
|
||||||
In contrast, these requests are invalid:
|
In contrast, these requests are invalid:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
POST /rooms/!roomid:domain/state/m.example.event/
|
POST /rooms/!roomid:domain/state/m.example.event/
|
||||||
{ "key" : "cannot use POST here" }
|
{ "key" : "cannot use POST here" }
|
||||||
```
|
```
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
|
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
|
||||||
{ "key" : "txnIds are not supported" }
|
{ "key" : "txnIds are not supported" }
|
||||||
```
|
```
|
||||||
|
|
||||||
Care should be taken to avoid setting the wrong `state key`:
|
Care should be taken to avoid setting the wrong `state key`:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.another.example.event/11
|
PUT /rooms/!roomid:domain/state/m.another.example.event/11
|
||||||
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
|
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
|
||||||
```
|
```
|
||||||
|
|
@ -3012,7 +3149,7 @@ PUT /rooms/!roomid:domain/state/m.another.example.event/11
|
||||||
The `state_key` is often used to store state about individual users, by
|
The `state_key` is often used to store state about individual users, by
|
||||||
using the user ID as the `state_key` value. For example:
|
using the user ID as the `state_key` value. For example:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
|
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
|
||||||
{ "animal" : "cat", "reason": "fluffy" }
|
{ "animal" : "cat", "reason": "fluffy" }
|
||||||
```
|
```
|
||||||
|
|
@ -3020,7 +3157,7 @@ PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
|
||||||
In some cases, there may be no need for a `state_key`, so it can be
|
In some cases, there may be no need for a `state_key`, so it can be
|
||||||
omitted:
|
omitted:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
PUT /rooms/!roomid:domain/state/m.room.bgd.color
|
PUT /rooms/!roomid:domain/state/m.room.bgd.color
|
||||||
{ "color": "red", "hex": "#ff0000" }
|
{ "color": "red", "hex": "#ff0000" }
|
||||||
```
|
```
|
||||||
|
|
@ -3303,10 +3440,10 @@ Unspecified room types are permitted through the use of
|
||||||
### Creation
|
### Creation
|
||||||
|
|
||||||
The homeserver will create an `m.room.create` event when a room is
|
The homeserver will create an `m.room.create` event when a room is
|
||||||
created, which serves as the root of the event graph for this room. This
|
created, which serves as the root of the event graph for this room. The
|
||||||
event also has a `creator` key which contains the user ID of the room
|
event `sender` is the user ID of the room creator. The server will also
|
||||||
creator. It will also generate several other events in order to manage
|
generate several other events in order to manage permissions in this room.
|
||||||
permissions in this room. This includes:
|
This includes:
|
||||||
|
|
||||||
- `m.room.power_levels` : Sets the power levels of users and required power
|
- `m.room.power_levels` : Sets the power levels of users and required power
|
||||||
levels for various actions within the room such as sending events.
|
levels for various actions within the room such as sending events.
|
||||||
|
|
@ -3345,27 +3482,49 @@ request.
|
||||||
|
|
||||||
### Permissions
|
### Permissions
|
||||||
|
|
||||||
{{% boxes/note %}}
|
{{% changed-in v="1.16" %}} Updated section to discuss creator power level
|
||||||
This section is a work in progress.
|
in room version 12 and beyond.
|
||||||
{{% /boxes/note %}}
|
|
||||||
|
|
||||||
Permissions for rooms are done via the concept of power levels - to do
|
Permissions for rooms are done via the concept of power levels - to do
|
||||||
any action in a room a user must have a suitable power level. Power
|
any action in a room a user must have a suitable power level. Power
|
||||||
levels are stored as state events in a given room. The power levels
|
levels are stored as state events in a given room. The power levels
|
||||||
required for operations and the power levels for users are defined in
|
required for operations and the power levels assigned to specific users
|
||||||
`m.room.power_levels`, where both a default and specific users' power
|
are defined in the `m.room.power_levels` state event. The `m.room.power_levels`
|
||||||
levels can be set. By default all users have a power level of 0, other
|
state event additionally defines some defaults, though room creators
|
||||||
than the room creator whose power level defaults to 100. Users can grant
|
are special in that:
|
||||||
other users increased power levels up to their own power level. For
|
|
||||||
example, user A with a power level of 50 could increase the power level
|
|
||||||
of user B to a maximum of level 50. Power levels for users are tracked
|
|
||||||
per-room even if the user is not present in the room. The keys contained
|
|
||||||
in `m.room.power_levels` determine the levels required for certain
|
|
||||||
operations such as kicking, banning and sending state events. See
|
|
||||||
[m.room.power\_levels](#room-events) for more information.
|
|
||||||
|
|
||||||
Clients may wish to assign names to particular power levels. A suggested
|
* In [room versions](/rooms) 1 through 11, room creators by default
|
||||||
mapping is as follows: - 0 User - 50 Moderator - 100 Admin
|
have power level 100 but still can have that level changed by power level
|
||||||
|
events, by the same rules as other members.
|
||||||
|
* In [room version 12](/rooms/v12) (and beyond), room creators are
|
||||||
|
*not* specified in the power levels event and have an infinitely high
|
||||||
|
power level that is immutable. After room creation, users
|
||||||
|
cannot be given this same infinitely high power level.
|
||||||
|
|
||||||
|
Users can grant other users increased power levels up to their own
|
||||||
|
power level (or the maximum allowable integer for the room when their
|
||||||
|
power level is infinitely high). For example, user A with a power level
|
||||||
|
of 50 could increase the power level of user B to a maximum of level 50.
|
||||||
|
Power levels for users are tracked per-room even if the user is not
|
||||||
|
present in the room. The keys contained in `m.room.power_levels` determine
|
||||||
|
the levels required for certain operations such as kicking, banning, and
|
||||||
|
sending state events. See [`m.room.power_levels`](#mroompower_levels) for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
Clients may wish to assign names to particular power levels. Most rooms
|
||||||
|
will use the default power level hierarchy assigned during room creation,
|
||||||
|
but rooms may still deviate slightly.
|
||||||
|
|
||||||
|
A suggested mapping is as follows:
|
||||||
|
|
||||||
|
* 0 to `state_default-1` (typically 49): User
|
||||||
|
* `state_default` to the level required to send `m.room.power_levels` events
|
||||||
|
minus 1 (typically 99): Moderator
|
||||||
|
* The level required send `m.room.power_levels` events and above: Administrator
|
||||||
|
* Creators of the room, in room version 12 and beyond: Creator
|
||||||
|
|
||||||
|
Clients may also wish to distinguish "above admin" power levels based on the
|
||||||
|
level required to send `m.room.tombstone` events.
|
||||||
|
|
||||||
### Room membership
|
### Room membership
|
||||||
|
|
||||||
|
|
@ -3803,42 +3962,42 @@ operations and run in a resource constrained environment. Like embedded
|
||||||
applications, they are not intended to be fully-fledged communication
|
applications, they are not intended to be fully-fledged communication
|
||||||
systems.
|
systems.
|
||||||
|
|
||||||
{{% cs-module name="instant_messaging" %}}
|
{{% cs-module name="Instant Messaging" filename="instant_messaging" %}}
|
||||||
{{% cs-module name="rich_replies" %}}
|
{{% cs-module name="Rich replies" filename="rich_replies" %}}
|
||||||
{{% cs-module name="voip_events" %}}
|
{{% cs-module name="Voice over IP" filename="voip_events" %}}
|
||||||
{{% cs-module name="typing_notifications" %}}
|
{{% cs-module name="Typing Notifications" filename="typing_notifications" %}}
|
||||||
{{% cs-module name="receipts" %}}
|
{{% cs-module name="Receipts" filename="receipts" %}}
|
||||||
{{% cs-module name="read_markers" %}}
|
{{% cs-module name="Read and unread markers" filename="read_markers" %}}
|
||||||
{{% cs-module name="presence" %}}
|
{{% cs-module name="Presence" filename="presence" %}}
|
||||||
{{% cs-module name="content_repo" %}}
|
{{% cs-module name="Content repository" filename="content_repo" %}}
|
||||||
{{% cs-module name="send_to_device" %}}
|
{{% cs-module name="Send-to-Device messaging" filename="send_to_device" %}}
|
||||||
{{% cs-module name="device_management" %}}
|
{{% cs-module name="Device Management" filename="device_management" %}}
|
||||||
{{% cs-module name="end_to_end_encryption" %}}
|
{{% cs-module name="End-to-End Encryption" filename="end_to_end_encryption" %}}
|
||||||
{{% cs-module name="secrets" %}}
|
{{% cs-module name="Secrets" filename="secrets" %}}
|
||||||
{{% cs-module name="history_visibility" %}}
|
{{% cs-module name="Room History Visibility" filename="history_visibility" %}}
|
||||||
{{% cs-module name="push" %}}
|
{{% cs-module name="Push Notifications" filename="push" %}}
|
||||||
{{% cs-module name="third_party_invites" %}}
|
{{% cs-module name="Third-party invites" filename="third_party_invites" %}}
|
||||||
{{% cs-module name="search" %}}
|
{{% cs-module name="Server Side Search" filename="search" %}}
|
||||||
{{% cs-module name="guest_access" %}}
|
{{% cs-module name="Guest Access" filename="guest_access" %}}
|
||||||
{{% cs-module name="room_previews" %}}
|
{{% cs-module name="Room Previews" filename="room_previews" %}}
|
||||||
{{% cs-module name="tags" %}}
|
{{% cs-module name="Room Tagging" filename="tags" %}}
|
||||||
{{% cs-module name="account_data" %}}
|
{{% cs-module name="Client Config" filename="account_data" %}}
|
||||||
{{% cs-module name="admin" %}}
|
{{% cs-module name="Server Administration" filename="admin" %}}
|
||||||
{{% cs-module name="event_context" %}}
|
{{% cs-module name="Event Context" filename="event_context" %}}
|
||||||
{{% cs-module name="sso_login" %}}
|
{{% cs-module name="SSO client login/authentication" filename="sso_login" %}}
|
||||||
{{% cs-module name="dm" %}}
|
{{% cs-module name="Direct Messaging" filename="dm" %}}
|
||||||
{{% cs-module name="ignore_users" %}}
|
{{% cs-module name="Ignoring Users" filename="ignore_users" %}}
|
||||||
{{% cs-module name="stickers" %}}
|
{{% cs-module name="Sticker Messages" filename="stickers" %}}
|
||||||
{{% cs-module name="report_content" %}}
|
{{% cs-module name="Reporting Content" filename="report_content" %}}
|
||||||
{{% cs-module name="third_party_networks" %}}
|
{{% cs-module name="Third-party Networks" filename="third_party_networks" %}}
|
||||||
{{% cs-module name="openid" %}}
|
{{% cs-module name="OpenID" filename="openid" %}}
|
||||||
{{% cs-module name="server_acls" %}}
|
{{% cs-module name="Server Access Control Lists (ACLs) for rooms" filename="server_acls" %}}
|
||||||
{{% cs-module name="mentions" %}}
|
{{% cs-module name="User and room mentions" filename="mentions" %}}
|
||||||
{{% cs-module name="room_upgrades" %}}
|
{{% cs-module name="Room Upgrades" filename="room_upgrades" %}}
|
||||||
{{% cs-module name="server_notices" %}}
|
{{% cs-module name="Server Notices" filename="server_notices" %}}
|
||||||
{{% cs-module name="moderation_policies" %}}
|
{{% cs-module name="Moderation policy lists" filename="moderation_policies" %}}
|
||||||
{{% cs-module name="spaces" %}}
|
{{% cs-module name="Spaces" filename="spaces" %}}
|
||||||
{{% cs-module name="event_replacements" %}}
|
{{% cs-module name="Event replacements" filename="event_replacements" %}}
|
||||||
{{% cs-module name="event_annotations" %}}
|
{{% cs-module name="Event annotations and reactions" filename="event_annotations" %}}
|
||||||
{{% cs-module name="threading" %}}
|
{{% cs-module name="Threading" filename="threading" %}}
|
||||||
{{% cs-module name="reference_relations" %}}
|
{{% cs-module name="Reference relations" filename="reference_relations" %}}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ specification.
|
||||||
Content locations are represented as Matrix Content (`mxc://`) URIs. They
|
Content locations are represented as Matrix Content (`mxc://`) URIs. They
|
||||||
look like:
|
look like:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
mxc://<server-name>/<media-id>
|
mxc://<server-name>/<media-id>
|
||||||
|
|
||||||
<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
|
<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
|
||||||
|
|
@ -134,9 +134,14 @@ entity isn't in the room.
|
||||||
`mxc://` URIs are vulnerable to directory traversal attacks such as
|
`mxc://` URIs are vulnerable to directory traversal attacks such as
|
||||||
`mxc://127.0.0.1/../../../some_service/etc/passwd`. This would cause the
|
`mxc://127.0.0.1/../../../some_service/etc/passwd`. This would cause the
|
||||||
target homeserver to try to access and return this file. As such,
|
target homeserver to try to access and return this file. As such,
|
||||||
homeservers MUST sanitise `mxc://` URIs by allowing only alphanumeric
|
homeservers MUST sanitise `mxc://` URIs by:
|
||||||
(`A-Za-z0-9`), `_` and `-` characters in the `server-name` and
|
|
||||||
`media-id` values. This set of whitelisted characters allows URL-safe
|
- restricting the `server-name` segment to valid
|
||||||
|
[server names](/appendices/#server-name)
|
||||||
|
- allowing only alphanumeric (`A-Za-z0-9`), `_` and `-` characters in
|
||||||
|
the `media-id` segment
|
||||||
|
|
||||||
|
The resulting set of whitelisted characters allows URL-safe
|
||||||
base64 encodings specified in RFC 4648. Applying this character
|
base64 encodings specified in RFC 4648. Applying this character
|
||||||
whitelist is preferable to blacklisting `.` and `/` as there are
|
whitelist is preferable to blacklisting `.` and `/` as there are
|
||||||
techniques around blacklisted characters (percent-encoded characters,
|
techniques around blacklisted characters (percent-encoded characters,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ exchange fingerprints between users to build a web of trust.
|
||||||
device. This may include long-term identity keys, and/or one-time
|
device. This may include long-term identity keys, and/or one-time
|
||||||
keys.
|
keys.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+----------+ +--------------+
|
+----------+ +--------------+
|
||||||
| Bob's HS | | Bob's Device |
|
| Bob's HS | | Bob's Device |
|
||||||
+----------+ +--------------+
|
+----------+ +--------------+
|
||||||
|
|
@ -29,7 +29,7 @@ keys.
|
||||||
|
|
||||||
2) Alice requests Bob's public identity keys and supported algorithms.
|
2) Alice requests Bob's public identity keys and supported algorithms.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+----------------+ +------------+ +----------+
|
+----------------+ +------------+ +----------+
|
||||||
| Alice's Device | | Alice's HS | | Bob's HS |
|
| Alice's Device | | Alice's HS | | Bob's HS |
|
||||||
+----------------+ +------------+ +----------+
|
+----------------+ +------------+ +----------+
|
||||||
|
|
@ -40,7 +40,7 @@ keys.
|
||||||
|
|
||||||
3) Alice selects an algorithm and claims any one-time keys needed.
|
3) Alice selects an algorithm and claims any one-time keys needed.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+----------------+ +------------+ +----------+
|
+----------------+ +------------+ +----------+
|
||||||
| Alice's Device | | Alice's HS | | Bob's HS |
|
| Alice's Device | | Alice's HS | | Bob's HS |
|
||||||
+----------------+ +------------+ +----------+
|
+----------------+ +------------+ +----------+
|
||||||
|
|
@ -491,7 +491,7 @@ this example, Bob's device sends the `m.key.verification.start`, Alice's device
|
||||||
could also send that message. As well, the order of the
|
could also send that message. As well, the order of the
|
||||||
`m.key.verification.done` messages could be reversed.
|
`m.key.verification.done` messages could be reversed.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+---------------+ +---------------+ +-------------+ +-------------+
|
+---------------+ +---------------+ +-------------+ +-------------+
|
||||||
| AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 |
|
| AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 |
|
||||||
+---------------+ +---------------+ +-------------+ +-------------+
|
+---------------+ +---------------+ +-------------+ +-------------+
|
||||||
|
|
@ -695,7 +695,7 @@ The process between Alice and Bob verifying each other would be:
|
||||||
The wire protocol looks like the following between Alice and Bob's
|
The wire protocol looks like the following between Alice and Bob's
|
||||||
devices:
|
devices:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+-------------+ +-----------+
|
+-------------+ +-----------+
|
||||||
| AliceDevice | | BobDevice |
|
| AliceDevice | | BobDevice |
|
||||||
+-------------+ +-----------+
|
+-------------+ +-----------+
|
||||||
|
|
@ -969,7 +969,7 @@ she can trust Bob's device if:
|
||||||
|
|
||||||
The following diagram illustrates how keys are signed:
|
The following diagram illustrates how keys are signed:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+------------------+ .................. +----------------+
|
+------------------+ .................. +----------------+
|
||||||
| +--------------+ | .................. : | +------------+ |
|
| +--------------+ | .................. : | +------------+ |
|
||||||
| | v v v : : v v v | |
|
| | v v v : : v v v | |
|
||||||
|
|
@ -1000,7 +1000,7 @@ the user who created them.
|
||||||
The following diagram illustrates Alice's view, hiding the keys and
|
The following diagram illustrates Alice's view, hiding the keys and
|
||||||
signatures that she cannot see:
|
signatures that she cannot see:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+------------------+ +----------------+ +----------------+
|
+------------------+ +----------------+ +----------------+
|
||||||
| +--------------+ | | | | +------------+ |
|
| +--------------+ | | | | +------------+ |
|
||||||
| | v v | v v v | |
|
| | v v | v v v | |
|
||||||
|
|
@ -1124,7 +1124,7 @@ The process between Alice and Bob verifying each other would be:
|
||||||
framework as described above.
|
framework as described above.
|
||||||
3. Alice's client displays a QR code that Bob is able to scan if Bob's client
|
3. Alice's client displays a QR code that Bob is able to scan if Bob's client
|
||||||
indicated the ability to scan, an option to scan Bob's QR code if her client
|
indicated the ability to scan, an option to scan Bob's QR code if her client
|
||||||
is able to scan. Bob's client prompts displays a QR code that Alice can
|
is able to scan. Bob's client displays a QR code that Alice can
|
||||||
scan if Alice's client indicated the ability to scan, and an option to scan
|
scan if Alice's client indicated the ability to scan, and an option to scan
|
||||||
Alice's QR code if his client is able to scan. The format for the QR code
|
Alice's QR code if his client is able to scan. The format for the QR code
|
||||||
is described below. Other options, like starting SAS Emoji verification,
|
is described below. Other options, like starting SAS Emoji verification,
|
||||||
|
|
@ -1218,7 +1218,7 @@ The binary segment MUST be of the following form:
|
||||||
|
|
||||||
For example, if Alice displays a QR code encoding the following binary data:
|
For example, if Alice displays a QR code encoding the following binary data:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
"MATRIX" |ver|mode| len | event ID
|
"MATRIX" |ver|mode| len | event ID
|
||||||
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
|
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
|
||||||
| user's cross-signing key | other user's cross-signing key | shared secret
|
| user's cross-signing key | other user's cross-signing key | shared secret
|
||||||
|
|
@ -1457,8 +1457,8 @@ readers without adding any useful extra information.
|
||||||
##### `m.olm.v1.curve25519-aes-sha2`
|
##### `m.olm.v1.curve25519-aes-sha2`
|
||||||
|
|
||||||
The name `m.olm.v1.curve25519-aes-sha2` corresponds to version 1 of the
|
The name `m.olm.v1.curve25519-aes-sha2` corresponds to version 1 of the
|
||||||
Olm ratchet, as defined by the [Olm
|
Olm ratchet, as defined by the [Olm specification](/olm-megolm/olm).
|
||||||
specification](http://matrix.org/docs/spec/olm.html). This uses:
|
This uses:
|
||||||
|
|
||||||
- Curve25519 for the initial key agreement.
|
- Curve25519 for the initial key agreement.
|
||||||
- HKDF-SHA-256 for ratchet key derivation.
|
- HKDF-SHA-256 for ratchet key derivation.
|
||||||
|
|
@ -1631,8 +1631,8 @@ This is due to a deprecation of the fields. See
|
||||||
{{% changed-in v="1.3" %}}
|
{{% changed-in v="1.3" %}}
|
||||||
|
|
||||||
The name `m.megolm.v1.aes-sha2` corresponds to version 1 of the Megolm
|
The name `m.megolm.v1.aes-sha2` corresponds to version 1 of the Megolm
|
||||||
ratchet, as defined by the [Megolm
|
ratchet, as defined by the [Megolm specification](/olm-megolm/megolm).
|
||||||
specification](http://matrix.org/docs/spec/megolm.html). This uses:
|
This uses:
|
||||||
|
|
||||||
- HMAC-SHA-256 for the hash ratchet.
|
- HMAC-SHA-256 for the hash ratchet.
|
||||||
- HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated HMAC-SHA-256
|
- HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated HMAC-SHA-256
|
||||||
|
|
@ -1775,17 +1775,16 @@ property is required for inclusion, though previous versions of the
|
||||||
specification did not have it. In addition to `/versions`, this can be
|
specification did not have it. In addition to `/versions`, this can be
|
||||||
a way to identify the server's support for fallback keys.
|
a way to identify the server's support for fallback keys.
|
||||||
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
|----------------------------------|--------------------|------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------|
|
||||||
| device_lists | DeviceLists | Optional. Information on e2e device updates. Note: only present on an incremental sync. |
|
| device_lists | DeviceLists | Optional. Information on e2e device updates. Note: only present on an incremental sync. |
|
||||||
| device_one_time_keys_count | {string: integer} | Optional. For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device. If an algorithm is unlisted, the count for that algorithm is assumed to be zero. If this entire parameter is missing, the count for all algorithms is assumed to be zero. |
|
| device_one_time_keys_count | {string: integer} | **Required if any unclaimed one-time keys exist.** For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device. If the count for an algorithm is zero, servers MAY omit that algorithm. If the count for all algorithms is zero, servers MAY omit this parameter entirely. |
|
||||||
| device_unused_fallback_key_types | [string] | **Required.** The unused fallback key algorithms. |
|
| device_unused_fallback_key_types | [string] | **Required.** The unused fallback key algorithms. |
|
||||||
|
|
||||||
`DeviceLists`
|
`DeviceLists`
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
|------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| changed | [string] | List of users who have updated their device identity or cross-signing keys, or who now share an encrypted room with the client since the previous sync response. |
|
| changed | [string] | List of users who have updated their device identity or cross-signing keys, or who now share an encrypted room with the client since the previous sync response. |
|
||||||
| left | [string] | List of users with whom we do not share any encrypted rooms anymore since the previous sync response. |
|
| left | [string] | List of users with whom we do not share any encrypted rooms anymore since the previous sync response. |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ given event (for example, if an event is edited multiple times). These should
|
||||||
be [aggregated](#aggregations-of-child-events) by the homeserver.
|
be [aggregated](#aggregations-of-child-events) by the homeserver.
|
||||||
|
|
||||||
The aggregation format of `m.replace` relationships gives the **most recent**
|
The aggregation format of `m.replace` relationships gives the **most recent**
|
||||||
replacement event, formatted [as normal](#room-event-format).
|
valid replacement event, formatted [as normal](#room-event-format).
|
||||||
|
|
||||||
The most recent event is determined by comparing `origin_server_ts`; if two or
|
The most recent event is determined by comparing `origin_server_ts`; if two or
|
||||||
more replacement events have identical `origin_server_ts`, the event with the
|
more replacement events have identical `origin_server_ts`, the event with the
|
||||||
|
|
@ -268,6 +268,11 @@ Client authors are reminded to take note of the requirements for [Validity of
|
||||||
replacement events](#validity-of-replacement-events), and to ignore any
|
replacement events](#validity-of-replacement-events), and to ignore any
|
||||||
invalid replacement events that are received.
|
invalid replacement events that are received.
|
||||||
|
|
||||||
|
Clients should render the content of the **most recent** valid replacement event. The
|
||||||
|
most recent event is determined by comparing `origin_server_ts`; if two or more
|
||||||
|
replacement events have identical `origin_server_ts`, the event with the
|
||||||
|
lexicographically largest `event_id` is treated as more recent.
|
||||||
|
|
||||||
##### Permalinks
|
##### Permalinks
|
||||||
|
|
||||||
When creating [links](/appendices/#uris) to events (also known as permalinks),
|
When creating [links](/appendices/#uris) to events (also known as permalinks),
|
||||||
|
|
@ -364,7 +369,7 @@ property under `m.new_content`.
|
||||||
|
|
||||||
A particular constraint applies to events which replace a [reply](#rich-replies):
|
A particular constraint applies to events which replace a [reply](#rich-replies):
|
||||||
in contrast to the original reply, there should be no `m.in_reply_to` property
|
in contrast to the original reply, there should be no `m.in_reply_to` property
|
||||||
in the the `m.relates_to` object, since it would be redundant (see
|
in the `m.relates_to` object, since it would be redundant (see
|
||||||
[Applying `m.new_content`](#applying-mnew_content) above, which notes that the
|
[Applying `m.new_content`](#applying-mnew_content) above, which notes that the
|
||||||
original event's `m.relates_to` is preserved), as well as being contrary to the
|
original event's `m.relates_to` is preserved), as well as being contrary to the
|
||||||
spirit of the event relationships mechanism which expects only one "parent" per
|
spirit of the event relationships mechanism which expects only one "parent" per
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ for sending events:
|
||||||
The following API endpoints are allowed to be accessed by guest accounts
|
The following API endpoints are allowed to be accessed by guest accounts
|
||||||
for their own account maintenance:
|
for their own account maintenance:
|
||||||
|
|
||||||
* [PUT /profile/{userId}/displayname](#put_matrixclientv3profileuseriddisplayname)
|
* [PUT /profile/{userId}/displayname](#put_matrixclientv3profileuseridkeyname). Guest users may only modify their display name; other profile fields may not be changed.
|
||||||
|
* {{% added-in v="1.16" %}} [DELETE /profile/{userId}/displayname](#delete_matrixclientv3profileuseridkeyname). Again, guest users may delete their display name but not other profile fields.
|
||||||
* [GET /devices](#get_matrixclientv3devices)
|
* [GET /devices](#get_matrixclientv3devices)
|
||||||
* [GET /devices/{deviceId}](#get_matrixclientv3devicesdeviceid)
|
* [GET /devices/{deviceId}](#get_matrixclientv3devicesdeviceid)
|
||||||
* [PUT /devices/{deviceId}](#put_matrixclientv3devicesdeviceid)
|
* [PUT /devices/{deviceId}](#put_matrixclientv3devicesdeviceid)
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ The four options for the `m.room.history_visibility` event are:
|
||||||
|
|
||||||
- `world_readable` - All events while this is the
|
- `world_readable` - All events while this is the
|
||||||
`m.room.history_visibility` value may be shared by any participating
|
`m.room.history_visibility` value may be shared by any participating
|
||||||
homeserver with anyone, regardless of whether they have ever joined
|
homeserver with any authenticated user, regardless of whether they have
|
||||||
the room.
|
ever joined the room. This includes [guest users](#guest-access).
|
||||||
- `shared` - Previous events are always accessible to newly joined
|
- `shared` - Previous events are always accessible to newly joined
|
||||||
members. All events in the room are accessible, even those sent when
|
members. All events in the room are accessible, even those sent when
|
||||||
the member was not a part of the room.
|
the member was not a part of the room.
|
||||||
|
|
@ -44,7 +44,7 @@ setting at that time was more restrictive.
|
||||||
#### Client behaviour
|
#### Client behaviour
|
||||||
|
|
||||||
Clients may want to display a notice that events may be read by
|
Clients may want to display a notice that events may be read by
|
||||||
non-joined people if the history visibility is set to `world_readable`.
|
non-joined users if the history visibility is set to `world_readable`.
|
||||||
|
|
||||||
#### Server behaviour
|
#### Server behaviour
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
{{% changed-in v="1.7" %}}
|
{{% changed-in v="1.7" %}}
|
||||||
|
|
||||||
|
{{% changed-in v="1.17" %}}: the legacy push rules that looked for mentions in
|
||||||
|
the `body` of the event were removed.
|
||||||
|
|
||||||
This module allows users to "mention" other users and rooms within a room event.
|
This module allows users to "mention" other users and rooms within a room event.
|
||||||
This is primarily used as an indicator that the recipient should receive a notification
|
This is primarily used as an indicator that the recipient should receive a notification
|
||||||
about the event.
|
about the event.
|
||||||
|
|
@ -38,19 +41,18 @@ encrypted as normal. To properly process mentions in encrypted rooms, events
|
||||||
must be decrypted first. See [receiving notifications](#receiving-notifications).
|
must be decrypted first. See [receiving notifications](#receiving-notifications).
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
Note that, for backwards compatibility, push rules such as [`.m.rule.contains_display_name`](#_m_rule_contains_display_name),
|
{{% boxes/note %}}
|
||||||
[`.m.rule.contains_user_name`](#_m_rule_contains_user_name), and
|
|
||||||
[`.m.rule.roomnotif`](#_m_rule_roomnotif) continue to match if the `body` of
|
|
||||||
the event contains the user's display name or ID. To avoid unintentional notifications,
|
|
||||||
**it is recommended that clients include a `m.mentions` property on each event**.
|
|
||||||
(If there are no mentions to include it can be an empty object.)
|
|
||||||
|
|
||||||
{{% boxes/rationale %}}
|
|
||||||
In previous versions of the specification, mentioning users was done by
|
In previous versions of the specification, mentioning users was done by
|
||||||
including the user's display name or the localpart of their Matrix ID and room
|
including the user's display name or the localpart of their Matrix ID and room
|
||||||
mentions were done by including the string "@room" in the plaintext `body` of
|
mentions were done by including the string "@room" in the plaintext `body` of
|
||||||
the event. This was prone to confusing and buggy behaviour.
|
the event. When the `m.mentions` field was introduced, those push rules were
|
||||||
{{% /boxes/rationale %}}
|
disabled if the `m.mentions` field was present.
|
||||||
|
|
||||||
|
To avoid unintentional notifications with clients and servers that still use
|
||||||
|
those push rules, **it is recommended that clients still include a `m.mentions`
|
||||||
|
property on each event**. (If there are no mentions to include it can be an
|
||||||
|
empty object.)
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
#### Client behaviour
|
#### Client behaviour
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
### Push Notifications
|
### Push Notifications
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+--------------------+ +-------------------+
|
+--------------------+ +-------------------+
|
||||||
Matrix HTTP | | | |
|
Matrix HTTP | | | |
|
||||||
Notification Protocol | App Developer | | Device Vendor |
|
Notification Protocol | App Developer | | Device Vendor |
|
||||||
|
|
@ -83,7 +83,7 @@ Push Ruleset
|
||||||
: A push ruleset *scopes a set of rules according to some criteria*. For
|
: A push ruleset *scopes a set of rules according to some criteria*. For
|
||||||
example, some rules may only be applied for messages from a particular
|
example, some rules may only be applied for messages from a particular
|
||||||
sender, a particular room, or by default. The push ruleset contains the
|
sender, a particular room, or by default. The push ruleset contains the
|
||||||
entire set of scopes and rules.
|
entire set of rules.
|
||||||
|
|
||||||
#### Push Rules
|
#### Push Rules
|
||||||
|
|
||||||
|
|
@ -91,10 +91,8 @@ A push rule is a single rule that states under what *conditions* an
|
||||||
event should be passed onto a push gateway and *how* the notification
|
event should be passed onto a push gateway and *how* the notification
|
||||||
should be presented. There are different "kinds" of push rules and each
|
should be presented. There are different "kinds" of push rules and each
|
||||||
rule has an associated priority. Every push rule MUST have a `kind` and
|
rule has an associated priority. Every push rule MUST have a `kind` and
|
||||||
`rule_id`. The `rule_id` is a unique string within the kind of rule and
|
`rule_id`. The `rule_id` is a unique string within the kind of rule.
|
||||||
its' scope: `rule_ids` do not need to be unique between rules of the
|
Rules may have extra keys depending on the value of `kind`.
|
||||||
same kind on different devices. Rules may have extra keys depending on
|
|
||||||
the value of `kind`.
|
|
||||||
|
|
||||||
The different `kind`s of rule, in the order that they are checked, are:
|
The different `kind`s of rule, in the order that they are checked, are:
|
||||||
|
|
||||||
|
|
@ -382,6 +380,9 @@ The following `alt_aliases` values will NOT match:
|
||||||
|
|
||||||
**`contains_display_name`**
|
**`contains_display_name`**
|
||||||
|
|
||||||
|
{{% changed-in v="1.17" %}}: this condition is deprecated and **should not be
|
||||||
|
used in new push rules**.
|
||||||
|
|
||||||
This matches messages where `content.body` contains the owner's display name in
|
This matches messages where `content.body` contains the owner's display name in
|
||||||
that room. This is a separate condition because display names may change and as such
|
that room. This is a separate condition because display names may change and as such
|
||||||
it would be hard to maintain a rule that matched the user's display name. This
|
it would be hard to maintain a rule that matched the user's display name. This
|
||||||
|
|
@ -413,6 +414,9 @@ Parameters:
|
||||||
|
|
||||||
#### Predefined Rules
|
#### Predefined Rules
|
||||||
|
|
||||||
|
{{% changed-in v="1.17" %}}: the legacy default push rules that looked for
|
||||||
|
mentions in the `body` of the event were removed.
|
||||||
|
|
||||||
Homeservers can specify "server-default rules". They operate at a lower
|
Homeservers can specify "server-default rules". They operate at a lower
|
||||||
priority than "user-defined rules", except for the `.m.rule.master` rule
|
priority than "user-defined rules", except for the `.m.rule.master` rule
|
||||||
which has always a higher priority than any other rule. The `rule_id`
|
which has always a higher priority than any other rule. The `rule_id`
|
||||||
|
|
@ -557,41 +561,6 @@ Definition:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<a id="_m_rule_contains_display_name"></a> **`.m.rule.contains_display_name`**
|
|
||||||
|
|
||||||
{{% changed-in v="1.7" %}}
|
|
||||||
|
|
||||||
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
|
|
||||||
does not have an [`m.mentions` property](#definition-mmentions)**.
|
|
||||||
|
|
||||||
Matches any message whose content contains the user's current display name
|
|
||||||
in the room in which it was sent.
|
|
||||||
|
|
||||||
Definition:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"rule_id": ".m.rule.contains_display_name",
|
|
||||||
"default": true,
|
|
||||||
"enabled": true,
|
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"kind": "contains_display_name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"actions": [
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"set_tweak": "sound",
|
|
||||||
"value": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"set_tweak": "highlight"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<a id="_m_rule_is_room_mention"></a> **`.m.rule.is_room_mention`**
|
<a id="_m_rule_is_room_mention"></a> **`.m.rule.is_room_mention`**
|
||||||
|
|
||||||
{{% added-in v="1.7" %}}
|
{{% added-in v="1.7" %}}
|
||||||
|
|
@ -626,44 +595,6 @@ Definition:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<a id="_m_rule_roomnotif"></a> **`.m.rule.roomnotif`**
|
|
||||||
|
|
||||||
{{% changed-in v="1.7" %}}
|
|
||||||
|
|
||||||
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
|
|
||||||
does not have an [`m.mentions` property](#definition-mmentions)**.
|
|
||||||
|
|
||||||
Matches any message from a sender with the proper power level whose content
|
|
||||||
contains the text `@room`, signifying the whole room should be notified of
|
|
||||||
the event.
|
|
||||||
|
|
||||||
Definition:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"rule_id": ".m.rule.roomnotif",
|
|
||||||
"default": true,
|
|
||||||
"enabled": true,
|
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"kind": "event_match",
|
|
||||||
"key": "content.body",
|
|
||||||
"pattern": "@room"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "sender_notification_permission",
|
|
||||||
"key": "room"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"actions": [
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"set_tweak": "highlight"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**<a id="mruletombstone"></a>`.m.rule.tombstone`**
|
**<a id="mruletombstone"></a>`.m.rule.tombstone`**
|
||||||
|
|
||||||
Matches any state event whose type is `m.room.tombstone`. This is
|
Matches any state event whose type is `m.room.tombstone`. This is
|
||||||
|
|
@ -776,39 +707,6 @@ Definition:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Default Content Rules
|
|
||||||
|
|
||||||
<a id="_m_rule_contains_user_name"></a> **`.m.rule.contains_user_name`**
|
|
||||||
|
|
||||||
{{% changed-in v="1.7" %}}
|
|
||||||
|
|
||||||
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
|
|
||||||
does not have an [`m.mentions` property](#definition-mmentions)**.
|
|
||||||
|
|
||||||
Matches any message whose content contains the local part of the user's
|
|
||||||
Matrix ID, separated by word boundaries.
|
|
||||||
|
|
||||||
Definition (as a `content` rule):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"rule_id": ".m.rule.contains_user_name",
|
|
||||||
"default": true,
|
|
||||||
"enabled": true,
|
|
||||||
"pattern": "[the local part of the user's Matrix ID]",
|
|
||||||
"actions": [
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"set_tweak": "sound",
|
|
||||||
"value": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"set_tweak": "highlight"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Default Underride Rules
|
##### Default Underride Rules
|
||||||
|
|
||||||
**`.m.rule.call`**
|
**`.m.rule.call`**
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ before delivering them to clients.
|
||||||
Some receipts are sent across federation as EDUs with type `m.receipt`. The
|
Some receipts are sent across federation as EDUs with type `m.receipt`. The
|
||||||
format of the EDUs are:
|
format of the EDUs are:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
<room_id>: {
|
<room_id>: {
|
||||||
<receipt_type>: {
|
<receipt_type>: {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ Previously, a rich reply could only reference another `m.room.message` event.
|
||||||
{{% boxes/note %}}
|
{{% boxes/note %}}
|
||||||
{{% changed-in v="1.13" %}}
|
{{% changed-in v="1.13" %}}
|
||||||
In previous versions of the specification, rich replies could include a fallback
|
In previous versions of the specification, rich replies could include a fallback
|
||||||
representation of the original message message in the `body` (using a prefix
|
representation of the original message in the `body` (using a prefix sequence)
|
||||||
sequence) and `formatted_body` (using a custom HTML element) for clients that do
|
and `formatted_body` (using a custom HTML element) for clients that do not
|
||||||
not support rich replies. This is no longer the case, but clients SHOULD still
|
support rich replies. This is no longer the case, but clients SHOULD still
|
||||||
remove this fallback before rendering the event.
|
remove this fallback before rendering the event.
|
||||||
|
|
||||||
To strip the fallback on the `body`, the client should iterate over each
|
To strip the fallback on the `body`, the client should iterate over each
|
||||||
|
|
@ -64,11 +64,16 @@ as if it were to be under `m.relates_to` directly instead.
|
||||||
|
|
||||||
#### Mentioning the replied to user
|
#### Mentioning the replied to user
|
||||||
|
|
||||||
In order to notify users of the reply, it may be desirable to include the `sender`
|
{{% boxes/note %}}
|
||||||
of the replied to event and any users mentioned in that event. See
|
{{% changed-in v="1.16" %}}
|
||||||
[user and room mentions](#user-and-room-mentions) for additional information.
|
Clients SHOULD no longer propagate mentioned users in the replied to event.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
An example including mentioning the original sender and other users:
|
In order to notify users of the reply, it MAY be desirable to include the `sender`
|
||||||
|
of the replied to event. See [user and room mentions](#user-and-room-mentions) for
|
||||||
|
additional information.
|
||||||
|
|
||||||
|
An example including mentioning the original sender:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -83,8 +88,6 @@ An example including mentioning the original sender and other users:
|
||||||
"user_ids": [
|
"user_ids": [
|
||||||
// The sender of $another_event.
|
// The sender of $another_event.
|
||||||
"@alice:example.org",
|
"@alice:example.org",
|
||||||
// Another Matrix ID copied from the m.mentions property of $another_event.
|
|
||||||
"@bob:example.org"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ It is sometimes desirable to offer a preview of a room, where a user can
|
||||||
This can be particularly effective when combined with [Guest Access](#guest-access).
|
This can be particularly effective when combined with [Guest Access](#guest-access).
|
||||||
|
|
||||||
Previews are implemented via the `world_readable` [Room History
|
Previews are implemented via the `world_readable` [Room History
|
||||||
Visibility](#room-history-visibility). setting, along with a special version of the [GET
|
Visibility](#room-history-visibility) setting, along with a special version of the [GET
|
||||||
/events](#get_matrixclientv3events) endpoint.
|
/events](#get_matrixclientv3events) endpoint.
|
||||||
|
|
||||||
#### Client behaviour
|
#### Client behaviour
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,17 @@ server:
|
||||||
previous room, no `type` is specified on the new room's create event
|
previous room, no `type` is specified on the new room's create event
|
||||||
either.
|
either.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.16" %}} If both the new and old [room version](/rooms) support
|
||||||
|
additional creators, the server will not transfer those additional creators automatically.
|
||||||
|
They must be explicitly set during the `/upgrade` call.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.16" %}} When upgrading to room version 12 or later, the `predecessor` field MAY NOT contain
|
||||||
|
an `event_id`.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
3. Replicates transferable state events to the new room. The exact
|
3. Replicates transferable state events to the new room. The exact
|
||||||
details for what is transferred is left as an implementation detail,
|
details for what is transferred is left as an implementation detail,
|
||||||
however the recommended state events to transfer are:
|
however the recommended state events to transfer are:
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ clients will try to use the default key to decrypt secrets.
|
||||||
|
|
||||||
Clients that want to present a simplified interface to users by not supporting
|
Clients that want to present a simplified interface to users by not supporting
|
||||||
multiple keys should use the default key if one is specified. If no default
|
multiple keys should use the default key if one is specified. If no default
|
||||||
key is specified, the client may behave as if there is no key is present at
|
key is specified, the client may behave as if no key is present at
|
||||||
all. When such a client creates a key, it should mark that key as being the
|
all. When such a client creates a key, it should mark that key as being the
|
||||||
default key.
|
default key.
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ Some secret is encrypted using keys with ID `key_id_1` and `key_id_2`:
|
||||||
|
|
||||||
`org.example.some.secret`:
|
`org.example.some.secret`:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"encrypted": {
|
"encrypted": {
|
||||||
"key_id_1": {
|
"key_id_1": {
|
||||||
|
|
@ -177,7 +177,7 @@ and the key descriptions for the keys would be:
|
||||||
|
|
||||||
`m.secret_storage.key.key_id_1`:
|
`m.secret_storage.key.key_id_1`:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"name": "Some key",
|
"name": "Some key",
|
||||||
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
||||||
|
|
@ -187,7 +187,7 @@ and the key descriptions for the keys would be:
|
||||||
|
|
||||||
`m.secret_storage.key.key_id_2`:
|
`m.secret_storage.key.key_id_2`:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"name": "Some other key",
|
"name": "Some other key",
|
||||||
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
||||||
|
|
@ -199,7 +199,7 @@ If `key_id_1` is the default key, then we also have:
|
||||||
|
|
||||||
`m.secret_storage.default_key`:
|
`m.secret_storage.default_key`:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"key": "key_id_1"
|
"key": "key_id_1"
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +294,7 @@ in the `iterations` parameter.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"passphrase": {
|
"passphrase": {
|
||||||
"algorithm": "m.pbkdf2",
|
"algorithm": "m.pbkdf2",
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ parent to the room. The `state_key` for the event is the child room's ID.
|
||||||
|
|
||||||
For example, to achieve the following:
|
For example, to achieve the following:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
#space:example.org
|
#space:example.org
|
||||||
#general:example.org (!abcdefg:example.org)
|
#general:example.org (!abcdefg:example.org)
|
||||||
!private:example.org
|
!private:example.org
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ opening an embedded web view.
|
||||||
|
|
||||||
These steps are illustrated as follows:
|
These steps are illustrated as follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
Matrix Client Matrix Homeserver Auth Server
|
Matrix Client Matrix Homeserver Auth Server
|
||||||
| | |
|
| | |
|
||||||
|-------------(0) GET /login----------->| |
|
|-------------(0) GET /login----------->| |
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ If the lookup yields a result for a Matrix User ID then the normal [invite
|
||||||
process](/server-server-api/#inviting-to-a-room) can be initiated. This process
|
process](/server-server-api/#inviting-to-a-room) can be initiated. This process
|
||||||
ends up looking like this:
|
ends up looking like this:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+---------+ +-------------+ +-----------------+
|
+---------+ +-------------+ +-----------------+
|
||||||
| Client | | Homeserver | | IdentityServer |
|
| Client | | Homeserver | | IdentityServer |
|
||||||
+---------+ +-------------+ +-----------------+
|
+---------+ +-------------+ +-----------------+
|
||||||
|
|
@ -74,7 +74,7 @@ the invite on the identity server with a call to
|
||||||
and emit a valid [`m.room.third_party_invite`](#mroomthird_party_invite) event
|
and emit a valid [`m.room.third_party_invite`](#mroomthird_party_invite) event
|
||||||
to the room. This process ends up looking like this:
|
to the room. This process ends up looking like this:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+---------+ +-------------+ +-----------------+
|
+---------+ +-------------+ +-----------------+
|
||||||
| Client | | Homeserver | | IdentityServer |
|
| Client | | Homeserver | | IdentityServer |
|
||||||
+---------+ +-------------+ +-----------------+
|
+---------+ +-------------+ +-----------------+
|
||||||
|
|
@ -133,7 +133,7 @@ and an identity server IS, the full sequence for a third-party invite
|
||||||
would look like the following. This diagram assumes H1 and H2 are
|
would look like the following. This diagram assumes H1 and H2 are
|
||||||
residents of the room while H3 is attempting to join.
|
residents of the room while H3 is attempting to join.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
||||||
| UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS |
|
| UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS |
|
||||||
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ included under the `m.relations` property in `unsigned` for the thread root. For
|
||||||
```
|
```
|
||||||
|
|
||||||
`latest_event` is the most recent event (topologically to the server) in the thread sent by an
|
`latest_event` is the most recent event (topologically to the server) in the thread sent by an
|
||||||
un-[ignored user](#ignoring-users).
|
un-[ignored user](#ignoring-users). It should be serialized in the same form as the event itself.
|
||||||
|
|
||||||
Note that, as in the example above, child events of the `latest_event` should
|
Note that, as in the example above, child events of the `latest_event` should
|
||||||
themselves be aggregated and included under `m.relations` for that event. The
|
themselves be aggregated and included under `m.relations` for that event. The
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ or not there have been any changes to the Matrix spec.
|
||||||
|
|
||||||
A call is set up with message events exchanged as follows:
|
A call is set up with message events exchanged as follows:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
Caller Callee
|
Caller Callee
|
||||||
[Place Call]
|
[Place Call]
|
||||||
m.call.invite ----------->
|
m.call.invite ----------->
|
||||||
|
|
@ -144,7 +144,7 @@ A call is set up with message events exchanged as follows:
|
||||||
|
|
||||||
Or a rejected call:
|
Or a rejected call:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
Caller Callee
|
Caller Callee
|
||||||
m.call.invite ------------>
|
m.call.invite ------------>
|
||||||
m.call.candidate --------->
|
m.call.candidate --------->
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,15 @@
|
||||||
title: "Identity Service API"
|
title: "Identity Service API"
|
||||||
weight: 40
|
weight: 40
|
||||||
type: docs
|
type: docs
|
||||||
|
description: |
|
||||||
|
The Matrix client-server and server-server APIs are largely expressed in
|
||||||
|
Matrix user identifiers. Sometimes it is useful to refer to users by other
|
||||||
|
(“third-party”) identifiers such as email addresses or phone numbers. The
|
||||||
|
Identity Service API describes how mappings between 3PIDs and Matrix user
|
||||||
|
IDs can be established, validated, and used; in practice this has been
|
||||||
|
applied to email addresses and phone numbers.
|
||||||
---
|
---
|
||||||
|
|
||||||
The Matrix client-server and server-server APIs are largely expressed in
|
|
||||||
Matrix user identifiers. From time to time, it is useful to refer to
|
|
||||||
users by other ("third-party") identifiers, or "3PID"s, e.g. their email
|
|
||||||
address or phone number. This Identity Service Specification describes
|
|
||||||
how mappings between third-party identifiers and Matrix user identifiers
|
|
||||||
can be established, validated, and used. This description technically
|
|
||||||
may apply to any 3PID, but in practice has only been applied
|
|
||||||
specifically to email addresses and phone numbers.
|
|
||||||
|
|
||||||
## General principles
|
## General principles
|
||||||
|
|
||||||
The purpose of an identity server is to validate, store, and answer
|
The purpose of an identity server is to validate, store, and answer
|
||||||
|
|
|
||||||
10
content/olm-megolm/_index.md
Normal file
10
content/olm-megolm/_index.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: "Olm & Megolm"
|
||||||
|
weight: 61
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
Matrix uses the Olm and Megolm cryptographic ratchets for [end-to-end encryption](../client-server-api/#end-to-end-encryption).
|
||||||
|
|
||||||
|
- [Olm: A Cryptographic Ratchet](/olm-megolm/olm/)
|
||||||
|
- [Megolm group ratchet](/olm-megolm/megolm/)
|
||||||
378
content/olm-megolm/megolm.md
Normal file
378
content/olm-megolm/megolm.md
Normal file
|
|
@ -0,0 +1,378 @@
|
||||||
|
---
|
||||||
|
title: "Megolm group ratchet"
|
||||||
|
weight: 20
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
An AES-based cryptographic ratchet intended for group communications.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
The Megolm ratchet is intended for encrypted messaging applications where there
|
||||||
|
may be a large number of recipients of each message, thus precluding the use of
|
||||||
|
peer-to-peer encryption systems such as [Olm][].
|
||||||
|
|
||||||
|
It also allows a recipient to decrypt received messages multiple times. For
|
||||||
|
instance, in client/server applications, a copy of the ciphertext can be stored
|
||||||
|
on the (untrusted) server, while the client need only store the session keys.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Each participant in a conversation uses their own outbound session for
|
||||||
|
encrypting messages. A session consists of a ratchet and an [Ed25519][] keypair.
|
||||||
|
|
||||||
|
Secrecy is provided by the ratchet, which can be wound forwards but not
|
||||||
|
backwards, and is used to derive a distinct message key for each message.
|
||||||
|
|
||||||
|
Authenticity is provided via Ed25519 signatures.
|
||||||
|
|
||||||
|
The value of the ratchet, and the public part of the Ed25519 key, are shared
|
||||||
|
with other participants in the conversation via secure peer-to-peer
|
||||||
|
channels. Provided that peer-to-peer channel provides authenticity of the
|
||||||
|
messages to the participants and deniability of the messages to third parties,
|
||||||
|
the Megolm session will inherit those properties.
|
||||||
|
|
||||||
|
## The Megolm ratchet algorithm
|
||||||
|
|
||||||
|
The Megolm ratchet \(R_i\) consists of four parts, \(R_{i,j}\) for
|
||||||
|
\(j \in {0,1,2,3}\). The length of each part depends on the hash function
|
||||||
|
in use (256 bits for this version of Megolm).
|
||||||
|
|
||||||
|
The ratchet is initialised with cryptographically-secure random data, and
|
||||||
|
advanced as follows:
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
R_{i,0} &=
|
||||||
|
\begin{cases}
|
||||||
|
H_0\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
|
||||||
|
R_{i-1,0} &\text{otherwise}
|
||||||
|
\end{cases}\\
|
||||||
|
R_{i,1} &=
|
||||||
|
\begin{cases}
|
||||||
|
H_1\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
|
||||||
|
H_1\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
|
||||||
|
R_{i-1,1} &\text{otherwise}
|
||||||
|
\end{cases}\\
|
||||||
|
R_{i,2} &=
|
||||||
|
\begin{cases}
|
||||||
|
H_2\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
|
||||||
|
H_2\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
|
||||||
|
H_2\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
|
||||||
|
R_{i-1,2} &\text{otherwise}
|
||||||
|
\end{cases}\\
|
||||||
|
R_{i,3} &=
|
||||||
|
\begin{cases}
|
||||||
|
H_3\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
|
||||||
|
H_3\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
|
||||||
|
H_3\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
|
||||||
|
H_3\left(R_{i-1,3}\right) &\text{otherwise}
|
||||||
|
\end{cases}
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
where \(H_0\), \(H_1\), \(H_2\), and \(H_3\) are different hash
|
||||||
|
functions. In summary: every \(2^8\) iterations, \(R_{i,3}\) is
|
||||||
|
reseeded from \(R_{i,2}\). Every \(2^{16}\) iterations, \(R_{i,2}\)
|
||||||
|
and \(R_{i,3}\) are reseeded from \(R_{i,1}\). Every \(2^{24}\)
|
||||||
|
iterations, \(R_{i,1}\), \(R_{i,2}\) and \(R_{i,3}\) are reseeded
|
||||||
|
from \(R_{i,0}\).
|
||||||
|
|
||||||
|
The complete ratchet value, \(R_{i}\), is hashed to generate the keys used
|
||||||
|
to encrypt each message. This scheme allows the ratchet to be advanced an
|
||||||
|
arbitrary amount forwards while needing at most 1020 hash computations. A
|
||||||
|
client can decrypt chat history onwards from the earliest value of the ratchet
|
||||||
|
it is aware of, but cannot decrypt history from before that point without
|
||||||
|
reversing the hash function.
|
||||||
|
|
||||||
|
This allows a participant to share its ability to decrypt chat history with
|
||||||
|
another from a point in the conversation onwards by giving a copy of the
|
||||||
|
ratchet at that point in the conversation.
|
||||||
|
|
||||||
|
|
||||||
|
## The Megolm protocol
|
||||||
|
|
||||||
|
### Session setup
|
||||||
|
|
||||||
|
Each participant in a conversation generates their own Megolm session. A
|
||||||
|
session consists of three parts:
|
||||||
|
|
||||||
|
* a 32 bit counter, \(i\).
|
||||||
|
* an [Ed25519][] keypair, \(K\).
|
||||||
|
* a ratchet, \(R_i\), which consists of four 256-bit values,
|
||||||
|
\(R_{i,j}\) for \(j \in {0,1,2,3}\).
|
||||||
|
|
||||||
|
The counter \(i\) is initialised to \(0\). A new Ed25519 keypair is
|
||||||
|
generated for \(K\). The ratchet is simply initialised with 1024 bits of
|
||||||
|
cryptographically-secure random data.
|
||||||
|
|
||||||
|
A single participant may use multiple sessions over the lifetime of a
|
||||||
|
conversation. The public part of \(K\) is used as an identifier to
|
||||||
|
discriminate between sessions.
|
||||||
|
|
||||||
|
### Sharing session data
|
||||||
|
|
||||||
|
To allow other participants in the conversation to decrypt messages, the
|
||||||
|
session data is formatted as described in [Session-sharing format](#session-sharing-format). It is then
|
||||||
|
shared with other participants in the conversation via a secure peer-to-peer
|
||||||
|
channel (such as that provided by [Olm][]).
|
||||||
|
|
||||||
|
When the session data is received from other participants, the recipient first
|
||||||
|
checks that the signature matches the public key. They then store their own
|
||||||
|
copy of the counter, ratchet, and public key.
|
||||||
|
|
||||||
|
### Message encryption
|
||||||
|
|
||||||
|
This version of Megolm uses [AES-256][] in [CBC][] mode with [PKCS#7][] padding and
|
||||||
|
[HMAC-SHA-256][] (truncated to 64 bits). The 256 bit AES key, 256 bit HMAC key,
|
||||||
|
and 128 bit AES IV are derived from the megolm ratchet \(R_i\):
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
\mathit{AES\_KEY}_{i}\;\parallel\;\mathit{HMAC\_KEY}_{i}\;\parallel\;\mathit{AES\_IV}_{i}
|
||||||
|
&= \operatorname{HKDF}\left(0,\,R_{i},\text{"MEGOLM\_KEYS"},\,80\right) \\
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
where \(\parallel\) represents string splitting, and
|
||||||
|
\(\operatorname{HKDF}\left(\mathit{salt},\,\mathit{IKM},\,\mathit{info},\,L\right)\)
|
||||||
|
refers to the [HMAC-based key
|
||||||
|
derivation function][] using using [SHA-256][] as the hash function
|
||||||
|
([HKDF-SHA-256][]) with a salt value of \(\mathit{salt}\), input key material of
|
||||||
|
\(\mathit{IKM}\), context string \(\mathit{info}\), and output keying material length of
|
||||||
|
\(L\) bytes.
|
||||||
|
|
||||||
|
The plain-text is encrypted with AES-256, using the key \(\mathit{AES\_KEY}_{i}\)
|
||||||
|
and the IV \(\mathit{AES\_IV}_{i}\) to give the cipher-text, \(X_{i}\).
|
||||||
|
|
||||||
|
The ratchet index \(i\), and the cipher-text \(X_{i}\), are then packed
|
||||||
|
into a message as described in [Message format](#message-format). Then the entire message
|
||||||
|
(including the version bytes and all payload bytes) are passed through
|
||||||
|
HMAC-SHA-256. The first 8 bytes of the MAC are appended to the message.
|
||||||
|
|
||||||
|
Finally, the authenticated message is signed using the Ed25519 keypair; the 64
|
||||||
|
byte signature is appended to the message.
|
||||||
|
|
||||||
|
The complete signed message, together with the public part of \(K\) (acting
|
||||||
|
as a session identifier), can then be sent over an insecure channel. The
|
||||||
|
message can then be authenticated and decrypted only by recipients who have
|
||||||
|
received the session data.
|
||||||
|
|
||||||
|
### Advancing the ratchet
|
||||||
|
|
||||||
|
After each message is encrypted, the ratchet is advanced. This is done as
|
||||||
|
described in [The Megolm ratchet algorithm](#the-megolm-ratchet-algorithm), using the following definitions:
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
H_0(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x00"}) \\
|
||||||
|
H_1(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x01"}) \\
|
||||||
|
H_2(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x02"}) \\
|
||||||
|
H_3(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x03"}) \\
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
where \(\operatorname{HMAC}(A, T)\) is the HMAC-SHA-256 of ``T``, using ``A`` as the
|
||||||
|
key.
|
||||||
|
|
||||||
|
For outbound sessions, the updated ratchet and counter are stored in the
|
||||||
|
session.
|
||||||
|
|
||||||
|
In order to maintain the ability to decrypt conversation history, inbound
|
||||||
|
sessions should store a copy of their earliest known ratchet value (unless they
|
||||||
|
explicitly want to drop the ability to decrypt that history - see [Partial
|
||||||
|
Forward Secrecy](#partial-forward-secrecy)). They may also choose to cache calculated ratchet values,
|
||||||
|
but the decision of which ratchet states to cache is left to the application.
|
||||||
|
|
||||||
|
## Data exchange formats
|
||||||
|
|
||||||
|
### Session sharing format
|
||||||
|
|
||||||
|
This format is used for the initial sharing of a Megolm session with other
|
||||||
|
group participants who need to be able to read messages encrypted by this
|
||||||
|
session.
|
||||||
|
|
||||||
|
The session sharing format is as follows:
|
||||||
|
|
||||||
|
```nohighlight
|
||||||
|
+---+----+--------+--------+--------+--------+------+-----------+
|
||||||
|
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub | Signature |
|
||||||
|
+---+----+--------+--------+--------+--------+------+-----------+
|
||||||
|
0 1 5 37 69 101 133 165 229 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
The version byte, ``V``, is ``"\x02"``.
|
||||||
|
|
||||||
|
This is followed by the ratchet index, \(i\), which is encoded as a
|
||||||
|
big-endian 32-bit integer; the ratchet values \(R_{i,j}\); and the public
|
||||||
|
part of the Ed25519 keypair \(K\).
|
||||||
|
|
||||||
|
The data is then signed using the Ed25519 keypair, and the 64-byte signature is
|
||||||
|
appended.
|
||||||
|
|
||||||
|
### Session export format
|
||||||
|
|
||||||
|
Once the session is initially shared with the group participants, each
|
||||||
|
participant needs to retain a copy of the session if they want to maintain
|
||||||
|
their ability to decrypt messages encrypted with that session.
|
||||||
|
|
||||||
|
For forward-secrecy purposes, a participant may choose to store a ratcheted
|
||||||
|
version of the session. But since the ratchet index is covered by the
|
||||||
|
signature, this would invalidate the signature. So we define a similar format,
|
||||||
|
called the *session export format*, which is identical to the [session sharing
|
||||||
|
format](#session-sharing-format) except for dropping the signature.
|
||||||
|
|
||||||
|
The Megolm session export format is thus as follows:
|
||||||
|
|
||||||
|
```nohighlight
|
||||||
|
+---+----+--------+--------+--------+--------+------+
|
||||||
|
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub |
|
||||||
|
+---+----+--------+--------+--------+--------+------+
|
||||||
|
0 1 5 37 69 101 133 165 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
The version byte, ``V``, is ``"\x01"``.
|
||||||
|
|
||||||
|
This is followed by the ratchet index, \(i\), which is encoded as a
|
||||||
|
big-endian 32-bit integer; the ratchet values \(R_{i,j}\); and the public
|
||||||
|
part of the Ed25519 keypair \(K\).
|
||||||
|
|
||||||
|
### Message format
|
||||||
|
|
||||||
|
Megolm messages consist of a one byte version, followed by a variable length
|
||||||
|
payload, a fixed length message authentication code, and a fixed length
|
||||||
|
signature.
|
||||||
|
|
||||||
|
```nohighlight
|
||||||
|
+---+------------------------------------+-----------+------------------+
|
||||||
|
| V | Payload Bytes | MAC Bytes | Signature Bytes |
|
||||||
|
+---+------------------------------------+-----------+------------------+
|
||||||
|
0 1 N N+8 N+72 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
The version byte, ``V``, is ``"\x03"``.
|
||||||
|
|
||||||
|
The payload uses a format based on the [Protocol Buffers encoding][]. It
|
||||||
|
consists of the following key-value pairs:
|
||||||
|
|
||||||
|
**Name**|**Tag**|**Type**|**Meaning**
|
||||||
|
:-----:|:-----:|:-----:|:-----:
|
||||||
|
Message-Index|0x08|Integer|The index of the ratchet, i
|
||||||
|
Cipher-Text|0x12|String|The cipher-text, Xi, of the message
|
||||||
|
|
||||||
|
Within the payload, integers are encoded using a variable length encoding. Each
|
||||||
|
integer is encoded as a sequence of bytes with the high bit set followed by a
|
||||||
|
byte with the high bit clear. The seven low bits of each byte store the bits of
|
||||||
|
the integer. The least significant bits are stored in the first byte.
|
||||||
|
|
||||||
|
Strings are encoded as a variable-length integer followed by the string itself.
|
||||||
|
|
||||||
|
Each key-value pair is encoded as a variable-length integer giving the tag,
|
||||||
|
followed by a string or variable-length integer giving the value.
|
||||||
|
|
||||||
|
The payload is followed by the MAC. The length of the MAC is determined by the
|
||||||
|
authenticated encryption algorithm being used (8 bytes in this version of the
|
||||||
|
protocol). The MAC protects all of the bytes preceding the MAC.
|
||||||
|
|
||||||
|
The length of the signature is determined by the signing algorithm being used
|
||||||
|
(64 bytes in this version of the protocol). The signature covers all of the
|
||||||
|
bytes preceding the signature.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
### Message Replays
|
||||||
|
|
||||||
|
A message can be decrypted successfully multiple times. This means that an
|
||||||
|
attacker can re-send a copy of an old message, and the recipient will treat it
|
||||||
|
as a new message.
|
||||||
|
|
||||||
|
To mitigate this it is recommended that applications track the ratchet indices
|
||||||
|
they have received and that they reject messages with a ratchet index that
|
||||||
|
they have already decrypted.
|
||||||
|
|
||||||
|
### Lack of Transcript Consistency
|
||||||
|
|
||||||
|
In a group conversation, there is no guarantee that all recipients have
|
||||||
|
received the same messages. For example, if Alice is in a conversation with Bob
|
||||||
|
and Charlie, she could send different messages to Bob and Charlie, or could
|
||||||
|
send some messages to Bob but not Charlie, or vice versa.
|
||||||
|
|
||||||
|
Solving this is, in general, a hard problem, particularly in a protocol which
|
||||||
|
does not guarantee in-order message delivery. For now it remains the subject of
|
||||||
|
future research.
|
||||||
|
|
||||||
|
### Lack of Backward Secrecy
|
||||||
|
|
||||||
|
[Backward secrecy](https://intensecrypto.org/public/lec_08_hash_functions_part2.html#sec-forward-and-backward-secrecy)
|
||||||
|
(also called 'future secrecy' or 'post-compromise security') is the property
|
||||||
|
that if current private keys are compromised, an attacker cannot decrypt
|
||||||
|
future messages in a given session. In other words, when looking
|
||||||
|
**backwards** in time at a compromise which has already happened, **current**
|
||||||
|
messages are still secret.
|
||||||
|
|
||||||
|
By itself, Megolm does not possess this property: once the key to a Megolm
|
||||||
|
session is compromised, the attacker can decrypt any message that was
|
||||||
|
encrypted using a key derived from the compromised or subsequent ratchet
|
||||||
|
values.
|
||||||
|
|
||||||
|
In order to mitigate this, the application should ensure that Megolm sessions
|
||||||
|
are not used indefinitely. Instead it should periodically start a new session,
|
||||||
|
with new keys shared over a secure channel.
|
||||||
|
|
||||||
|
<!-- TODO: Can we recommend sensible lifetimes for Megolm sessions? Probably
|
||||||
|
depends how paranoid we're feeling, but some guidelines might be useful. -->
|
||||||
|
|
||||||
|
### Partial Forward Secrecy
|
||||||
|
|
||||||
|
[Forward secrecy](https://intensecrypto.org/public/lec_08_hash_functions_part2.html#sec-forward-and-backward-secrecy)
|
||||||
|
(also called 'perfect forward secrecy') is the property that if the current
|
||||||
|
private keys are compromised, an attacker cannot decrypt *past* messages in
|
||||||
|
a given session. In other words, when looking **forwards** in time towards a
|
||||||
|
potential future compromise, **current** messages will be secret.
|
||||||
|
|
||||||
|
In Megolm, each recipient maintains a record of the ratchet value which allows
|
||||||
|
them to decrypt any messages sent in the session after the corresponding point
|
||||||
|
in the conversation. If this value is compromised, an attacker can similarly
|
||||||
|
decrypt past messages which were encrypted by a key derived from the
|
||||||
|
compromised or subsequent ratchet values. This gives 'partial' forward
|
||||||
|
secrecy.
|
||||||
|
|
||||||
|
To mitigate this issue, the application should offer the user the option to
|
||||||
|
discard historical conversations, by winding forward any stored ratchet values,
|
||||||
|
or discarding sessions altogether.
|
||||||
|
|
||||||
|
### Dependency on secure channel for key exchange
|
||||||
|
|
||||||
|
The design of the Megolm ratchet relies on the availability of a secure
|
||||||
|
peer-to-peer channel for the exchange of session keys. Any vulnerabilities in
|
||||||
|
the underlying channel are likely to be amplified when applied to Megolm
|
||||||
|
session setup.
|
||||||
|
|
||||||
|
For example, if the peer-to-peer channel is vulnerable to an unknown key-share
|
||||||
|
attack, the entire Megolm session become similarly vulnerable. For example:
|
||||||
|
Alice starts a group chat with Eve, and shares the session keys with Eve. Eve
|
||||||
|
uses the unknown key-share attack to forward the session keys to Bob, who
|
||||||
|
believes Alice is starting the session with him. Eve then forwards messages
|
||||||
|
from the Megolm session to Bob, who again believes they are coming from
|
||||||
|
Alice. Provided the peer-to-peer channel is not vulnerable to this attack, Bob
|
||||||
|
will realise that the key-sharing message was forwarded by Eve, and can treat
|
||||||
|
the Megolm session as a forgery.
|
||||||
|
|
||||||
|
A second example: if the peer-to-peer channel is vulnerable to a replay
|
||||||
|
attack, this can be extended to entire Megolm sessions.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The Megolm specification (this document) is licensed under the Apache License,
|
||||||
|
Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
[Ed25519]: http://ed25519.cr.yp.to/
|
||||||
|
[HMAC-based key derivation function]: https://tools.ietf.org/html/rfc5869
|
||||||
|
[HKDF-SHA-256]: https://tools.ietf.org/html/rfc5869
|
||||||
|
[HMAC-SHA-256]: https://tools.ietf.org/html/rfc2104
|
||||||
|
[SHA-256]: https://tools.ietf.org/html/rfc6234
|
||||||
|
[AES-256]: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||||
|
[CBC]: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||||
|
[PKCS#7]: https://tools.ietf.org/html/rfc2315
|
||||||
|
[Olm]: https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/olm.md
|
||||||
|
[Protocol Buffers encoding]: https://developers.google.com/protocol-buffers/docs/encoding
|
||||||
334
content/olm-megolm/olm.md
Normal file
334
content/olm-megolm/olm.md
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
---
|
||||||
|
title: "Olm: A Cryptographic Ratchet"
|
||||||
|
weight: 10
|
||||||
|
type: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
An implementation of the double cryptographic ratchet described by
|
||||||
|
https://whispersystems.org/docs/specifications/doubleratchet/.
|
||||||
|
|
||||||
|
## Notation
|
||||||
|
|
||||||
|
This document uses \(\parallel\) to represent string concatenation. When
|
||||||
|
\(\parallel\) appears on the right hand side of an \(=\) it means that
|
||||||
|
the inputs are concatenated. When \(\parallel\) appears on the left hand
|
||||||
|
side of an \(=\) it means that the output is split.
|
||||||
|
|
||||||
|
When this document uses \(\operatorname{ECDH}\left(K_A,K_B\right)\) it means
|
||||||
|
that each party computes a Diffie-Hellman agreement using their private key
|
||||||
|
and the remote party's public key.
|
||||||
|
So party \(A\) computes \(\operatorname{ECDH}\left(K_B^{public},K_A^{private}\right)\)
|
||||||
|
and party \(B\) computes \(\operatorname{ECDH}\left(K_A^{public},K_B^{private}\right)\).
|
||||||
|
|
||||||
|
Where this document uses \(\operatorname{HKDF}\left(salt,IKM,info,L\right)\) it
|
||||||
|
refers to the [HMAC-based key derivation function][] with a salt value of
|
||||||
|
\(salt\), input key material of \(IKM\), context string \(info\),
|
||||||
|
and output keying material length of \(L\) bytes.
|
||||||
|
|
||||||
|
## The Olm Algorithm
|
||||||
|
|
||||||
|
### Initial setup
|
||||||
|
|
||||||
|
The setup takes four [Curve25519][] inputs: Identity keys for Alice and Bob,
|
||||||
|
\(I_A\) and \(I_B\), and one-time keys for Alice and Bob,
|
||||||
|
\(E_A\) and \(E_B\). A shared secret, \(S\), is generated using
|
||||||
|
[Triple Diffie-Hellman][]. The initial 256 bit root key, \(R_0\), and 256
|
||||||
|
bit chain key, \(C_{0,0}\), are derived from the shared secret using an
|
||||||
|
HMAC-based Key Derivation Function using [SHA-256][] as the hash function
|
||||||
|
([HKDF-SHA-256][]) with default salt and ``"OLM_ROOT"`` as the info.
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
S&=\operatorname{ECDH}\left(I_A,E_B\right)\;\parallel\;
|
||||||
|
\operatorname{ECDH}\left(E_A,I_B\right)\;\parallel\;
|
||||||
|
\operatorname{ECDH}\left(E_A,E_B\right)\\
|
||||||
|
R_0\;\parallel\;C_{0,0}&=
|
||||||
|
\operatorname{HKDF}\left(0,S,\text{``OLM\_ROOT"},64\right)
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
### Advancing the root key
|
||||||
|
|
||||||
|
Advancing a root key takes the previous root key, \(R_{i-1}\), and two
|
||||||
|
Curve25519 inputs: the previous ratchet key, \(T_{i-1}\), and the current
|
||||||
|
ratchet key \(T_i\). The even ratchet keys are generated by Alice.
|
||||||
|
The odd ratchet keys are generated by Bob. A shared secret is generated
|
||||||
|
using Diffie-Hellman on the ratchet keys. The next root key, \(R_i\), and
|
||||||
|
chain key, \(C_{i,0}\), are derived from the shared secret using
|
||||||
|
[HKDF-SHA-256][] using \(R_{i-1}\) as the salt and ``"OLM_RATCHET"`` as the
|
||||||
|
info.
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
R_i\;\parallel\;C_{i,0}&=
|
||||||
|
\operatorname{HKDF}\left(
|
||||||
|
R_{i-1},
|
||||||
|
\operatorname{ECDH}\left(T_{i-1},T_i\right),
|
||||||
|
\text{``OLM\_RATCHET"},
|
||||||
|
64
|
||||||
|
\right)
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
### Advancing the chain key
|
||||||
|
|
||||||
|
Advancing a chain key takes the previous chain key, \(C_{i,j-1}\). The next
|
||||||
|
chain key, \(C_{i,j}\), is the [HMAC-SHA-256][] of ``"\x02"`` using the
|
||||||
|
previous chain key as the key.
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
C_{i,j}&=\operatorname{HMAC}\left(C_{i,j-1},\text{``\char`\\x02"}\right)
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
### Creating a message key
|
||||||
|
|
||||||
|
Creating a message key takes the current chain key, \(C_{i,j}\). The
|
||||||
|
message key, \(M_{i,j}\), is the [HMAC-SHA-256][] of ``"\x01"`` using the
|
||||||
|
current chain key as the key. The message keys where \(i\) is even are used
|
||||||
|
by Alice to encrypt messages. The message keys where \(i\) is odd are used
|
||||||
|
by Bob to encrypt messages.
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
M_{i,j}&=\operatorname{HMAC}\left(C_{i,j},\text{``\char`\\x01"}\right)
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
## The Olm Protocol
|
||||||
|
|
||||||
|
### Creating an outbound session
|
||||||
|
|
||||||
|
Bob publishes the public parts of his identity key, \(I_B\), and some
|
||||||
|
single-use one-time keys \(E_B\).
|
||||||
|
|
||||||
|
Alice downloads Bob's identity key, \(I_B\), and a one-time key,
|
||||||
|
\(E_B\). She generates a new single-use key, \(E_A\), and computes a
|
||||||
|
root key, \(R_0\), and a chain key \(C_{0,0}\). She also generates a
|
||||||
|
new ratchet key \(T_0\).
|
||||||
|
|
||||||
|
### Sending the first pre-key messages
|
||||||
|
|
||||||
|
Alice computes a message key, \(M_{0,j}\), and a new chain key,
|
||||||
|
\(C_{0,j+1}\), using the current chain key. She replaces the current chain
|
||||||
|
key with the new one.
|
||||||
|
|
||||||
|
Alice encrypts her plain-text with the message key, \(M_{0,j}\), using an
|
||||||
|
authenticated encryption scheme (see below) to get a cipher-text,
|
||||||
|
\(X_{0,j}\).
|
||||||
|
|
||||||
|
She then sends the following to Bob:
|
||||||
|
* The public part of her identity key, \(I_A\)
|
||||||
|
* The public part of her single-use key, \(E_A\)
|
||||||
|
* The public part of Bob's single-use key, \(E_B\)
|
||||||
|
* The current chain index, \(j\)
|
||||||
|
* The public part of her ratchet key, \(T_0\)
|
||||||
|
* The cipher-text, \(X_{0,j}\)
|
||||||
|
|
||||||
|
Alice will continue to send pre-key messages until she receives a message from
|
||||||
|
Bob.
|
||||||
|
|
||||||
|
### Creating an inbound session from a pre-key message
|
||||||
|
|
||||||
|
Bob receives a pre-key message as above.
|
||||||
|
|
||||||
|
Bob looks up the private part of his single-use key, \(E_B\). He can now
|
||||||
|
compute the root key, \(R_0\), and the chain key, \(C_{0,0}\), from
|
||||||
|
\(I_A\), \(E_A\), \(I_B\), and \(E_B\).
|
||||||
|
|
||||||
|
Bob then advances the chain key \(j\) times, to compute the chain key used
|
||||||
|
by the message, \(C_{0,j}\). He now creates the
|
||||||
|
message key, \(M_{0,j}\), and attempts to decrypt the cipher-text,
|
||||||
|
\(X_{0,j}\). If the cipher-text's authentication is correct then Bob can
|
||||||
|
discard the private part of his single-use one-time key, \(E_B\).
|
||||||
|
|
||||||
|
Bob stores Alice's initial ratchet key, \(T_0\), until he wants to
|
||||||
|
send a message.
|
||||||
|
|
||||||
|
### Sending normal messages
|
||||||
|
|
||||||
|
Once a message has been received from the other side, a session is considered
|
||||||
|
established, and a more compact form is used.
|
||||||
|
|
||||||
|
To send a message, the user checks if they have a sender chain key,
|
||||||
|
\(C_{i,j}\). Alice uses chain keys where \(i\) is even. Bob uses chain
|
||||||
|
keys where \(i\) is odd. If the chain key doesn't exist then a new ratchet
|
||||||
|
key \(T_i\) is generated and a new root key \(R_i\) and chain key
|
||||||
|
\(C_{i,0}\) are computed using \(R_{i-1}\), \(T_{i-1}\) and
|
||||||
|
\(T_i\).
|
||||||
|
|
||||||
|
A message key,
|
||||||
|
\(M_{i,j}\) is computed from the current chain key, \(C_{i,j}\), and
|
||||||
|
the chain key is replaced with the next chain key, \(C_{i,j+1}\). The
|
||||||
|
plain-text is encrypted with \(M_{i,j}\), using an authenticated encryption
|
||||||
|
scheme (see below) to get a cipher-text, \(X_{i,j}\).
|
||||||
|
|
||||||
|
The user then sends the following to the recipient:
|
||||||
|
* The current chain index, \(j\)
|
||||||
|
* The public part of the current ratchet key, \(T_i\)
|
||||||
|
* The cipher-text, \(X_{i,j}\)
|
||||||
|
|
||||||
|
### Receiving messages
|
||||||
|
|
||||||
|
The user receives a message as above with the sender's current chain index, \(j\),
|
||||||
|
the sender's ratchet key, \(T_i\), and the cipher-text, \(X_{i,j}\).
|
||||||
|
|
||||||
|
The user checks if they have a receiver chain with the correct
|
||||||
|
\(i\) by comparing the ratchet key, \(T_i\). If the chain doesn't exist
|
||||||
|
then they compute a new root key, \(R_i\), and a new receiver chain, with
|
||||||
|
chain key \(C_{i,0}\), using \(R_{i-1}\), \(T_{i-1}\) and
|
||||||
|
\(T_i\).
|
||||||
|
|
||||||
|
If the \(j\) of the message is less than
|
||||||
|
the current chain index on the receiver then the message may only be decrypted
|
||||||
|
if the receiver has stored a copy of the message key \(M_{i,j}\). Otherwise
|
||||||
|
the receiver computes the chain key, \(C_{i,j}\). The receiver computes the
|
||||||
|
message key, \(M_{i,j}\), from the chain key and attempts to decrypt the
|
||||||
|
cipher-text, \(X_{i,j}\).
|
||||||
|
|
||||||
|
If the decryption succeeds the receiver updates the chain key for \(T_i\)
|
||||||
|
with \(C_{i,j+1}\) and stores the message keys that were skipped in the
|
||||||
|
process so that they can decode out of order messages. If the receiver created
|
||||||
|
a new receiver chain then they discard their current sender chain so that
|
||||||
|
they will create a new chain when they next send a message.
|
||||||
|
|
||||||
|
## The Olm Message Format
|
||||||
|
|
||||||
|
Olm uses two types of messages. The underlying transport protocol must provide
|
||||||
|
a means for recipients to distinguish between them.
|
||||||
|
|
||||||
|
### Normal Messages
|
||||||
|
|
||||||
|
Olm messages start with a one byte version followed by a variable length
|
||||||
|
payload followed by a fixed length message authentication code.
|
||||||
|
|
||||||
|
```nohighlight
|
||||||
|
+--------------+------------------------------------+-----------+
|
||||||
|
| Version Byte | Payload Bytes | MAC Bytes |
|
||||||
|
+--------------+------------------------------------+-----------+
|
||||||
|
```
|
||||||
|
|
||||||
|
The version byte is ``"\x03"``.
|
||||||
|
|
||||||
|
The payload consists of key-value pairs where the keys are integers and the
|
||||||
|
values are integers and strings. The keys are encoded as a variable length
|
||||||
|
integer tag where the 3 lowest bits indicates the type of the value:
|
||||||
|
0 for integers, 2 for strings. If the value is an integer then the tag is
|
||||||
|
followed by the value encoded as a variable length integer. If the value is
|
||||||
|
a string then the tag is followed by the length of the string encoded as
|
||||||
|
a variable length integer followed by the string itself.
|
||||||
|
|
||||||
|
Olm uses a variable length encoding for integers. Each integer is encoded as a
|
||||||
|
sequence of bytes with the high bit set followed by a byte with the high bit
|
||||||
|
clear. The seven low bits of each byte store the bits of the integer. The least
|
||||||
|
significant bits are stored in the first byte.
|
||||||
|
|
||||||
|
**Name**|**Tag**|**Type**|**Meaning**
|
||||||
|
:-----:|:-----:|:-----:|:-----:
|
||||||
|
Ratchet-Key|0x0A|String|The public part of the ratchet key, Ti, of the message
|
||||||
|
Chain-Index|0x10|Integer|The chain index, j, of the message
|
||||||
|
Cipher-Text|0x22|String|The cipher-text, Xi, j, of the message
|
||||||
|
|
||||||
|
The length of the MAC is determined by the authenticated encryption algorithm
|
||||||
|
being used. (Olm version 1 uses [HMAC-SHA-256][], truncated to 8 bytes). The
|
||||||
|
MAC protects all of the bytes preceding the MAC.
|
||||||
|
|
||||||
|
### Pre-Key Messages
|
||||||
|
|
||||||
|
Olm pre-key messages start with a one byte version followed by a variable
|
||||||
|
length payload.
|
||||||
|
|
||||||
|
```nohighlight
|
||||||
|
+--------------+------------------------------------+
|
||||||
|
| Version Byte | Payload Bytes |
|
||||||
|
+--------------+------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
The version byte is ``"\x03"``.
|
||||||
|
|
||||||
|
The payload uses the same key-value format as for normal messages.
|
||||||
|
|
||||||
|
**Name**|**Tag**|**Type**|**Meaning**
|
||||||
|
:-----:|:-----:|:-----:|:-----:
|
||||||
|
One-Time-Key|0x0A|String|The public part of Bob's single-use key, Eb.
|
||||||
|
Base-Key|0x12|String|The public part of Alice's single-use key, Ea.
|
||||||
|
Identity-Key|0x1A|String|The public part of Alice's identity key, Ia.
|
||||||
|
Message|0x22|String|An embedded Olm message with its own version and MAC.
|
||||||
|
|
||||||
|
## Olm Authenticated Encryption
|
||||||
|
|
||||||
|
### Version 1
|
||||||
|
|
||||||
|
Version 1 of Olm uses [AES-256][] in [CBC][] mode with [PKCS#7][] padding for
|
||||||
|
encryption and [HMAC-SHA-256][] (truncated to 64 bits) for authentication. The
|
||||||
|
256 bit AES key, 256 bit HMAC key, and 128 bit AES IV are derived from the
|
||||||
|
message key using [HKDF-SHA-256][] using the default salt and an info of
|
||||||
|
``"OLM_KEYS"``.
|
||||||
|
|
||||||
|
\[
|
||||||
|
\begin{aligned}
|
||||||
|
AES\_KEY_{i,j}\;\parallel\;HMAC\_KEY_{i,j}\;\parallel\;AES\_IV_{i,j}
|
||||||
|
&= \operatorname{HKDF}\left(0,M_{i,j},\text{``OLM\_KEYS"},80\right)
|
||||||
|
\end{aligned}
|
||||||
|
\]
|
||||||
|
|
||||||
|
The plain-text is encrypted with AES-256, using the key \(AES\_KEY_{i,j}\)
|
||||||
|
and the IV \(AES\_IV_{i,j}\) to give the cipher-text, \(X_{i,j}\).
|
||||||
|
|
||||||
|
Then the entire message (including the Version Byte and all Payload Bytes) are
|
||||||
|
passed through [HMAC-SHA-256][]. The first 8 bytes of the MAC are appended to the message.
|
||||||
|
|
||||||
|
## Message authentication concerns
|
||||||
|
|
||||||
|
To avoid unknown key-share attacks, the application must include identifying
|
||||||
|
data for the sending and receiving user in the plain-text of (at least) the
|
||||||
|
pre-key messages. Such data could be a user ID, a telephone number;
|
||||||
|
alternatively it could be the public part of a keypair which the relevant user
|
||||||
|
has proven ownership of.
|
||||||
|
|
||||||
|
### Example attacks
|
||||||
|
|
||||||
|
1. Alice publishes her public [Curve25519][] identity key, \(I_A\). Eve
|
||||||
|
publishes the same identity key, claiming it as her own. Bob downloads
|
||||||
|
Eve's keys, and associates \(I_A\) with Eve. Alice sends a message to
|
||||||
|
Bob; Eve intercepts it before forwarding it to Bob. Bob believes the
|
||||||
|
message came from Eve rather than Alice.
|
||||||
|
|
||||||
|
This is prevented if Alice includes her user ID in the plain-text of the
|
||||||
|
pre-key message, so that Bob can see that the message was sent by Alice
|
||||||
|
originally.
|
||||||
|
|
||||||
|
2. Bob publishes his public [Curve25519][] identity key, \(I_B\). Eve
|
||||||
|
publishes the same identity key, claiming it as her own. Alice downloads
|
||||||
|
Eve's keys, and associates \(I_B\) with Eve. Alice sends a message to
|
||||||
|
Eve; Eve cannot decrypt it, but forwards it to Bob. Bob believes the
|
||||||
|
Alice sent the message to him, whereas Alice intended it to go to Eve.
|
||||||
|
|
||||||
|
This is prevented by Alice including the user ID of the intended recpient
|
||||||
|
(Eve) in the plain-text of the pre-key message. Bob can now tell that the
|
||||||
|
message was meant for Eve rather than him.
|
||||||
|
|
||||||
|
## IPR
|
||||||
|
|
||||||
|
The Olm specification (this document) is hereby placed in the public domain.
|
||||||
|
|
||||||
|
## Feedback
|
||||||
|
|
||||||
|
Can be sent to olm at matrix.org.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
The ratchet that Olm implements was designed by Trevor Perrin and Moxie
|
||||||
|
Marlinspike - details at https://whispersystems.org/docs/specifications/doubleratchet/. Olm is
|
||||||
|
an entirely new implementation written by the Matrix.org team.
|
||||||
|
|
||||||
|
[Curve25519]: http://cr.yp.to/ecdh.html
|
||||||
|
[Triple Diffie-Hellman]: https://whispersystems.org/blog/simplifying-otr-deniability/
|
||||||
|
[HMAC-based key derivation function]: https://tools.ietf.org/html/rfc5869
|
||||||
|
[HKDF-SHA-256]: https://tools.ietf.org/html/rfc5869
|
||||||
|
[HMAC-SHA-256]: https://tools.ietf.org/html/rfc2104
|
||||||
|
[SHA-256]: https://tools.ietf.org/html/rfc6234
|
||||||
|
[AES-256]: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||||
|
[CBC]: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||||
|
[PKCS#7]: https://tools.ietf.org/html/rfc2315
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: "Spec Change Proposals"
|
title: "Spec Change Proposals"
|
||||||
weight: 60
|
weight: 62
|
||||||
type: docs
|
type: docs
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -281,7 +281,7 @@ corresponding labels for each stage on the
|
||||||
[matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals)
|
[matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals)
|
||||||
pull request trackers.
|
pull request trackers.
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+ +
|
+ +
|
||||||
Proposals | Spec PRs | Additional States
|
Proposals | Spec PRs | Additional States
|
||||||
+-------+ | +------+ | +---------------+
|
+-------+ | +------+ | +---------------+
|
||||||
|
|
@ -497,6 +497,42 @@ In summary:
|
||||||
a small table at the bottom mapping the various values from stable
|
a small table at the bottom mapping the various values from stable
|
||||||
to unstable.
|
to unstable.
|
||||||
|
|
||||||
|
### Placeholder MSCs
|
||||||
|
|
||||||
|
Some proposals may contain security-sensitive or private context which can't be
|
||||||
|
publicly disclosed until a later stage in the idea or solution process. Typically,
|
||||||
|
the initial idea is validated using some amount of implementation or experimentation
|
||||||
|
and may require an MSC number to make that implementation easier.
|
||||||
|
|
||||||
|
Placeholder MSCs are used to represent proposals in a state where implementation
|
||||||
|
is ongoing, but the MSC details can't yet be disclosed. Authors which feel as
|
||||||
|
though their MSC could be highly sensitive MUST get in contact with the Spec Core
|
||||||
|
Team or [Security Team](https://matrix.org/security-disclosure-policy/) prior to
|
||||||
|
opening their MSC. If either team determines that a placeholder MSC is required,
|
||||||
|
it may be opened as such.
|
||||||
|
|
||||||
|
There are a few expectations attached to placeholder MSCs:
|
||||||
|
|
||||||
|
* They have a title which marks them WIP, and are in the "draft" state.
|
||||||
|
* They have the following labels: `[proposal-placeholder, action-required, needs-implementation]`.
|
||||||
|
* Notably, *not* `proposal`.
|
||||||
|
* They are relatively short-lived (ideally less than 6-12 months in placeholder).
|
||||||
|
* They propose solutions which are reasonably likely to be accepted. If a placeholder
|
||||||
|
needs to be closed because the idea won't work, isn't needed, etc, then the MSC's
|
||||||
|
content MUST be published ahead of that closure.
|
||||||
|
* Note: the MSC's publication (and therefore closure) may be delayed until an
|
||||||
|
appropriate point in the security disclosure cycle. For example, an alternative
|
||||||
|
MSC being published, or a stream of work being completed.
|
||||||
|
* When they are updated to receive real content, the following happens:
|
||||||
|
1. The Spec Core Team or the author leaves a comment to cause a notification
|
||||||
|
that the MSC has been replaced with real content.
|
||||||
|
2. The `proposal` label (or its equivalent) is added to trigger chat notifications
|
||||||
|
in the public Matrix rooms. The `proposal-placeholder` and `action-required`
|
||||||
|
labels should be removed at this stage as well. Other labels are removed/applied
|
||||||
|
per normal process.
|
||||||
|
* The Spec Core Team is aware of the intended MSC's title and purpose. This is
|
||||||
|
especially important if the Security Team approved the use of a placeholder MSC.
|
||||||
|
|
||||||
## Proposal Tracking
|
## Proposal Tracking
|
||||||
|
|
||||||
This is a living document generated from the list of proposals on the
|
This is a living document generated from the list of proposals on the
|
||||||
|
|
@ -519,7 +555,7 @@ resolve to the desired MSC, whether it started as an issue or a PR.
|
||||||
Other metadata:
|
Other metadata:
|
||||||
|
|
||||||
- The MSC number is taken from the GitHub Pull Request ID. This is
|
- The MSC number is taken from the GitHub Pull Request ID. This is
|
||||||
carried for the lifetime of the proposal. These IDs do not necessary
|
carried for the lifetime of the proposal. These IDs do not necessarily
|
||||||
represent a chronological order.
|
represent a chronological order.
|
||||||
- The GitHub PR title will act as the MSC's title.
|
- The GitHub PR title will act as the MSC's title.
|
||||||
- Please link to the spec PR (if any) by adding a "PRs: \#1234" line
|
- Please link to the spec PR (if any) by adding a "PRs: \#1234" line
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,18 @@
|
||||||
title: "Push Gateway API"
|
title: "Push Gateway API"
|
||||||
weight: 50
|
weight: 50
|
||||||
type: docs
|
type: docs
|
||||||
|
description: |
|
||||||
|
Clients may want to receive push notifications when events are received at the
|
||||||
|
homeserver. This is managed by a distinct entity called the Push Gateway.
|
||||||
---
|
---
|
||||||
|
|
||||||
Clients may want to receive push notifications when events are received
|
|
||||||
at the homeserver. This is managed by a distinct entity called the Push
|
|
||||||
Gateway.
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
A client's homeserver forwards information about received events to the
|
A client's homeserver forwards information about received events to the
|
||||||
push gateway. The gateway then submits a push notification to the push
|
push gateway. The gateway then submits a push notification to the push
|
||||||
notification provider (e.g. APNS, GCM).
|
notification provider (e.g. APNS, GCM).
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+--------------------+ +-------------------+
|
+--------------------+ +-------------------+
|
||||||
Matrix HTTP | | | |
|
Matrix HTTP | | | |
|
||||||
Notification Protocol | App Developer | | Device Vendor |
|
Notification Protocol | App Developer | | Device Vendor |
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,12 @@ Alternatively, consider flipping the column/row organization to be features
|
||||||
up top and versions on the left.
|
up top and versions on the left.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|
| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
|
||||||
|-------------------|---|---|---|---|---|---|---|---|---|----|----|
|
|-------------------|---|---|---|---|---|---|---|---|---|----|----|----|
|
||||||
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
|
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
|
||||||
| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ |
|
| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
|
||||||
| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ |
|
| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
|
||||||
|
| **Additional room creators** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |
|
||||||
|
|
||||||
## Complete list of room versions
|
## Complete list of room versions
|
||||||
|
|
||||||
|
|
@ -52,9 +53,22 @@ stable and unstable periodically for a variety of reasons, including
|
||||||
discovered security vulnerabilities and age.
|
discovered security vulnerabilities and age.
|
||||||
|
|
||||||
Clients should not ask room administrators to upgrade their rooms if the
|
Clients should not ask room administrators to upgrade their rooms if the
|
||||||
room is running a stable version. Servers SHOULD use **room version 11** as
|
room is running a stable version. Servers SHOULD use **room version 12** as
|
||||||
the default room version when creating new rooms.
|
the default room version when creating new rooms.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
|
||||||
|
{{% added-in v="1.16" %}}
|
||||||
|
|
||||||
|
Room version 12 is introduced and made default in this specification release.
|
||||||
|
Servers are encouraged to continue using room version 11 as the default room
|
||||||
|
version for the early days and weeks following this specification release,
|
||||||
|
and then gradually switch the default over when they deem appropriate.
|
||||||
|
|
||||||
|
<!-- TODO(SCT): Remove this note box in Matrix 1.17 -->
|
||||||
|
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
The available room versions are:
|
The available room versions are:
|
||||||
|
|
||||||
- [Version 1](/rooms/v1) - **Stable**. The initial room version.
|
- [Version 1](/rooms/v1) - **Stable**. The initial room version.
|
||||||
|
|
@ -76,6 +90,9 @@ The available room versions are:
|
||||||
- [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels
|
- [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels
|
||||||
and adds `knock_restricted` join rule.
|
and adds `knock_restricted` join rule.
|
||||||
- [Version 11](/rooms/v11) - **Stable**. Clarifies the redaction algorithm.
|
- [Version 11](/rooms/v11) - **Stable**. Clarifies the redaction algorithm.
|
||||||
|
- [Version 12](/rooms/v12) - **Stable**. Changes room IDs to be hashes of the
|
||||||
|
create event, formalizes room creators with infinite power level, and iterates
|
||||||
|
on state resolution.
|
||||||
|
|
||||||
## Room version grammar
|
## Room version grammar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
|
||||||
4
content/rooms/fragments/v12-event-format.md
Normal file
4
content/rooms/fragments/v12-event-format.md
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
Events in rooms of this version have the following structure:
|
||||||
|
|
||||||
|
{{% definition path="api/server-server/definitions/pdu_v12" %}}
|
||||||
|
|
@ -38,10 +38,14 @@ The complete list of rules, as of room version 3, is as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ is met:
|
||||||
2. The domain of the redaction event's `sender` matches that of the
|
2. The domain of the redaction event's `sender` matches that of the
|
||||||
original event's `sender`.
|
original event's `sender`.
|
||||||
|
|
||||||
|
Note that the first condition holds true even when the `sender` doesn't have a
|
||||||
|
high enough power level to send the type of event that they're redacting.
|
||||||
|
|
||||||
If the server would apply a redaction, the redaction event is also sent
|
If the server would apply a redaction, the redaction event is also sent
|
||||||
to clients. Otherwise, the server simply waits for a valid partner event
|
to clients. Otherwise, the server simply waits for a valid partner event
|
||||||
to arrive where it can then re-check the above.
|
to arrive where it can then re-check the above.
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
@ -70,7 +74,7 @@ The rules are as follows:
|
||||||
1. If membership state is `join` or `invite`, allow.
|
1. If membership state is `join` or `invite`, allow.
|
||||||
2. If the `join_authorised_via_users_server` key in `content`
|
2. If the `join_authorised_via_users_server` key in `content`
|
||||||
is not a user with sufficient permission to invite other
|
is not a user with sufficient permission to invite other
|
||||||
users, reject.
|
users or is not a joined member of the room, reject.
|
||||||
3. Otherwise, allow.
|
3. Otherwise, allow.
|
||||||
6. If the `join_rule` is `public`, allow.
|
6. If the `join_rule` is `public`, allow.
|
||||||
7. Otherwise, reject.
|
7. Otherwise, reject.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ refined in [room version 9](/rooms/v9)).
|
||||||
|
|
||||||
Clients should render the new join rule accordingly for such rooms. For example:
|
Clients should render the new join rule accordingly for such rooms. For example:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
This room is:
|
This room is:
|
||||||
[ ] Public
|
[ ] Public
|
||||||
[x] Private
|
[x] Private
|
||||||
|
|
@ -120,10 +120,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
@ -146,7 +150,7 @@ The rules are as follows:
|
||||||
1. If membership state is `join` or `invite`, allow.
|
1. If membership state is `join` or `invite`, allow.
|
||||||
2. If the `join_authorised_via_users_server` key in `content`
|
2. If the `join_authorised_via_users_server` key in `content`
|
||||||
is not a user with sufficient permission to invite other
|
is not a user with sufficient permission to invite other
|
||||||
users, reject.
|
users or is not a joined member of the room, reject.
|
||||||
3. Otherwise, allow.
|
3. Otherwise, allow.
|
||||||
6. If the `join_rule` is `public`, allow.
|
6. If the `join_rule` is `public`, allow.
|
||||||
7. Otherwise, reject.
|
7. Otherwise, reject.
|
||||||
|
|
|
||||||
|
|
@ -127,10 +127,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
@ -153,7 +157,7 @@ The rules are as follows:
|
||||||
1. If membership state is `join` or `invite`, allow.
|
1. If membership state is `join` or `invite`, allow.
|
||||||
2. If the `join_authorised_via_users_server` key in `content`
|
2. If the `join_authorised_via_users_server` key in `content`
|
||||||
is not a user with sufficient permission to invite other
|
is not a user with sufficient permission to invite other
|
||||||
users, reject.
|
users or is not a joined member of the room, reject.
|
||||||
3. Otherwise, allow.
|
3. Otherwise, allow.
|
||||||
6. If the `join_rule` is `public`, allow.
|
6. If the `join_rule` is `public`, allow.
|
||||||
7. Otherwise, reject.
|
7. Otherwise, reject.
|
||||||
|
|
|
||||||
501
content/rooms/v12.md
Normal file
501
content/rooms/v12.md
Normal file
|
|
@ -0,0 +1,501 @@
|
||||||
|
---
|
||||||
|
title: Room Version 12
|
||||||
|
type: docs
|
||||||
|
weight: 100
|
||||||
|
version: 12
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 11](/rooms/v11), iterating on the state resolution
|
||||||
|
algorithm, giving room creators infinite power level, and changing the format of room
|
||||||
|
IDs to be a hash of the create event.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
### Event format
|
||||||
|
|
||||||
|
Clients SHOULD observe the following changes to events in this room version:
|
||||||
|
|
||||||
|
* Room IDs no longer include a domain component and are instead a hash of the
|
||||||
|
`m.room.create` event, per below. See the [room ID grammar](/appendices#room-ids)
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
* A concept of "room creators" is formally defined as the `sender` of the `m.room.create`
|
||||||
|
event *plus* any `additional_creators` from the `m.room.create` event's `content`,
|
||||||
|
if present. In prior room versions, the only creator was the `sender` of the
|
||||||
|
`m.room.create` event (or `creator` in much older room versions).
|
||||||
|
|
||||||
|
* Room creators have infinitely high power level and cannot be specified in the
|
||||||
|
`m.room.power_levels` event, nor can they be changed after the room is created.
|
||||||
|
|
||||||
|
## Server implementation components
|
||||||
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
The information contained in this section is strictly for server
|
||||||
|
implementors. Applications which use the Client-Server API are generally
|
||||||
|
unaffected by the intricacies contained here. The section above
|
||||||
|
regarding client considerations is the resource that Client-Server API
|
||||||
|
use cases should reference.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
|
Room version 12 is based upon room version 11 with the following considerations.
|
||||||
|
|
||||||
|
### Event format
|
||||||
|
|
||||||
|
{{% rver-fragment name="v12-event-format" %}}
|
||||||
|
|
||||||
|
### Authorization rules
|
||||||
|
|
||||||
|
Events must be signed by the server denoted by the `sender` property.
|
||||||
|
|
||||||
|
The types of state events that affect authorization are:
|
||||||
|
|
||||||
|
- [`m.room.create`](/client-server-api#mroomcreate)
|
||||||
|
- [`m.room.member`](/client-server-api#mroommember)
|
||||||
|
- [`m.room.join_rules`](/client-server-api#mroomjoin_rules)
|
||||||
|
- [`m.room.power_levels`](/client-server-api#mroompower_levels)
|
||||||
|
- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite)
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Power levels are inferred from defaults when not explicitly supplied.
|
||||||
|
For example, mentions of the `sender`'s power level can also refer to
|
||||||
|
the default power level for users in the room.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v=12 %}} The power level of "room creators" is infinitely high.
|
||||||
|
|
||||||
|
Room creators include:
|
||||||
|
* The user ID denoted by the `sender` of the `m.room.create` event in the room.
|
||||||
|
* Any user IDs contained in the `additional_creators` array in `content` of the
|
||||||
|
`m.room.create` event in the room, if `additional_creators` is present.
|
||||||
|
|
||||||
|
Room creators cannot be demoted to a lower power level, even through `m.room.power_levels`.
|
||||||
|
This is reflected in rule 10.4 below.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
`m.room.redaction` events are subject to auth rules in the same way as any other event.
|
||||||
|
In practice, that means they will normally be allowed by the auth rules, unless the
|
||||||
|
`m.room.power_levels` event sets a power level requirement for `m.room.redaction`
|
||||||
|
events via the `events` or `events_default` properties. In particular, the _redact
|
||||||
|
level_ is **not** considered by the auth rules.
|
||||||
|
|
||||||
|
The ability to send a redaction event does not mean that the redaction itself should
|
||||||
|
be performed. Receiving servers must perform additional checks, as described in
|
||||||
|
the [Handling redactions](#handling-redactions) section.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
The `m.room.create` event MUST NOT be selected for `auth_events` on events. The
|
||||||
|
`room_id` (being the `m.room.create` event's ID) implies this instead. This is
|
||||||
|
reflected in a change to rule 3.2 below.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
The rules are as follows:
|
||||||
|
|
||||||
|
1. If type is `m.room.create`:
|
||||||
|
1. If it has any `prev_events`, reject.
|
||||||
|
2. {{% changed-in v=12 %}} If the event has a `room_id`, reject.
|
||||||
|
|
||||||
|
**Note**: The room ID is the event ID of the event with sigil `!` instead
|
||||||
|
of `$`.
|
||||||
|
3. If `content.room_version` is present and is not a recognised
|
||||||
|
version, reject.
|
||||||
|
4. {{% added-in v=12 %}} If `additional_creators` is present in `content` and
|
||||||
|
is not an array of strings where each string passes the same [user ID](/appendices#user-identifiers)
|
||||||
|
validation applied to `sender`, reject.
|
||||||
|
5. Otherwise, allow.
|
||||||
|
2. {{% added-in v=12 %}} If the event's `room_id` is not an event ID for an accepted
|
||||||
|
(not rejected) `m.room.create` event, with the sigil `!` instead of `$`, reject.
|
||||||
|
3. Considering the event's `auth_events`:
|
||||||
|
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||||
|
reject.
|
||||||
|
2. {{% changed-in v=12 %}} If there are entries whose `type` and `state_key`
|
||||||
|
don't match those specified by the [auth events selection](/server-server-api#auth-events-selection)
|
||||||
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: In this room version, `m.room.create` MUST NOT be selected.
|
||||||
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
|
performed on receipt of a
|
||||||
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
|
4. If the `content` of the `m.room.create` event in the room state has the
|
||||||
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
5. If type is `m.room.member`:
|
||||||
|
1. If there is no `state_key` property, or no `membership` property in
|
||||||
|
`content`, reject.
|
||||||
|
2. If `content` has a `join_authorised_via_users_server`
|
||||||
|
key:
|
||||||
|
1. If the event is not validly signed by the homeserver of the user ID denoted
|
||||||
|
by the key, reject.
|
||||||
|
3. If `membership` is `join`:
|
||||||
|
1. If the only previous event is an `m.room.create` and the
|
||||||
|
`state_key` is the sender of the `m.room.create`, allow.
|
||||||
|
2. If the `sender` does not match `state_key`, reject.
|
||||||
|
3. If the `sender` is banned, reject.
|
||||||
|
4. If the `join_rule` is `invite` or `knock` then allow if
|
||||||
|
membership state is `invite` or `join`.
|
||||||
|
5. If the `join_rule` is `restricted` or `knock_restricted`:
|
||||||
|
1. If membership state is `join` or `invite`, allow.
|
||||||
|
2. If the `join_authorised_via_users_server` key in `content`
|
||||||
|
is not a user with sufficient permission to invite other
|
||||||
|
users or is not a joined member of the room, reject.
|
||||||
|
3. Otherwise, allow.
|
||||||
|
6. If the `join_rule` is `public`, allow.
|
||||||
|
7. Otherwise, reject.
|
||||||
|
4. If `membership` is `invite`:
|
||||||
|
1. If `content` has a `third_party_invite` property:
|
||||||
|
1. If *target user* is banned, reject.
|
||||||
|
2. If `content.third_party_invite` does not have a `signed`
|
||||||
|
property, reject.
|
||||||
|
3. If `signed` does not have `mxid` and `token` properties,
|
||||||
|
reject.
|
||||||
|
4. If `mxid` does not match `state_key`, reject.
|
||||||
|
5. If there is no `m.room.third_party_invite` event in the
|
||||||
|
current room state with `state_key` matching `token`,
|
||||||
|
reject.
|
||||||
|
6. If `sender` does not match `sender` of the
|
||||||
|
`m.room.third_party_invite`, reject.
|
||||||
|
7. If any signature in `signed` matches any public key in
|
||||||
|
the `m.room.third_party_invite` event, allow. The public
|
||||||
|
keys are in `content` of `m.room.third_party_invite` as:
|
||||||
|
1. A single public key in the `public_key` property.
|
||||||
|
2. A list of public keys in the `public_keys` property.
|
||||||
|
8. Otherwise, reject.
|
||||||
|
2. If the `sender`'s current membership state is not `join`,
|
||||||
|
reject.
|
||||||
|
3. If *target user*'s current membership state is `join` or
|
||||||
|
`ban`, reject.
|
||||||
|
4. If the `sender`'s power level is greater than or equal to
|
||||||
|
the *invite level*, allow.
|
||||||
|
5. Otherwise, reject.
|
||||||
|
5. If `membership` is `leave`:
|
||||||
|
1. If the `sender` matches `state_key`, allow if and only if
|
||||||
|
that user's current membership state is `invite`, `join`,
|
||||||
|
or `knock`.
|
||||||
|
2. If the `sender`'s current membership state is not `join`,
|
||||||
|
reject.
|
||||||
|
3. If the *target user*'s current membership state is `ban`,
|
||||||
|
and the `sender`'s power level is less than the *ban level*,
|
||||||
|
reject.
|
||||||
|
4. If the `sender`'s power level is greater than or equal to
|
||||||
|
the *kick level*, and the *target user*'s power level is
|
||||||
|
less than the `sender`'s power level, allow.
|
||||||
|
5. Otherwise, reject.
|
||||||
|
6. If `membership` is `ban`:
|
||||||
|
1. If the `sender`'s current membership state is not `join`,
|
||||||
|
reject.
|
||||||
|
2. If the `sender`'s power level is greater than or equal to
|
||||||
|
the *ban level*, and the *target user*'s power level is less
|
||||||
|
than the `sender`'s power level, allow.
|
||||||
|
3. Otherwise, reject.
|
||||||
|
7. If `membership` is `knock`:
|
||||||
|
1. If the `join_rule` is anything other than `knock` or
|
||||||
|
`knock_restricted`, reject.
|
||||||
|
2. If `sender` does not match `state_key`, reject.
|
||||||
|
3. If the `sender`'s current membership is not `ban`, `invite`,
|
||||||
|
or `join`, allow.
|
||||||
|
4. Otherwise, reject.
|
||||||
|
8. Otherwise, the membership is unknown. Reject.
|
||||||
|
6. If the `sender`'s current membership state is not `join`, reject.
|
||||||
|
7. If type is `m.room.third_party_invite`:
|
||||||
|
1. Allow if and only if `sender`'s current power level is greater
|
||||||
|
than or equal to the *invite level*.
|
||||||
|
8. If the event type's *required power level* is greater than the
|
||||||
|
`sender`'s power level, reject.
|
||||||
|
9. If the event has a `state_key` that starts with an `@` and does not
|
||||||
|
match the `sender`, reject.
|
||||||
|
10. If type is `m.room.power_levels`:
|
||||||
|
1. If any of the properties `users_default`, `events_default`, `state_default`,
|
||||||
|
`ban`, `redact`, `kick`, or `invite` in `content` are present and
|
||||||
|
not an integer, reject.
|
||||||
|
2. If either of the properties `events` or `notifications` in `content`
|
||||||
|
are present and not an object with values that are integers,
|
||||||
|
reject.
|
||||||
|
3. If the `users` property in `content` is not an object with keys that
|
||||||
|
are valid user IDs with values that are integers, reject.
|
||||||
|
4. {{% added-in v=12 %}} If the `users` property in `content` contains the
|
||||||
|
`sender` of the `m.room.create` event or any of the `additional_creators`
|
||||||
|
array (if present) from the `content` of the `m.room.create` event, reject.
|
||||||
|
5. If there is no previous `m.room.power_levels` event in the room,
|
||||||
|
allow.
|
||||||
|
6. For the properties `users_default`, `events_default`, `state_default`,
|
||||||
|
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||||
|
changed or removed. For each found alteration:
|
||||||
|
1. If the current value is higher than the `sender`'s current
|
||||||
|
power level, reject.
|
||||||
|
2. If the new value is higher than the `sender`'s current power
|
||||||
|
level, reject.
|
||||||
|
7. For each entry being changed in, or removed from, the `events` or
|
||||||
|
`notifications` properties:
|
||||||
|
1. If the current value is greater than the `sender`'s current
|
||||||
|
power level, reject.
|
||||||
|
8. For each entry being added to, or changed in, the `events` or
|
||||||
|
`notifications` properties:
|
||||||
|
1. If the new value is greater than the `sender`'s current power
|
||||||
|
level, reject.
|
||||||
|
9. For each entry being changed in, or removed from, the `users` property,
|
||||||
|
other than the `sender`'s own entry:
|
||||||
|
1. If the current value is greater than or equal to the `sender`'s
|
||||||
|
current power level, reject.
|
||||||
|
10. For each entry being added to, or changed in, the `users` property:
|
||||||
|
1. If the new value is greater than the `sender`'s current power
|
||||||
|
level, reject.
|
||||||
|
10. Otherwise, allow.
|
||||||
|
11. Otherwise, allow.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Some consequences of these rules:
|
||||||
|
|
||||||
|
- Unless you are a member of the room, the only permitted operations
|
||||||
|
(apart from the initial create/join) are: joining a public room;
|
||||||
|
accepting or rejecting an invitation to a room.
|
||||||
|
- To unban somebody, you must have power level greater than or equal
|
||||||
|
to both the kick *and* ban levels, *and* greater than the target
|
||||||
|
user's power level.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
### State resolution
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v=12 %}} This state resolution algorithm is largely the same as the
|
||||||
|
algorithm found in [room version 2](/rooms/v2) with the following modifications:
|
||||||
|
|
||||||
|
1. The *iterative auth checks algorithm* in the [Algorithm](#algorithm) subsection
|
||||||
|
now starts with an *empty* state map instead of the unconflicted state map.
|
||||||
|
|
||||||
|
2. A new [definition](#definitions) for *conflicted state subgraph* has been added
|
||||||
|
which describes events that are required to authorize events during iterative
|
||||||
|
auth checks.
|
||||||
|
|
||||||
|
3. To ensure the new conflicted state subgraph is actually referenced, the definition
|
||||||
|
for *full conflicted set* additionally includes the subgraph.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
The room state *S′(E)* after an event *E* is defined in terms of the
|
||||||
|
room state *S(E)* before *E*, and depends on whether *E* is a state
|
||||||
|
event or a message event:
|
||||||
|
|
||||||
|
- If *E* is a message event, then *S′(E)* = *S(E)*.
|
||||||
|
- If *E* is a state event, then *S′(E)* is *S(E)*, except that its
|
||||||
|
entry corresponding to the `event_type` and `state_key` of *E* is
|
||||||
|
replaced by the `event_id` of *E*.
|
||||||
|
|
||||||
|
The room state *S(E)* before *E* is the *resolution* of the set of
|
||||||
|
states {*S′(E*<sub>1</sub>*)*, *S′(E*<sub>2</sub>*)*, …}
|
||||||
|
after the `prev_event`s {*E*<sub>1</sub>, *E*<sub>2</sub>, …} of *E*.
|
||||||
|
The resolution of a set of states is given in the algorithm below.
|
||||||
|
|
||||||
|
#### Definitions
|
||||||
|
|
||||||
|
The state resolution algorithm for version 2 rooms uses the following
|
||||||
|
definitions, given the set of room states
|
||||||
|
{*S*<sub>1</sub>, *S*<sub>2</sub>, …}:
|
||||||
|
|
||||||
|
**Power events.**
|
||||||
|
A *power event* is a state event with type `m.room.power_levels` or
|
||||||
|
`m.room.join_rules`, or a state event with type `m.room.member` where
|
||||||
|
the `membership` is `leave` or `ban` and the `sender` does not match the
|
||||||
|
`state_key`. The idea behind this is that power events are events that
|
||||||
|
might remove someone's ability to do something in the room.
|
||||||
|
|
||||||
|
**Unconflicted state map and conflicted state set.**
|
||||||
|
The keys of the state maps *S<sub>i</sub>* are 2-tuples of strings of the form
|
||||||
|
*K* = `(event_type, state_key)`. The values *V* are state events.
|
||||||
|
The key-value pairs (*K*, *V*) across all state maps *S<sub>i</sub>* can be
|
||||||
|
divided into two collections.
|
||||||
|
If a given key *K* is present in every *S<sub>i</sub>* with the same value *V*
|
||||||
|
in each state map, then the pair (*K*, *V*) belongs to the *unconflicted state map*.
|
||||||
|
Otherwise, *V* belongs to the *conflicted state set*.
|
||||||
|
|
||||||
|
Note that the unconflicted state map only has one event for each key *K*,
|
||||||
|
whereas the conflicted state set may contain multiple events with the same key.
|
||||||
|
|
||||||
|
**Auth chain.**
|
||||||
|
The *auth chain* of an event *E* is the set containing all of *E*'s auth events,
|
||||||
|
all of *their* auth events, and so on recursively, stretching back to the
|
||||||
|
start of the room. Put differently, these are the events reachable by walking
|
||||||
|
the graph induced by an event's `auth_events` links.
|
||||||
|
|
||||||
|
**Auth difference.**
|
||||||
|
The *auth difference* is calculated by first calculating the full auth
|
||||||
|
chain for each state *S*<sub>*i*</sub>, that is the union of the auth
|
||||||
|
chains for each event in *S*<sub>*i*</sub>, and then taking every event
|
||||||
|
that doesn't appear in every auth chain. If *C*<sub>*i*</sub> is the
|
||||||
|
full auth chain of *S*<sub>*i*</sub>, then the auth difference is
|
||||||
|
∪ *C*<sub>*i*</sub> − ∩ *C*<sub>*i*</sub>.
|
||||||
|
|
||||||
|
{{% added-in v=12 %}} **Conflicted state subgraph.**
|
||||||
|
Starting from an event in the *conflicted state set* and following `auth_events`
|
||||||
|
edges may lead to another event in the conflicted state set. The union of all
|
||||||
|
such paths between any pair of events in the conflicted state set (including
|
||||||
|
endpoints) forms a subgraph of the original `auth_event` graph, called the
|
||||||
|
*conflicted state subgraph*.
|
||||||
|
|
||||||
|
{{% changed-in v=12 %}} **Full conflicted set.**
|
||||||
|
The *full conflicted set* is the union of the conflicted state set, the conflicted
|
||||||
|
state subgraph, and the auth difference.
|
||||||
|
|
||||||
|
**Reverse topological power ordering.**
|
||||||
|
The *reverse topological power ordering* of a set of events is the
|
||||||
|
lexicographically smallest topological ordering based on the DAG formed
|
||||||
|
by auth events. The reverse topological power ordering is ordered from
|
||||||
|
earliest event to latest. For comparing two topological orderings to
|
||||||
|
determine which is the lexicographically smallest, the following
|
||||||
|
comparison relation on events is used: for events *x* and *y*,
|
||||||
|
*x* < *y* if
|
||||||
|
|
||||||
|
1. *x*'s sender has *greater* power level than *y*'s sender, when
|
||||||
|
looking at their respective `auth_event`s; or
|
||||||
|
2. the senders have the same power level, but *x*'s `origin_server_ts`
|
||||||
|
is *less* than *y*'s `origin_server_ts`; or
|
||||||
|
3. the senders have the same power level and the events have the same
|
||||||
|
`origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s
|
||||||
|
`event_id`.
|
||||||
|
|
||||||
|
The reverse topological power ordering can be found by sorting the
|
||||||
|
events using Kahn's algorithm for topological sorting, and at each step
|
||||||
|
selecting, among all the candidate vertices, the smallest vertex using
|
||||||
|
the above comparison relation.
|
||||||
|
|
||||||
|
**Mainline ordering.**
|
||||||
|
Let *P* = *P*<sub>0</sub> be an `m.room.power_levels` event.
|
||||||
|
Starting with *i* = 0, repeatedly fetch *P*<sub>*i*+1</sub>, the
|
||||||
|
`m.room.power_levels` event in the `auth_events` of *P<sub>i</sub>*.
|
||||||
|
Increment *i* and repeat until *P<sub>i</sub>* has no `m.room.power_levels`
|
||||||
|
event in its `auth_events`.
|
||||||
|
The *mainline of P*<sub>0</sub> is the list of events
|
||||||
|
[*P*<sub>0</sub> , *P*<sub>1</sub>, ... , *P<sub>n</sub>*],
|
||||||
|
fetched in this way.
|
||||||
|
|
||||||
|
Let *e* = *e<sub>0</sub>* be another event (possibly another
|
||||||
|
`m.room.power_levels` event). We can compute a similar list of events
|
||||||
|
[*e*<sub>1</sub>, ..., *e<sub>m</sub>*],
|
||||||
|
where *e*<sub>*j*+1</sub> is the `m.room.power_levels` event in the
|
||||||
|
`auth_events` of *e<sub>j</sub>* and where *e<sub>m</sub>* has no
|
||||||
|
`m.room.power_levels` event in its `auth_events`. (Note that the event we
|
||||||
|
started with, *e<sub>0</sub>*, is not included in this list. Also note that it
|
||||||
|
may be empty, because *e* may not cite an `m.room.power_levels` event in its
|
||||||
|
`auth_events` at all.)
|
||||||
|
|
||||||
|
Now compare these two lists as follows.
|
||||||
|
* Find the smallest index *j* ≥ 1 for which *e<sub>j</sub>* belongs to the
|
||||||
|
mainline of *P*.
|
||||||
|
* If such a *j* exists, then *e<sub>j</sub>* = *P<sub>i</sub>* for some unique
|
||||||
|
index *i* ≥ 0. Otherwise set *i* = ∞, where ∞ is a sentinel value greater
|
||||||
|
than any integer.
|
||||||
|
* In both cases, the *mainline position* of *e* is *i*.
|
||||||
|
|
||||||
|
Given mainline positions calculated from *P*, the *mainline ordering based on* *P* of a set of events is the ordering,
|
||||||
|
from smallest to largest, using the following comparison relation on
|
||||||
|
events: for events *x* and *y*, *x* < *y* if
|
||||||
|
|
||||||
|
1. the mainline position of *x* is **greater** than
|
||||||
|
the mainline position of *y* (i.e. the auth chain of
|
||||||
|
*x* is based on an earlier event in the mainline than *y*); or
|
||||||
|
2. the mainline positions of the events are the same, but *x*'s
|
||||||
|
`origin_server_ts` is *less* than *y*'s `origin_server_ts`; or
|
||||||
|
3. the mainline positions of the events are the same and the events have the
|
||||||
|
same `origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s
|
||||||
|
`event_id`.
|
||||||
|
|
||||||
|
**Iterative auth checks.**
|
||||||
|
The *iterative auth checks algorithm* takes as input an initial room
|
||||||
|
state and a sorted list of state events, and constructs a new room state
|
||||||
|
by iterating through the event list and applying the state event to the
|
||||||
|
room state if the state event is allowed by the [authorization
|
||||||
|
rules](/server-server-api#authorization-rules).
|
||||||
|
If the state event is not allowed by the authorization rules, then the
|
||||||
|
event is ignored. If a `(event_type, state_key)` key that is required
|
||||||
|
for checking the authorization rules is not present in the state, then
|
||||||
|
the appropriate state event from the event's `auth_events` is used if
|
||||||
|
the auth event is not rejected.
|
||||||
|
|
||||||
|
#### Algorithm
|
||||||
|
|
||||||
|
The *resolution* of a set of states is obtained as follows:
|
||||||
|
|
||||||
|
1. Select the set *X* of all *power events* that appear in the *full
|
||||||
|
conflicted set*. For each such power event *P*, enlarge *X* by adding
|
||||||
|
the events in the auth chain of *P* which also belong to the full
|
||||||
|
conflicted set. Sort *X* into a list using the *reverse topological
|
||||||
|
power ordering*.
|
||||||
|
2. {{% changed-in v=12 %}} Apply the *iterative auth checks algorithm*,
|
||||||
|
starting from an *empty* state map, to the list of events from the previous
|
||||||
|
step to get a partially resolved state.
|
||||||
|
3. Take all remaining events that weren't picked in step 1 and order
|
||||||
|
them by the mainline ordering based on the power level in the
|
||||||
|
partially resolved state obtained in step 2.
|
||||||
|
4. Apply the *iterative auth checks algorithm* on the partial resolved
|
||||||
|
state and the list of events from the previous step.
|
||||||
|
5. Update the result by replacing any event with the event with the
|
||||||
|
same key from the *unconflicted state map*, if such an event exists,
|
||||||
|
to get the final resolved state.
|
||||||
|
|
||||||
|
#### Rejected events
|
||||||
|
|
||||||
|
Events that have been rejected due to failing auth based on the state at
|
||||||
|
the event (rather than based on their auth chain) are handled as usual
|
||||||
|
by the algorithm, unless otherwise specified.
|
||||||
|
|
||||||
|
Note that no events rejected due to failure to auth against their auth
|
||||||
|
chain should appear in the process, as they should not appear in state
|
||||||
|
(the algorithm only uses events that appear in either the state sets or
|
||||||
|
in the auth chain of the events in the state sets).
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
This helps ensure that different servers' view of state is more likely
|
||||||
|
to converge, since rejection state of an event may be different. This
|
||||||
|
can happen if a third server gives an incorrect version of the state
|
||||||
|
when a server joins a room via it (either due to being faulty or
|
||||||
|
malicious). Convergence of state is a desirable property as it ensures
|
||||||
|
that all users in the room have a (mostly) consistent view of the state
|
||||||
|
of the room. If the view of the state on different servers diverges it
|
||||||
|
can lead to bifurcation of the room due to e.g. servers disagreeing on
|
||||||
|
who is in the room.
|
||||||
|
|
||||||
|
Intuitively, using rejected events feels dangerous, however:
|
||||||
|
|
||||||
|
1. Servers cannot arbitrarily make up state, since they still need to
|
||||||
|
pass the auth checks based on the event's auth chain (e.g. they
|
||||||
|
can't grant themselves power levels if they didn't have them
|
||||||
|
before).
|
||||||
|
2. For a previously rejected event to pass auth there must be a set of
|
||||||
|
state that allows said event. A malicious server could therefore
|
||||||
|
produce a fork where it claims the state is that particular set of
|
||||||
|
state, duplicate the rejected event to point to that fork, and send
|
||||||
|
the event. The duplicated event would then pass the auth checks.
|
||||||
|
Ignoring rejected events would therefore not eliminate any potential
|
||||||
|
attack vectors.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
Rejected auth events are deliberately excluded from use in the iterative
|
||||||
|
auth checks, as auth events aren't re-authed (although non-auth events
|
||||||
|
are) during the iterative auth checks.
|
||||||
|
|
||||||
|
## Unchanged from v11
|
||||||
|
|
||||||
|
The following sections have not been modified since v11, but are included for
|
||||||
|
completeness.
|
||||||
|
|
||||||
|
### Redactions
|
||||||
|
|
||||||
|
{{% rver-fragment name="v11-redactions" %}}
|
||||||
|
|
||||||
|
### Handling redactions
|
||||||
|
|
||||||
|
{{% rver-fragment name="v3-handling-redactions" %}}
|
||||||
|
|
||||||
|
### Event IDs
|
||||||
|
|
||||||
|
{{% rver-fragment name="v4-event-ids" %}}
|
||||||
|
|
||||||
|
### Canonical JSON
|
||||||
|
|
||||||
|
{{% rver-fragment name="v6-canonical-json" %}}
|
||||||
|
|
||||||
|
### Signing key validity period
|
||||||
|
|
||||||
|
{{% rver-fragment name="v5-signing-requirements" %}}
|
||||||
|
|
@ -102,10 +102,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,14 @@ The rules are as follows:
|
||||||
specified by the [auth events
|
specified by the [auth events
|
||||||
selection](/server-server-api#auth-events-selection)
|
selection](/server-server-api#auth-events-selection)
|
||||||
algorithm described in the server specification, reject.
|
algorithm described in the server specification, reject.
|
||||||
|
|
||||||
|
**Note**: This room version requires an `m.room.create` event to be selected.
|
||||||
3. If there are entries which were themselves rejected under the [checks
|
3. If there are entries which were themselves rejected under the [checks
|
||||||
performed on receipt of a
|
performed on receipt of a
|
||||||
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
|
||||||
4. If there is no `m.room.create` event among the entries, reject.
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
5. If any event in `auth_events` has a `room_id` which does not match that of
|
||||||
|
the event being authorised, reject.
|
||||||
3. If the `content` of the `m.room.create` event in the room state has the
|
3. If the `content` of the `m.room.create` event in the room state has the
|
||||||
property `m.federate` set to `false`, and the `sender` domain of the event
|
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||||
does not match the `sender` domain of the create event, reject.
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
|
|
||||||
|
|
@ -2,49 +2,46 @@
|
||||||
title: "Server-Server API"
|
title: "Server-Server API"
|
||||||
weight: 20
|
weight: 20
|
||||||
type: docs
|
type: docs
|
||||||
|
description: |
|
||||||
|
Matrix homeservers use the Federation APIs (also known as server-server APIs)
|
||||||
|
to communicate with each other. Homeservers use these APIs to push messages in
|
||||||
|
real-time, retrieve historic messages, and query profile or presence
|
||||||
|
information about users on other servers. The APIs are implemented over HTTPS,
|
||||||
|
with authentication provided by public key signatures both at the TLS
|
||||||
|
transport layer and in HTTP Authorization headers.
|
||||||
|
|
||||||
|
There are three main kinds of communication that occur between
|
||||||
|
homeservers:
|
||||||
|
|
||||||
|
Persistent Data Units (PDUs):
|
||||||
|
These events are broadcast from one homeserver to any others that have
|
||||||
|
joined the same room (identified by Room ID). They are persisted in
|
||||||
|
long-term storage and record the history of messages and state for a
|
||||||
|
room.
|
||||||
|
|
||||||
|
Like email, it is the responsibility of the originating server of a PDU
|
||||||
|
to deliver that event to its recipient servers. However PDUs are signed
|
||||||
|
using the originating server's private key so that it is possible to
|
||||||
|
deliver them through third-party servers.
|
||||||
|
|
||||||
|
Ephemeral Data Units (EDUs):
|
||||||
|
These events are pushed between pairs of homeservers. They are not
|
||||||
|
persisted and are not part of the history of a room, nor does the
|
||||||
|
receiving homeserver have to reply to them.
|
||||||
|
|
||||||
|
Queries:
|
||||||
|
These are single request/response interactions between a given pair of
|
||||||
|
servers, initiated by one side sending an HTTPS GET request to obtain
|
||||||
|
some information, and responded by the other. They are not persisted and
|
||||||
|
contain no long-term significant history. They simply request a snapshot
|
||||||
|
state at the instant the query is made.
|
||||||
|
|
||||||
|
EDUs and PDUs are further wrapped in an envelope called a Transaction,
|
||||||
|
which is transferred from the origin to the destination homeserver using
|
||||||
|
an HTTPS PUT request.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Matrix homeservers use the Federation APIs (also known as server-server
|
|
||||||
APIs) to communicate with each other. Homeservers use these APIs to push
|
|
||||||
messages to each other in real-time, to retrieve historic messages from
|
|
||||||
each other, and to query profile and presence information about users on
|
|
||||||
each other's servers.
|
|
||||||
|
|
||||||
The APIs are implemented using HTTPS requests between each of the
|
|
||||||
servers. These HTTPS requests are strongly authenticated using public
|
|
||||||
key signatures at the TLS transport layer and using public key
|
|
||||||
signatures in HTTP Authorization headers at the HTTP layer.
|
|
||||||
|
|
||||||
There are three main kinds of communication that occur between
|
|
||||||
homeservers:
|
|
||||||
|
|
||||||
Persistent Data Units (PDUs):
|
|
||||||
These events are broadcast from one homeserver to any others that have
|
|
||||||
joined the same room (identified by Room ID). They are persisted in
|
|
||||||
long-term storage and record the history of messages and state for a
|
|
||||||
room.
|
|
||||||
|
|
||||||
Like email, it is the responsibility of the originating server of a PDU
|
|
||||||
to deliver that event to its recipient servers. However PDUs are signed
|
|
||||||
using the originating server's private key so that it is possible to
|
|
||||||
deliver them through third-party servers.
|
|
||||||
|
|
||||||
Ephemeral Data Units (EDUs):
|
|
||||||
These events are pushed between pairs of homeservers. They are not
|
|
||||||
persisted and are not part of the history of a room, nor does the
|
|
||||||
receiving homeserver have to reply to them.
|
|
||||||
|
|
||||||
Queries:
|
|
||||||
These are single request/response interactions between a given pair of
|
|
||||||
servers, initiated by one side sending an HTTPS GET request to obtain
|
|
||||||
some information, and responded by the other. They are not persisted and
|
|
||||||
contain no long-term significant history. They simply request a snapshot
|
|
||||||
state at the instant the query is made.
|
|
||||||
|
|
||||||
EDUs and PDUs are further wrapped in an envelope called a Transaction,
|
|
||||||
which is transferred from the origin to the destination homeserver using
|
|
||||||
an HTTPS PUT request.
|
|
||||||
|
|
||||||
## API standards
|
## API standards
|
||||||
|
|
||||||
The mandatory baseline for server-server communication in Matrix is
|
The mandatory baseline for server-server communication in Matrix is
|
||||||
|
|
@ -289,7 +286,7 @@ and any query parameters if present, but should not include the leading
|
||||||
|
|
||||||
Step 1 sign JSON:
|
Step 1 sign JSON:
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
{
|
{
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"uri": "/target",
|
"uri": "/target",
|
||||||
|
|
@ -461,9 +458,12 @@ specification](/rooms).
|
||||||
Whenever a server receives an event from a remote server, the receiving
|
Whenever a server receives an event from a remote server, the receiving
|
||||||
server must ensure that the event:
|
server must ensure that the event:
|
||||||
|
|
||||||
1. Is a valid event, otherwise it is dropped. For an event to be valid, it
|
1. {{% changed-in v="1.16" %}} Is a valid event, otherwise it is dropped. For
|
||||||
must contain a `room_id`, and it must comply with the event format of
|
an event to be valid, it must comply with the event format of that [room version](/rooms).
|
||||||
that [room version](/rooms).
|
For some room versions, a `room_id` may also be required on the event in order
|
||||||
|
to determine the room version to check the event against. See the event format
|
||||||
|
section of the [room version specifications](/rooms) for details on when it
|
||||||
|
is required.
|
||||||
2. Passes signature checks, otherwise it is dropped.
|
2. Passes signature checks, otherwise it is dropped.
|
||||||
3. Passes hash checks, otherwise it is redacted before being processed
|
3. Passes hash checks, otherwise it is redacted before being processed
|
||||||
further.
|
further.
|
||||||
|
|
@ -529,7 +529,8 @@ the sender permission to send the event. The `auth_events` for the
|
||||||
`m.room.create` event in a room is empty; for other events, it should be
|
`m.room.create` event in a room is empty; for other events, it should be
|
||||||
the following subset of the room state:
|
the following subset of the room state:
|
||||||
|
|
||||||
- The `m.room.create` event.
|
- {{% changed-in v="1.16" %}} Depending on the [room version](/rooms), the
|
||||||
|
`m.room.create` event.
|
||||||
|
|
||||||
- The current `m.room.power_levels` event, if any.
|
- The current `m.room.power_levels` event, if any.
|
||||||
|
|
||||||
|
|
@ -818,7 +819,7 @@ ResidentServer->JoiningServer: send_join response
|
||||||
JoiningServer->Client: join response
|
JoiningServer->Client: join response
|
||||||
-->
|
-->
|
||||||
|
|
||||||
```
|
```nohighlight
|
||||||
+---------+ +---------------+ +-----------------+ +-----------------+
|
+---------+ +---------------+ +-----------------+ +-----------------+
|
||||||
| Client | | JoiningServer | | DirectoryServer | | ResidentServer |
|
| Client | | JoiningServer | | DirectoryServer | | ResidentServer |
|
||||||
+---------+ +---------------+ +-----------------+ +-----------------+
|
+---------+ +---------------+ +-----------------+ +-----------------+
|
||||||
|
|
@ -941,6 +942,18 @@ Note that invites are used to indicate that knocks were accepted. As such,
|
||||||
receiving servers should be prepared to manually link up a previous knock
|
receiving servers should be prepared to manually link up a previous knock
|
||||||
to an invite if the invite event does not directly reference the knock.
|
to an invite if the invite event does not directly reference the knock.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.16" %}} `invite_room_state` MUST now have its entries formatted
|
||||||
|
according to the room's version (see [room version specification](/rooms)). However,
|
||||||
|
servers SHOULD consider their local ecosystems before returning the described
|
||||||
|
`400 M_MISSING_PARAM` error code. While migrating, servers SHOULD warn about
|
||||||
|
invites which fail the validation rather than error in room versions 1 through 11.
|
||||||
|
All invites to other room versions which fail validation SHOULD result in an error.
|
||||||
|
|
||||||
|
The specification suggests that servers finish their migration no later than
|
||||||
|
January 2026, though servers may extend this as required to support their users.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
{{% http-api spec="server-server" api="invites-v1" %}}
|
{{% http-api spec="server-server" api="invites-v1" %}}
|
||||||
|
|
||||||
{{% http-api spec="server-server" api="invites-v2" %}}
|
{{% http-api spec="server-server" api="invites-v2" %}}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,4 @@ allOf:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: protocol_instance.yaml
|
$ref: protocol_instance.yaml
|
||||||
|
required: ['instances']
|
||||||
|
|
|
||||||
|
|
@ -77,4 +77,4 @@ properties:
|
||||||
"placeholder": "#foobar"
|
"placeholder": "#foobar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
required: ['user_fields', 'location_fields', 'icon', 'field_types', 'instances']
|
required: ['user_fields', 'location_fields', 'icon', 'field_types']
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
type: object
|
type: object
|
||||||
title: Registration
|
title: Registration
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,10 @@ paths:
|
||||||
has been removed, making this endpoint behave as though it was `false`.
|
has been removed, making this endpoint behave as though it was `false`.
|
||||||
This results in this endpoint being an equivalent to `/3pid/bind` rather
|
This results in this endpoint being an equivalent to `/3pid/bind` rather
|
||||||
than dual-purpose.
|
than dual-purpose.
|
||||||
|
|
||||||
|
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
|
||||||
|
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
|
||||||
|
to determine if this endpoint is available.
|
||||||
operationId: post3PIDs
|
operationId: post3PIDs
|
||||||
deprecated: true
|
deprecated: true
|
||||||
security:
|
security:
|
||||||
|
|
@ -202,6 +206,10 @@ paths:
|
||||||
Homeservers should prevent the caller from adding a 3PID to their account if it has
|
Homeservers should prevent the caller from adding a 3PID to their account if it has
|
||||||
already been added to another user's account on the homeserver.
|
already been added to another user's account on the homeserver.
|
||||||
|
|
||||||
|
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
|
||||||
|
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
|
||||||
|
to determine if this endpoint is available.
|
||||||
|
|
||||||
{{% boxes/warning %}}
|
{{% boxes/warning %}}
|
||||||
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
|
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
|
||||||
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
||||||
|
|
@ -331,6 +339,10 @@ paths:
|
||||||
Unlike other endpoints, this endpoint does not take an `id_access_token`
|
Unlike other endpoints, this endpoint does not take an `id_access_token`
|
||||||
parameter because the homeserver is expected to sign the request to the
|
parameter because the homeserver is expected to sign the request to the
|
||||||
identity server instead.
|
identity server instead.
|
||||||
|
|
||||||
|
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
|
||||||
|
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
|
||||||
|
to determine if this endpoint is available.
|
||||||
operationId: delete3pidFromAccount
|
operationId: delete3pidFromAccount
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,8 @@ paths:
|
||||||
description: |-
|
description: |-
|
||||||
The OpenGraph data for the URL, which may be empty. Some values are
|
The OpenGraph data for the URL, which may be empty. Some values are
|
||||||
replaced with matrix equivalents if they are provided in the response.
|
replaced with matrix equivalents if they are provided in the response.
|
||||||
The differences from the OpenGraph protocol are described here.
|
The differences from the [OpenGraph protocol](https://ogp.me/) are
|
||||||
|
described here.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -394,6 +395,9 @@ paths:
|
||||||
format: uri
|
format: uri
|
||||||
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
|
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
|
||||||
the image. Omitted if there is no image.
|
the image. Omitted if there is no image.
|
||||||
|
additionalProperties:
|
||||||
|
description: |-
|
||||||
|
Additional properties as per the [OpenGraph](https://ogp.me/) protocol.
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,25 @@ paths:
|
||||||
- default
|
- default
|
||||||
- available
|
- available
|
||||||
m.set_displayname:
|
m.set_displayname:
|
||||||
|
deprecated: true
|
||||||
$ref: '#/components/schemas/booleanCapability'
|
$ref: '#/components/schemas/booleanCapability'
|
||||||
description: Capability to indicate if the user can change their display name.
|
description: |
|
||||||
|
**Deprecated:** Capability to indicate if the user can change their display name.
|
||||||
|
Refer to `m.profile_fields` for extended profile management.
|
||||||
|
|
||||||
|
For backwards compatibility, servers that directly or indirectly include the
|
||||||
|
`displayname` profile field in the `m.profile_fields` capability MUST also
|
||||||
|
set this capability accordingly.
|
||||||
m.set_avatar_url:
|
m.set_avatar_url:
|
||||||
|
deprecated: true
|
||||||
$ref: '#/components/schemas/booleanCapability'
|
$ref: '#/components/schemas/booleanCapability'
|
||||||
description: Capability to indicate if the user can change their avatar.
|
description: |
|
||||||
|
**Deprecated:** Capability to indicate if the user can change their avatar.
|
||||||
|
Refer to `m.profile_fields` for extended profile management.
|
||||||
|
|
||||||
|
For backwards compatibility, servers that directly or indirectly include the
|
||||||
|
`avatar_url` profile field in the `m.profile_fields` capability MUST also
|
||||||
|
set this capability accordingly.
|
||||||
m.3pid_changes:
|
m.3pid_changes:
|
||||||
$ref: '#/components/schemas/booleanCapability'
|
$ref: '#/components/schemas/booleanCapability'
|
||||||
description: Capability to indicate if the user can change 3PID associations
|
description: Capability to indicate if the user can change 3PID associations
|
||||||
|
|
@ -86,6 +100,47 @@ paths:
|
||||||
$ref: '#/components/schemas/booleanCapability'
|
$ref: '#/components/schemas/booleanCapability'
|
||||||
description: Capability to indicate if the user can generate tokens to log further
|
description: Capability to indicate if the user can generate tokens to log further
|
||||||
clients into their account.
|
clients into their account.
|
||||||
|
m.profile_fields:
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
type: object
|
||||||
|
title: ProfileFieldsCapability
|
||||||
|
description: Capability to indicate if the user can set or modify extended profile fields via
|
||||||
|
[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`](/client-server-api/#put_matrixclientv3profileuseridkeyname).
|
||||||
|
If absent, clients SHOULD assume custom profile fields are supported, provided the
|
||||||
|
homeserver advertises a specification version that includes `m.profile_fields` in the
|
||||||
|
[`/versions`](/client-server-api/#get_matrixclientversions) response.
|
||||||
|
properties:
|
||||||
|
allowed:
|
||||||
|
type: array
|
||||||
|
description: |
|
||||||
|
If present, a list of profile fields that clients are allowed to create, modify or delete,
|
||||||
|
provided `enabled` is `true`; no other profile fields may be changed.
|
||||||
|
|
||||||
|
If absent, clients may set all profile fields except those forbidden by the `disallowed`
|
||||||
|
list, where present.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
- "m.example_field"
|
||||||
|
- "org.example.job_title"
|
||||||
|
disallowed:
|
||||||
|
type: array
|
||||||
|
description: |
|
||||||
|
This property has no meaning if `allowed` is also specified.
|
||||||
|
|
||||||
|
Otherwise, if present, a list of profile fields that clients are _not_ allowed to create, modify or delete.
|
||||||
|
Provided `enabled` is `true`, clients MAY assume that they can set any profile field which is not
|
||||||
|
included in this list.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
- "org.example.managed_field"
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
description: "`true` if the user can create, update or delete any profile fields, `false` otherwise."
|
||||||
|
example: true
|
||||||
|
required:
|
||||||
|
- enabled
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
|
|
|
||||||
|
|
@ -605,7 +605,8 @@ paths:
|
||||||
description: |-
|
description: |-
|
||||||
The OpenGraph data for the URL, which may be empty. Some values are
|
The OpenGraph data for the URL, which may be empty. Some values are
|
||||||
replaced with matrix equivalents if they are provided in the response.
|
replaced with matrix equivalents if they are provided in the response.
|
||||||
The differences from the OpenGraph protocol are described here.
|
The differences from the [OpenGraph](https://ogp.me/) protocol are
|
||||||
|
described here.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -620,6 +621,9 @@ paths:
|
||||||
format: uri
|
format: uri
|
||||||
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
|
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
|
||||||
the image. Omitted if there is no image.
|
the image. Omitted if there is no image.
|
||||||
|
additionalProperties:
|
||||||
|
description: |-
|
||||||
|
Additional properties as per the [OpenGraph](https://ogp.me/) protocol.
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,23 @@ paths:
|
||||||
2. An `m.room.member` event for the creator to join the room. This is
|
2. An `m.room.member` event for the creator to join the room. This is
|
||||||
needed so the remaining events can be sent.
|
needed so the remaining events can be sent.
|
||||||
|
|
||||||
3. A default `m.room.power_levels` event, giving the room creator
|
3. A default `m.room.power_levels` event. Overridden by the
|
||||||
(and not other members) permission to send state events. Overridden
|
`power_level_content_override` parameter.
|
||||||
by the `power_level_content_override` parameter.
|
|
||||||
|
In [room versions](/rooms) 1 through 11, the room creator (and not
|
||||||
|
other members) will be given permission to send state events.
|
||||||
|
|
||||||
|
In room versions 12 and later, the room creator is given infinite
|
||||||
|
power level and cannot be specified in the `users` field of
|
||||||
|
`m.room.power_levels`, so is not listed explicitly.
|
||||||
|
|
||||||
|
**Note**: For `trusted_private_chat`, the users specified in the
|
||||||
|
`invite` parameter SHOULD also be appended to `additional_creators`
|
||||||
|
by the server, per the `creation_content` parameter.
|
||||||
|
|
||||||
|
If the room's version is 12 or higher, the power level for sending
|
||||||
|
`m.room.tombstone` events MUST explicitly be higher than `state_default`.
|
||||||
|
For example, set to 150 instead of 100.
|
||||||
|
|
||||||
4. An `m.room.canonical_alias` event if `room_alias_name` is given.
|
4. An `m.room.canonical_alias` event if `room_alias_name` is given.
|
||||||
|
|
||||||
|
|
@ -61,8 +75,10 @@ paths:
|
||||||
|
|
||||||
The server will create a `m.room.create` event in the room with the
|
The server will create a `m.room.create` event in the room with the
|
||||||
requesting user as the creator, alongside other keys provided in the
|
requesting user as the creator, alongside other keys provided in the
|
||||||
`creation_content`.
|
`creation_content` or implied by behaviour of `creation_content`.
|
||||||
operationId: createRoom
|
operationId: createRoom
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": Added server behaviour for how the initial power levels change depending on room version.
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
- accessTokenBearer: []
|
- accessTokenBearer: []
|
||||||
|
|
@ -142,11 +158,20 @@ paths:
|
||||||
creation_content:
|
creation_content:
|
||||||
title: CreationContent
|
title: CreationContent
|
||||||
type: object
|
type: object
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": Added server behaviour for how to handle `trusted_private_chat` and invited users.
|
||||||
description: |-
|
description: |-
|
||||||
Extra keys, such as `m.federate`, to be added to the content
|
Extra keys, such as `m.federate`, to be added to the content
|
||||||
of the [`m.room.create`](/client-server-api/#mroomcreate) event. The server will overwrite the following
|
of the [`m.room.create`](/client-server-api/#mroomcreate) event.
|
||||||
|
|
||||||
|
The server will overwrite the following
|
||||||
keys: `creator`, `room_version`. Future versions of the specification
|
keys: `creator`, `room_version`. Future versions of the specification
|
||||||
may allow the server to overwrite other keys.
|
may allow the server to overwrite other keys.
|
||||||
|
|
||||||
|
When using the `trusted_private_chat` preset, the server SHOULD combine
|
||||||
|
`additional_creators` specified here and the `invite` array into the
|
||||||
|
eventual `m.room.create` event's `additional_creators`, deduplicating
|
||||||
|
between the two parameters.
|
||||||
initial_state:
|
initial_state:
|
||||||
type: array
|
type: array
|
||||||
description: |-
|
description: |-
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,17 @@ paths:
|
||||||
x-addedInMatrixVersion: "1.1"
|
x-addedInMatrixVersion: "1.1"
|
||||||
x-changedInMatrixVersion:
|
x-changedInMatrixVersion:
|
||||||
"1.11": UIA is not always required for this endpoint.
|
"1.11": UIA is not always required for this endpoint.
|
||||||
|
"1.17": |-
|
||||||
|
This endpoint no longer requires User-Interactive Authentication when used by an
|
||||||
|
application service.
|
||||||
summary: Upload cross-signing keys.
|
summary: Upload cross-signing keys.
|
||||||
description: |-
|
description: |-
|
||||||
Publishes cross-signing keys for the user.
|
Publishes cross-signing keys for the user.
|
||||||
|
|
||||||
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
|
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
|
||||||
|
except when used by an application service.
|
||||||
|
|
||||||
User-Interactive Authentication MUST be performed, except in these cases:
|
User-Interactive Authentication MUST be performed for regular clients, except in these cases:
|
||||||
- there is no existing cross-signing master key uploaded to the homeserver, OR
|
- there is no existing cross-signing master key uploaded to the homeserver, OR
|
||||||
- there is an existing cross-signing master key and it exactly matches the
|
- there is an existing cross-signing master key and it exactly matches the
|
||||||
cross-signing master key provided in the request body. If there are any additional
|
cross-signing master key provided in the request body. If there are any additional
|
||||||
|
|
@ -40,10 +44,12 @@ paths:
|
||||||
makes this endpoint idempotent in the case where the response is lost over the network,
|
makes this endpoint idempotent in the case where the response is lost over the network,
|
||||||
which would otherwise cause a UIA challenge upon retry.
|
which would otherwise cause a UIA challenge upon retry.
|
||||||
|
|
||||||
{{% boxes/warning %}}
|
{{% boxes/note %}}
|
||||||
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
|
When this endpoint requires User-Interactive Authentication,
|
||||||
|
it uses the [`m.oauth`](/client-server-api/#oauth-authentication)
|
||||||
|
authentication type if the access token was obtained
|
||||||
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/note %}}
|
||||||
operationId: uploadCrossSigningKeys
|
operationId: uploadCrossSigningKeys
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
|
||||||
30
data/api/client-server/definitions/m.oauth_params.yaml
Normal file
30
data/api/client-server/definitions/m.oauth_params.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright 2025 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.oauth params
|
||||||
|
description: Schema for `m.oauth` entry in the `params` object in a User-Interactive Authentication response.
|
||||||
|
required: ['url']
|
||||||
|
properties:
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
format: uri
|
||||||
|
description: |
|
||||||
|
A URL pointing to the homeserver's OAuth account management web UI
|
||||||
|
where the user can approve the action. MUST be a valid URI with scheme
|
||||||
|
`http://` or `https://`, the latter being RECOMMENDED.
|
||||||
|
pattern: "^https?://"
|
||||||
|
example: {
|
||||||
|
"url": "https://example.org/account/reset-cross-signing"
|
||||||
|
}
|
||||||
|
|
@ -41,3 +41,4 @@ allOf:
|
||||||
This is the identifier to use as the `third_party_instance_id` in a request to
|
This is the identifier to use as the `third_party_instance_id` in a request to
|
||||||
[`POST /_matrix/client/v3/publicRooms`](/client-server-api/#post_matrixclientv3publicrooms).
|
[`POST /_matrix/client/v3/publicRooms`](/client-server-api/#post_matrixclientv3publicrooms).
|
||||||
example: "irc-freenode"
|
example: "irc-freenode"
|
||||||
|
required: ['instances']
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ properties:
|
||||||
example: "All things general"
|
example: "All things general"
|
||||||
world_readable:
|
world_readable:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: Whether the room may be viewed by guest users without joining.
|
description: Whether the room may be viewed by users without joining.
|
||||||
example: false
|
example: false
|
||||||
guest_can_join:
|
guest_can_join:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
|
||||||
|
|
@ -34,24 +34,6 @@ properties:
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
example: {
|
example: {
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"set_tweak": "sound",
|
|
||||||
"value": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"set_tweak": "highlight"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default": true,
|
|
||||||
"enabled": true,
|
|
||||||
"pattern": "alice",
|
|
||||||
"rule_id": ".m.rule.contains_user_name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"override": [
|
"override": [
|
||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
|
@ -113,12 +95,14 @@ example: {
|
||||||
],
|
],
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"kind": "contains_display_name"
|
"kind": "event_property_contains",
|
||||||
|
"key": "content.m\\.mentions.user_ids",
|
||||||
|
"value": "@alice:example.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": true,
|
"default": true,
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rule_id": ".m.rule.contains_display_name"
|
"rule_id": ".m.rule.is_user_mention"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"actions": [
|
"actions": [
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,3 @@ allOf:
|
||||||
room_version:
|
room_version:
|
||||||
description: The version of the room.
|
description: The version of the room.
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
required:
|
|
||||||
- room_id
|
|
||||||
- num_joined_members
|
|
||||||
- world_readable
|
|
||||||
- guest_can_join
|
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,21 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Device management
|
- Device management
|
||||||
put:
|
put:
|
||||||
summary: Update a device
|
summary: Create or update a device
|
||||||
description: Updates the metadata on the given device.
|
x-changedInMatrixVersion:
|
||||||
|
"1.17": The ability to create new devices was added.
|
||||||
|
description: |-
|
||||||
|
Updates the metadata on the given device, or creates a new device.
|
||||||
|
|
||||||
|
The ability to create new devices is only available to application
|
||||||
|
services: regular clients may only update existing devices.
|
||||||
|
|
||||||
|
When a new device was created, the homeserver MUST return a 201 HTTP
|
||||||
|
status code. It MUST return a 200 HTTP status code if a device was
|
||||||
|
updated.
|
||||||
|
|
||||||
|
This endpoint is rate-limited for device creation. Servers MAY use login
|
||||||
|
rate limits.
|
||||||
operationId: updateDevice
|
operationId: updateDevice
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
@ -127,19 +140,34 @@ paths:
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {}
|
value: {}
|
||||||
|
"201":
|
||||||
|
description: |-
|
||||||
|
The device was successfully created by the application service.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value: {}
|
||||||
"404":
|
"404":
|
||||||
description: The current user has no device with the given ID.
|
description: The current user has no device with the given ID.
|
||||||
tags:
|
tags:
|
||||||
- Device management
|
- Device management
|
||||||
delete:
|
delete:
|
||||||
summary: Delete a device
|
summary: Delete a device
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.17": |-
|
||||||
|
This endpoint no longer requires User-Interactive Authentication when used by an
|
||||||
|
application service.
|
||||||
description: |-
|
description: |-
|
||||||
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
|
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
|
||||||
|
except when used by an application service.
|
||||||
|
|
||||||
Deletes the given device, and invalidates any access token associated with it.
|
Deletes the given device, and invalidates any access token associated with it.
|
||||||
|
|
||||||
{{% boxes/warning %}}
|
{{% boxes/warning %}}
|
||||||
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
|
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
|
||||||
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/warning %}}
|
||||||
operationId: deleteDevice
|
operationId: deleteDevice
|
||||||
|
|
@ -190,13 +218,18 @@ paths:
|
||||||
/delete_devices:
|
/delete_devices:
|
||||||
post:
|
post:
|
||||||
summary: Bulk deletion of devices
|
summary: Bulk deletion of devices
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.17": |-
|
||||||
|
This endpoint no longer requires User-Interactive Authentication when used by an
|
||||||
|
application service.
|
||||||
description: |-
|
description: |-
|
||||||
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
|
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
|
||||||
|
except when used by an application service.
|
||||||
|
|
||||||
Deletes the given devices, and invalidates any access token associated with them.
|
Deletes the given devices, and invalidates any access token associated with them.
|
||||||
|
|
||||||
{{% boxes/warning %}}
|
{{% boxes/warning %}}
|
||||||
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
|
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
|
||||||
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
|
||||||
{{% /boxes/warning %}}
|
{{% /boxes/warning %}}
|
||||||
operationId: deleteDevices
|
operationId: deleteDevices
|
||||||
|
|
|
||||||
|
|
@ -243,8 +243,13 @@ paths:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"400":
|
"400":
|
||||||
description: Part of the request was invalid. For example, the login type may
|
description: |-
|
||||||
not be recognised.
|
Part of the request was invalid. For example, the login type may not be recognised.
|
||||||
|
|
||||||
|
Specific error codes used with this status code include:
|
||||||
|
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
|
||||||
|
used the `m.login.application_service` type, but the server doesn't support logging
|
||||||
|
in via the Legacy authentication API.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -262,6 +267,8 @@ paths:
|
||||||
or the requested device ID is the same as a cross-signing key
|
or the requested device ID is the same as a cross-signing key
|
||||||
ID.
|
ID.
|
||||||
* `M_USER_DEACTIVATED`: The user has been deactivated.
|
* `M_USER_DEACTIVATED`: The user has been deactivated.
|
||||||
|
Servers MAY instead use `M_FORBIDDEN` when they can no longer authenticate
|
||||||
|
the deactivated user (e.g. their password has been wiped).
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ paths:
|
||||||
deleted alongside the device.
|
deleted alongside the device.
|
||||||
|
|
||||||
This endpoint does not use the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api) because
|
This endpoint does not use the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api) because
|
||||||
User-Interactive Authentication is designed to protect against attacks where the
|
User-Interactive Authentication is designed to protect against attacks where
|
||||||
someone gets hold of a single access token then takes over the account. This
|
someone gets hold of a single access token then takes over the account. This
|
||||||
endpoint invalidates all access tokens for the user, including the token used in
|
endpoint invalidates all access tokens for the user, including the token used in
|
||||||
the request, and therefore the attacker is unable to take over the account in
|
the request, and therefore the attacker is unable to take over the account in
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ paths:
|
||||||
This endpoint was deprecated in r0 of this specification. Clients
|
This endpoint was deprecated in r0 of this specification. Clients
|
||||||
should instead call the
|
should instead call the
|
||||||
[/rooms/{roomId}/event/{eventId}](/client-server-api/#get_matrixclientv3roomsroomideventeventid) API
|
[/rooms/{roomId}/event/{eventId}](/client-server-api/#get_matrixclientv3roomsroomideventeventid) API
|
||||||
or the [/rooms/{roomId}/context/{eventId](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API.
|
or the [/rooms/{roomId}/context/{eventId}](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API.
|
||||||
operationId: getOneEvent
|
operationId: getOneEvent
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ paths:
|
||||||
valid access token is provided. The homeserver SHOULD NOT revoke the
|
valid access token is provided. The homeserver SHOULD NOT revoke the
|
||||||
access token provided in the request. Whether other access tokens for
|
access token provided in the request. Whether other access tokens for
|
||||||
the user are revoked depends on the request parameters.
|
the user are revoked depends on the request parameters.
|
||||||
|
|
||||||
|
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
|
||||||
|
Clients SHOULD check the value of the [`m.change_password` capability](/client-server-api/#mchange_password-capability)
|
||||||
|
to determine if this endpoint is available.
|
||||||
security:
|
security:
|
||||||
- {}
|
- {}
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ paths:
|
||||||
example: "!somewhere:over.the.rainbow"
|
example: "!somewhere:over.the.rainbow"
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
required: true
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The events received, which may be none.
|
description: The events received, which may be none.
|
||||||
|
|
|
||||||
|
|
@ -16,48 +16,126 @@ info:
|
||||||
title: Matrix Client-Server Profile API
|
title: Matrix Client-Server Profile API
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
paths:
|
paths:
|
||||||
"/profile/{userId}/displayname":
|
"/profile/{userId}/{keyName}":
|
||||||
put:
|
put:
|
||||||
summary: Set the user's display name.
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": This endpoint now accepts a variable `keyName` parameter and `m.tz` was added as a defined key. Previously only `displayname` and `avatar_url` were accepted.
|
||||||
|
summary: Set a profile field for a user.
|
||||||
description: |-
|
description: |-
|
||||||
This API sets the given user's display name. You must have permission to
|
Set or update a profile field for a user. Must be authenticated with an
|
||||||
set this user's display name, e.g. you need to have their `access_token`.
|
access token authorised to make changes. Servers MAY impose size limits
|
||||||
operationId: setDisplayName
|
on individual fields, and the total profile MUST be under 64 KiB.
|
||||||
|
|
||||||
|
Servers MAY reject `null` values. Servers that accept `null` values SHOULD store
|
||||||
|
them rather than treating `null` as a deletion request. Clients that want to delete a
|
||||||
|
field, including its key and value, SHOULD use the `DELETE` endpoint instead.
|
||||||
|
|
||||||
|
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation)
|
||||||
|
depending on the `keyName`. Clients SHOULD check the value of the
|
||||||
|
[`m.profile_fields` capability](/client-server-api/#mprofile_fields-capability) to detect
|
||||||
|
which `keyName`s they are allowed to modify.
|
||||||
|
operationId: setProfileField
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
- accessTokenBearer: []
|
- accessTokenBearer: []
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: userId
|
name: userId
|
||||||
description: The user whose display name to set.
|
description: The user whose profile field should be set.
|
||||||
required: true
|
required: true
|
||||||
example: "@alice:example.com"
|
example: "@alice:example.com"
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- in: path
|
||||||
|
name: keyName
|
||||||
|
description: The name of the profile field to set. This MUST be either
|
||||||
|
`avatar_url`, `displayname`, `m.tz`, or a custom field following the
|
||||||
|
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
|
||||||
|
required: true
|
||||||
|
example: "displayname"
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
pattern: '^(avatar_url|displayname|m\.tz|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
|
||||||
requestBody:
|
requestBody:
|
||||||
|
description: A JSON object containing the property whose name matches
|
||||||
|
the `keyName` specified in the URL. See `additionalProperties` for
|
||||||
|
further details.
|
||||||
|
required: true
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
example: {
|
minProperties: 1
|
||||||
"displayname": "Alice Margatroid"
|
description: |
|
||||||
}
|
An object which contains exactly one property. The key
|
||||||
properties:
|
of that property MUST match the `keyName` specified in the URL.
|
||||||
displayname:
|
|
||||||
type: string
|
For `avatar_url`, the value MUST be an MXC URI string.
|
||||||
description: The new display name for this user.
|
|
||||||
description: The new display name information.
|
For `displayname`, the value MUST be a string.
|
||||||
required: true
|
|
||||||
|
For `m.tz`, the value MUST be a valid identifier from the [IANA Time Zone Database](https://www.iana.org/time-zones).
|
||||||
|
Servers MAY choose to validate the value. Clients MUST expect unknown or invalid
|
||||||
|
values.
|
||||||
|
|
||||||
|
For custom keys, any JSON type is allowed. Servers MAY not validate
|
||||||
|
these values, but clients SHOULD follow the format defined for that key.
|
||||||
|
additionalProperties: true
|
||||||
|
example: { "displayname": "Alice Wonderland" }
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The display name was set.
|
description: The profile field was set.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object # empty json object
|
type: object # empty JSON object
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {}
|
value: {}
|
||||||
|
"400":
|
||||||
|
description: |
|
||||||
|
The input was invalid in some way. This can include one
|
||||||
|
of the following error codes:
|
||||||
|
|
||||||
|
- `M_BAD_JSON`: The provided value is not valid JSON.
|
||||||
|
- `M_MISSING_PARAM`: The required `keyName` property is
|
||||||
|
missing from the request body.
|
||||||
|
- `M_PROFILE_TOO_LARGE`: Storing the supplied value would
|
||||||
|
make the profile exceed its maximum allowed size of 64 KiB.
|
||||||
|
- `M_KEY_TOO_LARGE`: The supplied profile key exceeds the
|
||||||
|
maximum allowed key length of 255 bytes.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: definitions/errors/error.yaml
|
||||||
|
examples:
|
||||||
|
bad_json:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"errcode": "M_BAD_JSON",
|
||||||
|
"error": "Malformed JSON payload.",
|
||||||
|
}
|
||||||
|
invalid_key:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"errcode": "M_INVALID_PARAM",
|
||||||
|
"error": "Invalid profile key.",
|
||||||
|
}
|
||||||
|
"403":
|
||||||
|
description: The server is unwilling to perform the operation, either
|
||||||
|
due to insufficient permissions or because profile modifications
|
||||||
|
are disabled.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: definitions/errors/error.yaml
|
||||||
|
examples:
|
||||||
|
forbidden:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"errcode": "M_FORBIDDEN",
|
||||||
|
"error": "Profile modification is not permitted.",
|
||||||
|
}
|
||||||
"429":
|
"429":
|
||||||
description: This request was rate-limited.
|
description: This request was rate-limited.
|
||||||
content:
|
content:
|
||||||
|
|
@ -67,98 +145,125 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
get:
|
get:
|
||||||
summary: Get the user's display name.
|
x-changedInMatrixVersion:
|
||||||
description: |-
|
"1.16": This endpoint now accepts a variable `keyName` parameter and `m.tz` was added as a defined key. Previously only `displayname` and `avatar_url` were accepted.
|
||||||
Get the user's display name. This API may be used to fetch the user's
|
summary: Get a profile field for a user.
|
||||||
own displayname or to query the name of other users; either locally or
|
description: Get the value of a profile field for a user.
|
||||||
on remote homeservers.
|
operationId: getProfileField
|
||||||
operationId: getDisplayName
|
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: userId
|
name: userId
|
||||||
description: The user whose display name to get.
|
description: The user whose profile field should be returned.
|
||||||
required: true
|
required: true
|
||||||
example: "@alice:example.com"
|
example: "@alice:example.com"
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- in: path
|
||||||
|
name: keyName
|
||||||
|
description: The name of the profile field to retrieve.
|
||||||
|
required: true
|
||||||
|
example: "displayname"
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
pattern: '^(avatar_url|displayname|m\.tz|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The display name for this user.
|
description: The profile field value was retrieved.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
description: |
|
||||||
displayname:
|
An object with one property, whose key matches the `keyName` specified
|
||||||
type: string
|
in the URL, and whose value is the current setting of that profile field.
|
||||||
description: The user's display name if they have set one, otherwise not
|
additionalProperties: true
|
||||||
present.
|
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: { "displayname": "Alice" }
|
||||||
"displayname": "Alice Margatroid"
|
|
||||||
}
|
|
||||||
"403":
|
"403":
|
||||||
x-addedInMatrixVersion: "1.12"
|
x-addedInMatrixVersion: "1.12"
|
||||||
description: The server is unwilling to disclose whether the user exists and/or
|
description: The server is unwilling to disclose whether the user
|
||||||
has a display name.
|
exists and/or has the specified profile field.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: definitions/errors/error.yaml
|
$ref: definitions/errors/error.yaml
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value:
|
||||||
|
{
|
||||||
"errcode": "M_FORBIDDEN",
|
"errcode": "M_FORBIDDEN",
|
||||||
"error": "Profile lookup is disabled on this homeserver"
|
"error": "Profile lookup is disabled on this homeserver",
|
||||||
}
|
}
|
||||||
"404":
|
"404":
|
||||||
description: There is no display name for this user or this user does not exist.
|
description: There is no profile field with this key for this user, or
|
||||||
|
the user does not exist.
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
"/profile/{userId}/avatar_url":
|
delete:
|
||||||
put:
|
x-addedInMatrixVersion: "1.16"
|
||||||
summary: Set the user's avatar URL.
|
summary: Remove a profile field from a user.
|
||||||
description: |-
|
description: Remove a specific field from a user's profile.
|
||||||
This API sets the given user's avatar URL. You must have permission to
|
operationId: deleteProfileField
|
||||||
set this user's avatar URL, e.g. you need to have their `access_token`.
|
|
||||||
operationId: setAvatarUrl
|
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
- accessTokenBearer: []
|
- accessTokenBearer: []
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: userId
|
name: userId
|
||||||
description: The user whose avatar URL to set.
|
description: The user whose profile field should be deleted.
|
||||||
required: true
|
required: true
|
||||||
example: "@alice:example.com"
|
example: "@alice:example.com"
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
requestBody:
|
- in: path
|
||||||
|
name: keyName
|
||||||
|
description: The name of the profile field to delete.
|
||||||
|
required: true
|
||||||
|
example: "displayname"
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
pattern: '^(avatar_url|displayname|m\.tz|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The profile field was deleted or it doesn't exist.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
example: {
|
|
||||||
"avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34"
|
|
||||||
}
|
|
||||||
properties:
|
|
||||||
avatar_url:
|
|
||||||
type: string
|
|
||||||
format: uri
|
|
||||||
description: The new avatar URL for this user.
|
|
||||||
description: The new avatar information.
|
|
||||||
required: true
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The avatar URL was set.
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: object # empty json object
|
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {}
|
value: {}
|
||||||
|
"400":
|
||||||
|
description: The request is malformed, contains invalid JSON, or
|
||||||
|
specifies an invalid key.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: definitions/errors/error.yaml
|
||||||
|
examples:
|
||||||
|
bad_json:
|
||||||
|
value:
|
||||||
|
{ "errcode": "M_BAD_JSON", "error": "Malformed request." }
|
||||||
|
invalid_key:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"errcode": "M_INVALID_PARAM",
|
||||||
|
"error": "Invalid profile key.",
|
||||||
|
}
|
||||||
|
"403":
|
||||||
|
description: The user is not authorised to delete this profile field.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: definitions/errors/error.yaml
|
||||||
|
examples:
|
||||||
|
forbidden:
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
"errcode": "M_FORBIDDEN",
|
||||||
|
"error": "Profile deletion is not permitted.",
|
||||||
|
}
|
||||||
"429":
|
"429":
|
||||||
description: This request was rate-limited.
|
description: This request was rate-limited.
|
||||||
content:
|
content:
|
||||||
|
|
@ -167,63 +272,11 @@ paths:
|
||||||
$ref: definitions/errors/rate_limited.yaml
|
$ref: definitions/errors/rate_limited.yaml
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
get:
|
|
||||||
summary: Get the user's avatar URL.
|
|
||||||
description: |-
|
|
||||||
Get the user's avatar URL. This API may be used to fetch the user's
|
|
||||||
own avatar URL or to query the URL of other users; either locally or
|
|
||||||
on remote homeservers.
|
|
||||||
operationId: getAvatarUrl
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: userId
|
|
||||||
description: The user whose avatar URL to get.
|
|
||||||
required: true
|
|
||||||
example: "@alice:example.com"
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The avatar URL for this user.
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
avatar_url:
|
|
||||||
type: string
|
|
||||||
format: uri
|
|
||||||
description: The user's avatar URL if they have set one, otherwise not present.
|
|
||||||
examples:
|
|
||||||
response:
|
|
||||||
value: {
|
|
||||||
"avatar_url": "mxc://matrix.org/SDGdghriugerRg"
|
|
||||||
}
|
|
||||||
"403":
|
|
||||||
x-addedInMatrixVersion: "1.12"
|
|
||||||
description: The server is unwilling to disclose whether the user exists and/or
|
|
||||||
has an avatar URL.
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: definitions/errors/error.yaml
|
|
||||||
examples:
|
|
||||||
response:
|
|
||||||
value: {
|
|
||||||
"errcode": "M_FORBIDDEN",
|
|
||||||
"error": "Profile lookup is disabled on this homeserver"
|
|
||||||
}
|
|
||||||
"404":
|
|
||||||
description: There is no avatar URL for this user or this user does not exist.
|
|
||||||
tags:
|
|
||||||
- User data
|
|
||||||
"/profile/{userId}":
|
"/profile/{userId}":
|
||||||
get:
|
get:
|
||||||
summary: Get this user's profile information.
|
summary: Get all profile information for a user.
|
||||||
description: |-
|
description: |-
|
||||||
Get the combined profile information for this user. This API may be used
|
Get the complete profile for a user.
|
||||||
to fetch the user's own profile information or other users; either
|
|
||||||
locally or on remote homeservers.
|
|
||||||
operationId: getUserProfile
|
operationId: getUserProfile
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
|
|
@ -243,45 +296,54 @@ paths:
|
||||||
properties:
|
properties:
|
||||||
avatar_url:
|
avatar_url:
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
format: mx-mxc-uri
|
||||||
description: The user's avatar URL if they have set one, otherwise not present.
|
description: The user's avatar URL if they have set one, otherwise not present.
|
||||||
displayname:
|
displayname:
|
||||||
type: string
|
type: string
|
||||||
description: The user's display name if they have set one, otherwise not
|
description: The user's display name if they have set one, otherwise not
|
||||||
present.
|
present.
|
||||||
|
m.tz:
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
type: string
|
||||||
|
description: The user's time zone.
|
||||||
|
additionalProperties:
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: Additional profile fields.
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value:
|
||||||
|
{
|
||||||
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
|
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
|
||||||
"displayname": "Alice Margatroid"
|
"displayname": "Alice Margatroid",
|
||||||
|
"m.tz": "Europe/London",
|
||||||
|
"m.example_field": "custom_value",
|
||||||
}
|
}
|
||||||
"403":
|
"403":
|
||||||
x-addedInMatrixVersion: "1.2"
|
x-addedInMatrixVersion: "1.2"
|
||||||
description: The server is unwilling to disclose whether the user exists and/or
|
description: The server is unwilling to disclose whether the user
|
||||||
has profile information.
|
exists and/or has profile information.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: definitions/errors/error.yaml
|
$ref: definitions/errors/error.yaml
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value:
|
||||||
|
{
|
||||||
"errcode": "M_FORBIDDEN",
|
"errcode": "M_FORBIDDEN",
|
||||||
"error": "Profile lookup is disabled on this homeserver"
|
"error": "Profile lookup is disabled on this homeserver",
|
||||||
}
|
}
|
||||||
"404":
|
"404":
|
||||||
description: There is no profile information for this user or this user does not
|
description: There is no profile information for this user or this
|
||||||
exist.
|
user does not exist.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: definitions/errors/error.yaml
|
$ref: definitions/errors/error.yaml
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value:
|
||||||
"errcode": "M_NOT_FOUND",
|
{ "errcode": "M_NOT_FOUND", "error": "Profile not found" }
|
||||||
"error": "Profile not found"
|
|
||||||
}
|
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
servers:
|
servers:
|
||||||
|
|
|
||||||
|
|
@ -230,11 +230,14 @@ paths:
|
||||||
format:
|
format:
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
The format to send notifications in to Push Gateways if the
|
The format in which to send notifications to the push gateway
|
||||||
`kind` is `http`. The details about what fields the
|
if the `kind` is `http`. The details about what fields the
|
||||||
homeserver should send to the push gateway are defined in the
|
homeserver should include are defined in the
|
||||||
[Push Gateway Specification](/push-gateway-api/). Currently the only format
|
[Push Gateway Specification](/push-gateway-api/). If omitted,
|
||||||
available is 'event_id_only'.
|
the server is expected to populate all of the event-related fields
|
||||||
|
specified in [`/_matrix/push/v1/notify`](/push-gateway-api/#post_matrixpushv1notify).
|
||||||
|
enum:
|
||||||
|
- "event_id_only"
|
||||||
append:
|
append:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: |-
|
description: |-
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ paths:
|
||||||
This cannot be undone.
|
This cannot be undone.
|
||||||
|
|
||||||
Any user with a power level greater than or equal to the `m.room.redaction`
|
Any user with a power level greater than or equal to the `m.room.redaction`
|
||||||
event power level may send redaction events in the room. If the user's power
|
event power level may send redactions for their own events in the room. If
|
||||||
level is also greater than or equal to the `redact` power level of the room,
|
the user's power level is also greater than or equal to the `redact` power
|
||||||
the user may redact events sent by other users.
|
level of the room, the user may redact events sent by other users.
|
||||||
|
|
||||||
Server administrators may redact events sent by users on their server.
|
Server administrators may redact events sent by users on their server.
|
||||||
operationId: redactEvent
|
operationId: redactEvent
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,18 @@ paths:
|
||||||
|
|
||||||
Any user ID returned by this API must conform to the grammar given in the
|
Any user ID returned by this API must conform to the grammar given in the
|
||||||
[Matrix specification](/appendices/#user-identifiers).
|
[Matrix specification](/appendices/#user-identifiers).
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% added-in v="1.17" %}}
|
||||||
|
Even if the server doesn't support the Legacy authentication API, it
|
||||||
|
MUST support this endpoint for application services to be able to
|
||||||
|
[create users](/application-service-api/#server-admin-style-permissions).
|
||||||
|
|
||||||
|
In that case application services MUST set the `"inhibit_login": true`
|
||||||
|
parameter as they cannot use it to log in as users. If the
|
||||||
|
`inhibit_login` parameter is not set to `true`, the server MUST return a
|
||||||
|
400 HTTP status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
|
||||||
|
{{% /boxes/note %}}
|
||||||
operationId: register
|
operationId: register
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
|
|
@ -203,6 +215,9 @@ paths:
|
||||||
* `M_INVALID_USERNAME` : The desired user ID is not a valid user name.
|
* `M_INVALID_USERNAME` : The desired user ID is not a valid user name.
|
||||||
* `M_EXCLUSIVE` : The desired user ID is in the exclusive namespace
|
* `M_EXCLUSIVE` : The desired user ID is in the exclusive namespace
|
||||||
claimed by an application service.
|
claimed by an application service.
|
||||||
|
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
|
||||||
|
used the `m.login.application_service` type without setting `inhibit_login` to `true`,
|
||||||
|
but the server doesn't support logging in via the Legacy authentication API.
|
||||||
|
|
||||||
These errors may be returned at any stage of the registration process,
|
These errors may be returned at any stage of the registration process,
|
||||||
including after authentication if the requested user ID was registered
|
including after authentication if the requested user ID was registered
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,6 @@ paths:
|
||||||
- leave
|
- leave
|
||||||
- ban
|
- ban
|
||||||
type: string
|
type: string
|
||||||
required:
|
|
||||||
- guest_can_join
|
|
||||||
- num_joined_members
|
|
||||||
- room_id
|
|
||||||
- world_readable
|
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,23 @@ paths:
|
||||||
new_version:
|
new_version:
|
||||||
type: string
|
type: string
|
||||||
description: The new version for the room.
|
description: The new version for the room.
|
||||||
|
additional_creators:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: Additional user ID to consider a room creator, if the room version supports it.
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: |-
|
||||||
|
When upgrading to a [room version](/rooms) which supports additional creators,
|
||||||
|
the [user IDs](/appendices#user-identifiers) which should be considered room
|
||||||
|
creators in addition to the user performing the upgrade.
|
||||||
|
|
||||||
|
If the room being upgraded has additional creators, they are *not* automatically
|
||||||
|
copied to the new room. The full set of additional creators needs to be set to
|
||||||
|
retain (or add/remove) more room creators.
|
||||||
|
|
||||||
|
When upgrading to a room version which doesn't support additional creators, this
|
||||||
|
field is ignored and has no effect during the upgrade process.
|
||||||
example: {
|
example: {
|
||||||
"new_version": "2"
|
"new_version": "2"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,31 @@ paths:
|
||||||
example: ""
|
example: ""
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: format
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: |-
|
||||||
|
The format to use for the returned data. `content` (the default) will
|
||||||
|
return only the content of the state event. `event` will return the entire
|
||||||
|
event in the usual format suitable for clients, including fields like event
|
||||||
|
ID, sender and timestamp.
|
||||||
|
example: event
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- content
|
||||||
|
- event
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The content of the state event.
|
description: |-
|
||||||
|
The content of the state event, or the entire client-formatted event
|
||||||
|
if `?format=event` was used.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
oneOf:
|
||||||
|
- type: object
|
||||||
|
- $ref: "../../event-schemas/schema/core-event-schema/state_event.yaml"
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,36 @@ paths:
|
||||||
example: 30000
|
example: 30000
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: use_state_after
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: |-
|
||||||
|
Controls whether to receive state changes between the previous sync
|
||||||
|
and the **start** of the timeline, or between the previous sync and
|
||||||
|
the **end** of the timeline.
|
||||||
|
|
||||||
|
If this is set to `true`, servers MUST respond with the state
|
||||||
|
between the previous sync and the **end** of the timeline in
|
||||||
|
`state_after` and MUST omit `state`.
|
||||||
|
|
||||||
|
If `false`, servers MUST respond with the state between the previous
|
||||||
|
sync and the **start** of the timeline in `state` and MUST omit
|
||||||
|
`state_after`.
|
||||||
|
|
||||||
|
Servers MAY implement this parameter ahead of declaring support for
|
||||||
|
the version of the spec in which it was introduced. Consequently,
|
||||||
|
clients MAY set this parameter to `true` regardless of the
|
||||||
|
[`/versions`](/client-server-api/#get_matrixclientversions) response.
|
||||||
|
If they do, they can infer whether the server actually supports this
|
||||||
|
parameter from the presence of `state_after` in the response. If
|
||||||
|
`state_after` is missing, clients MUST behave as if they had not
|
||||||
|
specified the parameter and update their local state with events
|
||||||
|
in `state` and `timeline`.
|
||||||
|
|
||||||
|
By default, this is `false`.
|
||||||
|
example: false
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The initial snapshot or delta for the client to use to update their
|
description: The initial snapshot or delta for the client to use to update their
|
||||||
|
|
@ -197,16 +227,50 @@ paths:
|
||||||
type: object
|
type: object
|
||||||
description: |-
|
description: |-
|
||||||
Updates to the state, between the time indicated by
|
Updates to the state, between the time indicated by
|
||||||
the `since` parameter, and the start of the
|
the `since` parameter, and the **start** of the
|
||||||
`timeline` (or all state up to the start of the
|
`timeline` (or all state up to the **start** of the
|
||||||
`timeline`, if `since` is not given, or
|
`timeline`, if `since` is not given, or
|
||||||
`full_state` is true).
|
`full_state` is true).
|
||||||
|
|
||||||
N.B. state updates for `m.room.member` events will
|
{{% boxes/note %}}
|
||||||
|
State updates for `m.room.member` events will
|
||||||
be incomplete if `lazy_load_members` is enabled in
|
be incomplete if `lazy_load_members` is enabled in
|
||||||
the `/sync` filter, and only return the member events
|
the `/sync` filter, and only return the member events
|
||||||
required to display the senders of the timeline events
|
required to display the senders of the timeline events
|
||||||
in this response.
|
in this response.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
MUST be omitted if `use_state_after` was set to `true`
|
||||||
|
in the request.
|
||||||
|
allOf:
|
||||||
|
- $ref: definitions/state_event_batch.yaml
|
||||||
|
state_after:
|
||||||
|
title: State
|
||||||
|
type: object
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: |-
|
||||||
|
Updates to the state, between the time indicated by
|
||||||
|
the `since` parameter, and the **end** of the
|
||||||
|
`timeline` (or all state up to the **end** of the
|
||||||
|
`timeline`, if `since` is not given, or
|
||||||
|
`full_state` is true).
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
State updates for `m.room.member` events will
|
||||||
|
be incomplete if `lazy_load_members` is enabled in
|
||||||
|
the `/sync` filter, and only return the member events
|
||||||
|
required to display the senders of the timeline events
|
||||||
|
in this response.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
If this field is set, even if it is empty, clients MUST
|
||||||
|
only update their local state with events in this list,
|
||||||
|
and MUST NOT update their local state with events in
|
||||||
|
`timeline`. If this field is not set, clients MUST update
|
||||||
|
their local state with events in `state` and `timeline`.
|
||||||
|
|
||||||
|
**Required** if `use_state_after` was set to `true` in the
|
||||||
|
request, even if it is empty.
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: definitions/state_event_batch.yaml
|
- $ref: definitions/state_event_batch.yaml
|
||||||
timeline:
|
timeline:
|
||||||
|
|
@ -353,7 +417,28 @@ paths:
|
||||||
state:
|
state:
|
||||||
title: State
|
title: State
|
||||||
type: object
|
type: object
|
||||||
description: The state updates for the room up to the start of the timeline.
|
description: |-
|
||||||
|
The state updates for the room up to the **start** of the timeline.
|
||||||
|
|
||||||
|
MUST be omitted if `use_state_after` was set to `true` in the
|
||||||
|
request.
|
||||||
|
allOf:
|
||||||
|
- $ref: definitions/state_event_batch.yaml
|
||||||
|
state_after:
|
||||||
|
title: State
|
||||||
|
type: object
|
||||||
|
x-addedInMatrixVersion: "1.16"
|
||||||
|
description: |-
|
||||||
|
The state updates for the room up to the **end** of the timeline.
|
||||||
|
|
||||||
|
If this field is set, even if it is empty, clients MUST only
|
||||||
|
update their local state with events in this list, and MUST NOT
|
||||||
|
update their local state with events in `timeline`. If this field
|
||||||
|
is not set, clients MUST update their local state with events in
|
||||||
|
`state` and `timeline`.
|
||||||
|
|
||||||
|
**Required** if `use_state_after` was set to `true` in the
|
||||||
|
request, even if it is empty.
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: definitions/state_event_batch.yaml
|
- $ref: definitions/state_event_batch.yaml
|
||||||
timeline:
|
timeline:
|
||||||
|
|
|
||||||
25
data/api/server-server/definitions/components/depth_v6.yaml
Normal file
25
data/api/server-server/definitions/components/depth_v6.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Copyright 2025 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
|
||||||
|
description: |-
|
||||||
|
The depth field of PDUs for room version 6 and beyond.
|
||||||
|
properties:
|
||||||
|
# v6 enforces Canonical JSON and therefore needs a depth limit change
|
||||||
|
depth:
|
||||||
|
type: integer
|
||||||
|
description: |-
|
||||||
|
The maximum depth of the `prev_events`, plus one. Must be less than the
|
||||||
|
maximum value for an integer (2^53 - 1). If the room's depth is already at
|
||||||
|
the limit, the depth must be set to the limit.
|
||||||
|
example: 12
|
||||||
|
|
@ -14,10 +14,6 @@
|
||||||
type: object
|
type: object
|
||||||
description: Common fields for all PDU versions
|
description: Common fields for all PDU versions
|
||||||
properties:
|
properties:
|
||||||
room_id:
|
|
||||||
type: string
|
|
||||||
description: Room identifier.
|
|
||||||
example: "!abc123:matrix.org"
|
|
||||||
sender:
|
sender:
|
||||||
type: string
|
type: string
|
||||||
description: The ID of the user sending the event.
|
description: The ID of the user sending the event.
|
||||||
|
|
@ -69,7 +65,6 @@ properties:
|
||||||
description: The number of milliseconds that have passed since this message was sent.
|
description: The number of milliseconds that have passed since this message was sent.
|
||||||
example: 4612
|
example: 4612
|
||||||
required:
|
required:
|
||||||
- room_id
|
|
||||||
- sender
|
- sender
|
||||||
- origin_server_ts
|
- origin_server_ts
|
||||||
- type
|
- type
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Copyright 2025 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
|
||||||
|
description: |-
|
||||||
|
The room_id field of PDUs for room version 11 and prior.
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: Room identifier.
|
||||||
|
example: "!abc123:matrix.org"
|
||||||
|
required:
|
||||||
|
- room_id
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Copyright 2025 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
|
||||||
|
description: |-
|
||||||
|
The room_id field of PDUs for room version 12 and beyond.
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: Room identifier. Omitted from `m.room.create` events.
|
||||||
|
example: "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ"
|
||||||
|
required:
|
||||||
|
- room_id
|
||||||
|
|
@ -18,6 +18,7 @@ example:
|
||||||
$ref: "../examples/pdu_v1.json"
|
$ref: "../examples/pdu_v1.json"
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "components/pdu_base.yaml"
|
- $ref: "components/pdu_base.yaml"
|
||||||
|
- $ref: "components/room_id_before_v12.yaml"
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
event_id:
|
event_id:
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,12 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
type: object
|
type: object
|
||||||
title: Persistent Data Unit
|
title: Persistent Data Unit
|
||||||
description: A persistent data unit (event) for room version 11 and beyond.
|
description: A persistent data unit (event) for room version 11.
|
||||||
example:
|
example:
|
||||||
$ref: "../examples/pdu_v11.json"
|
$ref: "../examples/pdu_v11.json"
|
||||||
allOf:
|
allOf:
|
||||||
# v11 is the v6 event, but without redacts.
|
# v11 is the v6 event, but without redacts.
|
||||||
- $ref: "components/pdu_base.yaml"
|
- $ref: "components/pdu_base.yaml"
|
||||||
- $ref: "components/auth_events_prev_events_v4.yaml"
|
- $ref: "components/auth_events_prev_events_v4.yaml"
|
||||||
- type: object
|
- $ref: "components/room_id_before_v12.yaml"
|
||||||
properties:
|
- $ref: "components/depth_v6.yaml"
|
||||||
# v6 enforces Canonical JSON and therefore needs a depth limit change
|
|
||||||
depth:
|
|
||||||
type: integer
|
|
||||||
description: |-
|
|
||||||
The maximum depth of the `prev_events`, plus one. Must be less than the
|
|
||||||
maximum value for an integer (2^53 - 1). If the room's depth is already at
|
|
||||||
the limit, the depth must be set to the limit.
|
|
||||||
example: 12
|
|
||||||
|
|
|
||||||
24
data/api/server-server/definitions/pdu_v12.yaml
Normal file
24
data/api/server-server/definitions/pdu_v12.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright 2025 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: Persistent Data Unit
|
||||||
|
description: A persistent data unit (event) for room version 12 and beyond.
|
||||||
|
example:
|
||||||
|
$ref: "../examples/pdu_v12.json"
|
||||||
|
allOf:
|
||||||
|
# v12 is the v11 event, but with special room ID requirements.
|
||||||
|
- $ref: "components/pdu_base.yaml"
|
||||||
|
- $ref: "components/auth_events_prev_events_v4.yaml"
|
||||||
|
- $ref: "components/depth_v6.yaml"
|
||||||
|
- $ref: "components/room_id_v12.yaml" # this is the v12 change
|
||||||
|
|
@ -18,6 +18,7 @@ example:
|
||||||
$ref: "../examples/pdu_v3.json"
|
$ref: "../examples/pdu_v3.json"
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "components/pdu_base.yaml"
|
- $ref: "components/pdu_base.yaml"
|
||||||
|
- $ref: "components/room_id_before_v12.yaml"
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
redacts:
|
redacts:
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ example:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "components/pdu_base.yaml"
|
- $ref: "components/pdu_base.yaml"
|
||||||
- $ref: "components/auth_events_prev_events_v4.yaml"
|
- $ref: "components/auth_events_prev_events_v4.yaml"
|
||||||
|
- $ref: "components/room_id_before_v12.yaml"
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
redacts:
|
redacts:
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,11 @@ example:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "components/pdu_base.yaml"
|
- $ref: "components/pdu_base.yaml"
|
||||||
- $ref: "components/auth_events_prev_events_v4.yaml"
|
- $ref: "components/auth_events_prev_events_v4.yaml"
|
||||||
|
- $ref: "components/room_id_before_v12.yaml"
|
||||||
|
- $ref: "components/depth_v6.yaml"
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
redacts:
|
redacts:
|
||||||
type: string
|
type: string
|
||||||
description: For redaction events, the ID of the event being redacted.
|
description: For redaction events, the ID of the event being redacted.
|
||||||
example: "$def_456-oldevent"
|
example: "$def_456-oldevent"
|
||||||
# v6 enforces Canonical JSON and therefore needs a depth limit change
|
|
||||||
depth:
|
|
||||||
type: integer
|
|
||||||
description: |-
|
|
||||||
The maximum depth of the `prev_events`, plus one. Must be less than the
|
|
||||||
maximum value for an integer (2^53 - 1). If the room's depth is already at
|
|
||||||
the limit, the depth must be set to the limit.
|
|
||||||
example: 12
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
[
|
||||||
|
{"$ref": "./minimal_pdu.json"},
|
||||||
|
{
|
||||||
|
"type": "m.room.create",
|
||||||
|
"content": {
|
||||||
|
"see_room_version_spec": "The event format changes depending on the room version."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
9
data/api/server-server/examples/pdu_v12.json
Normal file
9
data/api/server-server/examples/pdu_v12.json
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "components/pdu_base.json" },
|
||||||
|
{ "$ref": "components/auth_events_prev_events_v4.json" },
|
||||||
|
{
|
||||||
|
"room_id": "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -71,13 +71,32 @@ paths:
|
||||||
properties:
|
properties:
|
||||||
invite_room_state:
|
invite_room_state:
|
||||||
type: array
|
type: array
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": |
|
||||||
|
`m.room.create` and format requirements were added.
|
||||||
description: |-
|
description: |-
|
||||||
An optional list of [stripped state events](/client-server-api/#stripped-state)
|
A list of state events to help the receiver of the invite identify the room.
|
||||||
to help the receiver of the invite identify the room.
|
Translated as [stripped state events](/client-server-api/#stripped-state)
|
||||||
|
over the Client-Server API.
|
||||||
|
|
||||||
|
MUST contain the `m.room.create` event for the room. All events listed
|
||||||
|
MUST additionally be formatted according to the room version specification.
|
||||||
|
|
||||||
|
Servers might need to apply validation to the `invite_room_state` depending
|
||||||
|
on room version. See the `400 M_MISSING_PARAM` error definition for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
Note that events have a different format depending on the room
|
||||||
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
items:
|
items:
|
||||||
$ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml
|
type: object
|
||||||
example:
|
title: PDU
|
||||||
$ref: ../../event-schemas/examples/invite_room_state.json
|
properties: {}
|
||||||
|
description: |-
|
||||||
|
Note that events have a different format depending on the room
|
||||||
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
type: object
|
type: object
|
||||||
required: true
|
required: true
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -118,24 +137,7 @@ paths:
|
||||||
"origin_server_ts": 1549041175876,
|
"origin_server_ts": 1549041175876,
|
||||||
"sender": "@someone:example.org",
|
"sender": "@someone:example.org",
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"invite_room_state": [
|
"invite_room_state": {"$ref": "./examples/invite_or_knock_state.json"}
|
||||||
{
|
|
||||||
"type": "m.room.name",
|
|
||||||
"sender": "@bob:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"content": {
|
|
||||||
"name": "Example Room"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "m.room.join_rules",
|
|
||||||
"sender": "@bob:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"content": {
|
|
||||||
"join_rule": "invite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"membership": "invite"
|
"membership": "invite"
|
||||||
|
|
@ -168,6 +170,35 @@ paths:
|
||||||
"errcode": "M_FORBIDDEN",
|
"errcode": "M_FORBIDDEN",
|
||||||
"error": "User cannot invite the target user."
|
"error": "User cannot invite the target user."
|
||||||
}
|
}
|
||||||
|
"400":
|
||||||
|
description: |-
|
||||||
|
The `M_MISSING_PARAM` error code is used to indicate one or more of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
* The `m.room.create` event is missing from `invite_room_state`.
|
||||||
|
* One or more entries in `invite_room_state` are not formatted according
|
||||||
|
to the room's version.
|
||||||
|
* One or more events fails a [signature check](/server-server-api/#validating-hashes-and-signatures-on-received-events).
|
||||||
|
* One or more events does not reside in the same room as the invite.
|
||||||
|
Note: Some room versions may require calculating the room ID for an
|
||||||
|
event rather than relying on the presence of `room_id`.
|
||||||
|
|
||||||
|
Servers MAY apply the validation above to room versions 1 through 11,
|
||||||
|
and SHOULD apply the validation above to all other room versions.
|
||||||
|
|
||||||
|
If `M_MISSING_PARAM` is returned and the request is associated with a
|
||||||
|
Client-Server API request, the Client-Server API request SHOULD fail
|
||||||
|
with a 5xx error rather than being passed through.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: ../client-server/definitions/errors/error.yaml
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value: {
|
||||||
|
"errcode": "M_MISSING_PARAM",
|
||||||
|
"error": "Create event not among invite state entries."
|
||||||
|
}
|
||||||
servers:
|
servers:
|
||||||
- url: "{protocol}://{hostname}{basePath}"
|
- url: "{protocol}://{hostname}{basePath}"
|
||||||
variables:
|
variables:
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,32 @@ paths:
|
||||||
$ref: definitions/invite_event.yaml
|
$ref: definitions/invite_event.yaml
|
||||||
invite_room_state:
|
invite_room_state:
|
||||||
type: array
|
type: array
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": |
|
||||||
|
`m.room.create` and format requirements were added.
|
||||||
description: |-
|
description: |-
|
||||||
An optional list of [stripped state events](/client-server-api/#stripped-state)
|
A list of state events to help the receiver of the invite identify the room.
|
||||||
to help the receiver of the invite identify the room.
|
Translated as [stripped state events](/client-server-api/#stripped-state)
|
||||||
|
over the Client-Server API.
|
||||||
|
|
||||||
|
MUST contain the `m.room.create` event for the room. All events listed
|
||||||
|
MUST additionally be formatted according to the room version specification.
|
||||||
|
|
||||||
|
Servers might need to apply validation to the `invite_room_state` depending
|
||||||
|
on room version. See the `400 M_MISSING_PARAM` error definition for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
Note that events have a different format depending on the room
|
||||||
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
items:
|
items:
|
||||||
$ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml
|
type: object
|
||||||
example:
|
title: PDU
|
||||||
$ref: ../../event-schemas/examples/invite_room_state.json
|
properties: {}
|
||||||
|
description: |-
|
||||||
|
Note that events have a different format depending on the room
|
||||||
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
required:
|
required:
|
||||||
- room_version
|
- room_version
|
||||||
- event
|
- event
|
||||||
|
|
@ -111,24 +130,7 @@ paths:
|
||||||
"origin_server_ts": 1549041175876,
|
"origin_server_ts": 1549041175876,
|
||||||
"sender": "@someone:example.org",
|
"sender": "@someone:example.org",
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"invite_room_state": [
|
"invite_room_state": {"$ref": "./examples/invite_or_knock_state.json"}
|
||||||
{
|
|
||||||
"type": "m.room.name",
|
|
||||||
"sender": "@bob:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"content": {
|
|
||||||
"name": "Example Room"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "m.room.join_rules",
|
|
||||||
"sender": "@bob:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"content": {
|
|
||||||
"join_rule": "invite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"membership": "invite"
|
"membership": "invite"
|
||||||
|
|
@ -151,6 +153,24 @@ paths:
|
||||||
|
|
||||||
The error should be passed through to clients so that they
|
The error should be passed through to clients so that they
|
||||||
may give better feedback to users.
|
may give better feedback to users.
|
||||||
|
|
||||||
|
The `M_MISSING_PARAM` error code is used to indicate one or more of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
* The `m.room.create` event is missing from `invite_room_state`.
|
||||||
|
* One or more entries in `invite_room_state` are not formatted according
|
||||||
|
to the room's version.
|
||||||
|
* One or more events fails a [signature check](/server-server-api/#validating-hashes-and-signatures-on-received-events).
|
||||||
|
* One or more events does not reside in the same room as the invite.
|
||||||
|
Note: Some room versions may require calculating the room ID for an
|
||||||
|
event rather than relying on the presence of `room_id`.
|
||||||
|
|
||||||
|
Servers MAY apply the validation above to room versions 1 through 11,
|
||||||
|
and SHOULD apply the validation above to all other room versions.
|
||||||
|
|
||||||
|
If `M_MISSING_PARAM` is returned and the request is associated with a
|
||||||
|
Client-Server API request, the Client-Server API request SHOULD fail
|
||||||
|
with a 5xx error rather than being passed through.
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
|
|
||||||
|
|
@ -293,19 +293,41 @@ paths:
|
||||||
knock_room_state:
|
knock_room_state:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml
|
type: object
|
||||||
|
title: PDU
|
||||||
|
properties: {}
|
||||||
description: |-
|
description: |-
|
||||||
A list of [stripped state events](/client-server-api/#stripped-state)
|
Note that events have a different format depending on the room
|
||||||
to help the initiator of the knock identify the room.
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.16": |
|
||||||
|
`m.room.create` and format requirements were added.
|
||||||
|
description: |-
|
||||||
|
A list of state events to help the initiator of the knock identify
|
||||||
|
the room. Translated as [stripped state events](/client-server-api/#stripped-state)
|
||||||
|
over the Client-Server API.
|
||||||
|
|
||||||
|
MUST contain the `m.room.create` event for the room. All events
|
||||||
|
listed MUST additionally be formatted according to the room
|
||||||
|
version specification.
|
||||||
|
|
||||||
|
Entries which are [improperly signed](/server-server-api/#validating-hashes-and-signatures-on-received-events)
|
||||||
|
or formatted SHOULD be removed by the server prior to supplying
|
||||||
|
them over the Client-Server API.
|
||||||
|
|
||||||
|
Note that events have a different format depending on the room
|
||||||
|
version - check the [room version specification](/rooms) for
|
||||||
|
precise event formats.
|
||||||
example:
|
example:
|
||||||
$ref: ../../event-schemas/examples/knock_room_state.json
|
"$ref": "./examples/invite_or_knock_state.json"
|
||||||
required:
|
required:
|
||||||
- knock_room_state
|
- knock_room_state
|
||||||
examples:
|
examples:
|
||||||
response:
|
response:
|
||||||
value: {
|
value: {
|
||||||
"knock_room_state": {
|
"knock_room_state": {
|
||||||
"$ref": "../../event-schemas/examples/knock_room_state.json"
|
"$ref": "./examples/invite_or_knock_state.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"403":
|
"403":
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,6 @@
|
||||||
"type": "m.push_rules",
|
"type": "m.push_rules",
|
||||||
"content": {
|
"content": {
|
||||||
"global": {
|
"global": {
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"actions": [
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"set_tweak": "sound",
|
|
||||||
"value": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"set_tweak": "highlight"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"default": true,
|
|
||||||
"enabled": true,
|
|
||||||
"pattern": "alice",
|
|
||||||
"rule_id": ".m.rule.contains_user_name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"override": [
|
"override": [
|
||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
|
@ -82,12 +64,14 @@
|
||||||
],
|
],
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"kind": "contains_display_name"
|
"kind": "event_property_contains",
|
||||||
|
"key": "content.m\\.mentions.user_ids",
|
||||||
|
"value": "@alice:example.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": true,
|
"default": true,
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rule_id": ".m.rule.contains_display_name"
|
"rule_id": ".m.rule.is_user_mention"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"actions": [
|
"actions": [
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
entity:
|
entity:
|
||||||
description: |-
|
description: |-
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
type: object
|
type: object
|
||||||
x-addedInMatrixVersion: "1.10"
|
x-addedInMatrixVersion: "1.10"
|
||||||
description: |-
|
description: |-
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
description: "The content of all call events shares a set of common fields: those
|
description: "The content of all call events shares a set of common fields: those
|
||||||
of room events and some additional VoIP specific fields."
|
of room events and some additional VoIP specific fields."
|
||||||
properties:
|
properties:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
description: The basic set of fields all events must have.
|
description: The basic set of fields all events must have.
|
||||||
properties:
|
properties:
|
||||||
content:
|
content:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
description: Metadata about an avatar image.
|
description: Metadata about an avatar image.
|
||||||
properties:
|
properties:
|
||||||
h:
|
h:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
|
||||||
description: Metadata about an image.
|
description: Metadata about an image.
|
||||||
properties:
|
properties:
|
||||||
h:
|
h:
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue