mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-03-23 19:44:09 +01:00
Merge branch 'main' into 3077-multi-stream-voip
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
commit
83b3c676f3
1
.github/ISSUE_TEMPLATE/release.md
vendored
1
.github/ISSUE_TEMPLATE/release.md
vendored
|
|
@ -16,6 +16,7 @@ Previous release: <!-- LINK TO LAST RELEASE'S CHECKLIST -->
|
||||||
|
|
||||||
Preflight checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)):
|
Preflight checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)):
|
||||||
|
|
||||||
|
* [ ] Ensure the social media account holders are available for the release day.
|
||||||
* [ ] Blog post written
|
* [ ] Blog post written
|
||||||
* [ ] Check for release blockers that may have been missed
|
* [ ] Check for release blockers that may have been missed
|
||||||
* [ ] Review/fix the changelog
|
* [ ] Review/fix the changelog
|
||||||
|
|
|
||||||
2
.github/workflows/checks.yaml
vendored
2
.github/workflows/checks.yaml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: scripts/check-newsfragments
|
- run: scripts/check-newsfragments
|
||||||
|
|
|
||||||
95
.github/workflows/main.yml
vendored
95
.github/workflows/main.yml
vendored
|
|
@ -18,18 +18,37 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: "➕ Setup Node"
|
- name: "➕ Setup Node"
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '18'
|
||||||
- name: "🔎 Run validator"
|
- name: "🔎 Run validator"
|
||||||
run: |
|
run: |
|
||||||
npx @redocly/cli@latest lint data/api/*/*.yaml
|
npx @redocly/cli@latest lint data/api/*/*.yaml
|
||||||
|
|
||||||
check-examples:
|
check-event-examples:
|
||||||
name: "🔎 Check Event schema examples"
|
name: "🔎 Check Event schema examples"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "📥 Source checkout"
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: "➕ Setup Python"
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: scripts/requirements.txt
|
||||||
|
- name: "➕ Install dependencies"
|
||||||
|
run: |
|
||||||
|
pip install -r scripts/requirements.txt
|
||||||
|
- name: "🔎 Run validator"
|
||||||
|
run: |
|
||||||
|
python scripts/check-event-schema-examples.py
|
||||||
|
|
||||||
|
check-openapi-examples:
|
||||||
|
name: "🔎 Check OpenAPI definitions examples"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
@ -44,7 +63,26 @@ jobs:
|
||||||
pip install -r scripts/requirements.txt
|
pip install -r scripts/requirements.txt
|
||||||
- name: "🔎 Run validator"
|
- name: "🔎 Run validator"
|
||||||
run: |
|
run: |
|
||||||
python scripts/check-event-schema-examples.py
|
python scripts/check-openapi-sources.py
|
||||||
|
|
||||||
|
check-schemas-examples:
|
||||||
|
name: "🔎 Check JSON Schemas inline examples"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "📥 Source checkout"
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: "➕ Setup Python"
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: scripts/requirements.txt
|
||||||
|
- name: "➕ Install dependencies"
|
||||||
|
run: |
|
||||||
|
pip install -r scripts/requirements.txt
|
||||||
|
- name: "🔎 Run validator"
|
||||||
|
run: |
|
||||||
|
python scripts/check-json-schemas.py
|
||||||
|
|
||||||
calculate-baseurl:
|
calculate-baseurl:
|
||||||
name: "⚙️ Calculate baseURL for later jobs"
|
name: "⚙️ Calculate baseURL for later jobs"
|
||||||
|
|
@ -74,7 +112,7 @@ jobs:
|
||||||
needs: [calculate-baseurl]
|
needs: [calculate-baseurl]
|
||||||
steps:
|
steps:
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: "➕ Setup Python"
|
- name: "➕ Setup Python"
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -92,24 +130,29 @@ jobs:
|
||||||
export RELEASE="unstable"
|
export RELEASE="unstable"
|
||||||
fi
|
fi
|
||||||
# The output path matches the final deployment path at spec.matrix.org
|
# The output path matches the final deployment path at spec.matrix.org
|
||||||
scripts/dump-swagger.py \
|
scripts/dump-openapi.py \
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
||||||
--api application-service \
|
--api application-service \
|
||||||
-r "$RELEASE" \
|
-r "$RELEASE" \
|
||||||
-o spec/application-service-api/api.json
|
-o spec/application-service-api/api.json
|
||||||
scripts/dump-swagger.py \
|
scripts/dump-openapi.py \
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
||||||
--api client-server \
|
--api client-server \
|
||||||
-r "$RELEASE" \
|
-r "$RELEASE" \
|
||||||
-o spec/client-server-api/api.json
|
-o spec/client-server-api/api.json
|
||||||
scripts/dump-swagger.py \
|
scripts/dump-openapi.py \
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
||||||
--api push-gateway \
|
--api push-gateway \
|
||||||
-r "$RELEASE" \
|
-r "$RELEASE" \
|
||||||
-o spec/push-gateway-api/api.json
|
-o spec/push-gateway-api/api.json
|
||||||
|
scripts/dump-openapi.py \
|
||||||
|
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
||||||
|
--api server-server \
|
||||||
|
-r "$RELEASE" \
|
||||||
|
-o spec/server-server-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@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: openapi-artifact
|
name: openapi-artifact
|
||||||
path: openapi.tar.gz
|
path: openapi.tar.gz
|
||||||
|
|
@ -121,7 +164,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: "➕ Setup Python"
|
- name: "➕ Setup Python"
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
- name: "➕ Install towncrier"
|
- name: "➕ Install towncrier"
|
||||||
|
|
@ -129,7 +172,7 @@ jobs:
|
||||||
- name: "Generate changelog"
|
- name: "Generate changelog"
|
||||||
run: ./scripts/generate-changelog.sh vUNSTABLE
|
run: ./scripts/generate-changelog.sh vUNSTABLE
|
||||||
- name: "📤 Artifact upload"
|
- name: "📤 Artifact upload"
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: changelog-artifact
|
name: changelog-artifact
|
||||||
path: content/changelog/vUNSTABLE.md
|
path: content/changelog/vUNSTABLE.md
|
||||||
|
|
@ -142,16 +185,16 @@ jobs:
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
steps:
|
steps:
|
||||||
- name: "➕ Setup Node"
|
- name: "➕ Setup Node"
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '18'
|
||||||
- name: "➕ Setup Hugo"
|
- name: "➕ Setup Hugo"
|
||||||
uses: peaceiris/actions-hugo@c03b5dbed22245418539b65eb9a3b1d5fdd9a0a6
|
uses: peaceiris/actions-hugo@16361eb4acea8698b220b76c0d4e84e1fd22c61d
|
||||||
with:
|
with:
|
||||||
hugo-version: '0.113.0'
|
hugo-version: '0.113.0'
|
||||||
extended: true
|
extended: true
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: "⚙️ npm"
|
- name: "⚙️ npm"
|
||||||
run: |
|
run: |
|
||||||
npm i
|
npm i
|
||||||
|
|
@ -169,7 +212,7 @@ jobs:
|
||||||
# https://spec.matrix.org/latest/client-server-api/api.json
|
# https://spec.matrix.org/latest/client-server-api/api.json
|
||||||
# Works for /unstable/ and /v1.1/ as well.
|
# Works for /unstable/ and /v1.1/ as well.
|
||||||
- name: "📥 Spec definition download"
|
- name: "📥 Spec definition download"
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: openapi-artifact
|
name: openapi-artifact
|
||||||
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
||||||
|
|
@ -179,7 +222,7 @@ jobs:
|
||||||
- name: "📦 Tarball creation"
|
- name: "📦 Tarball creation"
|
||||||
run: tar -czf spec.tar.gz spec
|
run: tar -czf spec.tar.gz spec
|
||||||
- name: "📤 Artifact upload"
|
- name: "📤 Artifact upload"
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spec-artifact
|
name: spec-artifact
|
||||||
path: spec.tar.gz
|
path: spec.tar.gz
|
||||||
|
|
@ -190,10 +233,10 @@ jobs:
|
||||||
needs: [calculate-baseurl, build-spec]
|
needs: [calculate-baseurl, build-spec]
|
||||||
steps:
|
steps:
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: "📥 Fetch built spec"
|
- name: "📥 Fetch built spec"
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spec-artifact
|
name: spec-artifact
|
||||||
|
|
||||||
|
|
@ -219,16 +262,16 @@ jobs:
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
steps:
|
steps:
|
||||||
- name: "➕ Setup Node"
|
- name: "➕ Setup Node"
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '18'
|
||||||
- name: "➕ Setup Hugo"
|
- name: "➕ Setup Hugo"
|
||||||
uses: peaceiris/actions-hugo@c03b5dbed22245418539b65eb9a3b1d5fdd9a0a6
|
uses: peaceiris/actions-hugo@16361eb4acea8698b220b76c0d4e84e1fd22c61d
|
||||||
with:
|
with:
|
||||||
hugo-version: '0.93.3'
|
hugo-version: '0.93.3'
|
||||||
extended: true
|
extended: true
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: "⚙️ npm"
|
- name: "⚙️ npm"
|
||||||
run: |
|
run: |
|
||||||
npm i
|
npm i
|
||||||
|
|
@ -240,7 +283,7 @@ jobs:
|
||||||
hugo --config config.toml,historical.toml --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec"
|
hugo --config config.toml,historical.toml --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec"
|
||||||
|
|
||||||
- name: "📥 Spec definition download"
|
- name: "📥 Spec definition download"
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: openapi-artifact
|
name: openapi-artifact
|
||||||
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
||||||
|
|
@ -250,7 +293,7 @@ jobs:
|
||||||
- name: "📦 Tarball creation"
|
- name: "📦 Tarball creation"
|
||||||
run: tar -czf spec-historical.tar.gz spec
|
run: tar -czf spec-historical.tar.gz spec
|
||||||
- name: "📤 Artifact upload"
|
- name: "📤 Artifact upload"
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spec-historical-artifact
|
name: spec-historical-artifact
|
||||||
path: spec-historical.tar.gz
|
path: spec-historical.tar.gz
|
||||||
|
|
|
||||||
6
.github/workflows/netlify.yaml
vendored
6
.github/workflows/netlify.yaml
vendored
|
|
@ -35,7 +35,7 @@ jobs:
|
||||||
echo "::set-output name=prnumber::$pr_number"
|
echo "::set-output name=prnumber::$pr_number"
|
||||||
|
|
||||||
- name: '📥 Download artifact'
|
- name: '📥 Download artifact'
|
||||||
uses: dawidd6/action-download-artifact@af92a8455a59214b7b932932f2662fdefbd78126 # v2.15.0
|
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
||||||
with:
|
with:
|
||||||
workflow: main.yaml
|
workflow: main.yaml
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
run_id: ${{ github.event.workflow_run.id }}
|
||||||
|
|
@ -46,8 +46,8 @@ jobs:
|
||||||
|
|
||||||
- name: "📤 Deploy to Netlify"
|
- name: "📤 Deploy to Netlify"
|
||||||
id: netlify
|
id: netlify
|
||||||
# v1.2.2
|
# v2.1.0
|
||||||
uses: nwtgck/actions-netlify@f517512ae75beec8896aa7b027c1c72f01816200
|
uses: nwtgck/actions-netlify@7a92f00dde8c92a5a9e8385ec2919775f7647352
|
||||||
with:
|
with:
|
||||||
publish-dir: spec
|
publish-dir: spec
|
||||||
deploy-message: "Deploy from GitHub Actions"
|
deploy-message: "Deploy from GitHub Actions"
|
||||||
|
|
|
||||||
41
.github/workflows/release.yaml
vendored
Normal file
41
.github/workflows/release.yaml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
name: Release packages
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
jobs:
|
||||||
|
# Releases to npm after bumping the package.json version from 0.0.0 to $TAG.0 as the tags only contain MAJOR.MINOR
|
||||||
|
npm:
|
||||||
|
name: Publish to npm
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.release.prerelease == false
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: packages/npm
|
||||||
|
steps:
|
||||||
|
- name: 🧮 Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 🔧 Yarn cache
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: "yarn"
|
||||||
|
cache-dependency-path: packages/npm/yarn.lock
|
||||||
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
|
- name: 🔨 Install dependencies
|
||||||
|
run: "yarn install --frozen-lockfile"
|
||||||
|
|
||||||
|
- name: 🎖 Bump package.json version
|
||||||
|
run: "yarn version --new-version $VERSION"
|
||||||
|
env:
|
||||||
|
VERSION: ${{ github.event.release.tag_name }}.0
|
||||||
|
|
||||||
|
- name: 🚀 Publish to npm
|
||||||
|
id: npm-publish
|
||||||
|
uses: JS-DevTools/npm-publish@5a85faf05d2ade2d5b6682bfe5359915d5159c6c # v2.2.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.NPM_TOKEN }}
|
||||||
|
package: packages/npm
|
||||||
|
access: public
|
||||||
|
ignore-scripts: false
|
||||||
4
.github/workflows/spell-check.yaml
vendored
4
.github/workflows/spell-check.yaml
vendored
|
|
@ -11,9 +11,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Actions Repository
|
- name: Checkout Actions Repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Check spelling of proposals
|
- name: Check spelling of proposals
|
||||||
uses: crate-ci/typos@9be36f97fdbe645ee9a12449fb13aca856c2516a
|
uses: crate-ci/typos@ff3f309513469397e1094520fb7a054e057589e1
|
||||||
with:
|
with:
|
||||||
config: ${{github.workspace}}/.github/_typos.toml
|
config: ${{github.workspace}}/.github/_typos.toml
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,7 +2,7 @@ node_modules
|
||||||
/data/msc
|
/data/msc
|
||||||
/env*
|
/env*
|
||||||
/resources
|
/resources
|
||||||
/scripts/swagger
|
/scripts/openapi
|
||||||
/scripts/tmp
|
/scripts/tmp
|
||||||
/hugo-config.toml
|
/hugo-config.toml
|
||||||
/public
|
/public
|
||||||
|
|
|
||||||
4
.gitmodules
vendored
4
.gitmodules
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
[submodule "themes/docsy"]
|
|
||||||
path = themes/docsy
|
|
||||||
url = https://github.com/matrix-org/docsy.git
|
|
||||||
branch = master
|
|
||||||
|
|
@ -72,7 +72,7 @@ ask.
|
||||||
Adding to the changelog
|
Adding to the changelog
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
All API specifications require a changelog entry. Adding to the changelog can only
|
All changes to the contents of this repository require a changelog entry. Adding to the changelog can only
|
||||||
be done after you've opened your pull request, so be sure to do that first.
|
be done after you've opened your pull request, so be sure to do that first.
|
||||||
|
|
||||||
The changelog is managed by `Towncrier <https://github.com/twisted/towncrier>`_ in the
|
The changelog is managed by `Towncrier <https://github.com/twisted/towncrier>`_ in the
|
||||||
|
|
|
||||||
18
README.md
18
README.md
|
|
@ -22,7 +22,7 @@ The Matrix spec is compiled with [Hugo](https://gohugo.io/) (a static site gener
|
||||||
|
|
||||||
* `/data`: this can contain TOML, YAML, or JSON files. Files kept here are directly available to template code as
|
* `/data`: this can contain TOML, YAML, or JSON files. Files kept here are directly available to template code as
|
||||||
[data objects](https://gohugo.io/templates/data-templates/), so templates don't need to load them from a file and
|
[data objects](https://gohugo.io/templates/data-templates/), so templates don't need to load them from a file and
|
||||||
parse them. This is also where our Swagger/OpenAPI definitions and schemas are.
|
parse them. This is also where our OpenAPI definitions and schemas are.
|
||||||
|
|
||||||
* `/layouts`: this contains [Hugo templates](https://gohugo.io/templates/). Some templates define the overall layout of
|
* `/layouts`: this contains [Hugo templates](https://gohugo.io/templates/). Some templates define the overall layout of
|
||||||
a page: for example, whether it has header, footer, sidebar, and so on.
|
a page: for example, whether it has header, footer, sidebar, and so on.
|
||||||
|
|
@ -52,6 +52,7 @@ Additionally, the following directories may be of interest:
|
||||||
* `/data-definitions`: Bits of structured data consumable by Matrix implementations.
|
* `/data-definitions`: Bits of structured data consumable by Matrix implementations.
|
||||||
* `/meta`: Documentation relating to the spec's processes that are otherwise untracked (release instructions, etc).
|
* `/meta`: Documentation relating to the spec's processes that are otherwise untracked (release instructions, etc).
|
||||||
* `/scripts`: Various scripts for generating the spec and validating its contents.
|
* `/scripts`: Various scripts for generating the spec and validating its contents.
|
||||||
|
* `/packages`: Various packages for shipping spec files like OpenAPI bindings and data definitions.
|
||||||
|
|
||||||
## Authoring changes to the spec
|
## Authoring changes to the spec
|
||||||
|
|
||||||
|
|
@ -60,13 +61,12 @@ 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.93.0 is required.
|
v0.110.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
|
||||||
to process the SCSS.)
|
to process the SCSS.)
|
||||||
2. Run `npm i` to install the dependencies and fetch the docsy git submodule.
|
2. Run `npm i` to install the dependencies. Note that this will require NodeJS to be installed.
|
||||||
Note that this will require NodeJS to be installed.
|
|
||||||
3. Run `npm run get-proposals` to seed proposal data. This is merely for populating the content of the "Spec Change Proposals"
|
3. Run `npm run get-proposals` to seed proposal data. This is merely for populating the content of the "Spec Change Proposals"
|
||||||
page and is not required.
|
page and is not required.
|
||||||
4. Run `hugo serve` (or `docker run --rm -it -v $(pwd):/src -p 1313:1313
|
4. Run `hugo serve` (or `docker run --rm -it -v $(pwd):/src -p 1313:1313
|
||||||
|
|
@ -86,13 +86,13 @@ steps for authoring changes to the specification and instead of `hugo serve` run
|
||||||
spec to `/spec`. If you'd like to serve the spec off a path instead of a domain root (eg: `/unstable`), add `--baseURL "/unstable"`
|
spec to `/spec`. If you'd like to serve the spec off a path instead of a domain root (eg: `/unstable`), add `--baseURL "/unstable"`
|
||||||
to the `hugo -d "spec"` command.
|
to the `hugo -d "spec"` command.
|
||||||
|
|
||||||
For building the swagger definitions, create a python3 virtualenv and activate it. Then run `pip install -r ./scripts/requirements.txt`
|
For building the OpenAPI definitions, create a python3 virtualenv and activate it. Then run `pip install -r ./scripts/requirements.txt`
|
||||||
and finally `python ./scripts/dump-swagger.py` to generate it to `./scripts/swagger/api-docs.json`. To make use of the generated file,
|
and finally `python ./scripts/dump-openapi.py` to generate it to `./scripts/openapi/api-docs.json`. To make use of the generated file,
|
||||||
there are a number of options:
|
there are a number of options:
|
||||||
|
|
||||||
* You can open `./scripts/swagger-preview.html` in your browser, and then open the file by clicking on `Local JSON File`.
|
* You can open `./scripts/openapi-preview.html` in your browser, and then open the file by clicking on `Local JSON File`.
|
||||||
* You can run a local HTTP server by running `./scripts/swagger-http-server.py`, and then view the documentation by
|
* You can run a local HTTP server by running `./scripts/openapi-http-server.py`, and then view the documentation by
|
||||||
opening `./scripts/swagger-preview.html` in your browser.
|
opening `./scripts/openapi-preview.html` in your browser.
|
||||||
|
|
||||||
## Issue tracking
|
## Issue tracking
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@ limitations under the License.
|
||||||
Custom SCSS for the Matrix spec
|
Custom SCSS for the Matrix spec
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import "variables_project";
|
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
/* Import the CSS classes for the syntax highlighter.
|
/* Import the CSS classes for the syntax highlighter.
|
||||||
*
|
*
|
||||||
* This is generated with:
|
* This is generated with:
|
||||||
|
|
@ -49,6 +46,10 @@ Custom SCSS for the Matrix spec
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $black;
|
color: $black;
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +293,7 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styles for sections that are rendered from data, such as HTTP APIs and event schemas */
|
/* Styles for sections that are rendered from data, such as HTTP APIs and event schemas */
|
||||||
.rendered-data {
|
.td-content .rendered-data {
|
||||||
background-color: $secondary-lightest-background;
|
background-color: $secondary-lightest-background;
|
||||||
padding: 0.85rem;
|
padding: 0.85rem;
|
||||||
margin: 0.85rem 0;
|
margin: 0.85rem 0;
|
||||||
|
|
@ -346,23 +347,41 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
p code, table code {
|
p code, table code {
|
||||||
background-color: inherit;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
/* Docsy makes all tables "responsive tables", which causes Bootstrap 4 to create
|
@media (max-width: 800px) {
|
||||||
* tables with a "display" property of "block".
|
/* Docsy by default applies `overflow-x: auto;` to tables, which
|
||||||
*
|
* results in annoying horizontal scrolling on mobile, so we instead
|
||||||
* However, for "table-layout: fixed" to be effective, an element must have a
|
* switch to a fixed table layout on a narrow browser width.
|
||||||
* "display" property of "table".
|
* (On a wider width the default auto table-layout provides better readability.)
|
||||||
*
|
*
|
||||||
* Thus, we override the "display" property here. This may no longer be necessary once
|
* Docsy makes all tables "responsive tables", which causes Bootstrap 4 to create
|
||||||
* Docsy updates to Bootstrap v5+: https://github.com/google/docsy/issues/470.
|
* tables with a "display" property of "block".
|
||||||
* For more details, see
|
* However, for "table-layout: fixed" to be effective, an element must have a
|
||||||
* https://github.com/matrix-org/matrix-spec/pull/1295/files#r1010759688 */
|
* "display" property of "table".
|
||||||
display: table;
|
*
|
||||||
table-layout: fixed;
|
* Thus, we override the "display" property here. This may no longer be necessary once
|
||||||
width: 100%;
|
* Docsy updates to Bootstrap v5+: https://github.com/google/docsy/issues/470.
|
||||||
|
* For more details, see
|
||||||
|
* https://github.com/matrix-org/matrix-spec/pull/1295/files#r1010759688 */
|
||||||
|
display: table;
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.col-name, .col-type, .col-status {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-description {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-status-description {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add some space between two tables when they are right next to each other
|
// add some space between two tables when they are right next to each other
|
||||||
& + table {
|
& + table {
|
||||||
|
|
@ -378,6 +397,7 @@ footer {
|
||||||
|
|
||||||
th, td, caption {
|
th, td, caption {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
border-top: 1px $table-border-color solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.object-table, &.response-table, &.content-type-table {
|
&.object-table, &.response-table, &.content-type-table {
|
||||||
|
|
@ -390,14 +410,12 @@ footer {
|
||||||
|
|
||||||
// ... but avoid double border between caption and table
|
// ... but avoid double border between caption and table
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
|
||||||
|
background-color: $secondary-lighter-background;
|
||||||
}
|
}
|
||||||
|
|
||||||
caption, tbody tr {
|
tbody tr {
|
||||||
background-color: $table-row-default;
|
--bs-table-striped-bg: #{$secondary-lighter-background};
|
||||||
}
|
|
||||||
|
|
||||||
tbody tr:nth-child(even) {
|
|
||||||
background-color: $table-row-alternate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -409,19 +427,6 @@ footer {
|
||||||
&.basic-info th {
|
&.basic-info th {
|
||||||
width: 15rem;
|
width: 15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-name, .col-type, .col-status {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-description {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-status-description {
|
|
||||||
width: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
|
@ -512,3 +517,15 @@ dd {
|
||||||
border-radius: 0.25rem; // was $border-radius, but that var isn't accessible here.
|
border-radius: 0.25rem; // was $border-radius, but that var isn't accessible here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Style for breadcrumbs */
|
||||||
|
.td-breadcrumbs {
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: .25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ $dark: #333;
|
||||||
$gray-100: #FBFBFB;
|
$gray-100: #FBFBFB;
|
||||||
|
|
||||||
$secondary-background: #E5F5FB;
|
$secondary-background: #E5F5FB;
|
||||||
$secondary-lighter-background: #F4FaFC;
|
$secondary-lighter-background: #F4FAFC;
|
||||||
$secondary-lightest-background: #FBFDFD;
|
$secondary-lightest-background: #FBFDFD;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -33,8 +33,7 @@ $warning-background: #FFE0E0;
|
||||||
// colours for definition tables.
|
// colours for definition tables.
|
||||||
// the border colour matches that used for "highlight" divs
|
// the border colour matches that used for "highlight" divs
|
||||||
$table-border-color: rgba(black, .125);
|
$table-border-color: rgba(black, .125);
|
||||||
$table-row-alternate: $secondary-lightest-background;
|
$table-bg: $secondary-lightest-background;
|
||||||
$table-row-default: $secondary-lighter-background;
|
|
||||||
|
|
||||||
/* Configure docsy to use the default system fonts instead of Google Fonts.
|
/* Configure docsy to use the default system fonts instead of Google Fonts.
|
||||||
* See https://www.docsy.dev/docs/adding-content/lookandfeel/#fonts */
|
* See https://www.docsy.dev/docs/adding-content/lookandfeel/#fonts */
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Clarify spec re canonical JSON to handle negative-zero; also, give an example of negative-zero and a large power of ten
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Allow `+` in Matrix IDs, per [MSC4009](https://github.com/matrix-org/matrix-spec-proposals/pull/4009).
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix JSON schema of custom fields in query.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix missing `type` property in the JSON schema definition of the `m.reaction` event. Contributed by @chebureki.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Make sure examples types match schema in definitions.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix broken header formatting. Contributed by @midnightveil.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Render binary request and response bodies.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Remove unnecessary `oneOf`s in JSON schemas.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix description of MAC calculation in SAS verification.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Update link to SAS emoji definition data.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix various typos throughout the specification.
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
The [strike](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strike) element is deprecated in the HTML spec. Clients should prefer [s](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s) instead.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that read-receipts should be batched by thread as well as room.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that threads can be created based on replies.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Make clearer in the example for reply fallbacks that the prefix sequence should be repeated for each line.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify the format of account data objects for secret storage.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that the key backup MAC is implemented incorrectly and does not pass the ciphertext through HMAC-SHA-256.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify one-time key and fallback key types in examples.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that the HKDF calculation for SAS uses base64-encoded keys rather than the raw key bytes.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify how to perform the ECDH exchange in step 12 of the SAS process.
|
||||||
1
changelogs/client_server/newsfragments/1730.feature
Normal file
1
changelogs/client_server/newsfragments/1730.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add local erasure requests, as per [MSC4025](https://github.com/matrix-org/matrix-spec-proposals/pull/4025).
|
||||||
1
changelogs/client_server/newsfragments/1731.feature
Normal file
1
changelogs/client_server/newsfragments/1731.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Use the `body` field as media caption, as per [MSC2530](https://github.com/matrix-org/matrix-spec-proposals/pull/2530).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify the format of account data objects for secret storage.
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Make sure examples types match schema in definitions.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Upgrade Swagger data to OpenAPI 3.1.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Update the CI to validate the file extension of changelog entries.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Disclosure sections now only display their title when collapsed.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix the sidebar in recent versions of Hugo
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Bump jsonschema to validate JSON Schemas against Draft 2020-12.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Use Redocly CLI to validate OpenAPI definitions.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Use tag name as the OpenAPI definition version.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Make sure version in x-changedInMatrixVersion is a string.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Clarify usage of ABNF for grammar in the documentation style guide.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Update the version of Hugo used to render the spec to v0.113.0.
|
|
||||||
1
changelogs/internal/newsfragments/1680.clarification
Normal file
1
changelogs/internal/newsfragments/1680.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Update the spec release process.
|
||||||
1
changelogs/internal/newsfragments/1697.clarification
Normal file
1
changelogs/internal/newsfragments/1697.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Minor clarifications to the contributing guide.
|
||||||
1
changelogs/internal/newsfragments/1699.clarification
Normal file
1
changelogs/internal/newsfragments/1699.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Update Docsy to v0.8.0.
|
||||||
1
changelogs/internal/newsfragments/1713.misc
Normal file
1
changelogs/internal/newsfragments/1713.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix npm release script for `@matrix-org/spec`.
|
||||||
1
changelogs/internal/newsfragments/1724.clarification
Normal file
1
changelogs/internal/newsfragments/1724.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Update HTML templates to include links to object schema definitions.
|
||||||
|
|
@ -1,39 +1,66 @@
|
||||||
[tool.towncrier]
|
[tool.towncrier]
|
||||||
version = "unused"
|
version = "unused"
|
||||||
filename = "../rendered.md"
|
filename = "rendered.md"
|
||||||
issue_format = "[#{issue}](https://github.com/matrix-org/matrix-spec/issues/{issue})"
|
template = "template.md.jinja"
|
||||||
title_format = "### {name}" # Matches rendered spec, even if awkward
|
|
||||||
underlines = " " # 3 spaces intentionally to hide RST headings
|
|
||||||
|
|
||||||
# Note: The names below have the <strong> tag built-in so the rendered spec *and* the generated
|
|
||||||
# changelog can benefit from sane headings.
|
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "breaking"
|
directory = "breaking"
|
||||||
name = "<strong>Breaking Changes</strong>"
|
name = "Breaking Changes"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "deprecation"
|
directory = "deprecation"
|
||||||
name = "<strong>Deprecations</strong>"
|
name = "Deprecations"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "new"
|
directory = "new"
|
||||||
name = "<strong>New Endpoints</strong>"
|
name = "New Endpoints"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "removal"
|
directory = "removal"
|
||||||
name = "<strong>Removed Endpoints</strong>"
|
name = "Removed Endpoints"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "feature"
|
directory = "feature"
|
||||||
name = "<strong>Backwards Compatible Changes</strong>"
|
name = "Backwards Compatible Changes"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[[tool.towncrier.type]]
|
[[tool.towncrier.type]]
|
||||||
directory = "clarification"
|
directory = "clarification"
|
||||||
name = "<strong>Spec Clarifications</strong>"
|
name = "Spec Clarifications"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Client-Server API"
|
||||||
|
path = "client_server"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Server-Server API"
|
||||||
|
path = "server_server"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Application Service API"
|
||||||
|
path = "application_service"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Identity Service API"
|
||||||
|
path = "identity_service"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Push Gateway API"
|
||||||
|
path = "push_gateway"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Room Versions"
|
||||||
|
path = "room_versions"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Appendices"
|
||||||
|
path = "appendices"
|
||||||
|
|
||||||
|
[[tool.towncrier.section]]
|
||||||
|
name = "Internal Changes/Tooling"
|
||||||
|
path = "internal"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
For room versions 7 through 11: Clarify that `invite->knock` is not a legal transition.
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Document why `/state_ids` can respond with a 404.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix definition of response of `POST /_matrix/federation/v1/user/keys/claim`.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix level of examples in server keys definition.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Make sure examples types match schema in definitions.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix broken header formatting. Contributed by @midnightveil.
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify Server-Server API request signing example by using the `POST` HTTP method, as `GET` requests don't have request bodies.
|
||||||
24
changelogs/template.md.jinja
Normal file
24
changelogs/template.md.jinja
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{% for section_name, section in sections.items() %}
|
||||||
|
{% if section_name %}
|
||||||
|
|
||||||
|
### {{section_name}}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if section %}
|
||||||
|
{% for category, val in definitions.items() if category in section %}
|
||||||
|
**{{ definitions[category]['name'] }}**
|
||||||
|
|
||||||
|
{% for content, issues in section[category].items() %}
|
||||||
|
- {{ content }} (
|
||||||
|
{%- for issue in issues %}
|
||||||
|
[{{issue}}](https://github.com/matrix-org/matrix-spec/issues/{{issue|trim('#')}}){% if not loop.last %}, {% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
)
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
32
config.toml
32
config.toml
|
|
@ -7,9 +7,6 @@ canonifyURLs = true
|
||||||
|
|
||||||
enableRobotsTXT = true
|
enableRobotsTXT = true
|
||||||
|
|
||||||
# Hugo allows theme composition (and inheritance). The precedence is from left to right.
|
|
||||||
theme = ["docsy"]
|
|
||||||
|
|
||||||
# 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">`).
|
||||||
|
|
@ -23,6 +20,21 @@ languageName ="English"
|
||||||
# Weight used for sorting.
|
# Weight used for sorting.
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
# Entries in the main menu in the header.
|
||||||
|
[menus]
|
||||||
|
[[menus.main]]
|
||||||
|
name = 'Foundation'
|
||||||
|
url = 'https://matrix.org/foundation/'
|
||||||
|
weight = 10
|
||||||
|
[[menus.main]]
|
||||||
|
name = 'FAQs'
|
||||||
|
url = 'https://matrix.org/faq'
|
||||||
|
weight = 20
|
||||||
|
[[menus.main]]
|
||||||
|
name = 'Blog'
|
||||||
|
url = 'https://matrix.org/blog/posts'
|
||||||
|
weight = 30
|
||||||
|
|
||||||
[markup]
|
[markup]
|
||||||
[markup.goldmark]
|
[markup.goldmark]
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
|
|
@ -53,8 +65,8 @@ 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. CI will set these values here automatically when a release git tag (i.e `v1.5`) is created.
|
# of the spec. CI will set these values here automatically when a release git tag (i.e `v1.5`) is created.
|
||||||
# major = "1"
|
# major = "1"
|
||||||
# minor = "7"
|
# minor = "9"
|
||||||
# release_date = "May 25, 2023"
|
# release_date = "November 29, 2023"
|
||||||
|
|
||||||
# User interface configuration
|
# User interface configuration
|
||||||
[params.ui]
|
[params.ui]
|
||||||
|
|
@ -111,3 +123,13 @@ sidebar_menu_compact = true
|
||||||
X-Frame-Options = "sameorigin"
|
X-Frame-Options = "sameorigin"
|
||||||
Access-Control-Allow-Origin = "*"
|
Access-Control-Allow-Origin = "*"
|
||||||
Access-Control-Allow-Methods = "GET"
|
Access-Control-Allow-Methods = "GET"
|
||||||
|
|
||||||
|
# hugo module configuration
|
||||||
|
|
||||||
|
[module]
|
||||||
|
[module.hugoVersion]
|
||||||
|
extended = true
|
||||||
|
min = "0.110.0"
|
||||||
|
[[module.imports]]
|
||||||
|
path = "github.com/matrix-org/docsy"
|
||||||
|
disable = false
|
||||||
|
|
|
||||||
|
|
@ -419,9 +419,16 @@ into the `m.` namespace.
|
||||||
|
|
||||||
### Timestamps
|
### Timestamps
|
||||||
|
|
||||||
Unless otherwise stated, timestamps are measured as milliseconds since
|
Unless otherwise stated, timestamps are the number of milliseconds
|
||||||
the Unix epoch. Throughout the specification this may be referred to as
|
elapsed since the unix epoch (1970-01-01 00:00:00 UTC), but not counting
|
||||||
POSIX, Unix, or just "time in milliseconds".
|
leap seconds, so that each day is precisely 86,400,000 milliseconds.
|
||||||
|
|
||||||
|
This means that timestamps can repeat during leap seconds. Most
|
||||||
|
programming languages provide timestamps in that format natively, e.g.
|
||||||
|
[ECMAScript](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-time-values-and-time-range).
|
||||||
|
Throughout the specification this may be referred to as POSIX,
|
||||||
|
[Unix](https://en.wikipedia.org/wiki/Unix_time), or just "time in
|
||||||
|
milliseconds".
|
||||||
|
|
||||||
## Specification Versions
|
## Specification Versions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,12 +136,12 @@ removing insignificant whitespace, fractions, exponents and redundant
|
||||||
character escapes.
|
character escapes.
|
||||||
|
|
||||||
value = false / null / true / object / array / number / string
|
value = false / null / true / object / array / number / string
|
||||||
false = %x66.61.6c.73.65
|
false = %x66.61.6C.73.65
|
||||||
null = %x6e.75.6c.6c
|
null = %x6E.75.6C.6C
|
||||||
true = %x74.72.75.65
|
true = %x74.72.75.65
|
||||||
object = %x7B [ member *( %x2C member ) ] %7D
|
object = %x7B [ member *( %x2C member ) ] %x7D
|
||||||
member = string %x3A value
|
member = string %x3A value
|
||||||
array = %x5B [ value *( %x2C value ) ] %5B
|
array = %x5B [ value *( %x2C value ) ] %x5D
|
||||||
number = [ %x2D ] int
|
number = [ %x2D ] int
|
||||||
int = %x30 / ( %x31-39 *digit )
|
int = %x30 / ( %x31-39 *digit )
|
||||||
digit = %x30-39
|
digit = %x30-39
|
||||||
|
|
|
||||||
122
content/changelog/v1.8.md
Normal file
122
content/changelog/v1.8.md
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
---
|
||||||
|
date: 2023-08-23T09:23:53-06:00
|
||||||
|
---
|
||||||
|
<!--
|
||||||
|
This is a header file for the generated changelog.
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
v1.8 = Replaced by the version number (eg: v1.2)
|
||||||
|
August 23, 2023 = Replaced by the date (eg: April 01, 2021)
|
||||||
|
-->
|
||||||
|
|
||||||
|
## v1.8
|
||||||
|
|
||||||
|
<table class="release-info">
|
||||||
|
<tr><th>Git commit</th><td><a href="https://github.com/matrix-org/matrix-spec/tree/v1.8">https://github.com/matrix-org/matrix-spec/tree/v1.8</a></td>
|
||||||
|
<tr><th>Release date</th><td>August 23, 2023</td>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Intentionally blank line to ensure headers work in the concatenated changelog -->
|
||||||
|
|
||||||
|
### Client-Server API
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Require callers to be joined to the room to report its events, as per [MSC2249](https://github.com/matrix-org/matrix-spec-proposals/pull/2249). ([#1517](https://github.com/matrix-org/matrix-spec/issues/1517))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Fix missing `type` property in the JSON schema definition of the `m.reaction` event. Contributed by @chebureki. ([#1552](https://github.com/matrix-org/matrix-spec/issues/1552))
|
||||||
|
- Make sure examples types match schema in definitions. ([#1563](https://github.com/matrix-org/matrix-spec/issues/1563))
|
||||||
|
- Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas. ([#1564](https://github.com/matrix-org/matrix-spec/issues/1564))
|
||||||
|
- Fix broken header formatting. Contributed by @midnightveil. ([#1578](https://github.com/matrix-org/matrix-spec/issues/1578))
|
||||||
|
- Render binary request and response bodies. ([#1579](https://github.com/matrix-org/matrix-spec/issues/1579))
|
||||||
|
- Fix description of MAC calculation in SAS verification. ([#1590](https://github.com/matrix-org/matrix-spec/issues/1590))
|
||||||
|
- Update link to SAS emoji definition data. ([#1593](https://github.com/matrix-org/matrix-spec/issues/1593))
|
||||||
|
- Fix various typos throughout the specification. ([#1597](https://github.com/matrix-org/matrix-spec/issues/1597))
|
||||||
|
|
||||||
|
|
||||||
|
### Server-Server API
|
||||||
|
|
||||||
|
**Deprecations**
|
||||||
|
|
||||||
|
- Deprecate `matrix` SRV lookup steps during server discovery, as per [MSC4040](https://github.com/matrix-org/matrix-spec-proposals/pull/4040). ([#1624](https://github.com/matrix-org/matrix-spec/issues/1624))
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Add `matrix-fed` SRV lookup steps to server discovery, as per [MSC4040](https://github.com/matrix-org/matrix-spec-proposals/pull/4040). ([#1624](https://github.com/matrix-org/matrix-spec/issues/1624))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Document why `/state_ids` can respond with a 404. ([#1521](https://github.com/matrix-org/matrix-spec/issues/1521))
|
||||||
|
- Fix response definition for `POST /_matrix/federation/v1/user/keys/claim`. ([#1559](https://github.com/matrix-org/matrix-spec/issues/1559))
|
||||||
|
- Fix examples in server keys definition. ([#1560](https://github.com/matrix-org/matrix-spec/issues/1560))
|
||||||
|
- Make sure examples types match schema in definitions. ([#1563](https://github.com/matrix-org/matrix-spec/issues/1563))
|
||||||
|
- Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas. ([#1564](https://github.com/matrix-org/matrix-spec/issues/1564))
|
||||||
|
- Fix broken header formatting. Contributed by @midnightveil. ([#1578](https://github.com/matrix-org/matrix-spec/issues/1578))
|
||||||
|
- Remove spurious mention of a "default port" with respect to SRV record lookup. ([#1615](https://github.com/matrix-org/matrix-spec/issues/1615))
|
||||||
|
- Switch to ordered list for server name resolution steps. ([#1623](https://github.com/matrix-org/matrix-spec/issues/1623))
|
||||||
|
|
||||||
|
|
||||||
|
### Application Service API
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Fix type of custom `fields` in thirdparty lookup queries. ([#1584](https://github.com/matrix-org/matrix-spec/issues/1584))
|
||||||
|
|
||||||
|
|
||||||
|
### Identity Service API
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Make sure examples types match schema in definitions. ([#1563](https://github.com/matrix-org/matrix-spec/issues/1563))
|
||||||
|
|
||||||
|
|
||||||
|
### Push Gateway API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
### Room Versions
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Add room version 11 as per [MSC3820](https://github.com/matrix-org/matrix-spec-proposals/pull/3820). ([#1604](https://github.com/matrix-org/matrix-spec/issues/1604))
|
||||||
|
- Move `redacts` from top level to `content` on `m.room.redaction` events in room version 11, as per [MSC2174](https://github.com/matrix-org/matrix-spec-proposals/pull/2174). ([#1604](https://github.com/matrix-org/matrix-spec/issues/1604))
|
||||||
|
- Remove `creator` from `m.room.creator` events in room version 11, as per [MSC2175](https://github.com/matrix-org/matrix-spec-proposals/pull/2175). ([#1604](https://github.com/matrix-org/matrix-spec/issues/1604))
|
||||||
|
- Remove remaining usage of `origin` from events in room version 11, as per [MSC3989](https://github.com/matrix-org/matrix-spec-proposals/pull/3989). ([#1604](https://github.com/matrix-org/matrix-spec/issues/1604))
|
||||||
|
- Update the redaction rules in room version 11, as per [MSC2176](https://github.com/matrix-org/matrix-spec-proposals/pull/2176) and [MSC3821](https://github.com/matrix-org/matrix-spec-proposals/pull/3821). ([#1604](https://github.com/matrix-org/matrix-spec/issues/1604))
|
||||||
|
|
||||||
|
|
||||||
|
### Appendices
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Allow `+` in Matrix IDs, as per [MSC4009](https://github.com/matrix-org/matrix-spec-proposals/pull/4009). ([#1583](https://github.com/matrix-org/matrix-spec/issues/1583))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Clarify spec re canonical JSON to handle negative-zero; also, give an example of negative-zero and a large power of ten. ([#1573](https://github.com/matrix-org/matrix-spec/issues/1573))
|
||||||
|
|
||||||
|
|
||||||
|
### Internal Changes/Tooling
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Upgrade Swagger data to OpenAPI 3.1. ([#1310](https://github.com/matrix-org/matrix-spec/issues/1310))
|
||||||
|
- Create `@matrix-org/spec` npm package to ship the SAS Emoji data definitions & translations. ([#1620](https://github.com/matrix-org/matrix-spec/issues/1620))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Update the CI to validate the file extension of changelog entries. ([#1542](https://github.com/matrix-org/matrix-spec/issues/1542))
|
||||||
|
- Disclosure sections now only display their title when collapsed. ([#1549](https://github.com/matrix-org/matrix-spec/issues/1549))
|
||||||
|
- Fix the sidebar in recent versions of Hugo. ([#1551](https://github.com/matrix-org/matrix-spec/issues/1551))
|
||||||
|
- Bump jsonschema to validate JSON Schemas against Draft 2020-12. ([#1556](https://github.com/matrix-org/matrix-spec/issues/1556))
|
||||||
|
- Use Redocly CLI to validate OpenAPI definitions. ([#1558](https://github.com/matrix-org/matrix-spec/issues/1558))
|
||||||
|
- Use tag name as the OpenAPI definition version. ([#1561](https://github.com/matrix-org/matrix-spec/issues/1561))
|
||||||
|
- Make sure version in `x-changedInMatrixVersion` is a string. ([#1562](https://github.com/matrix-org/matrix-spec/issues/1562))
|
||||||
|
- Clarify usage of ABNF for grammar in the documentation style guide. ([#1582](https://github.com/matrix-org/matrix-spec/issues/1582))
|
||||||
|
- Remove unnecessary `oneOf`s in JSON schemas. ([#1585](https://github.com/matrix-org/matrix-spec/issues/1585))
|
||||||
|
- Update the version of Hugo used to render the spec to v0.113.0. ([#1591](https://github.com/matrix-org/matrix-spec/issues/1591))
|
||||||
|
- Fix rendered changelog with new version of towncrier. ([#1598](https://github.com/matrix-org/matrix-spec/issues/1598))
|
||||||
|
- Improve the layout of tables on desktop displays. Contributed by Martin Fischer. ([#1601](https://github.com/matrix-org/matrix-spec/issues/1601))
|
||||||
93
content/changelog/v1.9.md
Normal file
93
content/changelog/v1.9.md
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
date: 2023-11-29T10:04:26-07:00
|
||||||
|
---
|
||||||
|
<!--
|
||||||
|
This is a header file for the generated changelog.
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
v1.9 = Replaced by the version number (eg: v1.2)
|
||||||
|
November 29, 2023 = Replaced by the date (eg: April 01, 2021)
|
||||||
|
-->
|
||||||
|
|
||||||
|
## v1.9
|
||||||
|
|
||||||
|
<table class="release-info">
|
||||||
|
<tr><th>Git commit</th><td><a href="https://github.com/matrix-org/matrix-spec/tree/v1.9">https://github.com/matrix-org/matrix-spec/tree/v1.9</a></td>
|
||||||
|
<tr><th>Release date</th><td>November 29, 2023</td>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Intentionally blank line to ensure headers work in the concatenated changelog -->
|
||||||
|
|
||||||
|
### Client-Server API
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Add the `m.rule.suppress_edits` default push rule, as per [MSC3958](https://github.com/matrix-org/matrix-spec-proposals/pull/3958). ([#1617](https://github.com/matrix-org/matrix-spec/issues/1617))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Fix `m.call.negotiate` schema and example. ([#1546](https://github.com/matrix-org/matrix-spec/issues/1546))
|
||||||
|
- Clarify that the `via` property is required for `m.space.parent` and `m.space.child` as per [MSC1772](https://github.com/matrix-org/matrix-spec-proposals/pull/1772). Contributed by @PaarthShah. ([#1618](https://github.com/matrix-org/matrix-spec/issues/1618))
|
||||||
|
- Add a note to the `/publicRooms` API that the server name is case sensitive. ([#1638](https://github.com/matrix-org/matrix-spec/issues/1638))
|
||||||
|
- Clarify that an `m.room.name` event with an absent `name` field is not expected behavior. ([#1639](https://github.com/matrix-org/matrix-spec/issues/1639))
|
||||||
|
- Fix schemas used for account data and presence events in `GET /initialSync`. ([#1647](https://github.com/matrix-org/matrix-spec/issues/1647))
|
||||||
|
- Fix various typos throughout the specification. ([#1658](https://github.com/matrix-org/matrix-spec/issues/1658), [#1661](https://github.com/matrix-org/matrix-spec/issues/1661), [#1665](https://github.com/matrix-org/matrix-spec/issues/1665))
|
||||||
|
- Fix `.m.rule.suppress_notices` push rule not being valid JSON. ([#1671](https://github.com/matrix-org/matrix-spec/issues/1671))
|
||||||
|
- Add missing properties for `event_property_is` and `event_property_contains` push conditions to `PushConditions` object. ([#1673](https://github.com/matrix-org/matrix-spec/issues/1673))
|
||||||
|
- Indicate that fallback keys should have a `fallback` property set to `true`. ([#1676](https://github.com/matrix-org/matrix-spec/issues/1676))
|
||||||
|
- Clarify that thread roots are not considered within the thread. ([#1677](https://github.com/matrix-org/matrix-spec/issues/1677))
|
||||||
|
|
||||||
|
|
||||||
|
### Server-Server API
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Fix schema of `m.receipt` EDU. ([#1636](https://github.com/matrix-org/matrix-spec/issues/1636))
|
||||||
|
- Fix various typos throughout the specification. ([#1661](https://github.com/matrix-org/matrix-spec/issues/1661))
|
||||||
|
- Clarify that federation requests for non-local users are invalid. ([#1672](https://github.com/matrix-org/matrix-spec/issues/1672))
|
||||||
|
|
||||||
|
|
||||||
|
### Application Service API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
### Identity Service API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
### Push Gateway API
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
### Room Versions
|
||||||
|
|
||||||
|
No significant changes.
|
||||||
|
|
||||||
|
|
||||||
|
### Appendices
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Clarify timestamp specification with respect to leap seconds. ([#1627](https://github.com/matrix-org/matrix-spec/issues/1627))
|
||||||
|
- Fix various typos throughout the specification. ([#1652](https://github.com/matrix-org/matrix-spec/issues/1652))
|
||||||
|
|
||||||
|
|
||||||
|
### Internal Changes/Tooling
|
||||||
|
|
||||||
|
**Backwards Compatible Changes**
|
||||||
|
|
||||||
|
- Add more CI checks for OpenAPI definitions and JSON Schemas. ([#1656](https://github.com/matrix-org/matrix-spec/issues/1656))
|
||||||
|
- Generate server-server OpenAPI definition. ([#1657](https://github.com/matrix-org/matrix-spec/issues/1657))
|
||||||
|
|
||||||
|
**Spec Clarifications**
|
||||||
|
|
||||||
|
- Replace all mentions of Swagger by OpenAPI. ([#1633](https://github.com/matrix-org/matrix-spec/issues/1633))
|
||||||
|
- Fix enum types in JSON schemas. ([#1634](https://github.com/matrix-org/matrix-spec/issues/1634))
|
||||||
|
- Fix schema of `m.mentions` object. ([#1635](https://github.com/matrix-org/matrix-spec/issues/1635))
|
||||||
|
- Fix rendering of `m.receipt` event in Client-Server API. ([#1637](https://github.com/matrix-org/matrix-spec/issues/1637))
|
||||||
|
- Remove required `fieldname` in appservice Protocol definition. ([#1646](https://github.com/matrix-org/matrix-spec/issues/1646))
|
||||||
|
- Fix github action workflow responsible for releasing of @matrix-org/spec package. ([#1648](https://github.com/matrix-org/matrix-spec/issues/1648))
|
||||||
|
- Upgrade GitHub actions. ([#1660](https://github.com/matrix-org/matrix-spec/issues/1660))
|
||||||
|
|
@ -77,6 +77,7 @@ algorithm is represented by an object with the following properties:
|
||||||
|------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| key | string | **Required.** The unpadded Base64-encoded 32-byte Curve25519 public key. |
|
| key | string | **Required.** The unpadded Base64-encoded 32-byte Curve25519 public key. |
|
||||||
| signatures | Signatures | **Required.** Signatures of the key object. The signature is calculated using the process described at [Signing JSON](/appendices/#signing-json). |
|
| signatures | Signatures | **Required.** Signatures of the key object. The signature is calculated using the process described at [Signing JSON](/appendices/#signing-json). |
|
||||||
|
| fallback | boolean | Indicates whether this is a [fallback key](#one-time-and-fallback-keys). Defaults to `false`. |
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -150,7 +151,9 @@ JSON](/appendices/#signing-json).
|
||||||
|
|
||||||
One-time and fallback keys are also uploaded to the homeserver using the
|
One-time and fallback keys are also uploaded to the homeserver using the
|
||||||
[`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) API. New
|
[`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) API. New
|
||||||
one-time and fallback keys are uploaded as needed.
|
one-time and fallback keys are uploaded as needed. Fallback keys for key
|
||||||
|
algorithms whose format is a signed JSON object should contain a property named
|
||||||
|
`fallback` with a value of `true`.
|
||||||
|
|
||||||
Devices must store the private part of each key they upload. They can
|
Devices must store the private part of each key they upload. They can
|
||||||
discard the private part of a one-time key when they receive a message
|
discard the private part of a one-time key when they receive a message
|
||||||
|
|
@ -657,10 +660,12 @@ The process between Alice and Bob verifying each other would be:
|
||||||
11. Alice's device receives Bob's message and verifies the commitment
|
11. Alice's device receives Bob's message and verifies the commitment
|
||||||
hash from earlier matches the hash of the key Bob's device just sent
|
hash from earlier matches the hash of the key Bob's device just sent
|
||||||
and the content of Alice's `m.key.verification.start` message.
|
and the content of Alice's `m.key.verification.start` message.
|
||||||
12. Both Alice and Bob's devices perform an Elliptic-curve
|
12. Both Alice's and Bob's devices perform an Elliptic-curve Diffie-Hellman using
|
||||||
Diffie-Hellman
|
their private ephemeral key, and the other device's ephemeral public key
|
||||||
(*ECDH(K<sub>A</sub><sup>private</sup>*, *K<sub>B</sub><sup>public</sup>*)),
|
(*ECDH(K<sub>A</sub><sup>private</sup>*, *K<sub>B</sub><sup>public</sup>*)
|
||||||
using the result as the shared secret.
|
for Alice's device and
|
||||||
|
*ECDH(K<sub>B</sub><sup>private</sup>*, *K<sub>A</sub><sup>public</sup>*)
|
||||||
|
for Bob's device), using the result as the shared secret.
|
||||||
13. Both Alice and Bob's devices display a SAS to their users, which is
|
13. Both Alice and Bob's devices display a SAS to their users, which is
|
||||||
derived from the shared key using one of the methods in this
|
derived from the shared key using one of the methods in this
|
||||||
section. If multiple SAS methods are available, clients should allow
|
section. If multiple SAS methods are available, clients should allow
|
||||||
|
|
@ -833,15 +838,15 @@ is the concatenation of:
|
||||||
- The Device ID of the device which sent the
|
- The Device ID of the device which sent the
|
||||||
`m.key.verification.start` message, followed by `|`.
|
`m.key.verification.start` message, followed by `|`.
|
||||||
- The public key from the `m.key.verification.key` message sent by
|
- The public key from the `m.key.verification.key` message sent by
|
||||||
the device which sent the `m.key.verification.start` message,
|
the device which sent the `m.key.verification.start` message, encoded as
|
||||||
followed by `|`.
|
unpadded base64, followed by `|`.
|
||||||
- The Matrix ID of the user who sent the `m.key.verification.accept`
|
- The Matrix ID of the user who sent the `m.key.verification.accept`
|
||||||
message, followed by `|`.
|
message, followed by `|`.
|
||||||
- The Device ID of the device which sent the
|
- The Device ID of the device which sent the
|
||||||
`m.key.verification.accept` message, followed by `|`.
|
`m.key.verification.accept` message, followed by `|`.
|
||||||
- The public key from the `m.key.verification.key` message sent by
|
- The public key from the `m.key.verification.key` message sent by
|
||||||
the device which sent the `m.key.verification.accept` message,
|
the device which sent the `m.key.verification.accept` message, encoded as
|
||||||
followed by `|`.
|
unpadded base64, followed by `|`.
|
||||||
- The `transaction_id` being used.
|
- The `transaction_id` being used.
|
||||||
|
|
||||||
When the `key_agreement_protocol` is the deprecated method `curve25519`,
|
When the `key_agreement_protocol` is the deprecated method `curve25519`,
|
||||||
|
|
@ -1361,10 +1366,18 @@ The `session_data` field in the backups is constructed as follows:
|
||||||
PKCS\#7 padding. This encrypted data, encoded using unpadded base64,
|
PKCS\#7 padding. This encrypted data, encoded using unpadded base64,
|
||||||
becomes the `ciphertext` property of the `session_data`.
|
becomes the `ciphertext` property of the `session_data`.
|
||||||
|
|
||||||
5. Pass the raw encrypted data (prior to base64 encoding) through
|
5. Pass an empty string through HMAC-SHA-256 using the MAC key generated above.
|
||||||
HMAC-SHA-256 using the MAC key generated above. The first 8 bytes of
|
The first 8 bytes of the resulting MAC are base64-encoded, and become the
|
||||||
the resulting MAC are base64-encoded, and become the `mac` property
|
`mac` property of the `session_data`.
|
||||||
of the `session_data`.
|
|
||||||
|
{{% boxes/warning %}}
|
||||||
|
Step 5 was intended to pass the raw encrypted data, but due to a bug in libolm,
|
||||||
|
all implementations have since passed an empty string instead.
|
||||||
|
|
||||||
|
Future versions of the spec will fix this problem. See
|
||||||
|
[MSC4048](https://github.com/matrix-org/matrix-spec-proposals/pull/4048) for a
|
||||||
|
potential new key backup algorithm version that would fix this issue.
|
||||||
|
{{% /boxes/warning %}}
|
||||||
|
|
||||||
{{% definition path="api/client-server/definitions/key_backup_session_data" %}}
|
{{% definition path="api/client-server/definitions/key_backup_session_data" %}}
|
||||||
|
|
||||||
|
|
@ -1765,9 +1778,9 @@ Example response:
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"device_one_time_keys_count": {
|
"device_one_time_keys_count": {
|
||||||
"curve25519": 10,
|
|
||||||
"signed_curve25519": 20
|
"signed_curve25519": 20
|
||||||
}
|
},
|
||||||
|
"device_unused_fallback_key_types": ["signed_curve25519"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ event with the corresponding emoji (👍). Another potential usage is to allow
|
||||||
bots to send an event indicating the success or failure of a command.
|
bots to send an event indicating the success or failure of a command.
|
||||||
|
|
||||||
Along with the normal properties `event_id` and `rel_type`, an `m.relates_to`
|
Along with the normal properties `event_id` and `rel_type`, an `m.relates_to`
|
||||||
property with `rel_type: m.annotion` should contain a `key` that indicates the
|
property with `rel_type: m.annotation` should contain a `key` that indicates the
|
||||||
annotation being applied. For example, when reacting with emojis, the key
|
annotation being applied. For example, when reacting with emojis, the key
|
||||||
contains the emoji being used.
|
contains the emoji being used.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,25 @@ instead.
|
||||||
|
|
||||||
Some message types support HTML in the event content that clients should
|
Some message types support HTML in the event content that clients should
|
||||||
prefer to display if available. Currently `m.text`, `m.emote`, `m.notice`,
|
prefer to display if available. Currently `m.text`, `m.emote`, `m.notice`,
|
||||||
and `m.key.verification.request` support an additional `format` parameter of
|
`m.image`, `m.file`, `m.audio`, `m.video` and `m.key.verification.request`
|
||||||
`org.matrix.custom.html`. When this field is present, a `formatted_body`
|
support an additional `format` parameter of `org.matrix.custom.html`. When this
|
||||||
with the HTML must be provided. The plain text version of the HTML
|
field is present, a `formatted_body` with the HTML must be provided. The plain
|
||||||
should be provided in the `body`.
|
text version of the HTML should be provided in the `body`.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{% changed-in v="1.10" %}}
|
||||||
|
In previous versions of the specification, the `format` and `formatted` fields
|
||||||
|
were limited to `m.text`, `m.emote`, `m.notice`, and
|
||||||
|
`m.key.verification.request`. This list is expanded to include `m.image`,
|
||||||
|
`m.file`, `m.audio` and `m.video` for [media captions](#media-captions).
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
Clients should limit the HTML they render to avoid Cross-Site Scripting,
|
Clients should limit the HTML they render to avoid Cross-Site Scripting,
|
||||||
HTML injection, and similar attacks. The strongly suggested set of HTML
|
HTML injection, and similar attacks. The strongly suggested set of HTML
|
||||||
tags to permit, denying the use and rendering of anything else, is:
|
tags to permit, denying the use and rendering of anything else, is:
|
||||||
`font`, `del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`,
|
`font`, `del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`,
|
||||||
`a`, `ul`, `ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`,
|
`a`, `ul`, `ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`,
|
||||||
`strike`, `code`, `hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`,
|
`s`, `code`, `hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`,
|
||||||
`th`, `td`, `caption`, `pre`, `span`, `img`, `details`, `summary`.
|
`th`, `td`, `caption`, `pre`, `span`, `img`, `details`, `summary`.
|
||||||
|
|
||||||
Not all attributes on those tags should be permitted as they may be
|
Not all attributes on those tags should be permitted as they may be
|
||||||
|
|
@ -320,6 +328,49 @@ to the media repository, then reference the `mxc://` URI in a markdown-style lin
|
||||||
Clients SHOULD render spoilers differently with some sort of disclosure. For example, the
|
Clients SHOULD render spoilers differently with some sort of disclosure. For example, the
|
||||||
client could blur the actual text and ask the user to click on it for it to be revealed.
|
client could blur the actual text and ask the user to click on it for it to be revealed.
|
||||||
|
|
||||||
|
##### Media captions
|
||||||
|
|
||||||
|
{{% added-in v="1.10" %}}
|
||||||
|
|
||||||
|
Media messages, comprised of `m.image`, `m.file`, `m.audio` and `m.video`, can
|
||||||
|
include a caption to convey additional information about the media.
|
||||||
|
|
||||||
|
To send captions, clients MUST use the `filename` and the `body`, and optionally
|
||||||
|
the `formatted_body` with the `org.matrix.custom.html` format, described above.
|
||||||
|
|
||||||
|
If the `filename` is present, and its value is different than `body`, then
|
||||||
|
`body` is considered to be a caption, otherwise `body` is a filename. `format`
|
||||||
|
and `formatted_body` are only used for captions.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
In previous versions of the specification, `body` was usually used to set the
|
||||||
|
filename of the uploaded file, and `filename` was only present on `m.file` with
|
||||||
|
the same purpose.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
An example of a media message with a caption is:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msgtype": "m.image",
|
||||||
|
"url": "mxc://example.org/abc123",
|
||||||
|
"filename": "dog.jpg",
|
||||||
|
"body": "this is a ~~cat~~ picture :3",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "this is a <s>cat</s> picture :3",
|
||||||
|
"info": {
|
||||||
|
"w": 479,
|
||||||
|
"h": 640,
|
||||||
|
"mimetype": "image/jpeg",
|
||||||
|
"size": 27253
|
||||||
|
},
|
||||||
|
"m.mentions": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients MUST render the caption alongside the media and SHOULD prefer its
|
||||||
|
formatted representation.
|
||||||
|
|
||||||
#### Server behaviour
|
#### Server behaviour
|
||||||
|
|
||||||
Homeservers SHOULD reject `m.room.message` events which don't have a
|
Homeservers SHOULD reject `m.room.message` events which don't have a
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,20 @@ the event to reference the entity being mentioned.
|
||||||
|
|
||||||
{{% definition path="api/client-server/definitions/m.mentions" %}}
|
{{% definition path="api/client-server/definitions/m.mentions" %}}
|
||||||
|
|
||||||
|
An event's content will then look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"body": "Hello Alice!",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "Hello <a href='https://matrix.to/#/@alice:example.org'>Alice</a>!",
|
||||||
|
"m.mentions": {
|
||||||
|
"user_ids": ["@alice:example.org"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Additionally, see the [`.m.rule.is_user_mention`](#_m_rule_is_user_mention) and
|
Additionally, see the [`.m.rule.is_user_mention`](#_m_rule_is_user_mention) and
|
||||||
[`.m.rule.is_room_mention`](#_m_rule_is_room_mention) push rules.
|
[`.m.rule.is_room_mention`](#_m_rule_is_room_mention) push rules.
|
||||||
Users should not add their own Matrix ID to the `m.mentions` property as outgoing
|
Users should not add their own Matrix ID to the `m.mentions` property as outgoing
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ Definition:
|
||||||
{
|
{
|
||||||
"kind": "event_match",
|
"kind": "event_match",
|
||||||
"key": "content.msgtype",
|
"key": "content.msgtype",
|
||||||
"pattern": "m.notice",
|
"pattern": "m.notice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": []
|
"actions": []
|
||||||
|
|
@ -750,6 +750,30 @@ Definition:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**`.m.rule.suppress_edits`**
|
||||||
|
|
||||||
|
{{% added-in v="1.9" %}}
|
||||||
|
|
||||||
|
Suppresses notifications related to [event replacements](#event-replacements).
|
||||||
|
|
||||||
|
Definition:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rule_id": ".m.rule.suppress_edits",
|
||||||
|
"default": true,
|
||||||
|
"enabled": true,
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"kind": "event_property_is",
|
||||||
|
"key": "content.m\\.relates_to.rel_type",
|
||||||
|
"value": "m.replace"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actions": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
##### Default Content Rules
|
##### Default Content Rules
|
||||||
|
|
||||||
<a id="_m_rule_contains_user_name"/> **`.m.rule.contains_user_name`**
|
<a id="_m_rule_contains_user_name"/> **`.m.rule.contains_user_name`**
|
||||||
|
|
@ -1046,16 +1070,16 @@ ahead), however if the `m.read.private` receipt were to be updated to
|
||||||
event D then the user has read up to D (the `m.read` receipt is now
|
event D then the user has read up to D (the `m.read` receipt is now
|
||||||
behind the `m.read.private` receipt).
|
behind the `m.read.private` receipt).
|
||||||
|
|
||||||
{{< added-in v="1.4" >}} When handling threaded read receipts, the server
|
{{< added-in v="1.4" >}} When handling threaded read receipts, the server is to
|
||||||
is to partition the notification count to each thread (with the main timeline
|
partition the notification count to each thread (with the main timeline being
|
||||||
being its own thread). To determine if an event is part of a thread the
|
its own thread). To determine if an event is part of a thread the server follows
|
||||||
server follows the [event relationship](#forming-relationships-between-events)
|
the [event relationship](#forming-relationships-between-events) until it finds a
|
||||||
until it finds a thread root (as specified by the [threading module](#threading)),
|
thread root via an `m.thread` relation (as specified by the [threading
|
||||||
however it is not recommended that the server traverse infinitely. Instead,
|
module](#threading)), however it is not recommended that the server traverse
|
||||||
implementations are encouraged to do a maximum of 3 hops to find a thread
|
infinitely. Instead, implementations are encouraged to do a maximum of 3 hops to
|
||||||
before deciding that the event does not belong to a thread. This is primarily
|
find a thread before deciding that the event does not belong to a thread. This
|
||||||
to ensure that future events, like `m.reaction`, are correctly considered
|
is primarily to ensure that future events, like `m.reaction`, are correctly
|
||||||
"part of" a given thread.
|
considered "part of" a given thread.
|
||||||
|
|
||||||
#### Server behaviour
|
#### Server behaviour
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,16 +137,20 @@ either a thread root's event ID or `main` for the main timeline.
|
||||||
|
|
||||||
Threading introduces a concept of multiple conversations being held in the same
|
Threading introduces a concept of multiple conversations being held in the same
|
||||||
room and thus deserve their own read receipts and notification counts. An event is
|
room and thus deserve their own read receipts and notification counts. An event is
|
||||||
considered to be "in a thread" if it meets any of the following criteria:
|
considered to be "in a thread" if:
|
||||||
* It has a `rel_type` of `m.thread`.
|
|
||||||
* It has child events with a `rel_type` of `m.thread` (in which case it'd be the
|
|
||||||
thread root).
|
|
||||||
* Following the event relationships, it has a parent event which qualifies for
|
|
||||||
one of the above. Implementations should not recurse infinitely, though: a
|
|
||||||
maximum of 3 hops is recommended to cover indirect relationships.
|
|
||||||
|
|
||||||
Events not in a thread but still in the room are considered to be part of the
|
* It has a `rel_type` of `m.thread`, or
|
||||||
"main timeline", or a special thread with an ID of `main`.
|
* Following the event relationships, it has a parent event which references
|
||||||
|
the thread root with a `rel_type` of `m.thread`. Implementations should
|
||||||
|
not recurse infinitely, though: a maximum of 3 hops is recommended to
|
||||||
|
cover indirect relationships.
|
||||||
|
|
||||||
|
Events not in a thread but still in the room are considered to be in the "main
|
||||||
|
timeline". When referring to the main timeline as a thread (e.g. in receipts
|
||||||
|
and notifications counts) a special thread ID of `main` is used.
|
||||||
|
|
||||||
|
Thread roots are considered to be in the main timeline, as are events that are
|
||||||
|
related to a thread root via non-thread relations.
|
||||||
|
|
||||||
The following is an example DAG for a room, with dotted lines showing event
|
The following is an example DAG for a room, with dotted lines showing event
|
||||||
relationships and solid lines showing topological ordering.
|
relationships and solid lines showing topological ordering.
|
||||||
|
|
@ -204,7 +208,7 @@ event when the user expands that thread.
|
||||||
|
|
||||||
#### Server behaviour
|
#### Server behaviour
|
||||||
|
|
||||||
For efficiency, receipts SHOULD be batched into one event per room
|
For efficiency, receipts SHOULD be batched into one event per room and thread
|
||||||
before delivering them to clients.
|
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
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,7 @@ Servers are free to handle the reported content however they desire.
|
||||||
This may be a dedicated room to alert server administrators to the
|
This may be a dedicated room to alert server administrators to the
|
||||||
reported content or some other mechanism for notifying the appropriate
|
reported content or some other mechanism for notifying the appropriate
|
||||||
people.
|
people.
|
||||||
|
|
||||||
|
{{< changed-in v="1.8" >}} The server MUST verify that the user
|
||||||
|
reporting the event is currently joined to the room the event is
|
||||||
|
in before accepting a report.
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ specific fallback text is different for each `msgtype`, however the
|
||||||
general format for the `body` is:
|
general format for the `body` is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
> <@alice:example.org> This is the original body
|
> <@alice:example.org> This is the first line of the original body
|
||||||
|
> This is the second line
|
||||||
|
|
||||||
This is where the reply goes
|
This is where the reply goes
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,70 @@ default key.
|
||||||
|------------|-----------|------------------------------------------|
|
|------------|-----------|------------------------------------------|
|
||||||
| key | string | **Required.** The ID of the default key. |
|
| key | string | **Required.** The ID of the default key. |
|
||||||
|
|
||||||
|
|
||||||
|
###### `m.secret_storage.v1.aes-hmac-sha2`
|
||||||
|
|
||||||
|
For the purposes of allowing clients to check whether a user has correctly
|
||||||
|
entered the key, keys for use with the `m.secret_storage.v1.aes-hmac-sha2`
|
||||||
|
algorithm are stored with some additional data.
|
||||||
|
|
||||||
|
When storing a key, clients SHOULD:
|
||||||
|
|
||||||
|
1. Given the secret storage key, generate 64 bytes by performing an
|
||||||
|
HKDF with SHA-256 as the hash, a salt of 32 bytes of 0, and the empty
|
||||||
|
string as the info. The first 32 bytes are used as the AES key,
|
||||||
|
and the next 32 bytes are used as the MAC key.
|
||||||
|
|
||||||
|
2. Generate 16 random bytes, set bit 63 to 0 (in order to work around
|
||||||
|
differences in AES-CTR implementations), and use this as the AES
|
||||||
|
initialization vector (IV).
|
||||||
|
|
||||||
|
3. Encrypt a message consisting of 32 bytes of 0, using AES-CTR-256 using the
|
||||||
|
AES key and IV generated above.
|
||||||
|
|
||||||
|
4. Pass the raw encrypted data through HMAC-SHA-256 using the MAC key
|
||||||
|
generated above.
|
||||||
|
|
||||||
|
5. Encode the IV from step 2, and the MAC from step 4, using [unpadded
|
||||||
|
base64](/appendices/#unpadded-base64), and store the results in the `iv`
|
||||||
|
and `mac` properties respectively in the `m.secret_storage.key.[key ID]`
|
||||||
|
account-data. (The ciphertext from step 3 is discarded after passing
|
||||||
|
through the MAC calculation.)
|
||||||
|
|
||||||
|
This process can be repeated by a client checking if the key is correct: the
|
||||||
|
MAC should match if the key is correct. Note, however, that these properties
|
||||||
|
are **optional**. If they are not present, clients must assume that the key is
|
||||||
|
valid.
|
||||||
|
|
||||||
|
Note also, that although clients SHOULD use unpadded base64 as specified above,
|
||||||
|
some existing implementations use standard [RFC4648-compliant
|
||||||
|
base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4) with padding,
|
||||||
|
so clients must accept either encoding.
|
||||||
|
|
||||||
|
The structure of a `m.secret_storage.key.[key ID]` account data object for use
|
||||||
|
with this algorithm is therefore as follows:
|
||||||
|
|
||||||
|
`AesHmacSha2KeyDescription`
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|-------------|--------|------------------------------------------------------------------------------------------------------|
|
||||||
|
| name | string | Optional. The name of the key. |
|
||||||
|
| algorithm | string | **Required.** The encryption algorithm to be used for this key: `m.secret_storage.v1.aes-hmac-sha2`. |
|
||||||
|
| passphrase | object | See [deriving keys from passphrases](#deriving-keys-from-passphrases) section for a description of this property. |
|
||||||
|
| iv | string | Optional. The 16-byte initialization vector for the validation check, encoded as base64. |
|
||||||
|
| mac | string | Optional. The MAC of the result of encrypting 32 bytes of 0, encoded as base64. |
|
||||||
|
|
||||||
|
For example, it could look like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "m.default",
|
||||||
|
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
||||||
|
"iv": "random+data",
|
||||||
|
"mac": "mac+of+encrypted+zeros"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
##### Secret storage
|
##### Secret storage
|
||||||
|
|
||||||
Encrypted data is stored in the user's account data using the event
|
Encrypted data is stored in the user's account data using the event
|
||||||
|
|
@ -82,7 +146,7 @@ of the data.
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
|-----------|------------------|-------------|
|
|-----------|------------------|-------------|
|
||||||
| encrypted | {string: object} | **Required.** Map from key ID the encrypted data. The exact format for the encrypted data is dependent on the key algorithm. See the definition of `AesHmacSha2EncryptedData` in the [m.secret_storage.v1.aes-hmac-sha2](#msecret_storagev1aes-hmac-sha2) section. |
|
| encrypted | {string: object} | **Required.** Map from key ID the encrypted data. The exact format for the encrypted data is dependent on the key algorithm. See the definition of `AesHmacSha2EncryptedData` in the [m.secret_storage.v1.aes-hmac-sha2](#msecret_storagev1aes-hmac-sha2-1) section. |
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
@ -147,58 +211,41 @@ HMAC-SHA-256. The secret is encrypted as follows:
|
||||||
1. Given the secret storage key, generate 64 bytes by performing an
|
1. Given the secret storage key, generate 64 bytes by performing an
|
||||||
HKDF with SHA-256 as the hash, a salt of 32 bytes of 0, and with the
|
HKDF with SHA-256 as the hash, a salt of 32 bytes of 0, and with the
|
||||||
secret name as the info. The first 32 bytes are used as the AES key,
|
secret name as the info. The first 32 bytes are used as the AES key,
|
||||||
and the next 32 bytes are used as the MAC key
|
and the next 32 bytes are used as the MAC key.
|
||||||
|
|
||||||
2. Generate 16 random bytes, set bit 63 to 0 (in order to work around
|
2. Generate 16 random bytes, set bit 63 to 0 (in order to work around
|
||||||
differences in AES-CTR implementations), and use this as the AES
|
differences in AES-CTR implementations), and use this as the AES
|
||||||
initialization vector. This becomes the `iv` property, encoded using
|
initialization vector (IV).
|
||||||
base64.
|
|
||||||
3. Encrypt the data using AES-CTR-256 using the AES key generated
|
3. Encrypt the data using AES-CTR-256 using the AES key and IV generated
|
||||||
above. This encrypted data, encoded using base64, becomes the
|
above.
|
||||||
`ciphertext` property.
|
|
||||||
4. Pass the raw encrypted data (prior to base64 encoding) through
|
4. Pass the raw encrypted data through HMAC-SHA-256 using the MAC key
|
||||||
HMAC-SHA-256 using the MAC key generated above. The resulting MAC is
|
generated above.
|
||||||
base64-encoded and becomes the `mac` property.
|
|
||||||
|
5. Encode the IV from step 2, the ciphertext from step 3, and MAC from step 4,
|
||||||
|
using [unpadded base64](/appendices/#unpadded-base64), and store them as
|
||||||
|
the `iv`, `ciphertext`, and `mac` properties respectively in the account
|
||||||
|
data object.
|
||||||
|
|
||||||
|
**Note**: some existing implementations encode these properties using
|
||||||
|
standard [RFC4648-compliant
|
||||||
|
base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4) with
|
||||||
|
padding, so clients must accept either encoding.
|
||||||
|
|
||||||
|
The structure of the `encrypted` property of an account data object encrypted
|
||||||
|
with this algorithm is therefore as follows:
|
||||||
|
|
||||||
`AesHmacSha2EncryptedData`
|
`AesHmacSha2EncryptedData`
|
||||||
|
|
||||||
| Parameter | Type | Description
|
| Parameter | Type | Description
|
||||||
|------------|---------|------------------------------------------------------------------------|
|
|------------|---------|------------------------------------------------------------------------|
|
||||||
| iv | string | **Required.** The 16-byte initialization vector, encoded as base64. |
|
| iv | string | **Required.** The 16-byte initialization vector, encoded as base64. |
|
||||||
| ciphertext | string | **Required.** The AES-CTR-encrypted data, encoded as base64. |
|
| ciphertext | string | **Required.** The AES-CTR-encrypted data, encoded as base64. |
|
||||||
| mac | string | **Required.** The MAC, encoded as base64. |
|
| mac | string | **Required.** The MAC, encoded as base64. |
|
||||||
|
|
||||||
For the purposes of allowing clients to check whether a user has
|
|
||||||
correctly entered the key, clients should:
|
|
||||||
|
|
||||||
1. encrypt and MAC a message consisting of 32 bytes of 0 as described
|
For example, data encrypted using this algorithm could look like this:
|
||||||
above, using the empty string as the info parameter to the HKDF in
|
|
||||||
step 1.
|
|
||||||
2. store the `iv` and `mac` in the `m.secret_storage.key.[key ID]`
|
|
||||||
account-data.
|
|
||||||
|
|
||||||
`AesHmacSha2KeyDescription`
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
|
||||||
|-------------|--------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| name | string | Optional. The name of the key. |
|
|
||||||
| algorithm | string | **Required.** The encryption algorithm to be used for this key. Currently, only `m.secret_storage.v1.aes-hmac-sha2` is supported. |
|
|
||||||
| passphrase | object | See [deriving keys from passphrases](#deriving-keys-from-passphrases) section for a description of this property. |
|
|
||||||
| iv | string | The 16-byte initialization vector, encoded as base64. |
|
|
||||||
| mac | string | The MAC of the result of encrypting 32 bytes of 0, encoded as base64. |
|
|
||||||
|
|
||||||
For example, the `m.secret_storage.key.key_id` for a key using this
|
|
||||||
algorithm could look like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "m.default",
|
|
||||||
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
|
|
||||||
"iv": "random+data",
|
|
||||||
"mac": "mac+of+encrypted+zeros"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
and data encrypted using this algorithm could look like this:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -212,7 +259,7 @@ and data encrypted using this algorithm could look like this:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
###### Key representation
|
##### Key representation
|
||||||
|
|
||||||
When a user is given a raw key for `m.secret_storage.v1.aes-hmac-sha2`,
|
When a user is given a raw key for `m.secret_storage.v1.aes-hmac-sha2`,
|
||||||
it will be presented as a string constructed as follows:
|
it will be presented as a string constructed as follows:
|
||||||
|
|
@ -232,7 +279,7 @@ it will be presented as a string constructed as follows:
|
||||||
When decoding a raw key, the process should be reversed, with the
|
When decoding a raw key, the process should be reversed, with the
|
||||||
exception that whitespace is insignificant in the user's input.
|
exception that whitespace is insignificant in the user's input.
|
||||||
|
|
||||||
###### Deriving keys from passphrases
|
##### Deriving keys from passphrases
|
||||||
|
|
||||||
A user may wish to use a chosen passphrase rather than a randomly
|
A user may wish to use a chosen passphrase rather than a randomly
|
||||||
generated key. In this case, information on how to generate the key from
|
generated key. In this case, information on how to generate the key from
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ as by providing some context to what is going on in the thread but keeping the f
|
||||||
history behind a disclosure.
|
history behind a disclosure.
|
||||||
|
|
||||||
Threads are established using a `rel_type` of `m.thread` and reference the
|
Threads are established using a `rel_type` of `m.thread` and reference the
|
||||||
*thread root* (the first event in a thread). It is not possible to create a
|
*thread root* (the main timeline event to which the thread events refer). It is not possible to create a thread from an event which itself
|
||||||
thread from an event which itself is the child of an event relationship (i.e.,
|
is the child of an event relationship (i.e., one with an `m.relates_to`
|
||||||
one with an `m.relates_to` property). It is therefore also not possible to nest
|
property with a `rel_type` property - see [Relationship types](#relationship-types)).
|
||||||
threads. All events in a thread reference the thread root instead of the
|
It is therefore also not possible to nest threads.
|
||||||
most recent message, unlike rich reply chains.
|
|
||||||
|
Unlike rich reply chains, all events in a thread reference the thread root
|
||||||
|
instead of the most recent message.
|
||||||
|
|
||||||
As a worked example, the following represents a thread and how it would be formed:
|
As a worked example, the following represents a thread and how it would be formed:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ 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 |
|
| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|
||||||
|-------------------|---|---|---|---|---|---|---|---|---|----|
|
|-------------------|---|---|---|---|---|---|---|---|---|----|----|
|
||||||
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ |
|
| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
|
||||||
| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
|
| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ |
|
||||||
| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |
|
| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ |
|
||||||
|
|
||||||
## Complete list of room versions
|
## Complete list of room versions
|
||||||
|
|
||||||
|
|
@ -57,8 +57,7 @@ the default room version when creating new rooms.
|
||||||
|
|
||||||
The available room versions are:
|
The available room versions are:
|
||||||
|
|
||||||
- [Version 1](/rooms/v1) - **Stable**. The current version of most
|
- [Version 1](/rooms/v1) - **Stable**. The initial room version.
|
||||||
rooms.
|
|
||||||
- [Version 2](/rooms/v2) - **Stable**. Implements State Resolution
|
- [Version 2](/rooms/v2) - **Stable**. Implements State Resolution
|
||||||
Version 2.
|
Version 2.
|
||||||
- [Version 3](/rooms/v3) - **Stable**. Introduces events whose IDs
|
- [Version 3](/rooms/v3) - **Stable**. Introduces events whose IDs
|
||||||
|
|
@ -76,6 +75,7 @@ The available room versions are:
|
||||||
redacting some membership events.
|
redacting some membership events.
|
||||||
- [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.
|
||||||
|
|
||||||
## Room version grammar
|
## Room version grammar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,14 @@ not in the following list:
|
||||||
- `membership`
|
- `membership`
|
||||||
|
|
||||||
The content object must also be stripped of all keys, unless it is one
|
The content object must also be stripped of all keys, unless it is one
|
||||||
of one of the following event types:
|
of the following event types:
|
||||||
|
|
||||||
- `m.room.member` allows key `membership`.
|
- [`m.room.member`](/client-server-api#mroommember) allows key `membership`.
|
||||||
- `m.room.create` allows key `creator`.
|
- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`.
|
||||||
- `m.room.join_rules` allows key `join_rule`.
|
- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows key `join_rule`.
|
||||||
- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
|
- [`m.room.power_levels`](/client-server-api#mroompower_levels) allows keys
|
||||||
`kick`, `redact`, `state_default`, `users`, `users_default`.
|
`ban`, `events`, `events_default`, `kick`, `redact`, `state_default`, `users`,
|
||||||
- `m.room.aliases` allows key `aliases`.
|
`users_default`.
|
||||||
- `m.room.history_visibility` allows key `history_visibility`.
|
- [`m.room.aliases`](/client-server-api#historical-events) allows key `aliases`.
|
||||||
|
- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) allows
|
||||||
|
key `history_visibility`.
|
||||||
|
|
|
||||||
4
content/rooms/fragments/v11-event-format.md
Normal file
4
content/rooms/fragments/v11-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_v11" %}}
|
||||||
30
content/rooms/fragments/v11-redactions.md
Normal file
30
content/rooms/fragments/v11-redactions.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
Upon receipt of a redaction event, the server must strip off any keys
|
||||||
|
not in the following list:
|
||||||
|
|
||||||
|
- `event_id`
|
||||||
|
- `type`
|
||||||
|
- `room_id`
|
||||||
|
- `sender`
|
||||||
|
- `state_key`
|
||||||
|
- `content`
|
||||||
|
- `hashes`
|
||||||
|
- `signatures`
|
||||||
|
- `depth`
|
||||||
|
- `prev_events`
|
||||||
|
- `auth_events`
|
||||||
|
- `origin_server_ts`
|
||||||
|
|
||||||
|
The content object must also be stripped of all keys, unless it is one
|
||||||
|
of the following event types:
|
||||||
|
|
||||||
|
- [`m.room.member`](/client-server-api#mroommember) allows keys `membership`, `join_authorised_via_users_server`.
|
||||||
|
Additionally, it allows the `signed` key of the `third_party_invite` key.
|
||||||
|
- [`m.room.create`](/client-server-api#mroomcreate) allows all keys.
|
||||||
|
- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows keys `join_rule`, `allow`.
|
||||||
|
- [`m.room.power_levels`](/client-server-api#mroompower_levels) allows keys
|
||||||
|
`ban`, `events`, `events_default`, `invite`, `kick`, `redact`, `state_default`,
|
||||||
|
`users`, `users_default`.
|
||||||
|
- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility)
|
||||||
|
allows key `history_visibility`.
|
||||||
|
- [`m.room.redaction`](/client-server-api#mroomredaction) allows key `redacts`.
|
||||||
|
|
@ -19,11 +19,13 @@ not in the following list:
|
||||||
- `membership`
|
- `membership`
|
||||||
|
|
||||||
The content object must also be stripped of all keys, unless it is one
|
The content object must also be stripped of all keys, unless it is one
|
||||||
of one of the following event types:
|
of the following event types:
|
||||||
|
|
||||||
- `m.room.member` allows key `membership`.
|
- [`m.room.member`](/client-server-api#mroommember) allows key `membership`.
|
||||||
- `m.room.create` allows key `creator`.
|
- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`.
|
||||||
- `m.room.join_rules` allows key `join_rule`.
|
- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows key `join_rule`.
|
||||||
- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
|
- [`m.room.power_levels`](/client-server-api#mroompower_levels) allows keys
|
||||||
`kick`, `redact`, `state_default`, `users`, `users_default`.
|
`ban`, `events`, `events_default`, `kick`, `redact`, `state_default`, `users`,
|
||||||
- `m.room.history_visibility` allows key `history_visibility`.
|
`users_default`.
|
||||||
|
- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) allows
|
||||||
|
key `history_visibility`.
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ The rules are as follows:
|
||||||
7. If `membership` is `knock`:
|
7. If `membership` is `knock`:
|
||||||
1. If the `join_rule` is anything other than `knock`, reject.
|
1. If the `join_rule` is anything other than `knock`, reject.
|
||||||
2. If `sender` does not match `state_key`, reject.
|
2. If `sender` does not match `state_key`, reject.
|
||||||
3. If the `sender`'s current membership is not `ban` or `join`, allow.
|
3. If the `sender`'s current membership is not `ban`, `invite`,
|
||||||
|
or `join`, allow.
|
||||||
4. Otherwise, reject.
|
4. Otherwise, reject.
|
||||||
8. Otherwise, the membership is unknown. Reject.
|
8. Otherwise, the membership is unknown. Reject.
|
||||||
5. If the `sender`'s current membership state is not `join`, reject.
|
5. If the `sender`'s current membership state is not `join`, reject.
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,3 @@
|
||||||
---
|
|
||||||
---
|
|
||||||
|
|
||||||
{{% added-in this=true %}} `m.room.member` events now keep `join_authorised_via_users_server`
|
|
||||||
in addition to other keys in `content` when being redacted.
|
|
||||||
|
|
||||||
{{% boxes/rationale %}}
|
|
||||||
Without the `join_authorised_via_users_server` property, redacted join events
|
|
||||||
can become invalid when verifying the auth chain of a given event, thus creating
|
|
||||||
a split-brain scenario where the user is able to speak from one server's
|
|
||||||
perspective but most others will continually reject their events.
|
|
||||||
|
|
||||||
This can theoretically be worked around with a rejoin to the room, being careful
|
|
||||||
not to use the faulty events as `prev_events`, though instead it is encouraged
|
|
||||||
to use v9 rooms over v8 rooms to outright avoid the situation.
|
|
||||||
|
|
||||||
[Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373) has further
|
|
||||||
information.
|
|
||||||
{{% /boxes/rationale %}}
|
|
||||||
|
|
||||||
The full redaction algorithm follows.
|
|
||||||
|
|
||||||
Upon receipt of a redaction event, the server must strip off any keys
|
Upon receipt of a redaction event, the server must strip off any keys
|
||||||
not in the following list:
|
not in the following list:
|
||||||
|
|
@ -40,11 +19,15 @@ not in the following list:
|
||||||
- `membership`
|
- `membership`
|
||||||
|
|
||||||
The content object must also be stripped of all keys, unless it is one
|
The content object must also be stripped of all keys, unless it is one
|
||||||
of one of the following event types:
|
of the following event types:
|
||||||
|
|
||||||
- `m.room.member` allows keys `membership`, `join_authorised_via_users_server`.
|
- [`m.room.member`](/client-server-api#mroommember) allows keys `membership`,
|
||||||
- `m.room.create` allows key `creator`.
|
`join_authorised_via_users_server`.
|
||||||
- `m.room.join_rules` allows keys `join_rule`, `allow`.
|
- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`.
|
||||||
- `m.room.power_levels` allows keys `ban`, `events`, `events_default`,
|
- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows keys `join_rule`,
|
||||||
`kick`, `redact`, `state_default`, `users`, `users_default`.
|
`allow`.
|
||||||
- `m.room.history_visibility` allows key `history_visibility`.
|
- [`m.room.power_levels`](/client-server-api#mroompower_levels) allows keys
|
||||||
|
`ban`, `events`, `events_default`, `kick`, `redact`, `state_default`, `users`,
|
||||||
|
`users_default`.
|
||||||
|
- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility)
|
||||||
|
allows key `history_visibility`.
|
||||||
|
|
@ -194,7 +194,8 @@ The rules are as follows:
|
||||||
If the `join_rule` is anything other than `knock` or
|
If the `join_rule` is anything other than `knock` or
|
||||||
`knock_restricted`, reject.
|
`knock_restricted`, reject.
|
||||||
2. If `sender` does not match `state_key`, reject.
|
2. If `sender` does not match `state_key`, reject.
|
||||||
3. If the `sender`'s current membership is not `ban` or `join`, allow.
|
3. If the `sender`'s current membership is not `ban`, `invite`,
|
||||||
|
or `join`, allow.
|
||||||
4. Otherwise, reject.
|
4. Otherwise, reject.
|
||||||
8. Otherwise, the membership is unknown. Reject.
|
8. Otherwise, the membership is unknown. Reject.
|
||||||
5. If the `sender`'s current membership state is not `join`, reject.
|
5. If the `sender`'s current membership state is not `join`, reject.
|
||||||
|
|
|
||||||
285
content/rooms/v11.md
Normal file
285
content/rooms/v11.md
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
---
|
||||||
|
title: Room Version 11
|
||||||
|
type: docs
|
||||||
|
weight: 100
|
||||||
|
---
|
||||||
|
|
||||||
|
This room version builds on [version 10](/rooms/v10) while clarifying redaction
|
||||||
|
rules.
|
||||||
|
|
||||||
|
## Client considerations
|
||||||
|
|
||||||
|
### Redactions
|
||||||
|
|
||||||
|
{{< added-in this=true >}} The top-level `origin`, `membership`, and `prev_state` properties
|
||||||
|
are no longer protected from redaction. The [`m.room.create`](/client-server-api#mroomcreate)
|
||||||
|
event now keeps the entire `content` property. The [`m.room.redaction`](/client-server-api#mroomredaction)
|
||||||
|
event keeps the `redacts` property under `content`. The
|
||||||
|
[`m.room.power_levels`](/client-server-api#mroompower_levels) event keeps the
|
||||||
|
`invite` property under `content`.
|
||||||
|
|
||||||
|
The full redaction algorithm follows.
|
||||||
|
|
||||||
|
{{% rver-fragment name="v11-redactions" withVersioning="true" %}}
|
||||||
|
|
||||||
|
### Event format
|
||||||
|
|
||||||
|
Clients should no longer depend on the `creator` property in the `content` of
|
||||||
|
[`m.room.create`](/client-server-api#mroomcreate) events. In all room versions,
|
||||||
|
clients can rely on `sender` instead to determine a room creator.
|
||||||
|
|
||||||
|
The format of [`m.room.redaction`](/client-server-api#mroomredaction)
|
||||||
|
events has been modified. Client should look for the `redacts` key under `content`
|
||||||
|
instead of a top-level event property.
|
||||||
|
|
||||||
|
The `third_party_invite` key of [`m.room.member`](/client-server-api#mroommember)
|
||||||
|
events is no longer redacted, *but* will only contain the `signed` key after redaction.
|
||||||
|
|
||||||
|
## 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 %}}
|
||||||
|
|
||||||
|
This room version updates the redaction algorithm and modifies how servers should
|
||||||
|
create `m.room.create` and `m.room.redaction` events.
|
||||||
|
|
||||||
|
Room version 11 is based upon room version 10 with the following considerations.
|
||||||
|
|
||||||
|
### Redactions
|
||||||
|
|
||||||
|
[See above](#redactions).
|
||||||
|
|
||||||
|
### Event format
|
||||||
|
|
||||||
|
The core event format is the same as [room version 10](/rooms/v10#event-format).
|
||||||
|
However, this room version changes some properties of some event types.
|
||||||
|
|
||||||
|
{{% rver-fragment name="v11-event-format" %}}
|
||||||
|
|
||||||
|
#### Remove the `creator` property of `m.room.create` events
|
||||||
|
|
||||||
|
The `content` of a `m.room.create` event no longer has a `creator` property,
|
||||||
|
which previously was always equivalent to the `sender` of the event.
|
||||||
|
|
||||||
|
#### Moving the `redacts` property of `m.room.redaction` events to a `content` property
|
||||||
|
|
||||||
|
The `redacts` property of `m.room.redaction` events is moved from a top-level
|
||||||
|
event property to a property under the event `content`.
|
||||||
|
|
||||||
|
For backwards-compatibility with older clients, servers should add a `redacts` property
|
||||||
|
to the top level of `m.room.redaction` events in when serving such events over the
|
||||||
|
Client-Server API.
|
||||||
|
|
||||||
|
For improved compatibility with newer clients, servers should add a `redacts` property
|
||||||
|
to the `content` of `m.room.redaction` events in *older* room versions when serving
|
||||||
|
such events over the Client-Server API.
|
||||||
|
|
||||||
|
### Authorization rules
|
||||||
|
|
||||||
|
Events must be signed by the server denoted by the `sender` property.
|
||||||
|
|
||||||
|
`m.room.redaction` events are not explicitly part of the auth rules.
|
||||||
|
They are still subject to the minimum power level rules, but should always
|
||||||
|
fall into "10. Otherwise, allow". Instead of being authorized at the time
|
||||||
|
of receipt, they are authorized at a later stage: see the
|
||||||
|
[Redactions](#redactions) section below for more information.
|
||||||
|
|
||||||
|
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 %}}
|
||||||
|
|
||||||
|
The rules are as follows:
|
||||||
|
|
||||||
|
1. {{< changed-in this="true" >}}
|
||||||
|
If type is `m.room.create`:
|
||||||
|
1. If it has any `prev_events`, reject.
|
||||||
|
2. If the domain of the `room_id` does not match the domain of the
|
||||||
|
`sender`, reject.
|
||||||
|
3. If `content.room_version` is present and is not a recognised
|
||||||
|
version, reject.
|
||||||
|
4. Otherwise, allow.
|
||||||
|
2. Considering the event's `auth_events`:
|
||||||
|
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||||
|
reject.
|
||||||
|
2. 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.
|
||||||
|
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.
|
||||||
|
4. If there is no `m.room.create` event among the entries, reject.
|
||||||
|
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
|
||||||
|
does not match the `sender` domain of the create event, reject.
|
||||||
|
4. 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. {{< changed-in this="true" >}}
|
||||||
|
If the only previous event is an `m.room.create` and the
|
||||||
|
`state_key` is the sender, 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, 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.
|
||||||
|
5. If the `sender`'s current membership state is not `join`, reject.
|
||||||
|
6. 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*.
|
||||||
|
7. If the event type's *required power level* is greater than the
|
||||||
|
`sender`'s power level, reject.
|
||||||
|
8. If the event has a `state_key` that starts with an `@` and does not
|
||||||
|
match the `sender`, reject.
|
||||||
|
9. 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 obiect with keys that
|
||||||
|
are valid user IDs with values that are integers, reject.
|
||||||
|
4. If there is no previous `m.room.power_levels` event in the room,
|
||||||
|
allow.
|
||||||
|
5. 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.
|
||||||
|
6. 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.
|
||||||
|
7. 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.
|
||||||
|
8. 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.
|
||||||
|
9. 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.
|
||||||
|
10. 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 %}}
|
||||||
|
|
||||||
|
## Unchanged from v10
|
||||||
|
|
||||||
|
The following sections have not been modified since v10, but are included for
|
||||||
|
completeness.
|
||||||
|
|
||||||
|
### Handling redactions
|
||||||
|
|
||||||
|
{{% rver-fragment name="v3-handling-redactions" %}}
|
||||||
|
|
||||||
|
### Event IDs
|
||||||
|
|
||||||
|
{{% rver-fragment name="v4-event-ids" %}}
|
||||||
|
|
||||||
|
### State resolution
|
||||||
|
|
||||||
|
{{% rver-fragment name="v2-state-res" %}}
|
||||||
|
|
||||||
|
### Canonical JSON
|
||||||
|
|
||||||
|
{{% rver-fragment name="v6-canonical-json" %}}
|
||||||
|
|
||||||
|
### Signing key validity period
|
||||||
|
|
||||||
|
{{% rver-fragment name="v5-signing-requirements" %}}
|
||||||
|
|
@ -15,7 +15,7 @@ which implement the redaction algorithm locally should refer to the
|
||||||
|
|
||||||
### Redactions
|
### Redactions
|
||||||
|
|
||||||
{{% added-in this=true %}} All significant meaning for `m.room.aliases`
|
{{< added-in this=true >}} All significant meaning for `m.room.aliases`
|
||||||
has been removed from the redaction algorithm. The remaining rules are
|
has been removed from the redaction algorithm. The remaining rules are
|
||||||
the same as past room versions.
|
the same as past room versions.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,8 @@ The rules are as follows:
|
||||||
If `membership` is `knock`:
|
If `membership` is `knock`:
|
||||||
1. If the `join_rule` is anything other than `knock`, reject.
|
1. If the `join_rule` is anything other than `knock`, reject.
|
||||||
2. If `sender` does not match `state_key`, reject.
|
2. If `sender` does not match `state_key`, reject.
|
||||||
3. If the `sender`'s current membership is not `ban` or `join`, allow.
|
3. If the `sender`'s current membership is not `ban`, `invite`,
|
||||||
|
or `join`, allow.
|
||||||
4. Otherwise, reject.
|
4. Otherwise, reject.
|
||||||
7. Otherwise, the membership is unknown. Reject.
|
7. Otherwise, the membership is unknown. Reject.
|
||||||
5. If the `sender`'s current membership state is not `join`, reject.
|
5. If the `sender`'s current membership state is not `join`, reject.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,27 @@ Clients which implement the redaction algorithm locally should refer to the
|
||||||
|
|
||||||
### Redactions
|
### Redactions
|
||||||
|
|
||||||
|
{{< added-in this=true >}} [`m.room.member`](/client-server-api#mroommember) events
|
||||||
|
now keep `join_authorised_via_users_server` in addition to other keys in `content`
|
||||||
|
when being redacted.
|
||||||
|
|
||||||
|
{{% boxes/rationale %}}
|
||||||
|
Without the `join_authorised_via_users_server` property, redacted join events
|
||||||
|
can become invalid when verifying the auth chain of a given event, thus creating
|
||||||
|
a split-brain scenario where the user is able to speak from one server's
|
||||||
|
perspective but most others will continually reject their events.
|
||||||
|
|
||||||
|
This can theoretically be worked around with a rejoin to the room, being careful
|
||||||
|
not to use the faulty events as `prev_events`, though instead it is encouraged
|
||||||
|
to use v9 rooms over v8 rooms to outright avoid the situation.
|
||||||
|
|
||||||
|
[Issue #3373](https://github.com/matrix-org/matrix-doc/issues/3373) has further
|
||||||
|
information.
|
||||||
|
{{% /boxes/rationale %}}
|
||||||
|
|
||||||
|
The full redaction algorithm follows.
|
||||||
|
|
||||||
|
|
||||||
{{% rver-fragment name="v9-redactions" withVersioning="true" %}}
|
{{% rver-fragment name="v9-redactions" withVersioning="true" %}}
|
||||||
|
|
||||||
## Server implementation components
|
## Server implementation components
|
||||||
|
|
|
||||||
|
|
@ -135,43 +135,59 @@ to send. The process overall is as follows:
|
||||||
to step 4. If the response is valid, the `m.server` property is
|
to step 4. If the response is valid, the `m.server` property is
|
||||||
parsed as `<delegated_hostname>[:<delegated_port>]` and processed as
|
parsed as `<delegated_hostname>[:<delegated_port>]` and processed as
|
||||||
follows:
|
follows:
|
||||||
- If `<delegated_hostname>` is an IP literal, then that IP address
|
1. If `<delegated_hostname>` is an IP literal, then that IP address
|
||||||
should be used together with the `<delegated_port>` or 8448 if
|
should be used together with the `<delegated_port>` or 8448 if
|
||||||
no port is provided. The target server must present a valid TLS
|
no port is provided. The target server must present a valid TLS
|
||||||
certificate for the IP address. Requests must be made with a
|
certificate for the IP address. Requests must be made with a
|
||||||
`Host` header containing the IP address, including the port if
|
`Host` header containing the IP address, including the port if
|
||||||
one was provided.
|
one was provided.
|
||||||
- If `<delegated_hostname>` is not an IP literal, and
|
2. If `<delegated_hostname>` is not an IP literal, and
|
||||||
`<delegated_port>` is present, an IP address is discovered by
|
`<delegated_port>` is present, an IP address is discovered by
|
||||||
looking up CNAME, AAAA or A records for `<delegated_hostname>`. The
|
looking up CNAME, AAAA or A records for `<delegated_hostname>`. The
|
||||||
resulting IP address is used, alongside the `<delegated_port>`.
|
resulting IP address is used, alongside the `<delegated_port>`.
|
||||||
Requests must be made with a `Host` header of
|
Requests must be made with a `Host` header of
|
||||||
`<delegated_hostname>:<delegated_port>`. The target server must
|
`<delegated_hostname>:<delegated_port>`. The target server must
|
||||||
present a valid certificate for `<delegated_hostname>`.
|
present a valid certificate for `<delegated_hostname>`.
|
||||||
- If `<delegated_hostname>` is not an IP literal and no
|
3. {{< added-in v="1.8" >}} If `<delegated_hostname>` is not an IP literal and no
|
||||||
`<delegated_port>` is present, an SRV record is looked up for
|
`<delegated_port>` is present, an SRV record is looked up for
|
||||||
|
`_matrix-fed._tcp.<delegated_hostname>`. This may result in another
|
||||||
|
hostname (to be resolved using AAAA or A records) and port.
|
||||||
|
Requests should be made to the resolved IP address and port with
|
||||||
|
a `Host` header containing the `<delegated_hostname>`. The
|
||||||
|
target server must present a valid certificate for
|
||||||
|
`<delegated_hostname>`.
|
||||||
|
4. **[Deprecated]** If `<delegated_hostname>` is not an IP literal, no
|
||||||
|
`<delegated_port>` is present, and a `_matrix-fed._tcp.<delegated_hostname>`
|
||||||
|
SRV record was not found, an SRV record is looked up for
|
||||||
`_matrix._tcp.<delegated_hostname>`. This may result in another
|
`_matrix._tcp.<delegated_hostname>`. This may result in another
|
||||||
hostname (to be resolved using AAAA or A records) and port.
|
hostname (to be resolved using AAAA or A records) and port.
|
||||||
Requests should be made to the resolved IP address and port with
|
Requests should be made to the resolved IP address and port with
|
||||||
a `Host` header containing the `<delegated_hostname>`. The
|
a `Host` header containing the `<delegated_hostname>`. The
|
||||||
target server must present a valid certificate for
|
target server must present a valid certificate for
|
||||||
`<delegated_hostname>`.
|
`<delegated_hostname>`.
|
||||||
- If no SRV record is found, an IP address is resolved using CNAME, AAAA
|
5. If no SRV record is found, an IP address is resolved using CNAME, AAAA
|
||||||
or A records. Requests are then made to the resolve IP address
|
or A records. Requests are then made to the resolve IP address
|
||||||
and a port of 8448, using a `Host` header of
|
and a port of 8448, using a `Host` header of
|
||||||
`<delegated_hostname>`. The target server must present a valid
|
`<delegated_hostname>`. The target server must present a valid
|
||||||
certificate for `<delegated_hostname>`.
|
certificate for `<delegated_hostname>`.
|
||||||
|
|
||||||
4. If the `/.well-known` request resulted in an error response, a
|
4. {{< added-in v="1.8" >}} If the `/.well-known` request resulted in an error response, a server is
|
||||||
server is found by resolving an SRV record for
|
found by resolving an SRV record for `_matrix-fed._tcp.<hostname>`. This may
|
||||||
`_matrix._tcp.<hostname>`. This may result in a hostname (to be
|
result in a hostname (to be resolved using AAAA or A records) and
|
||||||
resolved using AAAA or A records) and port. Requests are made to the
|
port. Requests are made to the resolved IP address and port, with a `Host`
|
||||||
resolved IP address and port, using 8448 as a default port, with a
|
header of `<hostname>`. The target server must present a valid certificate
|
||||||
`Host` header of `<hostname>`. The target server must present a
|
for `<hostname>`.
|
||||||
valid certificate for `<hostname>`.
|
|
||||||
|
|
||||||
5. If the `/.well-known` request returned an error response, and the
|
5. **[Deprecated]** If the `/.well-known` request resulted in an error response,
|
||||||
SRV record was not found, an IP address is resolved using CNAME, AAAA and A
|
and a `_matrix-fed._tcp.<hostname>` SRV record was not found, a server is
|
||||||
|
found by resolving an SRV record for `_matrix._tcp.<hostname>`. This may
|
||||||
|
result in a hostname (to be resolved using AAAA or A records) and
|
||||||
|
port. Requests are made to the resolved IP address and port, with a `Host`
|
||||||
|
header of `<hostname>`. The target server must present a valid certificate
|
||||||
|
for `<hostname>`.
|
||||||
|
|
||||||
|
6. If the `/.well-known` request returned an error response, and
|
||||||
|
no SRV records were found, an IP address is resolved using CNAME, AAAA and A
|
||||||
records. Requests are made to the resolved IP address using port
|
records. Requests are made to the resolved IP address using port
|
||||||
8448 and a `Host` header containing the `<hostname>`. The target
|
8448 and a `Host` header containing the `<hostname>`. The target
|
||||||
server must present a valid certificate for `<hostname>`.
|
server must present a valid certificate for `<hostname>`.
|
||||||
|
|
@ -192,6 +208,14 @@ mandated by [RFC2782](https://www.rfc-editor.org/rfc/rfc2782.html):
|
||||||
> the name MUST NOT be an alias (in the sense of RFC 1034 or RFC 2181)
|
> the name MUST NOT be an alias (in the sense of RFC 1034 or RFC 2181)
|
||||||
{{% /boxes/note %}}
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Steps 3.4 and 5 are deprecated because they use a service name not registered by IANA.
|
||||||
|
They may be removed in a future version of the specification. Server admins are encouraged
|
||||||
|
to use `.well-known` over any form of SRV records.
|
||||||
|
|
||||||
|
The IANA registration for port 8448 and `matrix-fed` can be found [here](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=matrix-fed).
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
{{% http-api spec="server-server" api="wellknown" %}}
|
{{% http-api spec="server-server" api="wellknown" %}}
|
||||||
|
|
||||||
### Server implementation
|
### Server implementation
|
||||||
|
|
@ -266,7 +290,7 @@ Step 1 sign JSON:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "POST",
|
||||||
"uri": "/target",
|
"uri": "/target",
|
||||||
"origin": "origin.hs.example.com",
|
"origin": "origin.hs.example.com",
|
||||||
"destination": "destination.hs.example.com",
|
"destination": "destination.hs.example.com",
|
||||||
|
|
@ -287,7 +311,7 @@ condition applies throughout the request signing process.
|
||||||
|
|
||||||
Step 2 add Authorization header:
|
Step 2 add Authorization header:
|
||||||
|
|
||||||
GET /target HTTP/1.1
|
POST /target HTTP/1.1
|
||||||
Authorization: X-Matrix origin="origin.hs.example.com",destination="destination.hs.example.com",key="ed25519:key1",sig="ABCDEF..."
|
Authorization: X-Matrix origin="origin.hs.example.com",destination="destination.hs.example.com",key="ed25519:key1",sig="ABCDEF..."
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,17 +50,17 @@
|
||||||
"Flower": "زَهرَة",
|
"Flower": "زَهرَة",
|
||||||
"Butterfly": "فَرَاشَة",
|
"Butterfly": "فَرَاشَة",
|
||||||
"Octopus": "أُخطُبُوط",
|
"Octopus": "أُخطُبُوط",
|
||||||
"Fish": "سَمَكَة",
|
"Fish": "سَمَكة",
|
||||||
"Turtle": "سُلحفاة",
|
"Turtle": "سُلحفاة",
|
||||||
"Penguin": "بِطريق",
|
"Penguin": "بطريق",
|
||||||
"Rooster": "دِيك",
|
"Rooster": "دِيك",
|
||||||
"Panda": "باندَا",
|
"Panda": "باندَا",
|
||||||
"Rabbit": "أَرنَب",
|
"Rabbit": "أَرنَب",
|
||||||
"Elephant": "فِيل",
|
"Elephant": "فِيل",
|
||||||
"Pig": "خِنزِير",
|
"Pig": "خِنزِير",
|
||||||
"Unicorn": "حِصَانٌ بِقَرن",
|
"Unicorn": "حصان وحيد القرن",
|
||||||
"Horse": "حِصَان",
|
"Horse": "حِصَان",
|
||||||
"Lion": "أَسَد",
|
"Lion": "أَسَد",
|
||||||
"Cat": "هِرَّة",
|
"Cat": "هِرَّة",
|
||||||
"Dog": "كَلب"
|
"Dog": "كلب"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"Flag": "Vlajka",
|
"Flag": "Vlajka",
|
||||||
"Telephone": "Telefon",
|
"Telephone": "Telefon",
|
||||||
"Hammer": "Kladivo",
|
"Hammer": "Kladivo",
|
||||||
"Key": "Klíč",
|
"Key": "Klíč ke dveřím",
|
||||||
"Lock": "Zámek",
|
"Lock": "Zámek",
|
||||||
"Scissors": "Nůžky",
|
"Scissors": "Nůžky",
|
||||||
"Paperclip": "Sponka",
|
"Paperclip": "Sponka",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
"Pencil": "Lápiz",
|
"Pencil": "Lápiz",
|
||||||
"Key": "Llave",
|
"Key": "Llave",
|
||||||
"Hammer": "Martillo",
|
"Hammer": "Martillo",
|
||||||
"Telephone": "Telefono",
|
"Telephone": "Teléfono",
|
||||||
"Train": "Tren",
|
"Train": "Tren",
|
||||||
"Bicycle": "Bicicleta",
|
"Bicycle": "Bicicleta",
|
||||||
"Ball": "Bola",
|
"Ball": "Bola",
|
||||||
|
|
|
||||||
66
data-definitions/sas-emoji-v1-i18n/fa.json
Normal file
66
data-definitions/sas-emoji-v1-i18n/fa.json
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"Pin": "سنجاق",
|
||||||
|
"Folder": "پوشه",
|
||||||
|
"Headphones": "هدفون",
|
||||||
|
"Anchor": "لنگر",
|
||||||
|
"Bell": "زنگ",
|
||||||
|
"Trumpet": "شیپور",
|
||||||
|
"Guitar": "گیتار",
|
||||||
|
"Ball": "توپ",
|
||||||
|
"Trophy": "جام",
|
||||||
|
"Rocket": "موشک",
|
||||||
|
"Aeroplane": "هواپیما",
|
||||||
|
"Bicycle": "دوچرخه",
|
||||||
|
"Train": "قطار",
|
||||||
|
"Flag": "پرچم",
|
||||||
|
"Telephone": "تلفن",
|
||||||
|
"Hammer": "چکش",
|
||||||
|
"Key": "کلید",
|
||||||
|
"Lock": "قفل",
|
||||||
|
"Scissors": "قیچی",
|
||||||
|
"Paperclip": "گیره کاغذ",
|
||||||
|
"Pencil": "مداد",
|
||||||
|
"Book": "کتاب",
|
||||||
|
"Light Bulb": "لامپ",
|
||||||
|
"Gift": "هدیه",
|
||||||
|
"Clock": "ساعت",
|
||||||
|
"Hourglass": "ساعت شنی",
|
||||||
|
"Umbrella": "چتر",
|
||||||
|
"Thumbs Up": "لایک",
|
||||||
|
"Santa": "بابا نوئل",
|
||||||
|
"Spanner": "آچار",
|
||||||
|
"Glasses": "عینک",
|
||||||
|
"Hat": "کلاه",
|
||||||
|
"Robot": "ربات",
|
||||||
|
"Smiley": "خنده",
|
||||||
|
"Heart": "قلب",
|
||||||
|
"Cake": "کیک",
|
||||||
|
"Pizza": "پیتزا",
|
||||||
|
"Corn": "ذرت",
|
||||||
|
"Strawberry": "توت فرنگی",
|
||||||
|
"Apple": "سیب",
|
||||||
|
"Banana": "موز",
|
||||||
|
"Fire": "آتش",
|
||||||
|
"Cloud": "ابر",
|
||||||
|
"Moon": "ماه",
|
||||||
|
"Globe": "زمین",
|
||||||
|
"Mushroom": "قارچ",
|
||||||
|
"Cactus": "کاکتوس",
|
||||||
|
"Tree": "درخت",
|
||||||
|
"Flower": "گل",
|
||||||
|
"Butterfly": "پروانه",
|
||||||
|
"Octopus": "اختاپوس",
|
||||||
|
"Fish": "ماهی",
|
||||||
|
"Turtle": "لاکپشت",
|
||||||
|
"Penguin": "پنگوئن",
|
||||||
|
"Rooster": "خروس",
|
||||||
|
"Panda": "پاندا",
|
||||||
|
"Rabbit": "خرگوش",
|
||||||
|
"Elephant": "فیل",
|
||||||
|
"Pig": "خوک",
|
||||||
|
"Unicorn": "تک شاخ",
|
||||||
|
"Horse": "اسب",
|
||||||
|
"Lion": "شیر",
|
||||||
|
"Cat": "گربه",
|
||||||
|
"Dog": "سگ"
|
||||||
|
}
|
||||||
|
|
@ -9,14 +9,14 @@
|
||||||
"Moon": "月",
|
"Moon": "月",
|
||||||
"Apple": "リンゴ",
|
"Apple": "リンゴ",
|
||||||
"Cake": "ケーキ",
|
"Cake": "ケーキ",
|
||||||
"Robot": "ロボと",
|
"Robot": "ロボット",
|
||||||
"Glasses": "めがね",
|
"Glasses": "めがね",
|
||||||
"Book": "本",
|
"Book": "本",
|
||||||
"Telephone": "電話機",
|
"Telephone": "電話機",
|
||||||
"Train": "電車",
|
"Train": "電車",
|
||||||
"Bicycle": "自転車",
|
"Bicycle": "自転車",
|
||||||
"Pin": "ピン",
|
"Pin": "ピン",
|
||||||
"Folder": "フォルダ",
|
"Folder": "フォルダー",
|
||||||
"Headphones": "ヘッドホン",
|
"Headphones": "ヘッドホン",
|
||||||
"Anchor": "いかり",
|
"Anchor": "いかり",
|
||||||
"Bell": "ベル",
|
"Bell": "ベル",
|
||||||
|
|
|
||||||
66
data-definitions/sas-emoji-v1-i18n/pt.json
Normal file
66
data-definitions/sas-emoji-v1-i18n/pt.json
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"Thumbs Up": "Polegar para cima",
|
||||||
|
"Pin": "Pionés",
|
||||||
|
"Folder": "Pasta",
|
||||||
|
"Headphones": "Fones",
|
||||||
|
"Anchor": "Âncora",
|
||||||
|
"Bell": "Sino",
|
||||||
|
"Trumpet": "Trompete",
|
||||||
|
"Guitar": "Guitarra",
|
||||||
|
"Ball": "Bola",
|
||||||
|
"Trophy": "Troféu",
|
||||||
|
"Rocket": "Foguetão",
|
||||||
|
"Aeroplane": "Avião",
|
||||||
|
"Bicycle": "Bicicleta",
|
||||||
|
"Train": "Comboio",
|
||||||
|
"Flag": "Bandeira",
|
||||||
|
"Telephone": "Telefone",
|
||||||
|
"Hammer": "Martelo",
|
||||||
|
"Key": "Chave",
|
||||||
|
"Lock": "Cadeado",
|
||||||
|
"Scissors": "Tesoura",
|
||||||
|
"Paperclip": "Clipe",
|
||||||
|
"Pencil": "Lápis",
|
||||||
|
"Book": "Livro",
|
||||||
|
"Light Bulb": "Lâmpada",
|
||||||
|
"Gift": "Presente",
|
||||||
|
"Clock": "Relógio",
|
||||||
|
"Hourglass": "Ampulheta",
|
||||||
|
"Umbrella": "Guarda-chuva",
|
||||||
|
"Santa": "Pai Natal",
|
||||||
|
"Spanner": "Chave inglesa",
|
||||||
|
"Glasses": "Óculos",
|
||||||
|
"Hat": "Chapéu",
|
||||||
|
"Robot": "Robô",
|
||||||
|
"Smiley": "Sorriso",
|
||||||
|
"Heart": "Coração",
|
||||||
|
"Cake": "Bolo",
|
||||||
|
"Pizza": "Piza",
|
||||||
|
"Corn": "Milho",
|
||||||
|
"Strawberry": "Morango",
|
||||||
|
"Apple": "Maçã",
|
||||||
|
"Banana": "Banana",
|
||||||
|
"Fire": "Fogo",
|
||||||
|
"Cloud": "Nuvem",
|
||||||
|
"Moon": "Lua",
|
||||||
|
"Globe": "Globo",
|
||||||
|
"Mushroom": "Cogumelo",
|
||||||
|
"Cactus": "Cato",
|
||||||
|
"Tree": "Árvore",
|
||||||
|
"Flower": "Flor",
|
||||||
|
"Butterfly": "Borboleta",
|
||||||
|
"Octopus": "Polvo",
|
||||||
|
"Fish": "Peixe",
|
||||||
|
"Turtle": "Tartaruga",
|
||||||
|
"Penguin": "Pinguim",
|
||||||
|
"Rooster": "Galo",
|
||||||
|
"Panda": "Panda",
|
||||||
|
"Rabbit": "Coelho",
|
||||||
|
"Elephant": "Elefante",
|
||||||
|
"Pig": "Porco",
|
||||||
|
"Unicorn": "Unicórnio",
|
||||||
|
"Horse": "Cavalo",
|
||||||
|
"Lion": "Leão",
|
||||||
|
"Cat": "Gato",
|
||||||
|
"Dog": "Cão"
|
||||||
|
}
|
||||||
|
|
@ -1,64 +1,64 @@
|
||||||
{
|
{
|
||||||
"Dog": "Hlava psa",
|
"Dog": "Pes",
|
||||||
"Cat": "Hlava mačky",
|
"Cat": "Mačka",
|
||||||
"Lion": "Hlava leva",
|
"Lion": "Lev",
|
||||||
"Horse": "Kôň",
|
"Horse": "Kôň",
|
||||||
"Unicorn": "Hlava jednorožca",
|
"Unicorn": "Jednorožec",
|
||||||
"Pig": "Hlava prasaťa",
|
"Pig": "Prasa",
|
||||||
"Elephant": "Slon",
|
"Elephant": "Slon",
|
||||||
"Rabbit": "Hlava zajaca",
|
"Rabbit": "Zajac",
|
||||||
"Panda": "Hlava pandy",
|
"Panda": "Panda",
|
||||||
"Rooster": "Kohút",
|
"Rooster": "Kohút",
|
||||||
"Penguin": "Tučniak",
|
"Penguin": "Tučniak",
|
||||||
"Turtle": "Korytnačka",
|
"Turtle": "Korytnačka",
|
||||||
"Fish": "Ryba",
|
"Fish": "Ryba",
|
||||||
"Octopus": "Chobotnica",
|
"Octopus": "Chobotnica",
|
||||||
"Butterfly": "Motýľ",
|
"Butterfly": "Motýľ",
|
||||||
"Flower": "Tulipán",
|
"Flower": "Kvet",
|
||||||
"Tree": "Listnatý strom",
|
"Tree": "Strom",
|
||||||
"Cactus": "Kaktus",
|
"Cactus": "Kaktus",
|
||||||
"Mushroom": "Huba",
|
"Mushroom": "Huba",
|
||||||
"Globe": "Zemeguľa",
|
"Globe": "Zemeguľa",
|
||||||
"Moon": "Polmesiac",
|
"Moon": "Mesiac",
|
||||||
"Cloud": "Oblak",
|
"Cloud": "Oblak",
|
||||||
"Fire": "Oheň",
|
"Fire": "Oheň",
|
||||||
"Banana": "Banán",
|
"Banana": "Banán",
|
||||||
"Apple": "Červené jablko",
|
"Apple": "Jablko",
|
||||||
"Strawberry": "Jahoda",
|
"Strawberry": "Jahoda",
|
||||||
"Corn": "Kukuričný klas",
|
"Corn": "Kukurica",
|
||||||
"Pizza": "Pizza",
|
"Pizza": "Pizza",
|
||||||
"Cake": "Narodeninová torta",
|
"Cake": "Torta",
|
||||||
"Heart": "červené srdce",
|
"Heart": "Srdce",
|
||||||
"Smiley": "Škeriaca sa tvár",
|
"Smiley": "Smajlík",
|
||||||
"Robot": "Robot",
|
"Robot": "Robot",
|
||||||
"Hat": "Cilinder",
|
"Hat": "Klobúk",
|
||||||
"Glasses": "Okuliare",
|
"Glasses": "Okuliare",
|
||||||
"Spanner": "Francúzsky kľúč",
|
"Spanner": "Vidlicový kľúč",
|
||||||
"Santa": "Santa Claus",
|
"Santa": "Mikuláš",
|
||||||
"Thumbs Up": "Palec nahor",
|
"Thumbs Up": "Palec nahor",
|
||||||
"Umbrella": "Dáždnik",
|
"Umbrella": "Dáždnik",
|
||||||
"Hourglass": "Presýpacie hodiny",
|
"Hourglass": "Presýpacie hodiny",
|
||||||
"Clock": "Budík",
|
"Clock": "Budík",
|
||||||
"Gift": "Zabalený darček",
|
"Gift": "Darček",
|
||||||
"Light Bulb": "Žiarovka",
|
"Light Bulb": "Žiarovka",
|
||||||
"Book": "Zatvorená kniha",
|
"Book": "Kniha",
|
||||||
"Pencil": "Ceruzka",
|
"Pencil": "Ceruzka",
|
||||||
"Paperclip": "Sponka na papier",
|
"Paperclip": "Kancelárska sponka",
|
||||||
"Scissors": "Nožnice",
|
"Scissors": "Nožnice",
|
||||||
"Lock": "Zatvorená zámka",
|
"Lock": "Zámka",
|
||||||
"Key": "Kľúč",
|
"Key": "Kľúč",
|
||||||
"Hammer": "Kladivo",
|
"Hammer": "Kladivo",
|
||||||
"Telephone": "Telefón",
|
"Telephone": "Telefón",
|
||||||
"Flag": "Kockovaná zástava",
|
"Flag": "Zástava",
|
||||||
"Train": "Rušeň",
|
"Train": "Vlak",
|
||||||
"Bicycle": "Bicykel",
|
"Bicycle": "Bicykel",
|
||||||
"Aeroplane": "Lietadlo",
|
"Aeroplane": "Lietadlo",
|
||||||
"Rocket": "Raketa",
|
"Rocket": "Raketa",
|
||||||
"Trophy": "Trofej",
|
"Trophy": "Trofej",
|
||||||
"Ball": "Futbal",
|
"Ball": "Lopta",
|
||||||
"Guitar": "Gitara",
|
"Guitar": "Gitara",
|
||||||
"Trumpet": "Trúbka",
|
"Trumpet": "Trúbka",
|
||||||
"Bell": "Zvon",
|
"Bell": "Zvonec",
|
||||||
"Anchor": "Kotva",
|
"Anchor": "Kotva",
|
||||||
"Headphones": "Slúchadlá",
|
"Headphones": "Slúchadlá",
|
||||||
"Folder": "Fascikel",
|
"Folder": "Fascikel",
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,20 @@
|
||||||
"Hammer": "Búa",
|
"Hammer": "Búa",
|
||||||
"Key": "Chìa khóa",
|
"Key": "Chìa khóa",
|
||||||
"Lock": "Ổ khóa",
|
"Lock": "Ổ khóa",
|
||||||
"Scissors": "Cây kéo",
|
"Scissors": "Cái kéo",
|
||||||
"Paperclip": "Kẹp giấy",
|
"Paperclip": "Kẹp giấy",
|
||||||
"Pencil": "Viết chì",
|
"Pencil": "Viết chì",
|
||||||
"Book": "Sách",
|
"Book": "Sách",
|
||||||
"Light Bulb": "Bóng đèn tròn",
|
"Light Bulb": "Bóng đèn tròn",
|
||||||
"Gift": "Quà",
|
"Gift": "Quà tặng",
|
||||||
"Clock": "Đồng hồ",
|
"Clock": "Đồng hồ",
|
||||||
"Hourglass": "Đồng hồ cát",
|
"Hourglass": "Đồng hồ cát",
|
||||||
"Umbrella": "Cây dù",
|
"Umbrella": "Cái ô",
|
||||||
"Thumbs Up": "Thích",
|
"Thumbs Up": "Thích",
|
||||||
"Santa": "ông già Noel",
|
"Santa": "ông già Nô-en",
|
||||||
"Spanner": "Cờ-lê",
|
"Spanner": "Cờ-lê",
|
||||||
"Glasses": "Mắt kiếng",
|
"Glasses": "Kính mắt",
|
||||||
"Hat": "Nón",
|
"Hat": "Mũ",
|
||||||
"Robot": "Rô-bô",
|
"Robot": "Rô-bô",
|
||||||
"Smiley": "Mặt cười",
|
"Smiley": "Mặt cười",
|
||||||
"Heart": "Tim",
|
"Heart": "Tim",
|
||||||
|
|
|
||||||
66
data-definitions/sas-emoji-v1-i18n/zh_Hant.json
Normal file
66
data-definitions/sas-emoji-v1-i18n/zh_Hant.json
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"Pin": "圖釘",
|
||||||
|
"Folder": "資料夾",
|
||||||
|
"Headphones": "耳機",
|
||||||
|
"Anchor": "船錨",
|
||||||
|
"Bell": "鈴鐺",
|
||||||
|
"Trumpet": "喇叭",
|
||||||
|
"Guitar": "吉他",
|
||||||
|
"Ball": "足球",
|
||||||
|
"Trophy": "獎盃",
|
||||||
|
"Rocket": "火箭",
|
||||||
|
"Aeroplane": "飛機",
|
||||||
|
"Bicycle": "腳踏車",
|
||||||
|
"Train": "火車",
|
||||||
|
"Flag": "旗幟",
|
||||||
|
"Telephone": "電話",
|
||||||
|
"Hammer": "鎚子",
|
||||||
|
"Key": "鑰匙",
|
||||||
|
"Lock": "鎖頭",
|
||||||
|
"Scissors": "剪刀",
|
||||||
|
"Paperclip": "迴紋針",
|
||||||
|
"Pencil": "鉛筆",
|
||||||
|
"Book": "書",
|
||||||
|
"Light Bulb": "燈泡",
|
||||||
|
"Gift": "禮物",
|
||||||
|
"Clock": "時鐘",
|
||||||
|
"Hourglass": "沙漏",
|
||||||
|
"Umbrella": "雨傘",
|
||||||
|
"Thumbs Up": "讚",
|
||||||
|
"Santa": "聖誕老人",
|
||||||
|
"Spanner": "扳手",
|
||||||
|
"Glasses": "眼鏡",
|
||||||
|
"Hat": "帽子",
|
||||||
|
"Robot": "機器人",
|
||||||
|
"Smiley": "笑臉",
|
||||||
|
"Heart": "愛心",
|
||||||
|
"Cake": "蛋糕",
|
||||||
|
"Pizza": "披薩",
|
||||||
|
"Corn": "玉米",
|
||||||
|
"Strawberry": "草莓",
|
||||||
|
"Apple": "蘋果",
|
||||||
|
"Banana": "香蕉",
|
||||||
|
"Fire": "火",
|
||||||
|
"Cloud": "雲朵",
|
||||||
|
"Moon": "月亮",
|
||||||
|
"Globe": "地球",
|
||||||
|
"Mushroom": "蘑菇",
|
||||||
|
"Cactus": "仙人掌",
|
||||||
|
"Tree": "樹",
|
||||||
|
"Flower": "花",
|
||||||
|
"Butterfly": "蝴蝶",
|
||||||
|
"Octopus": "章魚",
|
||||||
|
"Fish": "魚",
|
||||||
|
"Turtle": "烏龜",
|
||||||
|
"Penguin": "企鵝",
|
||||||
|
"Rooster": "公雞",
|
||||||
|
"Panda": "熊貓",
|
||||||
|
"Rabbit": "兔子",
|
||||||
|
"Elephant": "大象",
|
||||||
|
"Pig": "豬",
|
||||||
|
"Unicorn": "獨角獸",
|
||||||
|
"Horse": "馬",
|
||||||
|
"Lion": "獅子",
|
||||||
|
"Cat": "貓",
|
||||||
|
"Dog": "狗"
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue